diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp index 6a9ce7d3fce..67a2b7e565a 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp @@ -100,7 +100,7 @@ TEST(GoblinUltraCircuitBuilder, GoblinSimple) EXPECT_EQ(accumulator, g1::affine_point_at_infinity); // Check number of ecc op "gates"/rows = 3 ops * 2 rows per op = 6 - EXPECT_EQ(builder.num_ecc_op_gates, 6); + EXPECT_EQ(builder.blocks.ecc_op.size(), 6); // Check that the expected op codes have been correctly recorded in the 1st op wire EXPECT_EQ(builder.blocks.ecc_op.w_l()[0], EccOpCode::ADD_ACCUM); @@ -150,7 +150,7 @@ TEST(GoblinUltraCircuitBuilder, GoblinEccOpQueueUltraOps) // Check that the ultra ops recorded in the EccOpQueue match the ops recorded in the wires 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) { + for (size_t j = 0; j < builder.blocks.ecc_op.size(); ++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/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index a8ed0ceb79f..a2830c08c0e 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -267,8 +267,6 @@ class GoblinUltraFlavor { std::vector memory_read_records; std::vector memory_write_records; - size_t num_ecc_op_gates; // needed to determine public input offset - auto get_to_be_shifted() { return RefArray{ this->table_1, this->table_2, this->table_3, this->table_4, this->w_l, this->w_r, diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index 35587e3c208..7a21b0eaf81 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -48,7 +48,8 @@ template class ExecutionTr Wires wires; // vectors of indices into a witness variables array Selectors selectors; - bool has_ram_rom = false; // does the block contain RAM/ROM gates + bool has_ram_rom = false; // does the block contain RAM/ROM gates + bool is_pub_inputs = false; // is this the public inputs block bool operator==(const ExecutionTraceBlock& other) const = default; @@ -156,7 +157,11 @@ template class UltraArith { UltraTraceBlock aux; UltraTraceBlock lookup; - TraceBlocks() { aux.has_ram_rom = true; } + TraceBlocks() + { + aux.has_ram_rom = true; + pub_inputs.is_pub_inputs = true; + } auto get() { return RefArray{ pub_inputs, arithmetic, delta_range, elliptic, aux, lookup }; } @@ -264,7 +269,11 @@ template class UltraHonkArith { UltraHonkTraceBlock poseidon_external; UltraHonkTraceBlock poseidon_internal; - TraceBlocks() { aux.has_ram_rom = true; } + TraceBlocks() + { + aux.has_ram_rom = true; + pub_inputs.is_pub_inputs = true; + } auto get() { 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 b845a817bb0..37f7a12e8ae 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 @@ -194,8 +194,8 @@ ecc_op_tuple GoblinUltraCircuitBuilder_::decompose_ecc_operands(uint32_t op_ * * @param in Variables array indices corresponding to operation inputs * @note We dont explicitly set values for the selectors here since their values are fully determined by - * num_ecc_op_gates. E.g. in the composer we can reconstruct q_ecc_op as the indicator on the first num_ecc_op_gates - * indices. All other selectors are simply 0 on this domain. + * the number of ecc op gates. E.g. in the composer we can reconstruct q_ecc_op as the indicator over the range of ecc + * op gates. All other selectors are simply 0 on this domain. */ template void GoblinUltraCircuitBuilder_::populate_ecc_op_wires(const ecc_op_tuple& in) { @@ -208,8 +208,6 @@ template void GoblinUltraCircuitBuilder_::populate_ecc_op_wire for (auto& selector : this->blocks.ecc_op.selectors) { selector.emplace_back(0); } - - num_ecc_op_gates += 2; }; template void GoblinUltraCircuitBuilder_::set_goblin_ecc_op_code_constant_variables() 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 28bda7e6f6e..6e0b874ab63 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 @@ -17,8 +17,6 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui static constexpr size_t DEFAULT_NON_NATIVE_FIELD_LIMB_BITS = UltraCircuitBuilder_>::DEFAULT_NON_NATIVE_FIELD_LIMB_BITS; - size_t num_ecc_op_gates = 0; // number of ecc op "gates" (rows); these are placed at the start of the circuit - // Stores record of ecc operations and performs corresponding native operations internally std::shared_ptr op_queue; @@ -99,7 +97,8 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui size_t get_num_gates() const override { auto num_ultra_gates = UltraCircuitBuilder_>::get_num_gates(); - return num_ultra_gates + num_ecc_op_gates; + auto num_goblin_ecc_op_gates = this->blocks.ecc_op.size(); + return num_ultra_gates + num_goblin_ecc_op_gates; } /**x @@ -115,11 +114,12 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui size_t nnfcount = 0; UltraCircuitBuilder_>::get_num_gates_split_into_components( count, rangecount, romcount, ramcount, nnfcount); + auto num_goblin_ecc_op_gates = this->blocks.ecc_op.size(); - size_t total = count + romcount + ramcount + rangecount + num_ecc_op_gates; + size_t total = count + romcount + ramcount + rangecount + num_goblin_ecc_op_gates; std::cout << "gates = " << total << " (arith " << count << ", rom " << romcount << ", ram " << ramcount << ", range " << rangecount << ", non native field gates " << nnfcount << ", goblin ecc op gates " - << num_ecc_op_gates << "), pubinp = " << this->public_inputs.size() << std::endl; + << num_goblin_ecc_op_gates << "), pubinp = " << this->public_inputs.size() << std::endl; } /** diff --git a/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp b/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp index 8d2d4c4520a..04629363042 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp @@ -147,20 +147,16 @@ PermutationMapping compute_permutation_mapping( cycle_index++; } - // Add information about public inputs to the computation + // Add information about public inputs so that the cycles can be altered later; See the construction of the + // permutation polynomials for details. const auto num_public_inputs = static_cast(circuit_constructor.public_inputs.size()); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/862): this is brittle. depends on when PI are placed. - // how can we make this more robust? - // The public inputs are placed at the top of the execution trace, potentially offset by a zero row. - const size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0; - size_t pub_input_offset = num_zero_rows; - // If Goblin, PI are further offset by number of ecc op gates - if constexpr (IsGoblinFlavor) { - pub_input_offset += circuit_constructor.num_ecc_op_gates; + size_t pub_inputs_offset = 0; + if constexpr (IsHonkFlavor) { + pub_inputs_offset = proving_key->pub_inputs_offset; } for (size_t i = 0; i < num_public_inputs; ++i) { - size_t idx = i + pub_input_offset; + size_t idx = i + pub_inputs_offset; mapping.sigmas[0][idx].row_index = static_cast(idx); mapping.sigmas[0][idx].column_index = 0; mapping.sigmas[0][idx].is_public_input = true; 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 a32119bf478..a55897bba72 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 @@ -37,6 +37,7 @@ void ExecutionTrace_::add_wires_and_selectors_to_proving_key( for (auto [pkey_selector, trace_selector] : zip_view(proving_key->get_selectors(), trace_data.selectors)) { pkey_selector = trace_selector.share(); } + proving_key->pub_inputs_offset = trace_data.pub_inputs_offset; } else if constexpr (IsPlonkFlavor) { for (size_t idx = 0; idx < trace_data.wires.size(); ++idx) { std::string wire_tag = "w_" + std::to_string(idx + 1) + "_lagrange"; @@ -106,6 +107,10 @@ typename ExecutionTrace_::TraceData ExecutionTrace_::construct_t if (block.has_ram_rom) { trace_data.ram_rom_offset = offset; } + // Store offset of public inputs block for use in the pub input mechanism of the permutation argument + if (block.is_pub_inputs) { + trace_data.pub_inputs_offset = offset; + } offset += block_size; } @@ -144,14 +149,13 @@ void ExecutionTrace_::add_ecc_op_wires_to_proving_key( // 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) { + for (size_t i = 0; i < builder.blocks.ecc_op.size(); ++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 } } - 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(); 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 55f45e5158b..c28d0610c83 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 @@ -21,8 +21,8 @@ template class ExecutionTrace_ { std::array selectors; // A vector of sets (vectors) of addresses into the wire polynomials whose values are copy constrained std::vector copy_cycles; - // The starting index in the trace of the block containing RAM/RAM read/write gates - uint32_t ram_rom_offset = 0; + uint32_t ram_rom_offset = 0; // offset of the RAM/ROM block in the execution trace + uint32_t pub_inputs_offset = 0; // offset of the public inputs block in the execution trace TraceData(size_t dyadic_circuit_size, Builder& builder) { diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 731619b9e50..9a5db80e308 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -20,7 +20,7 @@ template size_t ProverInstance_::compute_dyadic_size(Circ // minumum size of execution trace due to everything else size_t min_size_of_execution_trace = circuit.public_inputs.size() + circuit.num_gates; if constexpr (IsGoblinFlavor) { - min_size_of_execution_trace += circuit.num_ecc_op_gates; + min_size_of_execution_trace += circuit.blocks.ecc_op.size(); } // The number of gates is the maxmimum required by the lookup argument or everything else, plus an optional zero row diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 29a2b71fc86..0ab0c5b1a8b 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -77,11 +77,6 @@ template class ProverInstance_ { std::span public_wires_source = proving_key->w_r; - // Determine public input offsets in the circuit relative to the 0th index for Ultra flavors - proving_key->pub_inputs_offset = Flavor::has_zero_row ? 1 : 0; - if constexpr (IsGoblinFlavor) { - proving_key->pub_inputs_offset += proving_key->num_ecc_op_gates; - } // Construct the public inputs array for (size_t i = 0; i < proving_key->num_public_inputs; ++i) { size_t idx = i + proving_key->pub_inputs_offset;