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;