From 61067a5cdedfd10fbc32e381083b031bc80fc6d6 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:38:55 -0700 Subject: [PATCH] feat: gate blocks (#4741) Introduces the pattern for constructing an execution trace sorted by gate type. The single {`wires`, `selectors`} pair in the builders is replaced by a `GateBlocks` type which has one {`wires`, `selectors`} pair or "ExecutionTraceBlock" per gate type. The classes in arithmetization.hpp have been updated to describe this structure. This PR does not yet fully break the gates up by gate type. For example the Goblin ultra builder still only has three blocks: ecc op gates, public inputs, and "main" (everything else). This results in the exact same execution trace that is currently constructed in master. In principle, the full sorting amounts to simply adding gates to their particular block instead of `main`. This will be done in a follow on. This PR also makes modifications to the check_circuit functionality in the Ultra builder. Previously, there was a fair bit of logic for storing the pre-finalized state of the circuit so that it could be returned to its original state after finalizing and checking. This has been replaced by simply copying the circuit via its constructor, then ultimately resetting it using this copy. This is a bit less efficient but simplifies the logic substantially. (I have another follow on that will further simplify, improve efficiency, and move the check circuit logic to a separate class). Closes https://github.com/AztecProtocol/barretenberg/issues/862 --- .../plonk/composer/standard_composer.cpp | 11 +- .../plonk/composer/standard_composer.hpp | 8 +- .../plonk/composer/ultra_composer.cpp | 2 +- .../arithmetization/arithmetization.hpp | 268 ++-- .../circuit_builder/circuit_builder_base.hpp | 2 + .../goblin_ultra_circuit_builder.cpp | 240 ++-- .../goblin_ultra_circuit_builder.hpp | 25 - .../goblin_ultra_circuit_builder.test.cpp | 27 +- .../standard_circuit_builder.cpp | 153 +- .../standard_circuit_builder.hpp | 38 +- .../circuit_builder/ultra_circuit_builder.cpp | 1230 ++++++++--------- .../circuit_builder/ultra_circuit_builder.hpp | 378 +---- .../ultra_circuit_builder.test.cpp | 42 +- .../execution_trace/execution_trace.cpp | 93 +- .../execution_trace/execution_trace.hpp | 45 +- .../proof_system/plookup_tables/types.hpp | 5 + .../stdlib/primitives/field/field.test.cpp | 14 +- .../sumcheck/instance/prover_instance.cpp | 38 - .../sumcheck/instance/prover_instance.hpp | 9 +- 19 files changed, 1064 insertions(+), 1564 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.cpp b/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.cpp index 42c713ca291..3620fb540c3 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.cpp @@ -25,7 +25,7 @@ namespace bb::plonk { * * @return Pointer to the initialized proving key updated with selector polynomials. * */ -std::shared_ptr StandardComposer::compute_proving_key(const CircuitBuilder& circuit_constructor) +std::shared_ptr StandardComposer::compute_proving_key(CircuitBuilder& circuit_constructor) { if (circuit_proving_key) { return circuit_proving_key; @@ -41,7 +41,7 @@ std::shared_ptr StandardComposer::compute_proving_key(const subgroup_size, circuit_constructor.public_inputs.size(), crs, CircuitType::STANDARD); // Construct and add to proving key the wire, selector and copy constraint polynomials - Trace::generate(circuit_constructor, circuit_proving_key); + Trace::populate(circuit_constructor, circuit_proving_key); // Make all selectors nonzero enforce_nonzero_selector_polynomials(circuit_constructor, circuit_proving_key.get()); @@ -62,8 +62,7 @@ std::shared_ptr StandardComposer::compute_proving_key(const * * @return Pointer to created circuit verification key. * */ -std::shared_ptr StandardComposer::compute_verification_key( - const CircuitBuilder& circuit_constructor) +std::shared_ptr StandardComposer::compute_verification_key(CircuitBuilder& circuit_constructor) { if (circuit_verification_key) { return circuit_verification_key; @@ -89,7 +88,7 @@ std::shared_ptr StandardComposer::compute_verification_ * * @return The verifier. * */ -plonk::Verifier StandardComposer::create_verifier(const CircuitBuilder& circuit_constructor) +plonk::Verifier StandardComposer::create_verifier(CircuitBuilder& circuit_constructor) { auto verification_key = compute_verification_key(circuit_constructor); @@ -112,7 +111,7 @@ plonk::Verifier StandardComposer::create_verifier(const CircuitBuilder& circuit_ * * @return Initialized prover. * */ -plonk::Prover StandardComposer::create_prover(const CircuitBuilder& circuit_constructor) +plonk::Prover StandardComposer::create_prover(CircuitBuilder& circuit_constructor) { compute_proving_key(circuit_constructor); diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.hpp b/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.hpp index 84b6632fa77..63016750973 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.hpp @@ -56,11 +56,11 @@ class StandardComposer { }; return result; } - std::shared_ptr compute_proving_key(const CircuitBuilder& circuit_constructor); - std::shared_ptr compute_verification_key(const CircuitBuilder& circuit_constructor); + std::shared_ptr compute_proving_key(CircuitBuilder& circuit_constructor); + std::shared_ptr compute_verification_key(CircuitBuilder& circuit_constructor); - plonk::Verifier create_verifier(const CircuitBuilder& circuit_constructor); - plonk::Prover create_prover(const CircuitBuilder& circuit_constructor); + plonk::Verifier create_verifier(CircuitBuilder& circuit_constructor); + plonk::Prover create_prover(CircuitBuilder& circuit_constructor); /** * Create a manifest, which specifies proof rounds, elements and who supplies them. diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp index f42c1780807..80b0e886c5b 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp @@ -166,7 +166,7 @@ std::shared_ptr UltraComposer::compute_proving_key(CircuitBuilder& std::make_shared(subgroup_size, circuit.public_inputs.size(), crs, CircuitType::ULTRA); // Construct and add to proving key the wire, selector and copy constraint polynomials - Trace::generate(circuit, circuit_proving_key); + Trace::populate(circuit, circuit_proving_key); enforce_nonzero_selector_polynomials(circuit, circuit_proving_key.get()); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index 9001beef281..47e6545b9c5 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/common/ref_array.hpp" #include "barretenberg/ecc/curves/bn254/bn254.hpp" #include "barretenberg/proof_system/types/circuit_type.hpp" #include @@ -31,6 +32,36 @@ namespace bb { * We should only do this if it becomes necessary or convenient. */ +/** + * @brief Basic structure for storing gate data in a builder + * + * @tparam FF + * @tparam NUM_WIRES + * @tparam NUM_SELECTORS + */ +template class ExecutionTraceBlock { + public: + using SelectorType = std::vector>; + using WireType = std::vector>; + using Selectors = std::array; + using Wires = std::array; + + Wires wires; // vectors of indices into a witness variables array + Selectors selectors; + + bool operator==(const ExecutionTraceBlock& other) const = default; + + void reserve(size_t size_hint) + { + for (auto& w : wires) { + w.reserve(size_hint); + } + for (auto& p : selectors) { + p.reserve(size_hint); + } + } +}; + // These are not magic numbers and they should not be written with global constants. These parameters are not // accessible through clearly named static class members. template class StandardArith { @@ -38,30 +69,35 @@ template class StandardArith { static constexpr size_t NUM_WIRES = 3; static constexpr size_t NUM_SELECTORS = 5; using FF = FF_; - using SelectorType = std::vector>; - std::array selectors; + class StandardTraceBlock : public ExecutionTraceBlock { + public: + void populate_wires(const uint32_t& idx_1, const uint32_t& idx_2, const uint32_t& idx_3) + { + this->wires[0].emplace_back(idx_1); + this->wires[1].emplace_back(idx_2); + this->wires[2].emplace_back(idx_3); + } - SelectorType& q_m() { return selectors[0]; }; - SelectorType& q_1() { return selectors[1]; }; - SelectorType& q_2() { return selectors[2]; }; - SelectorType& q_3() { return selectors[3]; }; - SelectorType& q_c() { return selectors[4]; }; + auto& w_l() { return std::get<0>(this->wires); }; + auto& w_r() { return std::get<1>(this->wires); }; + auto& w_o() { return std::get<2>(this->wires); }; - const SelectorType& q_m() const { return selectors[0]; }; - const SelectorType& q_1() const { return selectors[1]; }; - const SelectorType& q_2() const { return selectors[2]; }; - const SelectorType& q_3() const { return selectors[3]; }; - const SelectorType& q_c() const { return selectors[4]; }; + auto& q_m() { return this->selectors[0]; }; + auto& q_1() { return this->selectors[1]; }; + auto& q_2() { return this->selectors[2]; }; + auto& q_3() { return this->selectors[3]; }; + auto& q_c() { return this->selectors[4]; }; + }; - auto& get() { return selectors; }; + struct TraceBlocks { + StandardTraceBlock pub_inputs; + StandardTraceBlock arithmetic; - void reserve(size_t size_hint) - { - for (auto& p : selectors) { - p.reserve(size_hint); - } - } + auto get() { return RefArray{ pub_inputs, arithmetic }; } + + bool operator==(const TraceBlocks& other) const = default; + }; // Note: These are needed for Plonk only (for poly storage in a std::map). Must be in same order as above struct. inline static const std::vector selector_names = { "q_m", "q_1", "q_2", "q_3", "q_c" }; @@ -72,44 +108,43 @@ template class UltraArith { static constexpr size_t NUM_WIRES = 4; static constexpr size_t NUM_SELECTORS = 11; using FF = FF_; - using SelectorType = std::vector>; - private: - std::array selectors; + class UltraTraceBlock : public ExecutionTraceBlock { + public: + void populate_wires(const uint32_t& idx_1, const uint32_t& idx_2, const uint32_t& idx_3, const uint32_t& idx_4) + { + this->wires[0].emplace_back(idx_1); + this->wires[1].emplace_back(idx_2); + this->wires[2].emplace_back(idx_3); + this->wires[3].emplace_back(idx_4); + } - public: - SelectorType& q_m() { return selectors[0]; }; - SelectorType& q_c() { return selectors[1]; }; - SelectorType& q_1() { return selectors[2]; }; - SelectorType& q_2() { return selectors[3]; }; - SelectorType& q_3() { return selectors[4]; }; - SelectorType& q_4() { return selectors[5]; }; - SelectorType& q_arith() { return selectors[6]; }; - SelectorType& q_sort() { return selectors[7]; }; - SelectorType& q_elliptic() { return selectors[8]; }; - SelectorType& q_aux() { return selectors[9]; }; - SelectorType& q_lookup_type() { return selectors[10]; }; - - const SelectorType& q_m() const { return selectors[0]; }; - const SelectorType& q_c() const { return selectors[1]; }; - const SelectorType& q_1() const { return selectors[2]; }; - const SelectorType& q_2() const { return selectors[3]; }; - const SelectorType& q_3() const { return selectors[4]; }; - const SelectorType& q_4() const { return selectors[5]; }; - const SelectorType& q_arith() const { return selectors[6]; }; - const SelectorType& q_sort() const { return selectors[7]; }; - const SelectorType& q_elliptic() const { return selectors[8]; }; - const SelectorType& q_aux() const { return selectors[9]; }; - const SelectorType& q_lookup_type() const { return selectors[10]; }; - - auto& get() { return selectors; }; + auto& w_l() { return std::get<0>(this->wires); }; + auto& w_r() { return std::get<1>(this->wires); }; + auto& w_o() { return std::get<2>(this->wires); }; + auto& w_4() { return std::get<3>(this->wires); }; + + auto& q_m() { return this->selectors[0]; }; + auto& q_c() { return this->selectors[1]; }; + auto& q_1() { return this->selectors[2]; }; + auto& q_2() { return this->selectors[3]; }; + auto& q_3() { return this->selectors[4]; }; + auto& q_4() { return this->selectors[5]; }; + auto& q_arith() { return this->selectors[6]; }; + auto& q_sort() { return this->selectors[7]; }; + auto& q_elliptic() { return this->selectors[8]; }; + auto& q_aux() { return this->selectors[9]; }; + auto& q_lookup_type() { return this->selectors[10]; }; + }; - void reserve(size_t size_hint) - { - for (auto& vec : selectors) { - vec.reserve(size_hint); - } - } + struct TraceBlocks { + UltraTraceBlock pub_inputs; + UltraTraceBlock main; + + auto get() { return RefArray{ pub_inputs, main }; } + + bool operator==(const TraceBlocks& other) const = default; + }; // Note: These are needed for Plonk only (for poly storage in a std::map). Must be in same order as above struct. inline static const std::vector selector_names = { "q_m", "q_c", "q_1", "q_2", @@ -128,75 +163,72 @@ template class UltraHonkArith { static constexpr size_t NUM_WIRES = 4; static constexpr size_t NUM_SELECTORS = 14; using FF = FF_; - using SelectorType = std::vector>; - - private: - std::array selectors; - public: - SelectorType& q_m() { return selectors[0]; }; - SelectorType& q_c() { return selectors[1]; }; - SelectorType& q_1() { return selectors[2]; }; - SelectorType& q_2() { return selectors[3]; }; - SelectorType& q_3() { return selectors[4]; }; - SelectorType& q_4() { return selectors[5]; }; - SelectorType& q_arith() { return selectors[6]; }; - SelectorType& q_sort() { return selectors[7]; }; - SelectorType& q_elliptic() { return selectors[8]; }; - SelectorType& q_aux() { return selectors[9]; }; - SelectorType& q_lookup_type() { return selectors[10]; }; - SelectorType& q_busread() { return selectors[11]; }; - SelectorType& q_poseidon2_external() { return this->selectors[12]; }; - SelectorType& q_poseidon2_internal() { return this->selectors[13]; }; - - const SelectorType& q_m() const { return selectors[0]; }; - const SelectorType& q_c() const { return selectors[1]; }; - const SelectorType& q_1() const { return selectors[2]; }; - const SelectorType& q_2() const { return selectors[3]; }; - const SelectorType& q_3() const { return selectors[4]; }; - const SelectorType& q_4() const { return selectors[5]; }; - const SelectorType& q_arith() const { return selectors[6]; }; - const SelectorType& q_sort() const { return selectors[7]; }; - const SelectorType& q_elliptic() const { return selectors[8]; }; - const SelectorType& q_aux() const { return selectors[9]; }; - const SelectorType& q_lookup_type() const { return selectors[10]; }; - const SelectorType& q_busread() const { return selectors[11]; }; - const SelectorType& q_poseidon2_external() const { return this->selectors[12]; }; - const SelectorType& q_poseidon2_internal() const { return this->selectors[13]; }; - - auto& get() { return selectors; }; - - void reserve(size_t size_hint) - { - for (auto& vec : selectors) { - vec.reserve(size_hint); + class UltraHonkTraceBlock : public ExecutionTraceBlock { + public: + void populate_wires(const uint32_t& idx_1, const uint32_t& idx_2, const uint32_t& idx_3, const uint32_t& idx_4) + { + this->wires[0].emplace_back(idx_1); + this->wires[1].emplace_back(idx_2); + this->wires[2].emplace_back(idx_3); + this->wires[3].emplace_back(idx_4); } - } - /** - * @brief Add zeros to all selectors which are not part of the conventional Ultra arithmetization - * @details Facilitates reuse of Ultra gate construction functions in arithmetizations which extend the conventional - * Ultra arithmetization - * - */ - void pad_additional() - { - q_busread().emplace_back(0); - q_poseidon2_external().emplace_back(0); - q_poseidon2_internal().emplace_back(0); + auto& w_l() { return std::get<0>(this->wires); }; + auto& w_r() { return std::get<1>(this->wires); }; + auto& w_o() { return std::get<2>(this->wires); }; + auto& w_4() { return std::get<3>(this->wires); }; + + auto& q_m() { return this->selectors[0]; }; + auto& q_c() { return this->selectors[1]; }; + auto& q_1() { return this->selectors[2]; }; + auto& q_2() { return this->selectors[3]; }; + auto& q_3() { return this->selectors[4]; }; + auto& q_4() { return this->selectors[5]; }; + auto& q_arith() { return this->selectors[6]; }; + auto& q_sort() { return this->selectors[7]; }; + auto& q_elliptic() { return this->selectors[8]; }; + auto& q_aux() { return this->selectors[9]; }; + auto& q_lookup_type() { return this->selectors[10]; }; + auto& q_busread() { return this->selectors[11]; }; + auto& q_poseidon2_external() { return this->selectors[12]; }; + auto& q_poseidon2_internal() { return this->selectors[13]; }; + + /** + * @brief Add zeros to all selectors which are not part of the conventional Ultra arithmetization + * @details Facilitates reuse of Ultra gate construction functions in arithmetizations which extend the + * conventional Ultra arithmetization + * + */ + void pad_additional() + { + q_busread().emplace_back(0); + q_poseidon2_external().emplace_back(0); + q_poseidon2_internal().emplace_back(0); + }; + + /** + * @brief Resizes all selectors which are not part of the conventional Ultra arithmetization + * @details Facilitates reuse of Ultra gate construction functions in arithmetizations which extend the + * conventional Ultra arithmetization + * @param new_size + */ + void resize_additional(size_t new_size) + { + q_busread().resize(new_size); + q_poseidon2_external().resize(new_size); + q_poseidon2_internal().resize(new_size); + }; }; - /** - * @brief Resizes all selectors which are not part of the conventional Ultra arithmetization - * @details Facilitates reuse of Ultra gate construction functions in arithmetizations which extend the conventional - * Ultra arithmetization - * @param new_size - */ - void resize_additional(size_t new_size) - { - q_busread().resize(new_size); - q_poseidon2_external().resize(new_size); - q_poseidon2_internal().resize(new_size); + struct TraceBlocks { + UltraHonkTraceBlock ecc_op; + UltraHonkTraceBlock pub_inputs; + UltraHonkTraceBlock main; + + auto get() { return RefArray{ ecc_op, pub_inputs, main }; } + + bool operator==(const TraceBlocks& other) const = default; }; // Note: Unused. Needed only for consistency with Ultra arith (which is used by Plonk) diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp index 5231f1cad23..b4b188ee856 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp @@ -67,6 +67,8 @@ template class CircuitBuilderBase { CircuitBuilderBase& operator=(CircuitBuilderBase&& other) noexcept = default; virtual ~CircuitBuilderBase() = default; + bool operator==(const CircuitBuilderBase& other) const = default; + virtual size_t get_num_gates() const { return num_gates; } virtual void print_num_gates() const { std::cout << num_gates << std::endl; } virtual size_t get_num_variables() const { return variables.size(); } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index be0aa89d1b1..8bb941d88ca 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -42,47 +42,41 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ calldata_read_counts[raw_read_idx]++; // mock gates that use poseidon selectors, with all zeros as input - this->w_l().emplace_back(this->zero_idx); - this->w_r().emplace_back(this->zero_idx); - this->w_o().emplace_back(this->zero_idx); - this->w_4().emplace_back(this->zero_idx); - this->q_m().emplace_back(0); - this->q_1().emplace_back(0); - this->q_2().emplace_back(0); - this->q_3().emplace_back(0); - this->q_c().emplace_back(0); - this->q_arith().emplace_back(0); - this->q_4().emplace_back(0); - this->q_sort().emplace_back(0); - this->q_lookup_type().emplace_back(0); - this->q_elliptic().emplace_back(0); - this->q_aux().emplace_back(0); - this->q_busread().emplace_back(0); - this->q_poseidon2_external().emplace_back(1); - this->q_poseidon2_internal().emplace_back(1); + this->blocks.main.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + this->blocks.main.q_m().emplace_back(0); + this->blocks.main.q_1().emplace_back(0); + this->blocks.main.q_2().emplace_back(0); + this->blocks.main.q_3().emplace_back(0); + this->blocks.main.q_c().emplace_back(0); + this->blocks.main.q_arith().emplace_back(0); + this->blocks.main.q_4().emplace_back(0); + this->blocks.main.q_sort().emplace_back(0); + this->blocks.main.q_lookup_type().emplace_back(0); + this->blocks.main.q_elliptic().emplace_back(0); + this->blocks.main.q_aux().emplace_back(0); + this->blocks.main.q_busread().emplace_back(0); + this->blocks.main.q_poseidon2_external().emplace_back(1); + this->blocks.main.q_poseidon2_internal().emplace_back(1); this->check_selector_length_consistency(); ++this->num_gates; // second gate that stores the output of all zeros of the poseidon gates - this->w_l().emplace_back(this->zero_idx); - this->w_r().emplace_back(this->zero_idx); - this->w_o().emplace_back(this->zero_idx); - this->w_4().emplace_back(this->zero_idx); - this->q_m().emplace_back(0); - this->q_1().emplace_back(0); - this->q_2().emplace_back(0); - this->q_3().emplace_back(0); - this->q_c().emplace_back(0); - this->q_arith().emplace_back(0); - this->q_4().emplace_back(0); - this->q_sort().emplace_back(0); - this->q_lookup_type().emplace_back(0); - this->q_elliptic().emplace_back(0); - this->q_aux().emplace_back(0); - this->q_busread().emplace_back(0); - this->q_poseidon2_external().emplace_back(0); - this->q_poseidon2_internal().emplace_back(0); + this->blocks.main.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + this->blocks.main.q_m().emplace_back(0); + this->blocks.main.q_1().emplace_back(0); + this->blocks.main.q_2().emplace_back(0); + this->blocks.main.q_3().emplace_back(0); + this->blocks.main.q_c().emplace_back(0); + this->blocks.main.q_arith().emplace_back(0); + this->blocks.main.q_4().emplace_back(0); + this->blocks.main.q_sort().emplace_back(0); + this->blocks.main.q_lookup_type().emplace_back(0); + this->blocks.main.q_elliptic().emplace_back(0); + this->blocks.main.q_aux().emplace_back(0); + this->blocks.main.q_busread().emplace_back(0); + this->blocks.main.q_poseidon2_external().emplace_back(0); + this->blocks.main.q_poseidon2_internal().emplace_back(0); this->check_selector_length_consistency(); ++this->num_gates; @@ -207,19 +201,13 @@ ecc_op_tuple GoblinUltraCircuitBuilder_::decompose_ecc_operands(uint32_t op_ */ template void GoblinUltraCircuitBuilder_::populate_ecc_op_wires(const ecc_op_tuple& in) { - ecc_op_wire_1().emplace_back(in.op); - ecc_op_wire_2().emplace_back(in.x_lo); - ecc_op_wire_3().emplace_back(in.x_hi); - ecc_op_wire_4().emplace_back(in.y_lo); - for (auto& selector : ecc_op_block.selectors.get()) { + this->blocks.ecc_op.populate_wires(in.op, in.x_lo, in.x_hi, in.y_lo); + for (auto& selector : this->blocks.ecc_op.selectors) { selector.emplace_back(0); } - ecc_op_wire_1().emplace_back(this->zero_idx); - ecc_op_wire_2().emplace_back(in.y_hi); - ecc_op_wire_3().emplace_back(in.z_1); - ecc_op_wire_4().emplace_back(in.z_2); - for (auto& selector : ecc_op_block.selectors.get()) { + this->blocks.ecc_op.populate_wires(this->zero_idx, in.y_hi, in.z_1, in.z_2); + for (auto& selector : this->blocks.ecc_op.selectors) { selector.emplace_back(0); } @@ -243,26 +231,23 @@ template void GoblinUltraCircuitBuilder_::set_goblin_ecc_op_co template void GoblinUltraCircuitBuilder_::create_calldata_lookup_gate(const databus_lookup_gate_& in) { - this->w_l().emplace_back(in.value); - this->w_r().emplace_back(in.index); - q_busread().emplace_back(1); + this->blocks.main.populate_wires(in.value, in.index, this->zero_idx, this->zero_idx); + this->blocks.main.q_busread().emplace_back(1); // populate all other components with zero - this->w_o().emplace_back(this->zero_idx); - this->w_4().emplace_back(this->zero_idx); - this->q_m().emplace_back(0); - this->q_1().emplace_back(0); - this->q_2().emplace_back(0); - this->q_3().emplace_back(0); - this->q_c().emplace_back(0); - this->q_sort().emplace_back(0); - this->q_arith().emplace_back(0); - this->q_4().emplace_back(0); - this->q_lookup_type().emplace_back(0); - this->q_elliptic().emplace_back(0); - this->q_aux().emplace_back(0); - this->q_poseidon2_external().emplace_back(0); - this->q_poseidon2_internal().emplace_back(0); + this->blocks.main.q_m().emplace_back(0); + this->blocks.main.q_1().emplace_back(0); + this->blocks.main.q_2().emplace_back(0); + this->blocks.main.q_3().emplace_back(0); + this->blocks.main.q_c().emplace_back(0); + this->blocks.main.q_sort().emplace_back(0); + this->blocks.main.q_arith().emplace_back(0); + this->blocks.main.q_4().emplace_back(0); + this->blocks.main.q_lookup_type().emplace_back(0); + this->blocks.main.q_elliptic().emplace_back(0); + this->blocks.main.q_aux().emplace_back(0); + this->blocks.main.q_poseidon2_external().emplace_back(0); + this->blocks.main.q_poseidon2_internal().emplace_back(0); this->check_selector_length_consistency(); ++this->num_gates; @@ -274,24 +259,21 @@ void GoblinUltraCircuitBuilder_::create_calldata_lookup_gate(const databus_l template void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseidon2_external_gate_& in) { - this->w_l().emplace_back(in.a); - this->w_r().emplace_back(in.b); - this->w_o().emplace_back(in.c); - this->w_4().emplace_back(in.d); - this->q_m().emplace_back(0); - this->q_1().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][0]); - this->q_2().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][1]); - this->q_3().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][2]); - this->q_c().emplace_back(0); - this->q_arith().emplace_back(0); - this->q_4().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][3]); - this->q_sort().emplace_back(0); - this->q_lookup_type().emplace_back(0); - this->q_elliptic().emplace_back(0); - this->q_aux().emplace_back(0); - this->q_busread().emplace_back(0); - this->q_poseidon2_external().emplace_back(1); - this->q_poseidon2_internal().emplace_back(0); + this->blocks.main.populate_wires(in.a, in.b, in.c, in.d); + this->blocks.main.q_m().emplace_back(0); + this->blocks.main.q_1().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][0]); + this->blocks.main.q_2().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][1]); + this->blocks.main.q_3().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][2]); + this->blocks.main.q_c().emplace_back(0); + this->blocks.main.q_arith().emplace_back(0); + this->blocks.main.q_4().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][3]); + this->blocks.main.q_sort().emplace_back(0); + this->blocks.main.q_lookup_type().emplace_back(0); + this->blocks.main.q_elliptic().emplace_back(0); + this->blocks.main.q_aux().emplace_back(0); + this->blocks.main.q_busread().emplace_back(0); + this->blocks.main.q_poseidon2_external().emplace_back(1); + this->blocks.main.q_poseidon2_internal().emplace_back(0); this->check_selector_length_consistency(); ++this->num_gates; } @@ -302,24 +284,21 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseid template void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseidon2_internal_gate_& in) { - this->w_l().emplace_back(in.a); - this->w_r().emplace_back(in.b); - this->w_o().emplace_back(in.c); - this->w_4().emplace_back(in.d); - this->q_m().emplace_back(0); - this->q_1().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][0]); - this->q_2().emplace_back(0); - this->q_3().emplace_back(0); - this->q_c().emplace_back(0); - this->q_arith().emplace_back(0); - this->q_4().emplace_back(0); - this->q_sort().emplace_back(0); - this->q_lookup_type().emplace_back(0); - this->q_elliptic().emplace_back(0); - this->q_aux().emplace_back(0); - this->q_busread().emplace_back(0); - this->q_poseidon2_external().emplace_back(0); - this->q_poseidon2_internal().emplace_back(1); + this->blocks.main.populate_wires(in.a, in.b, in.c, in.d); + this->blocks.main.q_m().emplace_back(0); + this->blocks.main.q_1().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][0]); + this->blocks.main.q_2().emplace_back(0); + this->blocks.main.q_3().emplace_back(0); + this->blocks.main.q_c().emplace_back(0); + this->blocks.main.q_arith().emplace_back(0); + this->blocks.main.q_4().emplace_back(0); + this->blocks.main.q_sort().emplace_back(0); + this->blocks.main.q_lookup_type().emplace_back(0); + this->blocks.main.q_elliptic().emplace_back(0); + this->blocks.main.q_aux().emplace_back(0); + this->blocks.main.q_busread().emplace_back(0); + this->blocks.main.q_poseidon2_external().emplace_back(0); + this->blocks.main.q_poseidon2_internal().emplace_back(1); this->check_selector_length_consistency(); ++this->num_gates; } @@ -333,24 +312,21 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid */ template void GoblinUltraCircuitBuilder_::create_poseidon2_end_gate(const poseidon2_end_gate_& in) { - this->w_l().emplace_back(in.a); - this->w_r().emplace_back(in.b); - this->w_o().emplace_back(in.c); - this->w_4().emplace_back(in.d); - this->q_m().emplace_back(0); - this->q_1().emplace_back(0); - this->q_2().emplace_back(0); - this->q_3().emplace_back(0); - this->q_c().emplace_back(0); - this->q_arith().emplace_back(0); - this->q_4().emplace_back(0); - this->q_sort().emplace_back(0); - this->q_lookup_type().emplace_back(0); - this->q_elliptic().emplace_back(0); - this->q_aux().emplace_back(0); - this->q_busread().emplace_back(0); - this->q_poseidon2_external().emplace_back(0); - this->q_poseidon2_internal().emplace_back(0); + this->blocks.main.populate_wires(in.a, in.b, in.c, in.d); + this->blocks.main.q_m().emplace_back(0); + this->blocks.main.q_1().emplace_back(0); + this->blocks.main.q_2().emplace_back(0); + this->blocks.main.q_3().emplace_back(0); + this->blocks.main.q_c().emplace_back(0); + this->blocks.main.q_arith().emplace_back(0); + this->blocks.main.q_4().emplace_back(0); + this->blocks.main.q_sort().emplace_back(0); + this->blocks.main.q_lookup_type().emplace_back(0); + this->blocks.main.q_elliptic().emplace_back(0); + this->blocks.main.q_aux().emplace_back(0); + this->blocks.main.q_busread().emplace_back(0); + this->blocks.main.q_poseidon2_external().emplace_back(0); + this->blocks.main.q_poseidon2_internal().emplace_back(0); this->check_selector_length_consistency(); ++this->num_gates; } @@ -481,25 +457,25 @@ template bool GoblinUltraCircuitBuilder_::check_circuit() FF w_3_value; FF w_4_value; // Get the values of selectors and wires and update tag products along the way - q_poseidon2_external_value = this->q_poseidon2_external()[i]; - q_poseidon2_internal_value = this->q_poseidon2_internal()[i]; - q_1_value = this->q_1()[i]; - q_2_value = this->q_2()[i]; - q_3_value = this->q_3()[i]; - q_4_value = this->q_4()[i]; - w_1_value = this->get_variable(this->w_l()[i]); - w_2_value = this->get_variable(this->w_r()[i]); - w_3_value = this->get_variable(this->w_o()[i]); - w_4_value = this->get_variable(this->w_4()[i]); + q_poseidon2_external_value = this->blocks.main.q_poseidon2_external()[i]; + q_poseidon2_internal_value = this->blocks.main.q_poseidon2_internal()[i]; + q_1_value = this->blocks.main.q_1()[i]; + q_2_value = this->blocks.main.q_2()[i]; + q_3_value = this->blocks.main.q_3()[i]; + q_4_value = this->blocks.main.q_4()[i]; + w_1_value = this->get_variable(this->blocks.main.w_l()[i]); + w_2_value = this->get_variable(this->blocks.main.w_r()[i]); + w_3_value = this->get_variable(this->blocks.main.w_o()[i]); + w_4_value = this->get_variable(this->blocks.main.w_4()[i]); FF w_1_shifted_value; FF w_2_shifted_value; FF w_3_shifted_value; FF w_4_shifted_value; if (i < (this->num_gates - 1)) { - w_1_shifted_value = this->get_variable(this->w_l()[i + 1]); - w_2_shifted_value = this->get_variable(this->w_r()[i + 1]); - w_3_shifted_value = this->get_variable(this->w_o()[i + 1]); - w_4_shifted_value = this->get_variable(this->w_4()[i + 1]); + w_1_shifted_value = this->get_variable(this->blocks.main.w_l()[i + 1]); + w_2_shifted_value = this->get_variable(this->blocks.main.w_r()[i + 1]); + w_3_shifted_value = this->get_variable(this->blocks.main.w_o()[i + 1]); + w_4_shifted_value = this->get_variable(this->blocks.main.w_4()[i + 1]); } else { w_1_shifted_value = FF::zero(); w_2_shifted_value = FF::zero(); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp index 22e707f5b35..58f38dd6807 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp @@ -11,7 +11,6 @@ using namespace bb; template class GoblinUltraCircuitBuilder_ : public UltraCircuitBuilder_> { public: using Arithmetization = UltraHonkArith; - using TraceBlock = ExecutionTraceBlock; static constexpr std::string_view NAME_STRING = "GoblinUltraArithmetization"; static constexpr CircuitType CIRCUIT_TYPE = CircuitType::ULTRA; @@ -29,30 +28,6 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui uint32_t mul_accum_op_idx; uint32_t equality_op_idx; - using WireVector = std::vector>; - using SelectorVector = std::vector>; - - // Execution trace block for goblin ecc op gates - TraceBlock ecc_op_block; - - WireVector& ecc_op_wire_1() { return std::get<0>(ecc_op_block.wires); }; - WireVector& ecc_op_wire_2() { return std::get<1>(ecc_op_block.wires); }; - WireVector& ecc_op_wire_3() { return std::get<2>(ecc_op_block.wires); }; - WireVector& ecc_op_wire_4() { return std::get<3>(ecc_op_block.wires); }; - - const WireVector& ecc_op_wire_1() const { return std::get<0>(ecc_op_block.wires); }; - const WireVector& ecc_op_wire_2() const { return std::get<1>(ecc_op_block.wires); }; - const WireVector& ecc_op_wire_3() const { return std::get<2>(ecc_op_block.wires); }; - const WireVector& ecc_op_wire_4() const { return std::get<3>(ecc_op_block.wires); }; - - SelectorVector& q_busread() { return this->selectors.q_busread(); }; - SelectorVector& q_poseidon2_external() { return this->selectors.q_poseidon2_external(); }; - SelectorVector& q_poseidon2_internal() { return this->selectors.q_poseidon2_internal(); }; - - const SelectorVector& q_busread() const { return this->selectors.q_busread(); }; - const SelectorVector& q_poseidon2_external() const { return this->selectors.q_poseidon2_external(); }; - const SelectorVector& q_poseidon2_internal() const { return this->selectors.q_poseidon2_internal(); }; - // DataBus call/return data arrays std::vector public_calldata; std::vector calldata_read_counts; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.test.cpp index 766686501ae..0c8db203f1d 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.test.cpp @@ -44,8 +44,7 @@ TEST(GoblinUltraCircuitBuilder, CopyConstructor) GoblinUltraCircuitBuilder duplicate_circuit_constructor{ circuit_constructor }; - EXPECT_EQ(duplicate_circuit_constructor.get_num_gates(), circuit_constructor.get_num_gates()); - EXPECT_EQ(duplicate_circuit_constructor.selectors.get(), circuit_constructor.selectors.get()); + EXPECT_EQ(duplicate_circuit_constructor, circuit_constructor); EXPECT_TRUE(duplicate_circuit_constructor.check_circuit()); } @@ -102,27 +101,27 @@ TEST(GoblinUltraCircuitBuilder, GoblinSimple) EXPECT_EQ(builder.num_ecc_op_gates, 6); // Check that the expected op codes have been correctly recorded in the 1st op wire - EXPECT_EQ(builder.ecc_op_wire_1()[0], EccOpCode::ADD_ACCUM); - EXPECT_EQ(builder.ecc_op_wire_1()[2], EccOpCode::MUL_ACCUM); - EXPECT_EQ(builder.ecc_op_wire_1()[4], EccOpCode::EQUALITY); + EXPECT_EQ(builder.blocks.ecc_op.w_l()[0], EccOpCode::ADD_ACCUM); + EXPECT_EQ(builder.blocks.ecc_op.w_l()[2], EccOpCode::MUL_ACCUM); + EXPECT_EQ(builder.blocks.ecc_op.w_l()[4], EccOpCode::EQUALITY); // Check that we can reconstruct the coordinates of P1 from the op_wires - auto P1_x_lo = uint256_t(builder.variables[builder.ecc_op_wire_2()[0]]); - auto P1_x_hi = uint256_t(builder.variables[builder.ecc_op_wire_3()[0]]); + auto P1_x_lo = uint256_t(builder.variables[builder.blocks.ecc_op.w_r()[0]]); + auto P1_x_hi = uint256_t(builder.variables[builder.blocks.ecc_op.w_o()[0]]); auto P1_x = P1_x_lo + (P1_x_hi << CHUNK_SIZE); EXPECT_EQ(P1_x, uint256_t(P1.x)); - auto P1_y_lo = uint256_t(builder.variables[builder.ecc_op_wire_4()[0]]); - auto P1_y_hi = uint256_t(builder.variables[builder.ecc_op_wire_2()[1]]); + auto P1_y_lo = uint256_t(builder.variables[builder.blocks.ecc_op.w_4()[0]]); + auto P1_y_hi = uint256_t(builder.variables[builder.blocks.ecc_op.w_r()[1]]); auto P1_y = P1_y_lo + (P1_y_hi << CHUNK_SIZE); EXPECT_EQ(P1_y, uint256_t(P1.y)); // Check that we can reconstruct the coordinates of P2 from the op_wires - auto P2_x_lo = uint256_t(builder.variables[builder.ecc_op_wire_2()[2]]); - auto P2_x_hi = uint256_t(builder.variables[builder.ecc_op_wire_3()[2]]); + auto P2_x_lo = uint256_t(builder.variables[builder.blocks.ecc_op.w_r()[2]]); + auto P2_x_hi = uint256_t(builder.variables[builder.blocks.ecc_op.w_o()[2]]); auto P2_x = P2_x_lo + (P2_x_hi << CHUNK_SIZE); EXPECT_EQ(P2_x, uint256_t(P2.x)); - auto P2_y_lo = uint256_t(builder.variables[builder.ecc_op_wire_4()[2]]); - auto P2_y_hi = uint256_t(builder.variables[builder.ecc_op_wire_2()[3]]); + auto P2_y_lo = uint256_t(builder.variables[builder.blocks.ecc_op.w_4()[2]]); + auto P2_y_hi = uint256_t(builder.variables[builder.blocks.ecc_op.w_r()[3]]); auto P2_y = P2_y_lo + (P2_y_hi << CHUNK_SIZE); EXPECT_EQ(P2_y, uint256_t(P2.y)); } @@ -150,7 +149,7 @@ TEST(GoblinUltraCircuitBuilder, GoblinEccOpQueueUltraOps) auto ultra_ops = builder.op_queue->get_aggregate_transcript(); for (size_t i = 1; i < 4; ++i) { for (size_t j = 0; j < builder.num_ecc_op_gates; ++j) { - auto op_wire_val = builder.variables[builder.ecc_op_block.wires[i][j]]; + auto op_wire_val = builder.variables[builder.blocks.ecc_op.wires[i][j]]; auto ultra_op_val = ultra_ops[i][j]; ASSERT_EQ(op_wire_val, ultra_op_val); } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp index e3a7478aa68..a3dcd7213bc 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp @@ -13,20 +13,18 @@ namespace bb { * Create an addition gate. * * @param in An add_triple containing the indexes of variables to be placed into the - * wires w_l, w_r, w_o and addition coefficients to be placed into q_1, q_2, q_3, q_c(). + * wires w_l, w_r, w_o and addition coefficients to be placed into q_1, q_2, q_3, q_c. */ template void StandardCircuitBuilder_::create_add_gate(const add_triple_& in) { this->assert_valid_variables({ in.a, in.b, in.c }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - q_m().emplace_back(FF::zero()); - q_1().emplace_back(in.a_scaling); - q_2().emplace_back(in.b_scaling); - q_3().emplace_back(in.c_scaling); - q_c().emplace_back(in.const_scaling); + blocks.arithmetic.populate_wires(in.a, in.b, in.c); + blocks.arithmetic.q_m().emplace_back(FF::zero()); + blocks.arithmetic.q_1().emplace_back(in.a_scaling); + blocks.arithmetic.q_2().emplace_back(in.b_scaling); + blocks.arithmetic.q_3().emplace_back(in.c_scaling); + blocks.arithmetic.q_c().emplace_back(in.const_scaling); ++this->num_gates; } @@ -70,25 +68,21 @@ template void StandardCircuitBuilder_::create_balanced_add_gat FF temp = t0 + t1; uint32_t temp_idx = this->add_variable(temp); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(temp_idx); - q_m().emplace_back(FF::zero()); - q_1().emplace_back(in.a_scaling); - q_2().emplace_back(in.b_scaling); - q_3().emplace_back(FF::neg_one()); - q_c().emplace_back(FF::zero()); + blocks.arithmetic.populate_wires(in.a, in.b, temp_idx); + blocks.arithmetic.q_m().emplace_back(FF::zero()); + blocks.arithmetic.q_1().emplace_back(in.a_scaling); + blocks.arithmetic.q_2().emplace_back(in.b_scaling); + blocks.arithmetic.q_3().emplace_back(FF::neg_one()); + blocks.arithmetic.q_c().emplace_back(FF::zero()); ++this->num_gates; - w_l().emplace_back(temp_idx); - w_r().emplace_back(in.c); - w_o().emplace_back(in.d); - q_m().emplace_back(FF::zero()); - q_1().emplace_back(FF::one()); - q_2().emplace_back(in.c_scaling); - q_3().emplace_back(in.d_scaling); - q_c().emplace_back(in.const_scaling); + blocks.arithmetic.populate_wires(temp_idx, in.c, in.d); + blocks.arithmetic.q_m().emplace_back(FF::zero()); + blocks.arithmetic.q_1().emplace_back(FF::one()); + blocks.arithmetic.q_2().emplace_back(in.c_scaling); + blocks.arithmetic.q_3().emplace_back(in.d_scaling); + blocks.arithmetic.q_c().emplace_back(in.const_scaling); ++this->num_gates; @@ -96,26 +90,22 @@ template void StandardCircuitBuilder_::create_balanced_add_gat // i.e. in.d * (in.d - 1) * (in.d - 2) = 0 FF temp_2 = this->get_variable(in.d).sqr() - this->get_variable(in.d); uint32_t temp_2_idx = this->add_variable(temp_2); - w_l().emplace_back(in.d); - w_r().emplace_back(in.d); - w_o().emplace_back(temp_2_idx); - q_m().emplace_back(FF::one()); - q_1().emplace_back(FF::neg_one()); - q_2().emplace_back(FF::zero()); - q_3().emplace_back(FF::neg_one()); - q_c().emplace_back(FF::zero()); + blocks.arithmetic.populate_wires(in.d, in.d, temp_2_idx); + blocks.arithmetic.q_m().emplace_back(FF::one()); + blocks.arithmetic.q_1().emplace_back(FF::neg_one()); + blocks.arithmetic.q_2().emplace_back(FF::zero()); + blocks.arithmetic.q_3().emplace_back(FF::neg_one()); + blocks.arithmetic.q_c().emplace_back(FF::zero()); ++this->num_gates; constexpr FF neg_two = -FF(2); - w_l().emplace_back(temp_2_idx); - w_r().emplace_back(in.d); - w_o().emplace_back(this->zero_idx); - q_m().emplace_back(FF::one()); - q_1().emplace_back(neg_two); - q_2().emplace_back(FF::zero()); - q_3().emplace_back(FF::zero()); - q_c().emplace_back(FF::zero()); + blocks.arithmetic.populate_wires(temp_2_idx, in.d, this->zero_idx); + blocks.arithmetic.q_m().emplace_back(FF::one()); + blocks.arithmetic.q_1().emplace_back(neg_two); + blocks.arithmetic.q_2().emplace_back(FF::zero()); + blocks.arithmetic.q_3().emplace_back(FF::zero()); + blocks.arithmetic.q_c().emplace_back(FF::zero()); ++this->num_gates; } @@ -179,20 +169,18 @@ template void StandardCircuitBuilder_::create_big_mul_gate(con * Create a multiplication gate. * * @param in A mul_tripple containing the indexes of variables to be placed into the - * wires w_l, w_r, w_o and scaling coefficients to be placed into q_m, q_3, q_c(). + * wires w_l, w_r, w_o and scaling coefficients to be placed into q_m, q_3, blocks.arithmetic.q_c(). */ template void StandardCircuitBuilder_::create_mul_gate(const mul_triple_& in) { this->assert_valid_variables({ in.a, in.b, in.c }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - q_m().emplace_back(in.mul_scaling); - q_1().emplace_back(FF::zero()); - q_2().emplace_back(FF::zero()); - q_3().emplace_back(in.c_scaling); - q_c().emplace_back(in.const_scaling); + blocks.arithmetic.populate_wires(in.a, in.b, in.c); + blocks.arithmetic.q_m().emplace_back(in.mul_scaling); + blocks.arithmetic.q_1().emplace_back(FF::zero()); + blocks.arithmetic.q_2().emplace_back(FF::zero()); + blocks.arithmetic.q_3().emplace_back(in.c_scaling); + blocks.arithmetic.q_c().emplace_back(in.const_scaling); ++this->num_gates; } @@ -207,15 +195,12 @@ template void StandardCircuitBuilder_::create_bool_gate(const { this->assert_valid_variables({ variable_index }); - w_l().emplace_back(variable_index); - w_r().emplace_back(variable_index); - w_o().emplace_back(variable_index); - - q_m().emplace_back(FF::one()); - q_1().emplace_back(FF::zero()); - q_2().emplace_back(FF::zero()); - q_3().emplace_back(FF::neg_one()); - q_c().emplace_back(FF::zero()); + blocks.arithmetic.populate_wires(variable_index, variable_index, variable_index); + blocks.arithmetic.q_m().emplace_back(FF::one()); + blocks.arithmetic.q_1().emplace_back(FF::zero()); + blocks.arithmetic.q_2().emplace_back(FF::zero()); + blocks.arithmetic.q_3().emplace_back(FF::neg_one()); + blocks.arithmetic.q_c().emplace_back(FF::zero()); ++this->num_gates; } @@ -229,14 +214,12 @@ template void StandardCircuitBuilder_::create_poly_gate(const { this->assert_valid_variables({ in.a, in.b, in.c }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - q_m().emplace_back(in.q_m); - q_1().emplace_back(in.q_l); - q_2().emplace_back(in.q_r); - q_3().emplace_back(in.q_o); - q_c().emplace_back(in.q_c); + blocks.arithmetic.populate_wires(in.a, in.b, in.c); + blocks.arithmetic.q_m().emplace_back(in.q_m); + blocks.arithmetic.q_1().emplace_back(in.q_l); + blocks.arithmetic.q_2().emplace_back(in.q_r); + blocks.arithmetic.q_3().emplace_back(in.q_o); + blocks.arithmetic.q_c().emplace_back(in.q_c); ++this->num_gates; } @@ -482,14 +465,12 @@ void StandardCircuitBuilder_::fix_witness(const uint32_t witness_index, cons { this->assert_valid_variables({ witness_index }); - w_l().emplace_back(witness_index); - w_r().emplace_back(this->zero_idx); - w_o().emplace_back(this->zero_idx); - q_m().emplace_back(FF::zero()); - q_1().emplace_back(FF::one()); - q_2().emplace_back(FF::zero()); - q_3().emplace_back(FF::zero()); - q_c().emplace_back(-witness_value); + blocks.arithmetic.populate_wires(witness_index, this->zero_idx, this->zero_idx); + blocks.arithmetic.q_m().emplace_back(FF::zero()); + blocks.arithmetic.q_1().emplace_back(FF::one()); + blocks.arithmetic.q_2().emplace_back(FF::zero()); + blocks.arithmetic.q_3().emplace_back(FF::zero()); + blocks.arithmetic.q_c().emplace_back(-witness_value); ++this->num_gates; } @@ -546,10 +527,12 @@ template bool StandardCircuitBuilder_::check_circuit() for (size_t i = 0; i < this->num_gates; i++) { gate_sum = FF::zero(); - left = this->get_variable(w_l()[i]); - right = this->get_variable(w_r()[i]); - output = this->get_variable(w_o()[i]); - gate_sum = q_m()[i] * left * right + q_1()[i] * left + q_2()[i] * right + q_3()[i] * output + q_c()[i]; + left = this->get_variable(blocks.arithmetic.w_l()[i]); + right = this->get_variable(blocks.arithmetic.w_r()[i]); + output = this->get_variable(blocks.arithmetic.w_o()[i]); + gate_sum = blocks.arithmetic.q_m()[i] * left * right + blocks.arithmetic.q_1()[i] * left + + blocks.arithmetic.q_2()[i] * right + blocks.arithmetic.q_3()[i] * output + + blocks.arithmetic.q_c()[i]; if (!gate_sum.is_zero()) { info("gate number", i); return false; @@ -590,11 +573,15 @@ template msgpack::sbuffer StandardCircuitBuilder_::export_circ } for (size_t i = 0; i < this->num_gates; i++) { - std::vector tmp_sel = { q_m()[i], q_1()[i], q_2()[i], q_3()[i], q_c()[i] }; + std::vector tmp_sel = { blocks.arithmetic.q_m()[i], + blocks.arithmetic.q_1()[i], + blocks.arithmetic.q_2()[i], + blocks.arithmetic.q_3()[i], + blocks.arithmetic.q_c()[i] }; std::vector tmp_w = { - this->real_variable_index[w_l()[i]], - this->real_variable_index[w_r()[i]], - this->real_variable_index[w_o()[i]], + this->real_variable_index[blocks.arithmetic.w_l()[i]], + this->real_variable_index[blocks.arithmetic.w_r()[i]], + this->real_variable_index[blocks.arithmetic.w_o()[i]], }; cir.selectors.push_back(tmp_sel); cir.wires.push_back(tmp_w); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp index 77c3e87e94a..32386b388a7 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp @@ -1,6 +1,7 @@ #pragma once #include "barretenberg/ecc/curves/bn254/bn254.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" +#include "barretenberg/proof_system/execution_trace/execution_trace.hpp" #include "barretenberg/proof_system/types/circuit_type.hpp" #include "barretenberg/proof_system/types/merkle_hash_type.hpp" #include "barretenberg/proof_system/types/pedersen_commitment_type.hpp" @@ -12,7 +13,7 @@ namespace bb { template class StandardCircuitBuilder_ : public CircuitBuilderBase { public: using Arithmetization = StandardArith; - using Selectors = Arithmetization; + using GateBlocks = typename Arithmetization::TraceBlocks; static constexpr size_t NUM_WIRES = Arithmetization::NUM_WIRES; // Keeping NUM_WIRES, at least temporarily, for backward compatibility static constexpr size_t program_width = Arithmetization::NUM_WIRES; @@ -24,31 +25,8 @@ template class StandardCircuitBuilder_ : public CircuitBuilderBase static constexpr merkle::HashType merkle_hash_type = merkle::HashType::FIXED_BASE_PEDERSEN; static constexpr pedersen::CommitmentType commitment_type = pedersen::CommitmentType::FIXED_BASE_PEDERSEN; - std::array>, NUM_WIRES> wires; - Arithmetization selectors; - - using WireVector = std::vector>; - using SelectorVector = std::vector>; - - WireVector& w_l() { return std::get<0>(wires); }; - WireVector& w_r() { return std::get<1>(wires); }; - WireVector& w_o() { return std::get<2>(wires); }; - - const WireVector& w_l() const { return std::get<0>(wires); }; - const WireVector& w_r() const { return std::get<1>(wires); }; - const WireVector& w_o() const { return std::get<2>(wires); }; - - SelectorVector& q_m() { return this->selectors.q_m(); }; - SelectorVector& q_1() { return this->selectors.q_1(); }; - SelectorVector& q_2() { return this->selectors.q_2(); }; - SelectorVector& q_3() { return this->selectors.q_3(); }; - SelectorVector& q_c() { return this->selectors.q_c(); }; - - const SelectorVector& q_m() const { return this->selectors.q_m(); }; - const SelectorVector& q_1() const { return this->selectors.q_1(); }; - const SelectorVector& q_2() const { return this->selectors.q_2(); }; - const SelectorVector& q_3() const { return this->selectors.q_3(); }; - const SelectorVector& q_c() const { return this->selectors.q_c(); }; + // Storage for wires and selectors for all gate types + GateBlocks blocks; static constexpr size_t UINT_LOG2_BASE = 2; @@ -60,10 +38,7 @@ template class StandardCircuitBuilder_ : public CircuitBuilderBase StandardCircuitBuilder_(const size_t size_hint = 0) : CircuitBuilderBase(size_hint) { - selectors.reserve(size_hint); - w_l().reserve(size_hint); - w_r().reserve(size_hint); - w_o().reserve(size_hint); + blocks.arithmetic.reserve(size_hint); // To effieciently constrain wires to zero, we set the first value of w_1 to be 0, and use copy constraints for // all future zero values. // (#216)(Adrian): This should be done in a constant way, maybe by initializing the constant_variable_indices @@ -82,8 +57,7 @@ template class StandardCircuitBuilder_ : public CircuitBuilderBase { CircuitBuilderBase::operator=(std::move(other)); constant_variable_indices = other.constant_variable_indices; - wires = other.wires; - selectors = other.selectors; + blocks = other.blocks; return *this; }; ~StandardCircuitBuilder_() override = default; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp index 21aa754edfe..c7c70b7adf0 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp @@ -61,24 +61,21 @@ void UltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_no { // First add a gate to simultaneously ensure first entries of all wires is zero and to add a non // zero value to all selectors aside from q_c and q_lookup - w_l().emplace_back(this->zero_idx); - w_r().emplace_back(this->zero_idx); - w_o().emplace_back(this->zero_idx); - w_4().emplace_back(this->zero_idx); - q_m().emplace_back(1); - q_1().emplace_back(1); - q_2().emplace_back(1); - q_3().emplace_back(1); - q_c().emplace_back(0); - q_sort().emplace_back(1); - - q_arith().emplace_back(1); - q_4().emplace_back(1); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(1); - q_aux().emplace_back(1); + blocks.main.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + blocks.main.q_m().emplace_back(1); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(1); + blocks.main.q_3().emplace_back(1); + blocks.main.q_c().emplace_back(0); + blocks.main.q_sort().emplace_back(1); + + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(1); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(1); + blocks.main.q_aux().emplace_back(1); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -125,23 +122,20 @@ void UltraCircuitBuilder_::create_add_gate(const add_triple_assert_valid_variables({ in.a, in.b, in.c }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - w_4().emplace_back(this->zero_idx); - q_m().emplace_back(0); - q_1().emplace_back(in.a_scaling); - q_2().emplace_back(in.b_scaling); - q_3().emplace_back(in.c_scaling); - q_c().emplace_back(in.const_scaling); - q_arith().emplace_back(1); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(in.a, in.b, in.c, this->zero_idx); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(in.a_scaling); + blocks.main.q_2().emplace_back(in.b_scaling); + blocks.main.q_3().emplace_back(in.c_scaling); + blocks.main.q_c().emplace_back(in.const_scaling); + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -160,23 +154,20 @@ void UltraCircuitBuilder_::create_big_add_gate(const add_quad_< const bool include_next_gate_w_4) { this->assert_valid_variables({ in.a, in.b, in.c, in.d }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - w_4().emplace_back(in.d); - q_m().emplace_back(0); - q_1().emplace_back(in.a_scaling); - q_2().emplace_back(in.b_scaling); - q_3().emplace_back(in.c_scaling); - q_c().emplace_back(in.const_scaling); - q_arith().emplace_back(include_next_gate_w_4 ? 2 : 1); - q_4().emplace_back(in.d_scaling); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(in.a, in.b, in.c, in.d); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(in.a_scaling); + blocks.main.q_2().emplace_back(in.b_scaling); + blocks.main.q_3().emplace_back(in.c_scaling); + blocks.main.q_c().emplace_back(in.const_scaling); + blocks.main.q_arith().emplace_back(include_next_gate_w_4 ? 2 : 1); + blocks.main.q_4().emplace_back(in.d_scaling); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -257,23 +248,20 @@ void UltraCircuitBuilder_::create_big_mul_gate(const mul_quad_< { this->assert_valid_variables({ in.a, in.b, in.c, in.d }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - w_4().emplace_back(in.d); - q_m().emplace_back(in.mul_scaling); - q_1().emplace_back(in.a_scaling); - q_2().emplace_back(in.b_scaling); - q_3().emplace_back(in.c_scaling); - q_c().emplace_back(in.const_scaling); - q_arith().emplace_back(1); - q_4().emplace_back(in.d_scaling); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(in.a, in.b, in.c, in.d); + blocks.main.q_m().emplace_back(in.mul_scaling); + blocks.main.q_1().emplace_back(in.a_scaling); + blocks.main.q_2().emplace_back(in.b_scaling); + blocks.main.q_3().emplace_back(in.c_scaling); + blocks.main.q_c().emplace_back(in.const_scaling); + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(in.d_scaling); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -286,23 +274,20 @@ void UltraCircuitBuilder_::create_balanced_add_gate(const add_q { this->assert_valid_variables({ in.a, in.b, in.c, in.d }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - w_4().emplace_back(in.d); - q_m().emplace_back(0); - q_1().emplace_back(in.a_scaling); - q_2().emplace_back(in.b_scaling); - q_3().emplace_back(in.c_scaling); - q_c().emplace_back(in.const_scaling); - q_arith().emplace_back(1); - q_4().emplace_back(in.d_scaling); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(in.a, in.b, in.c, in.d); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(in.a_scaling); + blocks.main.q_2().emplace_back(in.b_scaling); + blocks.main.q_3().emplace_back(in.c_scaling); + blocks.main.q_c().emplace_back(in.const_scaling); + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(in.d_scaling); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -331,23 +316,20 @@ void UltraCircuitBuilder_::create_mul_gate(const mul_triple_assert_valid_variables({ in.a, in.b, in.c }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - w_4().emplace_back(this->zero_idx); - q_m().emplace_back(in.mul_scaling); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(in.c_scaling); - q_c().emplace_back(in.const_scaling); - q_arith().emplace_back(1); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(in.a, in.b, in.c, this->zero_idx); + blocks.main.q_m().emplace_back(in.mul_scaling); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(in.c_scaling); + blocks.main.q_c().emplace_back(in.const_scaling); + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -362,24 +344,21 @@ void UltraCircuitBuilder_::create_bool_gate(const uint32_t vari { this->assert_valid_variables({ variable_index }); - w_l().emplace_back(variable_index); - w_r().emplace_back(variable_index); - w_o().emplace_back(this->zero_idx); - w_4().emplace_back(this->zero_idx); - q_m().emplace_back(1); - q_1().emplace_back(-1); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_sort().emplace_back(0); - - q_arith().emplace_back(1); - q_4().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(variable_index, variable_index, this->zero_idx, this->zero_idx); + blocks.main.q_m().emplace_back(1); + blocks.main.q_1().emplace_back(-1); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -396,24 +375,21 @@ void UltraCircuitBuilder_::create_poly_gate(const poly_triple_< { this->assert_valid_variables({ in.a, in.b, in.c }); - w_l().emplace_back(in.a); - w_r().emplace_back(in.b); - w_o().emplace_back(in.c); - w_4().emplace_back(this->zero_idx); - q_m().emplace_back(in.q_m); - q_1().emplace_back(in.q_l); - q_2().emplace_back(in.q_r); - q_3().emplace_back(in.q_o); - q_c().emplace_back(in.q_c); - q_sort().emplace_back(0); - - q_arith().emplace_back(1); - q_4().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(in.a, in.b, in.c, this->zero_idx); + blocks.main.q_m().emplace_back(in.q_m); + blocks.main.q_1().emplace_back(in.q_l); + blocks.main.q_2().emplace_back(in.q_r); + blocks.main.q_3().emplace_back(in.q_o); + blocks.main.q_c().emplace_back(in.q_c); + blocks.main.q_sort().emplace_back(0); + + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -441,57 +417,51 @@ void UltraCircuitBuilder_::create_ecc_add_gate(const ecc_add_ga this->assert_valid_variables({ in.x1, in.x2, in.x3, in.y1, in.y2, in.y3 }); bool can_fuse_into_previous_gate = true; - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (w_r()[this->num_gates - 1] == in.x1); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (w_o()[this->num_gates - 1] == in.y1); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (q_3()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (q_4()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (q_1()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (q_arith()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (q_m()[this->num_gates - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.w_r()[this->num_gates - 1] == in.x1); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.w_o()[this->num_gates - 1] == in.y1); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_3()[this->num_gates - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_4()[this->num_gates - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_1()[this->num_gates - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_arith()[this->num_gates - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_m()[this->num_gates - 1] == 0); if (can_fuse_into_previous_gate) { - q_1()[this->num_gates - 1] = in.sign_coefficient; - q_elliptic()[this->num_gates - 1] = 1; + blocks.main.q_1()[this->num_gates - 1] = in.sign_coefficient; + blocks.main.q_elliptic()[this->num_gates - 1] = 1; } else { - w_l().emplace_back(this->zero_idx); - w_r().emplace_back(in.x1); - w_o().emplace_back(in.y1); - w_4().emplace_back(this->zero_idx); - q_3().emplace_back(0); - q_4().emplace_back(0); - q_1().emplace_back(in.sign_coefficient); - - q_arith().emplace_back(0); - q_2().emplace_back(0); - q_m().emplace_back(0); - q_c().emplace_back(0); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(1); - q_aux().emplace_back(0); + blocks.main.populate_wires(this->zero_idx, in.x1, in.y1, this->zero_idx); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_1().emplace_back(in.sign_coefficient); + + blocks.main.q_arith().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(1); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; } - w_l().emplace_back(in.x2); - w_4().emplace_back(in.y2); - w_r().emplace_back(in.x3); - w_o().emplace_back(in.y3); - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(in.x2, in.x3, in.y3, in.y2); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -514,55 +484,50 @@ void UltraCircuitBuilder_::create_ecc_dbl_gate(const ecc_dbl_ga * can also chain double gates together **/ bool can_fuse_into_previous_gate = true; - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (w_r()[this->num_gates - 1] == in.x1); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (w_o()[this->num_gates - 1] == in.y1); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (q_arith()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (q_lookup_type()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (q_aux()[this->num_gates - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.w_r()[this->num_gates - 1] == in.x1); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.w_o()[this->num_gates - 1] == in.y1); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_arith()[this->num_gates - 1] == 0); + can_fuse_into_previous_gate = + can_fuse_into_previous_gate && (blocks.main.q_lookup_type()[this->num_gates - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_aux()[this->num_gates - 1] == 0); if (can_fuse_into_previous_gate) { - q_elliptic()[this->num_gates - 1] = 1; - q_m()[this->num_gates - 1] = 1; + blocks.main.q_elliptic()[this->num_gates - 1] = 1; + blocks.main.q_m()[this->num_gates - 1] = 1; } else { - w_r().emplace_back(in.x1); - w_o().emplace_back(in.y1); - w_l().emplace_back(this->zero_idx); - w_4().emplace_back(this->zero_idx); - q_elliptic().emplace_back(1); - q_m().emplace_back(1); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(this->zero_idx, in.x1, in.y1, this->zero_idx); + blocks.main.q_elliptic().emplace_back(1); + blocks.main.q_m().emplace_back(1); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; } - w_r().emplace_back(in.x3); - w_o().emplace_back(in.y3); - w_l().emplace_back(this->zero_idx); - w_4().emplace_back(this->zero_idx); - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(this->zero_idx, in.x3, in.y3, this->zero_idx); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -579,23 +544,20 @@ void UltraCircuitBuilder_::fix_witness(const uint32_t witness_i { this->assert_valid_variables({ witness_index }); - w_l().emplace_back(witness_index); - w_r().emplace_back(this->zero_idx); - w_o().emplace_back(this->zero_idx); - w_4().emplace_back(this->zero_idx); - q_m().emplace_back(0); - q_1().emplace_back(1); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(-witness_value); - q_arith().emplace_back(1); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.populate_wires(witness_index, this->zero_idx, this->zero_idx, this->zero_idx); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(-witness_value); + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -657,23 +619,20 @@ plookup::ReadData UltraCircuitBuilder_::create_gates_ read_data[plookup::ColumnIdx::C3].push_back(third_idx); this->assert_valid_variables({ first_idx, second_idx, third_idx }); - q_lookup_type().emplace_back(FF(1)); - q_3().emplace_back(FF(table.table_index)); - w_l().emplace_back(first_idx); - w_r().emplace_back(second_idx); - w_o().emplace_back(third_idx); - w_4().emplace_back(this->zero_idx); - q_1().emplace_back(0); - q_2().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_1_step_sizes[i + 1])); - q_m().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_2_step_sizes[i + 1])); - q_c().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_3_step_sizes[i + 1])); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(FF(1)); + blocks.main.q_3().emplace_back(FF(table.table_index)); + blocks.main.populate_wires(first_idx, second_idx, third_idx, this->zero_idx); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_1_step_sizes[i + 1])); + blocks.main.q_m().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_2_step_sizes[i + 1])); + blocks.main.q_c().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_3_step_sizes[i + 1])); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -967,47 +926,43 @@ void UltraCircuitBuilder_::create_sort_constraint(const std::ve this->assert_valid_variables(variable_index); for (size_t i = 0; i < variable_index.size(); i += gate_width) { + blocks.main.populate_wires( + variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]); - w_l().emplace_back(variable_index[i]); - w_r().emplace_back(variable_index[i + 1]); - w_o().emplace_back(variable_index[i + 2]); - w_4().emplace_back(variable_index[i + 3]); ++this->num_gates; - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(1); - q_elliptic().emplace_back(0); - q_lookup_type().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(1); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); } // dummy gate needed because of sort widget's check of next row - w_l().emplace_back(variable_index[variable_index.size() - 1]); - w_r().emplace_back(this->zero_idx); - w_o().emplace_back(this->zero_idx); - w_4().emplace_back(this->zero_idx); + blocks.main.populate_wires( + variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); ++this->num_gates; - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_elliptic().emplace_back(0); - q_lookup_type().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); } @@ -1027,24 +982,21 @@ void UltraCircuitBuilder_::create_dummy_constraints(const std:: this->assert_valid_variables(padded_list); for (size_t i = 0; i < padded_list.size(); i += gate_width) { - w_l().emplace_back(padded_list[i]); - w_r().emplace_back(padded_list[i + 1]); - w_o().emplace_back(padded_list[i + 2]); - w_4().emplace_back(padded_list[i + 3]); + blocks.main.populate_wires(padded_list[i], padded_list[i + 1], padded_list[i + 2], padded_list[i + 3]); ++this->num_gates; - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_elliptic().emplace_back(0); - q_lookup_type().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); } @@ -1061,94 +1013,87 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( this->assert_valid_variables(variable_index); // enforce range checks of first row and starting at start - w_l().emplace_back(variable_index[0]); - w_r().emplace_back(variable_index[1]); - w_o().emplace_back(variable_index[2]); - w_4().emplace_back(variable_index[3]); + blocks.main.populate_wires(variable_index[0], variable_index[1], variable_index[2], variable_index[3]); ++this->num_gates; - q_m().emplace_back(0); - q_1().emplace_back(1); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(-start); - q_arith().emplace_back(1); - q_4().emplace_back(0); - q_sort().emplace_back(1); - q_elliptic().emplace_back(0); - q_lookup_type().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(-start); + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(1); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); // enforce range check for middle rows for (size_t i = gate_width; i < variable_index.size() - gate_width; i += gate_width) { - w_l().emplace_back(variable_index[i]); - w_r().emplace_back(variable_index[i + 1]); - w_o().emplace_back(variable_index[i + 2]); - w_4().emplace_back(variable_index[i + 3]); + blocks.main.populate_wires( + variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]); ++this->num_gates; - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(1); - q_elliptic().emplace_back(0); - q_lookup_type().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(1); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); } // enforce range checks of last row and ending at end if (variable_index.size() > gate_width) { - w_l().emplace_back(variable_index[variable_index.size() - 4]); - w_r().emplace_back(variable_index[variable_index.size() - 3]); - w_o().emplace_back(variable_index[variable_index.size() - 2]); - w_4().emplace_back(variable_index[variable_index.size() - 1]); + blocks.main.populate_wires(variable_index[variable_index.size() - 4], + variable_index[variable_index.size() - 3], + variable_index[variable_index.size() - 2], + variable_index[variable_index.size() - 1]); ++this->num_gates; - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); - q_4().emplace_back(0); - q_sort().emplace_back(1); - q_elliptic().emplace_back(0); - q_lookup_type().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(1); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); } // dummy gate needed because of sort widget's check of next row // use this gate to check end condition - w_l().emplace_back(variable_index[variable_index.size() - 1]); - w_r().emplace_back(this->zero_idx); - w_o().emplace_back(this->zero_idx); - w_4().emplace_back(this->zero_idx); + blocks.main.populate_wires( + variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); ++this->num_gates; - q_m().emplace_back(0); - q_1().emplace_back(1); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_c().emplace_back(-end); - q_arith().emplace_back(1); - q_4().emplace_back(0); - q_sort().emplace_back(0); - q_elliptic().emplace_back(0); - q_lookup_type().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(-end); + blocks.main.q_arith().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); } @@ -1253,77 +1198,77 @@ std::vector UltraCircuitBuilder_::decompose_into_defa template void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECTORS type) { - q_aux().emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); switch (type) { case AUX_SELECTORS::LIMB_ACCUMULATE_1: { - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(1); - q_4().emplace_back(1); - q_m().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(1); + blocks.main.q_4().emplace_back(1); + blocks.main.q_m().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; } case AUX_SELECTORS::LIMB_ACCUMULATE_2: { - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(1); - q_4().emplace_back(0); - q_m().emplace_back(1); - q_c().emplace_back(0); - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(1); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_1: { - q_1().emplace_back(0); - q_2().emplace_back(1); - q_3().emplace_back(1); - q_4().emplace_back(0); - q_m().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(1); + blocks.main.q_3().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_2: { - q_1().emplace_back(0); - q_2().emplace_back(1); - q_3().emplace_back(0); - q_4().emplace_back(1); - q_m().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(1); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(1); + blocks.main.q_m().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_3: { - q_1().emplace_back(0); - q_2().emplace_back(1); - q_3().emplace_back(0); - q_4().emplace_back(0); - q_m().emplace_back(1); - q_c().emplace_back(0); - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(1); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(1); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; @@ -1333,15 +1278,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // Apply sorted memory read checks with the following additional check: // 1. Assert that if index field across two gates does not change, the value field does not change. // Used for ROM reads and RAM reads across write/read boundaries - q_1().emplace_back(1); - q_2().emplace_back(1); - q_3().emplace_back(0); - q_4().emplace_back(0); - q_m().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(1); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; @@ -1352,15 +1297,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // 2. Validate record computation (r = read_write_flag + index * \eta + \timestamp * \eta^2 + value * \eta^3) // 3. If adjacent index values across 2 gates does not change, and the next gate's read_write_flag is set to // 'read', validate adjacent values do not change Used for ROM reads and RAM reads across read/write boundaries - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_4().emplace_back(0); - q_m().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(1); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(1); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; @@ -1368,15 +1313,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT case AUX_SELECTORS::RAM_TIMESTAMP_CHECK: { // For two adjacent RAM entries that share the same index, validate the timestamp value is monotonically // increasing - q_1().emplace_back(1); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_4().emplace_back(1); - q_m().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(1); + blocks.main.q_m().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; @@ -1385,15 +1330,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // Memory read gate for reading memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - q_1().emplace_back(1); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_4().emplace_back(0); - q_m().emplace_back(1); // validate record witness is correctly computed - q_c().emplace_back(0); // read/write flag stored in q_c - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(1); // validate record witness is correctly computed + blocks.main.q_c().emplace_back(0); // read/write flag stored in q_c + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; @@ -1402,15 +1347,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // Memory read gate for reading memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - q_1().emplace_back(1); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_4().emplace_back(0); - q_m().emplace_back(1); // validate record witness is correctly computed - q_c().emplace_back(0); // read/write flag stored in q_c - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(1); // validate record witness is correctly computed + blocks.main.q_c().emplace_back(0); // read/write flag stored in q_c + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; @@ -1419,29 +1364,29 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // Memory read gate for writing memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - q_1().emplace_back(1); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_4().emplace_back(0); - q_m().emplace_back(1); // validate record witness is correctly computed - q_c().emplace_back(1); // read/write flag stored in q_c - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(1); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(1); // validate record witness is correctly computed + blocks.main.q_c().emplace_back(1); // read/write flag stored in q_c + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; } default: { - q_1().emplace_back(0); - q_2().emplace_back(0); - q_3().emplace_back(0); - q_4().emplace_back(0); - q_m().emplace_back(0); - q_c().emplace_back(0); - q_arith().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_m().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } check_selector_length_consistency(); break; @@ -1509,20 +1454,9 @@ void UltraCircuitBuilder_::range_constrain_two_limbs(const uint const std::array lo_sublimbs = get_sublimbs(lo_idx, lo_masks); const std::array hi_sublimbs = get_sublimbs(hi_idx, hi_masks); - w_l().emplace_back(lo_sublimbs[0]); - w_r().emplace_back(lo_sublimbs[1]); - w_o().emplace_back(lo_sublimbs[2]); - w_4().emplace_back(lo_idx); - - w_l().emplace_back(lo_sublimbs[3]); - w_r().emplace_back(lo_sublimbs[4]); - w_o().emplace_back(hi_sublimbs[0]); - w_4().emplace_back(hi_sublimbs[1]); - - w_l().emplace_back(hi_sublimbs[2]); - w_r().emplace_back(hi_sublimbs[3]); - w_o().emplace_back(hi_sublimbs[4]); - w_4().emplace_back(hi_idx); + blocks.main.populate_wires(lo_sublimbs[0], lo_sublimbs[1], lo_sublimbs[2], lo_idx); + blocks.main.populate_wires(lo_sublimbs[3], lo_sublimbs[4], hi_sublimbs[0], hi_sublimbs[1]); + blocks.main.populate_wires(hi_sublimbs[2], hi_sublimbs[3], hi_sublimbs[4], hi_idx); apply_aux_selectors(AUX_SELECTORS::LIMB_ACCUMULATE_1); apply_aux_selectors(AUX_SELECTORS::LIMB_ACCUMULATE_2); @@ -1682,28 +1616,19 @@ std::array UltraCircuitBuilder_::evaluate_non_nati 0 }, true); - w_l().emplace_back(input.a[1]); - w_r().emplace_back(input.b[1]); - w_o().emplace_back(input.r[0]); - w_4().emplace_back(lo_0_idx); + blocks.main.populate_wires(input.a[1], input.b[1], input.r[0], lo_0_idx); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_1); ++this->num_gates; - w_l().emplace_back(input.a[0]); - w_r().emplace_back(input.b[0]); - w_o().emplace_back(input.a[3]); - w_4().emplace_back(input.b[3]); + + blocks.main.populate_wires(input.a[0], input.b[0], input.a[3], input.b[3]); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_2); ++this->num_gates; - w_l().emplace_back(input.a[2]); - w_r().emplace_back(input.b[2]); - w_o().emplace_back(input.r[3]); - w_4().emplace_back(hi_0_idx); + + blocks.main.populate_wires(input.a[2], input.b[2], input.r[3], hi_0_idx); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_3); ++this->num_gates; - w_l().emplace_back(input.a[1]); - w_r().emplace_back(input.b[1]); - w_o().emplace_back(input.r[2]); - w_4().emplace_back(hi_1_idx); + + blocks.main.populate_wires(input.a[1], input.b[1], input.r[2], hi_1_idx); apply_aux_selectors(AUX_SELECTORS::NONE); ++this->num_gates; @@ -1767,28 +1692,30 @@ void UltraCircuitBuilder_::process_non_native_field_multiplicat // iterate over the cached items and create constraints for (const auto& input : cached_partial_non_native_field_multiplications) { - w_l().emplace_back(input.a[1]); - w_r().emplace_back(input.b[1]); - w_o().emplace_back(this->zero_idx); - w_4().emplace_back(input.lo_0); + blocks.main.w_l().emplace_back(input.a[1]); + blocks.main.w_r().emplace_back(input.b[1]); + blocks.main.w_o().emplace_back(this->zero_idx); + blocks.main.w_4().emplace_back(input.lo_0); + apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_1); ++this->num_gates; - w_l().emplace_back(input.a[0]); - w_r().emplace_back(input.b[0]); - w_o().emplace_back(input.a[3]); - w_4().emplace_back(input.b[3]); + + blocks.main.populate_wires(input.a[0], input.b[0], input.a[3], input.b[3]); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_2); ++this->num_gates; - w_l().emplace_back(input.a[2]); - w_r().emplace_back(input.b[2]); - w_o().emplace_back(this->zero_idx); - w_4().emplace_back(input.hi_0); + + blocks.main.w_l().emplace_back(input.a[2]); + blocks.main.w_r().emplace_back(input.b[2]); + blocks.main.w_o().emplace_back(this->zero_idx); + blocks.main.w_4().emplace_back(input.hi_0); + apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_3); ++this->num_gates; - w_l().emplace_back(input.a[1]); - w_r().emplace_back(input.b[1]); - w_o().emplace_back(this->zero_idx); - w_4().emplace_back(input.hi_1); + blocks.main.w_l().emplace_back(input.a[1]); + blocks.main.w_r().emplace_back(input.b[1]); + blocks.main.w_o().emplace_back(this->zero_idx); + blocks.main.w_4().emplace_back(input.hi_1); + apply_aux_selectors(AUX_SELECTORS::NONE); ++this->num_gates; } @@ -1909,63 +1836,58 @@ std::array UltraCircuitBuilder_::evaluate_non_nati * By setting `q_arith` to `3`, we can validate `x_p + y_p + q_m = z_p` **/ // GATE 1 - w_l().emplace_back(y_p); - w_r().emplace_back(x_0); - w_o().emplace_back(y_0); - w_4().emplace_back(x_p); - w_l().emplace_back(z_p); - w_r().emplace_back(x_1); - w_o().emplace_back(y_1); // | 1 | 2 | 3 | 4 | - w_4().emplace_back(z_0); // |-----|-----|-----|-----| - w_l().emplace_back(x_2); // | y.p | x.0 | y.0 | z.p | (b.p + b.p - c.p = 0) AND (a.0 + b.0 - c.0 = 0) - w_r().emplace_back(y_2); // | x.p | x.1 | y.1 | z.0 | (a.1 + b.1 - c.1 = 0) - w_o().emplace_back(z_2); // | x.2 | y.2 | z.2 | z.1 | (a.2 + b.2 - c.2 = 0) - w_4().emplace_back(z_1); // | x.3 | y.3 | z.3 | --- | (a.3 + b.3 - c.3 = 0) - w_l().emplace_back(x_3); - w_r().emplace_back(y_3); - w_o().emplace_back(z_3); - w_4().emplace_back(this->zero_idx); - - q_m().emplace_back(addconstp); - q_1().emplace_back(0); - q_2().emplace_back(-x_mulconst0 * - 2); // scale constants by 2. If q_arith = 3 then w_4_omega value (z0) gets scaled by 2x - q_3().emplace_back(-y_mulconst0 * 2); // z_0 - (x_0 * -xmulconst0) - (y_0 * ymulconst0) = 0 => z_0 = x_0 + y_0 - q_4().emplace_back(0); - q_c().emplace_back(-addconst0 * 2); - q_arith().emplace_back(3); - - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(-x_mulconst1); - q_3().emplace_back(-y_mulconst1); - q_4().emplace_back(0); - q_c().emplace_back(-addconst1); - q_arith().emplace_back(2); - - q_m().emplace_back(0); - q_1().emplace_back(-x_mulconst2); - q_2().emplace_back(-y_mulconst2); - q_3().emplace_back(1); - q_4().emplace_back(0); - q_c().emplace_back(-addconst2); - q_arith().emplace_back(1); - - q_m().emplace_back(0); - q_1().emplace_back(-x_mulconst3); - q_2().emplace_back(-y_mulconst3); - q_3().emplace_back(1); - q_4().emplace_back(0); - q_c().emplace_back(-addconst3); - q_arith().emplace_back(1); + // | 1 | 2 | 3 | 4 | + // |-----|-----|-----|-----| + // | y.p | x.0 | y.0 | z.p | (b.p + b.p - c.p = 0) AND (a.0 + b.0 - c.0 = 0) + // | x.p | x.1 | y.1 | z.0 | (a.1 + b.1 - c.1 = 0) + // | x.2 | y.2 | z.2 | z.1 | (a.2 + b.2 - c.2 = 0) + // | x.3 | y.3 | z.3 | --- | (a.3 + b.3 - c.3 = 0) + blocks.main.populate_wires(y_p, x_0, y_0, x_p); + blocks.main.populate_wires(z_p, x_1, y_1, z_0); + blocks.main.populate_wires(x_2, y_2, z_2, z_1); + blocks.main.populate_wires(x_3, y_3, z_3, this->zero_idx); + + blocks.main.q_m().emplace_back(addconstp); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back( + -x_mulconst0 * 2); // scale constants by 2. If q_arith = 3 then w_4_omega value (z0) gets scaled by 2x + blocks.main.q_3().emplace_back(-y_mulconst0 * + 2); // z_0 - (x_0 * -xmulconst0) - (y_0 * ymulconst0) = 0 => z_0 = x_0 + y_0 + blocks.main.q_4().emplace_back(0); + blocks.main.q_c().emplace_back(-addconst0 * 2); + blocks.main.q_arith().emplace_back(3); + + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(-x_mulconst1); + blocks.main.q_3().emplace_back(-y_mulconst1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_c().emplace_back(-addconst1); + blocks.main.q_arith().emplace_back(2); + + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(-x_mulconst2); + blocks.main.q_2().emplace_back(-y_mulconst2); + blocks.main.q_3().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_c().emplace_back(-addconst2); + blocks.main.q_arith().emplace_back(1); + + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(-x_mulconst3); + blocks.main.q_2().emplace_back(-y_mulconst3); + blocks.main.q_3().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_c().emplace_back(-addconst3); + blocks.main.q_arith().emplace_back(1); for (size_t i = 0; i < 4; ++i) { - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } } check_selector_length_consistency(); @@ -2035,62 +1957,57 @@ std::array UltraCircuitBuilder_::evaluate_non_nati * **/ // GATE 1 - w_l().emplace_back(y_p); - w_r().emplace_back(x_0); - w_o().emplace_back(y_0); - w_4().emplace_back(z_p); - w_l().emplace_back(x_p); - w_r().emplace_back(x_1); - w_o().emplace_back(y_1); // | 1 | 2 | 3 | 4 | - w_4().emplace_back(z_0); // |-----|-----|-----|-----| - w_l().emplace_back(x_2); // | y.p | x.0 | y.0 | z.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) - w_r().emplace_back(y_2); // | x.p | x.1 | y.1 | z.0 | (a.1 - b.1 - c.1 = 0) - w_o().emplace_back(z_2); // | x.2 | y.2 | z.2 | z.1 | (a.2 - b.2 - c.2 = 0) - w_4().emplace_back(z_1); // | x.3 | y.3 | z.3 | --- | (a.3 - b.3 - c.3 = 0) - w_l().emplace_back(x_3); - w_r().emplace_back(y_3); - w_o().emplace_back(z_3); - w_4().emplace_back(this->zero_idx); - - q_m().emplace_back(-addconstp); - q_1().emplace_back(0); - q_2().emplace_back(-x_mulconst0 * 2); - q_3().emplace_back(y_mulconst0 * 2); // z_0 + (x_0 * -xmulconst0) + (y_0 * ymulconst0) = 0 => z_0 = x_0 - y_0 - q_4().emplace_back(0); - q_c().emplace_back(-addconst0 * 2); - q_arith().emplace_back(3); - - q_m().emplace_back(0); - q_1().emplace_back(0); - q_2().emplace_back(-x_mulconst1); - q_3().emplace_back(y_mulconst1); - q_4().emplace_back(0); - q_c().emplace_back(-addconst1); - q_arith().emplace_back(2); - - q_m().emplace_back(0); - q_1().emplace_back(-x_mulconst2); - q_2().emplace_back(y_mulconst2); - q_3().emplace_back(1); - q_4().emplace_back(0); - q_c().emplace_back(-addconst2); - q_arith().emplace_back(1); - - q_m().emplace_back(0); - q_1().emplace_back(-x_mulconst3); - q_2().emplace_back(y_mulconst3); - q_3().emplace_back(1); - q_4().emplace_back(0); - q_c().emplace_back(-addconst3); - q_arith().emplace_back(1); + // | 1 | 2 | 3 | 4 | + // |-----|-----|-----|-----| + // | y.p | x.0 | y.0 | z.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0) + // | x.p | x.1 | y.1 | z.0 | (a.1 - b.1 - c.1 = 0) + // | x.2 | y.2 | z.2 | z.1 | (a.2 - b.2 - c.2 = 0) + // | x.3 | y.3 | z.3 | --- | (a.3 - b.3 - c.3 = 0) + blocks.main.populate_wires(y_p, x_0, y_0, z_p); + blocks.main.populate_wires(x_p, x_1, y_1, z_0); + blocks.main.populate_wires(x_2, y_2, z_2, z_1); + blocks.main.populate_wires(x_3, y_3, z_3, this->zero_idx); + + blocks.main.q_m().emplace_back(-addconstp); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(-x_mulconst0 * 2); + blocks.main.q_3().emplace_back(y_mulconst0 * + 2); // z_0 + (x_0 * -xmulconst0) + (y_0 * ymulconst0) = 0 => z_0 = x_0 - y_0 + blocks.main.q_4().emplace_back(0); + blocks.main.q_c().emplace_back(-addconst0 * 2); + blocks.main.q_arith().emplace_back(3); + + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(-x_mulconst1); + blocks.main.q_3().emplace_back(y_mulconst1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_c().emplace_back(-addconst1); + blocks.main.q_arith().emplace_back(2); + + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(-x_mulconst2); + blocks.main.q_2().emplace_back(y_mulconst2); + blocks.main.q_3().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_c().emplace_back(-addconst2); + blocks.main.q_arith().emplace_back(1); + + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(-x_mulconst3); + blocks.main.q_2().emplace_back(y_mulconst3); + blocks.main.q_3().emplace_back(1); + blocks.main.q_4().emplace_back(0); + blocks.main.q_c().emplace_back(-addconst3); + blocks.main.q_arith().emplace_back(1); for (size_t i = 0; i < 4; ++i) { - q_sort().emplace_back(0); - q_lookup_type().emplace_back(0); - q_elliptic().emplace_back(0); - q_aux().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - selectors.pad_additional(); + blocks.main.pad_additional(); } } check_selector_length_consistency(); @@ -2113,10 +2030,9 @@ template void UltraCircuitBuilder_:: // Record wire value can't yet be computed record.record_witness = this->add_variable(0); apply_aux_selectors(AUX_SELECTORS::ROM_READ); - w_l().emplace_back(record.index_witness); - w_r().emplace_back(record.value_column1_witness); - w_o().emplace_back(record.value_column2_witness); - w_4().emplace_back(record.record_witness); + blocks.main.populate_wires( + record.index_witness, record.value_column1_witness, record.value_column2_witness, record.record_witness); + record.gate_index = this->num_gates; ++this->num_gates; } @@ -2133,10 +2049,9 @@ void UltraCircuitBuilder_::create_sorted_ROM_gate(RomRecord& re { record.record_witness = this->add_variable(0); apply_aux_selectors(AUX_SELECTORS::ROM_CONSISTENCY_CHECK); - w_l().emplace_back(record.index_witness); - w_r().emplace_back(record.value_column1_witness); - w_o().emplace_back(record.value_column2_witness); - w_4().emplace_back(record.record_witness); + blocks.main.populate_wires( + record.index_witness, record.value_column1_witness, record.value_column2_witness, record.record_witness); + record.gate_index = this->num_gates; ++this->num_gates; } @@ -2179,10 +2094,9 @@ template void UltraCircuitBuilder_:: record.record_witness = this->add_variable(0); apply_aux_selectors(record.access_type == RamRecord::AccessType::READ ? AUX_SELECTORS::RAM_READ : AUX_SELECTORS::RAM_WRITE); - w_l().emplace_back(record.index_witness); - w_r().emplace_back(record.timestamp_witness); - w_o().emplace_back(record.value_witness); - w_4().emplace_back(record.record_witness); + blocks.main.populate_wires( + record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); + record.gate_index = this->num_gates; ++this->num_gates; } @@ -2200,10 +2114,9 @@ void UltraCircuitBuilder_::create_sorted_RAM_gate(RamRecord& re { record.record_witness = this->add_variable(0); apply_aux_selectors(AUX_SELECTORS::RAM_CONSISTENCY_CHECK); - w_l().emplace_back(record.index_witness); - w_r().emplace_back(record.timestamp_witness); - w_o().emplace_back(record.value_witness); - w_4().emplace_back(record.record_witness); + blocks.main.populate_wires( + record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); + record.gate_index = this->num_gates; ++this->num_gates; } @@ -2695,10 +2608,9 @@ template void UltraCircuitBuilder_:: uint32_t timestamp_delta_witness = this->add_variable(timestamp_delta); apply_aux_selectors(AUX_SELECTORS::RAM_TIMESTAMP_CHECK); - w_l().emplace_back(current.index_witness); - w_r().emplace_back(current.timestamp_witness); - w_o().emplace_back(timestamp_delta_witness); - w_4().emplace_back(this->zero_idx); + blocks.main.populate_wires( + current.index_witness, current.timestamp_witness, timestamp_delta_witness, this->zero_idx); + ++this->num_gates; // store timestamp offsets for later. Need to apply range checks to them, but calling @@ -3288,6 +3200,9 @@ inline typename Arithmetization::FF UltraCircuitBuilder_::compu * * @details The method switches the circuit to the "in-the-head" version, finalizes it, checks gates, lookups and * permutations and then switches it back from the in-the-head version, discarding the updates + * @note We want to check that the whole circuit works, but ultra circuits need to have ram, rom and range gates added + * in the end for the check to be complete as well as the set permutation check, so we finalize the circuit when we + * check it. This structure allows us to restore the circuit to the state before the finalization. * * @return true * @return false @@ -3295,9 +3210,11 @@ inline typename Arithmetization::FF UltraCircuitBuilder_::compu template bool UltraCircuitBuilder_::check_circuit() { bool result = true; - CircuitDataBackup circuit_backup = CircuitDataBackup::store_prefinilized_state(this); - // Finalize circuit-in-the-head + // Copy prefinalized circuit so that original circuit can be restored prior to return + UltraCircuitBuilder_ prefinalized_circuit = *this; + + // Finalize the circuit finalize_circuit(); // Sample randomness @@ -3397,26 +3314,26 @@ template bool UltraCircuitBuilder_:: FF w_4_value; FF w_4_index; // Get the values of selectors and wires and update tag products along the way - q_arith_value = q_arith()[i]; - q_aux_value = q_aux()[i]; - q_elliptic_value = q_elliptic()[i]; - q_sort_value = q_sort()[i]; - q_lookup_type_value = q_lookup_type()[i]; - q_1_value = q_1()[i]; - q_2_value = q_2()[i]; - q_3_value = q_3()[i]; - q_4_value = q_4()[i]; - q_m_value = q_m()[i]; - q_c_value = q_c()[i]; - w_1_value = this->get_variable(w_l()[i]); - update_tag_check_information(w_l()[i], w_1_value); - w_2_value = this->get_variable(w_r()[i]); - update_tag_check_information(w_r()[i], w_2_value); - w_3_value = this->get_variable(w_o()[i]); - update_tag_check_information(w_o()[i], w_3_value); - w_4_value = this->get_variable(w_4()[i]); + q_arith_value = blocks.main.q_arith()[i]; + q_aux_value = blocks.main.q_aux()[i]; + q_elliptic_value = blocks.main.q_elliptic()[i]; + q_sort_value = blocks.main.q_sort()[i]; + q_lookup_type_value = blocks.main.q_lookup_type()[i]; + q_1_value = blocks.main.q_1()[i]; + q_2_value = blocks.main.q_2()[i]; + q_3_value = blocks.main.q_3()[i]; + q_4_value = blocks.main.q_4()[i]; + q_m_value = blocks.main.q_m()[i]; + q_c_value = blocks.main.q_c()[i]; + w_1_value = this->get_variable(blocks.main.w_l()[i]); + update_tag_check_information(blocks.main.w_l()[i], w_1_value); + w_2_value = this->get_variable(blocks.main.w_r()[i]); + update_tag_check_information(blocks.main.w_r()[i], w_2_value); + w_3_value = this->get_variable(blocks.main.w_o()[i]); + update_tag_check_information(blocks.main.w_o()[i], w_3_value); + w_4_value = this->get_variable(blocks.main.w_4()[i]); // We need to wait before updating tag product for w_4 - w_4_index = w_4()[i]; + w_4_index = blocks.main.w_4()[i]; // If we are touching a gate with memory access, we need to update the value of the 4th witness if (memory_read_record_gates.contains(i)) { @@ -3432,10 +3349,10 @@ template bool UltraCircuitBuilder_:: FF w_3_shifted_value; FF w_4_shifted_value; if (i < (this->num_gates - 1)) { - w_1_shifted_value = this->get_variable(w_l()[i + 1]); - w_2_shifted_value = this->get_variable(w_r()[i + 1]); - w_3_shifted_value = this->get_variable(w_o()[i + 1]); - w_4_shifted_value = this->get_variable(w_4()[i + 1]); + w_1_shifted_value = this->get_variable(blocks.main.w_l()[i + 1]); + w_2_shifted_value = this->get_variable(blocks.main.w_r()[i + 1]); + w_3_shifted_value = this->get_variable(blocks.main.w_o()[i + 1]); + w_4_shifted_value = this->get_variable(blocks.main.w_4()[i + 1]); } else { w_1_shifted_value = FF::zero(); w_2_shifted_value = FF::zero(); @@ -3549,7 +3466,10 @@ template bool UltraCircuitBuilder_:: result = false; } - circuit_backup.restore_prefinilized_state(this); + + // Restore the circuit to its pre-finalized state + *this = prefinalized_circuit; + return result; } template class UltraCircuitBuilder_>; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp index d9e533c15c1..fef275152d2 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/proof_system/execution_trace/execution_trace.hpp" #include "barretenberg/proof_system/op_queue/ecc_op_queue.hpp" #include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/proof_system/plookup_tables/types.hpp" @@ -24,10 +25,12 @@ template struct non_native_field_witnesses { using namespace bb; -template -class UltraCircuitBuilder_ : public CircuitBuilderBase { +template +class UltraCircuitBuilder_ : public CircuitBuilderBase { public: - using Selectors = Arithmetization; + using Arithmetization = Arithmetization_; + using GateBlocks = typename Arithmetization::TraceBlocks; + using FF = typename Arithmetization::FF; static constexpr size_t NUM_WIRES = Arithmetization::NUM_WIRES; // Keeping NUM_WIRES, at least temporarily, for backward compatibility @@ -268,347 +271,8 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase>; - using SelectorVector = std::vector>; - - std::vector public_inputs; - std::vector variables; - // index of next variable in equivalence class (=REAL_VARIABLE if you're last) - std::vector next_var_index; - // index of previous variable in equivalence class (=FIRST if you're in a cycle alone) - std::vector prev_var_index; - // indices of corresponding real variables - std::vector real_variable_index; - std::vector real_variable_tags; - std::map constant_variable_indices; - WireVector w_l; - WireVector w_r; - WireVector w_o; - WireVector w_4; - SelectorVector q_m; - SelectorVector q_c; - SelectorVector q_1; - SelectorVector q_2; - SelectorVector q_3; - SelectorVector q_4; - SelectorVector q_arith; - SelectorVector q_sort; - SelectorVector q_elliptic; - SelectorVector q_aux; - SelectorVector q_lookup_type; - uint32_t current_tag = DUMMY_TAG; - std::map tau; - - std::vector ram_arrays; - std::vector rom_arrays; - - std::vector memory_read_records; - std::vector memory_write_records; - std::map range_lists; - - std::vector - cached_partial_non_native_field_multiplications; - - size_t num_gates; - bool circuit_finalized = false; - /** - * @brief Stores the state of everything logic-related in the builder. - * - * @details We need this function for tests. Specifically, to ensure that we are not changing anything in - * check_circuit - * - * @param builder - * @return CircuitDataBackup - */ - template static CircuitDataBackup store_full_state(const CircuitBuilder& builder) - { - CircuitDataBackup stored_state; - stored_state.public_inputs = builder.public_inputs; - stored_state.variables = builder.variables; - - stored_state.next_var_index = builder.next_var_index; - - stored_state.prev_var_index = builder.prev_var_index; - - stored_state.real_variable_index = builder.real_variable_index; - stored_state.real_variable_tags = builder.real_variable_tags; - stored_state.constant_variable_indices = builder.constant_variable_indices; - stored_state.w_l = builder.w_l(); - stored_state.w_r = builder.w_r(); - stored_state.w_o = builder.w_o(); - stored_state.w_4 = builder.w_4(); - stored_state.q_m = builder.q_m(); - stored_state.q_c = builder.q_c(); - stored_state.q_1 = builder.q_1(); - stored_state.q_2 = builder.q_2(); - stored_state.q_3 = builder.q_3(); - stored_state.q_4 = builder.q_4(); - stored_state.q_arith = builder.q_arith(); - stored_state.q_sort = builder.q_sort(); - stored_state.q_elliptic = builder.q_elliptic(); - stored_state.q_aux = builder.q_aux(); - stored_state.q_lookup_type = builder.q_lookup_type(); - stored_state.current_tag = builder.current_tag; - stored_state.tau = builder.tau; - - stored_state.ram_arrays = builder.ram_arrays; - stored_state.rom_arrays = builder.rom_arrays; - - stored_state.memory_read_records = builder.memory_read_records; - stored_state.memory_write_records = builder.memory_write_records; - stored_state.range_lists = builder.range_lists; - stored_state.circuit_finalized = builder.circuit_finalized; - stored_state.num_gates = builder.num_gates; - stored_state.cached_partial_non_native_field_multiplications = - builder.cached_partial_non_native_field_multiplications; - return stored_state; - } - - /** - * @brief Stores the state of all members of the circuit constructor that are needed to restore the state - * after finalizing the circuit. - * - * @param builder - * @return CircuitDataBackup - */ - template - static CircuitDataBackup store_prefinilized_state(const CircuitBuilder* builder) - { - CircuitDataBackup stored_state; - stored_state.public_inputs = builder->public_inputs; - stored_state.variables = builder->variables; - - stored_state.next_var_index = builder->next_var_index; - - stored_state.prev_var_index = builder->prev_var_index; - - stored_state.real_variable_index = builder->real_variable_index; - stored_state.real_variable_tags = builder->real_variable_tags; - stored_state.constant_variable_indices = builder->constant_variable_indices; - stored_state.current_tag = builder->current_tag; - stored_state.tau = builder->tau; - - stored_state.ram_arrays = builder->ram_arrays; - stored_state.rom_arrays = builder->rom_arrays; - - stored_state.memory_read_records = builder->memory_read_records; - stored_state.memory_write_records = builder->memory_write_records; - stored_state.range_lists = builder->range_lists; - stored_state.circuit_finalized = builder->circuit_finalized; - stored_state.num_gates = builder->num_gates; - stored_state.cached_partial_non_native_field_multiplications = - builder->cached_partial_non_native_field_multiplications; - - return stored_state; - } - - /** - * @brief Restores circuit constructor to a prefinilized state. - * - * @param builder - * @return CircuitDataBackup - */ - template void restore_prefinilized_state(CircuitBuilder* builder) - { - builder->public_inputs = public_inputs; - builder->variables = variables; - - builder->next_var_index = next_var_index; - - builder->prev_var_index = prev_var_index; - - builder->real_variable_index = real_variable_index; - builder->real_variable_tags = real_variable_tags; - builder->constant_variable_indices = constant_variable_indices; - builder->current_tag = current_tag; - builder->tau = tau; - - builder->ram_arrays = ram_arrays; - builder->rom_arrays = rom_arrays; - - builder->memory_read_records = memory_read_records; - builder->memory_write_records = memory_write_records; - builder->range_lists = range_lists; - builder->circuit_finalized = circuit_finalized; - builder->num_gates = num_gates; - builder->cached_partial_non_native_field_multiplications = cached_partial_non_native_field_multiplications; - builder->w_l().resize(num_gates); - builder->w_r().resize(num_gates); - builder->w_o().resize(num_gates); - builder->w_4().resize(num_gates); - builder->q_m().resize(num_gates); - builder->q_c().resize(num_gates); - builder->q_1().resize(num_gates); - builder->q_2().resize(num_gates); - builder->q_3().resize(num_gates); - builder->q_4().resize(num_gates); - builder->q_arith().resize(num_gates); - builder->q_sort().resize(num_gates); - builder->q_elliptic().resize(num_gates); - builder->q_aux().resize(num_gates); - builder->q_lookup_type().resize(num_gates); - if constexpr (HasAdditionalSelectors) { - builder->selectors.resize_additional(num_gates); - } - } - /** - * @brief Checks that the circuit state is the same as the stored circuit's one - * - * @param builder - * @return true - * @return false - */ - template bool is_same_state(const CircuitBuilder& builder) - { - if (!(public_inputs == builder.public_inputs)) { - return false; - } - if (!(variables == builder.variables)) { - return false; - } - if (!(next_var_index == builder.next_var_index)) { - return false; - } - if (!(prev_var_index == builder.prev_var_index)) { - return false; - } - if (!(real_variable_index == builder.real_variable_index)) { - return false; - } - if (!(real_variable_tags == builder.real_variable_tags)) { - return false; - } - if (!(constant_variable_indices == builder.constant_variable_indices)) { - return false; - } - if (!(w_l == builder.w_l())) { - return false; - } - if (!(w_r == builder.w_r())) { - return false; - } - if (!(w_o == builder.w_o())) { - return false; - } - if (!(w_4 == builder.w_4())) { - return false; - } - if (!(q_m == builder.q_m())) { - return false; - } - if (!(q_c == builder.q_c())) { - return false; - } - if (!(q_1 == builder.q_1())) { - return false; - } - if (!(q_2 == builder.q_2())) { - return false; - } - if (!(q_3 == builder.q_3())) { - return false; - } - if (!(q_4 == builder.q_4())) { - return false; - } - if (!(q_arith == builder.q_arith())) { - return false; - } - if (!(q_sort == builder.q_sort())) { - return false; - } - if (!(q_elliptic == builder.q_elliptic())) { - return false; - } - if (!(q_aux == builder.q_aux())) { - return false; - } - if (!(q_lookup_type == builder.q_lookup_type())) { - return false; - } - if (!(current_tag == builder.current_tag)) { - return false; - } - if (!(tau == builder.tau)) { - return false; - } - if (!(ram_arrays == builder.ram_arrays)) { - return false; - } - if (!(rom_arrays == builder.rom_arrays)) { - return false; - } - if (!(memory_read_records == builder.memory_read_records)) { - return false; - } - if (!(memory_write_records == builder.memory_write_records)) { - return false; - } - if (!(range_lists == builder.range_lists)) { - return false; - } - if (!(cached_partial_non_native_field_multiplications == - builder.cached_partial_non_native_field_multiplications)) { - return false; - } - if (!(num_gates == builder.num_gates)) { - return false; - } - if (!(circuit_finalized == builder.circuit_finalized)) { - return false; - } - return true; - } - }; - - std::array>, NUM_WIRES> wires; - Arithmetization selectors; - - using WireVector = std::vector>; - using SelectorVector = std::vector>; - - WireVector& w_l() { return std::get<0>(wires); }; - WireVector& w_r() { return std::get<1>(wires); }; - WireVector& w_o() { return std::get<2>(wires); }; - WireVector& w_4() { return std::get<3>(wires); }; - - const WireVector& w_l() const { return std::get<0>(wires); }; - const WireVector& w_r() const { return std::get<1>(wires); }; - const WireVector& w_o() const { return std::get<2>(wires); }; - const WireVector& w_4() const { return std::get<3>(wires); }; - - SelectorVector& q_m() { return selectors.q_m(); }; - SelectorVector& q_c() { return selectors.q_c(); }; - SelectorVector& q_1() { return selectors.q_1(); }; - SelectorVector& q_2() { return selectors.q_2(); }; - SelectorVector& q_3() { return selectors.q_3(); }; - SelectorVector& q_4() { return selectors.q_4(); }; - SelectorVector& q_arith() { return selectors.q_arith(); }; - SelectorVector& q_sort() { return selectors.q_sort(); }; - SelectorVector& q_elliptic() { return selectors.q_elliptic(); }; - SelectorVector& q_aux() { return selectors.q_aux(); }; - SelectorVector& q_lookup_type() { return selectors.q_lookup_type(); }; - - const SelectorVector& q_c() const { return selectors.q_c(); }; - const SelectorVector& q_1() const { return selectors.q_1(); }; - const SelectorVector& q_2() const { return selectors.q_2(); }; - const SelectorVector& q_3() const { return selectors.q_3(); }; - const SelectorVector& q_4() const { return selectors.q_4(); }; - const SelectorVector& q_arith() const { return selectors.q_arith(); }; - const SelectorVector& q_sort() const { return selectors.q_sort(); }; - const SelectorVector& q_elliptic() const { return selectors.q_elliptic(); }; - const SelectorVector& q_aux() const { return selectors.q_aux(); }; - const SelectorVector& q_lookup_type() const { return selectors.q_lookup_type(); }; - const SelectorVector& q_m() const { return selectors.q_m(); }; + // Storage for wires and selectors for all gate types + GateBlocks blocks; // These are variables that we have used a gate on, to enforce that they are // equal to a defined value. @@ -649,11 +313,7 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase(size_hint) { - selectors.reserve(size_hint); - w_l().reserve(size_hint); - w_r().reserve(size_hint); - w_o().reserve(size_hint); - w_4().reserve(size_hint); + blocks.main.reserve(size_hint); this->zero_idx = put_constant_variable(FF::zero()); this->tau.insert({ DUMMY_TAG, DUMMY_TAG }); // TODO(luke): explain this }; @@ -678,11 +338,7 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase(size_hint) { - selectors.reserve(size_hint); - w_l().reserve(size_hint); - w_r().reserve(size_hint); - w_o().reserve(size_hint); - w_4().reserve(size_hint); + blocks.main.reserve(size_hint); for (size_t idx = 0; idx < varnum; ++idx) { // Zeros are added for variables whose existence is known but whose values are not yet known. The values may @@ -705,8 +361,7 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase(std::move(other)) { - wires = other.wires; - selectors = other.selectors; + blocks = other.blocks; constant_variable_indices = other.constant_variable_indices; lookup_tables = other.lookup_tables; @@ -723,8 +378,7 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase::operator=(std::move(other)); - wires = other.wires; - selectors = other.selectors; + blocks = other.blocks; constant_variable_indices = other.constant_variable_indices; lookup_tables = other.lookup_tables; @@ -740,6 +394,8 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase>= table_bits; } } - auto saved_state = UltraCircuitBuilder::CircuitDataBackup::store_full_state(circuit_builder); + + UltraCircuitBuilder circuit_copy{ circuit_builder }; bool result = circuit_builder.check_circuit(); EXPECT_EQ(result, true); - EXPECT_TRUE(saved_state.is_same_state(circuit_builder)); + // Ensure that check_circuit did not alter the circuit + EXPECT_EQ(circuit_copy, circuit_builder); } TEST(ultra_circuit_constructor, base_case) @@ -154,11 +156,12 @@ TEST(ultra_circuit_constructor, test_elliptic_gate) circuit_constructor.create_ecc_add_gate({ x1, y1, x2, y2, x3, y3, 1 }); - auto saved_state = UltraCircuitBuilder::CircuitDataBackup::store_full_state(circuit_constructor); + UltraCircuitBuilder circuit_copy{ circuit_constructor }; bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); - EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + // Ensure that check_circuit did not alter the circuit + EXPECT_EQ(circuit_copy, circuit_constructor); circuit_constructor.create_ecc_add_gate({ x1 + 1, y1, x2, y2, x3, y3, 1 }); @@ -181,11 +184,12 @@ TEST(ultra_circuit_constructor, test_elliptic_double_gate) circuit_constructor.create_ecc_dbl_gate({ x1, y1, x3, y3 }); - auto saved_state = UltraCircuitBuilder::CircuitDataBackup::store_full_state(circuit_constructor); + UltraCircuitBuilder circuit_copy{ circuit_constructor }; bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); - EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + // Ensure that check_circuit did not alter the circuit + EXPECT_EQ(circuit_copy, circuit_constructor); } TEST(ultra_circuit_constructor, non_trivial_tag_permutation) @@ -212,11 +216,12 @@ TEST(ultra_circuit_constructor, non_trivial_tag_permutation) circuit_constructor.assign_tag(c_idx, 2); circuit_constructor.assign_tag(d_idx, 2); - auto saved_state = UltraCircuitBuilder::CircuitDataBackup::store_full_state(circuit_constructor); + UltraCircuitBuilder circuit_copy{ circuit_constructor }; bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); - EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + // Ensure that check_circuit did not alter the circuit + EXPECT_EQ(circuit_copy, circuit_constructor); // Break the tag circuit_constructor.real_variable_tags[circuit_constructor.real_variable_index[a_idx]] = 2; @@ -257,11 +262,12 @@ TEST(ultra_circuit_constructor, non_trivial_tag_permutation_and_cycles) circuit_constructor.create_add_gate( { e_idx, f_idx, circuit_constructor.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); - auto saved_state = UltraCircuitBuilder::CircuitDataBackup::store_full_state(circuit_constructor); + UltraCircuitBuilder circuit_copy{ circuit_constructor }; bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); - EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + // Ensure that check_circuit did not alter the circuit + EXPECT_EQ(circuit_copy, circuit_constructor); // Break the tag circuit_constructor.real_variable_tags[circuit_constructor.real_variable_index[a_idx]] = 2; @@ -281,11 +287,12 @@ TEST(ultra_circuit_constructor, bad_tag_permutation) circuit_constructor.create_add_gate({ a_idx, b_idx, circuit_constructor.zero_idx, 1, 1, 0, 0 }); circuit_constructor.create_add_gate({ c_idx, d_idx, circuit_constructor.zero_idx, 1, 1, 0, -1 }); - auto saved_state = UltraCircuitBuilder::CircuitDataBackup::store_full_state(circuit_constructor); + UltraCircuitBuilder circuit_copy{ circuit_constructor }; bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); - EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + // Ensure that check_circuit did not alter the circuit + EXPECT_EQ(circuit_copy, circuit_constructor); circuit_constructor.create_tag(1, 2); circuit_constructor.create_tag(2, 1); @@ -654,11 +661,13 @@ TEST(ultra_circuit_constructor, non_native_field_multiplication) const auto [lo_1_idx, hi_1_idx] = circuit_constructor.evaluate_non_native_field_multiplication(inputs); circuit_constructor.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); - auto saved_state = UltraCircuitBuilder::CircuitDataBackup::store_full_state(circuit_constructor); + UltraCircuitBuilder circuit_copy{ circuit_constructor }; + bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); - EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + // Ensure that check_circuit did not alter the circuit + EXPECT_EQ(circuit_copy, circuit_constructor); } TEST(ultra_circuit_constructor, rom) @@ -764,12 +773,13 @@ TEST(ultra_circuit_constructor, ram) }, false); - auto saved_state = UltraCircuitBuilder::CircuitDataBackup::store_full_state(circuit_constructor); + UltraCircuitBuilder circuit_copy{ circuit_constructor }; bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); - EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + // Ensure that check_circuit did not alter the circuit + EXPECT_EQ(circuit_copy, circuit_constructor); // Test the builder copy constructor for a circuit with RAM gates UltraCircuitBuilder duplicate_circuit_constructor{ circuit_constructor }; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp index 2235bf8f2c6..6c94579f4d7 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp @@ -6,7 +6,7 @@ namespace bb { template -void ExecutionTrace_::generate(const Builder& builder, +void ExecutionTrace_::populate(Builder& builder, const std::shared_ptr& proving_key) { // Construct wire polynomials, selector polynomials, and copy cycles from raw circuit data @@ -14,20 +14,24 @@ void ExecutionTrace_::generate(const Builder& builder, add_wires_and_selectors_to_proving_key(trace_data, builder, proving_key); + if constexpr (IsGoblinFlavor) { + add_ecc_op_wires_to_proving_key(builder, proving_key); + } + // Compute the permutation argument polynomials (sigma/id) and add them to proving key compute_permutation_argument_polynomials(builder, proving_key.get(), trace_data.copy_cycles); } template void ExecutionTrace_::add_wires_and_selectors_to_proving_key( - TraceData& trace_data, const Builder& builder, const std::shared_ptr& proving_key) + TraceData& trace_data, Builder& builder, const std::shared_ptr& proving_key) { if constexpr (IsHonkFlavor) { for (auto [pkey_wire, trace_wire] : zip_view(proving_key->get_wires(), trace_data.wires)) { - pkey_wire = std::move(trace_wire); + pkey_wire = trace_wire.share(); } for (auto [pkey_selector, trace_selector] : zip_view(proving_key->get_selectors(), trace_data.selectors)) { - pkey_selector = std::move(trace_selector); + pkey_selector = trace_selector.share(); } } else if constexpr (IsPlonkFlavor) { for (size_t idx = 0; idx < trace_data.wires.size(); ++idx) { @@ -42,19 +46,17 @@ void ExecutionTrace_::add_wires_and_selectors_to_proving_key( } template -typename ExecutionTrace_::TraceData ExecutionTrace_::construct_trace_data(const Builder& builder, +typename ExecutionTrace_::TraceData ExecutionTrace_::construct_trace_data(Builder& builder, size_t dyadic_circuit_size) { TraceData trace_data{ dyadic_circuit_size, builder }; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/862): Eventually trace_blocks will be constructed - // directly in the builder, i.e. the gate addition methods will directly populate the wire/selectors in the - // appropriate block. In the mean time we do some inefficient copying etc to construct it here post facto. - auto trace_blocks = create_execution_trace_blocks(builder); + // Complete the public inputs execution trace block from builder.public_inputs + populate_public_inputs_block(builder); - uint32_t offset = 0; // Track offset at which to place each block in the trace polynomials + uint32_t offset = Flavor::has_zero_row ? 1 : 0; // Offset at which to place each block in the trace polynomials // For each block in the trace, populate wire polys, copy cycles and selector polys - for (auto& block : trace_blocks) { + for (auto& block : builder.blocks.get()) { auto block_size = static_cast(block.wires[0].size()); // Update wire polynomials and copy cycles @@ -73,7 +75,7 @@ typename ExecutionTrace_::TraceData ExecutionTrace_::construct_t // Insert the selector values for this block into the selector polynomials at the correct offset // TODO(https://github.com/AztecProtocol/barretenberg/issues/398): implicit arithmetization/flavor consistency - for (auto [selector_poly, selector] : zip_view(trace_data.selectors, block.selectors.get())) { + for (auto [selector_poly, selector] : zip_view(trace_data.selectors, block.selectors)) { for (size_t row_idx = 0; row_idx < block_size; ++row_idx) { size_t trace_row_idx = row_idx + offset; selector_poly[trace_row_idx] = selector[row_idx]; @@ -85,52 +87,51 @@ typename ExecutionTrace_::TraceData ExecutionTrace_::construct_t return trace_data; } -template -std::vector::TraceBlock> ExecutionTrace_::create_execution_trace_blocks( - const Builder& builder) +template void ExecutionTrace_::populate_public_inputs_block(Builder& builder) { - std::vector trace_blocks; - - // Make a block for the zero row - if constexpr (Flavor::has_zero_row) { - TraceBlock zero_block; - for (auto& wire : zero_block.wires) { - wire.emplace_back(builder.zero_idx); - } - for (auto& selector : zero_block.selectors.get()) { - selector.emplace_back(0); - } - trace_blocks.emplace_back(zero_block); - } - - // Make a block for the ecc op wires - if constexpr (IsGoblinFlavor) { - trace_blocks.emplace_back(builder.ecc_op_block); - } - - // Make a block for the public inputs - TraceBlock public_block; + // Update the public inputs block for (auto& idx : builder.public_inputs) { for (size_t wire_idx = 0; wire_idx < NUM_WIRES; ++wire_idx) { if (wire_idx < 2) { // first two wires get a copy of the public inputs - public_block.wires[wire_idx].emplace_back(idx); + builder.blocks.pub_inputs.wires[wire_idx].emplace_back(idx); } else { // the remaining wires get zeros - public_block.wires[wire_idx].emplace_back(builder.zero_idx); + builder.blocks.pub_inputs.wires[wire_idx].emplace_back(builder.zero_idx); } } - for (auto& selector : public_block.selectors.get()) { + for (auto& selector : builder.blocks.pub_inputs.selectors) { selector.emplace_back(0); } } +} - public_block.is_public_input = true; - trace_blocks.emplace_back(public_block); - - // Make a block for the basic wires and selectors - TraceBlock conventional_block{ builder.wires, builder.selectors }; - trace_blocks.emplace_back(conventional_block); +template +void ExecutionTrace_::add_ecc_op_wires_to_proving_key( + Builder& builder, const std::shared_ptr& proving_key) + requires IsGoblinFlavor +{ + // Initialize the ecc op wire polynomials to zero on the whole domain + std::array op_wire_polynomials; + for (auto& poly : op_wire_polynomials) { + poly = Polynomial{ proving_key->circuit_size }; + } + Polynomial ecc_op_selector{ proving_key->circuit_size }; + + // Copy the ecc op data from the conventional wires into the op wires over the range of ecc op gates + const size_t op_wire_offset = Flavor::has_zero_row ? 1 : 0; + for (auto [ecc_op_wire, wire] : zip_view(op_wire_polynomials, proving_key->get_wires())) { + for (size_t i = 0; i < builder.num_ecc_op_gates; ++i) { + size_t idx = i + op_wire_offset; + ecc_op_wire[idx] = wire[idx]; + ecc_op_selector[idx] = 1; // construct the selector as the indicator on the ecc op block + } + } - return trace_blocks; + proving_key->num_ecc_op_gates = builder.num_ecc_op_gates; + proving_key->ecc_op_wire_1 = op_wire_polynomials[0].share(); + proving_key->ecc_op_wire_2 = op_wire_polynomials[1].share(); + proving_key->ecc_op_wire_3 = op_wire_polynomials[2].share(); + proving_key->ecc_op_wire_4 = op_wire_polynomials[3].share(); + proving_key->lagrange_ecc_op = ecc_op_selector.share(); } template class ExecutionTrace_; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp index a79877761de..6f635786e39 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp @@ -5,26 +5,12 @@ namespace bb { -/** - * @brief The wires and selectors used to define a block in the execution trace - * - * @tparam Arithmetization The set of selectors corresponding to the arithmetization - */ -template struct ExecutionTraceBlock { - // WORKTODO: Zac - make this less terrible - using Wires = std::array>, Arithmetization::NUM_WIRES>; - Wires wires; - Arithmetization selectors; - bool is_public_input = false; -}; - template class ExecutionTrace_ { using Builder = typename Flavor::CircuitBuilder; using Polynomial = typename Flavor::Polynomial; using FF = typename Flavor::FF; - using TraceBlock = ExecutionTraceBlock; + using TrackBlocks = typename Builder::Arithmetization::TraceBlocks; using Wires = std::array>, Builder::NUM_WIRES>; - using Selectors = typename Builder::Selectors; using ProvingKey = typename Flavor::ProvingKey; public: @@ -32,11 +18,11 @@ template class ExecutionTrace_ { struct TraceData { std::array wires; - std::array selectors; + std::array selectors; // A vector of sets (vectors) of addresses into the wire polynomials whose values are copy constrained std::vector copy_cycles; - TraceData(size_t dyadic_circuit_size, const Builder& builder) + TraceData(size_t dyadic_circuit_size, Builder& builder) { // Initializate the wire and selector polynomials for (auto& wire : wires) { @@ -54,7 +40,7 @@ template class ExecutionTrace_ { * * @param builder */ - static void generate(const Builder& builder, const std::shared_ptr&); + static void populate(Builder& builder, const std::shared_ptr&); private: /** @@ -65,7 +51,7 @@ template class ExecutionTrace_ { * @param proving_key */ static void add_wires_and_selectors_to_proving_key(TraceData& trace_data, - const Builder& builder, + Builder& builder, const std::shared_ptr& proving_key); /** @@ -75,16 +61,27 @@ template class ExecutionTrace_ { * @param dyadic_circuit_size * @return TraceData */ - static TraceData construct_trace_data(const Builder& builder, size_t dyadic_circuit_size); + static TraceData construct_trace_data(Builder& builder, size_t dyadic_circuit_size); + + /** + * @brief Populate the public inputs block + * @details The first two wires are a copy of the public inputs and the other wires and all selectors are zero + * + * @param builder + */ + static void populate_public_inputs_block(Builder& builder); /** - * @brief Temporary helper method to construct execution trace blocks from existing builder structures - * @details Eventually the builder will construct blocks directly + * @brief Construct and add the goblin ecc op wires to the proving key + * @details The ecc op wires vanish everywhere except on the ecc op block, where they contain a copy of the ecc op + * data assumed already to be present in the corrresponding block of the conventional wires in the proving key. * * @param builder - * @return std::vector + * @param proving_key */ - static std::vector create_execution_trace_blocks(const Builder& builder); + static void add_ecc_op_wires_to_proving_key(Builder& builder, + const std::shared_ptr& proving_key) + requires IsGoblinFlavor; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/proof_system/plookup_tables/types.hpp b/barretenberg/cpp/src/barretenberg/proof_system/plookup_tables/types.hpp index 489d9e60071..0dfcaa916d3 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/plookup_tables/types.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/plookup_tables/types.hpp @@ -190,6 +190,7 @@ struct MultiTable { MultiTable& operator=(const MultiTable& other) = default; MultiTable& operator=(MultiTable&& other) = default; + bool operator==(const MultiTable& other) const = default; }; // struct PlookupLargeKeyTable { @@ -262,6 +263,8 @@ struct MultiTable { */ struct BasicTable { struct KeyEntry { + bool operator==(const KeyEntry& other) const = default; + std::array key{ 0, 0 }; std::array value{ bb::fr(0), bb::fr(0) }; bool operator<(const KeyEntry& other) const @@ -296,6 +299,8 @@ struct BasicTable { std::vector lookup_gates; std::array (*get_values_from_key)(const std::array); + + bool operator==(const BasicTable& other) const = default; }; enum ColumnIdx { C1, C2, C3 }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp index 6977453e34a..da806c978ef 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp @@ -180,7 +180,12 @@ template class stdlib_field : public testing::Test { auto gates_before = builder.get_num_gates(); uint64_t expected = fidget(builder); auto gates_after = builder.get_num_gates(); - EXPECT_EQ(builder.get_variable(builder.w_o()[gates_after - 1]), fr(expected)); + if constexpr (IsAnyOf) { + EXPECT_EQ(builder.get_variable(builder.blocks.arithmetic.w_o()[gates_after - 1]), fr(expected)); + } + if constexpr (IsAnyOf) { + EXPECT_EQ(builder.get_variable(builder.blocks.main.w_o()[gates_after - 1]), fr(expected)); + } info("Number of gates added", gates_after - gates_before); bool result = builder.check_circuit(); EXPECT_EQ(result, true); @@ -254,7 +259,12 @@ template class stdlib_field : public testing::Test { auto gates_before = builder.get_num_gates(); fibbonaci(builder); auto gates_after = builder.get_num_gates(); - EXPECT_EQ(builder.get_variable(builder.w_l()[builder.get_num_gates() - 1]), fr(4181)); + if constexpr (IsAnyOf) { + EXPECT_EQ(builder.get_variable(builder.blocks.arithmetic.w_l()[builder.get_num_gates() - 1]), fr(4181)); + } + if constexpr (IsAnyOf) { + EXPECT_EQ(builder.get_variable(builder.blocks.main.w_l()[builder.get_num_gates() - 1]), fr(4181)); + } EXPECT_EQ(gates_after - gates_before, 18UL); bool result = builder.check_circuit(); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 1f2d09bb086..db6030ed29b 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -32,44 +32,6 @@ template size_t ProverInstance_::compute_dyadic_size(Circ return circuit.get_circuit_subgroup_size(total_num_gates); } -/** - * @brief Construct Goblin style ECC op wire polynomials - * @details The Ecc op wire values are assumed to have already been stored in the corresponding block of the - * conventional wire polynomials. The values for the ecc op wire polynomials are set based on those values. - * - * @tparam Flavor - * @param wire_polynomials - */ -template -void ProverInstance_::construct_ecc_op_wire_polynomials(Circuit& circuit) - requires IsGoblinFlavor -{ - std::array op_wire_polynomials; - for (auto& poly : op_wire_polynomials) { - poly = Polynomial{ dyadic_circuit_size }; - } - Polynomial ecc_op_selector{ dyadic_circuit_size }; - - // The ECC op wires are constructed to contain the op data on the appropriate range and to vanish everywhere else. - // The op data is assumed to have already been stored at the correct location in the convetional wires so the data - // can simply be copied over directly. - const size_t op_wire_offset = Flavor::has_zero_row ? 1 : 0; - for (auto [ecc_op_wire, wire] : zip_view(op_wire_polynomials, proving_key->get_wires())) { - for (size_t i = 0; i < circuit.num_ecc_op_gates; ++i) { - size_t idx = i + op_wire_offset; - ecc_op_wire[idx] = wire[idx]; - ecc_op_selector[idx] = 1; - } - } - - proving_key->num_ecc_op_gates = circuit.num_ecc_op_gates; - proving_key->ecc_op_wire_1 = op_wire_polynomials[0].share(); - proving_key->ecc_op_wire_2 = op_wire_polynomials[1].share(); - proving_key->ecc_op_wire_3 = op_wire_polynomials[2].share(); - proving_key->ecc_op_wire_4 = op_wire_polynomials[3].share(); - proving_key->lagrange_ecc_op = ecc_op_selector.share(); -} - /** * @brief * @details diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index d2b8da8f28e..5313f7b8304 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -69,12 +69,10 @@ template class ProverInstance_ { proving_key = std::make_shared(dyadic_circuit_size, circuit.public_inputs.size()); // Construct and add to proving key the wire, selector and copy constraint polynomials - Trace::generate(circuit, proving_key); + Trace::populate(circuit, proving_key); - // If Goblin, construct the ECC op queue wire and databus polynomials - // TODO(https://github.com/AztecProtocol/barretenberg/issues/862): Maybe do this in trace generation? + // If Goblin, construct the databus polynomials if constexpr (IsGoblinFlavor) { - construct_ecc_op_wire_polynomials(circuit); construct_databus_polynomials(circuit); } @@ -116,9 +114,6 @@ template class ProverInstance_ { size_t compute_dyadic_size(Circuit&); - void construct_ecc_op_wire_polynomials(Circuit&) - requires IsGoblinFlavor; - void construct_databus_polynomials(Circuit&) requires IsGoblinFlavor;