From dd9dd84e9cfc93f8605f28aa25fa36b0004052cb Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:18:46 -0700 Subject: [PATCH] feat: DataBus PoC (UltraHonk as extension of Ultra) (#3181) This work adds some basic PoC DataBus functionality to the GoblinUltra/UltraHonk arithmetization. In particular, it allows for proving lookups/reads from a new `calldata` column in the execution trace. The corresponding relation has been set up to share logic with the existing log-derivative lookup relation implemented in the ECCVM proving system. This work also establishes the mechanism for reusing the conventional `Ultra` arithmetization/builder logic (e.g. gate creation) in builders that extend this basic functionality. This same mechanism will be used shortly by @lucasxia01 to add a custom gate for poseidon hashing. --- .../src/barretenberg/flavor/goblin_ultra.hpp | 87 +++++---- .../flavor/goblin_ultra_recursive.hpp | 112 +++++++---- .../goblin/full_goblin_composer.test.cpp | 6 +- .../honk/proof_system/lookup_library.hpp | 8 +- .../goblin_ultra_circuit_builder.cpp | 33 +++- .../relations/databus_lookup_relation.hpp | 178 ++++++++++++++++++ .../relations/ecc_vm/ecc_lookup_relation.hpp | 14 ++ .../verifier/ultra_recursive_verifier.cpp | 16 +- .../sumcheck/instance/prover_instance.cpp | 53 ++++-- .../sumcheck/instance/prover_instance.hpp | 3 + .../ultra_honk/goblin_ultra_composer.test.cpp | 8 +- .../goblin_ultra_transcript.test.cpp | 5 +- .../ultra_honk/relation_correctness.test.cpp | 46 +++++ .../barretenberg/ultra_honk/ultra_prover.cpp | 25 ++- .../barretenberg/ultra_honk/ultra_prover.hpp | 3 + .../ultra_honk/ultra_verifier.cpp | 6 + 16 files changed, 489 insertions(+), 114 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 5b83ffc3154..ad09352b917 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -4,13 +4,16 @@ #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" +#include "barretenberg/relations/databus_lookup_relation.hpp" #include "barretenberg/relations/ecc_op_queue_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" #include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" +#include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/transcript/transcript.hpp" +#include "relation_definitions_fwd.hpp" namespace proof_system::honk::flavor { @@ -32,13 +35,12 @@ class GoblinUltra { // 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. - // 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; + static constexpr size_t NUM_ALL_ENTITIES = 53; // 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 = 27; // 25 (UH) + 1 op wire "selector" + q_busread + static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 28; // The total number of witness entities not including shifts. - static constexpr size_t NUM_WITNESS_ENTITIES = 17; // 11 (UH) + 4 op wires + (calldata + calldata_read_counts) + static constexpr size_t NUM_WITNESS_ENTITIES = 18; using GrandProductRelations = std::tuple, proof_system::LookupRelation>; @@ -50,7 +52,10 @@ class GoblinUltra { proof_system::GenPermSortRelation, proof_system::EllipticRelation, proof_system::AuxiliaryRelation, - proof_system::EccOpQueueRelation>; + proof_system::EccOpQueueRelation, + proof_system::DatabusLookupRelation>; + + using LogDerivLookupRelation = proof_system::DatabusLookupRelation; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length(); @@ -106,6 +111,7 @@ class GoblinUltra { DataType lagrange_first; // column 24 DataType lagrange_last; // column 25 DataType lagrange_ecc_op; // column 26 // indicator poly for ecc op gates + DataType databus_id; // column 27 // id polynomial, i.e. id_i = i DEFINE_POINTER_VIEW(NUM_PRECOMPUTED_ENTITIES, &q_m, @@ -134,7 +140,8 @@ class GoblinUltra { &table_4, &lagrange_first, &lagrange_last, - &lagrange_ecc_op) + &lagrange_ecc_op, + &databus_id) static constexpr CircuitType CIRCUIT_TYPE = CircuitBuilder::CIRCUIT_TYPE; @@ -172,6 +179,7 @@ class GoblinUltra { DataType ecc_op_wire_4; // column 14 DataType calldata; // column 15 DataType calldata_read_counts; // column 16 + DataType lookup_inverses; // column 17 DEFINE_POINTER_VIEW(NUM_WITNESS_ENTITIES, &w_l, @@ -190,7 +198,8 @@ class GoblinUltra { &ecc_op_wire_3, &ecc_op_wire_4, &calldata, - &calldata_read_counts) + &calldata_read_counts, + &lookup_inverses) std::vector get_wires() override { return { w_l, w_r, w_o, w_4 }; }; std::vector get_ecc_op_wires() @@ -240,30 +249,32 @@ class GoblinUltra { DataType lagrange_first; // column 24 DataType lagrange_last; // column 25 DataType lagrange_ecc_op; // column 26 - DataType w_l; // column 27 - DataType w_r; // column 28 - DataType w_o; // column 29 - DataType w_4; // column 30 - DataType sorted_accum; // column 31 - DataType z_perm; // column 32 - DataType z_lookup; // column 33 - DataType ecc_op_wire_1; // column 34 - DataType ecc_op_wire_2; // column 35 - DataType ecc_op_wire_3; // column 36 - DataType ecc_op_wire_4; // column 37 - DataType calldata; // column 38 - DataType calldata_read_counts; // column 39 - DataType table_1_shift; // column 40 - DataType table_2_shift; // column 41 - DataType table_3_shift; // column 42 - DataType table_4_shift; // column 43 - DataType w_l_shift; // column 44 - DataType w_r_shift; // column 45 - DataType w_o_shift; // column 46 - DataType w_4_shift; // column 47 - DataType sorted_accum_shift; // column 48 - DataType z_perm_shift; // column 49 - DataType z_lookup_shift; // column 50 + DataType databus_id; // column 27 + DataType w_l; // column 28 + DataType w_r; // column 29 + DataType w_o; // column 30 + DataType w_4; // column 31 + DataType sorted_accum; // column 32 + DataType z_perm; // column 33 + DataType z_lookup; // column 34 + DataType ecc_op_wire_1; // column 35 + DataType ecc_op_wire_2; // column 36 + DataType ecc_op_wire_3; // column 37 + DataType ecc_op_wire_4; // column 38 + DataType calldata; // column 39 + DataType calldata_read_counts; // column 40 + DataType lookup_inverses; // column 41 + DataType table_1_shift; // column 42 + DataType table_2_shift; // column 43 + DataType table_3_shift; // column 44 + DataType table_4_shift; // column 45 + DataType w_l_shift; // column 46 + DataType w_r_shift; // column 47 + DataType w_o_shift; // column 48 + DataType w_4_shift; // column 49 + DataType sorted_accum_shift; // column 50 + DataType z_perm_shift; // column 51 + DataType z_lookup_shift; // column 52 // defines a method pointer_view that returns the following, with const and non-const variants DEFINE_POINTER_VIEW(NUM_ALL_ENTITIES, @@ -294,6 +305,7 @@ class GoblinUltra { &lagrange_first, &lagrange_last, &lagrange_ecc_op, + &databus_id, &w_l, &w_r, &w_o, @@ -307,6 +319,7 @@ class GoblinUltra { &ecc_op_wire_4, &calldata, &calldata_read_counts, + &lookup_inverses, &table_1_shift, &table_2_shift, &table_3_shift, @@ -354,6 +367,7 @@ class GoblinUltra { lagrange_first, lagrange_last, lagrange_ecc_op, + databus_id, w_l, w_r, w_o, @@ -366,7 +380,8 @@ class GoblinUltra { ecc_op_wire_3, ecc_op_wire_4, calldata, - calldata_read_counts }; + calldata_read_counts, + lookup_inverses }; }; std::vector get_to_be_shifted() override { @@ -489,6 +504,7 @@ class GoblinUltra { ecc_op_wire_4 = "ECC_OP_WIRE_4"; calldata = "CALLDATA"; calldata_read_counts = "CALLDATA_READ_COUNTS"; + lookup_inverses = "LOOKUP_INVERSES"; // The ones beginning with "__" are only used for debugging q_c = "__Q_C"; @@ -554,6 +570,7 @@ class GoblinUltra { lagrange_first = verification_key->lagrange_first; lagrange_last = verification_key->lagrange_last; lagrange_ecc_op = verification_key->lagrange_ecc_op; + databus_id = verification_key->databus_id; } }; @@ -582,6 +599,7 @@ class GoblinUltra { Commitment ecc_op_wire_4_comm; Commitment calldata_comm; Commitment calldata_read_counts_comm; + Commitment lookup_inverses_comm; Commitment sorted_accum_comm; Commitment w_4_comm; Commitment z_perm_comm; @@ -597,6 +615,7 @@ class GoblinUltra { Transcript(const std::vector& proof) : BaseTranscript(proof) {} + void deserialize_full_transcript() override { // take current proof and put them into the struct @@ -618,6 +637,7 @@ class GoblinUltra { 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); + lookup_inverses_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); @@ -656,6 +676,7 @@ class GoblinUltra { 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(lookup_inverses_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); @@ -675,4 +696,4 @@ class GoblinUltra { }; }; -} // namespace proof_system::honk::flavor +} // namespace proof_system::honk::flavor \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index e85e9578ce2..f37d26b3adc 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -61,13 +61,12 @@ 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. - // 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; + static constexpr size_t NUM_ALL_ENTITIES = 53; // 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 = 27; // 25 (UH) + 1 op wire "selector" + q_busread + static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 28; // The total number of witness entities not including shifts. - static constexpr size_t NUM_WITNESS_ENTITIES = 17; // 11 (UH) + 4 op wires + (calldata + calldata_read_counts) + static constexpr size_t NUM_WITNESS_ENTITIES = 18; // define the tuple of Relations that comprise the Sumcheck relation using Relations = std::tuple, @@ -76,7 +75,8 @@ template class GoblinUltraRecursive_ { proof_system::GenPermSortRelation, proof_system::EllipticRelation, proof_system::AuxiliaryRelation, - proof_system::EccOpQueueRelation>; + proof_system::EccOpQueueRelation, + proof_system::DatabusLookupRelation>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); @@ -125,6 +125,37 @@ template class GoblinUltraRecursive_ { DataType lagrange_first; // column 24 DataType lagrange_last; // column 25 DataType lagrange_ecc_op; // column 26 // indicator poly for ecc op gates + DataType databus_id; // column 27 // id polynomial, i.e. id_i = i + + DEFINE_POINTER_VIEW(NUM_PRECOMPUTED_ENTITIES, + &q_m, + &q_c, + &q_l, + &q_r, + &q_o, + &q_4, + &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, + &databus_id) static constexpr CircuitType CIRCUIT_TYPE = CircuitBuilder::CIRCUIT_TYPE; @@ -162,6 +193,7 @@ template class GoblinUltraRecursive_ { DataType ecc_op_wire_4; // column 14 DataType calldata; // column 15 DataType calldata_read_counts; // column 16 + DataType lookup_inverses; // column 17 DEFINE_POINTER_VIEW(NUM_WITNESS_ENTITIES, &w_l, @@ -180,7 +212,8 @@ template class GoblinUltraRecursive_ { &ecc_op_wire_3, &ecc_op_wire_4, &calldata, - &calldata_read_counts) + &calldata_read_counts, + &lookup_inverses) std::vector get_wires() override { return { w_l, w_r, w_o, w_4 }; }; std::vector get_ecc_op_wires() @@ -230,31 +263,34 @@ template class GoblinUltraRecursive_ { DataType lagrange_first; // column 24 DataType lagrange_last; // column 25 DataType lagrange_ecc_op; // column 26 - DataType w_l; // column 27 - DataType w_r; // column 28 - DataType w_o; // column 29 - DataType w_4; // column 30 - DataType sorted_accum; // column 31 - DataType z_perm; // column 32 - DataType z_lookup; // column 33 - DataType ecc_op_wire_1; // column 34 - DataType ecc_op_wire_2; // column 35 - DataType ecc_op_wire_3; // column 36 - DataType ecc_op_wire_4; // column 37 - DataType calldata; // column 38 - DataType calldata_read_counts; // column 39 - DataType table_1_shift; // column 40 - DataType table_2_shift; // column 41 - DataType table_3_shift; // column 42 - DataType table_4_shift; // column 43 - DataType w_l_shift; // column 44 - DataType w_r_shift; // column 45 - DataType w_o_shift; // column 46 - DataType w_4_shift; // column 47 - DataType sorted_accum_shift; // column 48 - DataType z_perm_shift; // column 49 - DataType z_lookup_shift; // column 50 - + DataType databus_id; // column 27 + DataType w_l; // column 28 + DataType w_r; // column 29 + DataType w_o; // column 30 + DataType w_4; // column 31 + DataType sorted_accum; // column 32 + DataType z_perm; // column 33 + DataType z_lookup; // column 34 + DataType ecc_op_wire_1; // column 35 + DataType ecc_op_wire_2; // column 36 + DataType ecc_op_wire_3; // column 37 + DataType ecc_op_wire_4; // column 38 + DataType calldata; // column 39 + DataType calldata_read_counts; // column 40 + DataType lookup_inverses; // column 41 + DataType table_1_shift; // column 42 + DataType table_2_shift; // column 43 + DataType table_3_shift; // column 44 + DataType table_4_shift; // column 45 + DataType w_l_shift; // column 46 + DataType w_r_shift; // column 47 + DataType w_o_shift; // column 48 + DataType w_4_shift; // column 49 + DataType sorted_accum_shift; // column 50 + DataType z_perm_shift; // column 51 + DataType z_lookup_shift; // column 52 + + // defines a method pointer_view that returns the following, with const and non-const variants DEFINE_POINTER_VIEW(NUM_ALL_ENTITIES, &q_c, &q_l, @@ -283,6 +319,7 @@ template class GoblinUltraRecursive_ { &lagrange_first, &lagrange_last, &lagrange_ecc_op, + &databus_id, &w_l, &w_r, &w_o, @@ -296,6 +333,7 @@ template class GoblinUltraRecursive_ { &ecc_op_wire_4, &calldata, &calldata_read_counts, + &lookup_inverses, &table_1_shift, &table_2_shift, &table_3_shift, @@ -306,7 +344,7 @@ template class GoblinUltraRecursive_ { &w_4_shift, &sorted_accum_shift, &z_perm_shift, - &z_lookup_shift) + &z_lookup_shift); std::vector get_wires() override { return { w_l, w_r, w_o, w_4 }; }; std::vector get_ecc_op_wires() @@ -343,6 +381,7 @@ template class GoblinUltraRecursive_ { lagrange_first, lagrange_last, lagrange_ecc_op, + databus_id, w_l, w_r, w_o, @@ -355,7 +394,8 @@ template class GoblinUltraRecursive_ { ecc_op_wire_3, ecc_op_wire_4, calldata, - calldata_read_counts }; + calldata_read_counts, + lookup_inverses }; }; std::vector get_to_be_shifted() override { @@ -416,6 +456,7 @@ template class GoblinUltraRecursive_ { this->lagrange_first = Commitment::from_witness(builder, native_key->lagrange_first); this->lagrange_last = Commitment::from_witness(builder, native_key->lagrange_last); this->lagrange_ecc_op = Commitment::from_witness(builder, native_key->lagrange_ecc_op); + this->databus_id = Commitment::from_witness(builder, native_key->databus_id); }; }; @@ -453,6 +494,7 @@ template class GoblinUltraRecursive_ { this->ecc_op_wire_4 = "ECC_OP_WIRE_4"; this->calldata = "CALLDATA"; this->calldata_read_counts = "CALLDATA_READ_COUNTS"; + this->lookup_inverses = "LOOKUP_INVERSES"; // The ones beginning with "__" are only used for debugging this->q_c = "__Q_C"; @@ -516,6 +558,7 @@ template class GoblinUltraRecursive_ { this->lagrange_first = verification_key->lagrange_first; this->lagrange_last = verification_key->lagrange_last; this->lagrange_ecc_op = verification_key->lagrange_ecc_op; + this->databus_id = verification_key->databus_id; } }; @@ -539,6 +582,7 @@ template class GoblinUltraRecursive_ { Commitment ecc_op_wire_4_comm; Commitment calldata_comm; Commitment calldata_read_counts_comm; + Commitment lookup_inverses_comm; Commitment sorted_accum_comm; Commitment w_4_comm; Commitment z_perm_comm; @@ -581,6 +625,7 @@ template class GoblinUltraRecursive_ { calldata_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); calldata_read_counts_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + lookup_inverses_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); @@ -625,6 +670,7 @@ template class GoblinUltraRecursive_ { 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(lookup_inverses_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/goblin/full_goblin_composer.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/full_goblin_composer.test.cpp index cca8eeed977..0c675939b0c 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/full_goblin_composer.test.cpp @@ -80,7 +80,7 @@ class FullGoblinComposerTests : public ::testing::Test { static void perform_op_queue_interactions_for_mock_first_circuit( std::shared_ptr& op_queue) { - auto builder = GoblinUltraBuilder(op_queue); + auto builder = GoblinUltraBuilder{ op_queue }; // Add a mul accum op and an equality op auto point = Point::one() * FF::random_element(); @@ -163,7 +163,7 @@ TEST_F(FullGoblinComposerTests, SimpleCircuit) // Construct a series of simple Goblin circuits; generate and verify their proofs size_t NUM_CIRCUITS = 3; for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - auto builder = GoblinUltraBuilder(op_queue); + auto builder = GoblinUltraBuilder{ op_queue }; generate_test_circuit(builder); @@ -205,7 +205,7 @@ TEST_F(FullGoblinComposerTests, SimpleCircuitFailureCase) // Construct a series of simple Goblin circuits; generate and verify their proofs size_t NUM_CIRCUITS = 3; for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - auto builder = GoblinUltraBuilder(op_queue); + auto builder = GoblinUltraBuilder{ op_queue }; generate_test_circuit(builder); diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/lookup_library.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/lookup_library.hpp index b8770040beb..820bc2907a5 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/lookup_library.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/lookup_library.hpp @@ -1,5 +1,4 @@ #pragma once -#include "barretenberg/sumcheck/sumcheck.hpp" #include namespace proof_system::honk::lookup_library { @@ -24,9 +23,7 @@ namespace proof_system::honk::lookup_library { * */ template -void compute_logderivative_inverse(Polynomials& polynomials, - proof_system::RelationParameters& relation_parameters, - const size_t circuit_size) +void compute_logderivative_inverse(Polynomials& polynomials, auto& relation_parameters, const size_t circuit_size) { using FF = typename Flavor::FF; using Accumulator = typename Relation::ValueAccumulator0; @@ -128,6 +125,7 @@ void accumulate_logderivative_lookup_subrelation_contributions(ContainerOverSubr const auto inverse_exists = lookup_relation.template compute_inverse_exists(in); + // Note: the lookup_inverses are computed so that the value is 0 if !inverse_exists std::get<0>(accumulator) += (denominator_accumulator[NUM_TOTAL_TERMS - 1] * lookup_inverses - inverse_exists) * scaling_factor; @@ -150,7 +148,7 @@ void accumulate_logderivative_lookup_subrelation_contributions(ContainerOverSubr // degree of relation = NUM_TOTAL_TERMS + 2 barretenberg::constexpr_for<0, WRITE_TERMS, 1>([&]() { const auto p = lookup_relation.template compute_write_term_predicate(in); - const auto lookup_read_count = View(in.template lookup_read_counts()); + const auto lookup_read_count = lookup_relation.template lookup_read_counts(in); std::get<1>(accumulator) -= p * (denominator_accumulator[i + READ_TERMS] * lookup_read_count); }); } 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 5611b7ec5a0..610aefccf09 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 @@ -22,11 +22,31 @@ template void GoblinUltraCircuitBuilder_::finalize_circuit() // polynomials is zero, which is required for them to be shiftable. template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_non_zero() { + // Most polynomials are handled via the conventional Ultra method UltraCircuitBuilder_>::add_gates_to_ensure_all_polys_are_non_zero(); - // 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); + // All that remains is to handle databus related polynomials. In what follows we populate the calldata with some + // mock data then constuct a single calldata read gate + + // Populate the calldata with some data + public_calldata.emplace_back(this->add_variable(FF(5))); + public_calldata.emplace_back(this->add_variable(FF(7))); + public_calldata.emplace_back(this->add_variable(FF(9))); + + // Construct read counts with length of calldata + calldata_read_counts.resize(public_calldata.size()); + for (auto& val : calldata_read_counts) { + val = 0; + } + + // Construct gate corresponding to a single calldata read + size_t read_idx = 1; // index into calldata array at which we want to read + this->w_l.emplace_back(public_calldata[read_idx]); // populate with value of calldata at read index + this->w_r.emplace_back(this->add_variable(FF(read_idx))); // populate with read index as witness + calldata_read_counts[read_idx]++; // increment read count at read index + q_busread.emplace_back(1); // read selector on + + // 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); @@ -35,18 +55,13 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ 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 - public_calldata.emplace_back(this->one_idx); - calldata_read_counts.emplace_back(this->one_idx); + ++this->num_gates; } /** diff --git a/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp new file mode 100644 index 00000000000..da659a321e9 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp @@ -0,0 +1,178 @@ +#pragma once +#include +#include + +#include "barretenberg/common/constexpr_utils.hpp" +#include "barretenberg/honk/proof_system/lookup_library.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/relations/relation_types.hpp" + +namespace proof_system { + +template class DatabusLookupRelationImpl { + public: + using FF = FF_; + static constexpr size_t READ_TERMS = 1; + static constexpr size_t WRITE_TERMS = 1; + // 1 + polynomial degree of this relation + static constexpr size_t LENGTH = READ_TERMS + WRITE_TERMS + 3; + + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + LENGTH, // inverse polynomial correctness subrelation + LENGTH // log-derivative lookup argument subrelation + }; + + // The second subrelation is "linearly dependant" in the sense that it establishes the value of a sum across the + // entire execution trace rather than a per-row identity. + static constexpr std::array SUBRELATION_LINEARLY_INDEPENDENT = { true, false }; + + /** + * @brief Determine whether the inverse I needs to be computed at a given row + * @details The value of the inverse polynomial I(X) only needs to be computed when the databus lookup gate is + * "active". Otherwise it is set to 0. This method allows for determination of when the inverse should be computed. + * + * @tparam AllValues + * @param row + * @return true + * @return false + */ + template static bool lookup_exists_at_row(const AllValues& row) + { + return (row.q_busread == 1 || row.calldata_read_counts > 0); + } + + /** + * @brief Compute the Accumulator whose values indicate whether the inverse is computed or not + * @details This is needed for efficiency since we don't need to compute the inverse unless the log derivative + * lookup relation is active at a given row. + * + */ + template + static Accumulator compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + // TODO(luke): row_has_read should really be a boolean object thats equal to 1 when counts > 0 and 0 otherwise. + // This current structure will lead to failure if call_data_read_counts > 1. + const auto row_has_write = View(in.q_busread); + const auto row_has_read = View(in.calldata_read_counts); + + return row_has_write + row_has_read - (row_has_write * row_has_read); + + return Accumulator(View(in.q_busread) + View(in.calldata_read_counts)); + } + + template + static Accumulator lookup_read_counts(const AllEntities& in) + { + using View = typename Accumulator::View; + + if constexpr (index == 0) { + return Accumulator(View(in.calldata_read_counts)); + } + return Accumulator(1); + } + + /** + * @brief Compute scalar for read term in log derivative lookup argument + * + */ + template + static Accumulator compute_read_term_predicate([[maybe_unused]] const AllEntities& in) + + { + using View = typename Accumulator::View; + + if constexpr (read_index == 0) { + return Accumulator(View(in.q_busread)); + } + return Accumulator(1); + } + + /** + * @brief Compute scalar for write term in log derivative lookup argument + * + */ + template + static Accumulator compute_write_term_predicate(const AllEntities& /*unused*/) + { + return Accumulator(1); + } + + /** + * @brief Compute write term denominator in log derivative lookup argument + * + */ + template + static Accumulator compute_write_term(const AllEntities& in, const Parameters& params) + { + using View = typename Accumulator::View; + using ParameterView = GetParameterView; + + static_assert(write_index < WRITE_TERMS); + + const auto& calldata = View(in.calldata); + const auto& id = View(in.databus_id); + + const auto& gamma = ParameterView(params.gamma); + const auto& beta = ParameterView(params.beta); + + // Construct b_i + idx_i*\beta + \gamma + if constexpr (write_index == 0) { + return calldata + gamma + id * beta; // degree 1 + } + + return Accumulator(1); + } + + /** + * @brief Compute read term denominator in log derivative lookup argument + * + */ + template + static Accumulator compute_read_term(const AllEntities& in, const Parameters& params) + { + using View = typename Accumulator::View; + using ParameterView = GetParameterView; + + static_assert(read_index < READ_TERMS); + + // Bus value stored in w_1, index into bus column stored in w_2 + const auto& w_1 = View(in.w_l); + const auto& w_2 = View(in.w_r); + + const auto& gamma = ParameterView(params.gamma); + const auto& beta = ParameterView(params.beta); + + // Construct value + index*\beta + \gamma + if constexpr (read_index == 0) { + return w_1 + gamma + w_2 * beta; + } + + return Accumulator(1); + } + + /** + * @brief Accumulate the contribution from two surelations for the log derivative databus lookup argument + * @details See lookup_library.hpp for details of the generic log-derivative lookup argument + * + * @param accumulator transformed to `evals + C(in(X)...)*scaling_factor` + * @param in an std::array containing the fully extended Accumulator edges. + * @param params contains beta, gamma, and public_input_delta, .... + * @param scaling_factor optional term to scale the evaluation before adding to evals. + */ + template + static void accumulate(ContainerOverSubrelations& accumulator, + const AllEntities& in, + const Parameters& params, + const FF& scaling_factor) + { + honk::lookup_library::accumulate_logderivative_lookup_subrelation_contributions>( + accumulator, in, params, scaling_factor); + } +}; + +template using DatabusLookupRelation = Relation>; + +} // namespace proof_system diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_lookup_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_lookup_relation.hpp index fc04d785187..35af59f7490 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_lookup_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_lookup_relation.hpp @@ -40,6 +40,20 @@ template class ECCVMLookupRelationImpl { return row_has_write + row_has_read - (row_has_write * row_has_read); } + template + static Accumulator lookup_read_counts(const AllEntities& in) + { + using View = typename Accumulator::View; + + if constexpr (index == 0) { + return Accumulator(View(in.lookup_read_counts_0)); + } + if constexpr (index == 1) { + return Accumulator(View(in.lookup_read_counts_1)); + } + return Accumulator(1); + } + template static Accumulator compute_read_term_predicate(const AllEntities& in) 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 c4d91dbf987..d94df58d62a 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 @@ -30,9 +30,6 @@ std::array UltraRecursiveVerifier_::ve RelationParams relation_parameters; - info("Initial: num gates = ", builder->get_num_gates()); - size_t prev_num_gates = builder->get_num_gates(); - transcript = Transcript{ builder, proof.proof_data }; auto commitments = VerifierCommitments(key); @@ -83,6 +80,12 @@ std::array UltraRecursiveVerifier_::ve // Get permutation challenges auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); + // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial + if constexpr (IsGoblinFlavor) { + commitments.lookup_inverses = + transcript.template receive_from_prover(commitment_labels.lookup_inverses); + } + const FF public_input_delta = proof_system::honk::compute_public_input_delta( public_inputs, beta, gamma, circuit_size, static_cast(pub_inputs_offset.get_value())); const FF lookup_grand_product_delta = @@ -102,13 +105,6 @@ std::array UltraRecursiveVerifier_::ve auto sumcheck = Sumcheck(key->circuit_size); auto [multivariate_challenge, claimed_evaluations, verified] = sumcheck.verify(relation_parameters, transcript); - info("Sumcheck: num gates = ", - builder->get_num_gates() - prev_num_gates, - ", (total = ", - builder->get_num_gates(), - ")"); - prev_num_gates = builder->get_num_gates(); - // Execute ZeroMorph multilinear PCS evaluation verifier auto pairing_points = ZeroMorph::verify(commitments, claimed_evaluations, multivariate_challenge, transcript); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 084a01ec6ab..34f2842eede 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -1,4 +1,5 @@ #include "prover_instance.hpp" +#include "barretenberg/honk/proof_system/lookup_library.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/proof_system/composer/permutation_lib.hpp" #include "barretenberg/proof_system/library/grand_product_delta.hpp" @@ -199,10 +200,10 @@ void ProverInstance_::construct_databus_polynomials(Circuit& circuit) polynomial public_calldata(dyadic_circuit_size); polynomial calldata_read_counts(dyadic_circuit_size); - const size_t offset = Flavor::has_zero_row ? 1 : 0; + // Note: We do not utilize a zero row for databus columns 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]); + public_calldata[idx] = circuit.get_variable(circuit.public_calldata[idx]); + calldata_read_counts[idx] = circuit.get_variable(circuit.calldata_read_counts[idx]); } proving_key->calldata = public_calldata; @@ -275,6 +276,12 @@ std::shared_ptr ProverInstance_::compute_pr if constexpr (IsGoblinFlavor) { proving_key->num_ecc_op_gates = num_ecc_op_gates; + // Construct simple ID polynomial for databus indexing + typename Flavor::Polynomial databus_id(proving_key->circuit_size); + for (size_t i = 0; i < databus_id.size(); ++i) { + databus_id[i] = i; + } + proving_key->databus_id = databus_id; } return proving_key; @@ -328,9 +335,18 @@ template void ProverInstance_::initialize_prover_polynomi // DataBus polynomials prover_polynomials.calldata = proving_key->calldata; prover_polynomials.calldata_read_counts = proving_key->calldata_read_counts; + prover_polynomials.lookup_inverses = proving_key->lookup_inverses; prover_polynomials.q_busread = proving_key->q_busread; + prover_polynomials.databus_id = proving_key->databus_id; } + // These polynomials have not yet been computed; initialize them so prover_polynomials is "full" and we can use + // utilities like get_row() + prover_polynomials.z_perm = proving_key->z_perm; + prover_polynomials.z_lookup = proving_key->z_lookup; + prover_polynomials.z_perm_shift = proving_key->z_perm.shifted(); + prover_polynomials.z_lookup_shift = proving_key->z_lookup.shifted(); + std::span public_wires_source = prover_polynomials.w_r; // Determine public input offsets in the circuit relative to the 0th index for Ultra flavors @@ -430,6 +446,25 @@ template void ProverInstance_::add_plookup_memory_records } } +/** + * @brief Compute the inverse polynomial used in the log derivative lookup argument + * + * @tparam Flavor + * @param beta + * @param gamma + */ +template +void ProverInstance_::compute_logderivative_inverse(FF beta, FF gamma) + requires IsGoblinFlavor +{ + relation_parameters.beta = beta; + relation_parameters.gamma = gamma; + + // Compute permutation and lookup grand product polynomials + lookup_library::compute_logderivative_inverse( + prover_polynomials, relation_parameters, proving_key->circuit_size); +} + template void ProverInstance_::compute_grand_product_polynomials(FF beta, FF gamma) { auto public_input_delta = @@ -489,20 +524,14 @@ std::shared_ptr ProverInstance_::compu verification_key->table_3 = commitment_key->commit(proving_key->table_3); verification_key->table_4 = commitment_key->commit(proving_key->table_4); - // TODO(luke): Similar to the lagrange_first/last polynomials, we dont really need to commit to this polynomial - // due to its simple structure. Handling it in the same way as the lagrange polys for now for simplicity. + // TODO(luke): Similar to the lagrange_first/last polynomials, we dont really need to commit to these polynomials + // due to their simple structure. 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); + verification_key->databus_id = commitment_key->commit(proving_key->databus_id); } - // // See `add_recusrive_proof()` for how this recursive data is assigned. - // verification_key->recursive_proof_public_input_indices = - // std::vector(recursive_proof_public_input_indices.begin(), - // recursive_proof_public_input_indices.end()); - - // verification_key->contains_recursive_proof = contains_recursive_proof; - return verification_key; } diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 5ac94dd89a1..dc79b08d412 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -71,6 +71,9 @@ template class ProverInstance_ { void compute_sorted_list_accumulator(FF); + void compute_logderivative_inverse(FF, FF) + requires IsGoblinFlavor; + void compute_grand_product_polynomials(FF, FF); private: diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp index d23b2f6b393..a09a822085b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp @@ -99,7 +99,7 @@ TEST_F(GoblinUltraHonkComposerTests, SingleCircuit) // Add mock data to op queue to simulate interaction with a previous circuit op_queue->populate_with_mock_initital_data(); - auto builder = proof_system::GoblinUltraCircuitBuilder(op_queue); + auto builder = proof_system::GoblinUltraCircuitBuilder{ op_queue }; generate_test_circuit(builder); @@ -130,7 +130,7 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsMergeOnly) // Construct multiple test circuits that share an ECC op queue. Generate and verify a proof for each. size_t NUM_CIRCUITS = 3; for (size_t i = 0; i < NUM_CIRCUITS; ++i) { - auto builder = proof_system::GoblinUltraCircuitBuilder(op_queue); + auto builder = proof_system::GoblinUltraCircuitBuilder{ op_queue }; generate_test_circuit(builder); @@ -158,7 +158,7 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsHonkOnly) // Construct multiple test circuits that share an ECC op queue. Generate and verify a proof for each. size_t NUM_CIRCUITS = 3; for (size_t i = 0; i < NUM_CIRCUITS; ++i) { - auto builder = proof_system::GoblinUltraCircuitBuilder(op_queue); + auto builder = proof_system::GoblinUltraCircuitBuilder{ op_queue }; generate_test_circuit(builder); @@ -186,7 +186,7 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsHonkAndMerge) // Construct multiple test circuits that share an ECC op queue. Generate and verify a proof for each. size_t NUM_CIRCUITS = 3; for (size_t i = 0; i < NUM_CIRCUITS; ++i) { - auto builder = proof_system::GoblinUltraCircuitBuilder(op_queue); + auto builder = proof_system::GoblinUltraCircuitBuilder{ op_queue }; generate_test_circuit(builder); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp index 611110de27d..ee79064a5eb 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp @@ -10,7 +10,7 @@ using namespace proof_system::honk; class GoblinUltraTranscriptTests : public ::testing::Test { public: - // static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); } + static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); } using Flavor = proof_system::honk::flavor::GoblinUltra; using FF = Flavor::FF; @@ -26,7 +26,7 @@ class GoblinUltraTranscriptTests : public ::testing::Test { * * @return TranscriptManifest */ - TranscriptManifest construct_goblin_ultra_honk_manifest(size_t circuit_size) + static TranscriptManifest construct_goblin_ultra_honk_manifest(size_t circuit_size) { TranscriptManifest manifest_expected; @@ -61,6 +61,7 @@ class GoblinUltraTranscriptTests : public ::testing::Test { manifest_expected.add_challenge(round, "beta", "gamma"); round++; + manifest_expected.add_entry(round, "LOOKUP_INVERSES", size_G); manifest_expected.add_entry(round, "Z_PERM", size_G); manifest_expected.add_entry(round, "Z_LOOKUP", size_G); manifest_expected.add_challenge(round, "Sumcheck:alpha", "Sumcheck:zeta"); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp index 107919a9ec3..aac5c124212 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -57,6 +57,44 @@ template void check_relation(auto circuit_s } } +/** + * @brief Check that a given linearly dependent relation is satisfied for a set of polynomials + * @details We refer to a relation as linearly dependent if it defines a constraint on the sum across the full execution + * trace rather than at each individual row. For example, a subrelation of this type arises in the log derivative lookup + * argument. + * + * @tparam relation_idx Index into a tuple of provided relations + * @tparam Flavor + */ +template +void check_linearly_dependent_relation(auto circuit_size, auto polynomials, auto params) +{ + using AllValues = typename Flavor::AllValues; + // Define the appropriate SumcheckArrayOfValuesOverSubrelations type for this relation and initialize to zero + using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations; + SumcheckArrayOfValuesOverSubrelations result; + for (auto& element : result) { + element = 0; + } + + for (size_t i = 0; i < circuit_size; i++) { + + // Extract an array containing all the polynomial evaluations at a given row i + AllValues evaluations_at_index_i; + for (auto [eval, poly] : zip_view(evaluations_at_index_i.pointer_view(), polynomials.pointer_view())) { + *eval = (*poly)[i]; + } + + // Evaluate each constraint in the relation and check that each is satisfied + Relation::accumulate(result, evaluations_at_index_i, params, 1); + } + + // Result accumulated across entire execution trace should be zero + for (auto& element : result) { + ASSERT_EQ(element, 0); + } +} + template void create_some_add_gates(auto& circuit_builder) { using FF = typename Flavor::FF; @@ -295,6 +333,7 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) instance->initialize_prover_polynomials(); instance->compute_sorted_accumulator_polynomials(eta); + instance->compute_logderivative_inverse(beta, gamma); instance->compute_grand_product_polynomials(beta, gamma); // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution @@ -303,6 +342,11 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) ensure_non_zero(proving_key->q_lookup); ensure_non_zero(proving_key->q_elliptic); ensure_non_zero(proving_key->q_aux); + ensure_non_zero(proving_key->q_busread); + + ensure_non_zero(proving_key->calldata); + ensure_non_zero(proving_key->calldata_read_counts); + ensure_non_zero(proving_key->lookup_inverses); // Construct the round for applying sumcheck relations and results for storing computed results using Relations = typename Flavor::Relations; @@ -317,6 +361,8 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) check_relation>(circuit_size, prover_polynomials, params); check_relation>(circuit_size, prover_polynomials, params); check_relation>(circuit_size, prover_polynomials, params); + check_linearly_dependent_relation>( + circuit_size, prover_polynomials, params); } /** diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp index 112fbd6a6ed..f2ec19befbd 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp @@ -86,16 +86,33 @@ template void UltraProver_::execute_sorted_list_acc transcript.send_to_verifier(commitment_labels.w_4, w_4_commitment); } +/** + * @brief Compute log derivative inverse polynomial and its commitment, if required + * + */ +template void UltraProver_::execute_log_derivative_inverse_round() +{ + // Compute and store challenges beta and gamma + auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); + relation_parameters.beta = beta; + relation_parameters.gamma = gamma; + + if constexpr (IsGoblinFlavor) { + instance->compute_logderivative_inverse(beta, gamma); + + auto lookup_inverses_commitment = commitment_key->commit(instance->proving_key->lookup_inverses); + transcript.send_to_verifier(commitment_labels.lookup_inverses, lookup_inverses_commitment); + } +} + /** * @brief Compute permutation and lookup grand product polynomials and their commitments * */ template void UltraProver_::execute_grand_product_computation_round() { - // Compute and store parameters required by relations in Sumcheck - auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); - instance->compute_grand_product_polynomials(beta, gamma); + instance->compute_grand_product_polynomials(relation_parameters.beta, relation_parameters.gamma); auto z_perm_commitment = commitment_key->commit(instance->proving_key->z_perm); auto z_lookup_commitment = commitment_key->commit(instance->proving_key->z_lookup); @@ -149,6 +166,8 @@ template plonk::proof& UltraProver_::construct_proo execute_sorted_list_accumulator_round(); // Fiat-Shamir: beta & gamma + execute_log_derivative_inverse_round(); + // Compute grand product(s) and commitments. execute_grand_product_computation_round(); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp index 058f5852c0e..fe50c8e0c80 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp @@ -27,6 +27,7 @@ template class UltraProver_ { BBERG_PROFILE void execute_preamble_round(); BBERG_PROFILE void execute_wire_commitments_round(); BBERG_PROFILE void execute_sorted_list_accumulator_round(); + BBERG_PROFILE void execute_log_derivative_inverse_round(); BBERG_PROFILE void execute_grand_product_computation_round(); BBERG_PROFILE void execute_relation_check_rounds(); BBERG_PROFILE void execute_zeromorph_rounds(); @@ -39,6 +40,8 @@ template class UltraProver_ { std::vector public_inputs; size_t pub_inputs_offset; + proof_system::RelationParameters relation_parameters; + CommitmentLabels commitment_labels; Polynomial quotient_W; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 3dc1bcafa67..2c9d2ba85d2 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -96,6 +96,12 @@ template bool UltraVerifier_::verify_proof(const plonk // Get permutation challenges auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); + // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial + if constexpr (IsGoblinFlavor) { + commitments.lookup_inverses = + transcript.template receive_from_prover(commitment_labels.lookup_inverses); + } + const FF public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, circuit_size, pub_inputs_offset); const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, circuit_size);