From cfdaf9c1980356764a0bed88bc01358b8e807bd0 Mon Sep 17 00:00:00 2001 From: maramihali Date: Thu, 11 Jan 2024 15:26:14 +0000 Subject: [PATCH] feat: Protogalaxy Decider and complete folding tests (#3657) This PR introduces the Protogalaxy decider, now having a complete proof of concept of the folding protocol for Ultra instances. To enable this, sumcheck has been modified to work with the same power polynomial as in protogalaxy paper and can be initialised with a custom `target_sum`. Moreover, we now use different batching challenges for each subrelation in sumcheck, essential to ensure a reasonable degree of the combiner polynomial. Additional: Minor bug fixed in the computation of \vec{\beta*}. Resolves https://github.com/AztecProtocol/barretenberg/issues/772. Resolves https://github.com/AztecProtocol/barretenberg/issues/691. --- .circleci/config.yml | 12 - barretenberg/cpp/CMakePresets.json | 3 +- .../commitment_schemes/commitment_key.hpp | 3 - .../src/barretenberg/common/thread_utils.hpp | 1 + .../src/barretenberg/eccvm/eccvm_prover.cpp | 9 +- .../eccvm/eccvm_transcript.test.cpp | 9 +- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 13 +- .../cpp/src/barretenberg/flavor/ecc_vm.hpp | 1 + .../cpp/src/barretenberg/flavor/flavor.hpp | 4 + .../flavor/generated/AvmMini_flavor.hpp | 7 +- .../flavor/generated/Toy_flavor.hpp | 1 + .../barretenberg/flavor/goblin_translator.hpp | 1 + .../src/barretenberg/flavor/goblin_ultra.hpp | 62 ++++- .../flavor/goblin_ultra_recursive.hpp | 6 + .../cpp/src/barretenberg/flavor/ultra.hpp | 57 ++++- .../barretenberg/flavor/ultra_recursive.hpp | 6 + .../cpp/src/barretenberg/honk/CMakeLists.txt | 21 +- .../honk/proof_system/power_polynomial.hpp | 69 ------ .../proof_system/power_polynomial.test.cpp | 35 --- .../cpp/src/barretenberg/polynomials/pow.hpp | 177 ++++++++------ .../src/barretenberg/polynomials/pow.test.cpp | 29 ++- .../proof_system/composer/composer_lib.hpp | 4 +- .../protogalaxy/combiner.test.cpp | 21 +- .../protogalaxy/decider_prover.cpp | 121 ++++++++++ .../protogalaxy/decider_prover.hpp | 63 +++++ .../protogalaxy/decider_verifier.cpp | 113 +++++++++ .../protogalaxy/decider_verifier.hpp | 34 +++ .../protogalaxy/protogalaxy_prover.cpp | 140 ++++++----- .../protogalaxy/protogalaxy_prover.hpp | 90 +++---- .../protogalaxy/protogalaxy_verifier.cpp | 53 +++-- .../protogalaxy/protogalaxy_verifier.hpp | 8 +- .../relations/relation_parameters.hpp | 7 +- .../cpp/src/barretenberg/relations/utils.hpp | 83 +++++-- .../honk/verifier/goblin_verifier.test.cpp | 2 +- .../verifier/ultra_recursive_verifier.cpp | 17 +- .../verifier/ultra_recursive_verifier.hpp | 3 +- .../recursion/honk/verifier/verifier.test.cpp | 1 + .../sumcheck/instance/instances.hpp | 8 +- .../sumcheck/instance/prover_instance.cpp | 2 - .../sumcheck/instance/prover_instance.hpp | 13 +- .../sumcheck/instance/verifier_instance.hpp | 10 +- .../src/barretenberg/sumcheck/sumcheck.hpp | 69 +++--- .../barretenberg/sumcheck/sumcheck.test.cpp | 51 +++- .../barretenberg/sumcheck/sumcheck_round.hpp | 56 ++--- .../sumcheck/sumcheck_round.test.cpp | 22 +- .../goblin_translator_prover.cpp | 10 +- .../goblin_translator_verifier.cpp | 12 +- .../goblin_ultra_transcript.test.cpp | 19 +- .../ultra_honk/protogalaxy.test.cpp | 221 +++++++++++------- .../barretenberg/ultra_honk/sumcheck.test.cpp | 33 ++- .../ultra_honk/ultra_composer.cpp | 33 +++ .../ultra_honk/ultra_composer.hpp | 13 ++ .../barretenberg/ultra_honk/ultra_prover.cpp | 16 +- .../barretenberg/ultra_honk/ultra_prover.hpp | 1 + .../ultra_honk/ultra_transcript.test.cpp | 18 +- .../ultra_honk/ultra_verifier.cpp | 17 +- .../ultra_honk/ultra_verifier.hpp | 1 + .../vm/generated/AvmMini_prover.cpp | 10 +- .../vm/generated/AvmMini_verifier.cpp | 13 +- .../barretenberg/vm/generated/Toy_prover.cpp | 11 +- .../vm/generated/Toy_verifier.cpp | 13 +- 61 files changed, 1308 insertions(+), 650 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/honk/proof_system/power_polynomial.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/honk/proof_system/power_polynomial.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp create mode 100644 barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp create mode 100644 barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp create mode 100644 barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp diff --git a/.circleci/config.yml b/.circleci/config.yml index 186f118c56e..6d0a0ff24a9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -257,17 +257,6 @@ jobs: command: | barretenberg/cpp/scripts/ci/upload_benchmarks_to_s3.sh - barretenberg-honk-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Test" - command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/run_tests 1 honk_tests - barretenberg-proof-system-tests: docker: - image: aztecprotocol/alpine-build-image @@ -1135,7 +1124,6 @@ workflows: - barretenberg-x86_64-linux-clang <<: *defaults - barretenberg-proof-system-tests: *bb_test - - barretenberg-honk-tests: *bb_test - barretenberg-dsl-tests: *bb_test - barretenberg-tests: *bb_test - barretenberg-stdlib-tests: *bb_test diff --git a/barretenberg/cpp/CMakePresets.json b/barretenberg/cpp/CMakePresets.json index c458e9eee87..7b22541e785 100644 --- a/barretenberg/cpp/CMakePresets.json +++ b/barretenberg/cpp/CMakePresets.json @@ -351,8 +351,7 @@ "acvm_backend.wasm", "barretenberg", "wasi", - "env", - "honk_tests" + "env" ] }, { diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp index 394ff93fdbe..28359357e6c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.hpp @@ -7,9 +7,6 @@ * simplify the codebase. */ -#include "barretenberg/ecc/curves/bn254/bn254.hpp" -#include "barretenberg/ecc/curves/bn254/pairing.hpp" -#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/numeric/bitop/pow.hpp" #include "barretenberg/polynomials/polynomial.hpp" diff --git a/barretenberg/cpp/src/barretenberg/common/thread_utils.hpp b/barretenberg/cpp/src/barretenberg/common/thread_utils.hpp index 55ee79ff1ab..e6551665479 100644 --- a/barretenberg/cpp/src/barretenberg/common/thread_utils.hpp +++ b/barretenberg/cpp/src/barretenberg/common/thread_utils.hpp @@ -1,3 +1,4 @@ +#pragma once #include "thread.hpp" namespace barretenberg::thread_utils { diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index f43a46d64f1..f58b9524805 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -4,7 +4,6 @@ #include "barretenberg/common/ref_array.hpp" #include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/honk/proof_system/permutation_library.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/relations/lookup_relation.hpp" @@ -111,8 +110,12 @@ template void ECCVMProver_::execute_relation_check_ using Sumcheck = sumcheck::SumcheckProver; auto sumcheck = Sumcheck(key->circuit_size, transcript); - FF alpha = transcript->get_challenge("alpha"); - sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha); + FF alpha = transcript->get_challenge("Sumcheck:alpha"); + std::vector gate_challenges(numeric::get_msb(key->circuit_size)); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); } /** diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index 8df69c80e44..63abcda97de 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -126,10 +126,13 @@ template class ECCVMTranscriptTests : public ::testing::Test { round++; manifest_expected.add_entry(round, "LOOKUP_INVERSES", size_G); manifest_expected.add_entry(round, "Z_PERM", size_G); - manifest_expected.add_challenge(round, "alpha"); + manifest_expected.add_challenge(round, "Sumcheck:alpha"); - round++; - manifest_expected.add_challenge(round, "Sumcheck:zeta"); + for (size_t i = 0; i < log_n; i++) { + round++; + std::string label = "Sumcheck:gate_challenge_" + std::to_string(i); + manifest_expected.add_challenge(round, label); + } for (size_t i = 0; i < log_n; ++i) { round++; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 1d564c06a9f..6e23963e617 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -1,7 +1,6 @@ #include "./eccvm_verifier.hpp" #include "barretenberg/commitment_schemes/gemini/gemini.hpp" #include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -158,10 +157,16 @@ template bool ECCVMVerifier_::verify_proof(const plonk commitments.z_perm = receive_commitment(commitment_labels.z_perm); // Execute Sumcheck Verifier - auto sumcheck = SumcheckVerifier(circuit_size); - FF alpha = transcript->get_challenge("alpha"); + const size_t log_circuit_size = numeric::get_msb(circuit_size); + auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); + FF alpha = transcript->get_challenge("Sumcheck:alpha"); + std::vector gate_challenges(numeric::get_msb(key->circuit_size)); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto [multivariate_challenge, purported_evaluations, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, transcript); + sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { diff --git a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp index 2322c43f5a2..ede2d100ce8 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp @@ -45,6 +45,7 @@ template class ECCVMBa using CommitmentHandle = typename G1::affine_element; using CommitmentKey = pcs::CommitmentKey; using VerifierCommitmentKey = pcs::VerifierCommitmentKey; + using RelationSeparator = FF; static constexpr size_t NUM_WIRES = 74; diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index 187f8fcec63..a8c5ac25942 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -302,6 +302,10 @@ concept IsRecursiveFlavor = IsAnyOf concept IsGrumpkinFlavor = IsAnyOf; +template concept IsFoldingFlavor = IsAnyOf, + honk::flavor::UltraRecursive_, + honk::flavor::GoblinUltraRecursive>; + template concept UltraFlavor = IsAnyOf; template concept ECCVMFlavor = IsAnyOf; diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp index a7018fc8d1b..e9355c1f3f9 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp @@ -17,8 +17,7 @@ #include "barretenberg/relations/generated/AvmMini/mem_trace.hpp" #include "barretenberg/transcript/transcript.hpp" -namespace proof_system::honk { -namespace flavor { +namespace proof_system::honk::flavor { class AvmMiniFlavor { public: @@ -34,6 +33,7 @@ class AvmMiniFlavor { using CommitmentHandle = G1::affine_element; using CommitmentKey = pcs::CommitmentKey; using VerifierCommitmentKey = pcs::VerifierCommitmentKey; + using RelationSeparator = FF; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; static constexpr size_t NUM_WITNESS_ENTITIES = 38; @@ -636,5 +636,4 @@ class AvmMiniFlavor { }; }; -} // namespace flavor -} // namespace proof_system::honk +} // namespace proof_system::honk::flavor diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp index 7799ac60958..fdb992586b7 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp @@ -34,6 +34,7 @@ class ToyFlavor { using CommitmentHandle = G1::affine_element; using CommitmentKey = pcs::CommitmentKey; using VerifierCommitmentKey = pcs::VerifierCommitmentKey; + using RelationSeparator = FF; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 1; static constexpr size_t NUM_WITNESS_ENTITIES = 16; diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp index 02ea81495a1..8d70d97653b 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp @@ -34,6 +34,7 @@ class GoblinTranslator { using BF = Curve::BaseField; using Polynomial = barretenberg::Polynomial; using PolynomialHandle = std::span; + using RelationSeparator = FF; // The size of the circuit which is filled with non-zero values for most polynomials. Most relations (everything // except for Permutation and GenPermSort) can be evaluated just on the first chunk diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 0849e885773..240f8f7552e 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -68,7 +68,6 @@ class GoblinUltra { static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length(); - static constexpr size_t NUMBER_OF_SUBRELATIONS = compute_number_of_subrelations(); // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation @@ -77,6 +76,12 @@ class GoblinUltra { static constexpr size_t BATCHED_RELATION_TOTAL_LENGTH = MAX_TOTAL_RELATION_LENGTH + 1; static constexpr size_t NUM_RELATIONS = std::tuple_size_v; + // For instances of this flavour, used in folding, we need a unique sumcheck batching challenges for each + // subrelation. This + // is because using powers of alpha would increase the degree of Protogalaxy polynomial $G$ (the combiner) to much. + static constexpr size_t NUM_SUBRELATIONS = compute_number_of_subrelations(); + using RelationSeparator = std::array; + template using ProtogalaxyTupleOfTuplesOfUnivariates = decltype(create_protogalaxy_tuple_of_tuples_of_univariates()); @@ -85,7 +90,6 @@ class GoblinUltra { // Whether or not the first row of the execution trace is reserved for 0s to enable shifts static constexpr bool has_zero_row = true; - /** * @brief A base class labelling precomputed entities and (ordered) subsets of interest. * @details Used to build the proving key and verification key. @@ -448,14 +452,58 @@ class GoblinUltra { this->lagrange_ecc_op = verification_key->lagrange_ecc_op; this->databus_id = verification_key->databus_id; } + + VerifierCommitments_(const std::shared_ptr& verification_key, + const WitnessCommitments& witness_commitments) + { + this->q_m = verification_key->q_m; + this->q_l = verification_key->q_l; + this->q_r = verification_key->q_r; + this->q_o = verification_key->q_o; + this->q_4 = verification_key->q_4; + this->q_c = verification_key->q_c; + this->q_arith = verification_key->q_arith; + this->q_sort = verification_key->q_sort; + this->q_elliptic = verification_key->q_elliptic; + this->q_aux = verification_key->q_aux; + this->q_lookup = verification_key->q_lookup; + this->q_busread = verification_key->q_busread; + this->q_poseidon2_external = verification_key->q_poseidon2_external; + this->q_poseidon2_internal = verification_key->q_poseidon2_internal; + this->sigma_1 = verification_key->sigma_1; + this->sigma_2 = verification_key->sigma_2; + this->sigma_3 = verification_key->sigma_3; + this->sigma_4 = verification_key->sigma_4; + this->id_1 = verification_key->id_1; + this->id_2 = verification_key->id_2; + this->id_3 = verification_key->id_3; + this->id_4 = verification_key->id_4; + this->table_1 = verification_key->table_1; + this->table_2 = verification_key->table_2; + this->table_3 = verification_key->table_3; + this->table_4 = verification_key->table_4; + this->lagrange_first = verification_key->lagrange_first; + this->lagrange_last = verification_key->lagrange_last; + this->lagrange_ecc_op = verification_key->lagrange_ecc_op; + this->databus_id = verification_key->databus_id; + + this->w_l = witness_commitments.w_l; + this->w_r = witness_commitments.w_r; + this->w_o = witness_commitments.w_o; + this->sorted_accum = witness_commitments.sorted_accum; + this->w_4 = witness_commitments.w_4; + this->z_perm = witness_commitments.z_perm; + this->z_lookup = witness_commitments.z_lookup; + this->ecc_op_wire_1 = witness_commitments.ecc_op_wire_1; + this->ecc_op_wire_2 = witness_commitments.ecc_op_wire_2; + this->ecc_op_wire_3 = witness_commitments.ecc_op_wire_3; + this->calldata = witness_commitments.calldata; + this->calldata = witness_commitments.calldata_read_counts; + this->lookup_inverses = witness_commitments.lookup_inverses; + } }; // Specialize for GoblinUltra (general case used in GoblinUltraRecursive). using VerifierCommitments = VerifierCommitments_; - class FoldingParameters { - public: - std::vector gate_challenges; - FF target_sum; - }; /** * @brief Derived class that defines proof structure for GoblinUltra proofs, as well as supporting functions. diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index f1c6f9aaa90..ee257322187 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -74,6 +74,12 @@ class GoblinUltraRecursive { static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; static constexpr size_t NUM_RELATIONS = std::tuple_size::value; + // For instances of this flavour, used in folding, we need a unique sumcheck batching challenge for each + // subrelation. This is because using powers of alpha would increase the degree of Protogalaxy polynomial $G$ (the + // combiner) to much. + static constexpr size_t NUM_SUBRELATIONS = compute_number_of_subrelations(); + using RelationSeparator = std::array; + // define the container for storing the univariate contribution from each relation in Sumcheck using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates()); using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values()); diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index 5dad1648b59..de77c42235d 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -54,10 +54,14 @@ class Ultra { proof_system::AuxiliaryRelation>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); - static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length(); static_assert(MAX_PARTIAL_RELATION_LENGTH == 6); + static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length(); static_assert(MAX_TOTAL_RELATION_LENGTH == 12); - static constexpr size_t NUMBER_OF_SUBRELATIONS = compute_number_of_subrelations(); + static constexpr size_t NUM_SUBRELATIONS = compute_number_of_subrelations(); + // For instances of this flavour, used in folding, we need a unique sumcheck batching challenge for each + // subrelation. This is because using powers of alpha would increase the degree of Protogalaxy polynomial $G$ (the + // combiner) too much. + using RelationSeparator = std::array; // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation @@ -75,6 +79,8 @@ class Ultra { // Whether or not the first row of the execution trace is reserved for 0s to enable shifts static constexpr bool has_zero_row = true; + static constexpr bool is_decider = true; + private: /** * @brief A base class labelling precomputed entities and (ordered) subsets of interest. @@ -400,6 +406,11 @@ class Ultra { }; }; + /** + * @brief A container encapsulating all the commitments that the verifier receives (to precomputed polynomials and + * witness polynomials). + * + */ class VerifierCommitments : public AllEntities { public: VerifierCommitments(const std::shared_ptr& verification_key) @@ -430,12 +441,44 @@ class Ultra { lagrange_first = verification_key->lagrange_first; lagrange_last = verification_key->lagrange_last; } - }; - class FoldingParameters { - public: - std::vector gate_challenges; - FF target_sum; + VerifierCommitments(const std::shared_ptr& verification_key, + const WitnessCommitments& witness_commitments) + { + q_m = verification_key->q_m; + q_c = verification_key->q_c; + q_l = verification_key->q_l; + q_r = verification_key->q_r; + q_o = verification_key->q_o; + q_4 = verification_key->q_4; + q_arith = verification_key->q_arith; + q_sort = verification_key->q_sort; + q_elliptic = verification_key->q_elliptic; + q_aux = verification_key->q_aux; + q_lookup = verification_key->q_lookup; + sigma_1 = verification_key->sigma_1; + sigma_2 = verification_key->sigma_2; + sigma_3 = verification_key->sigma_3; + sigma_4 = verification_key->sigma_4; + id_1 = verification_key->id_1; + id_2 = verification_key->id_2; + id_3 = verification_key->id_3; + id_4 = verification_key->id_4; + table_1 = verification_key->table_1; + table_2 = verification_key->table_2; + table_3 = verification_key->table_3; + table_4 = verification_key->table_4; + lagrange_first = verification_key->lagrange_first; + lagrange_last = verification_key->lagrange_last; + + w_l = witness_commitments.w_l; + w_r = witness_commitments.w_r; + w_o = witness_commitments.w_o; + sorted_accum = witness_commitments.sorted_accum; + w_4 = witness_commitments.w_4; + z_perm = witness_commitments.z_perm; + z_lookup = witness_commitments.z_lookup; + } }; /** diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index d4591f885f3..19fced27b74 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -86,6 +86,12 @@ template class UltraRecursive_ { static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; static constexpr size_t NUM_RELATIONS = std::tuple_size::value; + // For instances of this flavour, used in folding, we need a unique sumcheck batching challenges for each + // subrelation to avoid increasing the degree of Protogalaxy polynomial $G$ (the + // combiner) too much. + static constexpr size_t NUM_SUBRELATIONS = compute_number_of_subrelations(); + using RelationSeparator = std::array; + // define the container for storing the univariate contribution from each relation in Sumcheck using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates()); using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values()); diff --git a/barretenberg/cpp/src/barretenberg/honk/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/honk/CMakeLists.txt index f57c608e058..a0e5fccbd8a 100644 --- a/barretenberg/cpp/src/barretenberg/honk/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/honk/CMakeLists.txt @@ -1,20 +1 @@ -barretenberg_module(honk proof_system commitment_schemes sumcheck) - -if(TESTING) - # TODO: Re-enable all these warnings once PoC is finished - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - target_compile_options( - honk_test_objects - PRIVATE - -Wno-error=unused-variable - ) - elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - target_compile_options( - honk_test_objects - PRIVATE - -Wno-error=maybe-uninitialized - -Wno-error=uninitialized - -Wno-error=unused-variable - ) - endif() -endif() + barretenberg_module(honk proof_system commitment_schemes sumcheck) diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/power_polynomial.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/power_polynomial.hpp deleted file mode 100644 index 5dfe7701a32..00000000000 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/power_polynomial.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include "barretenberg/common/thread.hpp" -#include "barretenberg/polynomials/polynomial.hpp" -#include - -namespace proof_system::honk::power_polynomial { -/** - * @brief Generate the power polynomial vector - * - * @details Generates a vector, where v[i]=ζⁱ - * - * @param zeta - * @param vector_size - * @return barretenberg::polynomial - */ -template barretenberg::Polynomial generate_vector(Fr zeta, size_t vector_size) -{ - // We know the size from the start, so we can allocate exactly the right amount of memory - barretenberg::Polynomial pow_vector(vector_size); - - constexpr size_t usefulness_margin = 4; - size_t num_threads = get_num_cpus_pow2(); - if (vector_size < (usefulness_margin * num_threads)) { - num_threads = 1; - } - // Prepare for a random number of threads. We need to handle the last thread separately - size_t thread_size = vector_size / num_threads; - size_t last_thread_size = thread_size; - // Check if the vector size is divided into threads cleanly - if ((vector_size % thread_size) != 0) { - thread_size += 1; - last_thread_size = vector_size % thread_size; - } - parallel_for(num_threads, [&](size_t i) { - // Exponentiate ζ to the starting power of the chunk - Fr starting_power = zeta.pow(i * thread_size); - // Set the chunk size depending ontwhether this is the last thread - size_t chunk_size = i != (num_threads - 1) ? thread_size : last_thread_size; - size_t j = 0; - // Go through elements and compute ζ powers - for (; j < chunk_size - 1; j++) { - pow_vector[i * thread_size + j] = starting_power; - starting_power *= zeta; - } - pow_vector[i * thread_size + j] = starting_power; - }); - return pow_vector; -} - -/** - * @brief Evaluate the power polynomial on {x_0,..,x_d} - * - * @details The power polynomial can be efficiently evaluated as ∏( ( b^{2^i} - 1 ) * x_i + 1) - * - * @param zeta ζ - * @param variables - * @return barretenberg::fr - */ -template Fr evaluate(Fr zeta, std::span variables) -{ - Fr evaluation = Fr::one(); - for (size_t i = 0; i < variables.size(); i++) { - // evaluation *= (b^{2^i} - 1) * x_i + 1 - evaluation *= (zeta - 1) * variables[i] + 1; - zeta *= zeta; - } - return evaluation; -} -} // namespace proof_system::honk::power_polynomial diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/power_polynomial.test.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/power_polynomial.test.cpp deleted file mode 100644 index 748731f0146..00000000000 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/power_polynomial.test.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "power_polynomial.hpp" -#include "barretenberg/numeric/random/engine.hpp" -#include - -TEST(power_polynomial, test_full_polynomial_correctness) -{ - const size_t order = 17; - const size_t n = size_t(1) << order; - barretenberg::fr zeta = barretenberg::fr::random_element(); - barretenberg::polynomial power_polynomial = proof_system::honk::power_polynomial::generate_vector(zeta, n); - - barretenberg::fr current_power = barretenberg::fr::one(); - for (size_t i = 0; i < n; i++) { - EXPECT_EQ(power_polynomial[i], current_power); - if (power_polynomial[i] != current_power) { - break; - } - current_power *= zeta; - } -} - -TEST(power_polynomial, test_evaluation_correctness) -{ - const size_t order = 30; - const size_t n = size_t(1) << order; - barretenberg::fr zeta = barretenberg::fr::random_element(); - // Not using the debug engine, because we want to test randomly - size_t random_index = static_cast(numeric::random::get_engine().get_random_uint32()) % n; - std::vector variables; - for (size_t i = 0; i < order; i++) { - variables.emplace_back((random_index >> i) & 1); - } - EXPECT_EQ(zeta.pow(static_cast(random_index)), - proof_system::honk::power_polynomial::evaluate(zeta, variables)); -} diff --git a/barretenberg/cpp/src/barretenberg/polynomials/pow.hpp b/barretenberg/cpp/src/barretenberg/polynomials/pow.hpp index 9039266cac0..a61bc21ba85 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/pow.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/pow.hpp @@ -1,51 +1,47 @@ #pragma once - +#include "barretenberg/common/thread.hpp" +#include "barretenberg/common/thread_utils.hpp" +#include +#include namespace barretenberg { /** * @brief Succinct representation of the `pow` polynomial that can be partially evaluated variable-by-variable. - * pow(X) = ∏_{0≤l struct PowUnivariate { - // ζ_{l}, initialized as ζ_{0} = ζ - // At round l, equals ζ^{ 2^l } - FF zeta_pow; - // ζ_{l+1}, initialized as ζ_{1} = ζ^2 - // Always equal to zeta_pow^2 - // At round l, equals ζ^{ 2^{l+1} } - FF zeta_pow_sqr; - // c_{l}, initialized as c_{0} = 1 - // c_{l} = ∏_{0 ≤ k < l-1} ( (1-u_{k}) + u_{k}⋅ζ_{k} ) - // At round d-1, equals pow(u_{0}, ..., u_{d-1}). - FF partial_evaluation_constant = FF(1); - // Initialize with the random zeta - explicit PowUnivariate(FF zeta_pow) - : zeta_pow(zeta_pow) - , zeta_pow_sqr(zeta_pow.sqr()) +template struct PowPolynomial { + + // \vec{β} = {β_0, β_1,.., β_{d-1}} + std::vector betas; + + // The values of pow_\vec{β}(i) for i=0,..,2^d - 1 for the given \vec{β} + std::vector pow_betas; + + // At round l of sumcheck this will point to the l-th element in \vec{β} + size_t current_element_idx = 0; + + // At round l of sumcheck, the periodicity represents the fixed interval at which elements not containing either of + // β_0,..,β_l appear in pow_betas + size_t periodicity = 2; + + // The value c_l obtained by partially evaluating one variable in the power polynomial at each round. At the + // end of round l in the sumcheck protocol, variable X_l is replaced by a verifier challenge u_l. The partial + // evaluation result is updated to represent pow(u_0,.., u_{l-1}) = \prod_{0 ≤ k < l} ( (1-u_k) + u_k⋅β_k). + FF partial_evaluation_result = FF(1); + + explicit PowPolynomial(const std::vector& betas) + : betas(betas) {} - // Evaluate the monomial ((1−X_{l}) + X_{l}⋅ζ_{l}) in the challenge point X_{l}=u_{l}. - FF univariate_eval(FF challenge) const { return (FF(1) + (challenge * (zeta_pow - FF(1)))); }; + FF const& operator[](size_t idx) const { return pow_betas[idx]; } + + FF current_element() const { return betas[current_element_idx]; } + + /** + * @brief Evaluate the monomial ((1−X_l) + X_l⋅β_l) in the challenge point X_l=u_l. + */ + FF univariate_eval(FF challenge) const { return (FF(1) + (challenge * (betas[current_element_idx] - FF(1)))); }; /** - * @brief Parially evaluate the polynomial in the new challenge, by updating the constant c_{l} -> c_{l+1}. - * Also update (ζ_{l}, ζ_{l+1}) -> (ζ_{l+1}, ζ_{l+1}^2) + * @brief Parially evaluate the pow polynomial in X_l and updating the value c_l -> c_{l+1}. * - * @param challenge l-th verifier challenge u_{l} + * @param challenge l-th verifier challenge u_l */ void partially_evaluate(FF challenge) { FF current_univariate_eval = univariate_eval(challenge); - zeta_pow = zeta_pow_sqr; - // TODO(luke): for native FF, this could be self_sqr() - zeta_pow_sqr = zeta_pow_sqr.sqr(); + partial_evaluation_result *= current_univariate_eval; + current_element_idx++; + periodicity *= 2; + } + + /** + * @brief Given \vec{β} = {β_0,...,β_{d-1}} compute pow_\vec{β}(i) for i=0,...,2^{d}-1 + * + */ + void compute_values() + { + size_t pow_size = 1 << betas.size(); + pow_betas = std::vector(pow_size); - partial_evaluation_constant *= current_univariate_eval; + // 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 + // on a specified minimum number of iterations per thread. This eventually leads to the use of a single thread. + // 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 = pow_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 = pow_size / num_threads; // actual iterations per thread + parallel_for(num_threads, [&](size_t thread_idx) { + size_t start = thread_idx * iterations_per_thread; + size_t end = (thread_idx + 1) * iterations_per_thread; + for (size_t i = start; i < end; i++) { + auto res = FF(1); + for (size_t j = i, beta_idx = 0; j > 0; j >>= 1, beta_idx++) { + if ((j & 1) == 1) { + res *= betas[beta_idx]; + } + } + pow_betas[i] = res; + } + }); } }; } // namespace barretenberg \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/polynomials/pow.test.cpp b/barretenberg/cpp/src/barretenberg/polynomials/pow.test.cpp index ad75285fce7..f73edfeea0d 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/pow.test.cpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/pow.test.cpp @@ -6,26 +6,37 @@ namespace barretenberg::test_pow { using FF = barretenberg::fr; -TEST(SumcheckPow, FullPowConsistency) +TEST(PowPolynomial, FullPowConsistency) { constexpr size_t d = 5; + std::vector betas(d); + for (auto& beta : betas) { + beta = FF::random_element(); + } - FF zeta = FF::random_element(); - - PowUnivariate pow_univariate(zeta); + PowPolynomial pow_polynomial(betas); std::array variables{}; for (auto& u_i : variables) { u_i = FF::random_element(); - pow_univariate.partially_evaluate(u_i); + pow_polynomial.partially_evaluate(u_i); } - FF zeta_power = zeta; + size_t beta_idx = 0; FF expected_eval = 1; for (auto& u_i : variables) { - expected_eval *= FF(1) - u_i + u_i * zeta_power; - zeta_power *= zeta_power; + expected_eval *= FF(1) - u_i + u_i * pow_polynomial.betas[beta_idx]; + beta_idx++; } - EXPECT_EQ(pow_univariate.partial_evaluation_constant, expected_eval); + EXPECT_EQ(pow_polynomial.partial_evaluation_result, expected_eval); +} + +TEST(PowPolynomial, PowPolynomialsOnPowers) +{ + auto betas = std::vector{ 2, 4, 16 }; + auto pow = PowPolynomial(betas); + pow.compute_values(); + auto expected_values = std::vector{ 1, 2, 4, 8, 16, 32, 64, 128 }; + EXPECT_EQ(expected_values, pow.pow_betas); } } // namespace barretenberg::test_pow diff --git a/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp b/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp index 10b1d751107..ee3cbcef0a3 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp @@ -1,7 +1,7 @@ #pragma once #include "barretenberg/flavor/flavor.hpp" -#include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" -#include "barretenberg/srs/factories/crs_factory.hpp" +#include "barretenberg/proof_system/polynomial_store/polynomial_store.hpp" + #include namespace proof_system { diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp index d69b45a9ef2..8ff572f47b9 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp @@ -1,5 +1,6 @@ #include "barretenberg/flavor/ultra.hpp" #include "barretenberg/honk/utils/testing.hpp" +#include "barretenberg/polynomials/pow.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/sumcheck/instance/instances.hpp" @@ -11,6 +12,7 @@ using Flavor = proof_system::honk::flavor::Ultra; using Polynomial = typename Flavor::Polynomial; using FF = typename Flavor::FF; using RelationParameters = proof_system::RelationParameters; +using PowPolynomial = barretenberg::PowPolynomial; // TODO(https://github.com/AztecProtocol/barretenberg/issues/780): Improve combiner tests to check more than the // arithmetic relation so we more than unit test folding relation parameters and alpha as well. @@ -38,7 +40,6 @@ TEST(Protogalaxy, CombinerOn2Instances) if (is_random_input) { std::vector> instance_data(NUM_INSTANCES); ProtoGalaxyProver prover; - std::vector pow_betas = { FF(1), FF(2) }; for (size_t idx = 0; idx < NUM_INSTANCES; idx++) { auto instance = std::make_shared(); @@ -51,9 +52,9 @@ TEST(Protogalaxy, CombinerOn2Instances) } ProverInstances instances{ instance_data }; - instances.alpha = Univariate(FF(0)); // focus on the arithmetic relation only - - auto result = prover.compute_combiner(instances, pow_betas); + instances.alphas.fill(Univariate(FF(0))); // focus on the arithmetic relation only + auto pow_polynomial = PowPolynomial(std::vector{ 2 }); + auto result = prover.compute_combiner(instances, pow_polynomial); auto expected_result = barretenberg::Univariate(std::array{ 87706, 13644570, @@ -72,7 +73,6 @@ TEST(Protogalaxy, CombinerOn2Instances) } else { std::vector> instance_data(NUM_INSTANCES); ProtoGalaxyProver prover; - std::vector pow_betas = { FF(1), FF(2) }; for (size_t idx = 0; idx < NUM_INSTANCES; idx++) { auto instance = std::make_shared(); @@ -85,7 +85,7 @@ TEST(Protogalaxy, CombinerOn2Instances) } ProverInstances instances{ instance_data }; - instances.alpha = Univariate(FF(0)); // focus on the arithmetic relation only + instances.alphas.fill(Univariate(FF(0))); // focus on the arithmetic relation only const auto create_add_gate = [](auto& polys, const size_t idx, FF w_l, FF w_r) { polys.w_l[idx] = w_l; @@ -131,7 +131,8 @@ TEST(Protogalaxy, CombinerOn2Instances) relation value: 0 0 0 0 0 0 0 0 0 6 18 36 60 90 */ - auto result = prover.compute_combiner(instances, pow_betas); + auto pow_polynomial = PowPolynomial(std::vector{ 2 }); + auto result = prover.compute_combiner(instances, pow_polynomial); auto expected_result = barretenberg::Univariate( std::array{ 0, 0, 12, 36, 72, 120, 180, 252, 336, 432, 540, 660, 792 }); @@ -163,7 +164,6 @@ TEST(Protogalaxy, CombinerOn4Instances) auto run_test = [&]() { std::vector> instance_data(NUM_INSTANCES); ProtoGalaxyProver prover; - std::vector pow_betas = { FF(1), FF(2) }; for (size_t idx = 0; idx < NUM_INSTANCES; idx++) { auto instance = std::make_shared(); @@ -175,14 +175,15 @@ TEST(Protogalaxy, CombinerOn4Instances) } ProverInstances instances{ instance_data }; - instances.alpha = Univariate(FF(0)); // focus on the arithmetic relation only + instances.alphas.fill(Univariate(FF(0))); // focus on the arithmetic relation only zero_all_selectors(instances[0]->prover_polynomials); zero_all_selectors(instances[1]->prover_polynomials); zero_all_selectors(instances[2]->prover_polynomials); zero_all_selectors(instances[3]->prover_polynomials); - auto result = prover.compute_combiner(instances, pow_betas); + auto pow_polynomial = PowPolynomial(std::vector{ 2 }); + auto result = prover.compute_combiner(instances, pow_polynomial); std::array zeroes; std::fill(zeroes.begin(), zeroes.end(), 0); auto expected_result = barretenberg::Univariate(zeroes); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp new file mode 100644 index 00000000000..eea53966aa6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp @@ -0,0 +1,121 @@ +#include "decider_prover.hpp" +#include "barretenberg/sumcheck/sumcheck.hpp" + +namespace proof_system::honk { + +/** + * Create DeciderProver_ from an accumulator. + * + * @param accumulator Relaxed instance (ϕ, ω, \vec{β}, e) whose proof we want to generate, produced by Protogalaxy + * folding prover + * + * @tparam a type of UltraFlavor + * */ +template +DeciderProver_::DeciderProver_(const std::shared_ptr& inst, + const std::shared_ptr& commitment_key, + const std::shared_ptr& transcript) + : accumulator(std::move(inst)) + , transcript(transcript) + , commitment_key(commitment_key) +{} + +/** + * @brief Add ϕ, \vec{β}, e to the transcript. These are produced in the last round of folding that was carried out + * before deciding. + */ +template void DeciderProver_::execute_preamble_round() +{ + const auto accumulator_size = static_cast(accumulator->instance_size); + const auto num_public_inputs = static_cast(accumulator->public_inputs.size()); + transcript->send_to_verifier("accumulator_size", accumulator_size); + transcript->send_to_verifier("public_input_size", num_public_inputs); + + for (size_t i = 0; i < accumulator->public_inputs.size(); ++i) { + auto public_input_i = accumulator->public_inputs[i]; + transcript->send_to_verifier("public_input_" + std::to_string(i), public_input_i); + } + + transcript->send_to_verifier("eta", accumulator->relation_parameters.eta); + transcript->send_to_verifier("beta", accumulator->relation_parameters.beta); + transcript->send_to_verifier("gamma", accumulator->relation_parameters.gamma); + transcript->send_to_verifier("public_input_delta", accumulator->relation_parameters.public_input_delta); + transcript->send_to_verifier("lookup_grand_product_delta", + accumulator->relation_parameters.lookup_grand_product_delta); + size_t alpha_idx = 0; + for (auto alpha : accumulator->alphas) { + transcript->send_to_verifier("alpha_" + std::to_string(alpha_idx), alpha); + } + + transcript->send_to_verifier("target_sum", accumulator->target_sum); + for (size_t idx = 0; idx < accumulator->gate_challenges.size(); idx++) { + transcript->send_to_verifier("gate_challenge_" + std::to_string(idx), accumulator->gate_challenges[idx]); + } + + auto comm_view = accumulator->witness_commitments.get_all(); + auto witness_labels = accumulator->commitment_labels.get_witness(); + for (size_t idx = 0; idx < witness_labels.size(); idx++) { + transcript->send_to_verifier(witness_labels[idx], comm_view[idx]); + } + + auto vk_view = accumulator->verification_key->get_all(); + auto vk_labels = accumulator->commitment_labels.get_precomputed(); + for (size_t idx = 0; idx < vk_labels.size(); idx++) { + transcript->send_to_verifier(vk_labels[idx], vk_view[idx]); + } +} + +/** + * @brief Run Sumcheck to establish that ∑_i pow(\vec{β*})f_i(ω) = e*. This results in u = (u_1,...,u_d) sumcheck round + * challenges and all evaluations at u being calculated. + * + */ +template void DeciderProver_::execute_relation_check_rounds() +{ + using Sumcheck = sumcheck::SumcheckProver; + auto instance_size = accumulator->instance_size; + auto sumcheck = Sumcheck(instance_size, transcript); + sumcheck_output = sumcheck.prove(accumulator); +} + +/** + * @brief Execute the ZeroMorph protocol to prove the multilinear evaluations produced by Sumcheck + * @details See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the unrolled protocol. + * + * */ +template void DeciderProver_::execute_zeromorph_rounds() +{ + ZeroMorph::prove(accumulator->prover_polynomials.get_unshifted(), + accumulator->prover_polynomials.get_to_be_shifted(), + sumcheck_output.claimed_evaluations.get_unshifted(), + sumcheck_output.claimed_evaluations.get_shifted(), + sumcheck_output.challenge, + commitment_key, + transcript); +} + +template plonk::proof& DeciderProver_::export_proof() +{ + proof.proof_data = transcript->proof_data; + return proof; +} + +template plonk::proof& DeciderProver_::construct_proof() +{ + // Add ϕ, \vec{β*}, e* to transcript + execute_preamble_round(); + + // Run sumcheck subprotocol. + execute_relation_check_rounds(); + + // Fiat-Shamir: rho, y, x, z + // Execute Zeromorph multilinear PCS + execute_zeromorph_rounds(); + + return export_proof(); +} + +template class DeciderProver_; +template class DeciderProver_; + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp new file mode 100644 index 00000000000..b11af2419a6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp @@ -0,0 +1,63 @@ +#pragma once +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" +#include "barretenberg/flavor/goblin_ultra.hpp" +#include "barretenberg/flavor/ultra.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/sumcheck/instance/prover_instance.hpp" +#include "barretenberg/sumcheck/sumcheck_output.hpp" +#include "barretenberg/transcript/transcript.hpp" + +namespace proof_system::honk { + +template class DeciderProver_ { + using FF = typename Flavor::FF; + using Commitment = typename Flavor::Commitment; + using CommitmentKey = typename Flavor::CommitmentKey; + using ProvingKey = typename Flavor::ProvingKey; + using Polynomial = typename Flavor::Polynomial; + using ProverPolynomials = typename Flavor::ProverPolynomials; + using CommitmentLabels = typename Flavor::CommitmentLabels; + using Curve = typename Flavor::Curve; + using Instance = ProverInstance_; + using Transcript = typename Flavor::Transcript; + using RelationSeparator = typename Flavor::RelationSeparator; + + public: + explicit DeciderProver_(const std::shared_ptr&, + const std::shared_ptr&, + const std::shared_ptr& transcript = std::make_shared()); + + BBERG_PROFILE void execute_preamble_round(); + BBERG_PROFILE void execute_relation_check_rounds(); + BBERG_PROFILE void execute_zeromorph_rounds(); + + plonk::proof& export_proof(); + plonk::proof& construct_proof(); + + std::shared_ptr accumulator; + + std::shared_ptr transcript; + + proof_system::RelationParameters relation_parameters; + + CommitmentLabels commitment_labels; + + Polynomial quotient_W; + + sumcheck::SumcheckOutput sumcheck_output; + + std::shared_ptr commitment_key; + + using ZeroMorph = pcs::zeromorph::ZeroMorphProver_; + + private: + plonk::proof proof; +}; + +extern template class DeciderProver_; +extern template class DeciderProver_; + +using DeciderProver = DeciderProver_; + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp new file mode 100644 index 00000000000..8b533659270 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -0,0 +1,113 @@ +#include "decider_verifier.hpp" +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" +#include "barretenberg/numeric/bitop/get_msb.hpp" +#include "barretenberg/sumcheck/instance/verifier_instance.hpp" +#include "barretenberg/transcript/transcript.hpp" + +using namespace barretenberg; +using namespace proof_system::honk::sumcheck; + +namespace proof_system::honk { + +template +DeciderVerifier_::DeciderVerifier_(const std::shared_ptr& transcript, + const std::shared_ptr& verifier_key) + : key(verifier_key) + , transcript(transcript) +{} +template +DeciderVerifier_::DeciderVerifier_() + : pcs_verification_key(std::make_unique(0, barretenberg::srs::get_crs_factory())) + , transcript(std::make_shared()) +{} + +/** + * @brief This function verifies an Ultra Honk proof for a given Flavor, produced for a relaxed instance (ϕ, \vec{β*}, + * e*). + * + */ +template bool DeciderVerifier_::verify_proof(const plonk::proof& proof) +{ + using FF = typename Flavor::FF; + using Commitment = typename Flavor::Commitment; + using Curve = typename Flavor::Curve; + using ZeroMorph = pcs::zeromorph::ZeroMorphVerifier_; + using Instance = VerifierInstance_; + using VerifierCommitments = typename Flavor::VerifierCommitments; + + static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; + transcript = std::make_shared(proof.proof_data); + auto inst = std::make_unique(); + + inst->instance_size = transcript->template receive_from_prover("instance_size"); + inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); + inst->public_input_size = transcript->template receive_from_prover("public_input_size"); + + for (size_t i = 0; i < inst->public_input_size; ++i) { + auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); + inst->public_inputs.emplace_back(public_input_i); + } + + auto eta = transcript->template receive_from_prover("eta"); + auto beta = transcript->template receive_from_prover("beta"); + auto gamma = transcript->template receive_from_prover("gamma"); + auto public_input_delta = transcript->template receive_from_prover("public_input_delta"); + auto lookup_grand_product_delta = transcript->template receive_from_prover("lookup_grand_product_delta"); + inst->relation_parameters = + RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + + inst->alphas[idx] = transcript->template receive_from_prover("alpha" + std::to_string(idx)); + } + + inst->target_sum = transcript->template receive_from_prover("target_sum"); + + inst->gate_challenges = std::vector(inst->log_instance_size); + for (size_t idx = 0; idx < inst->log_instance_size; idx++) { + inst->gate_challenges[idx] = + transcript->template receive_from_prover("gate_challenge_" + std::to_string(idx)); + } + auto comm_view = inst->witness_commitments.get_all(); + auto witness_labels = inst->commitment_labels.get_witness(); + for (size_t idx = 0; idx < witness_labels.size(); idx++) { + comm_view[idx] = transcript->template receive_from_prover(witness_labels[idx]); + } + + inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); + auto vk_view = inst->verification_key->get_all(); + auto vk_labels = inst->commitment_labels.get_precomputed(); + for (size_t idx = 0; idx < vk_labels.size(); idx++) { + vk_view[idx] = transcript->template receive_from_prover(vk_labels[idx]); + } + + VerifierCommitments commitments{ inst->verification_key, inst->witness_commitments }; + + auto sumcheck = SumcheckVerifier(inst->log_instance_size, transcript, inst->target_sum); + + auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = + sumcheck.verify(inst->relation_parameters, inst->alphas, inst->gate_challenges); + + // If Sumcheck did not verify, return false + if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { + return false; + } + + // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the + // unrolled protocol. + auto pairing_points = ZeroMorph::verify(commitments.get_unshifted(), + commitments.get_to_be_shifted(), + claimed_evaluations.get_unshifted(), + claimed_evaluations.get_shifted(), + multivariate_challenge, + transcript); + + auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + + return sumcheck_verified.value() && verified; +} + +template class DeciderVerifier_; +template class DeciderVerifier_; + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp new file mode 100644 index 00000000000..eb2e15a5ce0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp @@ -0,0 +1,34 @@ +#pragma once +#include "barretenberg/flavor/goblin_ultra.hpp" +#include "barretenberg/flavor/ultra.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/srs/global_crs.hpp" +#include "barretenberg/sumcheck/sumcheck.hpp" + +namespace proof_system::honk { +template class DeciderVerifier_ { + using FF = typename Flavor::FF; + using Commitment = typename Flavor::Commitment; + using VerificationKey = typename Flavor::VerificationKey; + using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; + using Transcript = typename Flavor::Transcript; + + public: + explicit DeciderVerifier_(); + explicit DeciderVerifier_(const std::shared_ptr& transcript, + const std::shared_ptr& verifier_key = nullptr); + + bool verify_proof(const plonk::proof& proof); + + std::shared_ptr key; + std::map commitments; + std::shared_ptr pcs_verification_key; + std::shared_ptr transcript; +}; + +extern template class DeciderVerifier_; +extern template class DeciderVerifier_; + +using DeciderVerifier = DeciderVerifier_; + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index 80c33a1aab4..e735ff8cab9 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -56,9 +56,9 @@ void ProtoGalaxyProver_::finalise_and_send_instance(std::shared 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"); - + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + instance->alphas[idx] = transcript->get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); + } auto vk_view = instance->verification_key->get_all(); auto labels = instance->commitment_labels.get_precomputed(); for (size_t idx = 0; idx < labels.size(); idx++) { @@ -88,13 +88,14 @@ void ProtoGalaxyProver_::send_accumulator(std::shared_ptrsend_to_verifier(domain_separator + "_lookup_grand_product_delta", instance->relation_parameters.lookup_grand_product_delta); - transcript->send_to_verifier(domain_separator + "_alpha", instance->alpha); + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + transcript->send_to_verifier(domain_separator + "_alpha_" + std::to_string(idx), instance->alphas[idx]); + } - 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 + "_target_sum", instance->target_sum); + for (size_t idx = 0; idx < instance->gate_challenges.size(); idx++) { transcript->send_to_verifier(domain_separator + "_gate_challenge_" + std::to_string(idx), - folding_parameters.gate_challenges[idx]); + instance->gate_challenges[idx]); } auto comm_view = instance->witness_commitments.get_all(); @@ -119,8 +120,20 @@ template void ProtoGalaxyProver_::prepa if (instance->is_accumulator) { send_accumulator(instance, domain_separator); } else { + // This is the first round of folding and we need to generate some gate challenges. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/740): implement option 2 to make this more + // efficient by avoiding the computation of the perturbator finalise_and_send_instance(instance, domain_separator); + instance->target_sum = 0; + auto beta = transcript->get_challenge(domain_separator + "_initial_gate_challenge"); + std::vector gate_challenges(instance->log_instance_size); + gate_challenges[0] = beta; + for (size_t i = 1; i < instance->log_instance_size; i++) { + gate_challenges[i] = gate_challenges[i - 1].sqr(); + } + instance->gate_challenges = gate_challenges; } + idx++; for (auto it = instances.begin() + 1; it != instances.end(); it++, idx++) { @@ -130,53 +143,11 @@ template void ProtoGalaxyProver_::prepa } } -// TODO(#https://github.com/AztecProtocol/barretenberg/issues/689): finalise implementation this function -template -FoldingResult ProtoGalaxyProver_::fold_instances() -{ - prepare_for_folding(); - - // TODO(#https://github.com/AztecProtocol/barretenberg/issues/740): Handle the case where we are folding for the - // first time and accumulator is 0 - FF delta = transcript->get_challenge("delta"); - auto accumulator = get_accumulator(); - auto deltas = compute_round_challenge_pows(accumulator->log_instance_size, delta); - - auto perturbator = compute_perturbator(accumulator, deltas); - 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); - - auto compressed_perturbator = perturbator.evaluate(perturbator_challenge); - 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"); - - FoldingResult res; - res.accumulator = - compute_next_accumulator(instances, combiner_quotient, combiner_challenge, compressed_perturbator); - res.folding_data = transcript->proof_data; - - return res; -} template std::shared_ptr ProtoGalaxyProver_::compute_next_accumulator( ProverInstances& instances, Univariate& combiner_quotient, - const FF& challenge, + FF& challenge, const FF& compressed_perturbator) { auto combiner_quotient_at_challenge = combiner_quotient.evaluate(challenge); @@ -188,15 +159,20 @@ std::shared_ptr ProtoGalaxyProver_ lagranges{ FF(1) - challenge, challenge }; auto next_accumulator = std::make_shared(); + next_accumulator->is_accumulator = true; + next_accumulator->instance_size = instances[0]->instance_size; + next_accumulator->log_instance_size = instances[0]->log_instance_size; // Compute the next target sum and send the next folding parameters to the verifier - auto next_target_sum = + FF 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]); } + next_accumulator->target_sum = next_target_sum; + next_accumulator->gate_challenges = instances.next_gate_challenges; // Initialize prover polynomials ProverPolynomials acc_prover_polynomials; @@ -209,8 +185,8 @@ std::shared_ptr ProtoGalaxyProver_prover_polynomials.get_all())) { - for (auto [acc_field, inst_field] : zip_view(acc_poly, inst_poly)) { - acc_field += inst_field * lagranges[inst_idx]; + for (auto [acc_el, inst_el] : zip_view(acc_poly, inst_poly)) { + acc_el += inst_el * lagranges[inst_idx]; } } } @@ -246,10 +222,13 @@ std::shared_ptr ProtoGalaxyProver_alpha = instances.alpha.evaluate(challenge); - transcript->send_to_verifier("next_alpha", next_accumulator->alpha); + // Evaluate the combined batching α_i univariate at challenge to obtain next α_i and send it to the + // verifier, where i ∈ {0,...,NUM_SUBRELATIONS - 1} + auto& folded_alphas = next_accumulator->alphas; + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + folded_alphas[idx] = instances.alphas[idx].evaluate(challenge); + transcript->send_to_verifier("next_alpha_" + std::to_string(idx), folded_alphas[idx]); + } // Evaluate each relation parameter univariate at challenge to obtain the folded relation parameters and send to // the verifier @@ -287,10 +266,51 @@ std::shared_ptr ProtoGalaxyProver_verification_key = acc_vk; - return next_accumulator; } +// TODO(#https://github.com/AztecProtocol/barretenberg/issues/689): finalise implementation this function +template +FoldingResult ProtoGalaxyProver_::fold_instances() +{ + prepare_for_folding(); + + // TODO(#https://github.com/AztecProtocol/barretenberg/issues/740): Handle the case where we are folding for the + // first time and accumulator is 0 + FF delta = transcript->get_challenge("delta"); + + auto accumulator = get_accumulator(); + auto deltas = compute_round_challenge_pows(accumulator->log_instance_size, delta); + + auto perturbator = compute_perturbator(accumulator, deltas); + for (size_t idx = 0; idx <= accumulator->log_instance_size; idx++) { + transcript->send_to_verifier("perturbator_" + std::to_string(idx), perturbator[idx]); + } + auto perturbator_challenge = transcript->get_challenge("perturbator_challenge"); + instances.next_gate_challenges = + update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); + combine_relation_parameters(instances); + combine_alpha(instances); + auto pow_polynomial = PowPolynomial(instances.next_gate_challenges); + auto combiner = compute_combiner(instances, pow_polynomial); + + auto compressed_perturbator = perturbator.evaluate(perturbator_challenge); + 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)); + } + FF combiner_challenge = transcript->get_challenge("combiner_quotient_challenge"); + + FoldingResult res; + auto next_accumulator = + compute_next_accumulator(instances, combiner_quotient, combiner_challenge, compressed_perturbator); + res.folding_data = transcript->proof_data; + res.accumulator = next_accumulator; + + return res; +} + 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 83aa42ae4ff..0270afc5b24 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -23,7 +23,8 @@ template class ProtoGalaxyProver_ { using RowEvaluations = typename Flavor::AllValues; using ProverPolynomials = typename Flavor::ProverPolynomials; using Relations = typename Flavor::Relations; - using AlphaType = typename ProverInstances::AlphaType; + using RelationSeparator = typename Flavor::RelationSeparator; + using CombinedRelationSeparator = typename ProverInstances::RelationSeparator; using VerificationKey = typename Flavor::VerificationKey; using CommitmentKey = typename Flavor::CommitmentKey; using WitnessCommitments = typename Flavor::WitnessCommitments; @@ -38,13 +39,14 @@ template class ProtoGalaxyProver_ { using ExtendedUnivariateWithRandomization = Univariate; - using ExtendedUnivariates = typename Flavor::template ProverUnivariates; using TupleOfTuplesOfUnivariates = typename Flavor::template ProtogalaxyTupleOfTuplesOfUnivariates; using RelationEvaluations = typename Flavor::TupleOfArraysOfValues; + static constexpr size_t NUM_SUBRELATIONS = ProverInstances::NUM_SUBRELATIONS; + ProverInstances instances; std::shared_ptr transcript = std::make_shared(); @@ -90,23 +92,6 @@ template class ProtoGalaxyProver_ { * 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. - */ - static std::vector compute_pow_polynomial_at_values(const std::vector& betas, const size_t instance_size) - { - std::vector pow_betas(instance_size); - for (size_t i = 0; i < instance_size; i++) { - auto res = FF(1); - for (size_t j = i, beta_idx = 0; j > 0; j >>= 1, beta_idx++) { - if ((j & 1) == 1) { - res *= betas[beta_idx]; - } - } - pow_betas[i] = res; - } - return pow_betas; - } /** * @brief For a new round challenge δ at each iteration of the ProtoGalaxy protocol, compute the vector @@ -128,10 +113,9 @@ template class ProtoGalaxyProver_ { { 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]; + for (size_t idx = 0; idx < log_instance_size; idx++) { + next_gate_challenges[idx] = gate_challenges[idx] + perturbator_challenge * round_challenges[idx]; } return next_gate_challenges; } @@ -148,7 +132,7 @@ template class ProtoGalaxyProver_ { * each subrelation is independently valid in Honk - from the Plonk paper, DO NOT confuse with α in ProtoGalaxy), */ static std::vector compute_full_honk_evaluations(const ProverPolynomials& instance_polynomials, - const FF& alpha, + const RelationSeparator& alpha, const RelationParameters& relation_parameters) { auto instance_size = instance_polynomials.get_polynomial_size(); @@ -164,9 +148,10 @@ template class ProtoGalaxyProver_ { Utils::template accumulate_relation_evaluations<>( row_evaluations, relation_evaluations, relation_parameters, FF(1)); - auto running_challenge = FF(1); auto output = FF(0); + auto running_challenge = FF(1); Utils::scale_and_batch_elements(relation_evaluations, alpha, running_challenge, output); + full_honk_evaluations[row] = output; } return full_honk_evaluations; @@ -237,8 +222,8 @@ template class ProtoGalaxyProver_ { const std::vector& deltas) { auto full_honk_evaluations = compute_full_honk_evaluations( - accumulator->prover_polynomials, accumulator->alpha, accumulator->relation_parameters); - const auto betas = accumulator->folding_parameters.gate_challenges; + accumulator->prover_polynomials, accumulator->alphas, accumulator->relation_parameters); + const auto betas = accumulator->gate_challenges; assert(betas.size() == deltas.size()); auto coeffs = construct_perturbator_coefficients(betas, deltas, full_honk_evaluations); return Polynomial(coeffs); @@ -285,11 +270,10 @@ template class ProtoGalaxyProver_ { * @brief Compute the combiner polynomial $G$ in the Protogalaxy paper. * */ - ExtendedUnivariateWithRandomization compute_combiner(const ProverInstances& instances, - const std::vector& pow_betas_star) + ExtendedUnivariateWithRandomization compute_combiner(const ProverInstances& instances, PowPolynomial& pow_betas) { size_t common_instance_size = instances[0]->instance_size; - + pow_betas.compute_values(); // 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 // on a specified minimum number of iterations per thread. This eventually leads to the use of a single thread. @@ -300,7 +284,6 @@ template class ProtoGalaxyProver_ { 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_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) { @@ -318,9 +301,10 @@ template class ProtoGalaxyProver_ { size_t end = (thread_idx + 1) * iterations_per_thread; for (size_t idx = start; idx < end; idx++) { + // No need to initialise extended_univariates to 0, it's assigned to extend_univariates(extended_univariates[thread_idx], instances, idx); - FF pow_challenge = pow_betas_star[idx]; + FF pow_challenge = pow_betas[idx]; // Accumulate the i-th row's univariate contribution. Note that the relation parameters passed to this // function have already been folded @@ -337,19 +321,21 @@ template class ProtoGalaxyProver_ { Utils::add_nested_tuples(univariate_accumulators, accumulators); } // Batch the univariate contributions from each sub-relation to obtain the round univariate - return batch_over_relations(univariate_accumulators, instances.alpha); + return batch_over_relations(univariate_accumulators, instances.alphas); } - static ExtendedUnivariateWithRandomization batch_over_relations(TupleOfTuplesOfUnivariates univariate_accumulators, - AlphaType alpha) + static ExtendedUnivariateWithRandomization batch_over_relations(TupleOfTuplesOfUnivariates& univariate_accumulators, + const CombinedRelationSeparator& alpha) { // First relation does not get multiplied by a batching challenge auto result = std::get<0>(std::get<0>(univariate_accumulators)) .template extend_to(); + size_t idx = 0; auto scale_and_sum = [&](auto& element) { auto extended = element.template extend_to(); - extended *= alpha; + extended *= alpha[idx]; result += extended; + idx++; }; Utils::template apply_to_tuple_of_tuples<0, 1>(univariate_accumulators, scale_and_sum); @@ -366,7 +352,7 @@ template class ProtoGalaxyProver_ { * */ static Univariate compute_combiner_quotient( - FF compressed_perturbator, ExtendedUnivariateWithRandomization combiner) + const FF compressed_perturbator, ExtendedUnivariateWithRandomization combiner) { std::array combiner_quotient_evals = {}; @@ -395,38 +381,38 @@ template class ProtoGalaxyProver_ { */ static void combine_relation_parameters(ProverInstances& instances) { - // array of parameters to be computed size_t param_idx = 0; - for (auto& folded_parameter : instances.relation_parameters.to_fold) { + auto to_fold = instances.relation_parameters.get_to_fold(); + for (auto& folded_parameter : 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].get(); + tmp.value_at(instance_idx) = instance->relation_parameters.get_to_fold()[param_idx]; instance_idx++; } - folded_parameter.get() = tmp.template extend_to(); + folded_parameter = tmp.template extend_to(); param_idx++; } } /** - * @brief Combine the relation batching parameter (named alpha) from each instance into a univariate, used in the + * @brief Combine the relation batching parameters (alphas) 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 combine_alpha(ProverInstances& instances) { - Univariate accumulated_alpha; - size_t instance_idx = 0; - for (auto& instance : instances) { - accumulated_alpha.value_at(instance_idx) = instance->alpha; - instance_idx++; + size_t alpha_idx = 0; + for (auto& alpha : instances.alphas) { + Univariate tmp; + size_t instance_idx = 0; + for (auto& instance : instances) { + tmp.value_at(instance_idx) = instance->alphas[alpha_idx]; + instance_idx++; + } + alpha = tmp.template extend_to(); + alpha_idx++; } - instances.alpha = accumulated_alpha.template extend_to(); } /** @@ -444,7 +430,7 @@ template class ProtoGalaxyProver_ { std::shared_ptr compute_next_accumulator( ProverInstances& instances, Univariate& combiner_quotient, - const FF& challenge, + FF& challenge, const FF& compressed_perturbator); }; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index 7107d991228..871d4ad23b8 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -25,14 +25,17 @@ void ProtoGalaxyVerifier_::receive_accumulator(const std::sha 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"); + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + inst->alphas[idx] = + transcript->template receive_from_prover(domain_separator + "_alpha_" + std::to_string(idx)); + } + + inst->target_sum = transcript->template receive_from_prover(domain_separator + "_target_sum"); - inst->folding_parameters.gate_challenges = std::vector(inst->log_instance_size); + inst->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] = + inst->gate_challenges[idx] = transcript->template receive_from_prover(domain_separator + "_gate_challenge_" + std::to_string(idx)); } auto comm_view = inst->witness_commitments.get_all(); @@ -91,7 +94,9 @@ void ProtoGalaxyVerifier_::receive_and_finalise_instance(cons inst->relation_parameters = RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - inst->alpha = transcript->get_challenge(domain_separator + "_alpha"); + for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + inst->alphas[idx] = transcript->get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); + } inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); auto vk_view = inst->verification_key->get_all(); @@ -114,7 +119,18 @@ void ProtoGalaxyVerifier_::prepare_for_folding(const std::vec if (inst->is_accumulator) { receive_accumulator(inst, domain_separator); } else { + // This is the first round of folding and we need to generate some gate challenges. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/740): implement option 2 to make this more + // efficient by avoiding the computation of the perturbator receive_and_finalise_instance(inst, domain_separator); + inst->target_sum = 0; + auto beta = transcript->get_challenge(domain_separator + "_initial_gate_challenge"); + std::vector gate_challenges(inst->log_instance_size); + gate_challenges[0] = beta; + for (size_t i = 1; i < inst->log_instance_size; i++) { + gate_challenges[i] = gate_challenges[i - 1].sqr(); + } + inst->gate_challenges = gate_challenges; } index++; @@ -138,7 +154,11 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(std::vectorlog_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); + + if (perturbator_coeffs[0] != accumulator->target_sum) { + return false; + } + auto perturbator = Polynomial(perturbator_coeffs); FF perturbator_challenge = transcript->get_challenge("perturbator_challenge"); auto perturbator_at_challenge = perturbator.evaluate(perturbator_challenge); @@ -162,8 +182,7 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(std::vectortemplate 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); + auto expected_betas_star = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); for (size_t idx = 0; idx < accumulator->log_instance_size; idx++) { auto beta_star = transcript->template receive_from_prover("next_gate_challenge_" + std::to_string(idx)); verified = verified & (expected_betas_star[idx] == beta_star); @@ -198,11 +217,19 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(std::vectoralphas[alpha_idx] * lagranges[instance_idx]; + instance_idx++; + } + auto next_alpha = transcript->template receive_from_prover("next_alpha_" + std::to_string(alpha_idx)); + verified = verified & (alpha == next_alpha); + } 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]; @@ -212,12 +239,8 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(std::vectorrelation_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); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp index c723532a5b9..b1ac218c32f 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp @@ -17,6 +17,9 @@ template class ProtoGalaxyVerifier_ { using VerificationKey = typename Flavor::VerificationKey; using WitnessCommitments = typename Flavor::WitnessCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; + using RelationSeparator = typename Flavor::RelationSeparator; + + static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; VerifierInstances instances; @@ -47,10 +50,9 @@ template class ProtoGalaxyVerifier_ { { 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]; + for (size_t idx = 0; idx < log_instance_size; idx++) { + next_gate_challenges[idx] = gate_challenges[idx] + perturbator_challenge * round_challenges[idx]; } return next_gate_challenges; } diff --git a/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp b/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp index 096f5b79603..2057f37c115 100644 --- a/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/common/ref_vector.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include @@ -38,17 +39,15 @@ template struct RelationParameters { { T(0), T(0), T(0), T(0), T(0) } } }; static constexpr int NUM_TO_FOLD = 5; - std::array, NUM_TO_FOLD> to_fold = { - eta, beta, gamma, public_input_delta, lookup_grand_product_delta - }; + RefVector get_to_fold() { return { eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; } static RelationParameters get_random() { RelationParameters result; result.eta = T::random_element(); + result.beta = T::random_element(); result.beta_sqr = result.beta * result.beta; result.beta_cube = result.beta_sqr * result.beta; - result.beta = T::random_element(); result.gamma = T::random_element(); result.public_input_delta = T::random_element(); result.lookup_grand_product_delta = T::random_element(); diff --git a/barretenberg/cpp/src/barretenberg/relations/utils.hpp b/barretenberg/cpp/src/barretenberg/relations/utils.hpp index a87f71855f8..b3a0750617e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/utils.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/utils.hpp @@ -1,4 +1,7 @@ #pragma once +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/flavor/goblin_ultra.hpp" +#include "barretenberg/flavor/ultra.hpp" #include "barretenberg/polynomials/pow.hpp" #include "barretenberg/relations/relation_parameters.hpp" @@ -10,8 +13,10 @@ template class RelationUtils { using Relations = typename Flavor::Relations; using PolynomialEvaluations = typename Flavor::AllValues; using RelationEvaluations = typename Flavor::TupleOfArraysOfValues; + using RelationSeparator = typename Flavor::RelationSeparator; static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS; + static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; /** * Utility methods for tuple of tuples of Univariates @@ -58,6 +63,27 @@ template class RelationUtils { apply_to_tuple_of_tuples(tuple, set_to_zero); } + /** + * @brief Scale Univaraites, each representing a subrelation, by different challenges + * + * @param tuple Tuple of tuples of Univariates + * @param challenge Array of NUM_SUBRELATIONS - 1 challenges (because the first subrelation doesn't need to be + * scaled) + * @param current_scalar power of the challenge + */ + static void scale_univariates(auto& tuple, const RelationSeparator& challenges, FF& current_scalar) + requires proof_system::IsFoldingFlavor + { + size_t idx = 0; + std::array tmp{ current_scalar }; + std::copy(challenges.begin(), challenges.end(), tmp.begin() + 1); + auto scale_by_challenges = [&](auto& element) { + element *= tmp[idx]; + idx++; + }; + apply_to_tuple_of_tuples(tuple, scale_by_challenges); + } + /** * @brief Scale Univaraites by consecutive powers of the provided challenge * @@ -65,7 +91,8 @@ template class RelationUtils { * @param challenge * @param current_scalar power of the challenge */ - static void scale_univariates(auto& tuple, const FF& challenge, FF& current_scalar) + static void scale_univariates(auto& tuple, const RelationSeparator& challenge, FF& current_scalar) + requires(!proof_system::IsFoldingFlavor) { auto scale_by_consecutive_powers_of_challenge = [&](auto& element) { element *= current_scalar; @@ -97,8 +124,8 @@ template class RelationUtils { /** * @brief Componentwise addition of nested tuples (tuples of tuples) * @details Used for summing tuples of tuples of Univariates. Needed for Sumcheck multithreading. Each thread - * accumulates relation contributions across a portion of the hypecube and then the results are accumulated into a - * single nested tuple. + * accumulates relation contributions across a portion of the hypecube and then the results are accumulated into + * a single nested tuple. * * @tparam Tuple * @tparam Index Index into outer tuple @@ -117,28 +144,27 @@ template class RelationUtils { /** * @brief Calculate the contribution of each relation to the expected value of the full Honk relation. * - * @details For each relation, use the purported values (supplied by the prover) of the multivariates to calculate - * a contribution to the purported value of the full Honk relation. These are stored in `evaluations`. Adding these - * together, with appropriate scaling factors, produces the expected value of the full Honk relation. This value is - * checked against the final value of the target total sum (called sigma_0 in the thesis). + * @details For each relation, use the purported values (supplied by the prover) of the multivariates to + * calculate a contribution to the purported value of the full Honk relation. These are stored in `evaluations`. + * Adding these together, with appropriate scaling factors, produces the expected value of the full Honk + * relation. This value is checked against the final value of the target total sum (called sigma_0 in the + * thesis). */ template // TODO(#224)(Cody): Input should be an array? inline static void accumulate_relation_evaluations(PolynomialEvaluations evaluations, RelationEvaluations& relation_evaluations, const Parameters& relation_parameters, - const FF& partial_evaluation_constant) + const FF& partial_evaluation_result) { using Relation = std::tuple_element_t; - Relation::accumulate(std::get(relation_evaluations), - evaluations, - relation_parameters, - partial_evaluation_constant); + Relation::accumulate( + std::get(relation_evaluations), evaluations, relation_parameters, partial_evaluation_result); // Repeat for the next relation. if constexpr (relation_idx + 1 < NUM_RELATIONS) { accumulate_relation_evaluations( - evaluations, relation_evaluations, relation_parameters, partial_evaluation_constant); + evaluations, relation_evaluations, relation_parameters, partial_evaluation_result); } } @@ -157,11 +183,36 @@ template class RelationUtils { apply_to_tuple_of_arrays(set_to_zero, tuple); }; + /** + * @brief Scale elements, which in sumcheck represent evaluations of subrelations, by different challenges then sum + * @param challenges Array of NUM_SUBRELATIONS - 1 challenges (because the first subrelation does not need to be + * scaled) + * @param result Batched result + */ + static void scale_and_batch_elements(auto& tuple, + const RelationSeparator& challenges, + FF current_scalar, + FF& result) + requires proof_system::IsFoldingFlavor + { + size_t idx = 0; + std::array tmp{ current_scalar }; + std::copy(challenges.begin(), challenges.end(), tmp.begin() + 1); + auto scale_by_challenges_and_accumulate = [&](auto& element) { + for (auto& entry : element) { + result += entry * tmp[idx]; + idx++; + } + }; + apply_to_tuple_of_arrays(scale_by_challenges_and_accumulate, tuple); + } + /** * @brief Scale elements by consecutive powers of the challenge then sum * @param result Batched result */ - static void scale_and_batch_elements(auto& tuple, const FF& challenge, FF current_scalar, FF& result) + static void scale_and_batch_elements(auto& tuple, const RelationSeparator& challenge, FF current_scalar, FF& result) + requires(!proof_system::IsFoldingFlavor) { auto scale_by_challenge_and_accumulate = [&](auto& element) { for (auto& entry : element) { @@ -178,7 +229,7 @@ template class RelationUtils { * @tparam Operation Any operation valid on elements of the inner arrays (FFs) * @param tuple Tuple of arrays (of FFs) */ - template + template static void apply_to_tuple_of_arrays(Operation&& operation, std::tuple& tuple) { auto& element = std::get(tuple); @@ -186,7 +237,7 @@ template class RelationUtils { std::invoke(std::forward(operation), element); if constexpr (idx + 1 < sizeof...(Ts)) { - apply_to_tuple_of_arrays(operation, tuple); + apply_to_tuple_of_arrays(operation, tuple); } } }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index ef0c98e5aea..5263c6b90c0 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -187,7 +187,7 @@ template class GoblinRecursiveVerifierTest : public testi OuterBuilder outer_circuit; RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); - info("Recursive Verifier: num gates = ", outer_circuit.num_gates); + info("Recursive Verifier Goblin: num gates = ", outer_circuit.num_gates); // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp index 8088fbe7792..fb9719d6cde 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp @@ -1,6 +1,5 @@ #include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/proof_system/library/grand_product_delta.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -103,11 +102,19 @@ std::array UltraRecursiveVerifier_::ve // Execute Sumcheck Verifier and extract multivariate opening point u = (u_0, ..., u_{d-1}) and purported // multivariate evaluations at u - auto sumcheck = Sumcheck(key->circuit_size); - auto alpha = transcript->get_challenge("alpha"); - auto [multivariate_challenge, claimed_evaluations, verified] = - sumcheck.verify(relation_parameters, alpha, transcript); + const size_t log_circuit_size = numeric::get_msb(static_cast(circuit_size.get_value())); + auto sumcheck = Sumcheck(log_circuit_size, transcript); + RelationSeparator alpha; + for (size_t idx = 0; idx < alpha.size(); idx++) { + alpha[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + auto gate_challenges = std::vector(log_circuit_size); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = + sumcheck.verify(relation_parameters, alpha, gate_challenges); // Execute ZeroMorph multilinear PCS evaluation verifier auto pairing_points = ZeroMorph::verify(commitments.get_unshifted(), commitments.get_to_be_shifted(), diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp index 8fb6ed47c7f..6077fe241ef 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp @@ -1,7 +1,5 @@ #pragma once -#include "barretenberg/flavor/goblin_ultra.hpp" #include "barretenberg/flavor/goblin_ultra_recursive.hpp" -#include "barretenberg/flavor/ultra.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" @@ -17,6 +15,7 @@ template class UltraRecursiveVerifier_ { using NativeVerificationKey = typename Flavor::NativeVerificationKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using Builder = typename Flavor::CircuitBuilder; + using RelationSeparator = typename Flavor::RelationSeparator; using PairingPoints = std::array; explicit UltraRecursiveVerifier_(Builder* builder, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index 3b045a35a73..49b8882d759 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -170,6 +170,7 @@ template class RecursiveVerifierTest : public testing::Te OuterBuilder outer_circuit; RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); + info("Recursive Verifier Ultra: num gates = ", outer_circuit.num_gates); // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err(); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp index 0fcc8d27614..405f49d8463 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp @@ -8,9 +8,9 @@ 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_; + static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; using Instance = ProverInstance_; using ArrayType = std::array, NUM_>; @@ -18,10 +18,10 @@ template struct ProverInstances_ { static constexpr size_t EXTENDED_LENGTH = (Flavor::MAX_TOTAL_RELATION_LENGTH - 1) * (NUM - 1) + 1; static constexpr size_t BATCHED_EXTENDED_LENGTH = (Flavor::MAX_TOTAL_RELATION_LENGTH - 1 + NUM - 1) * (NUM - 1) + 1; using RelationParameters = proof_system::RelationParameters>; - using AlphaType = Univariate; + using RelationSeparator = std::array, NUM_SUBRELATIONS - 1>; ArrayType _data; RelationParameters relation_parameters; - AlphaType alpha; + RelationSeparator alphas; std::vector next_gate_challenges; std::shared_ptr const& operator[](size_t idx) const { return _data[idx]; } @@ -65,7 +65,7 @@ template struct ProverInstances_ { 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)) { - result.evaluations[instance_idx] = (poly_ptr)[row_idx]; + result.evaluations[instance_idx] = poly_ptr[row_idx]; } instance_idx++; } diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index e9c430b77c1..34757cdc54e 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -415,11 +415,9 @@ template void ProverInstance_::compute_grand_product_poly { auto public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, proving_key->circuit_size, pub_inputs_offset); - relation_parameters.beta = beta; relation_parameters.gamma = gamma; relation_parameters.public_input_delta = public_input_delta; - auto lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, proving_key->circuit_size); relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 5c688ffecd5..d7f14f6c9f1 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -4,7 +4,6 @@ #include "barretenberg/flavor/ultra.hpp" #include "barretenberg/proof_system/composer/composer_lib.hpp" #include "barretenberg/relations/relation_parameters.hpp" -#include "barretenberg/srs/factories/file_crs_factory.hpp" namespace proof_system::honk { /** @@ -23,11 +22,11 @@ template class ProverInstance_ { using VerificationKey = typename Flavor::VerificationKey; using CommitmentKey = typename Flavor::CommitmentKey; using FF = typename Flavor::FF; - using FoldingParameters = typename Flavor::FoldingParameters; using ProverPolynomials = typename Flavor::ProverPolynomials; using Polynomial = typename Flavor::Polynomial; using WitnessCommitments = typename Flavor::WitnessCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; + using RelationSeparator = typename Flavor::RelationSeparator; public: std::shared_ptr proving_key; @@ -46,12 +45,16 @@ template class ProverInstance_ { // non-zero for Instances constructed from circuits, this concept doesn't exist for accumulated // instances size_t pub_inputs_offset = 0; - FF alpha; + RelationSeparator alphas; proof_system::RelationParameters relation_parameters; std::vector recursive_proof_public_input_indices; - // non-empty for the accumulated instances - FoldingParameters folding_parameters; + bool is_accumulator = false; + + // The folding parameters (\vec{β}, e) which are set for accumulators (i.e. relaxed instances). + std::vector gate_challenges; + FF target_sum; + size_t instance_size; size_t log_instance_size; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp index 06fdc47f264..23faaf87875 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp @@ -7,9 +7,9 @@ template class VerifierInstance_ { public: 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; + using RelationSeparator = typename Flavor::RelationSeparator; std::shared_ptr verification_key; std::vector public_inputs; @@ -18,9 +18,13 @@ template class VerifierInstance_ { size_t instance_size; size_t log_instance_size; RelationParameters relation_parameters; - FF alpha; + RelationSeparator alphas; bool is_accumulator = false; - FoldingParameters folding_parameters; + + // The folding parameters (\vec{β}, e) which are set for accumulators (i.e. relaxed instances). + std::vector gate_challenges; + FF target_sum; + WitnessCommitments witness_commitments; CommitmentLabels commitment_labels; }; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index e2a0a703cf6..9971f0447ea 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -16,11 +16,12 @@ template class SumcheckProver { using ClaimedEvaluations = typename Flavor::AllValues; using Transcript = typename Flavor::Transcript; using Instance = ProverInstance_; - - std::shared_ptr transcript; + using RelationSeparator = typename Flavor::RelationSeparator; const size_t multivariate_n; const size_t multivariate_d; + + std::shared_ptr transcript; SumcheckProverRound round; /** @@ -58,12 +59,23 @@ template class SumcheckProver { // prover instantiates sumcheck with circuit size and a prover transcript SumcheckProver(size_t multivariate_n, const std::shared_ptr& transcript) - : transcript(transcript) - , multivariate_n(multivariate_n) + : multivariate_n(multivariate_n) , multivariate_d(numeric::get_msb(multivariate_n)) + , transcript(transcript) , round(multivariate_n) , partially_evaluated_polynomials(multivariate_n){}; + // WORKTODO delete this + /** + * @brief Compute univariate restriction place in transcript, generate challenge, partially evaluate,... repeat + * until final round, then compute multivariate evaluations and place in transcript. + */ + SumcheckOutput prove(std::shared_ptr instance) + { + return prove( + instance->prover_polynomials, instance->relation_parameters, instance->alphas, instance->gate_challenges); + }; + /** * @brief Compute univariate restriction place in transcript, generate challenge, partially evaluate,... repeat * until final round, then compute multivariate evaluations and place in transcript. @@ -72,11 +84,12 @@ template class SumcheckProver { */ SumcheckOutput prove(ProverPolynomials& full_polynomials, const proof_system::RelationParameters& relation_parameters, - FF alpha) // pass by value, not by reference + const RelationSeparator alpha, + const std::vector& gate_challenges) { - FF zeta = transcript->get_challenge("Sumcheck:zeta"); - barretenberg::PowUnivariate pow_univariate(zeta); + barretenberg::PowPolynomial pow_univariate(gate_challenges); + pow_univariate.compute_values(); std::vector multivariate_challenge; multivariate_challenge.reserve(multivariate_d); @@ -89,10 +102,8 @@ template class SumcheckProver { multivariate_challenge.emplace_back(round_challenge); partially_evaluate(full_polynomials, multivariate_n, round_challenge); pow_univariate.partially_evaluate(round_challenge); - round.round_size = - round.round_size >> 1; // TODO(#224)(Cody): Maybe partially_evaluate should do this and release memory? - - // All but final round + round.round_size = round.round_size >> 1; // TODO(#224)(Cody): Maybe partially_evaluate should do this and + // release memory? // All but final round // We operate on partially_evaluated_polynomials in place. for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { // Write the round univariate to the transcript @@ -110,22 +121,13 @@ template class SumcheckProver { ClaimedEvaluations multivariate_evaluations; for (auto [eval, poly] : zip_view(multivariate_evaluations.get_all(), partially_evaluated_polynomials.get_all())) { - eval = (poly)[0]; + eval = poly[0]; } transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations); return { multivariate_challenge, multivariate_evaluations }; }; - /** - * @brief Compute univariate restriction place in transcript, generate challenge, partially evaluate,... repeat - * until final round, then compute multivariate evaluations and place in transcript. - */ - SumcheckOutput prove(std::shared_ptr instance) - { - return prove(instance->prover_polynomials, instance->relation_parameters, instance->alpha); - }; - /** * @brief Evaluate at the round challenge and prepare class for next round. * Illustration of layout in example of first round when d==3 (showing just one Honk polynomial, @@ -176,36 +178,37 @@ template class SumcheckVerifier { using FF = typename Flavor::FF; using ClaimedEvaluations = typename Flavor::AllValues; using Transcript = typename Flavor::Transcript; + using RelationSeparator = typename Flavor::RelationSeparator; static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; const size_t multivariate_d; + std::shared_ptr transcript; SumcheckVerifierRound round; - // verifier instantiates sumcheck with circuit size - explicit SumcheckVerifier(size_t multivariate_n) - : multivariate_d(numeric::get_msb(multivariate_n)) - , round(){}; + // Verifier instantiates sumcheck with circuit size, optionally a different target sum than 0 can be specified. + explicit SumcheckVerifier(size_t multivariate_d, std::shared_ptr transcript, FF target_sum = 0) + : multivariate_d(multivariate_d) + , transcript(transcript) + , round(target_sum){}; /** - * @brief Extract round univariate, check sum, generate challenge, compute next target sum..., repeat until final - * round, then use purported evaluations to generate purported full Honk relation value and check against final - * target sum. + * @brief Extract round univariate, check sum, generate challenge, compute next target sum..., repeat until + * final round, then use purported evaluations to generate purported full Honk relation value and check against + * final target sum. * * @details If verification fails, returns std::nullopt, otherwise returns SumcheckOutput * @param relation_parameters * @param transcript */ SumcheckOutput verify(const proof_system::RelationParameters& relation_parameters, - FF alpha, - const std::shared_ptr& transcript) + RelationSeparator alpha, + const std::vector& gate_challenges) { bool verified(true); - FF zeta = transcript->get_challenge("Sumcheck:zeta"); - - barretenberg::PowUnivariate pow_univariate(zeta); + barretenberg::PowPolynomial pow_univariate(gate_challenges); // All but final round. // target_total_sum is initialized to zero then mutated in place. diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp index ac2f53ccd02..6f83fbdd2e6 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp @@ -17,6 +17,7 @@ using namespace proof_system::honk::sumcheck; using Flavor = proof_system::honk::flavor::Ultra; using FF = typename Flavor::FF; using ProverPolynomials = typename Flavor::ProverPolynomials; +using RelationSeparator = Flavor::RelationSeparator; const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; namespace test_sumcheck_round { @@ -66,8 +67,16 @@ TEST_F(SumcheckTests, PolynomialNormalization) auto transcript = Flavor::Transcript::prover_init_empty(); auto sumcheck = SumcheckProver(multivariate_n, transcript); - FF alpha = transcript->get_challenge("alpha"); - auto output = sumcheck.prove(full_polynomials, {}, alpha); + RelationSeparator alpha; + for (size_t idx = 0; idx < alpha.size(); idx++) { + alpha[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + + std::vector gate_challenges(multivariate_d); + for (size_t idx = 0; idx < multivariate_d; idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto output = sumcheck.prove(full_polynomials, {}, alpha, gate_challenges); FF u_0 = output.challenge[0]; FF u_1 = output.challenge[1]; @@ -130,8 +139,16 @@ TEST_F(SumcheckTests, Prover) auto sumcheck = SumcheckProver(multivariate_n, transcript); - FF alpha = transcript->get_challenge("alpha"); - auto output = sumcheck.prove(full_polynomials, {}, alpha); + RelationSeparator alpha; + for (size_t idx = 0; idx < alpha.size(); idx++) { + alpha[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + + std::vector gate_challenges(multivariate_d); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto output = sumcheck.prove(full_polynomials, {}, alpha, gate_challenges); FF u_0 = output.challenge[0]; FF u_1 = output.challenge[1]; std::vector expected_values; @@ -205,14 +222,30 @@ TEST_F(SumcheckTests, ProverAndVerifierSimple) auto prover_transcript = Flavor::Transcript::prover_init_empty(); auto sumcheck_prover = SumcheckProver(multivariate_n, prover_transcript); - FF prover_alpha = prover_transcript->get_challenge("alpha"); - auto output = sumcheck_prover.prove(full_polynomials, {}, prover_alpha); + RelationSeparator prover_alpha; + for (size_t idx = 0; idx < prover_alpha.size(); idx++) { + prover_alpha[idx] = prover_transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + std::vector prover_gate_challenges(multivariate_d); + for (size_t idx = 0; idx < multivariate_d; idx++) { + prover_gate_challenges[idx] = + prover_transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto output = sumcheck_prover.prove(full_polynomials, {}, prover_alpha, prover_gate_challenges); auto verifier_transcript = Flavor::Transcript::verifier_init_empty(prover_transcript); - auto sumcheck_verifier = SumcheckVerifier(multivariate_n); - FF verifier_alpha = verifier_transcript->get_challenge("alpha"); - auto verifier_output = sumcheck_verifier.verify(relation_parameters, verifier_alpha, verifier_transcript); + auto sumcheck_verifier = SumcheckVerifier(multivariate_d, verifier_transcript); + RelationSeparator verifier_alpha; + for (size_t idx = 0; idx < verifier_alpha.size(); idx++) { + verifier_alpha[idx] = verifier_transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + std::vector verifier_gate_challenges(multivariate_d); + for (size_t idx = 0; idx < multivariate_d; idx++) { + verifier_gate_challenges[idx] = + verifier_transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto verifier_output = sumcheck_verifier.verify(relation_parameters, verifier_alpha, verifier_gate_challenges); auto verified = verifier_output.verified.value(); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp index 2a52cd665f7..0d6bc37092c 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp @@ -55,6 +55,7 @@ template class SumcheckProverRound { using Utils = barretenberg::RelationUtils; using Relations = typename Flavor::Relations; using SumcheckTupleOfTuplesOfUnivariates = typename Flavor::SumcheckTupleOfTuplesOfUnivariates; + using RelationSeparator = typename Flavor::RelationSeparator; public: using FF = typename Flavor::FF; @@ -103,15 +104,16 @@ template class SumcheckProverRound { barretenberg::Univariate compute_univariate( ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials, const proof_system::RelationParameters& relation_parameters, - const barretenberg::PowUnivariate& pow_univariate, - const FF alpha) + const barretenberg::PowPolynomial& pow_polynomial, + const RelationSeparator alpha) { - // Precompute the vector of required powers of zeta - // TODO(luke): Parallelize this + // Compute the constant contribution of pow polynomials for each edge. This is the product of the partial + // evaluation result c_l (i.e. pow(u_0,...,u_{l-1})) where u_0,...,u_{l-1} are the verifier challenges from + // previous rounds) and the elements of pow(\vec{β}) not containing β_0,..., β_l. std::vector pow_challenges(round_size >> 1); - pow_challenges[0] = pow_univariate.partial_evaluation_constant; + pow_challenges[0] = pow_polynomial.partial_evaluation_result; for (size_t i = 1; i < (round_size >> 1); ++i) { - pow_challenges[i] = pow_challenges[i - 1] * pow_univariate.zeta_pow_sqr; + pow_challenges[i] = pow_challenges[0] * pow_polynomial[i * pow_polynomial.periodicity]; } // Determine number of threads for multithreading. @@ -138,21 +140,15 @@ template class SumcheckProverRound { size_t start = thread_idx * iterations_per_thread; size_t end = (thread_idx + 1) * iterations_per_thread; - // For each edge_idx = 2i, we need to multiply the whole contribution by zeta^{2^{2i}} - // This means that each univariate for each relation needs an extra multiplication. for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) { extend_edges(extended_edges[thread_idx], polynomials, edge_idx); - // Update the pow polynomial's contribution c_l ⋅ ζ_{l+1}ⁱ for the next edge. - FF pow_challenge = pow_challenges[edge_idx >> 1]; - // Compute the i-th edge's univariate contribution, - // scale it by the pow polynomial's constant and zeta power "c_l ⋅ ζ_{l+1}ⁱ" - // and add it to the accumulators for Sˡ(Xₗ) + // scale it by pow_challenge constant contribution and add it to the accumulators for Sˡ(Xₗ) accumulate_relation_univariates(thread_univariate_accumulators[thread_idx], extended_edges[thread_idx], relation_parameters, - pow_challenge); + pow_challenges[edge_idx >> 1]); } }); @@ -160,9 +156,10 @@ template class SumcheckProverRound { for (auto& accumulators : thread_univariate_accumulators) { Utils::add_nested_tuples(univariate_accumulators, accumulators); } + // Batch the univariate contributions from each sub-relation to obtain the round univariate return batch_over_relations>( - univariate_accumulators, alpha, pow_univariate); + univariate_accumulators, alpha, pow_polynomial); } /** @@ -171,14 +168,14 @@ template class SumcheckProverRound { */ template static ExtendedUnivariate batch_over_relations(ContainerOverSubrelations& univariate_accumulators, - const FF& challenge, - const barretenberg::PowUnivariate& pow_univariate) + const RelationSeparator& challenge, + const barretenberg::PowPolynomial& pow_polynomial) { auto running_challenge = FF(1); Utils::scale_univariates(univariate_accumulators, challenge, running_challenge); auto result = ExtendedUnivariate(0); - extend_and_batch_univariates(univariate_accumulators, result, pow_univariate); + extend_and_batch_univariates(univariate_accumulators, result, pow_polynomial); // Reset all univariate accumulators to 0 before beginning accumulation in the next round Utils::zero_univariates(univariate_accumulators); @@ -191,16 +188,16 @@ template class SumcheckProverRound { * @tparam extended_size Size after extension * @param tuple A tuple of tuples of Univariates * @param result A Univariate of length extended_size - * @param pow_univariate Power polynomial univariate + * @param pow_polynomial Power polynomial univariate */ template static void extend_and_batch_univariates(const TupleOfTuplesOfUnivariates& tuple, ExtendedUnivariate& result, - const barretenberg::PowUnivariate& pow_univariate) + const barretenberg::PowPolynomial& pow_polynomial) { ExtendedUnivariate extended_random_polynomial; // Random poly R(X) = (1-X) + X.zeta_pow - auto random_polynomial = barretenberg::Univariate({ 1, pow_univariate.zeta_pow }); + auto random_polynomial = barretenberg::Univariate({ 1, pow_polynomial.current_element() }); extended_random_polynomial = random_polynomial.template extend_to(); auto extend_and_sum = [&](Element& element) { @@ -259,6 +256,7 @@ template class SumcheckVerifierRound { using Utils = barretenberg::RelationUtils; using Relations = typename Flavor::Relations; using TupleOfArraysOfValues = typename Flavor::TupleOfArraysOfValues; + using RelationSeparator = typename Flavor::RelationSeparator; public: using FF = typename Flavor::FF; @@ -274,7 +272,11 @@ template class SumcheckVerifierRound { TupleOfArraysOfValues relation_evaluations; // Verifier constructor - explicit SumcheckVerifierRound() { Utils::zero_elements(relation_evaluations); }; + explicit SumcheckVerifierRound(FF target_total_sum = 0) + : target_total_sum(target_total_sum) + { + Utils::zero_elements(relation_evaluations); + }; bool check_sum(barretenberg::Univariate& univariate) { @@ -323,13 +325,11 @@ template class SumcheckVerifierRound { // kill the pow_univariat FF compute_full_honk_relation_purported_value(ClaimedEvaluations purported_evaluations, const proof_system::RelationParameters& relation_parameters, - const barretenberg::PowUnivariate& pow_univariate, - const FF alpha) + const barretenberg::PowPolynomial& pow_polynomial, + const RelationSeparator alpha) { - Utils::template accumulate_relation_evaluations<>(purported_evaluations, - relation_evaluations, - relation_parameters, - pow_univariate.partial_evaluation_constant); + Utils::template accumulate_relation_evaluations<>( + purported_evaluations, relation_evaluations, relation_parameters, pow_polynomial.partial_evaluation_result); auto running_challenge = FF(1); auto output = FF(0); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.test.cpp index 2856012b163..c2e62341a53 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.test.cpp @@ -8,7 +8,6 @@ using namespace proof_system::honk; using namespace proof_system::honk::sumcheck; using barretenberg::BarycentricData; -using barretenberg::PowUnivariate; using barretenberg::Univariate; using Flavor = flavor::Ultra; @@ -25,6 +24,7 @@ TEST(SumcheckRound, SumcheckTupleOfTuplesOfUnivariates) { using Flavor = proof_system::honk::flavor::Ultra; using FF = typename Flavor::FF; + using RelationSeparator = typename Flavor::RelationSeparator; // Define three linear univariates of different sizes Univariate univariate_1({ 1, 2, 3 }); @@ -36,19 +36,21 @@ TEST(SumcheckRound, SumcheckTupleOfTuplesOfUnivariates) auto tuple_of_tuples = std::make_tuple(std::make_tuple(univariate_1), std::make_tuple(univariate_2, univariate_3)); // Use scale_univariate_accumulators to scale by challenge powers - FF challenge = 5; + RelationSeparator challenge = {}; + challenge[0] = 5; + challenge[1] = challenge[0].sqr(); FF running_challenge = 1; Utils::scale_univariates(tuple_of_tuples, challenge, running_challenge); // Use extend_and_batch_univariates to extend to MAX_LENGTH then accumulate - PowUnivariate pow_univariate(1); + barretenberg::PowPolynomial pow_polynomial({ 1 }); auto result = Univariate(); - SumcheckProverRound::extend_and_batch_univariates(tuple_of_tuples, result, pow_univariate); + SumcheckProverRound::extend_and_batch_univariates(tuple_of_tuples, result, pow_polynomial); // Repeat the batching process manually auto result_expected = univariate_1.template extend_to() * 1 + - univariate_2.template extend_to() * challenge + - univariate_3.template extend_to() * challenge * challenge; + univariate_2.template extend_to() * challenge[0] + + univariate_3.template extend_to() * challenge[1]; // Compare final batched univarites EXPECT_EQ(result, result_expected); @@ -74,6 +76,7 @@ TEST(SumcheckRound, TuplesOfEvaluationArrays) using Flavor = proof_system::honk::flavor::Ultra; using Utils = barretenberg::RelationUtils; using FF = typename Flavor::FF; + using RelationSeparator = typename Flavor::RelationSeparator; // Define two arrays of arbitrary elements std::array evaluations_1 = { 4 }; @@ -83,14 +86,15 @@ TEST(SumcheckRound, TuplesOfEvaluationArrays) auto tuple_of_arrays = std::make_tuple(evaluations_1, evaluations_2); // Use scale_and_batch_elements to scale by challenge powers - FF challenge = 5; FF running_challenge = 1; + RelationSeparator challenge = {}; + challenge[0] = 5; + challenge[1] = challenge[0].sqr(); FF result = 0; Utils::scale_and_batch_elements(tuple_of_arrays, challenge, running_challenge, result); // Repeat the batching process manually - auto result_expected = - evaluations_1[0] * 1 + evaluations_2[0] * challenge + evaluations_2[1] * challenge * challenge; + auto result_expected = evaluations_1[0] * 1 + evaluations_2[0] * challenge[0] + evaluations_2[1] * challenge[1]; // Compare batched result EXPECT_EQ(result, result_expected); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp index b398f982d30..00a4e291e8e 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp @@ -2,7 +2,6 @@ #include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/commitment_schemes/commitment_key.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" @@ -141,9 +140,12 @@ void GoblinTranslatorProver::execute_relation_check_rounds() using Sumcheck = sumcheck::SumcheckProver; auto sumcheck = Sumcheck(key->circuit_size, transcript); - - FF alpha = transcript->get_challenge("alpha"); - sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha); + FF alpha = transcript->get_challenge("Sumcheck:alpha"); + std::vector gate_challenges(numeric::get_msb(key->circuit_size)); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); } /** diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp index 44e736b71d5..d6797c62a1b 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp @@ -1,6 +1,5 @@ #include "./goblin_translator_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -244,11 +243,16 @@ bool GoblinTranslatorVerifier::verify_proof(const plonk::proof& proof) commitments.z_perm = receive_commitment(commitment_labels.z_perm); // Execute Sumcheck Verifier - auto sumcheck = SumcheckVerifier(circuit_size); + const size_t log_circuit_size = numeric::get_msb(circuit_size); + auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); + FF alpha = transcript->get_challenge("Sumcheck:alpha"); + std::vector gate_challenges(numeric::get_msb(key->circuit_size)); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } - FF alpha = transcript->get_challenge("alpha"); auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, transcript); + sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp index c1e174f0d62..5f7cc775fbf 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp @@ -33,6 +33,8 @@ class GoblinUltraTranscriptTests : public ::testing::Test { auto log_n = numeric::get_msb(circuit_size); size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; + size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; + size_t size_FF = sizeof(FF); size_t size_G = 2 * size_FF; size_t size_uni = MAX_PARTIAL_RELATION_LENGTH * size_FF; @@ -64,20 +66,27 @@ class GoblinUltraTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "LOOKUP_INVERSES", size_G); manifest_expected.add_entry(round, "Z_PERM", size_G); manifest_expected.add_entry(round, "Z_LOOKUP", size_G); - manifest_expected.add_challenge(round, "alpha"); - round++; - manifest_expected.add_challenge(round, "Sumcheck:zeta"); + for (size_t i = 0; i < NUM_SUBRELATIONS - 1; i++) { + std::string label = "Sumcheck:alpha_" + std::to_string(i); + manifest_expected.add_challenge(round, label); + round++; + } - for (size_t i = 0; i < log_n; ++i) { + for (size_t i = 0; i < log_n; i++) { + std::string label = "Sumcheck:gate_challenge_" + std::to_string(i); + manifest_expected.add_challenge(round, label); round++; + } + + for (size_t i = 0; i < log_n; ++i) { std::string idx = std::to_string(i); manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, size_uni); std::string label = "Sumcheck:u_" + idx; manifest_expected.add_challenge(round, label); + round++; } - round++; manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); manifest_expected.add_challenge(round, "rho"); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index 75995bf429e..f2f14ab43b4 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -1,8 +1,8 @@ +#include "barretenberg/polynomials/pow.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/ultra_honk/ultra_composer.hpp" #include -using namespace barretenberg; using namespace proof_system::honk; using Flavor = flavor::Ultra; @@ -18,9 +18,12 @@ using Polynomial = typename Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; using RelationParameters = proof_system::RelationParameters; using WitnessCommitments = typename Flavor::WitnessCommitments; +using CommitmentKey = Flavor::CommitmentKey; +using PowPolynomial = barretenberg::PowPolynomial; + const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; -namespace protogalaxy_tests { +namespace barretenberg::protogalaxy_tests { namespace { auto& engine = numeric::random::get_debug_engine(); } @@ -44,24 +47,44 @@ 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) +std::shared_ptr fold_and_verify(const std::vector>& instances, + UltraComposer& composer, + bool expected_result) { - 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; + 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 next_accumulator = proof.accumulator; + auto res = folding_verifier.verify_folding_proof(proof.folding_data); + EXPECT_EQ(res, expected_result); + return next_accumulator; } -WitnessCommitments construct_witness_commitments() +void check_accumulator_target_sum_manual(std::shared_ptr& accumulator, bool expected_result) { - WitnessCommitments wc; - auto w_view = wc.get_all(); - for (auto& view : w_view) { - view = Affine(Projective::random_element()); + auto instance_size = accumulator->instance_size; + auto expected_honk_evals = ProtoGalaxyProver::compute_full_honk_evaluations( + accumulator->prover_polynomials, accumulator->alphas, accumulator->relation_parameters); + // Construct pow(\vec{betas*}) as in the paper + auto expected_pows = PowPolynomial(accumulator->gate_challenges); + expected_pows.compute_values(); + + // Compute the corresponding target sum and create a dummy accumulator + auto expected_target_sum = FF(0); + for (size_t i = 0; i < instance_size; i++) { + expected_target_sum += expected_honk_evals[i] * expected_pows[i]; } - return wc; + + EXPECT_EQ(accumulator->target_sum == expected_target_sum, expected_result); +} +void decide_and_verify(std::shared_ptr& accumulator, UltraComposer& composer, bool expected_result) +{ + auto decider_prover = composer.create_decider_prover(accumulator, composer.commitment_key); + auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decision = decider_prover.construct_proof(); + auto verified = decider_verifier.verify_proof(decision); + EXPECT_EQ(verified, expected_result); } class ProtoGalaxyTests : public ::testing::Test { @@ -91,9 +114,11 @@ TEST_F(ProtoGalaxyTests, FullHonkEvaluationsValidCircuit) instance->compute_sorted_accumulator_polynomials(eta); instance->compute_grand_product_polynomials(beta, gamma); - auto alpha = FF::random_element(); + for (auto& alpha : instance->alphas) { + alpha = FF::random_element(); + } auto full_honk_evals = ProtoGalaxyProver::compute_full_honk_evaluations( - instance->prover_polynomials, alpha, instance->relation_parameters); + instance->prover_polynomials, instance->alphas, instance->relation_parameters); // Evaluations should be 0 for valid circuit for (const auto& eval : full_honk_evals) { @@ -115,6 +140,7 @@ TEST_F(ProtoGalaxyTests, PerturbatorCoefficients) TEST_F(ProtoGalaxyTests, PerturbatorPolynomial) { + using RelationSeparator = Flavor::RelationSeparator; const size_t log_instance_size(3); const size_t instance_size(1 << log_instance_size); @@ -124,17 +150,21 @@ TEST_F(ProtoGalaxyTests, PerturbatorPolynomial) } auto full_polynomials = construct_ultra_full_polynomials(random_polynomials); auto relation_parameters = proof_system::RelationParameters::get_random(); - auto alpha = FF::random_element(); + RelationSeparator alphas; + for (auto& alpha : alphas) { + alpha = FF::random_element(); + } auto full_honk_evals = - ProtoGalaxyProver::compute_full_honk_evaluations(full_polynomials, alpha, relation_parameters); + ProtoGalaxyProver::compute_full_honk_evaluations(full_polynomials, alphas, 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); + auto pow_beta = PowPolynomial(betas); + pow_beta.compute_values(); // Compute the corresponding target sum and create a dummy accumulator auto target_sum = FF(0); @@ -144,9 +174,10 @@ TEST_F(ProtoGalaxyTests, PerturbatorPolynomial) auto accumulator = std::make_shared(); accumulator->prover_polynomials = std::move(full_polynomials); - accumulator->folding_parameters = { betas, target_sum }; + accumulator->gate_challenges = betas; + accumulator->target_sum = target_sum; accumulator->relation_parameters = relation_parameters; - accumulator->alpha = alpha; + accumulator->alphas = alphas; auto deltas = ProtoGalaxyProver::compute_round_challenge_pows(log_instance_size, FF::random_element()); auto perturbator = ProtoGalaxyProver::compute_perturbator(accumulator, deltas); @@ -155,14 +186,6 @@ TEST_F(ProtoGalaxyTests, PerturbatorPolynomial) EXPECT_EQ(perturbator[0], target_sum); } -TEST_F(ProtoGalaxyTests, PowPolynomialsOnPowers) -{ - auto betas = std::vector{ 2, 4, 16 }; - auto pow_betas = ProtoGalaxyProver::compute_pow_polynomial_at_values(betas, 8); - auto expected_values = std::vector{ 1, 2, 4, 8, 16, 32, 64, 128 }; - EXPECT_EQ(expected_values, pow_betas); -} - TEST_F(ProtoGalaxyTests, CombinerQuotient) { auto compressed_perturbator = FF(2); // F(\alpha) in the paper @@ -191,7 +214,7 @@ TEST_F(ProtoGalaxyTests, CombinerQuotient) } } -TEST_F(ProtoGalaxyTests, FoldChallenges) +TEST_F(ProtoGalaxyTests, CombineRelationParameters) { using Instances = ProverInstances_; using Instance = typename Instances::Instance; @@ -212,82 +235,118 @@ TEST_F(ProtoGalaxyTests, FoldChallenges) EXPECT_EQ(instances.relation_parameters.eta, expected_eta); } -TEST_F(ProtoGalaxyTests, FoldAlpha) +TEST_F(ProtoGalaxyTests, CombineAlpha) { using Instances = ProverInstances_; using Instance = typename Instances::Instance; Builder builder1; auto instance1 = std::make_shared(builder1); - instance1->alpha = 2; + instance1->alphas.fill(2); Builder builder2; builder2.add_variable(3); auto instance2 = std::make_shared(builder2); - instance2->alpha = 4; + instance2->alphas.fill(4); Instances instances{ { instance1, instance2 } }; 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); + for (const auto& alpha : instances.alphas) { + EXPECT_EQ(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) +// Check both manually and using the protocol two rounds of folding +TEST_F(ProtoGalaxyTests, FullProtogalaxyTest) { - const size_t log_instance_size(4); - const size_t instance_size(1 << log_instance_size); + auto composer = UltraComposer(); - 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 builder_1 = typename Flavor::CircuitBuilder(); + builder_1.add_public_variable(FF(1)); - 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(); - } + auto instance_1 = composer.create_instance(builder_1); - // Construct pow(\vec{betas}) as in the paper - auto pow_beta = ProtoGalaxyProver::compute_pow_polynomial_at_values(betas, instance_size); + auto builder_2 = typename Flavor::CircuitBuilder(); + builder_2.add_public_variable(FF(1)); - // 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 instance_2 = composer.create_instance(builder_2); - 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 = std::move(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 instances = std::vector>{ instance_1, instance_2 }; + auto first_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(first_accumulator, true); + + auto builder_3 = typename Flavor::CircuitBuilder(); + builder_3.add_public_variable(FF(1)); + auto instance_3 = composer.create_instance(builder_3); + + instances = std::vector>{ first_accumulator, instance_3 }; + auto second_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(second_accumulator, true); + + decide_and_verify(second_accumulator, composer, true); +} - auto builder = typename Flavor::CircuitBuilder(); +TEST_F(ProtoGalaxyTests, TamperedCommitment) +{ 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 builder_1 = typename Flavor::CircuitBuilder(); + builder_1.add_public_variable(FF(1)); - auto proof = folding_prover.fold_instances(); - auto res = folding_verifier.verify_folding_proof(proof.folding_data); - EXPECT_EQ(res, true); + auto instance_1 = composer.create_instance(builder_1); + + auto builder_2 = typename Flavor::CircuitBuilder(); + builder_2.add_public_variable(FF(1)); + + auto instance_2 = composer.create_instance(builder_2); + + auto instances = std::vector>{ instance_1, instance_2 }; + auto first_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(first_accumulator, true); + + auto builder_3 = typename Flavor::CircuitBuilder(); + builder_3.add_public_variable(FF(1)); + auto instance_3 = composer.create_instance(builder_3); + + // tampering with the commitment should cause the decider to fail + first_accumulator->witness_commitments.w_l = Projective(Affine::random_element()); + instances = std::vector>{ first_accumulator, instance_3 }; + + auto second_accumulator = fold_and_verify(instances, composer, true); + + decide_and_verify(second_accumulator, composer, false); +} + +TEST_F(ProtoGalaxyTests, TamperedAccumulatorPolynomial) +{ + auto composer = UltraComposer(); + + auto builder_1 = typename Flavor::CircuitBuilder(); + builder_1.add_public_variable(FF(1)); + + auto instance_1 = composer.create_instance(builder_1); + + auto builder_2 = typename Flavor::CircuitBuilder(); + builder_2.add_public_variable(FF(1)); + + auto instance_2 = composer.create_instance(builder_2); + + auto instances = std::vector>{ instance_1, instance_2 }; + auto first_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(first_accumulator, true); + + auto builder_3 = typename Flavor::CircuitBuilder(); + builder_3.add_public_variable(FF(1)); + auto instance_3 = composer.create_instance(builder_3); + + // tampering with accumulator's polynomial should cause both folding and deciding to fail + instances = std::vector>{ first_accumulator, instance_3 }; + first_accumulator->prover_polynomials.w_l[1] = FF::random_element(); + auto second_accumulator = fold_and_verify(instances, composer, false); + + decide_and_verify(second_accumulator, composer, false); } -} // namespace protogalaxy_tests \ No newline at end of file +} // namespace barretenberg::protogalaxy_tests \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp index c0a1c6b1f61..09815ab23c8 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp @@ -36,6 +36,7 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) using Flavor = flavor::Ultra; using FF = typename Flavor::FF; using Transcript = typename Flavor::Transcript; + using RelationSeparator = typename Flavor::RelationSeparator; // Create a composer and a dummy circuit with a few gates auto builder = proof_system::UltraCircuitBuilder(); @@ -162,16 +163,38 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) auto prover_transcript = Transcript::prover_init_empty(); auto circuit_size = instance->proving_key->circuit_size; - instance->alpha = prover_transcript->get_challenge("alpha"); - auto sumcheck_prover = SumcheckProver(circuit_size, prover_transcript); + auto log_circuit_size = numeric::get_msb(circuit_size); + + RelationSeparator prover_alphas; + for (size_t idx = 0; idx < prover_alphas.size(); idx++) { + prover_alphas[idx] = prover_transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + instance->alphas = prover_alphas; + auto sumcheck_prover = SumcheckProver(circuit_size, prover_transcript); + std::vector prover_gate_challenges(log_circuit_size); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + prover_gate_challenges[idx] = + prover_transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + instance->gate_challenges = prover_gate_challenges; auto prover_output = sumcheck_prover.prove(instance); auto verifier_transcript = Transcript::verifier_init_empty(prover_transcript); - auto sumcheck_verifier = SumcheckVerifier(circuit_size); - FF alpha = verifier_transcript->get_challenge("alpha"); - auto verifier_output = sumcheck_verifier.verify(instance->relation_parameters, alpha, verifier_transcript); + auto sumcheck_verifier = SumcheckVerifier(log_circuit_size, verifier_transcript); + RelationSeparator verifier_alphas; + for (size_t idx = 0; idx < verifier_alphas.size(); idx++) { + verifier_alphas[idx] = verifier_transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + + std::vector verifier_gate_challenges(log_circuit_size); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + verifier_gate_challenges[idx] = + verifier_transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto verifier_output = + sumcheck_verifier.verify(instance->relation_parameters, verifier_alphas, verifier_gate_challenges); auto verified = verifier_output.verified.value(); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp index 7f318aa98a3..359c58b7949 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp @@ -97,6 +97,39 @@ UltraVerifier_ UltraComposer_::create_verifier(const std::shared return output_state; } +template +DeciderProver_ UltraComposer_::create_decider_prover(const std::shared_ptr& accumulator, + const std::shared_ptr& transcript) +{ + commitment_key = compute_commitment_key(accumulator->instance_size); + DeciderProver_ output_state(accumulator, commitment_key, transcript); + + return output_state; +} + +template +DeciderProver_ UltraComposer_::create_decider_prover( + const std::shared_ptr& accumulator, + const std::shared_ptr& commitment_key, + const std::shared_ptr& transcript) +{ + DeciderProver_ output_state(accumulator, commitment_key, transcript); + + return output_state; +} + +template +DeciderVerifier_ UltraComposer_::create_decider_verifier(const std::shared_ptr& accumulator, + const std::shared_ptr& transcript) +{ + auto& verification_key = accumulator->verification_key; + DeciderVerifier_ output_state(transcript, verification_key); + auto pcs_verification_key = std::make_unique(accumulator->instance_size, crs_factory_); + output_state.pcs_verification_key = std::move(pcs_verification_key); + + return output_state; +} + template class UltraComposer_; template class UltraComposer_; } // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp index ee0e6a10825..a7798e55914 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp @@ -1,6 +1,8 @@ #pragma once #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/proof_system/composer/composer_lib.hpp" +#include "barretenberg/protogalaxy/decider_prover.hpp" +#include "barretenberg/protogalaxy/decider_verifier.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" #include "barretenberg/srs/global_crs.hpp" @@ -66,6 +68,17 @@ template class UltraComposer_ { const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); + DeciderProver_ create_decider_prover( + const std::shared_ptr&, + const std::shared_ptr& transcript = std::make_shared()); + DeciderProver_ create_decider_prover( + const std::shared_ptr&, + const std::shared_ptr&, + const std::shared_ptr& transcript = std::make_shared()); + + DeciderVerifier_ create_decider_verifier( + const std::shared_ptr&, + const std::shared_ptr& transcript = std::make_shared()); UltraVerifier_ create_verifier(CircuitBuilder& circuit); UltraVerifier_ create_ultra_with_keccak_verifier(CircuitBuilder& circuit); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp index fe3031181ef..44b95ce6bf4 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp @@ -1,5 +1,4 @@ #include "ultra_prover.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" namespace proof_system::honk { @@ -148,9 +147,18 @@ template void UltraProver_::execute_grand_product_c template void UltraProver_::execute_relation_check_rounds() { using Sumcheck = sumcheck::SumcheckProver; - - auto sumcheck = Sumcheck(instance->proving_key->circuit_size, transcript); - instance->alpha = transcript->get_challenge("alpha"); + auto circuit_size = instance->proving_key->circuit_size; + auto sumcheck = Sumcheck(circuit_size, transcript); + RelationSeparator alphas; + for (size_t idx = 0; idx < alphas.size(); idx++) { + alphas[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + instance->alphas = alphas; + std::vector gate_challenges(numeric::get_msb(circuit_size)); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + instance->gate_challenges = gate_challenges; sumcheck_output = sumcheck.prove(instance); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp index 5817648097d..2ba793fa0bc 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp @@ -20,6 +20,7 @@ template class UltraProver_ { using Curve = typename Flavor::Curve; using Instance = ProverInstance_; using Transcript = typename Flavor::Transcript; + using RelationSeparator = typename Flavor::RelationSeparator; public: explicit UltraProver_(const std::shared_ptr&, diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index c5564e8fd10..6e8b19a0891 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -33,6 +33,7 @@ class UltraTranscriptTests : public ::testing::Test { auto log_n = numeric::get_msb(circuit_size); size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; + size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; size_t size_FF = sizeof(FF); size_t size_G = 2 * size_FF; size_t size_uni = MAX_PARTIAL_RELATION_LENGTH * size_FF; @@ -57,20 +58,27 @@ class UltraTranscriptTests : public ::testing::Test { round++; manifest_expected.add_entry(round, "Z_PERM", size_G); manifest_expected.add_entry(round, "Z_LOOKUP", size_G); - manifest_expected.add_challenge(round, "alpha"); - round++; - manifest_expected.add_challenge(round, "Sumcheck:zeta"); + for (size_t i = 0; i < NUM_SUBRELATIONS - 1; i++) { + std::string label = "Sumcheck:alpha_" + std::to_string(i); + manifest_expected.add_challenge(round, label); + round++; + } - for (size_t i = 0; i < log_n; ++i) { + for (size_t i = 0; i < log_n; i++) { + std::string label = "Sumcheck:gate_challenge_" + std::to_string(i); + manifest_expected.add_challenge(round, label); round++; + } + + for (size_t i = 0; i < log_n; ++i) { std::string idx = std::to_string(i); manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, size_uni); std::string label = "Sumcheck:u_" + idx; manifest_expected.add_challenge(round, label); + round++; } - round++; manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); manifest_expected.add_challenge(round, "rho"); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 21ca72be6d1..637806709e8 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -1,6 +1,5 @@ #include "./ultra_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -131,14 +130,22 @@ template bool UltraVerifier_::verify_proof(const plonk commitments.z_lookup = transcript->template receive_from_prover(commitment_labels.z_lookup); // Execute Sumcheck Verifier - auto sumcheck = SumcheckVerifier(circuit_size); - FF alpha = transcript->get_challenge("alpha"); + const size_t log_circuit_size = numeric::get_msb(circuit_size); + auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); + RelationSeparator alphas; + for (size_t idx = 0; idx < alphas.size(); idx++) { + alphas[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + + auto gate_challenges = std::vector(log_circuit_size); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, transcript); + sumcheck.verify(relation_parameters, alphas, gate_challenges); // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { - info("UltraVerifier: Sumcheck failed."); return false; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp index a805b4fc645..8e6c02d0b68 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp @@ -12,6 +12,7 @@ template class UltraVerifier_ { using VerificationKey = typename Flavor::VerificationKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using Transcript = typename Flavor::Transcript; + using RelationSeparator = typename Flavor::RelationSeparator; public: explicit UltraVerifier_(const std::shared_ptr& transcript, diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp index 9a7d4cc632b..a4931f5cf90 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp @@ -5,7 +5,6 @@ #include "barretenberg/commitment_schemes/commitment_key.hpp" #include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/honk/proof_system/permutation_library.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/relations/lookup_relation.hpp" @@ -74,9 +73,12 @@ void AvmMiniProver::execute_relation_check_rounds() using Sumcheck = sumcheck::SumcheckProver; auto sumcheck = Sumcheck(key->circuit_size, transcript); - auto alpha = transcript->get_challenge("alpha"); - - sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha); + FF alpha = transcript->get_challenge("Sumcheck:alpha"); + std::vector gate_challenges(numeric::get_msb(key->circuit_size)); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); } /** diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp index f0b102ede71..157e4a8bc0d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp @@ -2,7 +2,6 @@ #include "./AvmMini_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -118,11 +117,15 @@ bool AvmMiniVerifier::verify_proof(const plonk::proof& proof) commitments.avmMini_last = transcript->template receive_from_prover(commitment_labels.avmMini_last); // Execute Sumcheck Verifier - auto sumcheck = SumcheckVerifier(circuit_size); - - auto alpha = transcript->get_challenge("alpha"); + const size_t log_circuit_size = numeric::get_msb(circuit_size); + auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); + FF alpha = transcript->get_challenge("Sumcheck:alpha"); + auto gate_challenges = std::vector(log_circuit_size); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, transcript); + sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp index a29c274d1e4..9a210d2c7ed 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp @@ -5,7 +5,6 @@ #include "barretenberg/commitment_schemes/commitment_key.hpp" #include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/honk/proof_system/permutation_library.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/relations/lookup_relation.hpp" @@ -71,11 +70,13 @@ void ToyProver::execute_wire_commitments_round() void ToyProver::execute_relation_check_rounds() { using Sumcheck = sumcheck::SumcheckProver; - auto sumcheck = Sumcheck(key->circuit_size, transcript); - auto alpha = transcript->get_challenge("alpha"); - - sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha); + FF alpha = transcript->get_challenge("Sumcheck:alpha"); + std::vector gate_challenges(numeric::get_msb(key->circuit_size)); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); } /** diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp index 02c29056ce0..6fac55b463c 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp @@ -2,7 +2,6 @@ #include "./Toy_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" -#include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -84,11 +83,15 @@ bool ToyVerifier::verify_proof(const plonk::proof& proof) transcript->template receive_from_prover(commitment_labels.lookup_xor_counts); // Execute Sumcheck Verifier - auto sumcheck = SumcheckVerifier(circuit_size); - - auto alpha = transcript->get_challenge("alpha"); + const size_t log_circuit_size = numeric::get_msb(circuit_size); + auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); + FF alpha = transcript->get_challenge("Sumcheck:alpha"); + auto gate_challenges = std::vector(log_circuit_size); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, transcript); + sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) {