diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp index 329ddd088f3..4f71252275c 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp @@ -506,6 +506,8 @@ class GoblinUltra { Commitment ecc_op_wire_2_comm; Commitment ecc_op_wire_3_comm; Commitment ecc_op_wire_4_comm; + Commitment calldata_comm; + Commitment calldata_read_counts_comm; Commitment sorted_accum_comm; Commitment w_4_comm; Commitment z_perm_comm; @@ -540,6 +542,8 @@ class GoblinUltra { ecc_op_wire_2_comm = deserialize_from_buffer(proof_data, num_bytes_read); ecc_op_wire_3_comm = deserialize_from_buffer(proof_data, num_bytes_read); ecc_op_wire_4_comm = deserialize_from_buffer(proof_data, num_bytes_read); + calldata_comm = deserialize_from_buffer(proof_data, num_bytes_read); + calldata_read_counts_comm = deserialize_from_buffer(proof_data, num_bytes_read); sorted_accum_comm = deserialize_from_buffer(proof_data, num_bytes_read); w_4_comm = deserialize_from_buffer(proof_data, num_bytes_read); z_perm_comm = deserialize_from_buffer(proof_data, num_bytes_read); @@ -576,6 +580,8 @@ class GoblinUltra { serialize_to_buffer(ecc_op_wire_2_comm, proof_data); serialize_to_buffer(ecc_op_wire_3_comm, proof_data); serialize_to_buffer(ecc_op_wire_4_comm, proof_data); + serialize_to_buffer(calldata_comm, proof_data); + serialize_to_buffer(calldata_read_counts_comm, proof_data); serialize_to_buffer(sorted_accum_comm, proof_data); serialize_to_buffer(w_4_comm, proof_data); serialize_to_buffer(z_perm_comm, proof_data); diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp index ee4479fe7d1..a914a136c3b 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp @@ -61,12 +61,13 @@ template class GoblinUltraRecursive_ { // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often // need containers of this size to hold related data, so we choose a name more agnostic than `NUM_POLYNOMIALS`. // Note: this number does not include the individual sorted list polynomials. - static constexpr size_t NUM_ALL_ENTITIES = 48; // 43 (UH) + 4 op wires + 1 op wire "selector" + // NUM = 43 (UH) + 4 op wires + 1 op wire "selector" + 3 (calldata + calldata_read_counts + q_busread) + static constexpr size_t NUM_ALL_ENTITIES = 51; // The number of polynomials precomputed to describe a circuit and to aid a prover in constructing a satisfying // assignment of witnesses. We again choose a neutral name. - static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 26; // 25 (UH) + 1 op wire "selector" + static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 27; // 25 (UH) + 1 op wire "selector" + q_busread // The total number of witness entities not including shifts. - static constexpr size_t NUM_WITNESS_ENTITIES = 15; // 11 (UH) + 4 op wires + static constexpr size_t NUM_WITNESS_ENTITIES = 17; // 11 (UH) + 4 op wires + (calldata + calldata_read_counts) // define the tuple of Relations that comprise the Sumcheck relation using Relations = std::tuple, @@ -108,27 +109,28 @@ template class GoblinUltraRecursive_ { DataType& q_elliptic = std::get<8>(this->_data); DataType& q_aux = std::get<9>(this->_data); DataType& q_lookup = std::get<10>(this->_data); - DataType& sigma_1 = std::get<11>(this->_data); - DataType& sigma_2 = std::get<12>(this->_data); - DataType& sigma_3 = std::get<13>(this->_data); - DataType& sigma_4 = std::get<14>(this->_data); - DataType& id_1 = std::get<15>(this->_data); - DataType& id_2 = std::get<16>(this->_data); - DataType& id_3 = std::get<17>(this->_data); - DataType& id_4 = std::get<18>(this->_data); - DataType& table_1 = std::get<19>(this->_data); - DataType& table_2 = std::get<20>(this->_data); - DataType& table_3 = std::get<21>(this->_data); - DataType& table_4 = std::get<22>(this->_data); - DataType& lagrange_first = std::get<23>(this->_data); - DataType& lagrange_last = std::get<24>(this->_data); - DataType& lagrange_ecc_op = std::get<25>(this->_data); // indicator poly for ecc op gates + DataType& q_busread = std::get<11>(this->_data); + DataType& sigma_1 = std::get<12>(this->_data); + DataType& sigma_2 = std::get<13>(this->_data); + DataType& sigma_3 = std::get<14>(this->_data); + DataType& sigma_4 = std::get<15>(this->_data); + DataType& id_1 = std::get<16>(this->_data); + DataType& id_2 = std::get<17>(this->_data); + DataType& id_3 = std::get<18>(this->_data); + DataType& id_4 = std::get<19>(this->_data); + DataType& table_1 = std::get<20>(this->_data); + DataType& table_2 = std::get<21>(this->_data); + DataType& table_3 = std::get<22>(this->_data); + DataType& table_4 = std::get<23>(this->_data); + DataType& lagrange_first = std::get<24>(this->_data); + DataType& lagrange_last = std::get<25>(this->_data); + DataType& lagrange_ecc_op = std::get<26>(this->_data); // indicator poly for ecc op gates static constexpr CircuitType CIRCUIT_TYPE = CircuitBuilder::CIRCUIT_TYPE; std::vector get_selectors() override { - return { q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, q_elliptic, q_aux, q_lookup }; + return { q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, q_elliptic, q_aux, q_lookup, q_busread }; }; std::vector get_sigma_polynomials() override { return { sigma_1, sigma_2, sigma_3, sigma_4 }; }; std::vector get_id_polynomials() override { return { id_1, id_2, id_3, id_4 }; }; @@ -158,6 +160,8 @@ template class GoblinUltraRecursive_ { DataType& ecc_op_wire_2 = std::get<12>(this->_data); DataType& ecc_op_wire_3 = std::get<13>(this->_data); DataType& ecc_op_wire_4 = std::get<14>(this->_data); + DataType& calldata = std::get<15>(this->_data); + DataType& calldata_read_counts = std::get<16>(this->_data); std::vector get_wires() override { return { w_l, w_r, w_o, w_4 }; }; std::vector get_ecc_op_wires() @@ -191,43 +195,46 @@ template class GoblinUltraRecursive_ { DataType& q_elliptic = std::get<8>(this->_data); DataType& q_aux = std::get<9>(this->_data); DataType& q_lookup = std::get<10>(this->_data); - DataType& sigma_1 = std::get<11>(this->_data); - DataType& sigma_2 = std::get<12>(this->_data); - DataType& sigma_3 = std::get<13>(this->_data); - DataType& sigma_4 = std::get<14>(this->_data); - DataType& id_1 = std::get<15>(this->_data); - DataType& id_2 = std::get<16>(this->_data); - DataType& id_3 = std::get<17>(this->_data); - DataType& id_4 = std::get<18>(this->_data); - DataType& table_1 = std::get<19>(this->_data); - DataType& table_2 = std::get<20>(this->_data); - DataType& table_3 = std::get<21>(this->_data); - DataType& table_4 = std::get<22>(this->_data); - DataType& lagrange_first = std::get<23>(this->_data); - DataType& lagrange_last = std::get<24>(this->_data); - DataType& lagrange_ecc_op = std::get<25>(this->_data); - DataType& w_l = std::get<26>(this->_data); - DataType& w_r = std::get<27>(this->_data); - DataType& w_o = std::get<28>(this->_data); - DataType& w_4 = std::get<29>(this->_data); - DataType& sorted_accum = std::get<30>(this->_data); - DataType& z_perm = std::get<31>(this->_data); - DataType& z_lookup = std::get<32>(this->_data); - DataType& ecc_op_wire_1 = std::get<33>(this->_data); - DataType& ecc_op_wire_2 = std::get<34>(this->_data); - DataType& ecc_op_wire_3 = std::get<35>(this->_data); - DataType& ecc_op_wire_4 = std::get<36>(this->_data); - DataType& table_1_shift = std::get<37>(this->_data); - DataType& table_2_shift = std::get<38>(this->_data); - DataType& table_3_shift = std::get<39>(this->_data); - DataType& table_4_shift = std::get<40>(this->_data); - DataType& w_l_shift = std::get<41>(this->_data); - DataType& w_r_shift = std::get<42>(this->_data); - DataType& w_o_shift = std::get<43>(this->_data); - DataType& w_4_shift = std::get<44>(this->_data); - DataType& sorted_accum_shift = std::get<45>(this->_data); - DataType& z_perm_shift = std::get<46>(this->_data); - DataType& z_lookup_shift = std::get<47>(this->_data); + DataType& q_busread = std::get<11>(this->_data); + DataType& sigma_1 = std::get<12>(this->_data); + DataType& sigma_2 = std::get<13>(this->_data); + DataType& sigma_3 = std::get<14>(this->_data); + DataType& sigma_4 = std::get<15>(this->_data); + DataType& id_1 = std::get<16>(this->_data); + DataType& id_2 = std::get<17>(this->_data); + DataType& id_3 = std::get<18>(this->_data); + DataType& id_4 = std::get<19>(this->_data); + DataType& table_1 = std::get<20>(this->_data); + DataType& table_2 = std::get<21>(this->_data); + DataType& table_3 = std::get<22>(this->_data); + DataType& table_4 = std::get<23>(this->_data); + DataType& lagrange_first = std::get<24>(this->_data); + DataType& lagrange_last = std::get<25>(this->_data); + DataType& lagrange_ecc_op = std::get<26>(this->_data); + DataType& w_l = std::get<27>(this->_data); + DataType& w_r = std::get<28>(this->_data); + DataType& w_o = std::get<29>(this->_data); + DataType& w_4 = std::get<30>(this->_data); + DataType& sorted_accum = std::get<31>(this->_data); + DataType& z_perm = std::get<32>(this->_data); + DataType& z_lookup = std::get<33>(this->_data); + DataType& ecc_op_wire_1 = std::get<34>(this->_data); + DataType& ecc_op_wire_2 = std::get<35>(this->_data); + DataType& ecc_op_wire_3 = std::get<36>(this->_data); + DataType& ecc_op_wire_4 = std::get<37>(this->_data); + DataType& calldata = std::get<38>(this->_data); + DataType& calldata_read_counts = std::get<39>(this->_data); + DataType& table_1_shift = std::get<40>(this->_data); + DataType& table_2_shift = std::get<41>(this->_data); + DataType& table_3_shift = std::get<42>(this->_data); + DataType& table_4_shift = std::get<43>(this->_data); + DataType& w_l_shift = std::get<44>(this->_data); + DataType& w_r_shift = std::get<45>(this->_data); + DataType& w_o_shift = std::get<46>(this->_data); + DataType& w_4_shift = std::get<47>(this->_data); + DataType& sorted_accum_shift = std::get<48>(this->_data); + DataType& z_perm_shift = std::get<49>(this->_data); + DataType& z_lookup_shift = std::get<50>(this->_data); std::vector get_wires() override { return { w_l, w_r, w_o, w_4 }; }; std::vector get_ecc_op_wires() @@ -237,25 +244,46 @@ template class GoblinUltraRecursive_ { // Gemini-specific getters. std::vector get_unshifted() override { - return { q_c, q_l, - q_r, q_o, - q_4, q_m, - q_arith, q_sort, - q_elliptic, q_aux, - q_lookup, sigma_1, - sigma_2, sigma_3, - sigma_4, id_1, - id_2, id_3, - id_4, table_1, - table_2, table_3, - table_4, lagrange_first, - lagrange_last, lagrange_ecc_op, - w_l, w_r, - w_o, w_4, - sorted_accum, z_perm, - z_lookup, ecc_op_wire_1, - ecc_op_wire_2, ecc_op_wire_3, - ecc_op_wire_4 }; + return { q_c, + q_l, + q_r, + q_o, + q_4, + q_m, + q_arith, + q_sort, + q_elliptic, + q_aux, + q_lookup, + q_busread, + sigma_1, + sigma_2, + sigma_3, + sigma_4, + id_1, + id_2, + id_3, + id_4, + table_1, + table_2, + table_3, + table_4, + lagrange_first, + lagrange_last, + lagrange_ecc_op, + w_l, + w_r, + w_o, + w_4, + sorted_accum, + z_perm, + z_lookup, + ecc_op_wire_1, + ecc_op_wire_2, + ecc_op_wire_3, + ecc_op_wire_4, + calldata, + calldata_read_counts }; }; std::vector get_to_be_shifted() override { @@ -325,6 +353,7 @@ template class GoblinUltraRecursive_ { this->q_elliptic = Commitment::from_witness(builder, native_key->q_elliptic); this->q_aux = Commitment::from_witness(builder, native_key->q_aux); this->q_lookup = Commitment::from_witness(builder, native_key->q_lookup); + this->q_busread = Commitment::from_witness(builder, native_key->q_busread); this->sigma_1 = Commitment::from_witness(builder, native_key->sigma_1); this->sigma_2 = Commitment::from_witness(builder, native_key->sigma_2); this->sigma_3 = Commitment::from_witness(builder, native_key->sigma_3); @@ -375,6 +404,8 @@ template class GoblinUltraRecursive_ { this->ecc_op_wire_2 = "ECC_OP_WIRE_2"; this->ecc_op_wire_3 = "ECC_OP_WIRE_3"; this->ecc_op_wire_4 = "ECC_OP_WIRE_4"; + this->calldata = "CALLDATA"; + this->calldata_read_counts = "CALLDATA_READ_COUNTS"; // The ones beginning with "__" are only used for debugging this->q_c = "__Q_C"; @@ -388,6 +419,7 @@ template class GoblinUltraRecursive_ { this->q_elliptic = "__Q_ELLIPTIC"; this->q_aux = "__Q_AUX"; this->q_lookup = "__Q_LOOKUP"; + this->q_busread = "__Q_BUSREAD"; this->sigma_1 = "__SIGMA_1"; this->sigma_2 = "__SIGMA_2"; this->sigma_3 = "__SIGMA_3"; @@ -421,6 +453,7 @@ template class GoblinUltraRecursive_ { this->q_elliptic = verification_key->q_elliptic; this->q_aux = verification_key->q_aux; this->q_lookup = verification_key->q_lookup; + this->q_busread = verification_key->q_busread; this->sigma_1 = verification_key->sigma_1; this->sigma_2 = verification_key->sigma_2; this->sigma_3 = verification_key->sigma_3; @@ -446,7 +479,6 @@ template class GoblinUltraRecursive_ { */ class Transcript : public BaseTranscript { public: - // Transcript objects defined as public member variables for easy access and modification uint32_t circuit_size; uint32_t public_input_size; uint32_t pub_inputs_offset; @@ -458,6 +490,8 @@ template class GoblinUltraRecursive_ { Commitment ecc_op_wire_2_comm; Commitment ecc_op_wire_3_comm; Commitment ecc_op_wire_4_comm; + Commitment calldata_comm; + Commitment calldata_read_counts_comm; Commitment sorted_accum_comm; Commitment w_4_comm; Commitment z_perm_comm; @@ -470,26 +504,9 @@ template class GoblinUltraRecursive_ { Transcript() = default; - // Used by verifier to initialize the transcript Transcript(const std::vector& proof) : BaseTranscript(proof) {} - - static Transcript prover_init_empty() - { - Transcript transcript; - constexpr uint32_t init{ 42 }; // arbitrary - transcript.send_to_verifier("Init", init); - return transcript; - }; - - static Transcript verifier_init_empty(const Transcript& transcript) - { - Transcript verifier_transcript{ transcript.proof_data }; - [[maybe_unused]] auto _ = verifier_transcript.template receive_from_prover("Init"); - return verifier_transcript; - }; - /** * @brief Takes a FULL GoblinUltraRecursive proof and deserializes it into the public member variables that * compose the structure. Must be called in order to access the structure of the proof. @@ -514,6 +531,9 @@ template class GoblinUltraRecursive_ { ecc_op_wire_2_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); ecc_op_wire_3_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); ecc_op_wire_4_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + calldata_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + calldata_read_counts_comm = + deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); sorted_accum_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); w_4_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); z_perm_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); @@ -532,6 +552,7 @@ template class GoblinUltraRecursive_ { zm_cq_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); zm_pi_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); } + /** * @brief Serializes the structure variables into a FULL GoblinUltraRecursive proof. Should be called only if * deserialize_full_transcript() was called and some transcript variable was modified. @@ -540,7 +561,7 @@ template class GoblinUltraRecursive_ { void serialize_full_transcript() override { size_t old_proof_length = BaseTranscript::proof_data.size(); - BaseTranscript::proof_data.clear(); // clear proof_data so the rest of the function can replace it + BaseTranscript::proof_data.clear(); size_t log_n = numeric::get_msb(circuit_size); serialize_to_buffer(circuit_size, BaseTranscript::proof_data); serialize_to_buffer(public_input_size, BaseTranscript::proof_data); @@ -555,6 +576,8 @@ template class GoblinUltraRecursive_ { serialize_to_buffer(ecc_op_wire_2_comm, BaseTranscript::proof_data); serialize_to_buffer(ecc_op_wire_3_comm, BaseTranscript::proof_data); serialize_to_buffer(ecc_op_wire_4_comm, BaseTranscript::proof_data); + serialize_to_buffer(calldata_comm, BaseTranscript::proof_data); + serialize_to_buffer(calldata_read_counts_comm, BaseTranscript::proof_data); serialize_to_buffer(sorted_accum_comm, BaseTranscript::proof_data); serialize_to_buffer(w_4_comm, BaseTranscript::proof_data); serialize_to_buffer(z_perm_comm, BaseTranscript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/honk/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/honk/instance/prover_instance.cpp index bff9f5e7ae3..3ef96a7f459 100644 --- a/barretenberg/cpp/src/barretenberg/honk/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/instance/prover_instance.cpp @@ -58,9 +58,10 @@ template void ProverInstance_::compute_witness(Circuit& c proving_key->w_o = wire_polynomials[2]; proving_key->w_4 = wire_polynomials[3]; - // If Goblin, construct the ECC op queue wire polynomials + // If Goblin, construct the ECC op queue wire and databus polynomials if constexpr (IsGoblinFlavor) { construct_ecc_op_wire_polynomials(wire_polynomials); + construct_databus_polynomials(circuit); } // Construct the sorted concatenated list polynomials for the lookup argument @@ -183,6 +184,30 @@ template void ProverInstance_::construct_ecc_op_wire_poly proving_key->ecc_op_wire_4 = op_wire_polynomials[3]; } +/** + * @brief + * @details + * + * @tparam Flavor + * @param circuit + */ +template void ProverInstance_::construct_databus_polynomials(Circuit& circuit) +{ + if constexpr (IsGoblinFlavor) { + polynomial public_calldata(dyadic_circuit_size); + polynomial calldata_read_counts(dyadic_circuit_size); + + const size_t offset = Flavor::has_zero_row ? 1 : 0; + for (size_t idx = 0; idx < circuit.public_calldata.size(); ++idx) { + public_calldata[idx + offset] = circuit.get_variable(circuit.public_calldata[idx]); + calldata_read_counts[idx + offset] = circuit.get_variable(circuit.calldata_read_counts[idx]); + } + + proving_key->calldata = public_calldata; + proving_key->calldata_read_counts = calldata_read_counts; + } +} + template std::shared_ptr ProverInstance_::compute_proving_key(Circuit& circuit) { @@ -467,6 +492,7 @@ std::shared_ptr ProverInstance_::compu // due to its simple structure. Handling it in the same way as the lagrange polys for now for simplicity. if constexpr (IsGoblinFlavor) { verification_key->lagrange_ecc_op = commitment_key->commit(proving_key->lagrange_ecc_op); + verification_key->q_busread = commitment_key->commit(proving_key->q_busread); } // // See `add_recusrive_proof()` for how this recursive data is assigned. diff --git a/barretenberg/cpp/src/barretenberg/honk/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/honk/instance/prover_instance.hpp index 42e5b50e1a7..1119bd79128 100644 --- a/barretenberg/cpp/src/barretenberg/honk/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/instance/prover_instance.hpp @@ -92,6 +92,8 @@ template class ProverInstance_ { void construct_ecc_op_wire_polynomials(auto&); + void construct_databus_polynomials(Circuit&); + void add_table_column_selector_poly_to_proving_key(barretenberg::polynomial& small, const std::string& tag); void add_plookup_memory_records_to_wire_4(FF); diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 224fa64ab20..afbb045b1c1 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -54,11 +54,17 @@ template void UltraProver_::execute_wire_commitment } if constexpr (IsGoblinFlavor) { + // Commit to Goblin ECC op wires auto op_wire_polys = instance->proving_key->get_ecc_op_wires(); auto labels = commitment_labels.get_ecc_op_wires(); for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { transcript.send_to_verifier(labels[idx], commitment_key->commit(op_wire_polys[idx])); } + // Commit to DataBus columns + transcript.send_to_verifier(commitment_labels.calldata, + commitment_key->commit(instance->proving_key->calldata)); + transcript.send_to_verifier(commitment_labels.calldata_read_counts, + commitment_key->commit(instance->proving_key->calldata_read_counts)); } } diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index ab2fb367b91..53bc9e20219 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -70,7 +70,7 @@ template bool UltraVerifier_::verify_proof(const plonk commitments.w_r = transcript.template receive_from_prover(commitment_labels.w_r); commitments.w_o = transcript.template receive_from_prover(commitment_labels.w_o); - // If Goblin, get commitments to ECC op wire polynomials + // If Goblin, get commitments to ECC op wire polynomials and DataBus columns if constexpr (IsGoblinFlavor) { commitments.ecc_op_wire_1 = transcript.template receive_from_prover(commitment_labels.ecc_op_wire_1); @@ -80,6 +80,9 @@ template bool UltraVerifier_::verify_proof(const plonk transcript.template receive_from_prover(commitment_labels.ecc_op_wire_3); commitments.ecc_op_wire_4 = transcript.template receive_from_prover(commitment_labels.ecc_op_wire_4); + commitments.calldata = transcript.template receive_from_prover(commitment_labels.calldata); + commitments.calldata_read_counts = + transcript.template receive_from_prover(commitment_labels.calldata_read_counts); } // Get challenge for sorted list batching and wire four memory records diff --git a/barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp index c1d07a642f5..4e9f5cd7e61 100644 --- a/barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp @@ -51,6 +51,8 @@ class GoblinUltraTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "ECC_OP_WIRE_2", size_G); manifest_expected.add_entry(round, "ECC_OP_WIRE_3", size_G); manifest_expected.add_entry(round, "ECC_OP_WIRE_4", size_G); + manifest_expected.add_entry(round, "CALLDATA", size_G); + manifest_expected.add_entry(round, "CALLDATA_READ_COUNTS", size_G); manifest_expected.add_challenge(round, "eta"); round++; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index ec3b20b4bad..ae5b8d172d2 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -106,11 +106,11 @@ template class Ultra { template class UltraHonk : public Ultra { public: - static constexpr size_t NUM_SELECTORS = 11; // 12; + static constexpr size_t NUM_SELECTORS = 12; using FF = FF_; using SelectorType = std::vector>; - // SelectorType& q_busread() { return this->selectors[11]; }; + SelectorType& q_busread() { return this->selectors[11]; }; UltraHonk() : Ultra(NUM_SELECTORS) 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 d5912d343aa..131876d4b21 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 @@ -24,25 +24,30 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ { UltraCircuitBuilder_>::add_gates_to_ensure_all_polys_are_non_zero(); - // WORKTODO: addtional logic to take care of q_busread selector - // 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(1); - // this->q_1.emplace_back(1); - // this->q_2.emplace_back(1); - // this->q_3.emplace_back(1); - // this->q_c.emplace_back(0); - // this->q_sort.emplace_back(1); - - // this->q_arith.emplace_back(1); - // this->q_4.emplace_back(1); - // this->q_lookup_type.emplace_back(0); - // this->q_elliptic.emplace_back(1); - // this->q_aux.emplace_back(1); - // pad_additional_selectors(); - // ++this->num_gates; + // Additional gate to add a nonzero value to q_busread + 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_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); + q_busread.emplace_back(1); + ++this->num_gates; + + // Add some nonzero values to the calldata and corresponding read counts + // WORKTODO: will need to do this more carefully once we actually have a databus lookup relation + public_calldata.emplace_back(this->one_idx); + calldata_read_counts.emplace_back(this->one_idx); } /** 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 da844afccbc..c4959ea4bbe 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 @@ -35,6 +35,7 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui uint32_t equality_op_idx; using WireVector = std::vector>; + using SelectorVector = std::vector>; // Wires storing ecc op queue data; values are indices into the variables array std::array::NUM_WIRES> ecc_op_wires; @@ -44,8 +45,11 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui WireVector& ecc_op_wire_3 = std::get<2>(ecc_op_wires); WireVector& ecc_op_wire_4 = std::get<3>(ecc_op_wires); + SelectorVector& q_busread = this->selectors.q_busread(); + // DataBus call/return data arrays std::vector public_calldata; + std::vector calldata_read_counts; std::vector public_return_data; // Functions for adding ECC op queue "gates" @@ -76,7 +80,7 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui void finalize_circuit(); void add_gates_to_ensure_all_polys_are_non_zero(); - void pad_additional_selectors() override{}; + void pad_additional_selectors() override { q_busread.emplace_back(0); }; size_t get_num_constant_gates() const override { return 0; } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp b/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp index c1bcc1fe754..a4eca92741a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp @@ -22,7 +22,8 @@ void construct_selector_polynomials(const typename Flavor::CircuitBuilder& circu size_t gate_offset = zero_row_offset + circuit_constructor.public_inputs.size(); // If Goblin, (1) update the conventional gate offset to account for ecc op gates at the top of the execution trace, - // and (2) construct ecc op gate selector polynomial. + // and (2) construct ecc op gate selector polynomial. This selector is handled separately from the others since it + // is computable based simply on num_ecc_op_gates and thus is not constructed explicitly in the builder. // Note 1: All other selectors will be automatically and correctly initialized to 0 on this domain. // Note 2: If applicable, the ecc op gates are shifted down by 1 to account for a zero row. if constexpr (IsGoblinFlavor) { @@ -30,11 +31,11 @@ void construct_selector_polynomials(const typename Flavor::CircuitBuilder& circu gate_offset += num_ecc_op_gates; const size_t op_gate_offset = zero_row_offset; // The op gate selector is simply the indicator on the domain [offset, num_ecc_op_gates + offset - 1] - barretenberg::polynomial selector_poly_lagrange(proving_key->circuit_size); + barretenberg::polynomial ecc_op_selector(proving_key->circuit_size); for (size_t i = 0; i < num_ecc_op_gates; ++i) { - selector_poly_lagrange[i + op_gate_offset] = 1; + ecc_op_selector[i + op_gate_offset] = 1; } - proving_key->lagrange_ecc_op = selector_poly_lagrange; + proving_key->lagrange_ecc_op = ecc_op_selector; } // TODO(#398): Loose coupling here! Would rather build up pk from arithmetization diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp index 068a62ca1c8..67d57aa8cc2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp @@ -57,7 +57,7 @@ std::array UltraRecursiveVerifier_::ve commitments.w_r = transcript.template receive_from_prover(commitment_labels.w_r); commitments.w_o = transcript.template receive_from_prover(commitment_labels.w_o); - // If Goblin, get commitments to ECC op wire polynomials + // If Goblin, get commitments to ECC op wire polynomials and DataBus columns if constexpr (IsGoblinFlavor) { commitments.ecc_op_wire_1 = transcript.template receive_from_prover(commitment_labels.ecc_op_wire_1); @@ -67,6 +67,9 @@ std::array UltraRecursiveVerifier_::ve transcript.template receive_from_prover(commitment_labels.ecc_op_wire_3); commitments.ecc_op_wire_4 = transcript.template receive_from_prover(commitment_labels.ecc_op_wire_4); + commitments.calldata = transcript.template receive_from_prover(commitment_labels.calldata); + commitments.calldata_read_counts = + transcript.template receive_from_prover(commitment_labels.calldata_read_counts); } // Get challenge for sorted list batching and wire four memory records