From bb86ce9a27e09b8a336af04b787b81d5f1d49ac8 Mon Sep 17 00:00:00 2001 From: maramihali Date: Fri, 8 Dec 2023 11:34:44 +0200 Subject: [PATCH] feat: complete folding prover and verifier for ultra instances (#3419) Closes https://github.com/AztecProtocol/barretenberg/issues/781 Closes https://github.com/AztecProtocol/barretenberg/issues/689 Closes https://github.com/AztecProtocol/barretenberg/issues/690 Closes https://github.com/AztecProtocol/barretenberg/issues/802 This PR provides the first full version of folding prover and verifiers for Ultra instances and provides the first full folding test. The protogalaxy interfaces have been slightly reworked so the prover now returns a complete new relaxed `Instance` and a folding proof. While the verifier receives the folding proof and returns a boolean dependent on whether the pubic data from the relaxed instance, sent by the prover, is the same as the data computed by the folding verifier. --- .../src/barretenberg/flavor/goblin_ultra.hpp | 79 ++++- .../cpp/src/barretenberg/flavor/ultra.hpp | 94 ++++-- .../src/barretenberg/honk/utils/testing.hpp | 22 +- .../barretenberg/honk/utils/testing.test.cpp | 4 +- .../protogalaxy/combiner.test.cpp | 11 +- .../protogalaxy/combiner_example_gen.py | 1 - .../protogalaxy/folding_result.hpp | 35 +- .../protogalaxy/protogalaxy_prover.cpp | 319 +++++++++++++++--- .../protogalaxy/protogalaxy_prover.hpp | 104 ++++-- .../protogalaxy/protogalaxy_verifier.cpp | 254 +++++++++++--- .../protogalaxy/protogalaxy_verifier.hpp | 50 ++- .../sumcheck/instance/instances.hpp | 30 +- .../sumcheck/instance/prover_instance.cpp | 3 + .../sumcheck/instance/prover_instance.hpp | 12 +- .../sumcheck/instance/verifier_instance.hpp | 8 +- .../ultra_honk/protogalaxy.test.cpp | 93 ++++- .../ultra_honk/ultra_composer.hpp | 16 +- 17 files changed, 893 insertions(+), 242 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 80d1ca652e9..ce322761ccb 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -194,11 +194,6 @@ class GoblinUltra { { return { this->ecc_op_wire_1, this->ecc_op_wire_2, this->ecc_op_wire_3, this->ecc_op_wire_4 }; } - // The sorted concatenations of table and witness data needed for plookup. - RefVector get_sorted_polynomials() - { - return { this->sorted_1, this->sorted_2, this->sorted_3, this->sorted_4 }; - }; }; template class ShiftedEntities { @@ -290,11 +285,60 @@ class GoblinUltra { this->calldata_read_counts, this->lookup_inverses }; }; + + RefVector get_witness() + { + return { this->w_l, + this->w_r, + this->w_o, + this->w_4, + this->sorted_accum, + this->z_perm, + this->z_lookup, + this->ecc_op_wire_1, + this->ecc_op_wire_2, + this->ecc_op_wire_3, + this->ecc_op_wire_4, + this->calldata, + this->calldata_read_counts, + this->lookup_inverses }; + }; RefVector get_to_be_shifted() { return { this->table_1, this->table_2, this->table_3, this->table_4, this->w_l, this->w_r, this->w_o, this->w_4, this->sorted_accum, this->z_perm, this->z_lookup }; }; + RefVector get_precomputed() + { + return { this->q_m, + this->q_c, + this->q_l, + this->q_r, + this->q_o, + this->q_4, + this->q_arith, + this->q_sort, + this->q_elliptic, + this->q_aux, + this->q_lookup, + this->q_busread, + this->sigma_1, + this->sigma_2, + this->sigma_3, + this->sigma_4, + this->id_1, + this->id_2, + this->id_3, + this->id_4, + this->table_1, + this->table_2, + this->table_3, + this->table_4, + this->lagrange_first, + this->lagrange_last, + this->lagrange_ecc_op, + this->databus_id }; + } RefVector get_shifted() { return ShiftedEntities::get_all(); }; }; @@ -381,6 +425,29 @@ class GoblinUltra { } }; + /** + * @brief An owning container of polynomials. + * @warning When this was introduced it broke some of our design principles. + * - Execution trace builders don't handle "polynomials" because the interpretation of the execution trace + * columns as polynomials is a detail of the proving system, and trace builders are (sometimes in practice, + * always in principle) reusable for different proving protocols (e.g., Plonk and Honk). + * - Polynomial storage is handled by key classes. Polynomials aren't moved, but are accessed elsewhere by + * std::spans. + * + * We will consider revising this data model: TODO(https://github.com/AztecProtocol/barretenberg/issues/743) + */ + class AllPolynomials : public AllEntities { + public: + [[nodiscard]] AllValues get_row(const size_t row_idx) const + { + AllValues result; + for (auto [result_field, polynomial] : zip_view(result.get_all(), this->get_all())) { + result_field = polynomial[row_idx]; + } + return result; + } + }; + /** * @brief A container for the witness commitments. */ @@ -488,7 +555,7 @@ class GoblinUltra { using VerifierCommitments = VerifierCommitments_; class FoldingParameters { public: - std::vector gate_separation_challenges; + std::vector gate_challenges; FF target_sum; }; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index 065a70aed2f..450571eaaba 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -207,6 +207,18 @@ class Ultra { }; }; + + 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 }; @@ -248,8 +260,8 @@ class Ultra { using VerificationKey = VerificationKey_>; /** - * @brief A field element for each entity of the flavor. These entities represent the prover polynomials evaluated - * at one point. + * @brief A field element for each entity of the flavor. These entities represent the prover polynomials + * evaluated at one point. */ class AllValues : public AllEntities { public: @@ -273,6 +285,29 @@ class Ultra { } }; + /** + * @brief An owning container of polynomials. + * @warning When this was introduced it broke some of our design principles. + * - Execution trace builders don't handle "polynomials" because the interpretation of the execution trace + * columns as polynomials is a detail of the proving system, and trace builders are (sometimes in practice, + * always in principle) reusable for different proving protocols (e.g., Plonk and Honk). + * - Polynomial storage is handled by key classes. Polynomials aren't moved, but are accessed elsewhere by + * std::spans. + * + * We will consider revising this data model: TODO(https://github.com/AztecProtocol/barretenberg/issues/743) + */ + class AllPolynomials : public AllEntities { + public: + [[nodiscard]] AllValues get_row(const size_t row_idx) const + { + AllValues result; + for (auto [result_field, polynomial] : zip_view(result.get_all(), this->get_all())) { + result_field = polynomial[row_idx]; + } + return result; + } + }; + /** * @brief A container for storing the partially evaluated multivariates produced by sumcheck. */ @@ -323,32 +358,31 @@ class Ultra { z_lookup = "Z_LOOKUP"; sorted_accum = "SORTED_ACCUM"; - // The ones beginning with "__" are only used for debugging - q_c = "__Q_C"; - q_l = "__Q_L"; - q_r = "__Q_R"; - q_o = "__Q_O"; - q_4 = "__Q_4"; - q_m = "__Q_M"; - q_arith = "__Q_ARITH"; - q_sort = "__Q_SORT"; - q_elliptic = "__Q_ELLIPTIC"; - q_aux = "__Q_AUX"; - q_lookup = "__Q_LOOKUP"; - sigma_1 = "__SIGMA_1"; - sigma_2 = "__SIGMA_2"; - sigma_3 = "__SIGMA_3"; - sigma_4 = "__SIGMA_4"; - id_1 = "__ID_1"; - id_2 = "__ID_2"; - id_3 = "__ID_3"; - id_4 = "__ID_4"; - table_1 = "__TABLE_1"; - table_2 = "__TABLE_2"; - table_3 = "__TABLE_3"; - table_4 = "__TABLE_4"; - lagrange_first = "__LAGRANGE_FIRST"; - lagrange_last = "__LAGRANGE_LAST"; + q_c = "Q_C"; + q_l = "Q_L"; + q_r = "Q_R"; + q_o = "Q_O"; + q_4 = "Q_4"; + q_m = "Q_M"; + q_arith = "Q_ARITH"; + q_sort = "Q_SORT"; + q_elliptic = "Q_ELLIPTIC"; + q_aux = "Q_AUX"; + q_lookup = "Q_LOOKUP"; + sigma_1 = "SIGMA_1"; + sigma_2 = "SIGMA_2"; + sigma_3 = "SIGMA_3"; + sigma_4 = "SIGMA_4"; + id_1 = "ID_1"; + id_2 = "ID_2"; + id_3 = "ID_3"; + id_4 = "ID_4"; + table_1 = "TABLE_1"; + table_2 = "TABLE_2"; + table_3 = "TABLE_3"; + table_4 = "TABLE_4"; + lagrange_first = "LAGRANGE_FIRST"; + lagrange_last = "LAGRANGE_LAST"; }; }; @@ -357,11 +391,11 @@ class Ultra { 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_c = verification_key->q_c; q_arith = verification_key->q_arith; q_sort = verification_key->q_sort; q_elliptic = verification_key->q_elliptic; @@ -386,7 +420,7 @@ class Ultra { class FoldingParameters { public: - std::vector gate_separation_challenges; + std::vector gate_challenges; FF target_sum; }; diff --git a/barretenberg/cpp/src/barretenberg/honk/utils/testing.hpp b/barretenberg/cpp/src/barretenberg/honk/utils/testing.hpp index 37c056609ee..dda23952741 100644 --- a/barretenberg/cpp/src/barretenberg/honk/utils/testing.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/utils/testing.hpp @@ -9,18 +9,17 @@ namespace proof_system::honk { * function returns an array of data pointed to by the ProverPolynomials. */ template -std::pair, Flavor::NUM_ALL_ENTITIES>, - typename Flavor::ProverPolynomials> -get_sequential_prover_polynomials(const size_t log_circuit_size, const size_t starting_value) +std::pair get_sequential_prover_polynomials( + const size_t log_circuit_size, const size_t starting_value) { using FF = typename Flavor::FF; using ProverPolynomials = typename Flavor::ProverPolynomials; using Polynomial = typename Flavor::Polynomial; - std::array, Flavor::NUM_ALL_ENTITIES> storage; + typename Flavor::AllPolynomials storage; size_t circuit_size = 1 << log_circuit_size; size_t value_idx = starting_value; - for (auto& polynomial : storage) { + for (auto& polynomial : storage.get_all()) { polynomial = Polynomial(circuit_size); for (auto& value : polynomial) { value = FF(value_idx++); @@ -28,7 +27,7 @@ get_sequential_prover_polynomials(const size_t log_circuit_size, const size_t st } ProverPolynomials prover_polynomials; - for (auto [prover_poly, storage_poly] : zip_view(prover_polynomials.get_all(), storage)) { + for (auto [prover_poly, storage_poly] : zip_view(prover_polynomials.get_all(), storage.get_all())) { prover_poly = storage_poly; } @@ -36,17 +35,16 @@ get_sequential_prover_polynomials(const size_t log_circuit_size, const size_t st } template -std::pair, Flavor::NUM_ALL_ENTITIES>, - typename Flavor::ProverPolynomials> -get_zero_prover_polynomials(const size_t log_circuit_size) +std::pair get_zero_prover_polynomials( + const size_t log_circuit_size) { using FF = typename Flavor::FF; using ProverPolynomials = typename Flavor::ProverPolynomials; using Polynomial = typename Flavor::Polynomial; - std::array, Flavor::NUM_ALL_ENTITIES> storage; + typename Flavor::AllPolynomials storage; size_t circuit_size = 1 << log_circuit_size; - for (auto& polynomial : storage) { + for (auto& polynomial : storage.get_all()) { polynomial = Polynomial(circuit_size); for (auto& value : polynomial) { value = FF(0); @@ -54,7 +52,7 @@ get_zero_prover_polynomials(const size_t log_circuit_size) } ProverPolynomials prover_polynomials; - for (auto [prover_poly, storage_poly] : zip_view(prover_polynomials.get_all(), storage)) { + for (auto [prover_poly, storage_poly] : zip_view(prover_polynomials.get_all(), storage.get_all())) { prover_poly = storage_poly; } diff --git a/barretenberg/cpp/src/barretenberg/honk/utils/testing.test.cpp b/barretenberg/cpp/src/barretenberg/honk/utils/testing.test.cpp index c4b5fda266c..3e150e4a2d5 100644 --- a/barretenberg/cpp/src/barretenberg/honk/utils/testing.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/utils/testing.test.cpp @@ -10,8 +10,8 @@ TEST(HonkTestingUtils, ProverPolynomials) auto [storage, prover_polynomials] = proof_system::honk::get_sequential_prover_polynomials(/*log_circuit_size=*/2, /*starting_value=*/0); auto& first_polynomial = prover_polynomials.get_all()[0]; - EXPECT_EQ(storage[0][0], first_polynomial[0]); - EXPECT_EQ(storage[0][1], first_polynomial[1]); + EXPECT_EQ(storage.get_all()[0][0], first_polynomial[0]); + EXPECT_EQ(storage.get_all()[0][1], first_polynomial[1]); }; } // namespace barretenberg::test_testing_utils diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp index dce50d0220c..68f22195659 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp @@ -33,9 +33,11 @@ TEST(Protogalaxy, CombinerOn2Instances) }; auto run_test = [&](bool is_random_input) { + // Combiner test on prover polynomisls containing random values, restricted to only the standard arithmetic + // relation. if (is_random_input) { std::vector> instance_data(NUM_INSTANCES); - std::array, NUM_INSTANCES> storage_arrays; + std::array storage_arrays; ProtoGalaxyProver prover; std::vector pow_betas = { FF(1), FF(2) }; @@ -46,6 +48,7 @@ TEST(Protogalaxy, CombinerOn2Instances) restrict_to_standard_arithmetic_relation(prover_polynomials); storage_arrays[idx] = std::move(storage); instance->prover_polynomials = prover_polynomials; + instance->instance_size = 2; instance_data[idx] = instance; } @@ -70,7 +73,7 @@ TEST(Protogalaxy, CombinerOn2Instances) EXPECT_EQ(result, expected_result); } else { std::vector> instance_data(NUM_INSTANCES); - std::array, NUM_INSTANCES> storage_arrays; + std::array storage_arrays; ProtoGalaxyProver prover; std::vector pow_betas = { FF(1), FF(2) }; @@ -81,6 +84,7 @@ TEST(Protogalaxy, CombinerOn2Instances) restrict_to_standard_arithmetic_relation(prover_polynomials); storage_arrays[idx] = std::move(storage); instance->prover_polynomials = prover_polynomials; + instance->instance_size = 2; instance_data[idx] = instance; } @@ -162,7 +166,7 @@ TEST(Protogalaxy, CombinerOn4Instances) auto run_test = [&]() { std::vector> instance_data(NUM_INSTANCES); - std::array, NUM_INSTANCES> storage_arrays; + std::array storage_arrays; ProtoGalaxyProver prover; std::vector pow_betas = { FF(1), FF(2) }; @@ -172,6 +176,7 @@ TEST(Protogalaxy, CombinerOn4Instances) /*log_circuit_size=*/1); storage_arrays[idx] = std::move(storage); instance->prover_polynomials = prover_polynomials; + instance->instance_size = 2; instance_data[idx] = instance; } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py index 906d1948847..ac701d41e95 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py @@ -103,7 +103,6 @@ def compute_first_example(): row.q_l, row.q_r, row.q_o, row.q_c) accumulator += zeta_pow * relation_value zeta_pow *= zeta - return accumulator diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp index 61118b8b6e1..171f9b38a78 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp @@ -1,39 +1,18 @@ #pragma once #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/sumcheck/instance/prover_instance.hpp" namespace proof_system::honk { -template struct ProverFoldingResult { - public: - using ProverPolynomials = typename Flavor::ProverPolynomials; - using FoldingParameters = typename Flavor::FoldingParameters; - ProverPolynomials folded_prover_polynomials; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/656): turn folding data into a struct - std::vector folding_data; - FoldingParameters params; -}; - -template struct VerifierFoldingResult { - using FF = typename Flavor::FF; - using VerificationKey = typename Flavor::VerificationKey; - using FoldingParameters = typename Flavor::FoldingParameters; - std::vector folded_public_inputs; - std::shared_ptr folded_verification_key; - FoldingParameters parameters; -}; - /** - * @brief The aggregated result from the prover and verifier after a round of folding, used to create a new Instance. + * @brief The result of running the Protogalaxy prover containing a new accumulator (relaxed instance) as well as the + * proof data to instantiate the verifier transcript. * * @tparam Flavor */ template struct FoldingResult { - using FF = typename Flavor::FF; - using ProverPolynomials = typename Flavor::ProverPolynomials; - using VerificationKey = typename Flavor::VerificationKey; - using FoldingParameters = typename Flavor::FoldingParameters; - ProverPolynomials folded_prover_polynomials; - std::vector folded_public_inputs; - std::shared_ptr verification_key; - FoldingParameters folding_parameters; + public: + std::shared_ptr> accumulator; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/656): turn folding data into a struct + std::vector folding_data; }; } // namespace proof_system::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index b8543daa64c..4a95f231d52 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -1,91 +1,306 @@ #include "protogalaxy_prover.hpp" #include "barretenberg/flavor/flavor.hpp" namespace proof_system::honk { +template +void ProtoGalaxyProver_::finalise_and_send_instance(std::shared_ptr instance, + const std::string& domain_separator) +{ + instance->initialize_prover_polynomials(); -template void ProtoGalaxyProver_::prepare_for_folding() + const auto instance_size = static_cast(instance->instance_size); + const auto num_public_inputs = static_cast(instance->public_inputs.size()); + transcript->send_to_verifier(domain_separator + "_instance_size", instance_size); + transcript->send_to_verifier(domain_separator + "_public_input_size", num_public_inputs); + + for (size_t i = 0; i < instance->public_inputs.size(); ++i) { + auto public_input_i = instance->public_inputs[i]; + transcript->send_to_verifier(domain_separator + "_public_input_" + std::to_string(i), public_input_i); + } + transcript->send_to_verifier(domain_separator + "_pub_inputs_offset", + static_cast(instance->pub_inputs_offset)); + + auto& witness_commitments = instance->witness_commitments; + + // Commit to the first three wire polynomials of the instance + // We only commit to the fourth wire polynomial after adding memory recordss + witness_commitments.w_l = commitment_key->commit(instance->proving_key->w_l); + witness_commitments.w_r = commitment_key->commit(instance->proving_key->w_r); + witness_commitments.w_o = commitment_key->commit(instance->proving_key->w_o); + + auto wire_comms = witness_commitments.get_wires(); + auto commitment_labels = instance->commitment_labels; + auto wire_labels = commitment_labels.get_wires(); + for (size_t idx = 0; idx < 3; ++idx) { + transcript->send_to_verifier(domain_separator + "_" + wire_labels[idx], wire_comms[idx]); + } + + auto eta = transcript->get_challenge(domain_separator + "_eta"); + instance->compute_sorted_accumulator_polynomials(eta); + + // Commit to the sorted withness-table accumulator and the finalized (i.e. with memory records) fourth wire + // polynomial + witness_commitments.sorted_accum = commitment_key->commit(instance->prover_polynomials.sorted_accum); + witness_commitments.w_4 = commitment_key->commit(instance->prover_polynomials.w_4); + + transcript->send_to_verifier(domain_separator + "_" + commitment_labels.sorted_accum, + witness_commitments.sorted_accum); + transcript->send_to_verifier(domain_separator + "_" + commitment_labels.w_4, witness_commitments.w_4); + + auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); + instance->compute_grand_product_polynomials(beta, gamma); + + witness_commitments.z_perm = commitment_key->commit(instance->prover_polynomials.z_perm); + witness_commitments.z_lookup = commitment_key->commit(instance->prover_polynomials.z_lookup); + + transcript->send_to_verifier(domain_separator + "_" + commitment_labels.z_perm, + instance->witness_commitments.z_perm); + transcript->send_to_verifier(domain_separator + "_" + commitment_labels.z_lookup, + instance->witness_commitments.z_lookup); + + instance->alpha = transcript->get_challenge(domain_separator + "_alpha"); + + auto vk_view = instance->verification_key->get_all(); + auto labels = instance->commitment_labels.get_precomputed(); + for (size_t idx = 0; idx < labels.size(); idx++) { + transcript->send_to_verifier(domain_separator + "_" + labels[idx], vk_view[idx]); + } +} + +template +void ProtoGalaxyProver_::send_accumulator(std::shared_ptr instance, + const std::string& domain_separator) { - auto idx = 0; - for (auto it = instances.begin(); it != instances.end(); it++, idx++) { - auto instance = *it; - instance->initialize_prover_polynomials(); + const auto instance_size = static_cast(instance->instance_size); + const auto num_public_inputs = static_cast(instance->public_inputs.size()); + transcript->send_to_verifier(domain_separator + "_instance_size", instance_size); + transcript->send_to_verifier(domain_separator + "_public_input_size", num_public_inputs); - auto domain_separator = std::to_string(idx); - const auto circuit_size = static_cast(instance->proving_key->circuit_size); - const auto num_public_inputs = static_cast(instance->proving_key->num_public_inputs); + for (size_t i = 0; i < instance->public_inputs.size(); ++i) { + auto public_input_i = instance->public_inputs[i]; + transcript->send_to_verifier(domain_separator + "_public_input_" + std::to_string(i), public_input_i); + } - transcript->send_to_verifier(domain_separator + "_circuit_size", circuit_size); - transcript->send_to_verifier(domain_separator + "_public_input_size", num_public_inputs); - transcript->send_to_verifier(domain_separator + "_pub_inputs_offset", - static_cast(instance->pub_inputs_offset)); + transcript->send_to_verifier(domain_separator + "_eta", instance->relation_parameters.eta); + transcript->send_to_verifier(domain_separator + "_beta", instance->relation_parameters.beta); + transcript->send_to_verifier(domain_separator + "_gamma", instance->relation_parameters.gamma); + transcript->send_to_verifier(domain_separator + "_public_input_delta", + instance->relation_parameters.public_input_delta); + transcript->send_to_verifier(domain_separator + "_lookup_grand_product_delta", + instance->relation_parameters.lookup_grand_product_delta); - for (size_t i = 0; i < instance->proving_key->num_public_inputs; ++i) { - auto public_input_i = instance->public_inputs[i]; - transcript->send_to_verifier(domain_separator + "_public_input_" + std::to_string(i), public_input_i); - } + transcript->send_to_verifier(domain_separator + "_alpha", instance->alpha); - auto [eta, beta, gamma] = challenges_to_field_elements(transcript->get_challenges( - domain_separator + "_eta", domain_separator + "_beta", domain_separator + "_gamma")); + auto folding_parameters = instance->folding_parameters; + transcript->send_to_verifier(domain_separator + "_target_sum", folding_parameters.target_sum); + for (size_t idx = 0; idx < folding_parameters.gate_challenges.size(); idx++) { + transcript->send_to_verifier(domain_separator + "_gate_challenge_" + std::to_string(idx), + folding_parameters.gate_challenges[idx]); + } - instance->compute_sorted_accumulator_polynomials(eta); - instance->compute_grand_product_polynomials(beta, gamma); - instance->alpha = transcript->get_challenge(domain_separator + "_alpha"); + auto comm_view = instance->witness_commitments.get_all(); + auto witness_labels = instance->commitment_labels.get_witness(); + for (size_t idx = 0; idx < witness_labels.size(); idx++) { + transcript->send_to_verifier(domain_separator + "_" + witness_labels[idx], comm_view[idx]); } - fold_relation_parameters(instances); - fold_alpha(instances); + auto vk_view = instance->verification_key->get_all(); + auto vk_labels = instance->commitment_labels.get_precomputed(); + for (size_t idx = 0; idx < vk_labels.size(); idx++) { + transcript->send_to_verifier(domain_separator + "_" + vk_labels[idx], vk_view[idx]); + } +} + +template void ProtoGalaxyProver_::prepare_for_folding() +{ + auto idx = 0; + auto instance = instances[0]; + auto domain_separator = std::to_string(idx); + transcript->send_to_verifier(domain_separator + "is_accumulator", instance->is_accumulator); + if (instance->is_accumulator) { + send_accumulator(instance, domain_separator); + } else { + finalise_and_send_instance(instance, domain_separator); + } + idx++; + + for (auto it = instances.begin() + 1; it != instances.end(); it++, idx++) { + auto instance = *it; + auto domain_separator = std::to_string(idx); + finalise_and_send_instance(instance, domain_separator); + } } // TODO(#https://github.com/AztecProtocol/barretenberg/issues/689): finalise implementation this function template -ProverFoldingResult ProtoGalaxyProver_::fold_instances() +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 - // TODO(#https://github.com/AztecProtocol/barretenberg/issues/763): Fold alpha FF delta = transcript->get_challenge("delta"); auto accumulator = get_accumulator(); - auto instance_size = accumulator->prover_polynomials.get_polynomial_size(); - const auto log_instance_size = static_cast(numeric::get_msb(instance_size)); - auto deltas = compute_round_challenge_pows(log_instance_size, delta); + auto deltas = compute_round_challenge_pows(accumulator->log_instance_size, delta); auto perturbator = compute_perturbator(accumulator, deltas); - for (size_t idx = 0; idx <= log_instance_size; idx++) { + for (size_t idx = 0; idx <= accumulator->log_instance_size; idx++) { transcript->send_to_verifier("perturbator_" + std::to_string(idx), perturbator[idx]); } + assert(perturbator[0] == accumulator->folding_parameters.target_sum); + auto perturbator_challenge = transcript->get_challenge("perturbator_challenge"); + instances.next_gate_challenges = + update_gate_challenges(perturbator_challenge, accumulator->folding_parameters.gate_challenges, deltas); + const auto pow_betas_star = + compute_pow_polynomial_at_values(instances.next_gate_challenges, accumulator->instance_size); + + combine_relation_parameters(instances); + combine_alpha(instances); + auto combiner = compute_combiner(instances, pow_betas_star); - FF perturbator_challenge = transcript->get_challenge("perturbator_challenge"); auto compressed_perturbator = perturbator.evaluate(perturbator_challenge); - std::vector betas_star(log_instance_size); - betas_star[0] = 1; - auto betas = accumulator->folding_parameters.gate_separation_challenges; - for (size_t idx = 1; idx < log_instance_size; idx++) { - betas_star[idx] = betas[idx] + perturbator_challenge * deltas[idx - 1]; + auto combiner_quotient = compute_combiner_quotient(compressed_perturbator, combiner); + + for (size_t idx = ProverInstances::NUM; idx < ProverInstances::BATCHED_EXTENDED_LENGTH; idx++) { + transcript->send_to_verifier("combiner_quotient_" + std::to_string(idx), combiner_quotient.value_at(idx)); } + auto combiner_challenge = transcript->get_challenge("combiner_quotient_challenge"); - auto pow_betas_star = compute_pow_polynomial_at_values(betas_star, instance_size); + FoldingResult res; + res.accumulator = + compute_next_accumulator(instances, combiner_quotient, combiner_challenge, compressed_perturbator); + res.folding_data = transcript->proof_data; - auto combiner = compute_combiner(instances, pow_betas_star); - auto combiner_quotient = compute_combiner_quotient(compressed_perturbator, combiner); - for (size_t idx = ProverInstances::NUM; idx < combiner.size(); idx++) { - transcript->send_to_verifier("combiner_quotient_" + std::to_string(idx), combiner_quotient.value_at(idx)); + return res; +} +template +std::shared_ptr ProtoGalaxyProver_::compute_next_accumulator( + ProverInstances& instances, + Univariate& combiner_quotient, + const FF& challenge, + const FF& compressed_perturbator) +{ + auto combiner_quotient_at_challenge = combiner_quotient.evaluate(challenge); + + // Given the challenge \gamma, compute Z(\gamma) and {L_0(\gamma),L_1(\gamma)} + // TODO(https://github.com/AztecProtocol/barretenberg/issues/764): Generalize the vanishing polynomial formula + // and the computation of Lagrange basis for k instances + auto vanishing_polynomial_at_challenge = challenge * (challenge - FF(1)); + std::vector lagranges{ FF(1) - challenge, challenge }; + + auto next_accumulator = std::make_shared(); + + // Compute the next target sum and send the next folding parameters to the verifier + auto next_target_sum = + compressed_perturbator * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; + next_accumulator->folding_parameters = { instances.next_gate_challenges, next_target_sum }; + transcript->send_to_verifier("next_target_sum", next_target_sum); + for (size_t idx = 0; idx < instances.next_gate_challenges.size(); idx++) { + transcript->send_to_verifier("next_gate_challenge_" + std::to_string(idx), instances.next_gate_challenges[idx]); } - FF combiner_challenge = transcript->get_challenge("combiner_quotient_challenge"); - auto combiner_quotient_at_challenge = combiner_quotient.evaluate(combiner_challenge); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/764): Generalize these formulas as well as computation - // of Lagrange basis - auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); - auto lagrange_0_at_challenge = FF(1) - combiner_challenge; + // Allocate space, initialised to 0, for the prover polynomials of the next accumulator + AllPolynomials storage; + for (auto& polynomial : storage.get_all()) { + polynomial = typename Flavor::Polynomial(instances[0]->instance_size); + for (auto& value : polynomial) { + value = FF(0); + } + } + ProverPolynomials acc_prover_polynomials; + size_t poly_idx = 0; + auto prover_polynomial_pointers = acc_prover_polynomials.get_all(); + for (auto& polynomial : storage.get_all()) { + prover_polynomial_pointers[poly_idx] = polynomial; + poly_idx++; + } - auto new_target_sum = compressed_perturbator * lagrange_0_at_challenge + - vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; + // Fold the prover polynomials + auto acc_poly_views = acc_prover_polynomials.get_all(); + for (size_t inst_idx = 0; inst_idx < ProverInstances::NUM; inst_idx++) { + auto inst_poly_views = instances[inst_idx]->prover_polynomials.get_all(); + for (auto [acc_poly_view, inst_poly_view] : zip_view(acc_poly_views, inst_poly_views)) { + for (size_t poly_idx = 0; poly_idx < inst_poly_view.size(); poly_idx++) { + (acc_poly_view)[poly_idx] += (inst_poly_view)[poly_idx] * lagranges[inst_idx]; + } + } + } + next_accumulator->prover_polynomials = acc_prover_polynomials; - ProverFoldingResult res; - res.params.target_sum = new_target_sum; - res.folding_data = transcript->proof_data; - return res; + // Fold the witness commtiments and send them to the verifier + auto witness_labels = next_accumulator->commitment_labels.get_witness(); + size_t comm_idx = 0; + for (auto& acc_comm : next_accumulator->witness_commitments.get_all()) { + acc_comm = Commitment::infinity(); + size_t inst_idx = 0; + for (auto& instance : instances) { + acc_comm = acc_comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst_idx]; + inst_idx++; + } + transcript->send_to_verifier("next_" + witness_labels[comm_idx], acc_comm); + comm_idx++; + } + + // Fold public data ϕ from all instances to produce ϕ* and add it to the transcript. As part of the folding + // verification, the verifier will produce ϕ* as well and check it against what was sent by the prover. + + // Fold the public inputs and send to the verifier + next_accumulator->public_inputs = std::vector(instances[0]->public_inputs.size(), 0); + size_t el_idx = 0; + for (auto& el : next_accumulator->public_inputs) { + size_t inst = 0; + for (auto& instance : instances) { + el += instance->public_inputs[el_idx] * lagranges[inst]; + inst++; + } + transcript->send_to_verifier("next_public_input_" + std::to_string(el_idx), el); + el_idx++; + } + + // Evaluate the combined batching challenge α univariate at challenge to obtain next α and send it to the + // verifier + next_accumulator->alpha = instances.alpha.evaluate(challenge); + transcript->send_to_verifier("next_alpha", next_accumulator->alpha); + + // Evaluate each relation parameter univariate at challenge to obtain the folded relation parameters and send to + // the verifier + auto& combined_relation_parameters = instances.relation_parameters; + auto folded_relation_parameters = proof_system::RelationParameters{ + combined_relation_parameters.eta.evaluate(challenge), + combined_relation_parameters.beta.evaluate(challenge), + combined_relation_parameters.gamma.evaluate(challenge), + combined_relation_parameters.public_input_delta.evaluate(challenge), + combined_relation_parameters.lookup_grand_product_delta.evaluate(challenge), + }; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/805): Add the relation parameters to the transcript + // together. + transcript->send_to_verifier("next_eta", folded_relation_parameters.eta); + transcript->send_to_verifier("next_beta", folded_relation_parameters.beta); + transcript->send_to_verifier("next_gamma", folded_relation_parameters.gamma); + transcript->send_to_verifier("next_public_input_delta", folded_relation_parameters.public_input_delta); + transcript->send_to_verifier("next_lookup_grand_product_delta", + folded_relation_parameters.lookup_grand_product_delta); + next_accumulator->relation_parameters = folded_relation_parameters; + + // Fold the verification key and send it to the verifier as this is part of ϕ as well + auto acc_vk = std::make_shared(instances[0]->prover_polynomials.get_polynomial_size(), + instances[0]->public_inputs.size()); + auto labels = next_accumulator->commitment_labels.get_precomputed(); + size_t vk_idx = 0; + for (auto& vk : acc_vk->get_all()) { + size_t inst = 0; + vk = Commitment::infinity(); + for (auto& instance : instances) { + vk = vk + (instance->verification_key->get_all()[vk_idx]) * lagranges[inst]; + inst++; + } + transcript->send_to_verifier("next_" + labels[vk_idx], vk); + vk_idx++; + } + next_accumulator->verification_key = acc_vk; + + return next_accumulator; } + template class ProtoGalaxyProver_>; template class ProtoGalaxyProver_>; } // namespace proof_system::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index 5e2b7b32ec6..9c881d82a89 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -24,6 +24,11 @@ template class ProtoGalaxyProver_ { using ProverPolynomials = typename Flavor::ProverPolynomials; using Relations = typename Flavor::Relations; using AlphaType = typename ProverInstances::AlphaType; + using VerificationKey = typename Flavor::VerificationKey; + using CommitmentKey = typename Flavor::CommitmentKey; + using WitnessCommitments = typename Flavor::WitnessCommitments; + using Commitment = typename Flavor::Commitment; + using AllPolynomials = typename Flavor::AllPolynomials; using BaseUnivariate = Univariate; // The length of ExtendedUnivariate is the largest length (==max_relation_degree + 1) of a univariate polynomial @@ -44,19 +49,48 @@ template class ProtoGalaxyProver_ { ProverInstances instances; std::shared_ptr transcript = std::make_shared(); + std::shared_ptr commitment_key; + ProtoGalaxyProver_() = default; - ProtoGalaxyProver_(ProverInstances insts) - : instances(insts){}; + ProtoGalaxyProver_(const std::vector>& insts, + const std::shared_ptr& commitment_key) + : instances(ProverInstances(insts)) + , commitment_key(std::move(commitment_key)){}; ~ProtoGalaxyProver_() = default; /** - * @brief Prior to folding we need to add all the public inputs to the transcript, labelled by their corresponding - * instance index, compute all the instance's polynomials and record the relation parameters involved in computing - * these polynomials in the transcript. - * + * @brief Prior to folding, we need to finalize the given instances and add all their public data ϕ to the + * transcript, labelled by their corresponding instance index for domain separation. + * TODO(https://github.com/AztecProtocol/barretenberg/issues/795):The rounds prior to actual proving/folding are + * common between decider and folding verifier and could be somehow shared so we do not duplicate code so much. */ void prepare_for_folding(); + /** + * @brief Send the public data of an accumulator, i.e. a relaxed instance, to the verifier (ϕ in the paper). + * + * @param domain_separator separates the same type of data coming from difference instances by instance + * index + */ + void send_accumulator(std::shared_ptr, const std::string& domain_separator); + + /** + * @brief For each instance produced by a circuit, prior to folding, we need to complete the computation of its + * prover polynomials, commit to witnesses and generate the relation parameters as well as send the public data ϕ of + * an instance to the verifier. + * + * @param domain_separator separates the same type of data coming from difference instances by instance + * index + */ + void finalise_and_send_instance(std::shared_ptr, const std::string& domain_separator); + + /** + * @brief Run the folding prover protocol to produce a new accumulator and a folding proof to be verified by the + * folding verifier. + * + * TODO(https://github.com/AztecProtocol/barretenberg/issues/753): fold goblin polynomials + */ + FoldingResult fold_instances(); /** * @brief Given a vector \vec{\beta} of values, compute the pow polynomial on these values as defined in the paper. */ @@ -89,6 +123,20 @@ template class ProtoGalaxyProver_ { 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); + next_gate_challenges[0] = 1; + + for (size_t idx = 1; idx < log_instance_size; idx++) { + next_gate_challenges[idx] = gate_challenges[idx] + perturbator_challenge * round_challenges[idx - 1]; + } + return next_gate_challenges; + } + // Returns the accumulator, which is the first element in ProverInstances. The accumulator is assumed to have the // FoldingParameters set and be the result of a previous round of folding. // TODO(https://github.com/AztecProtocol/barretenberg/issues/740): handle the case when the accumulator is empty @@ -191,14 +239,12 @@ template class ProtoGalaxyProver_ { { auto full_honk_evaluations = compute_full_honk_evaluations( accumulator->prover_polynomials, accumulator->alpha, accumulator->relation_parameters); - const auto betas = accumulator->folding_parameters.gate_separation_challenges; + const auto betas = accumulator->folding_parameters.gate_challenges; assert(betas.size() == deltas.size()); auto coeffs = construct_perturbator_coefficients(betas, deltas, full_honk_evaluations); return Polynomial(coeffs); } - ProverFoldingResult fold_instances(); - TupleOfTuplesOfUnivariates univariate_accumulators; /** @@ -243,7 +289,7 @@ template class ProtoGalaxyProver_ { ExtendedUnivariateWithRandomization compute_combiner(const ProverInstances& instances, const std::vector& pow_betas_star) { - size_t common_circuit_size = instances[0]->prover_polynomials.get_polynomial_size(); + size_t common_instance_size = instances[0]->instance_size; // Determine number of threads for multithreading. // Note: Multithreading is "on" for every round but we reduce the number of threads from the max available based @@ -251,14 +297,15 @@ template class ProtoGalaxyProver_ { // For now we use a power of 2 number of threads simply to ensure the round size is evenly divided. size_t max_num_threads = get_num_cpus_pow2(); // number of available threads (power of 2) size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread - size_t desired_num_threads = common_circuit_size / min_iterations_per_thread; + size_t desired_num_threads = common_instance_size / min_iterations_per_thread; size_t num_threads = std::min(desired_num_threads, max_num_threads); // fewer than max if justified num_threads = num_threads > 0 ? num_threads : 1; // ensure num threads is >= 1 - size_t iterations_per_thread = common_circuit_size / num_threads; // actual iterations per thread + size_t iterations_per_thread = common_instance_size / num_threads; // actual iterations per thread // Construct univariate accumulator containers; one per thread std::vector thread_univariate_accumulators(num_threads); for (auto& accum : thread_univariate_accumulators) { + // just normal relation lengths Utils::zero_univariates(accum); } @@ -341,21 +388,21 @@ template class ProtoGalaxyProver_ { } /** - * @brief Create folded (univariate) relation parameters. + * @brief Combine each relation parameter, in part, from all the instances into univariates, used in the computation + * of combiner. * @details For a given relation parameter type, extract that parameter from each instance, place the values in a * univariate (i.e., sum them against an appropriate univariate Lagrange basis) and then extended as needed during * the constuction of the combiner. */ - static void fold_relation_parameters(ProverInstances& instances) + static void combine_relation_parameters(ProverInstances& instances) { // array of parameters to be computed - auto& folded_parameters = instances.relation_parameters.to_fold; size_t param_idx = 0; - for (auto& folded_parameter : folded_parameters) { + for (auto& folded_parameter : instances.relation_parameters.to_fold) { Univariate tmp(0); size_t instance_idx = 0; for (auto& instance : instances) { - tmp.value_at(instance_idx) = instance->relation_parameters.to_fold[param_idx]; + tmp.value_at(instance_idx) = instance->relation_parameters.to_fold[param_idx].get(); instance_idx++; } folded_parameter.get() = tmp.template extend_to(); @@ -364,14 +411,15 @@ template class ProtoGalaxyProver_ { } /** - * @brief Create folded univariate for the relation batching parameter (alpha). + * @brief Combine the relation batching parameter (named alpha) from each instance into a univariate, used in the + * computation of combiner. * */ // TODO(https://github.com/AztecProtocol/barretenberg/issues/772): At the moment we have a single α per Instance, we // fold them and then we use the unique folded_α for each folded subrelation that is batched in the combiner. This // is obviously insecure. We need to generate α_i for each subrelation_i, fold them and then use folded_α_i when // batching the i-th folded subrelation in the combiner. - static void fold_alpha(ProverInstances& instances) + static void combine_alpha(ProverInstances& instances) { Univariate accumulated_alpha; size_t instance_idx = 0; @@ -381,6 +429,24 @@ template class ProtoGalaxyProver_ { } instances.alpha = accumulated_alpha.template extend_to(); } + + /** + * @brief Compute the next accumulator (ϕ*, ω*\vec{\beta*}, e*), send the public data ϕ* and the folding parameters + * (\vec{\beta*}, e*) to the verifier and return the complete accumulator + * + * @details At this stage, we assume that the instances have the same size and the same number of public parameter.s + * @param instances + * @param combiner_quotient polynomial K in the paper + * @param challenge + * @param compressed_perturbator + * + * TODO(https://github.com/AztecProtocol/barretenberg/issues/796): optimise the construction of the new accumulator + */ + std::shared_ptr compute_next_accumulator( + ProverInstances& instances, + Univariate& combiner_quotient, + const FF& challenge, + const FF& compressed_perturbator); }; extern template class ProtoGalaxyProver_>; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index 1aa99dea379..7107d991228 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -3,57 +3,148 @@ namespace proof_system::honk { template -void ProtoGalaxyVerifier_::prepare_for_folding(std::vector fold_data) +void ProtoGalaxyVerifier_::receive_accumulator(const std::shared_ptr& inst, + const std::string& domain_separator) +{ + 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"); + + 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); + } + + 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 }; + inst->alpha = transcript->template receive_from_prover(domain_separator + "_alpha"); + + inst->folding_parameters.target_sum = + transcript->template receive_from_prover(domain_separator + "_target_sum"); + + inst->folding_parameters.gate_challenges = std::vector(inst->log_instance_size); + for (size_t idx = 0; idx < inst->log_instance_size; idx++) { + inst->folding_parameters.gate_challenges[idx] = + transcript->template receive_from_prover(domain_separator + "_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(domain_separator + "_" + 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(domain_separator + "_" + vk_labels[idx]); + } +} + +template +void ProtoGalaxyVerifier_::receive_and_finalise_instance(const std::shared_ptr& inst, + const std::string& domain_separator) +{ + 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"); + + 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); + } + + inst->pub_inputs_offset = + transcript->template receive_from_prover(domain_separator + "_pub_inputs_offset"); + + 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); + + 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); + + 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); + + 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 }; + + inst->alpha = transcript->get_challenge(domain_separator + "_alpha"); + + 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 ProtoGalaxyVerifier_::prepare_for_folding(const std::vector& fold_data) { transcript = std::make_shared(fold_data); auto index = 0; - for (auto it = verifier_instances.begin(); it != verifier_instances.end(); it++, index++) { + auto inst = instances[0]; + auto domain_separator = std::to_string(index); + inst->is_accumulator = transcript->template receive_from_prover(domain_separator + "is_accumulator"); + if (inst->is_accumulator) { + receive_accumulator(inst, domain_separator); + } else { + receive_and_finalise_instance(inst, domain_separator); + } + index++; + + for (auto it = instances.begin() + 1; it != instances.end(); it++, index++) { auto inst = *it; auto domain_separator = std::to_string(index); - inst->instance_size = transcript->template receive_from_prover(domain_separator + "_circuit_size"); - inst->public_input_size = - transcript->template receive_from_prover(domain_separator + "_public_input_size"); - inst->pub_inputs_offset = - transcript->template receive_from_prover(domain_separator + "_pub_inputs_offset"); - - 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); - } - auto [eta, beta, gamma] = challenges_to_field_elements(transcript->get_challenges( - domain_separator + "_eta", domain_separator + "_beta", domain_separator + "_gamma")); - - 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 }; - inst->alpha = transcript->get_challenge(domain_separator + "_alpha"); + receive_and_finalise_instance(inst, domain_separator); } } template -VerifierFoldingResult ProtoGalaxyVerifier_< - VerifierInstances>::fold_public_parameters(std::vector fold_data) +bool ProtoGalaxyVerifier_::verify_folding_proof(std::vector fold_data) { - using Flavor = typename VerifierInstances::Flavor; - prepare_for_folding(fold_data); - FF delta = transcript->get_challenge("delta"); + + auto delta = transcript->get_challenge("delta"); auto accumulator = get_accumulator(); - auto log_instance_size = static_cast(numeric::get_msb(accumulator->instance_size)); - auto deltas = compute_round_challenge_pows(log_instance_size, delta); - std::vector perturbator_coeffs(log_instance_size + 1); - for (size_t idx = 0; idx <= log_instance_size; idx++) { + 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)); } + ASSERT(perturbator_coeffs[0] == accumulator->folding_parameters.target_sum); auto perturbator = Polynomial(perturbator_coeffs); FF perturbator_challenge = transcript->get_challenge("perturbator_challenge"); auto perturbator_at_challenge = perturbator.evaluate(perturbator_challenge); - // Thed 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 = {}; + // 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)); @@ -64,14 +155,99 @@ VerifierFoldingResult ProtoGalaxyVerifier_< auto combiner_quotient_at_challenge = combiner_quotient.evaluate(combiner_challenge); auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); - auto lagrange_0_at_challenge = FF(1) - combiner_challenge; + 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"); + bool verified = (expected_next_target_sum == next_target_sum); + auto expected_betas_star = + update_gate_challenges(perturbator_challenge, accumulator->folding_parameters.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)); + verified = verified & (expected_betas_star[idx] == beta_star); + } + + // 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; + for (auto& expected_comm : acc_witness_commitments.get_all()) { + expected_comm = Commitment::infinity(); + 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]); + verified = verified & (comm == expected_comm); + comm_idx++; + } - auto new_target_sum = perturbator_at_challenge * lagrange_0_at_challenge + - vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; + std::vector folded_public_inputs(instances[0]->public_inputs.size(), 0); + size_t el_idx = 0; + for (auto& expected_el : folded_public_inputs) { + size_t inst = 0; + for (auto& instance : instances) { + expected_el += instance->public_inputs[el_idx] * lagranges[inst]; + inst++; + } + auto el = transcript->template receive_from_prover("next_public_input" + std::to_string(el_idx)); + verified = verified & (el == expected_el); + el_idx++; + } + + auto expected_alpha = FF(0); + auto expected_parameters = proof_system::RelationParameters{}; + for (size_t inst_idx = 0; inst_idx < VerifierInstances::NUM; inst_idx++) { + auto instance = instances[inst_idx]; + expected_alpha += instance->alpha * lagranges[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_alpha = transcript->template receive_from_prover("next_alpha"); + verified = verified & (next_alpha == expected_alpha); + info(verified); + auto next_eta = transcript->template receive_from_prover("next_eta"); + verified = verified & (next_eta == expected_parameters.eta); + info(verified); + + auto next_beta = transcript->template receive_from_prover("next_beta"); + verified = verified & (next_beta == expected_parameters.beta); + + auto next_gamma = transcript->template receive_from_prover("next_gamma"); + verified = verified & (next_gamma == expected_parameters.gamma); + + auto next_public_input_delta = transcript->template receive_from_prover("next_public_input_delta"); + verified = verified & (next_public_input_delta == expected_parameters.public_input_delta); + + auto next_lookup_grand_product_delta = + transcript->template receive_from_prover("next_lookup_grand_product_delta"); + verified = verified & (next_lookup_grand_product_delta == expected_parameters.lookup_grand_product_delta); + + 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 = Commitment::infinity(); + 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]); + verified = verified & (vk == expected_vk); + vk_idx++; + } - VerifierFoldingResult res; - res.parameters.target_sum = new_target_sum; - return res; + return verified; } template class ProtoGalaxyVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp index 3c5a4ed8ef1..c723532a5b9 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp @@ -12,17 +12,23 @@ template class ProtoGalaxyVerifier_ { using Flavor = typename VerifierInstances::Flavor; using Transcript = typename Flavor::Transcript; using FF = typename Flavor::FF; + using Commitment = typename Flavor::Commitment; using Instance = typename VerifierInstances::Instance; using VerificationKey = typename Flavor::VerificationKey; + using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; + + VerifierInstances instances; - VerifierInstances verifier_instances; std::shared_ptr transcript = std::make_shared(); + CommitmentLabels commitment_labels; + ProtoGalaxyVerifier_(VerifierInstances insts) - : verifier_instances(insts){}; + : instances(insts){}; ~ProtoGalaxyVerifier_() = default; /** - * @brief For a new round challenge δ at each iteration of the ProtoGalaxy protocol, compute the vector + * @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) @@ -35,21 +41,47 @@ template class ProtoGalaxyVerifier_ { return pows; } - std::shared_ptr get_accumulator() { return verifier_instances[0]; } + 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); + next_gate_challenges[0] = 1; + + for (size_t idx = 1; idx < log_instance_size; idx++) { + next_gate_challenges[idx] = gate_challenges[idx] + perturbator_challenge * round_challenges[idx - 1]; + } + return next_gate_challenges; + } + + std::shared_ptr get_accumulator() { return instances[0]; } /** - * @brief Instatiate the VerifierInstances and the VerifierTranscript. + * @brief Instatiate the instances and the transcript. * * @param fold_data The data transmitted via the transcript by the prover. */ - void prepare_for_folding(std::vector fold_data); + void prepare_for_folding(const std::vector&); + + /** + * @brief Instantiatied 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. + * @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. * - * TODO(https://github.com/AztecProtocol/barretenberg/issues/690): finalise the implementation of this function */ - VerifierFoldingResult fold_public_parameters(std::vector fold_data); + bool verify_folding_proof(std::vector); }; extern template class ProtoGalaxyVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp index 1fc658eae9c..0fcc8d27614 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp @@ -8,6 +8,7 @@ template struct ProverInstances_ { public: static_assert(NUM_ > 0, "Must have at least one prover instance"); using Flavor = Flavor_; + using FoldingParameters = typename Flavor::FoldingParameters; using FF = typename Flavor::FF; static constexpr size_t NUM = NUM_; using Instance = ProverInstance_; @@ -21,6 +22,7 @@ template struct ProverInstances_ { ArrayType _data; RelationParameters relation_parameters; AlphaType alpha; + std::vector next_gate_challenges; std::shared_ptr const& operator[](size_t idx) const { return _data[idx]; } typename ArrayType::iterator begin() { return _data.begin(); }; @@ -54,16 +56,15 @@ template struct ProverInstances_ { */ std::vector> row_to_univariates(size_t row_idx) const { - auto instance_polynomial_views = get_polynomial_views(); + auto insts_prover_polynomials_views = get_polynomials_views(); std::vector> results; - // Initialize to our amount of columns - results.resize(instance_polynomial_views[0].size()); + // Set the size corresponding to the number of rows in the execution trace + results.resize(insts_prover_polynomials_views[0].size()); size_t instance_idx = 0; - // Iterate instances - for (auto& get_all : instance_polynomial_views) { - // Iterate columns + // Iterate over the prover polynomials' views corresponding to each instance + for (auto& get_all : insts_prover_polynomials_views) { + // Iterate over all columns in the trace execution of an instance and extract their value at row_idx. for (auto [result, poly_ptr] : zip_view(results, get_all)) { - // Assign row for each instance result.evaluations[instance_idx] = (poly_ptr)[row_idx]; } instance_idx++; @@ -72,9 +73,10 @@ template struct ProverInstances_ { } private: - auto get_polynomial_views() const + // Returns a vector containing pointer views to the prover polynomials corresponding to each instance. + auto get_polynomials_views() const { - // As a practical measure, get the first instance's pointer view to deduce the vector type + // As a practical measure, get the first instance's view to deduce the vector type std::vector get_alls{ _data[0]->prover_polynomials.get_all() }; // complete the views, starting from the second item for (size_t i = 1; i < NUM; i++) { @@ -97,14 +99,10 @@ template struct VerifierInstances_ { std::shared_ptr const& operator[](size_t idx) const { return _data[idx]; } typename ArrayType::iterator begin() { return _data.begin(); }; typename ArrayType::iterator end() { return _data.end(); }; - VerifierInstances_(std::vector> vks) + + VerifierInstances_() { - ASSERT(vks.size() == NUM); - for (size_t idx = 0; idx < vks.size(); idx++) { - Instance inst; - inst.verification_key = std::move(vks[idx]); - _data[idx] = std::make_unique(inst); - } + std::generate(_data.begin(), _data.end(), []() { return std::make_unique(); }); }; }; } // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 8e1a6ede949..4e5a5d66123 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -353,6 +353,9 @@ template void ProverInstance_::initialize_prover_polynomi size_t idx = i + pub_inputs_offset; public_inputs.emplace_back(public_wires_source[idx]); } + + instance_size = proving_key->circuit_size; + log_instance_size = static_cast(numeric::get_msb(instance_size)); } template void ProverInstance_::compute_sorted_accumulator_polynomials(FF eta) diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 5f12dc0c1dd..ea09aa6fceb 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -3,7 +3,6 @@ #include "barretenberg/flavor/goblin_ultra.hpp" #include "barretenberg/flavor/ultra.hpp" #include "barretenberg/proof_system/composer/composer_lib.hpp" -#include "barretenberg/protogalaxy/folding_result.hpp" #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" @@ -28,6 +27,7 @@ template class ProverInstance_ { using ProverPolynomials = typename Flavor::ProverPolynomials; using Polynomial = typename Flavor::Polynomial; using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; public: std::shared_ptr proving_key; @@ -35,6 +35,7 @@ template class ProverInstance_ { ProverPolynomials prover_polynomials; WitnessCommitments witness_commitments; + CommitmentLabels commitment_labels; std::array sorted_polynomials; @@ -50,6 +51,9 @@ template class ProverInstance_ { std::vector recursive_proof_public_input_indices; // non-empty for the accumulated instances FoldingParameters folding_parameters; + bool is_accumulator = false; + size_t instance_size; + size_t log_instance_size; ProverInstance_(Circuit& circuit) { @@ -58,12 +62,6 @@ template class ProverInstance_ { compute_witness(circuit); } - ProverInstance_(FoldingResult result) - : verification_key(std::move(result.verification_key)) - , prover_polynomials(result.folded_prover_polynomials) - , public_inputs(result.folded_public_inputs) - , folding_parameters(result.folding_parameters){}; - ProverInstance_() = default; ~ProverInstance_() = default; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp index fb14bd32b8b..06fdc47f264 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp @@ -8,14 +8,20 @@ template class VerifierInstance_ { using FF = typename Flavor::FF; using VerificationKey = typename Flavor::VerificationKey; using FoldingParameters = typename Flavor::FoldingParameters; + using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; std::shared_ptr verification_key; std::vector public_inputs; - size_t pub_inputs_offset; + size_t pub_inputs_offset = 0; size_t public_input_size; size_t instance_size; + size_t log_instance_size; RelationParameters relation_parameters; FF alpha; + bool is_accumulator = false; FoldingParameters folding_parameters; + WitnessCommitments witness_commitments; + CommitmentLabels commitment_labels; }; } // namespace proof_system::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index fac96d16cc6..caf1285e0b8 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -6,14 +6,18 @@ using namespace barretenberg; using namespace proof_system::honk; using Flavor = flavor::Ultra; +using VerificationKey = Flavor::VerificationKey; using Instance = ProverInstance_; using Instances = ProverInstances_; using ProtoGalaxyProver = ProtoGalaxyProver_; using FF = Flavor::FF; +using Affine = Flavor::Commitment; +using Projective = Flavor::GroupElement; using Builder = Flavor::CircuitBuilder; using Polynomial = typename Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; using RelationParameters = proof_system::RelationParameters; +using WitnessCommitments = typename Flavor::WitnessCommitments; const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; namespace protogalaxy_tests { @@ -81,6 +85,26 @@ ProverPolynomials construct_ultra_full_polynomials(auto& input_polynomials) return full_polynomials; } +std::shared_ptr construct_ultra_verification_key(size_t instance_size, size_t num_public_inputs) +{ + auto verification_key = std::make_shared(instance_size, num_public_inputs); + auto vk_view = verification_key->get_all(); + for (auto& view : vk_view) { + view = Affine(Projective::random_element()); + } + return verification_key; +} + +WitnessCommitments construct_witness_commitments() +{ + WitnessCommitments wc; + auto w_view = wc.get_all(); + for (auto& view : w_view) { + view = Affine(Projective::random_element()); + } + return wc; +} + class ProtoGalaxyTests : public ::testing::Test { public: static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); } @@ -159,11 +183,9 @@ TEST_F(ProtoGalaxyTests, PerturbatorPolynomial) target_sum += full_honk_evals[i] * pow_beta[i]; } - auto accumulator = std::make_shared( - FoldingResult{ .folded_prover_polynomials = full_polynomials, - .folded_public_inputs = std::vector{}, - .verification_key = std::make_shared(), - .folding_parameters = { betas, target_sum } }); + auto accumulator = std::make_shared(); + accumulator->prover_polynomials = full_polynomials; + accumulator->folding_parameters = { betas, target_sum }; accumulator->relation_parameters = relation_parameters; accumulator->alpha = alpha; @@ -225,7 +247,7 @@ TEST_F(ProtoGalaxyTests, FoldChallenges) instance2->relation_parameters.eta = 3; Instances instances{ { instance1, instance2 } }; - ProtoGalaxyProver::fold_relation_parameters(instances); + ProtoGalaxyProver::combine_relation_parameters(instances); Univariate expected_eta{ { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 } }; EXPECT_EQ(instances.relation_parameters.eta, expected_eta); @@ -246,10 +268,67 @@ TEST_F(ProtoGalaxyTests, FoldAlpha) instance2->alpha = 4; Instances instances{ { instance1, instance2 } }; - ProtoGalaxyProver::fold_alpha(instances); + ProtoGalaxyProver::combine_alpha(instances); Univariate expected_alpha{ { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26 } }; EXPECT_EQ(instances.alpha, expected_alpha); } +// TODO(https://github.com/AztecProtocol/barretenberg/issues/807): Have proper full folding testing (both failing and +// passing) and move creating a test accumulator in a separate function. +TEST_F(ProtoGalaxyTests, ComputeNewAccumulator) +{ + const size_t log_instance_size(4); + const size_t instance_size(1 << log_instance_size); + + std::array, NUM_POLYNOMIALS> random_polynomials; + for (auto& poly : random_polynomials) { + poly = get_random_polynomial(instance_size); + } + auto full_polynomials = construct_ultra_full_polynomials(random_polynomials); + auto relation_parameters = proof_system::RelationParameters::get_random(); + auto alpha = FF::random_element(); + + auto full_honk_evals = + ProtoGalaxyProver::compute_full_honk_evaluations(full_polynomials, alpha, relation_parameters); + std::vector betas(log_instance_size); + for (size_t idx = 0; idx < log_instance_size; idx++) { + betas[idx] = FF::random_element(); + } + + // Construct pow(\vec{betas}) as in the paper + auto pow_beta = ProtoGalaxyProver::compute_pow_polynomial_at_values(betas, instance_size); + + // Compute the corresponding target sum and create a dummy accumulator + auto target_sum = FF(0); + for (size_t i = 0; i < instance_size; i++) { + target_sum += full_honk_evals[i] * pow_beta[i]; + } + + auto accumulator = std::make_shared(); + accumulator->witness_commitments = construct_witness_commitments(); + accumulator->instance_size = instance_size; + accumulator->log_instance_size = log_instance_size; + accumulator->prover_polynomials = full_polynomials; + accumulator->folding_parameters = { betas, target_sum }; + accumulator->relation_parameters = relation_parameters; + accumulator->alpha = alpha; + accumulator->is_accumulator = true; + accumulator->public_inputs = std::vector{ FF::random_element() }; + accumulator->verification_key = construct_ultra_verification_key(instance_size, 1); + + auto builder = typename Flavor::CircuitBuilder(); + auto composer = UltraComposer(); + builder.add_public_variable(FF(1)); + + auto instance = composer.create_instance(builder); + auto instances = std::vector>{ accumulator, instance }; + auto folding_prover = composer.create_folding_prover(instances, composer.commitment_key); + auto folding_verifier = composer.create_folding_verifier(); + + auto proof = folding_prover.fold_instances(); + auto res = folding_verifier.verify_folding_proof(proof.folding_data); + EXPECT_EQ(res, true); +} + } // namespace protogalaxy_tests \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp index 0d4dd752d08..7daaab2e1d3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp @@ -90,21 +90,17 @@ template class UltraComposer_ { */ MergeVerifier_ create_merge_verifier() { return MergeVerifier_(); } - ProtoGalaxyProver_ create_folding_prover(const std::vector>& instances) + ProtoGalaxyProver_ create_folding_prover(const std::vector>& instances, + const std::shared_ptr& commitment_key) { - ProverInstances insts(instances); - ProtoGalaxyProver_ output_state(insts); + ProtoGalaxyProver_ output_state(instances, commitment_key); return output_state; }; - ProtoGalaxyVerifier_ create_folding_verifier( - const std::vector>& instances) + ProtoGalaxyVerifier_ create_folding_verifier() { - std::vector> vks; - for (const auto& inst : instances) { - vks.emplace_back(inst->verification_key); - } - VerifierInstances insts(vks); + + auto insts = VerifierInstances(); ProtoGalaxyVerifier_ output_state(insts); return output_state;