-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Circuit simulator #580
Changes from 14 commits
ad0f6e2
3c3c821
f5ad944
6bbf664
c7c67d0
7848146
4da38c9
213ac0f
be9d58c
bf57c0e
a7c1f0b
1322151
e347cd1
b903a8a
9cffa42
0fe1567
d720a1a
3d70094
9fae028
3b79321
29fba08
e908e94
3f92696
a6e50ef
7639b4b
0069914
af52eca
fbc541c
66a927e
3c45641
0319741
d56a5f2
7a6cd60
6f0cf3c
60bced7
6a9d027
5d8715b
0ca164a
1bcd9a1
79eb049
8adc31c
e8ed76b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#pragma once | ||
#include "barretenberg/ecc/curves/bn254/fr.hpp" | ||
#include "barretenberg/proof_system/arithmetization/gate_data.hpp" | ||
#include "barretenberg/proof_system/types/merkle_hash_type.hpp" | ||
#include "barretenberg/proof_system/types/pedersen_commitment_type.hpp" | ||
|
||
namespace proof_system { | ||
|
||
class CircuitSimulatorBN254 { | ||
public: | ||
using FF = barretenberg::fr; // IOU templating | ||
static constexpr merkle::HashType merkle_hash_type = merkle::HashType::NONE; // UGH | ||
static constexpr pedersen::CommitmentType commitment_type = pedersen::CommitmentType::NONE; | ||
|
||
bool contains_recursive_proof = false; | ||
static constexpr size_t UINT_LOG2_BASE = 2; // WORKTODO: 6 for Ultra | ||
|
||
const uint32_t zero_idx = 0; | ||
|
||
// uint32_t add_variable([[maybe_unused]]const FF& in){ | ||
// return 0; // WORKTODO: return part of `in` for debugging purposes? | ||
// } | ||
|
||
inline uint32_t add_variable([[maybe_unused]] const barretenberg::fr index) const { return 1028; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1028 = 0x404, recognizable when printing if something went wrong in the simulation. |
||
inline barretenberg::fr get_variable([[maybe_unused]] const uint32_t index) const { return 1028; } | ||
|
||
uint32_t put_constant_variable([[maybe_unused]] const barretenberg::fr& variable) { return 1028; } | ||
void set_public_input([[maybe_unused]] const uint32_t witness_index) | ||
{ | ||
// WORKTODO Public input logic? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haven't thought through potential subtleties with |
||
} | ||
|
||
void fix_witness([[maybe_unused]] const uint32_t witness_index, | ||
[[maybe_unused]] const barretenberg::fr& witness_value){ | ||
// WORKTODO: logic? | ||
}; | ||
|
||
[[nodiscard]] size_t get_num_gates() const { return 0; } | ||
|
||
void create_add_gate([[maybe_unused]] const add_triple& in){}; | ||
void create_mul_gate([[maybe_unused]] const mul_triple& in){}; | ||
void create_bool_gate([[maybe_unused]] const uint32_t a){}; | ||
void create_poly_gate([[maybe_unused]] const poly_triple& in){}; | ||
void create_big_add_gate([[maybe_unused]] const add_quad& in){}; | ||
void create_big_add_gate_with_bit_extraction([[maybe_unused]] const add_quad& in){}; | ||
void create_big_mul_gate([[maybe_unused]] const mul_quad& in){}; | ||
void create_balanced_add_gate([[maybe_unused]] const add_quad& in){}; | ||
void create_fixed_group_add_gate([[maybe_unused]] const fixed_group_add_quad& in){}; | ||
void create_fixed_group_add_gate_with_init([[maybe_unused]] const fixed_group_add_quad& in, | ||
[[maybe_unused]] const fixed_group_init_quad& init){}; | ||
void create_fixed_group_add_gate_final([[maybe_unused]] const add_quad& in){}; | ||
|
||
accumulator_triple create_and_constraint([[maybe_unused]] const uint32_t a, | ||
[[maybe_unused]] const uint32_t b, | ||
[[maybe_unused]] const size_t num_bits) | ||
{ | ||
return { { 1028 }, { 1028 }, { 1028 } }; | ||
}; | ||
accumulator_triple create_xor_constraint([[maybe_unused]] const uint32_t a, | ||
[[maybe_unused]] const uint32_t b, | ||
[[maybe_unused]] const size_t num_bits) | ||
{ | ||
return { { 1028 }, { 1028 }, { 1028 } }; | ||
}; | ||
|
||
size_t get_num_constant_gates() { return 1028; }; | ||
// maybe this shouldn't be implemented? | ||
|
||
bool create_range_constraint(FF const& elt, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My goal is to preserve the composer interface when I can, but without tracking witness indices. In this case I decided to change the interface (input is a field element |
||
size_t const& num_bits, | ||
std::string const& msg = "create_range_constraint") | ||
{ | ||
const bool constraint_holds = static_cast<uint256_t>(elt).get_msb() < num_bits; | ||
if (!constraint_holds) { | ||
failure(msg); | ||
} | ||
return constraint_holds; | ||
} | ||
|
||
std::vector<uint32_t> decompose_into_base4_accumulators( | ||
[[maybe_unused]] const uint32_t witness_index, | ||
[[maybe_unused]] const size_t num_bits, | ||
[[maybe_unused]] std::string const& msg = "create_range_constraint") | ||
{ | ||
return { 1028 }; | ||
}; | ||
|
||
void assert_equal(FF left, FF right, std::string const& msg) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another departure of the form "witness index becomes a value". |
||
{ | ||
if (left != right) { | ||
failure(msg); | ||
} | ||
} | ||
|
||
void assert_equal_constant(FF left, FF right, std::string const& msg) { assert_equal(left, right, msg); } | ||
|
||
bool _failed = false; | ||
std::string _err; | ||
|
||
[[maybe_unused]] bool failed() const { return _failed; }; | ||
[[nodiscard]] const std::string& err() const { return _err; }; | ||
|
||
void set_err(std::string msg) { _err = std::move(msg); } | ||
void failure(std::string msg) | ||
{ | ||
_failed = true; | ||
set_err(std::move(msg)); | ||
} | ||
|
||
[[nodiscard]] bool check_circuit() const { return !_failed; } | ||
}; | ||
|
||
} // namespace proof_system |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#include "circuit_simulator.hpp" | ||
#include <gtest/gtest.h> | ||
|
||
namespace { | ||
auto& engine = numeric::random::get_debug_engine(); | ||
} | ||
|
||
namespace proof_system::circuit_simulator_tests { | ||
|
||
class CircuitSimulatorBN254Test : public ::testing::Test {}; | ||
|
||
TEST(CircuitSimulatorBN254Test, Base) | ||
{ | ||
CircuitSimulatorBN254 circuit; | ||
} | ||
|
||
// TODO: Add more tests. | ||
|
||
} // namespace proof_system::circuit_simulator_tests |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,6 +67,7 @@ | |
#include "barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp" | ||
#include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" | ||
#include "barretenberg/polynomials/evaluation_domain.hpp" | ||
#include "barretenberg/proof_system/circuit_builder/circuit_simulator.hpp" | ||
#include "barretenberg/proof_system/types/circuit_type.hpp" | ||
#include <array> | ||
#include <concepts> | ||
|
@@ -299,6 +300,10 @@ concept IsPlonkFlavor = IsAnyOf<T, plonk::flavor::Standard, plonk::flavor::Turbo | |
template <typename T> | ||
concept IsHonkFlavor = IsAnyOf<T, honk::flavor::Standard, honk::flavor::Ultra, honk::flavor::StandardGrumpkin, honk::flavor::UltraGrumpkin>; | ||
|
||
// WORKTODO: move? smart way of not referring to instances? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will probably want a |
||
template <typename T> | ||
concept IsSimulator = IsAnyOf<T, proof_system::CircuitSimulatorBN254>; | ||
|
||
template <typename T> concept IsGrumpkinFlavor = IsAnyOf<T, honk::flavor::StandardGrumpkin, honk::flavor::UltraGrumpkin>; | ||
|
||
template <typename T> concept StandardFlavor = IsAnyOf<T, honk::flavor::Standard, honk::flavor::StandardGrumpkin>; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ namespace proof_system { | |
* A cache that wraps an underlying external store. It favours holding the largest polynomials in it's cache up | ||
* to max_cache_size_ polynomials. This saves on many expensive copies of large amounts of memory to the external | ||
* store. Smaller polynomials get swapped out, but they're also much cheaper to read/write. | ||
* The default ctor sets the cache size to 70. | ||
* The default ctor sets the cache size to 40. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated: I should have changed this in a PR earlier this week. |
||
* In combination with the slab allocator, this brings us to about 4GB mem usage for 512k circuits. | ||
* In tests using just the external store increased proof time from by about 50%. | ||
* This pretty much recoups all losses. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,5 @@ | |
|
||
namespace proof_system::merkle { | ||
// TODO(Cody) Get rid of this? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO the various enum's that track types should go away. |
||
enum HashType { FIXED_BASE_PEDERSEN, LOOKUP_PEDERSEN }; | ||
enum HashType { FIXED_BASE_PEDERSEN, LOOKUP_PEDERSEN, NONE }; | ||
} // namespace proof_system::merkle |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,8 @@ | |
|
||
#include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" | ||
#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" | ||
#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" | ||
#include "barretenberg/proof_system/circuit_builder/circuit_simulator.hpp" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (schnorr tests pass) |
||
// #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" | ||
#include "barretenberg/stdlib/primitives/point/point.hpp" | ||
#include "schnorr.hpp" | ||
|
||
|
@@ -12,7 +13,7 @@ using namespace barretenberg; | |
using namespace proof_system::plonk::stdlib; | ||
using namespace proof_system::plonk::stdlib::schnorr; | ||
|
||
using Composer = proof_system::UltraCircuitBuilder; | ||
using Composer = proof_system::CircuitSimulatorBN254; | ||
using bool_ct = bool_t<Composer>; | ||
using byte_array_ct = byte_array<Composer>; | ||
using field_ct = field_t<Composer>; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
#include "barretenberg/crypto/blake2s/blake2s.hpp" | ||
#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" | ||
#include "barretenberg/proof_system/circuit_builder/circuit_simulator.hpp" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (blake2s tests pass) |
||
// #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" | ||
#include "blake2s.hpp" | ||
#include "blake2s_plookup.hpp" | ||
#include <gtest/gtest.h> | ||
|
||
using namespace barretenberg; | ||
using namespace proof_system::plonk::stdlib; | ||
|
||
using Builder = proof_system::UltraCircuitBuilder; | ||
using Builder = proof_system::CircuitSimulatorBN254; | ||
|
||
using field_ct = field_t<Builder>; | ||
using witness_ct = witness_t<Builder>; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
#include "barretenberg/stdlib/primitives/point/point.hpp" | ||
#include "barretenberg/stdlib/primitives/witness/witness.hpp" | ||
|
||
// TODO: This does not belong in barretenberg. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The notion of an "address" I mean... just a side note. |
||
namespace proof_system::plonk { | ||
namespace stdlib { | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -397,7 +397,9 @@ void bool_t<ComposerContext>::assert_equal(const bool_t& rhs, std::string const& | |
const bool_t lhs = *this; | ||
ComposerContext* ctx = lhs.get_context() ? lhs.get_context() : rhs.get_context(); | ||
|
||
if (lhs.is_constant() && rhs.is_constant()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We want to put the composer in a failing state without changing existing code. We can't reuse the "both are witnesses" code because the assert_equal that takes in values (ant not witness indices) only exists on the simulator. |
||
if constexpr (IsSimulator<ComposerContext>) { | ||
context->assert_equal(lhs.get_value(), rhs.get_value(), msg); | ||
} else if (lhs.is_constant() && rhs.is_constant()) { | ||
ASSERT(lhs.get_value() == rhs.get_value()); | ||
} else if (lhs.is_constant()) { | ||
// if rhs is inverted, flip the value of the lhs constant | ||
|
@@ -550,6 +552,7 @@ template <typename ComposerContext> bool_t<ComposerContext> bool_t<ComposerConte | |
} | ||
|
||
INSTANTIATE_STDLIB_TYPE(bool_t); | ||
INSTANTIATE_STDLIB_SIMULATOR_TYPE(bool_t); | ||
|
||
} // namespace stdlib | ||
} // namespace proof_system::plonk |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,8 +18,10 @@ auto& engine = numeric::random::get_debug_engine(); | |
|
||
template <class Composer> class BoolTest : public ::testing::Test {}; | ||
|
||
using CircuitTypes = ::testing:: | ||
Types<proof_system::StandardCircuitBuilder, proof_system::TurboCircuitBuilder, proof_system::UltraCircuitBuilder>; | ||
using CircuitTypes = ::testing::Types<proof_system::CircuitSimulatorBN254, | ||
proof_system::StandardCircuitBuilder, | ||
proof_system::TurboCircuitBuilder, | ||
proof_system::UltraCircuitBuilder>; | ||
|
||
TYPED_TEST_SUITE(BoolTest, CircuitTypes); | ||
TYPED_TEST(BoolTest, TestBasicOperations) | ||
|
@@ -28,8 +30,6 @@ TYPED_TEST(BoolTest, TestBasicOperations) | |
STDLIB_TYPE_ALIASES | ||
auto composer = Composer(); | ||
|
||
auto gates_before = composer.get_num_gates(); | ||
|
||
bool_ct a = witness_ct(&composer, barretenberg::fr::one()); | ||
bool_ct b = witness_ct(&composer, barretenberg::fr::zero()); | ||
a = a ^ b; // a = 1 | ||
|
@@ -50,8 +50,7 @@ TYPED_TEST(BoolTest, TestBasicOperations) | |
bool result = composer.check_circuit(); | ||
EXPECT_EQ(result, true); | ||
|
||
auto gates_after = composer.get_num_gates(); | ||
EXPECT_EQ(gates_after - gates_before, 6UL); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These tests that function like benchmarks should break, since we don't track gates, but they aren't testing circuit logic, so I felt comfortable deleting them. |
||
info("composer gates = ", composer.get_num_gates()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: delete line |
||
} | ||
|
||
TYPED_TEST(BoolTest, Xor) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -351,9 +351,9 @@ typename byte_array<Composer>::byte_slice byte_array<Composer>::split_byte(const | |
|
||
if (byte.is_constant()) { | ||
field_t<Composer> low(context, low_value); | ||
field_t<Composer> high(context, high_value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CIRCUIT BUG: we were not correctly setting bits in the constant case. |
||
field_t<Composer> shifted_high(context, high_value * (uint64_t(1) << (8ULL - num_high_bits))); | ||
bool_t<Composer> bit(context, static_cast<bool>(bit_value)); | ||
return { low, high, bit }; | ||
return { low, shifted_high, bit }; | ||
} | ||
field_t<Composer> low = witness_t<Composer>(context, low_value); | ||
field_t<Composer> high = witness_t<Composer>(context, high_value); | ||
|
@@ -381,6 +381,7 @@ typename byte_array<Composer>::byte_slice byte_array<Composer>::split_byte(const | |
} | ||
|
||
INSTANTIATE_STDLIB_TYPE(byte_array); | ||
INSTANTIATE_STDLIB_SIMULATOR_TYPE(byte_array); | ||
|
||
} // namespace stdlib | ||
} // namespace proof_system::plonk |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: share code with
CircuitConstructorBase