From 93420480603b2dfa126e5bddb08cd768b7093352 Mon Sep 17 00:00:00 2001 From: maramihali Date: Wed, 24 Jan 2024 10:02:04 +0000 Subject: [PATCH] feat: recursive folding and decider verifier for Protogalaxy (#4156) Implements the recursive folding verifier and recursive decider verifier resembling the native ones as closely as possible. Tests follow the example of the other recursive honk verifiers and native protogalaxy tests. Additionally, I introduced a function that sequentially computes polynomials in coefficient form in the `ProtoGalaxyRecursiveVerifier` to avoid having to instantiate the entire `Polynomial` class on `stdlib::bn254`. Closes https://github.com/AztecProtocol/barretenberg/issues/789. Closes https://github.com/AztecProtocol/barretenberg/issues/834. --- .../protogalaxy_bench/protogalaxy.bench.cpp | 2 +- .../ecc/fields/field_declarations.hpp | 7 + .../src/barretenberg/flavor/goblin_ultra.hpp | 67 +--- .../flavor/goblin_ultra_recursive.hpp | 20 +- .../cpp/src/barretenberg/flavor/ultra.hpp | 48 +-- .../barretenberg/flavor/ultra_recursive.hpp | 96 +++-- .../protogalaxy/protogalaxy_prover.cpp | 4 - .../protogalaxy/protogalaxy_verifier.cpp | 15 + .../stdlib/primitives/curves/bn254.hpp | 2 + .../verifier/decider_recursive_verifier.cpp | 96 +++++ .../verifier/decider_recursive_verifier.hpp | 30 ++ .../protogalaxy_recursive_verifier.cpp | 320 ++++++++++++++++ .../protogalaxy_recursive_verifier.hpp | 118 ++++++ .../protogalaxy_recursive_verifier.test.cpp | 350 ++++++++++++++++++ .../verifier/ultra_recursive_verifier.hpp | 5 - .../barretenberg/stdlib/utility/utility.hpp | 4 + .../ultra_honk/protogalaxy.test.cpp | 4 +- .../ultra_honk/ultra_composer.hpp | 3 +- 18 files changed, 1060 insertions(+), 131 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp index a4164418e4a..b0a4f05afbf 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp @@ -30,7 +30,7 @@ void fold_one(State& state) noexcept std::shared_ptr instance_1 = construct_instance(); std::shared_ptr instance_2 = construct_instance(); - auto folding_prover = composer.create_folding_prover({ instance_1, instance_2 }, composer.commitment_key); + auto folding_prover = composer.create_folding_prover({ instance_1, instance_2 }); for (auto _ : state) { auto proof = folding_prover.fold_instances(); diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp index 3a43b2ac69e..217e2b42bd2 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp @@ -112,6 +112,13 @@ template struct alignas(32) field { *this = field(value); } + constexpr explicit operator bool() const + { + field out = from_montgomery_form(); + ASSERT(out.data[0] == 0 || out.data[0] == 1); + return static_cast(out.data[0]); + } + constexpr explicit operator uint32_t() const { field out = from_montgomery_form(); diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 8629356b726..5f13c7ac66b 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -155,7 +155,7 @@ class GoblinUltra { // GoblinUltra needs to expose more public classes than most flavors due to GoblinUltraRecursive reuse, but these // are internal: - private: + public: // WireEntities for basic witness entities template class WireEntities { public: @@ -418,42 +418,8 @@ class GoblinUltra { template class VerifierCommitments_ : public AllEntities { public: - VerifierCommitments_(const std::shared_ptr& verification_key) - { - this->q_m = verification_key->q_m; - this->q_l = verification_key->q_l; - this->q_r = verification_key->q_r; - this->q_o = verification_key->q_o; - this->q_4 = verification_key->q_4; - this->q_c = verification_key->q_c; - this->q_arith = verification_key->q_arith; - this->q_sort = verification_key->q_sort; - 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->q_poseidon2_external = verification_key->q_poseidon2_external; - this->q_poseidon2_internal = verification_key->q_poseidon2_internal; - this->sigma_1 = verification_key->sigma_1; - this->sigma_2 = verification_key->sigma_2; - this->sigma_3 = verification_key->sigma_3; - this->sigma_4 = verification_key->sigma_4; - this->id_1 = verification_key->id_1; - this->id_2 = verification_key->id_2; - this->id_3 = verification_key->id_3; - this->id_4 = verification_key->id_4; - this->table_1 = verification_key->table_1; - this->table_2 = verification_key->table_2; - this->table_3 = verification_key->table_3; - this->table_4 = verification_key->table_4; - 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; - } - VerifierCommitments_(const std::shared_ptr& verification_key, - const WitnessCommitments& witness_commitments) + const std::optional>& witness_commitments = std::nullopt) { this->q_m = verification_key->q_m; this->q_l = verification_key->q_l; @@ -486,19 +452,22 @@ class GoblinUltra { this->lagrange_ecc_op = verification_key->lagrange_ecc_op; this->databus_id = verification_key->databus_id; - this->w_l = witness_commitments.w_l; - this->w_r = witness_commitments.w_r; - this->w_o = witness_commitments.w_o; - this->sorted_accum = witness_commitments.sorted_accum; - this->w_4 = witness_commitments.w_4; - this->z_perm = witness_commitments.z_perm; - this->z_lookup = witness_commitments.z_lookup; - this->ecc_op_wire_1 = witness_commitments.ecc_op_wire_1; - this->ecc_op_wire_2 = witness_commitments.ecc_op_wire_2; - this->ecc_op_wire_3 = witness_commitments.ecc_op_wire_3; - this->calldata = witness_commitments.calldata; - this->calldata = witness_commitments.calldata_read_counts; - this->lookup_inverses = witness_commitments.lookup_inverses; + if (witness_commitments.has_value()) { + auto commitments = witness_commitments.value(); + this->w_l = commitments.w_l; + this->w_r = commitments.w_r; + this->w_o = commitments.w_o; + this->sorted_accum = commitments.sorted_accum; + this->w_4 = commitments.w_4; + this->z_perm = commitments.z_perm; + this->z_lookup = commitments.z_lookup; + this->ecc_op_wire_1 = commitments.ecc_op_wire_1; + this->ecc_op_wire_2 = commitments.ecc_op_wire_2; + this->ecc_op_wire_3 = commitments.ecc_op_wire_3; + this->calldata = commitments.calldata; + this->calldata = commitments.calldata_read_counts; + this->lookup_inverses = commitments.lookup_inverses; + } } }; // Specialize for GoblinUltra (general case used in GoblinUltraRecursive). diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index 8c47654f6fe..e1146ea4b70 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -67,12 +67,14 @@ template class GoblinUltraRecursive_ { using Relations = GoblinUltra::Relations_; 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(); // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation // length = 3 static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; - static constexpr size_t NUM_RELATIONS = std::tuple_size::value; + static constexpr size_t BATCHED_RELATION_TOTAL_LENGTH = MAX_TOTAL_RELATION_LENGTH + 1; + static constexpr size_t NUM_RELATIONS = std::tuple_size_v; // For instances of this flavour, used in folding, we need a unique sumcheck batching challenge for each // subrelation. This is because using powers of alpha would increase the degree of Protogalaxy polynomial $G$ (the @@ -104,6 +106,12 @@ template class GoblinUltraRecursive_ { */ class VerificationKey : public VerificationKey_> { public: + VerificationKey(const size_t circuit_size, const size_t num_public_inputs) + { + this->circuit_size = circuit_size; + this->log_circuit_size = numeric::get_msb(circuit_size); + this->num_public_inputs = num_public_inputs; + }; /** * @brief Construct a new Verification Key with stdlib types from a provided native verification * key @@ -112,9 +120,10 @@ template class GoblinUltraRecursive_ { * @param native_key Native verification key from which to extract the precomputed commitments */ VerificationKey(CircuitBuilder* builder, const std::shared_ptr& native_key) - : VerificationKey_>(native_key->circuit_size, - native_key->num_public_inputs) { + this->circuit_size = native_key->circuit_size; + this->log_circuit_size = numeric::get_msb(this->circuit_size); + this->num_public_inputs = native_key->num_public_inputs; this->q_m = Commitment::from_witness(builder, native_key->q_m); this->q_l = Commitment::from_witness(builder, native_key->q_l); this->q_r = Commitment::from_witness(builder, native_key->q_r); @@ -148,6 +157,11 @@ template class GoblinUltraRecursive_ { }; }; + /** + * @brief A container for the witness commitments. + */ + using WitnessCommitments = GoblinUltra::WitnessEntities; + using CommitmentLabels = GoblinUltra::CommitmentLabels; // Reuse the VerifierCommitments from GoblinUltra using VerifierCommitments = GoblinUltra::VerifierCommitments_; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index 3bf08e29b8f..2fd21fab351 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -412,37 +412,8 @@ class Ultra { */ class VerifierCommitments : public AllEntities { public: - VerifierCommitments(const std::shared_ptr& verification_key) - { - q_m = verification_key->q_m; - q_c = verification_key->q_c; - q_l = verification_key->q_l; - q_r = verification_key->q_r; - q_o = verification_key->q_o; - q_4 = verification_key->q_4; - q_arith = verification_key->q_arith; - q_sort = verification_key->q_sort; - q_elliptic = verification_key->q_elliptic; - q_aux = verification_key->q_aux; - q_lookup = verification_key->q_lookup; - sigma_1 = verification_key->sigma_1; - sigma_2 = verification_key->sigma_2; - sigma_3 = verification_key->sigma_3; - sigma_4 = verification_key->sigma_4; - id_1 = verification_key->id_1; - id_2 = verification_key->id_2; - id_3 = verification_key->id_3; - id_4 = verification_key->id_4; - table_1 = verification_key->table_1; - table_2 = verification_key->table_2; - table_3 = verification_key->table_3; - table_4 = verification_key->table_4; - lagrange_first = verification_key->lagrange_first; - lagrange_last = verification_key->lagrange_last; - } - VerifierCommitments(const std::shared_ptr& verification_key, - const WitnessCommitments& witness_commitments) + const std::optional& witness_commitments = std::nullopt) { q_m = verification_key->q_m; q_c = verification_key->q_c; @@ -470,13 +441,16 @@ class Ultra { lagrange_first = verification_key->lagrange_first; lagrange_last = verification_key->lagrange_last; - w_l = witness_commitments.w_l; - w_r = witness_commitments.w_r; - w_o = witness_commitments.w_o; - sorted_accum = witness_commitments.sorted_accum; - w_4 = witness_commitments.w_4; - z_perm = witness_commitments.z_perm; - z_lookup = witness_commitments.z_lookup; + if (witness_commitments.has_value()) { + auto commitments = witness_commitments.value(); + this->w_l = commitments.w_l; + this->w_r = commitments.w_r; + this->w_o = commitments.w_o; + this->sorted_accum = commitments.sorted_accum; + this->w_4 = commitments.w_4; + this->z_perm = commitments.z_perm; + this->z_lookup = commitments.z_lookup; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index ea9303c7c87..94955d72f75 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -79,11 +79,15 @@ template class UltraRecursive_ { bb::AuxiliaryRelation>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); + static_assert(MAX_PARTIAL_RELATION_LENGTH == 6); + static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length(); + static_assert(MAX_TOTAL_RELATION_LENGTH == 12); // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation // length = 3 static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; + static constexpr size_t BATCHED_RELATION_TOTAL_LENGTH = MAX_TOTAL_RELATION_LENGTH + 1; static constexpr size_t NUM_RELATIONS = std::tuple_size::value; // For instances of this flavour, used in folding, we need a unique sumcheck batching challenges for each @@ -161,6 +165,12 @@ template class UltraRecursive_ { RefVector get_wires() { return { w_l, w_r, w_o, w_4 }; }; }; + public: + /** + * @brief A container for the witness commitments. + */ + using WitnessCommitments = WitnessEntities; + /** * @brief A base class labelling all entities (for instance, all of the polynomials used by the prover during * sumcheck) in this Honk variant along with particular subsets of interest @@ -229,6 +239,17 @@ template class UltraRecursive_ { }; }; + RefVector get_precomputed() + { + return { q_m, q_c, q_l, q_r, q_o, q_4, 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 + + }; + } + + RefVector get_witness() { return { w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup }; }; RefVector get_to_be_shifted() { return { table_1, table_2, table_3, table_4, w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup }; @@ -251,6 +272,12 @@ template class UltraRecursive_ { */ class VerificationKey : public VerificationKey_> { public: + VerificationKey(const size_t circuit_size, const size_t num_public_inputs) + { + this->circuit_size = circuit_size; + this->log_circuit_size = numeric::get_msb(circuit_size); + this->num_public_inputs = num_public_inputs; + }; /** * @brief Construct a new Verification Key with stdlib types from a provided native verification key * @@ -258,8 +285,10 @@ template class UltraRecursive_ { * @param native_key Native verification key from which to extract the precomputed commitments */ VerificationKey(CircuitBuilder* builder, const std::shared_ptr& native_key) - : VerificationKey_>(native_key->circuit_size, native_key->num_public_inputs) { + this->circuit_size = native_key->circuit_size; + this->log_circuit_size = numeric::get_msb(this->circuit_size); + this->num_public_inputs = native_key->num_public_inputs; this->q_m = Commitment::from_witness(builder, native_key->q_m); this->q_l = Commitment::from_witness(builder, native_key->q_l); this->q_r = Commitment::from_witness(builder, native_key->q_r); @@ -317,38 +346,38 @@ template class UltraRecursive_ { this->z_lookup = "Z_LOOKUP"; this->sorted_accum = "SORTED_ACCUM"; - // The ones beginning with "__" are only used for debugging - this->q_c = "__Q_C"; - this->q_l = "__Q_L"; - this->q_r = "__Q_R"; - this->q_o = "__Q_O"; - this->q_4 = "__Q_4"; - this->q_m = "__Q_M"; - this->q_arith = "__Q_ARITH"; - this->q_sort = "__Q_SORT"; - this->q_elliptic = "__Q_ELLIPTIC"; - this->q_aux = "__Q_AUX"; - this->q_lookup = "__Q_LOOKUP"; - this->sigma_1 = "__SIGMA_1"; - this->sigma_2 = "__SIGMA_2"; - this->sigma_3 = "__SIGMA_3"; - this->sigma_4 = "__SIGMA_4"; - this->id_1 = "__ID_1"; - this->id_2 = "__ID_2"; - this->id_3 = "__ID_3"; - this->id_4 = "__ID_4"; - this->table_1 = "__TABLE_1"; - this->table_2 = "__TABLE_2"; - this->table_3 = "__TABLE_3"; - this->table_4 = "__TABLE_4"; - this->lagrange_first = "__LAGRANGE_FIRST"; - this->lagrange_last = "__LAGRANGE_LAST"; + this->q_c = "Q_C"; + this->q_l = "Q_L"; + this->q_r = "Q_R"; + this->q_o = "Q_O"; + this->q_4 = "Q_4"; + this->q_m = "Q_M"; + this->q_arith = "Q_ARITH"; + this->q_sort = "Q_SORT"; + this->q_elliptic = "Q_ELLIPTIC"; + this->q_aux = "Q_AUX"; + this->q_lookup = "Q_LOOKUP"; + this->sigma_1 = "SIGMA_1"; + this->sigma_2 = "SIGMA_2"; + this->sigma_3 = "SIGMA_3"; + this->sigma_4 = "SIGMA_4"; + this->id_1 = "ID_1"; + this->id_2 = "ID_2"; + this->id_3 = "ID_3"; + this->id_4 = "ID_4"; + this->table_1 = "TABLE_1"; + this->table_2 = "TABLE_2"; + this->table_3 = "TABLE_3"; + this->table_4 = "TABLE_4"; + this->lagrange_first = "LAGRANGE_FIRST"; + this->lagrange_last = "LAGRANGE_LAST"; }; }; class VerifierCommitments : public AllEntities { public: - VerifierCommitments(const std::shared_ptr& verification_key) + VerifierCommitments(const std::shared_ptr& verification_key, + const std::optional& witness_commitments = std::nullopt) { this->q_m = verification_key->q_m; this->q_l = verification_key->q_l; @@ -375,6 +404,17 @@ template class UltraRecursive_ { this->table_4 = verification_key->table_4; this->lagrange_first = verification_key->lagrange_first; this->lagrange_last = verification_key->lagrange_last; + + if (witness_commitments.has_value()) { + auto commitments = witness_commitments.value(); + this->w_l = commitments.w_l; + this->w_r = commitments.w_r; + this->w_o = commitments.w_o; + this->sorted_accum = commitments.sorted_accum; + this->w_4 = commitments.w_4; + this->z_perm = commitments.z_perm; + this->z_lookup = commitments.z_lookup; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index ca78b870604..6a138c51a51 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -269,14 +269,10 @@ std::shared_ptr ProtoGalaxyProver_ FoldingResult ProtoGalaxyProver_::fold_instances() { prepare_for_folding(); - - // TODO(#https://github.com/AztecProtocol/barretenberg/issues/740): Handle the case where we are folding for the - // first time and accumulator is 0 FF delta = transcript->get_challenge("delta"); auto accumulator = get_accumulator(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index 0e33b27cd77..bf7d4c50117 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -6,17 +6,20 @@ template void ProtoGalaxyVerifier_::receive_accumulator(const std::shared_ptr& inst, const std::string& domain_separator) { + // Get circuit parameters inst->instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); inst->public_input_size = transcript->template receive_from_prover(domain_separator + "_public_input_size"); + // Get folded public inputs for (size_t i = 0; i < inst->public_input_size; ++i) { auto public_input_i = transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); inst->public_inputs.emplace_back(public_input_i); } + // Get folded relation parameters auto eta = transcript->template receive_from_prover(domain_separator + "_eta"); auto beta = transcript->template receive_from_prover(domain_separator + "_beta"); auto gamma = transcript->template receive_from_prover(domain_separator + "_gamma"); @@ -26,6 +29,7 @@ void ProtoGalaxyVerifier_::receive_accumulator(const std::sha inst->relation_parameters = RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + // Get the folded relation separator challenges \vec{α} for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { inst->alphas[idx] = transcript->template receive_from_prover(domain_separator + "_alpha_" + std::to_string(idx)); @@ -33,11 +37,14 @@ void ProtoGalaxyVerifier_::receive_accumulator(const std::sha inst->target_sum = transcript->template receive_from_prover(domain_separator + "_target_sum"); + // Get the folded gate challenges, \vec{β} in the paper inst->gate_challenges = std::vector(inst->log_instance_size); for (size_t idx = 0; idx < inst->log_instance_size; idx++) { inst->gate_challenges[idx] = transcript->template receive_from_prover(domain_separator + "_gate_challenge_" + std::to_string(idx)); } + + // Get the folded commitments to all witness polynomials auto comm_view = inst->witness_commitments.get_all(); auto witness_labels = inst->commitment_labels.get_witness(); for (size_t idx = 0; idx < witness_labels.size(); idx++) { @@ -45,6 +52,7 @@ void ProtoGalaxyVerifier_::receive_accumulator(const std::sha transcript->template receive_from_prover(domain_separator + "_" + witness_labels[idx]); } + // Get the folded commitments to selector polynomials inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); auto vk_view = inst->verification_key->get_all(); auto vk_labels = inst->commitment_labels.get_precomputed(); @@ -57,6 +65,7 @@ template void ProtoGalaxyVerifier_::receive_and_finalise_instance(const std::shared_ptr& inst, const std::string& domain_separator) { + // Get circuit parameters and the public inputs inst->instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); inst->public_input_size = @@ -71,33 +80,39 @@ void ProtoGalaxyVerifier_::receive_and_finalise_instance(cons inst->pub_inputs_offset = transcript->template receive_from_prover(domain_separator + "_pub_inputs_offset"); + // Get commitments to first three wire polynomials auto labels = inst->commitment_labels; auto& witness_commitments = inst->witness_commitments; witness_commitments.w_l = transcript->template receive_from_prover(domain_separator + "_" + labels.w_l); witness_commitments.w_r = transcript->template receive_from_prover(domain_separator + "_" + labels.w_r); witness_commitments.w_o = transcript->template receive_from_prover(domain_separator + "_" + labels.w_o); + // Get challenge for sorted list batching and wire four memory records commitment auto eta = transcript->get_challenge(domain_separator + "_eta"); witness_commitments.sorted_accum = transcript->template receive_from_prover(domain_separator + "_" + labels.sorted_accum); witness_commitments.w_4 = transcript->template receive_from_prover(domain_separator + "_" + labels.w_4); + // Get permutation challenges and commitment to permutation and lookup grand products auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); witness_commitments.z_perm = transcript->template receive_from_prover(domain_separator + "_" + labels.z_perm); witness_commitments.z_lookup = transcript->template receive_from_prover(domain_separator + "_" + labels.z_lookup); + // Compute correction terms for grand products const FF public_input_delta = compute_public_input_delta( inst->public_inputs, beta, gamma, inst->instance_size, inst->pub_inputs_offset); const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, inst->instance_size); inst->relation_parameters = RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + // Get the relation separation challenges for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { inst->alphas[idx] = transcript->get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); } + // Get the commitments to the selector polynomials for the given instance inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); auto vk_view = inst->verification_key->get_all(); auto vk_labels = labels.get_precomputed(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp index 594ac29d75d..d437cee5044 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp @@ -17,6 +17,8 @@ template struct bn254 { using ScalarFieldNative = curve::BN254::ScalarField; using BaseFieldNative = curve::BN254::BaseField; using GroupNative = curve::BN254::Group; + using ElementNative = GroupNative::element; + using AffineElementNative = GroupNative::affine_element; // Stdlib types corresponding to those defined in the native description of the curve. // Note: its useful to have these type names match the native analog exactly so that components that digest a Curve diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp new file mode 100644 index 00000000000..6578f48cc99 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp @@ -0,0 +1,96 @@ +#include "barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp" +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" +#include "barretenberg/numeric/bitop/get_msb.hpp" +#include "barretenberg/sumcheck/instance/verifier_instance.hpp" +#include "barretenberg/transcript/transcript.hpp" + +namespace bb::stdlib::recursion::honk { + +template +DeciderRecursiveVerifier_::DeciderRecursiveVerifier_(Builder* builder) + : builder(builder) +{} + +/** + * @brief This function verifies an Ultra Honk proof for a given Flavor, produced for a relaxed instance (ϕ, \vec{β*}, + * e*). + * + */ +template +std::array DeciderRecursiveVerifier_::verify_proof( + const bb::plonk::proof& proof) +{ + using Sumcheck = ::bb::honk::sumcheck::SumcheckVerifier; + using Curve = typename Flavor::Curve; + using ZeroMorph = ::bb::honk::pcs::zeromorph::ZeroMorphVerifier_; + using VerifierCommitments = typename Flavor::VerifierCommitments; + using Transcript = typename Flavor::Transcript; + using Instance = typename ::bb::honk::VerifierInstance_; + + static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; + transcript = std::make_shared(builder, proof.proof_data); + auto inst = std::make_unique(); + + const auto instance_size = transcript->template receive_from_prover("instance_size"); + const auto public_input_size = transcript->template receive_from_prover("public_input_size"); + const auto log_instance_size = static_cast(numeric::get_msb(uint32_t(instance_size.get_value()))); + + for (size_t i = 0; i < uint32_t(public_input_size.get_value()); ++i) { + auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); + inst->public_inputs.emplace_back(public_input_i); + } + + auto eta = transcript->template receive_from_prover("eta"); + auto beta = transcript->template receive_from_prover("beta"); + auto gamma = transcript->template receive_from_prover("gamma"); + auto public_input_delta = transcript->template receive_from_prover("public_input_delta"); + auto lookup_grand_product_delta = transcript->template receive_from_prover("lookup_grand_product_delta"); + inst->relation_parameters = + RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + inst->alphas[idx] = transcript->template receive_from_prover("alpha" + std::to_string(idx)); + } + + inst->target_sum = transcript->template receive_from_prover("target_sum"); + + inst->gate_challenges = std::vector(log_instance_size); + for (size_t idx = 0; idx < log_instance_size; idx++) { + inst->gate_challenges[idx] = + transcript->template receive_from_prover("gate_challenge_" + std::to_string(idx)); + } + auto comm_view = inst->witness_commitments.get_all(); + auto witness_labels = inst->commitment_labels.get_witness(); + for (size_t idx = 0; idx < witness_labels.size(); idx++) { + comm_view[idx] = transcript->template receive_from_prover(witness_labels[idx]); + } + + inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); + auto vk_view = inst->verification_key->get_all(); + auto vk_labels = inst->commitment_labels.get_precomputed(); + for (size_t idx = 0; idx < vk_labels.size(); idx++) { + vk_view[idx] = transcript->template receive_from_prover(vk_labels[idx]); + } + + VerifierCommitments commitments{ inst->verification_key, inst->witness_commitments }; + + auto sumcheck = Sumcheck(log_instance_size, transcript, inst->target_sum); + + auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = + sumcheck.verify(inst->relation_parameters, inst->alphas, inst->gate_challenges); + + // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the + // unrolled protocol. + auto pairing_points = ZeroMorph::verify(commitments.get_unshifted(), + commitments.get_to_be_shifted(), + claimed_evaluations.get_unshifted(), + claimed_evaluations.get_shifted(), + multivariate_challenge, + transcript); + + return pairing_points; +} + +template class DeciderRecursiveVerifier_>; +template class DeciderRecursiveVerifier_>; +} // namespace bb::stdlib::recursion::honk diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp new file mode 100644 index 00000000000..18e6b75fa0b --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "barretenberg/flavor/goblin_ultra_recursive.hpp" +#include "barretenberg/flavor/ultra_recursive.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" +#include "barretenberg/sumcheck/sumcheck.hpp" + +namespace bb::stdlib::recursion::honk { +template class DeciderRecursiveVerifier_ { + using FF = typename Flavor::FF; + using Commitment = typename Flavor::Commitment; + using GroupElement = typename Flavor::GroupElement; + using VerificationKey = typename Flavor::VerificationKey; + using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; + using Builder = typename Flavor::CircuitBuilder; + using RelationSeparator = typename Flavor::RelationSeparator; + using PairingPoints = std::array; + + public: + explicit DeciderRecursiveVerifier_(Builder* builder); + + PairingPoints verify_proof(const bb::plonk::proof& proof); + + std::map commitments; + std::shared_ptr pcs_verification_key; + Builder* builder; + std::shared_ptr> transcript; +}; + +} // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp new file mode 100644 index 00000000000..68c366de5b9 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp @@ -0,0 +1,320 @@ +#include "protogalaxy_recursive_verifier.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/proof_system/library/grand_product_delta.hpp" +namespace bb::stdlib::recursion::honk { + +template +void ProtoGalaxyRecursiveVerifier_::receive_accumulator(const std::shared_ptr& inst, + const std::string& domain_separator) +{ + // Get circuit parameters + const auto instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); + const auto public_input_size = + transcript->template receive_from_prover(domain_separator + "_public_input_size"); + inst->instance_size = uint32_t(instance_size.get_value()); + inst->log_instance_size = uint32_t(numeric::get_msb(inst->instance_size)); + inst->public_input_size = uint32_t(public_input_size.get_value()); + + // Get folded public inputs + for (size_t i = 0; i < inst->public_input_size; ++i) { + auto public_input_i = + transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); + inst->public_inputs.emplace_back(public_input_i); + } + + // Get folded relation parameters + auto eta = transcript->template receive_from_prover(domain_separator + "_eta"); + auto beta = transcript->template receive_from_prover(domain_separator + "_beta"); + auto gamma = transcript->template receive_from_prover(domain_separator + "_gamma"); + auto public_input_delta = transcript->template receive_from_prover(domain_separator + "_public_input_delta"); + auto lookup_grand_product_delta = + transcript->template receive_from_prover(domain_separator + "_lookup_grand_product_delta"); + inst->relation_parameters = + RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + + // Get the folded relation separator challenges \vec{α} + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + inst->alphas[idx] = + transcript->template receive_from_prover(domain_separator + "_alpha_" + std::to_string(idx)); + } + + inst->target_sum = transcript->template receive_from_prover(domain_separator + "_target_sum"); + + // Get the folded gate challenges, \vec{β} in the paper + inst->gate_challenges = std::vector(inst->log_instance_size); + for (size_t idx = 0; idx < inst->log_instance_size; idx++) { + inst->gate_challenges[idx] = + transcript->template receive_from_prover(domain_separator + "_gate_challenge_" + std::to_string(idx)); + } + + // Get the folded commitments to all witness polynomials + auto comm_view = inst->witness_commitments.get_all(); + auto witness_labels = inst->commitment_labels.get_witness(); + for (size_t idx = 0; idx < witness_labels.size(); idx++) { + comm_view[idx] = + transcript->template receive_from_prover(domain_separator + "_" + witness_labels[idx]); + } + + // Get the folded commitments to selector polynomials + inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); + auto vk_view = inst->verification_key->get_all(); + auto vk_labels = inst->commitment_labels.get_precomputed(); + for (size_t idx = 0; idx < vk_labels.size(); idx++) { + vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); + } +} + +template +void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_instance( + const std::shared_ptr& inst, const std::string& domain_separator) +{ + // Get circuit parameters and the public inputs + const auto instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); + const auto public_input_size = + transcript->template receive_from_prover(domain_separator + "_public_input_size"); + inst->instance_size = uint32_t(instance_size.get_value()); + inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); + inst->public_input_size = uint32_t(public_input_size.get_value()); + + for (size_t i = 0; i < inst->public_input_size; ++i) { + auto public_input_i = + transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); + inst->public_inputs.emplace_back(public_input_i); + } + + const auto pub_inputs_offset = + transcript->template receive_from_prover(domain_separator + "_pub_inputs_offset"); + + inst->pub_inputs_offset = uint32_t(pub_inputs_offset.get_value()); + + // Get commitments to first three wire polynomials + auto labels = inst->commitment_labels; + auto& witness_commitments = inst->witness_commitments; + witness_commitments.w_l = transcript->template receive_from_prover(domain_separator + "_" + labels.w_l); + witness_commitments.w_r = transcript->template receive_from_prover(domain_separator + "_" + labels.w_r); + witness_commitments.w_o = transcript->template receive_from_prover(domain_separator + "_" + labels.w_o); + + // Get challenge for sorted list batching and wire four memory records commitment + auto eta = transcript->get_challenge(domain_separator + "_eta"); + witness_commitments.sorted_accum = + transcript->template receive_from_prover(domain_separator + "_" + labels.sorted_accum); + witness_commitments.w_4 = transcript->template receive_from_prover(domain_separator + "_" + labels.w_4); + + // Get permutation challenges and commitment to permutation and lookup grand products + auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); + witness_commitments.z_perm = + transcript->template receive_from_prover(domain_separator + "_" + labels.z_perm); + witness_commitments.z_lookup = + transcript->template receive_from_prover(domain_separator + "_" + labels.z_lookup); + + // Compute correction terms for grand products + const FF public_input_delta = bb::honk::compute_public_input_delta( + inst->public_inputs, beta, gamma, inst->instance_size, inst->pub_inputs_offset); + const FF lookup_grand_product_delta = + bb::honk::compute_lookup_grand_product_delta(beta, gamma, inst->instance_size); + inst->relation_parameters = + RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + + // Get the relation separation challenges + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + inst->alphas[idx] = transcript->get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); + } + + // Get the commitments to the selector polynomials for the given instance + inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); + auto vk_view = inst->verification_key->get_all(); + auto vk_labels = labels.get_precomputed(); + for (size_t idx = 0; idx < vk_labels.size(); idx++) { + vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); + } +} + +// TODO(https://github.com/AztecProtocol/barretenberg/issues/795): The rounds prior to actual verifying are common +// between decider and folding verifier and could be somehow shared so we do not duplicate code so much. +template void ProtoGalaxyRecursiveVerifier_::prepare_for_folding() +{ + auto index = 0; + auto inst = instances[0]; + auto domain_separator = std::to_string(index); + const auto is_accumulator = transcript->template receive_from_prover(domain_separator + "is_accumulator"); + inst->is_accumulator = static_cast(is_accumulator.get_value()); + if (inst->is_accumulator) { + receive_accumulator(inst, domain_separator); + } else { + // This is the first round of folding and we need to generate some gate challenges. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/740): implement option 2 to make this more + // efficient by avoiding the computation of the perturbator + receive_and_finalise_instance(inst, domain_separator); + inst->target_sum = 0; + auto beta = transcript->get_challenge(domain_separator + "_initial_gate_challenge"); + std::vector gate_challenges(inst->log_instance_size); + gate_challenges[0] = beta; + for (size_t i = 1; i < inst->log_instance_size; i++) { + gate_challenges[i] = gate_challenges[i - 1].sqr(); + } + inst->gate_challenges = gate_challenges; + } + index++; + + for (auto it = instances.begin() + 1; it != instances.end(); it++, index++) { + auto inst = *it; + auto domain_separator = std::to_string(index); + receive_and_finalise_instance(inst, domain_separator); + } +} + +template +void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(std::vector proof) +{ + using Transcript = typename Flavor::Transcript; + using ElementNative = typename Flavor::Curve::ElementNative; + using AffineElementNative = typename Flavor::Curve::AffineElementNative; + using ScalarNative = typename Flavor::Curve::ScalarFieldNative; + + transcript = std::make_shared(builder, proof); + prepare_for_folding(); + + auto delta = transcript->get_challenge("delta"); + auto accumulator = get_accumulator(); + auto deltas = compute_round_challenge_pows(accumulator->log_instance_size, delta); + + std::vector perturbator_coeffs(accumulator->log_instance_size + 1); + for (size_t idx = 0; idx <= accumulator->log_instance_size; idx++) { + perturbator_coeffs[idx] = transcript->template receive_from_prover("perturbator_" + std::to_string(idx)); + } + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/833): As currently the stdlib transcript is not + // creating proper constraints linked to Fiat-Shamir we add an additonal gate to ensure assert_equal is correct. + // This comparison to 0 can be removed here and below once we have merged the transcript. + auto zero = FF::from_witness(builder, ScalarNative(0)); + zero.assert_equal(accumulator->target_sum - perturbator_coeffs[0], "F(0) != e"); + + FF perturbator_challenge = transcript->get_challenge("perturbator_challenge"); + + auto perturbator_at_challenge = evaluate_perturbator(perturbator_coeffs, perturbator_challenge); + // The degree of K(X) is dk - k - 1 = k(d - 1) - 1. Hence we need k(d - 1) evaluations to represent it. + std::array combiner_quotient_evals; + for (size_t idx = 0; idx < VerifierInstances::BATCHED_EXTENDED_LENGTH - VerifierInstances::NUM; idx++) { + combiner_quotient_evals[idx] = transcript->template receive_from_prover( + "combiner_quotient_" + std::to_string(idx + VerifierInstances::NUM)); + } + Univariate combiner_quotient( + combiner_quotient_evals); + FF combiner_challenge = transcript->get_challenge("combiner_quotient_challenge"); + auto combiner_quotient_at_challenge = combiner_quotient.evaluate(combiner_challenge); // fine recursive i think + + auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); + auto lagranges = std::vector{ FF(1) - combiner_challenge, combiner_challenge }; + + // Compute next folding parameters and verify against the ones received from the prover + auto expected_next_target_sum = + perturbator_at_challenge * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; + auto next_target_sum = transcript->template receive_from_prover("next_target_sum"); + zero.assert_equal(expected_next_target_sum - next_target_sum, "next target sum mismatch"); + + auto expected_betas_star = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); + for (size_t idx = 0; idx < accumulator->log_instance_size; idx++) { + auto beta_star = transcript->template receive_from_prover("next_gate_challenge_" + std::to_string(idx)); + zero.assert_equal(beta_star - expected_betas_star[idx], + " next gate challenge mismatch at: " + std::to_string(idx)); + } + + // Compute ϕ and verify against the data received from the prover + WitnessCommitments acc_witness_commitments; + auto witness_labels = commitment_labels.get_witness(); + size_t comm_idx = 0; + auto random_generator = Commitment::from_witness(builder, AffineElementNative(ElementNative::random_element())); + for (auto& expected_comm : acc_witness_commitments.get_all()) { + expected_comm = random_generator; + size_t inst = 0; + for (auto& instance : instances) { + expected_comm = expected_comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst]; + inst++; + } + auto comm = transcript->template receive_from_prover("next_" + witness_labels[comm_idx]); + auto res = expected_comm - comm; + random_generator.x.assert_equal(res.x); + random_generator.y.assert_equal(res.y); + comm_idx++; + } + + std::vector folded_public_inputs(instances[0]->public_inputs.size(), 0); + size_t public_input_idx = 0; + for (auto& expected_public_input : folded_public_inputs) { + size_t inst = 0; + for (auto& instance : instances) { + expected_public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; + inst++; + } + auto next_public_input = + transcript->template receive_from_prover("next_public_input" + std::to_string(public_input_idx)); + zero.assert_equal(expected_public_input - next_public_input, + "folded public input mismatch at: " + std::to_string(public_input_idx)); + public_input_idx++; + } + + for (size_t alpha_idx = 0; alpha_idx < NUM_SUBRELATIONS - 1; alpha_idx++) { + FF expected_alpha(0); + size_t instance_idx = 0; + for (auto& instance : instances) { + expected_alpha += instance->alphas[alpha_idx] * lagranges[instance_idx]; + instance_idx++; + } + auto next_alpha = transcript->template receive_from_prover("next_alpha_" + std::to_string(alpha_idx)); + zero.assert_equal(expected_alpha - next_alpha, + "folded relation separator mismatch at: " + std::to_string(alpha_idx)); + } + + auto expected_parameters = bb::RelationParameters{}; + for (size_t inst_idx = 0; inst_idx < VerifierInstances::NUM; inst_idx++) { + auto instance = instances[inst_idx]; + expected_parameters.eta += instance->relation_parameters.eta * lagranges[inst_idx]; + expected_parameters.beta += instance->relation_parameters.beta * lagranges[inst_idx]; + expected_parameters.gamma += instance->relation_parameters.gamma * lagranges[inst_idx]; + expected_parameters.public_input_delta += + instance->relation_parameters.public_input_delta * lagranges[inst_idx]; + expected_parameters.lookup_grand_product_delta += + instance->relation_parameters.lookup_grand_product_delta * lagranges[inst_idx]; + } + + auto next_eta = transcript->template receive_from_prover("next_eta"); + zero.assert_equal(expected_parameters.eta - next_eta, "relation parameter eta mismatch"); + + auto next_beta = transcript->template receive_from_prover("next_beta"); + zero.assert_equal(expected_parameters.beta - next_beta, "relation parameter beta mismatch"); + + auto next_gamma = transcript->template receive_from_prover("next_gamma"); + zero.assert_equal(expected_parameters.gamma - next_gamma, "relation parameter gamma mismatch"); + + auto next_public_input_delta = transcript->template receive_from_prover("next_public_input_delta"); + zero.assert_equal(expected_parameters.public_input_delta - next_public_input_delta, + "relation parameter public input delta mismatch"); + + auto next_lookup_grand_product_delta = + transcript->template receive_from_prover("next_lookup_grand_product_delta"); + zero.assert_equal(expected_parameters.lookup_grand_product_delta - next_lookup_grand_product_delta, + "relation parameter lookup grand product delta mismatch"); + + auto acc_vk = std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); + auto vk_labels = commitment_labels.get_precomputed(); + size_t vk_idx = 0; + for (auto& expected_vk : acc_vk->get_all()) { + size_t inst = 0; + expected_vk = random_generator; + for (auto& instance : instances) { + expected_vk = expected_vk + instance->verification_key->get_all()[vk_idx] * lagranges[inst]; + inst++; + } + auto vk = transcript->template receive_from_prover("next_" + vk_labels[vk_idx]); + auto res = expected_vk - vk; + random_generator.x.assert_equal(res.x); + random_generator.y.assert_equal(res.y); + vk_idx++; + } +} + +template class ProtoGalaxyRecursiveVerifier_< + bb::honk::VerifierInstances_, 2>>; +template class ProtoGalaxyRecursiveVerifier_< + bb::honk::VerifierInstances_, 2>>; +} // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp new file mode 100644 index 00000000000..64b75719542 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp @@ -0,0 +1,118 @@ +#pragma once +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/flavor/goblin_ultra_recursive.hpp" +#include "barretenberg/flavor/ultra_recursive.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/protogalaxy/folding_result.hpp" +#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" +#include "barretenberg/sumcheck/instance/instances.hpp" + +namespace bb::stdlib::recursion::honk { +template class ProtoGalaxyRecursiveVerifier_ { + public: + using Flavor = typename VerifierInstances::Flavor; + using FF = typename Flavor::FF; + using Commitment = typename Flavor::Commitment; + using GroupElement = typename Flavor::GroupElement; + using Instance = typename VerifierInstances::Instance; + using VerificationKey = typename Flavor::VerificationKey; + using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; + using Builder = typename Flavor::CircuitBuilder; + using RelationSeparator = typename Flavor::RelationSeparator; + using PairingPoints = std::array; + + static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; + + VerifierInstances instances; + + CommitmentLabels commitment_labels; + + Builder* builder; + std::shared_ptr> transcript; + + explicit ProtoGalaxyRecursiveVerifier_(Builder* builder) + : instances(VerifierInstances()) + , builder(builder){}; + /** + * @brief Given a new round challenge δ for each iteration of the full ProtoGalaxy protocol, compute the vector + * [δ, δ^2,..., δ^t] where t = logn and n is the size of the instance. + */ + static std::vector compute_round_challenge_pows(size_t log_instance_size, FF round_challenge) + { + std::vector pows(log_instance_size); + pows[0] = round_challenge; + for (size_t i = 1; i < log_instance_size; i++) { + pows[i] = pows[i - 1].sqr(); + } + return pows; + } + + static std::vector update_gate_challenges(const FF perturbator_challenge, + const std::vector& gate_challenges, + const std::vector& round_challenges) + { + auto log_instance_size = gate_challenges.size(); + std::vector next_gate_challenges(log_instance_size); + + for (size_t idx = 0; idx < log_instance_size; idx++) { + next_gate_challenges[idx] = gate_challenges[idx] + perturbator_challenge * round_challenges[idx]; + } + return next_gate_challenges; + } + + std::shared_ptr get_accumulator() { return instances[0]; } + + /** + * @brief Instatiate the instances and the transcript. + * + * @param fold_data The data transmitted via the transcript by the prover. + */ + void prepare_for_folding(); + + /** + * @brief Instantiate the accumulator (i.e. the relaxed instance) from the transcript. + * + */ + void receive_accumulator(const std::shared_ptr&, const std::string&); + + /** + * @brief Process the public data ϕ for the Instances to be folded. + * + */ + void receive_and_finalise_instance(const std::shared_ptr&, const std::string&); + + /** + * @brief Run the folding protocol on the verifier side to establish whether the public data ϕ of the new + * accumulator, received from the prover is the same as that produced by the verifier. + * + * @details In the recursive setting this function doesn't return anything because the equality checks performed by + * the recursive verifier, ensuring the folded ϕ*, e* and β* on the verifier side correspond to what has been sent + * by the prover, are expressed as constraints. + + */ + void verify_folding_proof(std::vector proof); + + /** + * @brief Evaluates the perturbator at a given scalar, in a sequential manner for the recursive setting. + * + * @details This method is equivalent to the one in the Polynomial class for evaluating a polynomial, represented by + * coefficients in monomial basis, at a given point. The Polynomial class is used in the native verifier for + * constructing and computing the perturbator. We implement this separate functionality here in the recursive + * folding verifier to avoid instantiating the entire Polynomial class on stdlib::bn254. Furthermore, the evaluation + * needs to be done sequentially as we don't support a parallel_for in circuits. + * + */ + static FF evaluate_perturbator(std::vector coeffs, FF point) + { + FF point_acc = FF(1); + FF result = FF(0); + for (size_t i = 0; i < coeffs.size(); i++) { + result += coeffs[i] * point_acc; + point_acc *= point; + } + return result; + }; +}; + +} // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp new file mode 100644 index 00000000000..61dee74084f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -0,0 +1,350 @@ +#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" +#include "barretenberg/common/test.hpp" +#include "barretenberg/flavor/ultra_recursive.hpp" +#include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" +#include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" +#include "barretenberg/stdlib/primitives/curves/bn254.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" + +namespace bb::stdlib::recursion::honk { +class ProtogalaxyRecursiveTest : public testing::Test { + public: + // Define types relevant for testing + using UltraFlavor = ::bb::honk::flavor::Ultra; + using GoblinUltraFlavor = ::bb::honk::flavor::GoblinUltra; + using UltraComposer = ::bb::honk::UltraComposer_; + using GoblinUltraComposer = ::bb::honk::UltraComposer_; + + using InnerFlavor = UltraFlavor; + using InnerComposer = UltraComposer; + using Instance = ::bb::honk::ProverInstance_; + using InnerBuilder = typename InnerComposer::CircuitBuilder; + using InnerCurve = bn254; + using Commitment = InnerFlavor::Commitment; + using FF = InnerFlavor::FF; + + // Types for recursive verifier circuit + // cannot do on Goblin + using OuterBuilder = GoblinUltraCircuitBuilder; + using RecursiveFlavor = ::bb::honk::flavor::UltraRecursive_; + using RecursiveVerifierInstances = ::bb::honk::VerifierInstances_; + using FoldingRecursiveVerifier = ProtoGalaxyRecursiveVerifier_; + using DeciderRecursiveVerifier = DeciderRecursiveVerifier_; + using DeciderVerifier = ::bb::honk::DeciderVerifier_; + using NativeVerifierInstances = ::bb::honk::VerifierInstances_; + using NativeFoldingVerifier = bb::honk::ProtoGalaxyVerifier_; + + // Helper for getting composer for prover/verifier of recursive (outer) circuit + template static auto get_outer_composer() + { + if constexpr (IsGoblinBuilder) { + return GoblinUltraComposer(); + } else { + return UltraComposer(); + } + } + + /** + * @brief Create a non-trivial arbitrary inner circuit, the proof of which will be recursively verified + * + * @param builder + * @param public_inputs + * @param log_num_gates + * + * TODO(https://github.com/AztecProtocol/barretenberg/issues/744): make testing utility with functionality shared + * amongst test files + */ + static void create_inner_circuit(InnerBuilder& builder, size_t log_num_gates = 10) + { + using fr_ct = InnerCurve::ScalarField; + using fq_ct = InnerCurve::BaseField; + using public_witness_ct = InnerCurve::public_witness_ct; + using witness_ct = InnerCurve::witness_ct; + using byte_array_ct = InnerCurve::byte_array_ct; + using fr = typename InnerCurve::ScalarFieldNative; + + // Create 2^log_n many add gates based on input log num gates + const size_t num_gates = 1 << log_num_gates; + for (size_t i = 0; i < num_gates; ++i) { + fr a = fr::random_element(); + uint32_t a_idx = builder.add_variable(a); + + fr b = fr::random_element(); + fr c = fr::random_element(); + fr d = a + b + c; + uint32_t b_idx = builder.add_variable(b); + uint32_t c_idx = builder.add_variable(c); + uint32_t d_idx = builder.add_variable(d); + + builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); + } + + // Define some additional non-trivial but arbitrary circuit logic + fr_ct a(public_witness_ct(&builder, fr::random_element())); + fr_ct b(public_witness_ct(&builder, fr::random_element())); + fr_ct c(public_witness_ct(&builder, fr::random_element())); + + for (size_t i = 0; i < 32; ++i) { + a = (a * b) + b + a; + a = a.madd(b, c); + } + pedersen_hash::hash({ a, b }); + byte_array_ct to_hash(&builder, "nonsense test data"); + blake3s(to_hash); + + fr bigfield_data = fr::random_element(); + fr bigfield_data_a{ bigfield_data.data[0], bigfield_data.data[1], 0, 0 }; + fr bigfield_data_b{ bigfield_data.data[2], bigfield_data.data[3], 0, 0 }; + + fq_ct big_a(fr_ct(witness_ct(&builder, bigfield_data_a.to_montgomery_form())), fr_ct(witness_ct(&builder, 0))); + fq_ct big_b(fr_ct(witness_ct(&builder, bigfield_data_b.to_montgomery_form())), fr_ct(witness_ct(&builder, 0))); + + big_a* big_b; + }; + + public: + static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } + + static std::shared_ptr fold_and_verify(const std::vector>& instances, + InnerComposer& inner_composer) + { + // Generate a folding proof + auto inner_folding_prover = inner_composer.create_folding_prover(instances); + auto inner_folding_proof = inner_folding_prover.fold_instances(); + + // Create a recursive folding verifier circuit for the folding proof of the two instances + OuterBuilder outer_folding_circuit; + FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; + verifier.verify_folding_proof(inner_folding_proof.folding_data); + info("Recursive Verifier with Ultra instances: num gates = ", outer_folding_circuit.num_gates); + + // Perform native folding verification and ensure it returns the same result (either true or false) as calling + // check_circuit on the recursive folding verifier + auto native_folding_verifier = inner_composer.create_folding_verifier(); + auto native_folding_result = native_folding_verifier.verify_folding_proof(inner_folding_proof.folding_data); + EXPECT_EQ(native_folding_result, outer_folding_circuit.check_circuit()); + + // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring + // the manifests produced by each agree. + auto recursive_folding_manifest = verifier.transcript->get_manifest(); + auto native_folding_manifest = native_folding_verifier.transcript->get_manifest(); + + for (size_t i = 0; i < recursive_folding_manifest.size(); ++i) { + EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]); + } + + // Check for a failure flag in the recursive verifier circuit + EXPECT_EQ(outer_folding_circuit.failed(), false) << outer_folding_circuit.err(); + + return inner_folding_proof.accumulator; + } +}; +/** + * @brief Create inner circuit and call check_circuit on it + * + */ +TEST_F(ProtogalaxyRecursiveTest, InnerCircuit) +{ + InnerBuilder builder; + + create_inner_circuit(builder); + + bool result = builder.check_circuit(); + EXPECT_EQ(result, true); +} + +/** + * @brief Ensure that evaluating the perturbator in the recursive folding verifier returns the same result as + * evaluating in Polynomial class. + * + */ +TEST_F(ProtogalaxyRecursiveTest, NewEvaluate) +{ + OuterBuilder builder; + using fr_ct = bn254::ScalarField; + using fr = bn254::ScalarFieldNative; + + std::vector coeffs; + std::vector coeffs_ct; + for (size_t idx = 0; idx < 8; idx++) { + auto el = fr::random_element(); + coeffs.emplace_back(el); + coeffs_ct.emplace_back(fr_ct(&builder, el)); + } + Polynomial poly(coeffs); + fr point = fr::random_element(); + fr_ct point_ct(fr_ct(&builder, point)); + auto res1 = poly.evaluate(point); + + auto res2 = FoldingRecursiveVerifier::evaluate_perturbator(coeffs_ct, point_ct); + EXPECT_EQ(res1, res2.get_value()); +} + +/** + * @brief Tests a simple recursive fold that is valid works as expected. + * + */ +TEST_F(ProtogalaxyRecursiveTest, RecursiveFoldingTest) +{ + // Create two arbitrary circuits for the first round of folding + InnerBuilder builder1; + + create_inner_circuit(builder1); + InnerBuilder builder2; + builder2.add_public_variable(FF(1)); + create_inner_circuit(builder2); + + InnerComposer inner_composer = InnerComposer(); + auto instance1 = inner_composer.create_instance(builder1); + auto instance2 = inner_composer.create_instance(builder2); + auto instances = std::vector>{ instance1, instance2 }; + + fold_and_verify(instances, inner_composer); +} + +/** + * @brief Recursively verify two rounds of folding valid circuits and then recursive verify the final decider proof, + * make sure the verifer circuits pass check_circuit(). Ensure that the algorithm of the recursive and native verifiers + * are identical by checking the manifests + + */ +TEST_F(ProtogalaxyRecursiveTest, FullProtogalaxyRecursiveTest) +{ + + // Create two arbitrary circuits for the first round of folding + InnerBuilder builder1; + + create_inner_circuit(builder1); + InnerBuilder builder2; + builder2.add_public_variable(FF(1)); + create_inner_circuit(builder2); + + InnerComposer inner_composer = InnerComposer(); + auto instance1 = inner_composer.create_instance(builder1); + auto instance2 = inner_composer.create_instance(builder2); + auto instances = std::vector>{ instance1, instance2 }; + + auto accumulator = fold_and_verify(instances, inner_composer); + + // Create another circuit to do a second round of folding + InnerBuilder builder3; + create_inner_circuit(builder3); + auto instance3 = inner_composer.create_instance(builder3); + instances = std::vector>{ accumulator, instance3 }; + + accumulator = fold_and_verify(instances, inner_composer); + + // Create a decider proof for the relaxed instance obtained through folding + auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); + auto inner_decider_proof = inner_decider_prover.construct_proof(); + + // Create a decider verifier circuit for recursively verifying the decider proof + OuterBuilder outer_decider_circuit; + DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; + auto pairing_points = decider_verifier.verify_proof(inner_decider_proof); + info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + // Check for a failure flag in the recursive verifier circuit + EXPECT_EQ(outer_decider_circuit.failed(), false) << outer_decider_circuit.err(); + + // Perform native verification then perform the pairing on the outputs of the recursive + // decider verifier and check that the result agrees. + DeciderVerifier native_decider_verifier = inner_composer.create_decider_verifier(accumulator); + auto native_result = native_decider_verifier.verify_proof(inner_decider_proof); + auto recursive_result = native_decider_verifier.pcs_verification_key->pairing_check(pairing_points[0].get_value(), + pairing_points[1].get_value()); + EXPECT_EQ(native_result, recursive_result); + + // Ensure that the underlying native and recursive decider verification algorithms agree by ensuring + // the manifests produced are the same. + auto recursive_decider_manifest = decider_verifier.transcript->get_manifest(); + auto native_decider_manifest = native_decider_verifier.transcript->get_manifest(); + for (size_t i = 0; i < recursive_decider_manifest.size(); ++i) { + EXPECT_EQ(recursive_decider_manifest[i], native_decider_manifest[i]); + } + + // Construct and verify a proof of the recursive decider verifier circuit + { + auto composer = get_outer_composer(); + auto instance = composer.create_instance(outer_decider_circuit); + auto prover = composer.create_prover(instance); + auto verifier = composer.create_verifier(instance); + auto proof = prover.construct_proof(); + bool verified = verifier.verify_proof(proof); + + ASSERT(verified); + } +} + +TEST_F(ProtogalaxyRecursiveTest, TamperedDeciderProof) +{ + // Create two arbitrary circuits for the first round of folding + InnerBuilder builder1; + + create_inner_circuit(builder1); + InnerBuilder builder2; + builder2.add_public_variable(FF(1)); + create_inner_circuit(builder2); + + InnerComposer inner_composer = InnerComposer(); + auto instance1 = inner_composer.create_instance(builder1); + auto instance2 = inner_composer.create_instance(builder2); + auto instances = std::vector>{ instance1, instance2 }; + + auto accumulator = fold_and_verify(instances, inner_composer); + + // Tamper with the accumulator by changing the target sum + accumulator->target_sum = FF::random_element(); + + // Create a decider proof for the relaxed instance obtained through folding + auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); + auto inner_decider_proof = inner_decider_prover.construct_proof(); + + // Create a decider verifier circuit for recursively verifying the decider proof + OuterBuilder outer_decider_circuit; + DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; + decider_verifier.verify_proof(inner_decider_proof); + info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + + // We expect the decider circuit check to fail due to the bad proof + EXPECT_FALSE(outer_decider_circuit.check_circuit()); +} + +TEST_F(ProtogalaxyRecursiveTest, TamperedAccumulator) +{ + // Create two arbitrary circuits for the first round of folding + InnerBuilder builder1; + + create_inner_circuit(builder1); + InnerBuilder builder2; + builder2.add_public_variable(FF(1)); + create_inner_circuit(builder2); + + InnerComposer inner_composer = InnerComposer(); + auto instance1 = inner_composer.create_instance(builder1); + auto instance2 = inner_composer.create_instance(builder2); + auto instances = std::vector>{ instance1, instance2 }; + + auto accumulator = fold_and_verify(instances, inner_composer); + + // Create another circuit to do a second round of folding + InnerBuilder builder3; + create_inner_circuit(builder3); + auto instance3 = inner_composer.create_instance(builder3); + + // Tamper with the accumulator + instances = std::vector>{ accumulator, instance3 }; + accumulator->prover_polynomials.w_l[1] = FF::random_element(); + + // Generate a folding proof + auto inner_folding_prover = inner_composer.create_folding_prover(instances); + auto inner_folding_proof = inner_folding_prover.fold_instances(); + + // Create a recursive folding verifier circuit for the folding proof of the two instances + OuterBuilder outer_folding_circuit; + FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; + verifier.verify_folding_proof(inner_folding_proof.folding_data); + EXPECT_EQ(outer_folding_circuit.check_circuit(), false); +} + +} // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp index f26b44d1116..5712966f001 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp @@ -20,11 +20,6 @@ template class UltraRecursiveVerifier_ { explicit UltraRecursiveVerifier_(Builder* builder, const std::shared_ptr& native_verifier_key); - UltraRecursiveVerifier_(UltraRecursiveVerifier_&& other) = delete; - UltraRecursiveVerifier_(const UltraRecursiveVerifier_& other) = delete; - UltraRecursiveVerifier_& operator=(const UltraRecursiveVerifier_& other) = delete; - UltraRecursiveVerifier_& operator=(UltraRecursiveVerifier_&& other) = delete; - ~UltraRecursiveVerifier_() = default; // TODO(luke): Eventually this will return something like aggregation_state but I'm simplifying for now until we // determine the exact interface. Simply returns the two pairing points. diff --git a/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp b/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp index bec32c7a78c..1759f5fc412 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp @@ -117,6 +117,10 @@ template class StdlibTypesUtility { using type = uint32_t; }; + template struct NativeType { + using type = bool; + }; + template struct NativeType { using type = FF; }; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index ab2e65df40a..1f41c5325ab 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -47,7 +47,7 @@ std::shared_ptr fold_and_verify(const std::vector& accumulator, } void decide_and_verify(std::shared_ptr& accumulator, UltraComposer& composer, bool expected_result) { - auto decider_prover = composer.create_decider_prover(accumulator, composer.commitment_key); + auto decider_prover = composer.create_decider_prover(accumulator); auto decider_verifier = composer.create_decider_verifier(accumulator); auto decision = decider_prover.construct_proof(); auto verified = decider_verifier.verify_proof(decision); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp index b81d6a42178..5d2a6a71ea2 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp @@ -110,8 +110,7 @@ template class UltraComposer_ { */ MergeVerifier_ create_merge_verifier() { return MergeVerifier_(); } - ProtoGalaxyProver_ create_folding_prover(const std::vector>& instances, - const std::shared_ptr& commitment_key) + ProtoGalaxyProver_ create_folding_prover(const std::vector>& instances) { ProtoGalaxyProver_ output_state(instances, commitment_key);