From 9a71a91911db1b9a198cb3223a8d71ceb39d6596 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 10 Jan 2025 10:05:21 +0000 Subject: [PATCH 01/33] eccvm sumcheck butchered --- .../src/barretenberg/eccvm/eccvm_prover.cpp | 3 +- .../eccvm/eccvm_transcript.test.cpp | 3 + .../src/barretenberg/eccvm/eccvm_verifier.cpp | 17 +- .../src/barretenberg/sumcheck/sumcheck.hpp | 220 +++++++++++++++--- .../barretenberg/sumcheck/sumcheck_output.hpp | 26 ++- 5 files changed, 227 insertions(+), 42 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index 35f2e319175..91464213235 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -106,7 +106,8 @@ void ECCVMProver::execute_relation_check_rounds() zk_sumcheck_data = ZKData(key->log_circuit_size, transcript, key->commitment_key); - sumcheck_output = sumcheck.prove(key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data); + sumcheck_output = sumcheck.prove( + key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data, key->commitment_key); } /** diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index 8166d607aca..97de02d8b33 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -320,6 +320,9 @@ TEST_F(ECCVMTranscriptTests, VerifierManifestConsistency) // Check consistency between the manifests generated by the prover and verifier auto prover_manifest = prover.transcript->get_manifest(); auto verifier_manifest = verifier.transcript->get_manifest(); + prover_manifest.print(); + info("========"); + verifier_manifest.print(); // Note: a manifest can be printed using manifest.print() // The last challenge generated by the ECCVM Prover is the translation univariate batching challenge and, on the diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index b2a260a8be7..fd904a3b20d 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -59,14 +59,13 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) libra_commitments[0] = transcript->template receive_from_prover("Libra:concatenation_commitment"); - auto [multivariate_challenge, claimed_evaluations, libra_evaluation, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, gate_challenges); + auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); // If Sumcheck did not verify, return false - if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { + if (sumcheck_output.verified.has_value() && !sumcheck_output.verified.value()) { vinfo("eccvm sumcheck failed"); return false; } @@ -77,16 +76,16 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) Shplemini::compute_batch_opening_claim(circuit_size, commitments.get_unshifted(), commitments.get_to_be_shifted(), - claimed_evaluations.get_unshifted(), - claimed_evaluations.get_shifted(), - multivariate_challenge, + sumcheck_output.claimed_evaluations.get_unshifted(), + sumcheck_output.claimed_evaluations.get_shifted(), + sumcheck_output.challenge, key->pcs_verification_key->get_g1_identity(), transcript, Flavor::REPEATED_COMMITMENTS, Flavor::HasZK, &consistency_checked, libra_commitments, - libra_evaluation); + sumcheck_output.claimed_libra_evaluation); // Reduce the accumulator to a single opening claim const OpeningClaim multivariate_to_univariate_opening_claim = @@ -134,8 +133,8 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) const bool batched_opening_verified = PCS::reduce_verify(key->pcs_verification_key, batch_opening_claim, ipa_transcript); - vinfo("eccvm sumcheck verified?: ", sumcheck_verified.value()); + vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified.value()); vinfo("batch opening verified?: ", batched_opening_verified); - return sumcheck_verified.value() && batched_opening_verified && consistency_checked; + return sumcheck_output.verified.value() && batched_opening_verified && consistency_checked; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index afd1cb3a663..2e103352444 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -122,9 +122,11 @@ template class SumcheckProver { using ProverPolynomials = typename Flavor::ProverPolynomials; using PartiallyEvaluatedMultivariates = typename Flavor::PartiallyEvaluatedMultivariates; using ClaimedEvaluations = typename Flavor::AllValues; - + using ZKData = ZKSumcheckData; using Transcript = typename Flavor::Transcript; using RelationSeparator = typename Flavor::RelationSeparator; + using CommitmentKey = typename Flavor::CommitmentKey; + /** * @brief The total algebraic degree of the Sumcheck relation \f$ F \f$ as a polynomial in Prover Polynomials * \f$P_1,\ldots, P_N\f$. @@ -133,32 +135,21 @@ template class SumcheckProver { // this constant specifies the number of coefficients of libra polynomials, and evaluations of round univariate static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; - // Specify the number of all witnesses including shifts and derived witnesses from flavors that have ZK, - // otherwise, set this constant to 0 - static constexpr size_t NUM_ALL_WITNESS_ENTITIES = Flavor::NUM_ALL_WITNESS_ENTITIES; - /** - * @brief The size of the hypercube, i.e. \f$ 2^d\f$. - * - */ using SumcheckRoundUnivariate = typename bb::Univariate; - using EvaluationMaskingTable = - std::array, NUM_ALL_WITNESS_ENTITIES>; + + // The size of the hypercube, i.e. \f$ 2^d\f$. const size_t multivariate_n; - /** - * @brief The number of variables - * - */ + // The number of variables const size_t multivariate_d; - using EvalMaskingScalars = std::array; - // Define the length of Libra Univariates. For non-ZK Flavors: set to 0. - static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Flavor::HasZK ? Flavor::BATCHED_RELATION_PARTIAL_LENGTH : 0; - using LibraUnivariates = std::vector>; - using ZKData = ZKSumcheckData; std::shared_ptr transcript; SumcheckProverRound round; + static constexpr bool IS_ECCVM = std::is_same_v; + std::vector round_univariate_commitments = {}; + std::vector> round_univariate_evaluations = {}; + /** * * @brief Container for partially evaluated Prover Polynomials at a current challenge. Upon computing challenge \f$ @@ -268,7 +259,8 @@ template class SumcheckProver { const bb::RelationParameters& relation_parameters, const RelationSeparator alpha, const std::vector& gate_challenges, - ZKData& zk_sumcheck_data) + ZKData& zk_sumcheck_data, + const std::shared_ptr& ck = nullptr) requires FlavorHasZK { @@ -293,9 +285,22 @@ template class SumcheckProver { PROFILE_THIS_NAME("rest of sumcheck round 1"); - // Place the evaluations of the round univariate into transcript. - transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); + if constexpr (!IS_ECCVM) { + // Place the evaluations of the round univariate into transcript. + transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); + } else { + auto round_univariate_commitment = + ck->commit(Polynomial(std::span(round_univariate.evaluations))); + transcript->send_to_verifier("Sumcheck:univariate_comm_0", round_univariate_commitment); + round_univariate_commitments.push_back(std::move(round_univariate_commitment)); + + transcript->send_to_verifier("Sumcheck:univariate_0_eval_0", round_univariate.value_at(0)); + transcript->send_to_verifier("Sumcheck:univariate_0_eval_1", round_univariate.value_at(1)); + round_univariate_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1) }); + } + FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); + multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round partially_evaluate(full_polynomials, multivariate_n, round_challenge); @@ -319,9 +324,24 @@ template class SumcheckProver { alpha, zk_sumcheck_data, row_disabling_polynomial); - // Place evaluations of Sumcheck Round Univariate in the transcript - transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); + if constexpr (!IS_ECCVM) { + // Place evaluations of Sumcheck Round Univariate in the transcript + transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); + } else { + transcript->send_to_verifier("Sumcheck:univariate_comm_" + std::to_string(round_idx), + ck->commit(Polynomial(std::span(round_univariate.evaluations)))); + transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_0", + round_univariate.value_at(0)); + transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_1", + round_univariate.value_at(1)); + round_univariate_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1) }); + + info("prover evals ", round_univariate.value_at(0) + round_univariate.value_at(1)); + } FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + + info("prover eval at challenge", round_idx, " ", round_univariate.evaluate(round_challenge)); + multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round partially_evaluate(partially_evaluated_polynomials, round.round_size, round_challenge); @@ -337,7 +357,15 @@ template class SumcheckProver { // Zero univariates are used to pad the proof to the fixed size CONST_PROOF_SIZE_LOG_N. auto zero_univariate = bb::Univariate::zero(); for (size_t idx = multivariate_d; idx < CONST_PROOF_SIZE_LOG_N; idx++) { - transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx), zero_univariate); + if constexpr (!IS_ECCVM) { + transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx), zero_univariate); + } else { + transcript->send_to_verifier("Sumcheck:univariate_comm_" + std::to_string(idx), + ck->commit(Polynomial(std::span(zero_univariate)))); + transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx) + "_eval_0", FF(0)); + transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx) + "_eval_1", FF(0)); + round_univariate_evaluations.push_back({ FF(0), FF(0) }); + } FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(idx)); multivariate_challenge.emplace_back(round_challenge); } @@ -359,7 +387,17 @@ template class SumcheckProver { transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all()); // The sum of the Libra constant term and the evaluations of Libra univariates at corresponding sumcheck // challenges is included in the Sumcheck Output - return SumcheckOutput{ multivariate_challenge, multivariate_evaluations, libra_evaluation }; + if constexpr (!IS_ECCVM) { + return SumcheckOutput{ multivariate_challenge, multivariate_evaluations, libra_evaluation }; + } else { + info("last sumcheck challenge, ", multivariate_challenge.back()); + + return SumcheckOutput{ round_univariate_commitments, + round_univariate_evaluations, + multivariate_challenge, + multivariate_evaluations, + libra_evaluation }; + } vinfo("finished sumcheck"); }; @@ -555,6 +593,7 @@ template class SumcheckVerifier { using ClaimedLibraEvaluations = typename std::vector; using Transcript = typename Flavor::Transcript; using RelationSeparator = typename Flavor::RelationSeparator; + using Commitment = typename Flavor::Commitment; /** * @brief Maximum partial algebraic degree of the relation \f$\tilde F = pow_{\beta} \cdot F \f$, i.e. \ref @@ -575,6 +614,11 @@ template class SumcheckVerifier { std::shared_ptr transcript; SumcheckVerifierRound round; + static constexpr bool IS_ECCVM = std::is_same_v || IsECCVMRecursiveFlavor; + + std::vector round_univariate_commitments = {}; + std::vector> round_univariate_evaluations = {}; + // 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) @@ -607,6 +651,8 @@ template class SumcheckVerifier { FF libra_challenge; FF libra_total_sum; + bb::Univariate round_univariate; + if constexpr (Flavor::HasZK) { // get the claimed sum of libra masking multivariate over the hypercube libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); @@ -623,10 +669,11 @@ template class SumcheckVerifier { for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { // Obtain the round univariate from the transcript std::string round_univariate_label = "Sumcheck:univariate_" + std::to_string(round_idx); - auto round_univariate = + round_univariate = transcript->template receive_from_prover>( round_univariate_label); FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + multivariate_challenge.emplace_back(round_challenge); if constexpr (IsRecursiveFlavor) { typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); @@ -637,7 +684,6 @@ template class SumcheckVerifier { if (round_idx < multivariate_d) { verified = verified && checked; } - multivariate_challenge.emplace_back(round_challenge); round.compute_next_target_sum(round_univariate, round_challenge, dummy_round); gate_separators.partially_evaluate(round_challenge, dummy_round); @@ -646,11 +692,8 @@ template class SumcheckVerifier { if (round_idx < multivariate_d) { bool checked = round.check_sum(round_univariate); verified = verified && checked; - multivariate_challenge.emplace_back(round_challenge); round.compute_next_target_sum(round_univariate, round_challenge); gate_separators.partially_evaluate(round_challenge); - } else { - multivariate_challenge.emplace_back(round_challenge); } } } @@ -699,5 +742,120 @@ template class SumcheckVerifier { return SumcheckOutput{ multivariate_challenge, purported_evaluations, libra_evaluation, verified }; } }; + + /** + * @brief Sumcheck Verifier for ECCVM and ECCVMRecursive. + * @details The verifier receives commitments to RoundUnivariates, along with their evaluations at 0 and 1. These + * evaluations will be proved as a part of Shplemini. The only check that the Verifier performs in this version is + * the comparison of the target sumcheck sum with the claimed evaluations of the first sumcheck round univariate. + * + * Note that the SumcheckOutput in this case contains a vector of commitments and a vector of arrays of evaluations + * at 0 and 1. Moreover, the purported honk value computed by the verifier has to be propagated to the PCS round, as + * it gives a claimed evaluation of the last sumcheck univariate. + * + * @param relation_parameters + * @param alpha + * @param gate_challenges + * @return SumcheckOutput + */ + SumcheckOutput verify(const bb::RelationParameters& relation_parameters, + RelationSeparator alpha, + const std::vector& gate_challenges) + requires std::is_same_v || IsECCVMRecursiveFlavor + { + bool verified(true); + + bb::GateSeparatorPolynomial gate_separators(gate_challenges); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1144): Add proper constraints for taking the log of + // a field_t link multivariate_d. + if (multivariate_d == 0) { + throw_or_abort("Number of variables in multivariate is 0."); + } + + // get the claimed sum of libra masking multivariate over the hypercube + const FF libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); + // get the challenge for the ZK Sumcheck claim + const FF libra_challenge = transcript->template get_challenge("Libra:Challenge"); + + std::vector multivariate_challenge; + multivariate_challenge.reserve(CONST_PROOF_SIZE_LOG_N); + // if Flavor has ZK, the target total sum is corrected by Libra total sum multiplied by the Libra + // challenge + round.target_total_sum += libra_total_sum * libra_challenge; + + for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + // Obtain the round univariate from the transcript + const std::string round_univariate_comm_label = "Sumcheck:univariate_comm_" + std::to_string(round_idx); + const std::string univariate_eval_label_0 = "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_0"; + const std::string univariate_eval_label_1 = "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_1"; + + // Receive the commitment to the round univariate + round_univariate_commitments.push_back( + transcript->template receive_from_prover(round_univariate_comm_label)); + // Receive evals at 0 and 1 + round_univariate_evaluations.push_back( + { transcript->template receive_from_prover(univariate_eval_label_0), + transcript->template receive_from_prover(univariate_eval_label_1) }); + + const FF round_challenge = + transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + multivariate_challenge.emplace_back(round_challenge); + + if constexpr (IsRecursiveFlavor) { + typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! + stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); + // Only utilize the checked value if this is not a constant proof size padding round + gate_separators.partially_evaluate(round_challenge, dummy_round); + + } else { + if (round_idx < multivariate_d) { + gate_separators.partially_evaluate(round_challenge); + } + } + } + + if constexpr (IsRecursiveFlavor) { + verified = + (round_univariate_evaluations[0][0].get_value() + round_univariate_evaluations[0][1].get_value() == + round.target_total_sum.get_value()); + } else { + verified = verified && (round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1] == + round.target_total_sum); + } + + // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge + const FF libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); + const FF full_libra_purported_value = libra_evaluation * libra_challenge; + + // Final round + ClaimedEvaluations purported_evaluations; + auto transcript_evaluations = + transcript->template receive_from_prover>("Sumcheck:evaluations"); + for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), transcript_evaluations)) { + eval = transcript_eval; + } + // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge + RowDisablingPolynomial row_disabler = RowDisablingPolynomial(); + const FF correcting_factor = row_disabler.evaluate_at_challenge(multivariate_challenge, multivariate_d); + // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover polynomials. + // In ZK Flavors, the evaluation is corrected by full_libra_purported_value + const FF full_honk_purported_value = round.compute_full_relation_purported_value(purported_evaluations, + relation_parameters, + gate_separators, + alpha, + full_libra_purported_value, + correcting_factor); + //! [Final Verification Step] + // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output + return SumcheckOutput{ round_univariate_commitments, + round_univariate_evaluations, + multivariate_challenge, + purported_evaluations, + libra_evaluation, + full_honk_purported_value, + verified }; + }; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp index ea0c014a615..d5f6d6f2316 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp @@ -28,7 +28,10 @@ template struct SumcheckOutput { * * @tparam Flavor */ -template struct SumcheckOutput>> { +template +struct SumcheckOutput< + Flavor, + std::enable_if_t && !(std::is_same_v || IsECCVMRecursiveFlavor)>> { using FF = typename Flavor::FF; using ClaimedEvaluations = typename Flavor::AllValues; // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ @@ -41,4 +44,25 @@ template struct SumcheckOutput verified = false; // Optional b/c this struct is shared by the Prover/Verifier }; + +template +struct SumcheckOutput || IsECCVMRecursiveFlavor>> { + using FF = typename Flavor::FF; + using ClaimedEvaluations = typename Flavor::AllValues; + using Commitment = typename Flavor::Commitment; + + std::vector round_univariate_commitments; + std::vector> round_univariate_evaluations; + // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ + std::vector challenge; + // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck + ClaimedEvaluations claimed_evaluations; + // For ZK Flavors: the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges + FF claimed_libra_evaluation; + + std::optional full_honk_purported_value = std::nullopt; + // Whether or not the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N \f$ and final Sumcheck evaluation + // have been confirmed + std::optional verified = false; // Optional b/c this struct is shared by the Prover/Verifier +}; } // namespace bb From 1b18f0581277c40229efb298230643f2fd1a434f Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 10 Jan 2025 17:58:15 +0000 Subject: [PATCH 02/33] wip wip --- .../commitment_schemes/shplonk/shplemini.hpp | 19 ++++++ .../src/barretenberg/eccvm/eccvm_verifier.cpp | 6 +- .../src/barretenberg/sumcheck/sumcheck.hpp | 65 +++++++++++++------ .../barretenberg/sumcheck/sumcheck_output.hpp | 27 ++++++-- 4 files changed, 90 insertions(+), 27 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 33075943661..5b40040bcad 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -31,11 +31,15 @@ template class ShpleminiProver_ { const std::shared_ptr>& commitment_key, const std::shared_ptr& transcript, const std::array& libra_polynomials = {}, + const std::vector sumcheck_round_univariates = {}, + const std::vector> sumcheck_round_evaluations = {}, RefSpan concatenated_polynomials = {}, const std::vector>& groups_to_be_concatenated = {}) { // While Shplemini is not templated on Flavor, we derive ZK flag this way const bool has_zk = (libra_polynomials[0].size() > 0); + const bool is_eccvm = (!sumcheck_round_univariates.empty()); + std::vector opening_claims = GeminiProver::prove(circuit_size, f_polynomials, g_polynomials, @@ -47,7 +51,22 @@ template class ShpleminiProver_ { has_zk); // Create opening claims for Libra masking univariates std::vector libra_opening_claims; + std::vector sumcheck_round_claims; OpeningClaim new_claim; + if (is_eccvm) { + + const size_t log_circuit_size = numeric::get_msb(static_cast(circuit_size)); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + const std::vector evaluation_points = { FF(0), FF(1), multilinear_challenge[idx] }; + size_t eval_idx = 0; + for (auto& eval_point : evaluation_points) { + new_claim.polynomial = sumcheck_round_univariates[idx]; + new_claim.opening_pair.challenge = eval_point; + new_claim.opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx]; + eval_idx++; + } + } + } if (has_zk) { static constexpr FF subgroup_generator = Curve::subgroup_generator; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index fd904a3b20d..2ad4a658038 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -65,7 +65,7 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); // If Sumcheck did not verify, return false - if (sumcheck_output.verified.has_value() && !sumcheck_output.verified.value()) { + if (!sumcheck_output.verified) { vinfo("eccvm sumcheck failed"); return false; } @@ -133,8 +133,8 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) const bool batched_opening_verified = PCS::reduce_verify(key->pcs_verification_key, batch_opening_claim, ipa_transcript); - vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified.value()); + vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified); vinfo("batch opening verified?: ", batched_opening_verified); - return sumcheck_output.verified.value() && batched_opening_verified && consistency_checked; + return sumcheck_output.verified && batched_opening_verified && consistency_checked; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 2e103352444..5cfada85630 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -148,7 +148,9 @@ template class SumcheckProver { static constexpr bool IS_ECCVM = std::is_same_v; std::vector round_univariate_commitments = {}; - std::vector> round_univariate_evaluations = {}; + std::vector> round_univariate_evaluations = {}; + std::vector> round_univariates = {}; + std::vector eval_domain = {}; /** * @@ -282,6 +284,11 @@ template class SumcheckProver { row_disabling_polynomial); vinfo("starting sumcheck rounds..."); { + if constexpr (IS_ECCVM) { + for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) { + eval_domain.push_back(FF(idx)); + } + } PROFILE_THIS_NAME("rest of sumcheck round 1"); @@ -289,18 +296,30 @@ template class SumcheckProver { // Place the evaluations of the round univariate into transcript. transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); } else { - auto round_univariate_commitment = - ck->commit(Polynomial(std::span(round_univariate.evaluations))); + // To commit using monomial srs, need to transform to monomial form + Polynomial round_poly_monomial = Polynomial( + eval_domain, std::span(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH); + auto round_univariate_commitment = ck->commit(round_poly_monomial); transcript->send_to_verifier("Sumcheck:univariate_comm_0", round_univariate_commitment); - round_univariate_commitments.push_back(std::move(round_univariate_commitment)); + // Store round univariate in monomial, as it is required for Shplonk + round_univariates.push_back(std::move(round_poly_monomial)); + + // Send the evaluations of the rounds univariate at 0 and 1 transcript->send_to_verifier("Sumcheck:univariate_0_eval_0", round_univariate.value_at(0)); transcript->send_to_verifier("Sumcheck:univariate_0_eval_1", round_univariate.value_at(1)); - round_univariate_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1) }); + + // Store the evaluations to be used in Shplonk. Third value will be computed after getting the round + // challenge + round_univariate_evaluations.push_back( + { round_univariate.value_at(0), round_univariate.value_at(1), FF(0) }); } FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); + // Store the evaluation at the challenge. Could be optimized + round_univariate_evaluations[0][2] = round_univariate.evaluate(round_challenge); + multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round partially_evaluate(full_polynomials, multivariate_n, round_challenge); @@ -334,12 +353,14 @@ template class SumcheckProver { round_univariate.value_at(0)); transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_1", round_univariate.value_at(1)); - round_univariate_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1) }); + round_univariate_evaluations.push_back( + { round_univariate.value_at(0), round_univariate.value_at(1), FF(0) }); info("prover evals ", round_univariate.value_at(0) + round_univariate.value_at(1)); } FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + round_univariate_evaluations[round_idx][2] = round_univariate.evaluate(round_challenge); info("prover eval at challenge", round_idx, " ", round_univariate.evaluate(round_challenge)); multivariate_challenge.emplace_back(round_challenge); @@ -364,7 +385,7 @@ template class SumcheckProver { ck->commit(Polynomial(std::span(zero_univariate)))); transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx) + "_eval_0", FF(0)); transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx) + "_eval_1", FF(0)); - round_univariate_evaluations.push_back({ FF(0), FF(0) }); + round_univariate_evaluations.push_back({ FF(0), FF(0), FF(0) }); } FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(idx)); multivariate_challenge.emplace_back(round_challenge); @@ -392,7 +413,7 @@ template class SumcheckProver { } else { info("last sumcheck challenge, ", multivariate_challenge.back()); - return SumcheckOutput{ round_univariate_commitments, + return SumcheckOutput{ round_univariates, round_univariate_evaluations, multivariate_challenge, multivariate_evaluations, @@ -617,7 +638,7 @@ template class SumcheckVerifier { static constexpr bool IS_ECCVM = std::is_same_v || IsECCVMRecursiveFlavor; std::vector round_univariate_commitments = {}; - std::vector> round_univariate_evaluations = {}; + std::vector> round_univariate_evaluations = {}; // 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) @@ -758,9 +779,9 @@ template class SumcheckVerifier { * @param gate_challenges * @return SumcheckOutput */ - SumcheckOutput verify(const bb::RelationParameters& relation_parameters, - RelationSeparator alpha, - const std::vector& gate_challenges) + SumcheckVerifierOutput verify(const bb::RelationParameters& relation_parameters, + RelationSeparator alpha, + const std::vector& gate_challenges) requires std::is_same_v || IsECCVMRecursiveFlavor { bool verified(true); @@ -816,6 +837,12 @@ template class SumcheckVerifier { } } + // Populate claimed evaluations at the challenge + for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + round_univariate_evaluations[round_idx][2] = + round_univariate_evaluations[round_idx - 1][0] + round_univariate_evaluations[round_idx - 1][1]; + } + if constexpr (IsRecursiveFlavor) { verified = (round_univariate_evaluations[0][0].get_value() + round_univariate_evaluations[0][1].get_value() == @@ -849,13 +876,13 @@ template class SumcheckVerifier { correcting_factor); //! [Final Verification Step] // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output - return SumcheckOutput{ round_univariate_commitments, - round_univariate_evaluations, - multivariate_challenge, - purported_evaluations, - libra_evaluation, - full_honk_purported_value, - verified }; + return SumcheckVerifierOutput{ round_univariate_commitments, + round_univariate_evaluations, + multivariate_challenge, + purported_evaluations, + libra_evaluation, + full_honk_purported_value, + verified }; }; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp index d5f6d6f2316..77ac62d390b 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/polynomials/polynomial.hpp" #include #include #include @@ -45,14 +46,13 @@ struct SumcheckOutput< std::optional verified = false; // Optional b/c this struct is shared by the Prover/Verifier }; -template -struct SumcheckOutput || IsECCVMRecursiveFlavor>> { +template struct SumcheckVerifierOutput { using FF = typename Flavor::FF; using ClaimedEvaluations = typename Flavor::AllValues; using Commitment = typename Flavor::Commitment; std::vector round_univariate_commitments; - std::vector> round_univariate_evaluations; + std::vector> round_univariate_evaluations; // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ std::vector challenge; // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck @@ -60,9 +60,26 @@ struct SumcheckOutput full_honk_purported_value = std::nullopt; + FF full_honk_purported_value; // Whether or not the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N \f$ and final Sumcheck evaluation // have been confirmed - std::optional verified = false; // Optional b/c this struct is shared by the Prover/Verifier + bool verified; // Optional b/c this struct is shared by the Prover/Verifier +}; + +template +struct SumcheckOutput || IsECCVMRecursiveFlavor>> { + using FF = typename Flavor::FF; + using ClaimedEvaluations = typename Flavor::AllValues; + using Commitment = typename Flavor::Commitment; + + std::vector> round_univariates; + std::vector> round_univariate_evaluations; + + // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ + std::vector challenge; + // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck + ClaimedEvaluations claimed_evaluations; + // For ZK Flavors: the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges + FF claimed_libra_evaluation; }; } // namespace bb From e00dd04333c420f736572262f8428d82bbad9cbe Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 14 Jan 2025 10:01:41 +0000 Subject: [PATCH 03/33] eccvm verifies --- .../commitment_schemes/shplonk/shplemini.hpp | 81 ++++++++++++++++++- .../commitment_schemes/shplonk/shplonk.hpp | 44 ++++++++-- .../src/barretenberg/eccvm/eccvm_prover.cpp | 4 +- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 4 +- .../src/barretenberg/sumcheck/sumcheck.hpp | 74 +++++++++-------- 5 files changed, 162 insertions(+), 45 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 5b40040bcad..6baacf7f03b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -23,7 +23,7 @@ template class ShpleminiProver_ { using ShplonkProver = ShplonkProver_; using GeminiProver = GeminiProver_; - template + template static OpeningClaim prove(const FF circuit_size, RefSpan f_polynomials, RefSpan g_polynomials, @@ -52,6 +52,8 @@ template class ShpleminiProver_ { // Create opening claims for Libra masking univariates std::vector libra_opening_claims; std::vector sumcheck_round_claims; + + info(sumcheck_round_univariates.size()); OpeningClaim new_claim; if (is_eccvm) { @@ -59,10 +61,12 @@ template class ShpleminiProver_ { for (size_t idx = 0; idx < log_circuit_size; idx++) { const std::vector evaluation_points = { FF(0), FF(1), multilinear_challenge[idx] }; size_t eval_idx = 0; + new_claim.polynomial = std::move(sumcheck_round_univariates[idx]); + for (auto& eval_point : evaluation_points) { - new_claim.polynomial = sumcheck_round_univariates[idx]; new_claim.opening_pair.challenge = eval_point; new_claim.opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx]; + sumcheck_round_claims.push_back(new_claim); eval_idx++; } } @@ -85,8 +89,8 @@ template class ShpleminiProver_ { } } - const OpeningClaim batched_claim = - ShplonkProver::prove(commitment_key, opening_claims, transcript, libra_opening_claims); + const OpeningClaim batched_claim = ShplonkProver::prove( + commitment_key, opening_claims, transcript, libra_opening_claims, sumcheck_round_claims); return batched_claim; }; }; @@ -169,6 +173,8 @@ template class ShpleminiVerifier_ { // Shplemini Refactoring: Remove bool pointer const std::array& libra_commitments = {}, const Fr& libra_univariate_evaluation = Fr{ 0 }, + const std::vector& sumcheck_round_commitments = {}, + const std::vector>& sumcheck_round_evaluations = {}, const std::vector>& concatenation_group_commitments = {}, RefSpan concatenated_evaluations = {}) @@ -346,6 +352,16 @@ template class ShpleminiVerifier_ { libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation); } + if (!sumcheck_round_evaluations.empty()) { + batch_sumcheck_round_claims(log_circuit_size, + commitments, + scalars, + multivariate_challenge, + shplonk_batching_challenge, + shplonk_evaluation_challenge, + sumcheck_round_commitments, + sumcheck_round_evaluations); + } return { commitments, scalars, shplonk_evaluation_challenge }; }; /** @@ -683,5 +699,62 @@ template class ShpleminiVerifier_ { scalars.push_back(batching_scalars[1] + batching_scalars[2]); scalars.push_back(batching_scalars[3]); } + + static void batch_sumcheck_round_claims(const size_t log_circuit_size, + std::vector& commitments, + std::vector& scalars, + const std::vector& multilinear_challenge, + const Fr& shplonk_batching_challenge, + const Fr& shplonk_evaluation_challenge, + const std::vector& sumcheck_round_commitments, + const std::vector>& sumcheck_round_evaluations) + { + std::vector round_commitments = {}; + std::vector truncated_challenge = {}; + std::vector> round_evals = {}; + + for (size_t idx = 0; idx < log_circuit_size; idx++) { + round_commitments.emplace_back(sumcheck_round_commitments[idx]); + round_evals.emplace_back(sumcheck_round_evaluations[idx]); + truncated_challenge.emplace_back(multilinear_challenge[idx]); + } + + std::vector denominators = {}; + Fr shplonk_challenge_power = Fr{ 1 }; + for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_LIBRA_COMMITMENTS + 1; ++j) { + shplonk_challenge_power *= shplonk_batching_challenge; + } + + Fr& constant_term = scalars[scalars.size() - 4]; + + std::array const_denominators; + + const_denominators[0] = Fr(1) / (shplonk_evaluation_challenge); + const_denominators[1] = Fr(1) / (shplonk_evaluation_challenge - Fr{ 1 }); + + for (const auto& [challenge, comm] : zip_view(truncated_challenge, round_commitments)) { + denominators.push_back(shplonk_evaluation_challenge - challenge); + commitments.push_back(comm); + } + + Fr::batch_invert(denominators); + for (const auto& [eval_array, denominator] : zip_view(round_evals, denominators)) { + Fr batched_scaling_factor = Fr(0); + for (size_t idx = 0; idx < 2; idx++) { + Fr current_scaling_factor = const_denominators[idx] * shplonk_challenge_power; + batched_scaling_factor -= current_scaling_factor; + shplonk_challenge_power *= shplonk_batching_challenge; + constant_term += current_scaling_factor * eval_array[idx]; + } + Fr current_scaling_factor = denominator * shplonk_challenge_power; + + batched_scaling_factor -= current_scaling_factor; + shplonk_challenge_power *= shplonk_batching_challenge; + + constant_term += current_scaling_factor * eval_array[2]; + + scalars.push_back(batched_scaling_factor); + } + }; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index 65b0fca780d..d1ffb1235ff 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -41,7 +41,8 @@ template class ShplonkProver_ { */ static Polynomial compute_batched_quotient(std::span> opening_claims, const Fr& nu, - std::span> libra_opening_claims) + std::span> libra_opening_claims, + std::span> sumcheck_round_claims) { // Find n, the maximum size of all polynomials fⱼ(X) size_t max_poly_size{ 0 }; @@ -86,6 +87,20 @@ template class ShplonkProver_ { Q.add_scaled(tmp, current_nu); current_nu *= nu; } + // size_t counter = 0; + for (const auto& claim : sumcheck_round_claims) { + + // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) + tmp = claim.polynomial; + tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; + // info("prover const term", tmp.at(0)); + tmp.factor_roots(claim.opening_pair.challenge); + + // Add the claim quotient to the batched quotient polynomial + Q.add_scaled(tmp, current_nu); + current_nu *= nu; + // counter++; + } // Return batched quotient polynomial Q(X) return Q; }; @@ -105,7 +120,8 @@ template class ShplonkProver_ { Polynomial& batched_quotient_Q, const Fr& nu_challenge, const Fr& z_challenge, - std::span> libra_opening_claims = {}) + std::span> libra_opening_claims = {}, + std::span> sumcheck_opening_claims = {}) { const size_t num_opening_claims = opening_claims.size(); @@ -120,6 +136,11 @@ template class ShplonkProver_ { for (const auto& claim : libra_opening_claims) { inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge); } + + for (const auto& claim : sumcheck_opening_claims) { + inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge); + } + Fr::batch_invert(inverse_vanishing_evals); // G(X) = Q(X) - Q_z(X) = Q(X) - ∑ⱼ νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ), @@ -160,6 +181,17 @@ template class ShplonkProver_ { idx++; current_nu *= nu_challenge; } + + for (const auto& claim : sumcheck_opening_claims) { + tmp = claim.polynomial; + tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ ) + + // Add the claim quotient to the batched quotient polynomial + G.add_scaled(tmp, -scaling_factor); + idx++; + current_nu *= nu_challenge; + } // Return opening pair (z, 0) and polynomial G(X) = Q(X) - Q_z(X) return { .polynomial = G, .opening_pair = { .challenge = z_challenge, .evaluation = Fr::zero() } }; }; @@ -177,15 +209,17 @@ template class ShplonkProver_ { static ProverOpeningClaim prove(const std::shared_ptr>& commitment_key, std::span> opening_claims, const std::shared_ptr& transcript, - std::span> libra_opening_claims = {}) + std::span> libra_opening_claims = {}, + std::span> sumcheck_round_claims = {}) { const Fr nu = transcript->template get_challenge("Shplonk:nu"); - auto batched_quotient = compute_batched_quotient(opening_claims, nu, libra_opening_claims); + auto batched_quotient = + compute_batched_quotient(opening_claims, nu, libra_opening_claims, sumcheck_round_claims); auto batched_quotient_commitment = commitment_key->commit(batched_quotient); transcript->send_to_verifier("Shplonk:Q", batched_quotient_commitment); const Fr z = transcript->template get_challenge("Shplonk:z"); return compute_partially_evaluated_batched_quotient( - opening_claims, batched_quotient, nu, z, libra_opening_claims); + opening_claims, batched_quotient, nu, z, libra_opening_claims, sumcheck_round_claims); } }; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index 91464213235..6a01449960a 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -137,7 +137,9 @@ void ECCVMProver::execute_pcs_rounds() sumcheck_output.challenge, key->commitment_key, transcript, - small_subgroup_ipa_prover.get_witness_polynomials()); + small_subgroup_ipa_prover.get_witness_polynomials(), + sumcheck_output.round_univariates, + sumcheck_output.round_univariate_evaluations); // Get the challenge at which we evaluate all transcript polynomials as univariates evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 2ad4a658038..04a9a3a0d1b 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -85,7 +85,9 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) Flavor::HasZK, &consistency_checked, libra_commitments, - sumcheck_output.claimed_libra_evaluation); + sumcheck_output.claimed_libra_evaluation, + sumcheck_output.round_univariate_commitments, + sumcheck_output.round_univariate_evaluations); // Reduce the accumulator to a single opening claim const OpeningClaim multivariate_to_univariate_opening_claim = diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 5cfada85630..ce499f922df 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -296,29 +296,15 @@ template class SumcheckProver { // Place the evaluations of the round univariate into transcript. transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); } else { - // To commit using monomial srs, need to transform to monomial form - Polynomial round_poly_monomial = Polynomial( - eval_domain, std::span(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH); - auto round_univariate_commitment = ck->commit(round_poly_monomial); - transcript->send_to_verifier("Sumcheck:univariate_comm_0", round_univariate_commitment); - - // Store round univariate in monomial, as it is required for Shplonk - round_univariates.push_back(std::move(round_poly_monomial)); - - // Send the evaluations of the rounds univariate at 0 and 1 - transcript->send_to_verifier("Sumcheck:univariate_0_eval_0", round_univariate.value_at(0)); - transcript->send_to_verifier("Sumcheck:univariate_0_eval_1", round_univariate.value_at(1)); - - // Store the evaluations to be used in Shplonk. Third value will be computed after getting the round - // challenge - round_univariate_evaluations.push_back( - { round_univariate.value_at(0), round_univariate.value_at(1), FF(0) }); + commit_to_round_univariate( + round_univariate, eval_domain, transcript, ck, round_univariates, round_univariate_evaluations); } - FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); + const FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); // Store the evaluation at the challenge. Could be optimized round_univariate_evaluations[0][2] = round_univariate.evaluate(round_challenge); + info("prover eval at challenge", round_idx, " ", round_univariate.evaluate(round_challenge)); multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round @@ -347,18 +333,11 @@ template class SumcheckProver { // Place evaluations of Sumcheck Round Univariate in the transcript transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); } else { - transcript->send_to_verifier("Sumcheck:univariate_comm_" + std::to_string(round_idx), - ck->commit(Polynomial(std::span(round_univariate.evaluations)))); - transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_0", - round_univariate.value_at(0)); - transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_1", - round_univariate.value_at(1)); - round_univariate_evaluations.push_back( - { round_univariate.value_at(0), round_univariate.value_at(1), FF(0) }); - - info("prover evals ", round_univariate.value_at(0) + round_univariate.value_at(1)); + commit_to_round_univariate( + round_univariate, eval_domain, transcript, ck, round_univariates, round_univariate_evaluations); } - FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + const FF round_challenge = + transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); round_univariate_evaluations[round_idx][2] = round_univariate.evaluate(round_challenge); info("prover eval at challenge", round_idx, " ", round_univariate.evaluate(round_challenge)); @@ -385,7 +364,6 @@ template class SumcheckProver { ck->commit(Polynomial(std::span(zero_univariate)))); transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx) + "_eval_0", FF(0)); transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx) + "_eval_1", FF(0)); - round_univariate_evaluations.push_back({ FF(0), FF(0), FF(0) }); } FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(idx)); multivariate_challenge.emplace_back(round_challenge); @@ -411,8 +389,6 @@ template class SumcheckProver { if constexpr (!IS_ECCVM) { return SumcheckOutput{ multivariate_challenge, multivariate_evaluations, libra_evaluation }; } else { - info("last sumcheck challenge, ", multivariate_challenge.back()); - return SumcheckOutput{ round_univariates, round_univariate_evaluations, multivariate_challenge, @@ -561,6 +537,30 @@ polynomials that are sent in clear. } }; } + + void commit_to_round_univariate(bb::Univariate& round_univariate, + const std::vector& eval_domain, + const std::shared_ptr& transcript, + const std::shared_ptr& ck, + std::vector>& round_univariates, + std::vector>& round_univariate_evaluations) + { + Polynomial round_poly_monomial = + Polynomial(eval_domain, std::span(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH); + auto round_univariate_commitment = ck->commit(round_poly_monomial); + transcript->send_to_verifier("Sumcheck:univariate_comm_0", round_univariate_commitment); + + // Store round univariate in monomial, as it is required for Shplonk + round_univariates.push_back(std::move(round_poly_monomial)); + + // Send the evaluations of the rounds univariate at 0 and 1 + transcript->send_to_verifier("Sumcheck:univariate_0_eval_0", round_univariate.value_at(0)); + transcript->send_to_verifier("Sumcheck:univariate_0_eval_1", round_univariate.value_at(1)); + + // Store the evaluations to be used in Shplonk. Third value will be computed after getting the round + // challenge + round_univariate_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1), FF(0) }); + } }; /*! \brief Implementation of the sumcheck Verifier for statements of the form \f$\sum_{\vec \ell \in \{0,1\}^d} pow_{\beta}(\vec \ell) \cdot F \left(P_1(\vec \ell),\ldots, P_N(\vec \ell) \right) = 0 \f$ for multilinear @@ -839,8 +839,8 @@ template class SumcheckVerifier { // Populate claimed evaluations at the challenge for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - round_univariate_evaluations[round_idx][2] = - round_univariate_evaluations[round_idx - 1][0] + round_univariate_evaluations[round_idx - 1][1]; + round_univariate_evaluations[round_idx - 1][2] = + round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; } if constexpr (IsRecursiveFlavor) { @@ -874,6 +874,12 @@ template class SumcheckVerifier { alpha, full_libra_purported_value, correcting_factor); + + round_univariate_evaluations[multivariate_d - 1][2] = full_honk_purported_value; + info("last eval at 0", round_univariate_evaluations[multivariate_d - 1][0]); + info("last eval at 1", round_univariate_evaluations[multivariate_d - 1][1]); + info("last eval at challenge", round_univariate_evaluations[multivariate_d - 1][2]); + //! [Final Verification Step] // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output return SumcheckVerifierOutput{ round_univariate_commitments, From 682c0752c97fd4564960abb8331ba97ee0c09a90 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 14 Jan 2025 13:25:35 +0000 Subject: [PATCH 04/33] build fixed recursion failing --- .../commitment_schemes/kzg/kzg.test.cpp | 2 ++ .../commitment_schemes/shplonk/shplemini.hpp | 9 +++++++-- .../eccvm_verifier/eccvm_recursive_verifier.cpp | 15 ++++++++------- .../translator_recursive_verifier.cpp | 2 ++ .../translator_vm/translator_prover.cpp | 2 ++ .../translator_vm/translator_verifier.cpp | 2 ++ 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp index dcf3b4fe315..1612747e470 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp @@ -324,6 +324,8 @@ TYPED_TEST(KZGTest, ShpleminiKzgWithShiftAndConcatenation) &consistency_checked, /* libra commitments = */ {}, /* libra evaluations = */ {}, + {}, + {}, to_vector_of_ref_vectors(concatenation_groups_commitments), RefVector(c_evaluations)); const auto pairing_points = KZG::reduce_verify_batch_opening_claim(batch_opening_claim, verifier_transcript); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 6baacf7f03b..8b66293ecaf 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -736,8 +736,13 @@ template class ShpleminiVerifier_ { denominators.push_back(shplonk_evaluation_challenge - challenge); commitments.push_back(comm); } - - Fr::batch_invert(denominators); + if constexpr (!Curve::is_stdlib_type) { + Fr::batch_invert(denominators); + } else { + for (auto& denominator : denominators) { + denominator = Fr{ 1 } / denominator; + } + } for (const auto& [eval_array, denominator] : zip_view(round_evals, denominators)) { Fr batched_scaling_factor = Fr(0); for (size_t idx = 0; idx < 2; idx++) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index 248fa30346e..57a56b33226 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -80,8 +80,7 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) libra_commitments[0] = transcript->template receive_from_prover("Libra:concatenation_commitment"); - auto [multivariate_challenge, claimed_evaluations, claimed_libra_evaluation, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, gate_challenges); + auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); @@ -93,16 +92,18 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) Shplemini::compute_batch_opening_claim(circuit_size, commitments.get_unshifted(), commitments.get_to_be_shifted(), - claimed_evaluations.get_unshifted(), - claimed_evaluations.get_shifted(), - multivariate_challenge, + sumcheck_output.claimed_evaluations.get_unshifted(), + sumcheck_output.claimed_evaluations.get_shifted(), + sumcheck_output.challenge, key->pcs_verification_key->get_g1_identity(), transcript, Flavor::REPEATED_COMMITMENTS, Flavor::HasZK, &consistency_checked, libra_commitments, - claimed_libra_evaluation); + sumcheck_output.claimed_libra_evaluation, + sumcheck_output.round_univariate_commitments, + sumcheck_output.round_univariate_evaluations); // Reduce the accumulator to a single opening claim const OpeningClaim multivariate_to_univariate_opening_claim = @@ -148,7 +149,7 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) const OpeningClaim batch_opening_claim = Shplonk::reduce_verification(key->pcs_verification_key->get_g1_identity(), opening_claims, transcript); - ASSERT(sumcheck_verified); + ASSERT(sumcheck_output.verified); return { batch_opening_claim, ipa_transcript }; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp index c0cbacf2e92..5de989d8c62 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp @@ -136,6 +136,8 @@ std::array TranslatorRecursiveVerifier_proving_key->commitment_key, transcript, small_subgroup_ipa_prover.get_witness_polynomials(), + {}, + {}, key->proving_key->polynomials.get_concatenated(), key->proving_key->polynomials.get_groups_to_be_concatenated()); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp index 4cff080cf23..22ea3c8e8e2 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp @@ -129,6 +129,8 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) &consistency_checked, libra_commitments, libra_evaluation, + {}, + {}, commitments.get_groups_to_be_concatenated(), claimed_evaluations.get_concatenated()); const auto pairing_points = PCS::reduce_verify_batch_opening_claim(opening_claim, transcript); From af6d6e6ed2563d6cdda3a66e1a8bc10be9d7e625 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 14 Jan 2025 14:29:04 +0000 Subject: [PATCH 05/33] debugging rec verifier --- .../eccvm_recursive_verifier.cpp | 1 + .../cpp/src/barretenberg/sumcheck/sumcheck.hpp | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index 57a56b33226..d4f33adc408 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -81,6 +81,7 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) libra_commitments[0] = transcript->template receive_from_prover("Libra:concatenation_commitment"); auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); + info("verified? in eccvm rec verifier ", sumcheck_output.verified); libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index ce499f922df..c07e1e95e4f 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -304,7 +304,6 @@ template class SumcheckProver { // Store the evaluation at the challenge. Could be optimized round_univariate_evaluations[0][2] = round_univariate.evaluate(round_challenge); - info("prover eval at challenge", round_idx, " ", round_univariate.evaluate(round_challenge)); multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round @@ -340,7 +339,6 @@ template class SumcheckProver { transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); round_univariate_evaluations[round_idx][2] = round_univariate.evaluate(round_challenge); - info("prover eval at challenge", round_idx, " ", round_univariate.evaluate(round_challenge)); multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round @@ -841,12 +839,19 @@ template class SumcheckVerifier { for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { round_univariate_evaluations[round_idx - 1][2] = round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; + if constexpr (IsRecursiveFlavor) { + round_univariate_evaluations[round_idx - 1][2].self_reduce(); + }; } if constexpr (IsRecursiveFlavor) { - verified = - (round_univariate_evaluations[0][0].get_value() + round_univariate_evaluations[0][1].get_value() == - round.target_total_sum.get_value()); + FF first_sumcheck_round_evaluations_sum = + round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; + first_sumcheck_round_evaluations_sum.self_reduce(); + round.target_total_sum.self_reduce(); + + verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); + info("verified?", verified); } else { verified = verified && (round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1] == round.target_total_sum); @@ -876,9 +881,6 @@ template class SumcheckVerifier { correcting_factor); round_univariate_evaluations[multivariate_d - 1][2] = full_honk_purported_value; - info("last eval at 0", round_univariate_evaluations[multivariate_d - 1][0]); - info("last eval at 1", round_univariate_evaluations[multivariate_d - 1][1]); - info("last eval at challenge", round_univariate_evaluations[multivariate_d - 1][2]); //! [Final Verification Step] // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output From 9323abe6e3e2659357b79603df54cc69c4ba5797 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 14 Jan 2025 15:59:31 +0000 Subject: [PATCH 06/33] recursion fix --- .../cpp/src/barretenberg/sumcheck/sumcheck.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index c07e1e95e4f..91e3252d1d4 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -301,9 +301,10 @@ template class SumcheckProver { } const FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); - - // Store the evaluation at the challenge. Could be optimized - round_univariate_evaluations[0][2] = round_univariate.evaluate(round_challenge); + if constexpr (IS_ECCVM) { + // Store the evaluation at the challenge. Could be optimized + round_univariate_evaluations[0][2] = round_univariate.evaluate(round_challenge); + } multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round @@ -337,8 +338,10 @@ template class SumcheckProver { } const FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); - - round_univariate_evaluations[round_idx][2] = round_univariate.evaluate(round_challenge); + if constexpr (IS_ECCVM) { + // Store the evaluation at the challenge. Could be optimized + round_univariate_evaluations[round_idx][2] = round_univariate.evaluate(round_challenge); + } multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round @@ -849,7 +852,7 @@ template class SumcheckVerifier { round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; first_sumcheck_round_evaluations_sum.self_reduce(); round.target_total_sum.self_reduce(); - + first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); info("verified?", verified); } else { From 230ce10158fe2667bbfaea7d3b8b1915d233ec83 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 14 Jan 2025 17:53:03 +0000 Subject: [PATCH 07/33] sumcheck output unified --- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 2 +- .../eccvm_recursive_verifier.cpp | 2 +- .../decider_recursive_verifier.cpp | 23 ++++--- .../translator_recursive_verifier.cpp | 13 ++-- .../src/barretenberg/sumcheck/sumcheck.hpp | 46 +++++++------ .../barretenberg/sumcheck/sumcheck_output.hpp | 69 +++---------------- .../translator_vm/translator_verifier.cpp | 15 ++-- 7 files changed, 63 insertions(+), 107 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 04a9a3a0d1b..0b04b039a82 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -135,7 +135,7 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) const bool batched_opening_verified = PCS::reduce_verify(key->pcs_verification_key, batch_opening_claim, ipa_transcript); - vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified); + vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified.value()); vinfo("batch opening verified?: ", batched_opening_verified); return sumcheck_output.verified && batched_opening_verified && consistency_checked; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index d4f33adc408..d756797d910 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -81,7 +81,7 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) libra_commitments[0] = transcript->template receive_from_prover("Libra:concatenation_commitment"); auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); - info("verified? in eccvm rec verifier ", sumcheck_output.verified); + info("verified? in eccvm rec verifier ", sumcheck_output.verified.value()); libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/decider_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/decider_recursive_verifier.cpp index 3be2eb346a5..9dd4d65f43c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/decider_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/decider_recursive_verifier.cpp @@ -27,20 +27,21 @@ std::array DeciderRecursiveVerifier_:: auto sumcheck = Sumcheck( static_cast(accumulator->verification_key->log_circuit_size), transcript, accumulator->target_sum); - auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = + auto sumcheck_output = sumcheck.verify(accumulator->relation_parameters, accumulator->alphas, accumulator->gate_challenges); // Execute Shplemini rounds. - const auto opening_claim = Shplemini::compute_batch_opening_claim(accumulator->verification_key->circuit_size, - commitments.get_unshifted(), - commitments.get_to_be_shifted(), - claimed_evaluations.get_unshifted(), - claimed_evaluations.get_shifted(), - multivariate_challenge, - Commitment::one(builder), - transcript, - Flavor::REPEATED_COMMITMENTS, - Flavor::HasZK); + const auto opening_claim = + Shplemini::compute_batch_opening_claim(accumulator->verification_key->circuit_size, + commitments.get_unshifted(), + commitments.get_to_be_shifted(), + sumcheck_output.claimed_evaluations.get_unshifted(), + sumcheck_output.claimed_evaluations.get_shifted(), + sumcheck_output.challenge, + Commitment::one(builder), + transcript, + Flavor::REPEATED_COMMITMENTS, + Flavor::HasZK); auto pairing_points = PCS::reduce_verify_batch_opening_claim(opening_claim, transcript); return pairing_points; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp index 5de989d8c62..62a7b0643ea 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp @@ -114,8 +114,7 @@ std::array TranslatorRecursiveVerifier_ libra_commitments = {}; libra_commitments[0] = transcript->template receive_from_prover("Libra:concatenation_commitment"); - auto [multivariate_challenge, claimed_evaluations, libra_evaluation, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, gate_challenges); + auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); @@ -126,20 +125,20 @@ std::array TranslatorRecursiveVerifier_ class SumcheckProver { transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all()); // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output - return SumcheckOutput{ multivariate_challenge, multivariate_evaluations }; + return SumcheckOutput{ .challenge = multivariate_challenge, + .claimed_evaluations = multivariate_evaluations }; vinfo("finished sumcheck"); }; @@ -388,13 +389,15 @@ template class SumcheckProver { // The sum of the Libra constant term and the evaluations of Libra univariates at corresponding sumcheck // challenges is included in the Sumcheck Output if constexpr (!IS_ECCVM) { - return SumcheckOutput{ multivariate_challenge, multivariate_evaluations, libra_evaluation }; + return SumcheckOutput{ .challenge = multivariate_challenge, + .claimed_evaluations = multivariate_evaluations, + .claimed_libra_evaluation = libra_evaluation }; } else { - return SumcheckOutput{ round_univariates, - round_univariate_evaluations, - multivariate_challenge, - multivariate_evaluations, - libra_evaluation }; + return SumcheckOutput{ .challenge = multivariate_challenge, + .claimed_evaluations = multivariate_evaluations, + .claimed_libra_evaluation = libra_evaluation, + .round_univariates = round_univariates, + .round_univariate_evaluations = round_univariate_evaluations }; } vinfo("finished sumcheck"); }; @@ -759,9 +762,14 @@ template class SumcheckVerifier { verified = final_check && verified; // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output if constexpr (!Flavor::HasZK) { - return SumcheckOutput{ multivariate_challenge, purported_evaluations, verified }; + return SumcheckOutput{ .challenge = multivariate_challenge, + .claimed_evaluations = purported_evaluations, + .verified = verified }; } else { - return SumcheckOutput{ multivariate_challenge, purported_evaluations, libra_evaluation, verified }; + return SumcheckOutput{ .challenge = multivariate_challenge, + .claimed_evaluations = purported_evaluations, + .verified = verified, + .claimed_libra_evaluation = libra_evaluation }; } }; @@ -780,9 +788,9 @@ template class SumcheckVerifier { * @param gate_challenges * @return SumcheckOutput */ - SumcheckVerifierOutput verify(const bb::RelationParameters& relation_parameters, - RelationSeparator alpha, - const std::vector& gate_challenges) + SumcheckOutput verify(const bb::RelationParameters& relation_parameters, + RelationSeparator alpha, + const std::vector& gate_challenges) requires std::is_same_v || IsECCVMRecursiveFlavor { bool verified(true); @@ -854,7 +862,6 @@ template class SumcheckVerifier { round.target_total_sum.self_reduce(); first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); - info("verified?", verified); } else { verified = verified && (round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1] == round.target_total_sum); @@ -887,13 +894,12 @@ template class SumcheckVerifier { //! [Final Verification Step] // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output - return SumcheckVerifierOutput{ round_univariate_commitments, - round_univariate_evaluations, - multivariate_challenge, - purported_evaluations, - libra_evaluation, - full_honk_purported_value, - verified }; + return SumcheckOutput{ .challenge = multivariate_challenge, + .claimed_evaluations = purported_evaluations, + .verified = verified, + .claimed_libra_evaluation = libra_evaluation, + .round_univariate_commitments = round_univariate_commitments, + .round_univariate_evaluations = round_univariate_evaluations }; }; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp index 77ac62d390b..3c814eb3b76 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp @@ -12,74 +12,25 @@ namespace bb { * =(u_0,\ldots, u_{d-1})\f$. These are computed by \ref bb::SumcheckProver< Flavor > "Sumcheck Prover" and need to be * checked using Shplemini. */ -template struct SumcheckOutput { - using FF = typename Flavor::FF; - using ClaimedEvaluations = typename Flavor::AllValues; - // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ - std::vector challenge; - // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck - ClaimedEvaluations claimed_evaluations; - // Whether or not the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N \f$ and final Sumcheck evaluation - // have been confirmed - std::optional verified = false; // optional b/c this struct is shared by the Prover/Verifier -}; -/** - * @brief A modification of SumcheckOutput required by ZK Flavors where a vector of evaluations of Libra univariates is - * included. - * - * @tparam Flavor - */ -template -struct SumcheckOutput< - Flavor, - std::enable_if_t && !(std::is_same_v || IsECCVMRecursiveFlavor)>> { - using FF = typename Flavor::FF; - using ClaimedEvaluations = typename Flavor::AllValues; - // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ - std::vector challenge; - // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck - ClaimedEvaluations claimed_evaluations; - // For ZK Flavors: the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges - FF claimed_libra_evaluation; - // Whether or not the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N \f$ and final Sumcheck evaluation - // have been confirmed - std::optional verified = false; // Optional b/c this struct is shared by the Prover/Verifier -}; - -template struct SumcheckVerifierOutput { +template struct SumcheckOutput { using FF = typename Flavor::FF; using ClaimedEvaluations = typename Flavor::AllValues; using Commitment = typename Flavor::Commitment; - std::vector round_univariate_commitments; - std::vector> round_univariate_evaluations; // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ std::vector challenge; // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck ClaimedEvaluations claimed_evaluations; - // For ZK Flavors: the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges - FF claimed_libra_evaluation; - - FF full_honk_purported_value; // Whether or not the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N \f$ and final Sumcheck evaluation // have been confirmed - bool verified; // Optional b/c this struct is shared by the Prover/Verifier -}; - -template -struct SumcheckOutput || IsECCVMRecursiveFlavor>> { - using FF = typename Flavor::FF; - using ClaimedEvaluations = typename Flavor::AllValues; - using Commitment = typename Flavor::Commitment; - - std::vector> round_univariates; - std::vector> round_univariate_evaluations; - - // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ - std::vector challenge; - // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck - ClaimedEvaluations claimed_evaluations; + std::optional verified = false; // optional b/c this struct is shared by the Prover/Verifier // For ZK Flavors: the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges - FF claimed_libra_evaluation; + FF claimed_libra_evaluation = FF{ 0 }; + // For ECCVMVerifier: Commitments to round univariates + std::vector round_univariate_commitments; + // For ECCVMProver: Round univariates in monomial basis + std::vector> round_univariates = {}; + // For ECCVMProver/Verifier: evaluations of round univariates at 0, 1, and round challenge + std::vector> round_univariate_evaluations = {}; }; -} // namespace bb +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp index 22ea3c8e8e2..972a81f2979 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp @@ -102,11 +102,10 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) std::array libra_commitments = {}; libra_commitments[0] = transcript->template receive_from_prover("Libra:concatenation_commitment"); - auto [multivariate_challenge, claimed_evaluations, libra_evaluation, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, gate_challenges); + auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false - if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { + if (sumcheck_output.verified.has_value() && !sumcheck_output.verified.value()) { return false; } @@ -119,20 +118,20 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) Shplemini::compute_batch_opening_claim(circuit_size, commitments.get_unshifted_without_concatenated(), commitments.get_to_be_shifted(), - claimed_evaluations.get_unshifted_without_concatenated(), - claimed_evaluations.get_shifted(), - multivariate_challenge, + sumcheck_output.claimed_evaluations.get_unshifted_without_concatenated(), + sumcheck_output.claimed_evaluations.get_shifted(), + sumcheck_output.challenge, Commitment::one(), transcript, Flavor::REPEATED_COMMITMENTS, Flavor::HasZK, &consistency_checked, libra_commitments, - libra_evaluation, + sumcheck_output.claimed_libra_evaluation, {}, {}, commitments.get_groups_to_be_concatenated(), - claimed_evaluations.get_concatenated()); + sumcheck_output.claimed_evaluations.get_concatenated()); const auto pairing_points = PCS::reduce_verify_batch_opening_claim(opening_claim, transcript); auto verified = key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); From f1eb3c56cc5e25b4fc95c002ae9c52000a3543a5 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 15 Jan 2025 10:22:08 +0000 Subject: [PATCH 08/33] remove self reduce --- barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index f4279d1d768..02262c04843 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -850,16 +850,12 @@ template class SumcheckVerifier { for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { round_univariate_evaluations[round_idx - 1][2] = round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; - if constexpr (IsRecursiveFlavor) { - round_univariate_evaluations[round_idx - 1][2].self_reduce(); - }; } if constexpr (IsRecursiveFlavor) { FF first_sumcheck_round_evaluations_sum = round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; - first_sumcheck_round_evaluations_sum.self_reduce(); - round.target_total_sum.self_reduce(); + first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); } else { From 8cb98b0a296958c5078566f37b8010d149096dab Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 15 Jan 2025 17:19:45 +0000 Subject: [PATCH 09/33] trying to constify eccvm recursive --- .../commitment_schemes/shplonk/shplemini.hpp | 38 ++++++++----- .../src/barretenberg/sumcheck/sumcheck.hpp | 53 ++++++++++++------- 2 files changed, 59 insertions(+), 32 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 8b66293ecaf..4f9dd4c923f 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -709,15 +709,6 @@ template class ShpleminiVerifier_ { const std::vector& sumcheck_round_commitments, const std::vector>& sumcheck_round_evaluations) { - std::vector round_commitments = {}; - std::vector truncated_challenge = {}; - std::vector> round_evals = {}; - - for (size_t idx = 0; idx < log_circuit_size; idx++) { - round_commitments.emplace_back(sumcheck_round_commitments[idx]); - round_evals.emplace_back(sumcheck_round_evaluations[idx]); - truncated_challenge.emplace_back(multilinear_challenge[idx]); - } std::vector denominators = {}; Fr shplonk_challenge_power = Fr{ 1 }; @@ -732,7 +723,7 @@ template class ShpleminiVerifier_ { const_denominators[0] = Fr(1) / (shplonk_evaluation_challenge); const_denominators[1] = Fr(1) / (shplonk_evaluation_challenge - Fr{ 1 }); - for (const auto& [challenge, comm] : zip_view(truncated_challenge, round_commitments)) { + for (const auto& [challenge, comm] : zip_view(multilinear_challenge, sumcheck_round_commitments)) { denominators.push_back(shplonk_evaluation_challenge - challenge); commitments.push_back(comm); } @@ -743,23 +734,44 @@ template class ShpleminiVerifier_ { denominator = Fr{ 1 } / denominator; } } - for (const auto& [eval_array, denominator] : zip_view(round_evals, denominators)) { + size_t round_idx = 0; + for (const auto& [eval_array, denominator] : zip_view(sumcheck_round_evaluations, denominators)) { Fr batched_scaling_factor = Fr(0); + Fr const_term_contribution = Fr(0); + for (size_t idx = 0; idx < 2; idx++) { Fr current_scaling_factor = const_denominators[idx] * shplonk_challenge_power; batched_scaling_factor -= current_scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; - constant_term += current_scaling_factor * eval_array[idx]; + const_term_contribution += current_scaling_factor * eval_array[idx]; } Fr current_scaling_factor = denominator * shplonk_challenge_power; batched_scaling_factor -= current_scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; - constant_term += current_scaling_factor * eval_array[2]; + const_term_contribution += current_scaling_factor * eval_array[2]; + if constexpr (Curve::is_stdlib_type) { + auto builder = shplonk_batching_challenge.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! + stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= log_circuit_size); + Fr zero = Fr(0); + const_term_contribution = Fr::conditional_assign(dummy_round, zero, const_term_contribution); + batched_scaling_factor = Fr::conditional_assign(dummy_round, zero, batched_scaling_factor); + } else { + if (round_idx >= log_circuit_size) { + const_term_contribution = 0; + batched_scaling_factor = 0; + } + } + constant_term += const_term_contribution; scalars.push_back(batched_scaling_factor); + round_idx++; } + + info(commitments.size()); + info(scalars.size()); }; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 02262c04843..1013108a620 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -285,11 +285,6 @@ template class SumcheckProver { row_disabling_polynomial); vinfo("starting sumcheck rounds..."); { - if constexpr (IS_ECCVM) { - for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) { - eval_domain.push_back(FF(idx)); - } - } PROFILE_THIS_NAME("rest of sumcheck round 1"); @@ -297,6 +292,11 @@ template class SumcheckProver { // Place the evaluations of the round univariate into transcript. transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); } else { + + for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) { + eval_domain.push_back(FF(idx)); + } + commit_to_round_univariate( round_univariate, eval_domain, transcript, ck, round_univariates, round_univariate_evaluations); } @@ -336,14 +336,11 @@ template class SumcheckProver { } else { commit_to_round_univariate( round_univariate, eval_domain, transcript, ck, round_univariates, round_univariate_evaluations); + round_univariate_evaluations[round_idx - 1][2] = + round_univariate.value_at(0) + round_univariate.value_at(1); } const FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); - if constexpr (IS_ECCVM) { - // Store the evaluation at the challenge. Could be optimized - round_univariate_evaluations[round_idx][2] = round_univariate.evaluate(round_challenge); - } - multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round partially_evaluate(partially_evaluated_polynomials, round.round_size, round_challenge); @@ -354,6 +351,11 @@ template class SumcheckProver { gate_separators.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; } + + if constexpr (IS_ECCVM) { + round_univariate_evaluations[multivariate_d - 1][2] = + round_univariate.evaluate(multivariate_challenge[multivariate_d - 1]); + } vinfo("completed ", multivariate_d, " rounds of sumcheck"); // Zero univariates are used to pad the proof to the fixed size CONST_PROOF_SIZE_LOG_N. @@ -846,16 +848,11 @@ template class SumcheckVerifier { } } - // Populate claimed evaluations at the challenge - for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - round_univariate_evaluations[round_idx - 1][2] = - round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; - } - if constexpr (IsRecursiveFlavor) { FF first_sumcheck_round_evaluations_sum = round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; - + first_sumcheck_round_evaluations_sum.self_reduce(); + round.target_total_sum.self_reduce(); first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); } else { @@ -885,10 +882,28 @@ template class SumcheckVerifier { alpha, full_libra_purported_value, correcting_factor); + // Populate claimed evaluations at the challenge + for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + if constexpr (IsRecursiveFlavor) { - round_univariate_evaluations[multivariate_d - 1][2] = full_honk_purported_value; + FF claimed_sum = + round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; + typename Flavor::CircuitBuilder* builder = libra_evaluation.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! + stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); + round_univariate_evaluations[round_idx - 1][2] = + FF::conditional_assign(dummy_round, full_honk_purported_value, claimed_sum); + } else { + if (round_idx < multivariate_d) { + round_univariate_evaluations[round_idx - 1][2] = + round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; + ; + } else { + round_univariate_evaluations[round_idx - 1][2] = full_honk_purported_value; + } + } + } - //! [Final Verification Step] // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output return SumcheckOutput{ .challenge = multivariate_challenge, .claimed_evaluations = purported_evaluations, From c91f533d5408b8f524bf520b5d0279c3f58a30e4 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 16 Jan 2025 17:56:51 +0000 Subject: [PATCH 10/33] build fix --- barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp | 1 - barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 1d49c8dfff7..5df3e862353 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -862,7 +862,6 @@ template class SumcheckVerifier { eval = transcript_eval; } // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge - RowDisablingPolynomial row_disabler = RowDisablingPolynomial(); // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover polynomials. // In ZK Flavors, the evaluation is corrected by full_libra_purported_value FF full_honk_purported_value = round.compute_full_relation_purported_value( diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp index 3c814eb3b76..9b3ab52330b 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp @@ -27,7 +27,7 @@ template struct SumcheckOutput { // For ZK Flavors: the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges FF claimed_libra_evaluation = FF{ 0 }; // For ECCVMVerifier: Commitments to round univariates - std::vector round_univariate_commitments; + std::vector round_univariate_commitments = {}; // For ECCVMProver: Round univariates in monomial basis std::vector> round_univariates = {}; // For ECCVMProver/Verifier: evaluations of round univariates at 0, 1, and round challenge From 7c736668e0aad02845ea16c3db3860ff05aedc9b Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 16 Jan 2025 19:03:54 +0000 Subject: [PATCH 11/33] tests fixed --- .../commitment_schemes/shplonk/shplemini.hpp | 4 --- .../src/barretenberg/eccvm/eccvm_flavor.hpp | 15 ++++++--- .../eccvm/eccvm_transcript.test.cpp | 9 ++++-- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 2 +- .../eccvm_recursive_verifier.cpp | 1 - .../src/barretenberg/sumcheck/sumcheck.hpp | 31 ++++++++++--------- 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 9ec126286a6..6268331d42c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -53,7 +53,6 @@ template class ShpleminiProver_ { std::vector libra_opening_claims; std::vector sumcheck_round_claims; - info(sumcheck_round_univariates.size()); OpeningClaim new_claim; if (is_eccvm) { @@ -769,9 +768,6 @@ template class ShpleminiVerifier_ { scalars.push_back(batched_scaling_factor); round_idx++; } - - info(commitments.size()); - info(scalars.size()); }; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp index 37c0e0d7003..ee44fac3dcd 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp @@ -950,7 +950,8 @@ class ECCVMFlavor { Commitment lookup_inverses_comm; Commitment libra_concatenation_commitment; FF libra_sum; - std::vector> sumcheck_univariates; + std::array sumcheck_round_commitments; + std::array, CONST_PROOF_SIZE_LOG_N> sumcheck_round_evaluations; FF libra_claimed_evaluation; Commitment libra_big_sum_commitment; Commitment libra_quotient_commitment; @@ -1164,9 +1165,10 @@ class ECCVMFlavor { libra_sum = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N; ++i) { - sumcheck_univariates.emplace_back(NativeTranscript::template deserialize_from_buffer< - bb::Univariate>( - NativeTranscript::proof_data, num_frs_read)); + sumcheck_round_commitments[i] = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + sumcheck_round_evaluations[i] = NativeTranscript::template deserialize_from_buffer>( + NativeTranscript::proof_data, num_frs_read); } libra_claimed_evaluation = NativeTranscript::template deserialize_from_buffer(proof_data, num_frs_read); @@ -1318,7 +1320,10 @@ class ECCVMFlavor { NativeTranscript::template serialize_to_buffer(libra_sum, NativeTranscript::proof_data); for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N; ++i) { - NativeTranscript::template serialize_to_buffer(sumcheck_univariates[i], NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(sumcheck_round_commitments[i], + NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(sumcheck_round_evaluations[i], + NativeTranscript::proof_data); } NativeTranscript::template serialize_to_buffer(libra_claimed_evaluation, proof_data); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index bf1a8916c61..bb525da244f 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -29,11 +29,9 @@ class ECCVMTranscriptTests : public ::testing::Test { TranscriptManifest construct_eccvm_honk_manifest() { TranscriptManifest manifest_expected; - size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; // Size of types is number of bb::frs needed to represent the type size_t frs_per_Fr = bb::field_conversion::calc_num_bn254_frs(); size_t frs_per_G = bb::field_conversion::calc_num_bn254_frs(); - size_t frs_per_uni = MAX_PARTIAL_RELATION_LENGTH * frs_per_Fr; size_t frs_per_evals = (Flavor::NUM_ALL_ENTITIES)*frs_per_Fr; size_t frs_per_uint32 = bb::field_conversion::calc_num_bn254_frs(); @@ -146,7 +144,9 @@ class ECCVMTranscriptTests : public ::testing::Test { for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N; ++i) { round++; std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, frs_per_uni); + manifest_expected.add_entry(round, "Sumcheck:univariate_comm_" + idx, frs_per_G); + manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx + "_eval_0", frs_per_Fr); + manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx + "_eval_1", frs_per_Fr); std::string label = "Sumcheck:u_" + idx; manifest_expected.add_challenge(round, label); } @@ -284,6 +284,9 @@ TEST_F(ECCVMTranscriptTests, ProverManifestConsistency) auto manifest_expected = this->construct_eccvm_honk_manifest(); auto prover_manifest = prover.transcript->get_manifest(); + manifest_expected.print(); + info("====="); + prover_manifest.print(); // Note: a manifest can be printed using manifest.print() for (size_t round = 0; round < manifest_expected.size(); ++round) { ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 0b04b039a82..e03d175dd7c 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -137,6 +137,6 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) PCS::reduce_verify(key->pcs_verification_key, batch_opening_claim, ipa_transcript); vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified.value()); vinfo("batch opening verified?: ", batched_opening_verified); - return sumcheck_output.verified && batched_opening_verified && consistency_checked; + return sumcheck_output.verified.value() && batched_opening_verified && consistency_checked; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index d756797d910..57a56b33226 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -81,7 +81,6 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) libra_commitments[0] = transcript->template receive_from_prover("Libra:concatenation_commitment"); auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); - info("verified? in eccvm rec verifier ", sumcheck_output.verified.value()); libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 5df3e862353..afb4173328f 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -148,7 +148,7 @@ template class SumcheckProver { static constexpr bool IS_ECCVM = std::is_same_v; std::vector round_univariate_commitments = {}; - std::vector> round_univariate_evaluations = {}; + std::vector> round_evaluations = {}; std::vector> round_univariates = {}; std::vector eval_domain = {}; @@ -298,14 +298,10 @@ template class SumcheckProver { } commit_to_round_univariate( - round_univariate, eval_domain, transcript, ck, round_univariates, round_univariate_evaluations); + round_idx, round_univariate, eval_domain, transcript, ck, round_univariates, round_evaluations); } const FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); - if constexpr (IS_ECCVM) { - // Store the evaluation at the challenge. Could be optimized - round_univariate_evaluations[0][2] = round_univariate.evaluate(round_challenge); - } multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round @@ -335,9 +331,7 @@ template class SumcheckProver { transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); } else { commit_to_round_univariate( - round_univariate, eval_domain, transcript, ck, round_univariates, round_univariate_evaluations); - round_univariate_evaluations[round_idx - 1][2] = - round_univariate.value_at(0) + round_univariate.value_at(1); + round_idx, round_univariate, eval_domain, transcript, ck, round_univariates, round_evaluations); } const FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); @@ -353,7 +347,7 @@ template class SumcheckProver { } if constexpr (IS_ECCVM) { - round_univariate_evaluations[multivariate_d - 1][2] = + round_evaluations[multivariate_d - 1][2] = round_univariate.evaluate(multivariate_challenge[multivariate_d - 1]); } vinfo("completed ", multivariate_d, " rounds of sumcheck"); @@ -399,7 +393,7 @@ template class SumcheckProver { .claimed_evaluations = multivariate_evaluations, .claimed_libra_evaluation = libra_evaluation, .round_univariates = round_univariates, - .round_univariate_evaluations = round_univariate_evaluations }; + .round_univariate_evaluations = round_evaluations }; } vinfo("finished sumcheck"); }; @@ -544,28 +538,35 @@ polynomials that are sent in clear. }; } - void commit_to_round_univariate(bb::Univariate& round_univariate, + void commit_to_round_univariate(const size_t round_idx, + bb::Univariate& round_univariate, const std::vector& eval_domain, const std::shared_ptr& transcript, const std::shared_ptr& ck, std::vector>& round_univariates, std::vector>& round_univariate_evaluations) { + + const std::string idx = std::to_string(round_idx); Polynomial round_poly_monomial = Polynomial(eval_domain, std::span(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH); auto round_univariate_commitment = ck->commit(round_poly_monomial); - transcript->send_to_verifier("Sumcheck:univariate_comm_0", round_univariate_commitment); + transcript->send_to_verifier("Sumcheck:univariate_comm_" + idx, round_univariate_commitment); // Store round univariate in monomial, as it is required for Shplonk round_univariates.push_back(std::move(round_poly_monomial)); // Send the evaluations of the rounds univariate at 0 and 1 - transcript->send_to_verifier("Sumcheck:univariate_0_eval_0", round_univariate.value_at(0)); - transcript->send_to_verifier("Sumcheck:univariate_0_eval_1", round_univariate.value_at(1)); + transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_0", round_univariate.value_at(0)); + transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_1", round_univariate.value_at(1)); // Store the evaluations to be used in Shplonk. Third value will be computed after getting the round // challenge round_univariate_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1), FF(0) }); + if (round_idx > 0) { + round_univariate_evaluations[round_idx - 1][2] = + round_univariate.value_at(0) + round_univariate.value_at(1); + }; } }; /*! \brief Implementation of the sumcheck Verifier for statements of the form \f$\sum_{\vec \ell \in \{0,1\}^d} From 6aec0f7169e83d98b4a4c9471b7de2df53bc3953 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 17 Jan 2025 11:20:56 +0000 Subject: [PATCH 12/33] commited sumcheck test added --- .../commitment_schemes/shplonk/shplemini.hpp | 2 +- .../sumcheck/sumcheck_committed.test.cpp | 118 ++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_committed.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 6268331d42c..b6ee703033b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -686,7 +686,7 @@ template class ShpleminiVerifier_ { // compute the scalars to be multiplied against the commitments [libra_concatenated], [big_sum], [big_sum], and // [libra_quotient] - for (size_t idx = 0; idx < libra_evaluations.size(); idx++) { + for (size_t idx = 0; idx < NUM_LIBRA_EVALUATIONS; idx++) { Fr scaling_factor = denominators[idx] * shplonk_challenge_power; batching_scalars[idx] = -scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_committed.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_committed.test.cpp new file mode 100644 index 00000000000..97014fbf026 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_committed.test.cpp @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +#include "barretenberg/eccvm/eccvm_circuit_builder.hpp" +#include "barretenberg/eccvm/eccvm_prover.hpp" +#include "barretenberg/eccvm/eccvm_verifier.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/plonk_honk_shared/library/grand_product_delta.hpp" +#include "barretenberg/relations/permutation_relation.hpp" +#include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/sumcheck/sumcheck.hpp" +#include "barretenberg/sumcheck/sumcheck_round.hpp" + +using namespace bb; + +class ECCVMTests : public ::testing::Test { + protected: + void SetUp() override { srs::init_grumpkin_crs_factory(bb::srs::get_grumpkin_crs_path()); }; +}; +namespace { +auto& engine = numeric::get_debug_randomness(); +} + +/** + * @brief Adds operations in BN254 to the op_queue and then constructs and ECCVM circuit from the op_queue. + * + * @param engine + * @return ECCVMCircuitBuilder + */ +ECCVMCircuitBuilder generate_circuit(numeric::RNG* engine = nullptr) +{ + using Curve = curve::BN254; + using G1 = Curve::Element; + using Fr = Curve::ScalarField; + + std::shared_ptr op_queue = std::make_shared(); + G1 a = G1::random_element(engine); + G1 b = G1::random_element(engine); + G1 c = G1::random_element(engine); + Fr x = Fr::random_element(engine); + Fr y = Fr::random_element(engine); + + op_queue->add_accumulate(a); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->mul_accumulate(b, y); + op_queue->add_accumulate(a); + op_queue->mul_accumulate(b, x); + op_queue->eq_and_reset(); + op_queue->add_accumulate(c); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->eq_and_reset(); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->mul_accumulate(c, x); + ECCVMCircuitBuilder builder{ op_queue }; + return builder; +} + +TEST_F(ECCVMTests, BaseCase) +{ + using Flavor = ECCVMFlavor; + using ProvingKey = ECCVMFlavor::ProvingKey; + using SumcheckProver = SumcheckProver; + using FF = ECCVMFlavor::FF; + using ZKData = ZKSumcheckData; + bb::RelationParameters relation_parameters; + + ECCVMCircuitBuilder builder = generate_circuit(&engine); + ECCVMProver prover(builder); + auto key = std::make_shared(builder); + + // Compute and add beta to relation parameters + const FF beta = FF::random_element(); + + const FF gamma = FF::random_element(); + // TODO(#583)(@zac-williamson): fix Transcript to be able to generate more than 2 challenges per round! oof. + const FF beta_sqr = beta * beta; + relation_parameters.gamma = gamma; + relation_parameters.beta = beta; + relation_parameters.beta_sqr = beta_sqr; + relation_parameters.beta_cube = beta_sqr * beta; + relation_parameters.eccvm_set_permutation_delta = + gamma * (gamma + beta_sqr) * (gamma + beta_sqr + beta_sqr) * (gamma + beta_sqr + beta_sqr + beta_sqr); + relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert(); + // Compute inverse polynomial for our logarithmic-derivative lookup method + compute_logderivative_inverse( + key->polynomials, relation_parameters, key->circuit_size); + + auto sumcheck_prover = SumcheckProver(key->circuit_size, prover.transcript); + const FF alpha = FF::random_element(); + + std::vector gate_challenges(CONST_PROOF_SIZE_LOG_N); + for (size_t idx = 0; idx < CONST_PROOF_SIZE_LOG_N; idx++) { + gate_challenges[idx] = FF::random_element(); + } + ZKData zk_sumcheck_data = ZKData(key->log_circuit_size, prover.transcript, key->commitment_key); + + auto prover_output = sumcheck_prover.prove( + key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data, key->commitment_key); + + ECCVMVerifier verifier(prover.key); + + const auto circuit_size = verifier.transcript->template receive_from_prover("circuit_size"); + + // Execute Sumcheck Verifier + const size_t log_circuit_size = numeric::get_msb(circuit_size); + auto sumcheck_verifier = SumcheckVerifier(log_circuit_size, verifier.transcript); + + // Receive commitments to Libra masking polynomials + + auto sumcheck_output = sumcheck_verifier.verify(relation_parameters, alpha, gate_challenges); + + ASSERT_TRUE(sumcheck_output.verified); +} From 74cd1a87816e18c7a327ae6487e31d1c547af6a5 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 17 Jan 2025 14:22:03 +0000 Subject: [PATCH 13/33] test cleaned up --- .../eccvm/eccvm_composer.test.cpp | 87 ++++++++++++- .../src/barretenberg/sumcheck/sumcheck.hpp | 14 ++- .../sumcheck/sumcheck_committed.test.cpp | 118 ------------------ 3 files changed, 94 insertions(+), 125 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_committed.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp index 16525eb8b9f..add13ec0075 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp @@ -10,10 +10,12 @@ #include "barretenberg/plonk_honk_shared/library/grand_product_delta.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/sumcheck/sumcheck.hpp" #include "barretenberg/sumcheck/sumcheck_round.hpp" using namespace bb; - +using FF = ECCVMFlavor::FF; +using PK = ECCVMFlavor::ProvingKey; class ECCVMTests : public ::testing::Test { protected: void SetUp() override { srs::init_grumpkin_crs_factory(bb::srs::get_grumpkin_crs_path()); }; @@ -58,6 +60,33 @@ ECCVMCircuitBuilder generate_circuit(numeric::RNG* engine = nullptr) ECCVMCircuitBuilder builder{ op_queue }; return builder; } +void complete_proving_key_for_test(bb::RelationParameters& relation_parameters, + std::shared_ptr& pk, + std::vector& gate_challenges) +{ + // Prepare the inputs for the sumcheck prover: + // Compute and add beta to relation parameters + const FF beta = FF::random_element(); + const FF gamma = FF::random_element(); + const FF beta_sqr = beta * beta; + relation_parameters.gamma = gamma; + relation_parameters.beta = beta; + relation_parameters.beta_sqr = beta_sqr; + relation_parameters.beta_cube = beta_sqr * beta; + relation_parameters.eccvm_set_permutation_delta = + gamma * (gamma + beta_sqr) * (gamma + beta_sqr + beta_sqr) * (gamma + beta_sqr + beta_sqr + beta_sqr); + relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert(); + + // Compute z_perm and inverse polynomial for our logarithmic-derivative lookup method + compute_logderivative_inverse( + pk->polynomials, relation_parameters, pk->circuit_size); + compute_grand_products(pk->polynomials, relation_parameters); + + // Generate gate challenges + for (size_t idx = 0; idx < CONST_PROOF_SIZE_LOG_N; idx++) { + gate_challenges[idx] = FF::random_element(); + } +} TEST_F(ECCVMTests, BaseCase) { @@ -84,3 +113,59 @@ TEST_F(ECCVMTests, EqFails) bool verified = verifier.verify_proof(proof); ASSERT_FALSE(verified); } + +TEST_F(ECCVMTests, CommitedSumcheck) +{ + using Flavor = ECCVMFlavor; + using ProvingKey = ECCVMFlavor::ProvingKey; + using SumcheckProver = SumcheckProver; + using FF = ECCVMFlavor::FF; + using Transcript = Flavor::Transcript; + using ZKData = ZKSumcheckData; + + bb::RelationParameters relation_parameters; + std::vector gate_challenges(CONST_PROOF_SIZE_LOG_N); + + ECCVMCircuitBuilder builder = generate_circuit(&engine); + + ECCVMProver prover(builder); + auto pk = std::make_shared(builder); + const size_t log_circuit_size = pk->log_circuit_size; + + std::shared_ptr prover_transcript = std::make_shared(); + + // Prepare the inputs for the sumcheck prover: + // Compute and add beta to relation parameters + const FF alpha = FF::random_element(); + complete_proving_key_for_test(relation_parameters, pk, gate_challenges); + + auto sumcheck_prover = SumcheckProver(pk->circuit_size, prover_transcript); + + ZKData zk_sumcheck_data = ZKData(log_circuit_size, prover_transcript); + + auto prover_output = sumcheck_prover.prove( + pk->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data, pk->commitment_key); + + ECCVMVerifier verifier(prover.key); + std::shared_ptr verifier_transcript = std::make_shared(prover_transcript->proof_data); + + // Execute Sumcheck Verifier + SumcheckVerifier sumcheck_verifier = SumcheckVerifier(log_circuit_size, verifier_transcript); + SumcheckOutput verifier_output = sumcheck_verifier.verify(relation_parameters, alpha, gate_challenges); + + // Evaluate prover's round univariates at corresponding challenges and compare them with the claimed evaluations + // computed by the verifier + for (size_t idx = 0; idx < log_circuit_size; idx++) { + FF true_eval_at_the_challenge = prover_output.round_univariates[idx].evaluate(prover_output.challenge[idx]); + FF verifier_eval_at_the_challenge = verifier_output.round_univariate_evaluations[idx][2]; + EXPECT_TRUE(true_eval_at_the_challenge == verifier_eval_at_the_challenge); + } + + // Check that the first sumcheck univariate is consistent with the claimed ZK Sumchek Sum + FF prover_target_sum = zk_sumcheck_data.libra_challenge * zk_sumcheck_data.libra_total_sum; + + EXPECT_TRUE(prover_target_sum == verifier_output.round_univariate_evaluations[0][0] + + verifier_output.round_univariate_evaluations[0][1]); + + EXPECT_TRUE(verifier_output.verified.value()); +} diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index afb4173328f..8b847c30698 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -782,7 +782,7 @@ template class SumcheckVerifier { const std::vector& gate_challenges) requires std::is_same_v || IsECCVMRecursiveFlavor { - bool verified(true); + bool verified(false); bb::GateSeparatorPolynomial gate_separators(gate_challenges); @@ -801,6 +801,7 @@ template class SumcheckVerifier { multivariate_challenge.reserve(CONST_PROOF_SIZE_LOG_N); // if Flavor has ZK, the target total sum is corrected by Libra total sum multiplied by the Libra // challenge + info(round.target_total_sum); round.target_total_sum += libra_total_sum * libra_challenge; for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { @@ -840,17 +841,18 @@ template class SumcheckVerifier { round_univariate_evaluations[round_idx - 1][2] = round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; } - + FF first_sumcheck_round_evaluations_sum = + round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; + info("sum of evals", first_sumcheck_round_evaluations_sum); if constexpr (IsRecursiveFlavor) { - FF first_sumcheck_round_evaluations_sum = - round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; first_sumcheck_round_evaluations_sum.self_reduce(); round.target_total_sum.self_reduce(); first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); } else { - verified = verified && (round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1] == - round.target_total_sum); + info(round.target_total_sum); + verified = (first_sumcheck_round_evaluations_sum == round.target_total_sum); + info(verified); } // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_committed.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_committed.test.cpp deleted file mode 100644 index 97014fbf026..00000000000 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_committed.test.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include -#include - -#include "barretenberg/eccvm/eccvm_circuit_builder.hpp" -#include "barretenberg/eccvm/eccvm_prover.hpp" -#include "barretenberg/eccvm/eccvm_verifier.hpp" -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/plonk_honk_shared/library/grand_product_delta.hpp" -#include "barretenberg/relations/permutation_relation.hpp" -#include "barretenberg/relations/relation_parameters.hpp" -#include "barretenberg/sumcheck/sumcheck.hpp" -#include "barretenberg/sumcheck/sumcheck_round.hpp" - -using namespace bb; - -class ECCVMTests : public ::testing::Test { - protected: - void SetUp() override { srs::init_grumpkin_crs_factory(bb::srs::get_grumpkin_crs_path()); }; -}; -namespace { -auto& engine = numeric::get_debug_randomness(); -} - -/** - * @brief Adds operations in BN254 to the op_queue and then constructs and ECCVM circuit from the op_queue. - * - * @param engine - * @return ECCVMCircuitBuilder - */ -ECCVMCircuitBuilder generate_circuit(numeric::RNG* engine = nullptr) -{ - using Curve = curve::BN254; - using G1 = Curve::Element; - using Fr = Curve::ScalarField; - - std::shared_ptr op_queue = std::make_shared(); - G1 a = G1::random_element(engine); - G1 b = G1::random_element(engine); - G1 c = G1::random_element(engine); - Fr x = Fr::random_element(engine); - Fr y = Fr::random_element(engine); - - op_queue->add_accumulate(a); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->mul_accumulate(b, y); - op_queue->add_accumulate(a); - op_queue->mul_accumulate(b, x); - op_queue->eq_and_reset(); - op_queue->add_accumulate(c); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->eq_and_reset(); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->mul_accumulate(c, x); - ECCVMCircuitBuilder builder{ op_queue }; - return builder; -} - -TEST_F(ECCVMTests, BaseCase) -{ - using Flavor = ECCVMFlavor; - using ProvingKey = ECCVMFlavor::ProvingKey; - using SumcheckProver = SumcheckProver; - using FF = ECCVMFlavor::FF; - using ZKData = ZKSumcheckData; - bb::RelationParameters relation_parameters; - - ECCVMCircuitBuilder builder = generate_circuit(&engine); - ECCVMProver prover(builder); - auto key = std::make_shared(builder); - - // Compute and add beta to relation parameters - const FF beta = FF::random_element(); - - const FF gamma = FF::random_element(); - // TODO(#583)(@zac-williamson): fix Transcript to be able to generate more than 2 challenges per round! oof. - const FF beta_sqr = beta * beta; - relation_parameters.gamma = gamma; - relation_parameters.beta = beta; - relation_parameters.beta_sqr = beta_sqr; - relation_parameters.beta_cube = beta_sqr * beta; - relation_parameters.eccvm_set_permutation_delta = - gamma * (gamma + beta_sqr) * (gamma + beta_sqr + beta_sqr) * (gamma + beta_sqr + beta_sqr + beta_sqr); - relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert(); - // Compute inverse polynomial for our logarithmic-derivative lookup method - compute_logderivative_inverse( - key->polynomials, relation_parameters, key->circuit_size); - - auto sumcheck_prover = SumcheckProver(key->circuit_size, prover.transcript); - const FF alpha = FF::random_element(); - - std::vector gate_challenges(CONST_PROOF_SIZE_LOG_N); - for (size_t idx = 0; idx < CONST_PROOF_SIZE_LOG_N; idx++) { - gate_challenges[idx] = FF::random_element(); - } - ZKData zk_sumcheck_data = ZKData(key->log_circuit_size, prover.transcript, key->commitment_key); - - auto prover_output = sumcheck_prover.prove( - key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data, key->commitment_key); - - ECCVMVerifier verifier(prover.key); - - const auto circuit_size = verifier.transcript->template receive_from_prover("circuit_size"); - - // Execute Sumcheck Verifier - const size_t log_circuit_size = numeric::get_msb(circuit_size); - auto sumcheck_verifier = SumcheckVerifier(log_circuit_size, verifier.transcript); - - // Receive commitments to Libra masking polynomials - - auto sumcheck_output = sumcheck_verifier.verify(relation_parameters, alpha, gate_challenges); - - ASSERT_TRUE(sumcheck_output.verified); -} From f53a3081635cbea6047c7793283f09b49b013277 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 17 Jan 2025 19:58:08 +0000 Subject: [PATCH 14/33] creating test for pcs --- .../shplonk/shplemini.test.cpp | 82 +++++++++++++++++++ .../src/barretenberg/sumcheck/sumcheck.hpp | 61 +------------- .../sumcheck/zk_sumcheck_data.hpp | 64 +++++++++++++-- 3 files changed, 141 insertions(+), 66 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp index 2bcc54538b2..a2fe8ac56a1 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -10,6 +10,7 @@ #include "barretenberg/commitment_schemes/utils/instance_witness_generator.hpp" #include "barretenberg/commitment_schemes/utils/test_settings.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/sumcheck/sumcheck.hpp" #include #include @@ -226,7 +227,88 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) EXPECT_EQ(shplemini_result, expected_result); } +TYPED_TEST(ShpleminiTest, OpeningSumcheckUnivariates) +{ + using Curve = TypeParam::Curve; + using Fr = typename Curve::ScalarField; + using Commitment = typename Curve::AffineElement; + using CK = typename TypeParam::CommitmentKey; + + using ShpleminiProver = ShpleminiProver_; + using ShpleminiVerifier = ShpleminiVerifier_; + + constexpr size_t length = 24; + std::shared_ptr ck = create_commitment_key(4096); + + // generate sumcheck polys + auto zk_sumcheck_data = ZKSumcheckData(this->log_n, length); + std::vector challenge = this->random_evaluation_point(CONST_PROOF_SIZE_LOG_N); + std::vector> round_univariates = {}; + std::vector sumcheck_commitments = {}; + std::vector> sumcheck_evaluations = {}; + + for (size_t idx = 0; idx < this->log_n; idx++) { + bb::Polynomial round_univariate = zk_sumcheck_data.libra_univariates[idx]; + round_univariate.at(0) += zk_sumcheck_data.libra_running_sum; + + round_univariates.push_back(std::move(round_univariate)); + sumcheck_commitments.push_back(ck->commit(round_univariate)); + sumcheck_evaluations.push_back( + { round_univariate.at(0), round_univariate.evaluate(Fr(1)), round_univariate.evaluate(challenge[idx]) }); + + zk_sumcheck_data.update_zk_sumcheck_data(challenge[idx], idx); + } + auto round_univariate = bb::Polynomial(this->n); + for (size_t idx = this->log_n; idx < CONST_PROOF_SIZE_LOG_N; idx++) { + round_univariates.push_back(std::move(round_univariate)); + sumcheck_commitments.push_back(ck->commit(round_univariate)); + sumcheck_evaluations.push_back({ Fr(0), Fr(0), Fr(0) }); + } + + auto prover_transcript = TypeParam::Transcript::prover_init_empty(); + + const auto opening_claim = ShpleminiProver::prove( + this->n, {}, {}, challenge, ck, prover_transcript, {}, round_univariates, sumcheck_evaluations); + + if constexpr (std::is_same_v) { + IPA::compute_opening_proof(this->ck(), opening_claim, prover_transcript); + } else { + KZG::compute_opening_proof(this->ck(), opening_claim, prover_transcript); + } + + // Initialize verifier's transcript + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); + // bool consistency_checked = true; + + // Run Shplemini + const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(this->n, + {}, + {}, + {}, + {}, + challenge, + this->vk()->get_g1_identity(), + verifier_transcript, + {}, + true, + nullptr, + {}, + {}, + sumcheck_commitments, + sumcheck_evaluations); + // Verify claim using KZG or IPA + if constexpr (std::is_same_v) { + auto result = + IPA::reduce_verify_batch_opening_claim(batch_opening_claim, this->vk(), verifier_transcript); + EXPECT_EQ(result, true); + } else { + const auto pairing_points = + KZG::reduce_verify_batch_opening_claim(batch_opening_claim, verifier_transcript); + // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2) + EXPECT_EQ(this->vk()->pairing_check(pairing_points[0], pairing_points[1]), true); + } +} /** * @brief Test Shplemini with ZK data consisting of a hiding polynomial generated by GeminiProver and Libra polynomials * used to mask Sumcheck Round Univariates. diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 8b847c30698..dbfd22f15cc 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -307,7 +307,7 @@ template class SumcheckProver { // Prepare sumcheck book-keeping table for the next round partially_evaluate(full_polynomials, multivariate_n, round_challenge); // Prepare ZK Sumcheck data for the next round - update_zk_sumcheck_data(zk_sumcheck_data, round_challenge, round_idx); + zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx); row_disabling_polynomial.update_evaluations(round_challenge, round_idx); gate_separators.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; // TODO(#224)(Cody): Maybe partially_evaluate should do this and @@ -339,7 +339,7 @@ template class SumcheckProver { // Prepare sumcheck book-keeping table for the next round partially_evaluate(partially_evaluated_polynomials, round.round_size, round_challenge); // Prepare evaluation masking and libra structures for the next round (for ZK Flavors) - update_zk_sumcheck_data(zk_sumcheck_data, round_challenge, round_idx); + zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx); row_disabling_polynomial.update_evaluations(round_challenge, round_idx); gate_separators.partially_evaluate(round_challenge); @@ -481,63 +481,6 @@ polynomials that are sent in clear. return multivariate_evaluations; }; - /** - * @brief Upon receiving the challenge \f$u_i\f$, the prover updates Libra data. If \f$ i < d-1\f$ - - - update the table of Libra univariates by multiplying every term by \f$1/2\f$. - - computes the value \f$2^{d-i - 2} \cdot \texttt{libra_challenge} \cdot g_0(u_0)\f$ applying \ref - bb::Univariate::evaluate "evaluate" method to the first univariate in the table \f$\texttt{libra_univariates}\f$ - - places the value \f$ g_0(u_0)\f$ to the vector \f$ \texttt{libra_evaluations}\f$ - - update the running sum - \f{align}{ - \texttt{libra_running_sum} \gets 2^{d-i-2} \cdot \texttt{libra_challenge} \cdot g_0(u_0) + 2^{-1} - \cdot \left( \texttt{libra_running_sum} - (\texttt{libra_univariates}_{i+1}(0) + - \texttt{libra_univariates}_{i+1}(1)) \right) \f} If \f$ i = d-1\f$ - - compute the value \f$ g_{d-1}(u_{d-1})\f$ applying \ref bb::Univariate::evaluate "evaluate" method to the - last univariate in the table \f$\texttt{libra_univariates}\f$ and dividing the result by \f$ - \texttt{libra_challenge} \f$. - - update the table of Libra univariates by multiplying every term by \f$\texttt{libra_challenge}^{-1}\f$. - @todo Refactor once the Libra univariates are extracted from the Proving Key. Then the prover does not need to - update the first round_idx - 1 univariates and could release the memory. Also, use batch_invert / reduce - the number of divisions by 2. - * @param libra_univariates - * @param round_challenge - * @param round_idx - * @param libra_running_sum - * @param libra_evaluations - */ - void update_zk_sumcheck_data(ZKData& zk_sumcheck_data, const FF round_challenge, size_t round_idx) - { - static constexpr FF two_inv = FF(1) / FF(2); - // when round_idx = d - 1, the update is not needed - if (round_idx < zk_sumcheck_data.libra_univariates.size() - 1) { - for (auto& univariate : zk_sumcheck_data.libra_univariates) { - univariate *= two_inv; - }; - // compute the evaluation \f$ \rho \cdot 2^{d-2-i} \çdot g_i(u_i) \f$ - auto libra_evaluation = zk_sumcheck_data.libra_univariates[round_idx].evaluate(round_challenge); - auto next_libra_univariate = zk_sumcheck_data.libra_univariates[round_idx + 1]; - // update the running sum by adding g_i(u_i) and subtracting (g_i(0) + g_i(1)) - zk_sumcheck_data.libra_running_sum += - -next_libra_univariate.evaluate(FF(0)) - next_libra_univariate.evaluate(FF(1)); - zk_sumcheck_data.libra_running_sum *= two_inv; - - zk_sumcheck_data.libra_running_sum += libra_evaluation; - zk_sumcheck_data.libra_scaling_factor *= two_inv; - - zk_sumcheck_data.libra_evaluations.emplace_back(libra_evaluation / zk_sumcheck_data.libra_scaling_factor); - } else { - // compute the evaluation of the last Libra univariate at the challenge u_{d-1} - auto libra_evaluation = zk_sumcheck_data.libra_univariates[round_idx].evaluate(round_challenge) / - zk_sumcheck_data.libra_scaling_factor; - // place the evalution into the vector of Libra evaluations - zk_sumcheck_data.libra_evaluations.emplace_back(libra_evaluation); - for (auto univariate : zk_sumcheck_data.libra_univariates) { - univariate *= FF(1) / zk_sumcheck_data.libra_challenge; - } - }; - } - void commit_to_round_univariate(const size_t round_idx, bb::Univariate& round_univariate, const std::vector& eval_domain, diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp index d35f188d1a7..b38c4dd81a4 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp @@ -45,17 +45,19 @@ template struct ZKSumcheckData { FF libra_running_sum; ClaimedLibraEvaluations libra_evaluations; + size_t univariate_length; // Default constructor ZKSumcheckData() = default; // Main constructor ZKSumcheckData(const size_t multivariate_d, - std::shared_ptr transcript, + std::shared_ptr transcript = nullptr, std::shared_ptr commitment_key = nullptr) : constant_term(FF::random_element()) - , libra_concatenated_monomial_form(SUBGROUP_SIZE + 2) // includes masking - , libra_univariates(generate_libra_univariates(multivariate_d)) // random univariates of degree 2 + , libra_concatenated_monomial_form(SUBGROUP_SIZE + 2) // includes masking + , libra_univariates(generate_libra_univariates(multivariate_d, LIBRA_UNIVARIATES_LENGTH)) , log_circuit_size(multivariate_d) + , univariate_length(LIBRA_UNIVARIATES_LENGTH) { create_interpolation_domain(); @@ -81,21 +83,38 @@ template struct ZKSumcheckData { libra_running_sum = libra_total_sum * libra_challenge; // Setup the Libra data + setup_auxiliary_data(libra_univariates, libra_scaling_factor, libra_challenge, libra_running_sum); } + // Constructor for test purposes. Creates log_circuit size polynomials g_i(X_i) of length univariate_length, + // computes the sum \sum_H (constant_term + \sum g_i). + ZKSumcheckData(const size_t multivariate_d, const size_t univariate_length) + : constant_term(FF::random_element()) + , libra_univariates(generate_libra_univariates(multivariate_d, univariate_length)) + , log_circuit_size(multivariate_d) + , libra_scaling_factor(FF(1)) + , libra_challenge(FF::random_element()) + , libra_total_sum(compute_libra_total_sum(libra_univariates, libra_scaling_factor, constant_term)) + , libra_running_sum(libra_total_sum * libra_challenge) + , univariate_length(univariate_length) + + { + setup_auxiliary_data(libra_univariates, libra_scaling_factor, libra_challenge, libra_running_sum); + } /** * @brief Given number of univariate polynomials and the number of their evaluations meant to be hidden, this method * produces a vector of univariate polynomials of length Flavor::BATCHED_RELATION_PARTIAL_LENGTH with * independent uniformly random coefficients. * */ - static std::vector> generate_libra_univariates(const size_t number_of_polynomials) + static std::vector> generate_libra_univariates(const size_t number_of_polynomials, + const size_t univariate_length) { std::vector> libra_full_polynomials(number_of_polynomials); for (auto& libra_polynomial : libra_full_polynomials) { - libra_polynomial = Polynomial::random(LIBRA_UNIVARIATES_LENGTH); + libra_polynomial = Polynomial::random(univariate_length); }; return libra_full_polynomials; }; @@ -116,7 +135,7 @@ template struct ZKSumcheckData { scaling_factor *= one_half; for (auto& univariate : libra_univariates) { - total_sum += univariate.evaluate(FF(0)) + univariate.evaluate(FF(1)); + total_sum += univariate.at(0) + univariate.evaluate(FF(1)); scaling_factor *= 2; } total_sum *= scaling_factor; @@ -146,7 +165,7 @@ template struct ZKSumcheckData { univariate *= libra_scaling_factor; }; // subtract the contribution of the first libra univariate from libra total sum - libra_running_sum += -libra_univariates[0].evaluate(FF(0)) - libra_univariates[0].evaluate(FF(1)); + libra_running_sum += -libra_univariates[0].at(0) - libra_univariates[0].evaluate(FF(1)); libra_running_sum *= one_half; } @@ -214,6 +233,37 @@ template struct ZKSumcheckData { libra_concatenated_monomial_form.at(SUBGROUP_SIZE + idx) += masking_scalars.value_at(idx); } } + + void update_zk_sumcheck_data(const FF round_challenge, const size_t round_idx) + { + static constexpr FF two_inv = FF(1) / FF(2); + // when round_idx = d - 1, the update is not needed + if (round_idx < this->log_circuit_size - 1) { + for (auto& univariate : this->libra_univariates) { + univariate *= two_inv; + }; + // compute the evaluation \f$ \rho \cdot 2^{d-2-i} \çdot g_i(u_i) \f$ + const FF libra_evaluation = this->libra_univariates[round_idx].evaluate(round_challenge); + const auto& next_libra_univariate = this->libra_univariates[round_idx + 1]; + // update the running sum by adding g_i(u_i) and subtracting (g_i(0) + g_i(1)) + this->libra_running_sum += -next_libra_univariate.at(0) - next_libra_univariate.evaluate(FF(1)); + this->libra_running_sum *= two_inv; + + this->libra_running_sum += libra_evaluation; + this->libra_scaling_factor *= two_inv; + + this->libra_evaluations.emplace_back(libra_evaluation / this->libra_scaling_factor); + } else { + // compute the evaluation of the last Libra univariate at the challenge u_{d-1} + const FF libra_evaluation = + this->libra_univariates[round_idx].evaluate(round_challenge) / this->libra_scaling_factor; + // place the evalution into the vector of Libra evaluations + this->libra_evaluations.emplace_back(libra_evaluation); + for (auto univariate : this->libra_univariates) { + univariate *= FF(1) / this->libra_challenge; + } + }; + } }; } // namespace bb From f4c3dc8d8b593547b5ec6e72a74889bc10cfd3af Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Sat, 18 Jan 2025 14:01:18 +0000 Subject: [PATCH 15/33] shplemini test + clean-up + figuring out constness --- .../shplonk/shplemini.test.cpp | 239 ++++++++++++------ .../commitment_schemes/shplonk/shplonk.hpp | 3 +- .../utils/instance_witness_generator.hpp | 12 + .../eccvm/eccvm_composer.test.cpp | 4 +- .../src/barretenberg/eccvm/eccvm_prover.cpp | 3 +- .../eccvm_recursive_verifier.cpp | 6 +- .../eccvm_recursive_verifier.test.cpp | 104 ++++++++ .../src/barretenberg/sumcheck/sumcheck.hpp | 56 ++-- .../sumcheck/zk_sumcheck_data.hpp | 11 +- 9 files changed, 327 insertions(+), 111 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp index a2fe8ac56a1..119e6317304 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -19,10 +19,53 @@ namespace bb { template class ShpleminiTest : public CommitmentTest { public: + // Size of the test polynomials static constexpr size_t n = 32; static constexpr size_t log_n = 5; + // Total number of random polynomials in each test static constexpr size_t num_polynomials = 5; + // Number of shiftable polynomials static constexpr size_t num_shiftable = 2; + + // Actual length of Sumcheck Round Univariates in ECCVM + static constexpr size_t length = 24; + + using Fr = typename Flavor::Curve::ScalarField; + using GroupElement = typename Flavor::Curve::Element; + using Commitment = typename Flavor::Curve::AffineElement; + using CK = typename Flavor::CommitmentKey; + + void compute_sumcheck_opening_data(std::vector>& round_univariates, + std::vector& sumcheck_commitments, + std::vector>& sumcheck_evaluations, + std::vector& challenge, + std::shared_ptr& ck) + { + // Generate valid sumcheck polynomials of given length + auto mock_sumcheck_polynomials = ZKSumcheckData(log_n, length); + for (size_t idx = 0; idx < log_n; idx++) { + bb::Polynomial round_univariate = mock_sumcheck_polynomials.libra_univariates[idx]; + + round_univariate.at(0) += mock_sumcheck_polynomials.libra_running_sum; + + sumcheck_commitments.push_back(ck->commit(round_univariate)); + + sumcheck_evaluations.push_back({ round_univariate.at(0), + round_univariate.evaluate(Fr(1)), + round_univariate.evaluate(challenge[idx]) }); + + mock_sumcheck_polynomials.update_zk_sumcheck_data(challenge[idx], idx); + round_univariates.push_back(round_univariate); + } + + // Simulate the `const proof size` logic + auto round_univariate = bb::Polynomial(this->n); + for (size_t idx = this->log_n; idx < CONST_PROOF_SIZE_LOG_N; idx++) { + round_univariates.push_back(round_univariate); + sumcheck_commitments.push_back(ck->commit(round_univariate)); + sumcheck_evaluations.push_back({ Fr(0), Fr(0), Fr(0) }); + } + } }; using TestSettings = ::testing::Types; @@ -227,49 +270,60 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) EXPECT_EQ(shplemini_result, expected_result); } -TYPED_TEST(ShpleminiTest, OpeningSumcheckUnivariates) + +/** + * @brief Test Shplemini with ZK data consisting of a hiding polynomial generated by GeminiProver and Libra polynomials + * used to mask Sumcheck Round Univariates. This abstracts the PCS step in each ZK Flavor running over BN254. + * + */ +TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) { + using ZKData = ZKSumcheckData; using Curve = TypeParam::Curve; + using ShpleminiProver = ShpleminiProver_; + using ShpleminiVerifier = ShpleminiVerifier_; using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using CK = typename TypeParam::CommitmentKey; - using ShpleminiProver = ShpleminiProver_; - using ShpleminiVerifier = ShpleminiVerifier_; + // Initialize transcript and commitment key + auto prover_transcript = TypeParam::Transcript::prover_init_empty(); - constexpr size_t length = 24; - std::shared_ptr ck = create_commitment_key(4096); + // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck. + static constexpr size_t log_subgroup_size = static_cast(numeric::get_msb(Curve::SUBGROUP_SIZE)); + std::shared_ptr ck = create_commitment_key(std::max(this->n, 1ULL << (log_subgroup_size + 1))); - // generate sumcheck polys - auto zk_sumcheck_data = ZKSumcheckData(this->log_n, length); - std::vector challenge = this->random_evaluation_point(CONST_PROOF_SIZE_LOG_N); - std::vector> round_univariates = {}; - std::vector sumcheck_commitments = {}; - std::vector> sumcheck_evaluations = {}; + // Generate Libra polynomials, compute masked concatenated Libra polynomial, commit to it + ZKData zk_sumcheck_data(this->log_n, prover_transcript, ck); - for (size_t idx = 0; idx < this->log_n; idx++) { - bb::Polynomial round_univariate = zk_sumcheck_data.libra_univariates[idx]; + // Generate multivariate challenge of size CONST_PROOF_SIZE_LOG_N + std::vector const_size_mle_opening_point = this->random_evaluation_point(CONST_PROOF_SIZE_LOG_N); + // Truncate the multivariate challenge to evaluate prover polynomials (As in Sumcheck) + const std::vector mle_opening_point(const_size_mle_opening_point.begin(), + const_size_mle_opening_point.begin() + this->log_n); - round_univariate.at(0) += zk_sumcheck_data.libra_running_sum; + // Generate random prover polynomials, compute their evaluations and commitments + InstanceWitnessGenerator pcs_instance_witness( + this->n, this->num_polynomials, this->num_shiftable, mle_opening_point, ck); - round_univariates.push_back(std::move(round_univariate)); - sumcheck_commitments.push_back(ck->commit(round_univariate)); - sumcheck_evaluations.push_back( - { round_univariate.at(0), round_univariate.evaluate(Fr(1)), round_univariate.evaluate(challenge[idx]) }); + // Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges + const Fr claimed_inner_product = SmallSubgroupIPAProver::compute_claimed_inner_product( + zk_sumcheck_data, const_size_mle_opening_point, this->log_n); - zk_sumcheck_data.update_zk_sumcheck_data(challenge[idx], idx); - } - auto round_univariate = bb::Polynomial(this->n); - for (size_t idx = this->log_n; idx < CONST_PROOF_SIZE_LOG_N; idx++) { - round_univariates.push_back(std::move(round_univariate)); - sumcheck_commitments.push_back(ck->commit(round_univariate)); - sumcheck_evaluations.push_back({ Fr(0), Fr(0), Fr(0) }); - } + prover_transcript->template send_to_verifier("Libra:claimed_evaluation", claimed_inner_product); - auto prover_transcript = TypeParam::Transcript::prover_init_empty(); + // Instantiate SmallSubgroupIPAProver, this prover sends commitments to Big Sum and Quotient polynomials + SmallSubgroupIPAProver small_subgroup_ipa_prover( + zk_sumcheck_data, const_size_mle_opening_point, claimed_inner_product, prover_transcript, ck); - const auto opening_claim = ShpleminiProver::prove( - this->n, {}, {}, challenge, ck, prover_transcript, {}, round_univariates, sumcheck_evaluations); + // Reduce to KZG or IPA based on the curve used in the test Flavor + const auto opening_claim = ShpleminiProver::prove(this->n, + RefVector(pcs_instance_witness.unshifted_polynomials), + RefVector(pcs_instance_witness.to_be_shifted_polynomials), + const_size_mle_opening_point, + ck, + prover_transcript, + small_subgroup_ipa_prover.get_witness_polynomials()); if constexpr (std::is_same_v) { IPA::compute_opening_proof(this->ck(), opening_claim, prover_transcript); @@ -279,24 +333,45 @@ TYPED_TEST(ShpleminiTest, OpeningSumcheckUnivariates) // Initialize verifier's transcript auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); - // bool consistency_checked = true; + + // Start populating Verifier's array of Libra commitments + std::array libra_commitments = {}; + libra_commitments[0] = + verifier_transcript->template receive_from_prover("Libra:concatenation_commitment"); + + // Place Libra data to the transcript + const Fr libra_total_sum = verifier_transcript->template receive_from_prover("Libra:Sum"); + const Fr libra_challenge = verifier_transcript->template get_challenge("Libra:Challenge"); + const Fr libra_evaluation = verifier_transcript->template receive_from_prover("Libra:claimed_evaluation"); + + // Check that transcript is consistent + EXPECT_EQ(libra_total_sum, zk_sumcheck_data.libra_total_sum); + EXPECT_EQ(libra_challenge, zk_sumcheck_data.libra_challenge); + EXPECT_EQ(libra_evaluation, claimed_inner_product); + + // Finalize the array of Libra/SmallSubgroupIpa commitments + libra_commitments[1] = verifier_transcript->template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[2] = verifier_transcript->template receive_from_prover("Libra:quotient_commitment"); + + // Used to verify the consistency of the evaluations of the concatenated libra polynomial, big sum polynomial, and + // the quotient polynomial computed by SmallSubgroupIPAProver + bool consistency_checked = true; // Run Shplemini - const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(this->n, - {}, - {}, - {}, - {}, - challenge, - this->vk()->get_g1_identity(), - verifier_transcript, - {}, - true, - nullptr, - {}, - {}, - sumcheck_commitments, - sumcheck_evaluations); + const auto batch_opening_claim = + ShpleminiVerifier::compute_batch_opening_claim(this->n, + RefVector(pcs_instance_witness.unshifted_commitments), + RefVector(pcs_instance_witness.to_be_shifted_commitments), + RefVector(pcs_instance_witness.unshifted_evals), + RefVector(pcs_instance_witness.shifted_evals), + const_size_mle_opening_point, + this->vk()->get_g1_identity(), + verifier_transcript, + {}, + true, + &consistency_checked, + libra_commitments, + libra_evaluation); // Verify claim using KZG or IPA if constexpr (std::is_same_v) { auto result = @@ -309,59 +384,63 @@ TYPED_TEST(ShpleminiTest, OpeningSumcheckUnivariates) EXPECT_EQ(this->vk()->pairing_check(pairing_points[0], pairing_points[1]), true); } } + /** - * @brief Test Shplemini with ZK data consisting of a hiding polynomial generated by GeminiProver and Libra polynomials - * used to mask Sumcheck Round Univariates. + * @brief Test Shplemini with ZK data consisting of a hiding polynomial generated by GeminiProver, Libra polynomials + * used to mask Sumcheck Round Univariates and prove/verify the claimed evaluations of committed sumcheck round + * univariates. This test abstracts the PCS step in each ZK Flavor running over Grumpkin. * */ -TYPED_TEST(ShpleminiTest, ShpleminiWithZK) +TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) { - using ZKData = ZKSumcheckData; using Curve = TypeParam::Curve; - using ShpleminiProver = ShpleminiProver_; - using ShpleminiVerifier = ShpleminiVerifier_; using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using CK = typename TypeParam::CommitmentKey; - // Initialize transcript and commitment key - auto prover_transcript = TypeParam::Transcript::prover_init_empty(); + using ShpleminiProver = ShpleminiProver_; + using ShpleminiVerifier = ShpleminiVerifier_; - // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck. - static constexpr size_t log_subgroup_size = static_cast(numeric::get_msb(Curve::SUBGROUP_SIZE)); - std::shared_ptr ck = create_commitment_key(std::max(this->n, 1ULL << (log_subgroup_size + 1))); + std::shared_ptr ck = create_commitment_key(4096); - // Generate Libra polynomials, compute masked concatenated Libra polynomial, commit to it - ZKData zk_sumcheck_data(this->log_n, prover_transcript, ck); + // Generate Sumcheck challenge + std::vector challenge = this->random_evaluation_point(CONST_PROOF_SIZE_LOG_N); - // Generate multivariate challenge of size CONST_PROOF_SIZE_LOG_N - std::vector const_size_mle_opening_point = this->random_evaluation_point(CONST_PROOF_SIZE_LOG_N); - // Truncate the multivariate challenge to evaluate prover polynomials (As in Sumcheck) - const std::vector mle_opening_point(const_size_mle_opening_point.begin(), - const_size_mle_opening_point.begin() + this->log_n); + // Initialize the corresponding PCS inputs + std::vector> round_univariates = {}; + std::vector sumcheck_commitments = {}; + std::vector> sumcheck_evaluations = {}; - // Generate random prover polynomials, compute their evaluations and commitments - auto pcs_instance_witness = - InstanceWitnessGenerator(this->n, this->num_polynomials, this->num_shiftable, mle_opening_point, ck); + // Generate valid sumcheck polynomials of given length + this->compute_sumcheck_opening_data(round_univariates, sumcheck_commitments, sumcheck_evaluations, challenge, ck); + + auto prover_transcript = TypeParam::Transcript::prover_init_empty(); + + // Generate masking polynomials for Sumcheck Round Univariates + ZKSumcheckData zk_sumcheck_data(this->log_n, prover_transcript, ck); + // Generate mock witness + InstanceWitnessGenerator pcs_instance_witness(this->n, 1, ck); // Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges - const Fr claimed_inner_product = SmallSubgroupIPAProver::compute_claimed_inner_product( - zk_sumcheck_data, const_size_mle_opening_point, this->log_n); + const Fr claimed_inner_product = + SmallSubgroupIPAProver::compute_claimed_inner_product(zk_sumcheck_data, challenge, this->log_n); prover_transcript->template send_to_verifier("Libra:claimed_evaluation", claimed_inner_product); // Instantiate SmallSubgroupIPAProver, this prover sends commitments to Big Sum and Quotient polynomials - auto small_subgroup_ipa_prover = SmallSubgroupIPAProver( - zk_sumcheck_data, const_size_mle_opening_point, claimed_inner_product, prover_transcript, ck); + SmallSubgroupIPAProver small_subgroup_ipa_prover( + zk_sumcheck_data, challenge, claimed_inner_product, prover_transcript, ck); - // Reduce to KZG or IPA based on the curve used in the test Flavor + // Reduce proving to a single claimed fed to KZG or IPA const auto opening_claim = ShpleminiProver::prove(this->n, RefVector(pcs_instance_witness.unshifted_polynomials), RefVector(pcs_instance_witness.to_be_shifted_polynomials), - const_size_mle_opening_point, + challenge, ck, prover_transcript, - small_subgroup_ipa_prover.get_witness_polynomials()); + small_subgroup_ipa_prover.get_witness_polynomials(), + round_univariates, + sumcheck_evaluations); if constexpr (std::is_same_v) { IPA::compute_opening_proof(this->ck(), opening_claim, prover_transcript); @@ -372,7 +451,6 @@ TYPED_TEST(ShpleminiTest, ShpleminiWithZK) // Initialize verifier's transcript auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); - // Start populating Verifier's array of Libra commitments std::array libra_commitments = {}; libra_commitments[0] = verifier_transcript->template receive_from_prover("Libra:concatenation_commitment"); @@ -391,25 +469,25 @@ TYPED_TEST(ShpleminiTest, ShpleminiWithZK) libra_commitments[1] = verifier_transcript->template receive_from_prover("Libra:big_sum_commitment"); libra_commitments[2] = verifier_transcript->template receive_from_prover("Libra:quotient_commitment"); - // Used to verify the consistency of the evaluations of the concatenated libra polynomial, big sum polynomial, and - // the quotient polynomial computed by SmallSubgroupIPAProver bool consistency_checked = true; // Run Shplemini const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(this->n, RefVector(pcs_instance_witness.unshifted_commitments), - RefVector(pcs_instance_witness.to_be_shifted_commitments), + {}, RefVector(pcs_instance_witness.unshifted_evals), - RefVector(pcs_instance_witness.shifted_evals), - const_size_mle_opening_point, + {}, + challenge, this->vk()->get_g1_identity(), verifier_transcript, {}, true, &consistency_checked, libra_commitments, - libra_evaluation); + libra_evaluation, + sumcheck_commitments, + sumcheck_evaluations); // Verify claim using KZG or IPA if constexpr (std::is_same_v) { auto result = @@ -422,5 +500,4 @@ TYPED_TEST(ShpleminiTest, ShpleminiWithZK) EXPECT_EQ(this->vk()->pairing_check(pairing_points[0], pairing_points[1]), true); } } - } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index d1ffb1235ff..46a31c64485 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -87,7 +87,7 @@ template class ShplonkProver_ { Q.add_scaled(tmp, current_nu); current_nu *= nu; } - // size_t counter = 0; + for (const auto& claim : sumcheck_round_claims) { // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) @@ -99,7 +99,6 @@ template class ShplonkProver_ { // Add the claim quotient to the batched quotient polynomial Q.add_scaled(tmp, current_nu); current_nu *= nu; - // counter++; } // Return batched quotient polynomial Q(X) return Q; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp index f3b99924b9f..d7b8fd93f3f 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp @@ -65,6 +65,18 @@ template struct InstanceWitnessGenerator { idx++; } } + InstanceWitnessGenerator(const size_t n, + const size_t num_zero_polynomials, + std::shared_ptr& commitment_key) + : ck(commitment_key) // Initialize the commitment key + , unshifted_polynomials(num_zero_polynomials) + { + for (size_t idx = 0; idx < num_zero_polynomials; idx++) { + unshifted_polynomials[idx] = Polynomial(n); + unshifted_commitments.push_back(ck->commit(unshifted_polynomials[idx])); + unshifted_evals.push_back(Fr(0)); + } + } }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp index add13ec0075..afdcfa3a9c4 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp @@ -143,8 +143,8 @@ TEST_F(ECCVMTests, CommitedSumcheck) ZKData zk_sumcheck_data = ZKData(log_circuit_size, prover_transcript); - auto prover_output = sumcheck_prover.prove( - pk->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data, pk->commitment_key); + auto prover_output = + sumcheck_prover.prove(pk->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data); ECCVMVerifier verifier(prover.key); std::shared_ptr verifier_transcript = std::make_shared(prover_transcript->proof_data); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index 6a01449960a..1defb569f97 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -106,8 +106,7 @@ void ECCVMProver::execute_relation_check_rounds() zk_sumcheck_data = ZKData(key->log_circuit_size, transcript, key->commitment_key); - sumcheck_output = sumcheck.prove( - key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data, key->commitment_key); + sumcheck_output = sumcheck.prove(key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data); } /** diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index 57a56b33226..470dc9482f9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -27,6 +27,8 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) using OpeningClaim = OpeningClaim; RelationParameters relation_parameters; + auto init_num_gates = builder->get_estimated_num_finalized_gates(); + info("before sumcheck", init_num_gates); StdlibProof stdlib_proof = bb::convert_native_proof_to_stdlib(builder, proof.pre_ipa_proof); StdlibProof stdlib_ipa_proof = bb::convert_native_proof_to_stdlib(builder, proof.ipa_proof); @@ -87,6 +89,8 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) // Compute the Shplemini accumulator consisting of the Shplonk evaluation and the commitments and scalars vector // produced by the unified protocol + auto num_gates = builder->get_estimated_num_finalized_gates(); + info("after sumcheck", num_gates - init_num_gates); bool consistency_checked = true; BatchOpeningClaim sumcheck_batch_opening_claims = Shplemini::compute_batch_opening_claim(circuit_size, @@ -148,7 +152,7 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) const OpeningClaim batch_opening_claim = Shplonk::reduce_verification(key->pcs_verification_key->get_g1_identity(), opening_claims, transcript); - + info(" after shplemini ", builder->get_estimated_num_finalized_gates() - init_num_gates); ASSERT(sumcheck_output.verified); return { batch_opening_claim, ipa_transcript }; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp index d180fe037fa..72ec962ee90 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp @@ -72,6 +72,56 @@ template class ECCVMRecursiveTests : public ::testing InnerBuilder builder{ op_queue }; return builder; } + static InnerBuilder generate_circuit_diff_size(numeric::RNG* engine = nullptr) + { + using Curve = curve::BN254; + using G1 = Curve::Element; + using Fr = Curve::ScalarField; + + std::shared_ptr op_queue = std::make_shared(); + G1 a = G1::random_element(engine); + G1 b = G1::random_element(engine); + G1 c = G1::random_element(engine); + Fr x = Fr::random_element(engine); + Fr y = Fr::random_element(engine); + + op_queue->add_accumulate(a); + op_queue->mul_accumulate(a, x); + // op_queue->mul_accumulate(b, x); + op_queue->mul_accumulate(b, y); + op_queue->add_accumulate(a); + op_queue->mul_accumulate(b, x); + op_queue->eq_and_reset(); + op_queue->add_accumulate(c); + op_queue->mul_accumulate(a, x); + + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->eq_and_reset(); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->mul_accumulate(c, x); + InnerBuilder builder{ op_queue }; + return builder; + } static void test_recursive_verification() { @@ -123,6 +173,56 @@ template class ECCVMRecursiveTests : public ::testing ASSERT(verified); } } + static void test_recursive_verification2() + { + InnerBuilder builder = generate_circuit_diff_size(&engine); + InnerProver prover(builder); + ECCVMProof proof = prover.construct_proof(); + auto verification_key = std::make_shared(prover.key); + + info("ECCVM Recursive Verifier"); + OuterBuilder outer_circuit; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; + auto [opening_claim, ipa_transcript] = verifier.verify_proof(proof); + + info("Recursive Verifier: num gates = ", outer_circuit.get_estimated_num_finalized_gates()); + + // Check for a failure flag in the recursive verifier circuit + EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err(); + + bool result = CircuitChecker::check(outer_circuit); + EXPECT_TRUE(result); + + InnerVerifier native_verifier(prover.key); + bool native_result = native_verifier.verify_proof(proof); + EXPECT_TRUE(native_result); + auto recursive_manifest = verifier.transcript->get_manifest(); + auto native_manifest = native_verifier.transcript->get_manifest(); + for (size_t i = 0; i < recursive_manifest.size(); ++i) { + EXPECT_EQ(recursive_manifest[i], native_manifest[i]) + << "Recursive Verifier/Verifier manifest discrepency in round " << i; + } + + // Ensure verification key is the same + EXPECT_EQ(verifier.key->circuit_size, verification_key->circuit_size); + EXPECT_EQ(verifier.key->log_circuit_size, verification_key->log_circuit_size); + EXPECT_EQ(verifier.key->num_public_inputs, verification_key->num_public_inputs); + for (auto [vk_poly, native_vk_poly] : zip_view(verifier.key->get_all(), verification_key->get_all())) { + EXPECT_EQ(vk_poly.get_value(), native_vk_poly); + } + + // Construct a full proof from the recursive verifier circuit + { + auto proving_key = std::make_shared(outer_circuit); + OuterProver prover(proving_key); + auto verification_key = std::make_shared(proving_key->proving_key); + OuterVerifier verifier(verification_key); + auto proof = prover.construct_proof(); + bool verified = verifier.verify_proof(proof); + + ASSERT(verified); + } + } static void test_recursive_verification_failure() { @@ -150,6 +250,10 @@ TYPED_TEST(ECCVMRecursiveTests, SingleRecursiveVerification) TestFixture::test_recursive_verification(); }; +TYPED_TEST(ECCVMRecursiveTests, SingleRecursiveVerificationSize2) +{ + TestFixture::test_recursive_verification2(); +}; TYPED_TEST(ECCVMRecursiveTests, SingleRecursiveVerificationFailure) { TestFixture::test_recursive_verification_failure(); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index dbfd22f15cc..dcb6382f6a9 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -262,10 +262,14 @@ template class SumcheckProver { const bb::RelationParameters& relation_parameters, const RelationSeparator alpha, const std::vector& gate_challenges, - ZKData& zk_sumcheck_data, - const std::shared_ptr& ck = nullptr) + ZKData& zk_sumcheck_data) requires Flavor::HasZK { + std::shared_ptr ck = nullptr; + + if constexpr (IS_ECCVM) { + ck = std::make_shared(BATCHED_RELATION_PARTIAL_LENGTH); + } bb::GateSeparatorPolynomial gate_separators(gate_challenges, multivariate_d); @@ -744,7 +748,6 @@ template class SumcheckVerifier { multivariate_challenge.reserve(CONST_PROOF_SIZE_LOG_N); // if Flavor has ZK, the target total sum is corrected by Libra total sum multiplied by the Libra // challenge - info(round.target_total_sum); round.target_total_sum += libra_total_sum * libra_challenge; for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { @@ -779,28 +782,13 @@ template class SumcheckVerifier { } } - // Populate claimed evaluations at the challenge - for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - round_univariate_evaluations[round_idx - 1][2] = - round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; - } FF first_sumcheck_round_evaluations_sum = round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; - info("sum of evals", first_sumcheck_round_evaluations_sum); - if constexpr (IsRecursiveFlavor) { - first_sumcheck_round_evaluations_sum.self_reduce(); - round.target_total_sum.self_reduce(); - first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); - verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); - } else { - info(round.target_total_sum); - verified = (first_sumcheck_round_evaluations_sum == round.target_total_sum); - info(verified); - } + + // Populate claimed evaluations at the challenge // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge - // Final round ClaimedEvaluations purported_evaluations; auto transcript_evaluations = transcript->template receive_from_prover>("Sumcheck:evaluations"); @@ -821,7 +809,33 @@ template class SumcheckVerifier { // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) full_honk_purported_value.self_reduce(); } - round_univariate_evaluations[multivariate_d - 1][2] = full_honk_purported_value; + + if constexpr (IsRecursiveFlavor) { + + for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + typename Flavor::CircuitBuilder* builder = libra_challenge.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! + stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); + round_univariate_evaluations[round_idx - 1][2] = FF::conditional_assign( + dummy_round, + full_honk_purported_value, + round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]); + }; + + first_sumcheck_round_evaluations_sum.self_reduce(); + round.target_total_sum.self_reduce(); + first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); + verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); + } else { + for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { + round_univariate_evaluations[round_idx - 1][2] = + round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; + }; + for (size_t round_idx = multivariate_d; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + round_univariate_evaluations[round_idx - 1][2] = full_honk_purported_value; + }; + verified = (first_sumcheck_round_evaluations_sum == round.target_total_sum); + } //! [Final Verification Step] // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp index b38c4dd81a4..512a2e57203 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp @@ -87,8 +87,15 @@ template struct ZKSumcheckData { setup_auxiliary_data(libra_univariates, libra_scaling_factor, libra_challenge, libra_running_sum); } - // Constructor for test purposes. Creates log_circuit size polynomials g_i(X_i) of length univariate_length, - // computes the sum \sum_H (constant_term + \sum g_i). + /** + * @brief For test purposes: Constructs a sumcheck instance from the polynomial \f$ g + \sum_{i=0}^d g_i(X_i)\f$, + * where \f$ g_i \f$ is a random univariate of a given length and \f$ g\f$ is a random constant term. + * + * @details To test Shplemini with commitments to Sumcheck Round Univariates, we need to create valid Sumcheck Round + * Univariates. Fortunately, the functionality of ZKSumcheckData could be re-used for this purpose. + * @param multivariate_d + * @param univariate_length + */ ZKSumcheckData(const size_t multivariate_d, const size_t univariate_length) : constant_term(FF::random_element()) , libra_univariates(generate_libra_univariates(multivariate_d, univariate_length)) From 158794153f0fdcf3d460c34b6da4a4b6cde14e24 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 20 Jan 2025 13:45:39 +0000 Subject: [PATCH 16/33] const proof size + clean up + docs --- .../commitment_schemes/shplonk/shplemini.hpp | 4 +- .../shplonk/shplemini.test.cpp | 10 +- .../polynomials/row_disabling_polynomial.hpp | 22 ++++ .../src/barretenberg/sumcheck/sumcheck.hpp | 108 ++++++++++++------ 4 files changed, 109 insertions(+), 35 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index b6ee703033b..e04a459ed4d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -78,7 +78,9 @@ template class ShpleminiProver_ { std::array libra_eval_labels = { "Libra:concatenation_eval", "Libra:shifted_big_sum_eval", "Libra:big_sum_eval", "Libra:quotient_eval" }; - const std::array evaluation_points = { gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r }; + const std::array evaluation_points = { + gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r + }; for (size_t idx = 0; idx < 4; idx++) { new_claim.polynomial = std::move(libra_polynomials[idx]); new_claim.opening_pair.challenge = evaluation_points[idx]; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp index 119e6317304..bde4864e3e3 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -34,7 +34,15 @@ template class ShpleminiTest : public CommitmentTest>& round_univariates, std::vector& sumcheck_commitments, std::vector>& sumcheck_evaluations, diff --git a/barretenberg/cpp/src/barretenberg/polynomials/row_disabling_polynomial.hpp b/barretenberg/cpp/src/barretenberg/polynomials/row_disabling_polynomial.hpp index e5c2abe7f67..e4af64d824f 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/row_disabling_polynomial.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/row_disabling_polynomial.hpp @@ -174,6 +174,28 @@ template struct RowDisablingPolynomial { return FF{ 1 } - evaluation_at_multivariate_challenge; } + /** + * @brief stdlib version of the above that ensures that the verifier's work does not depend on `log_circuit_size`. + * + */ + template + static FF evaluate_at_challenge(std::vector multivariate_challenge, + const size_t log_circuit_size, + Builder* builder) + { + FF evaluation_at_multivariate_challenge{ 1 }; + const FF one = FF{ 1 }; + + for (size_t idx = 2; idx < CONST_PROOF_SIZE_LOG_N; idx++) { + stdlib::bool_t dummy_round = stdlib::witness_t(builder, idx >= log_circuit_size); + evaluation_at_multivariate_challenge = + FF::conditional_assign(dummy_round, + evaluation_at_multivariate_challenge * one, + evaluation_at_multivariate_challenge * multivariate_challenge[idx]); + } + + return one - evaluation_at_multivariate_challenge; + } }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index dcb6382f6a9..6fd67450da6 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -296,11 +296,14 @@ template class SumcheckProver { // Place the evaluations of the round univariate into transcript. transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); } else { - + // Compute the vector {0, 1, \ldots, BATCHED_RELATION_PARTIAL_LENGTH-1} needed to transform the round + // univariates from Lagrange to monomial basis for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) { eval_domain.push_back(FF(idx)); } + // Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure + // needed in the PCS round commit_to_round_univariate( round_idx, round_univariate, eval_domain, transcript, ck, round_univariates, round_evaluations); } @@ -334,6 +337,9 @@ template class SumcheckProver { // Place evaluations of Sumcheck Round Univariate in the transcript transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); } else { + + // Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure + // needed in the PCS round commit_to_round_univariate( round_idx, round_univariate, eval_domain, transcript, ck, round_univariates, round_evaluations); } @@ -485,6 +491,18 @@ polynomials that are sent in clear. return multivariate_evaluations; }; + /** + * @brief Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure + * needed in the PCS round + * + * @param round_idx + * @param round_univariate Sumcheck Round Univariate + * @param eval_domain {0, 1, ... , BATCHED_RELATION_PARTIAL_LENGTH-1} + * @param transcript + * @param ck Commitment key of size BATCHED_RELATION_PARTIAL_LENGTH + * @param round_univariates Auxiliary container to be fed to Shplemini + * @param round_univariate_evaluations Auxiliary container to be fed to Shplemini + */ void commit_to_round_univariate(const size_t round_idx, bb::Univariate& round_univariate, const std::vector& eval_domain, @@ -495,20 +513,20 @@ polynomials that are sent in clear. { const std::string idx = std::to_string(round_idx); + + // Transform to monomial form and commit to it Polynomial round_poly_monomial = Polynomial(eval_domain, std::span(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH); - auto round_univariate_commitment = ck->commit(round_poly_monomial); - transcript->send_to_verifier("Sumcheck:univariate_comm_" + idx, round_univariate_commitment); + transcript->send_to_verifier("Sumcheck:univariate_comm_" + idx, ck->commit(round_poly_monomial)); - // Store round univariate in monomial, as it is required for Shplonk + // Store round univariate in monomial, as it is required by Shplemini round_univariates.push_back(std::move(round_poly_monomial)); - // Send the evaluations of the rounds univariate at 0 and 1 + // Send the evaluations of the round univariate at 0 and 1 transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_0", round_univariate.value_at(0)); transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_1", round_univariate.value_at(1)); - // Store the evaluations to be used in Shplonk. Third value will be computed after getting the round - // challenge + // Store the evaluations to be used by ShpleminiProver. round_univariate_evaluations.push_back({ round_univariate.value_at(0), round_univariate.value_at(1), FF(0) }); if (round_idx > 0) { round_univariate_evaluations[round_idx - 1][2] = @@ -588,12 +606,15 @@ template class SumcheckVerifier { std::shared_ptr transcript; SumcheckVerifierRound round; - - static constexpr bool IS_ECCVM = std::is_same_v || IsECCVMRecursiveFlavor; + FF libra_evaluation{ 0 }; + FF libra_challenge; + FF libra_total_sum; std::vector round_univariate_commitments = {}; std::vector> round_univariate_evaluations = {}; + typename Flavor::CircuitBuilder* builder; + // 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) @@ -624,13 +645,12 @@ template class SumcheckVerifier { throw_or_abort("Number of variables in multivariate is 0."); } - FF libra_challenge; bb::Univariate round_univariate; if constexpr (Flavor::HasZK) { // If running zero-knowledge sumcheck the target total sum is corrected by the claimed sum of libra masking // multivariate over the hypercube - FF libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); + libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); libra_challenge = transcript->template get_challenge("Libra:Challenge"); round.target_total_sum += libra_total_sum * libra_challenge; } @@ -683,17 +703,12 @@ template class SumcheckVerifier { purported_evaluations, relation_parameters, gate_separators, alpha); // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge - FF libra_evaluation{ 0 }; if constexpr (Flavor::HasZK) { libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); FF correcting_factor = RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); full_honk_purported_value = full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; - if constexpr (IsECCVMRecursiveFlavor) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) - full_honk_purported_value.self_reduce(); - } } //! [Final Verification Step] @@ -713,11 +728,11 @@ template class SumcheckVerifier { * @brief Sumcheck Verifier for ECCVM and ECCVMRecursive. * @details The verifier receives commitments to RoundUnivariates, along with their evaluations at 0 and 1. These * evaluations will be proved as a part of Shplemini. The only check that the Verifier performs in this version is - * the comparison of the target sumcheck sum with the claimed evaluations of the first sumcheck round univariate. + * the comparison of the target sumcheck sum with the claimed evaluations of the first sumcheck round univariate at + * 0 and 1. * - * Note that the SumcheckOutput in this case contains a vector of commitments and a vector of arrays of evaluations - * at 0 and 1. Moreover, the purported honk value computed by the verifier has to be propagated to the PCS round, as - * it gives a claimed evaluation of the last sumcheck univariate. + * Note that the SumcheckOutput in this case contains a vector of commitments and a vector of arrays (of size 3) of + * evaluations at 0, 1, and a round challenge. * * @param relation_parameters * @param alpha @@ -740,7 +755,7 @@ template class SumcheckVerifier { } // get the claimed sum of libra masking multivariate over the hypercube - const FF libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); + libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); // get the challenge for the ZK Sumcheck claim const FF libra_challenge = transcript->template get_challenge("Libra:Challenge"); @@ -769,7 +784,7 @@ template class SumcheckVerifier { multivariate_challenge.emplace_back(round_challenge); if constexpr (IsRecursiveFlavor) { - typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); + builder = round_challenge.get_context(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); // Only utilize the checked value if this is not a constant proof size padding round @@ -786,9 +801,6 @@ template class SumcheckVerifier { round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; // Populate claimed evaluations at the challenge - - // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge - ClaimedEvaluations purported_evaluations; auto transcript_evaluations = transcript->template receive_from_prover>("Sumcheck:evaluations"); @@ -801,19 +813,29 @@ template class SumcheckVerifier { FF full_honk_purported_value = round.compute_full_relation_purported_value( purported_evaluations, relation_parameters, gate_separators, alpha); + // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge const FF libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); - const FF correcting_factor = - RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); - full_honk_purported_value = full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; - if constexpr (IsECCVMRecursiveFlavor) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) - full_honk_purported_value.self_reduce(); - } + // We have to branch here for two reasons: + // 1) need to make the vk constant + // 2) ECCVMRecursive uses big_field where we need to self_reduce(). if constexpr (IsRecursiveFlavor) { + // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the rows + // where all sumcheck relations are disabled + const FF correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d, builder); + + // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row and the + // Libra polynomials + full_honk_purported_value = + full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) + full_honk_purported_value.self_reduce(); + // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be + // checked as a part of Shplemini and pad claimed evaluations to the CONST_PROOF_SIZE_LOG_N for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - typename Flavor::CircuitBuilder* builder = libra_challenge.get_context(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); round_univariate_evaluations[round_idx - 1][2] = FF::conditional_assign( @@ -824,16 +846,36 @@ template class SumcheckVerifier { first_sumcheck_round_evaluations_sum.self_reduce(); round.target_total_sum.self_reduce(); + + // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the claimed + // target total sum first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); } else { + // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the rows + // where all sumcheck relations are disabled + const FF correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); + + // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row and the + // Libra polynomials + full_honk_purported_value = + full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; + + // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be checked + // as a part of Shplemini for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { round_univariate_evaluations[round_idx - 1][2] = round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; }; + + // Pad claimed evaluations to the CONST_PROOF_SIZE_LOG_N for (size_t round_idx = multivariate_d; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { round_univariate_evaluations[round_idx - 1][2] = full_honk_purported_value; }; + + // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the claimed + // target total sum verified = (first_sumcheck_round_evaluations_sum == round.target_total_sum); } From e94c0310674603b417290f5823013f5016c38d48 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 20 Jan 2025 13:50:40 +0000 Subject: [PATCH 17/33] eccvm bench correction --- .../src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp index 10bf6c077e6..9f96f20bea9 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp @@ -65,8 +65,8 @@ void eccvm_prove(State& state) noexcept }; } -BENCHMARK(eccvm_generate_prover)->Unit(kMillisecond)->DenseRange(12, 18); -BENCHMARK(eccvm_prove)->Unit(kMillisecond)->DenseRange(12, 18); +BENCHMARK(eccvm_generate_prover)->Unit(kMillisecond)->DenseRange(12, CONST_ECCVM_LOG_N); +BENCHMARK(eccvm_prove)->Unit(kMillisecond)->DenseRange(12, CONST_ECCVM_LOG_N); } // namespace BENCHMARK_MAIN(); From 9e5e4e79b2d29903de9b85382ad93f13971d2ced Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 20 Jan 2025 15:02:47 +0000 Subject: [PATCH 18/33] build fix --- .../commitment_schemes/shplonk/shplemini.hpp | 141 +++++++++++++----- .../eccvm/eccvm_composer.test.cpp | 2 +- .../src/barretenberg/sumcheck/sumcheck.hpp | 6 +- .../barretenberg/sumcheck/sumcheck_output.hpp | 3 +- .../sumcheck/zk_sumcheck_data.hpp | 25 ++++ 5 files changed, 131 insertions(+), 46 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index e04a459ed4d..f77b4f1f950 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -38,8 +38,6 @@ template class ShpleminiProver_ { { // While Shplemini is not templated on Flavor, we derive ZK flag this way const bool has_zk = (libra_polynomials[0].size() > 0); - const bool is_eccvm = (!sumcheck_round_univariates.empty()); - std::vector opening_claims = GeminiProver::prove(circuit_size, f_polynomials, g_polynomials, @@ -49,27 +47,10 @@ template class ShpleminiProver_ { concatenated_polynomials, groups_to_be_concatenated, has_zk); - // Create opening claims for Libra masking univariates + // Create opening claims for Libra masking univariates and Sumcheck Round Univariates std::vector libra_opening_claims; - std::vector sumcheck_round_claims; OpeningClaim new_claim; - if (is_eccvm) { - - const size_t log_circuit_size = numeric::get_msb(static_cast(circuit_size)); - for (size_t idx = 0; idx < log_circuit_size; idx++) { - const std::vector evaluation_points = { FF(0), FF(1), multilinear_challenge[idx] }; - size_t eval_idx = 0; - new_claim.polynomial = std::move(sumcheck_round_univariates[idx]); - - for (auto& eval_point : evaluation_points) { - new_claim.opening_pair.challenge = eval_point; - new_claim.opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx]; - sumcheck_round_claims.push_back(new_claim); - eval_idx++; - } - } - } if (has_zk) { static constexpr FF subgroup_generator = Curve::subgroup_generator; @@ -90,6 +71,25 @@ template class ShpleminiProver_ { } } + // Currently, only used in ECCVM. + std::vector sumcheck_round_claims; + + if (!sumcheck_round_univariates.empty()) { + const size_t log_circuit_size = numeric::get_msb(static_cast(circuit_size)); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + const std::vector evaluation_points = { FF(0), FF(1), multilinear_challenge[idx] }; + size_t eval_idx = 0; + new_claim.polynomial = std::move(sumcheck_round_univariates[idx]); + + for (auto& eval_point : evaluation_points) { + new_claim.opening_pair.challenge = eval_point; + new_claim.opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx]; + sumcheck_round_claims.push_back(new_claim); + eval_idx++; + } + } + } + const OpeningClaim batched_claim = ShplonkProver::prove( commitment_key, opening_claims, transcript, libra_opening_claims, sumcheck_round_claims); return batched_claim; @@ -332,10 +332,6 @@ template class ShpleminiVerifier_ { // Add A₀(−r)/(z+r) to the constant term accumulator constant_term_accumulator += gemini_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[1]; - // Finalize the batch opening claim - commitments.emplace_back(g1_identity); - scalars.emplace_back(constant_term_accumulator); - remove_repeated_commitments(commitments, scalars, repeated_commitments, has_zk); // For ZK flavors, the sumcheck output contains the evaluations of Libra univariates that submitted to the @@ -343,6 +339,7 @@ template class ShpleminiVerifier_ { if (has_zk) { add_zk_data(commitments, scalars, + constant_term_accumulator, libra_commitments, libra_evaluations, gemini_evaluation_challenge, @@ -353,16 +350,23 @@ template class ShpleminiVerifier_ { libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation); } + // Currently, only used in ECCVM if (!sumcheck_round_evaluations.empty()) { batch_sumcheck_round_claims(log_circuit_size, commitments, scalars, + constant_term_accumulator, multivariate_challenge, shplonk_batching_challenge, shplonk_evaluation_challenge, sumcheck_round_commitments, sumcheck_round_evaluations); } + + // Finalize the batch opening claim + commitments.emplace_back(g1_identity); + scalars.emplace_back(constant_term_accumulator); + return { commitments, scalars, shplonk_evaluation_challenge }; }; /** @@ -655,6 +659,7 @@ template class ShpleminiVerifier_ { */ static void add_zk_data(std::vector& commitments, std::vector& scalars, + Fr& constant_term_accumulator, const std::array& libra_commitments, const std::array& libra_evaluations, const Fr& gemini_evaluation_challenge, @@ -668,9 +673,6 @@ template class ShpleminiVerifier_ { shplonk_challenge_power *= shplonk_batching_challenge; } - // need to keep track of the contribution to the constant term - Fr& constant_term = scalars.back(); - // add Libra commitments to the vector of commitments for (size_t idx = 0; idx < libra_commitments.size(); idx++) { commitments.push_back(libra_commitments[idx]); @@ -692,7 +694,7 @@ template class ShpleminiVerifier_ { Fr scaling_factor = denominators[idx] * shplonk_challenge_power; batching_scalars[idx] = -scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; - constant_term += scaling_factor * libra_evaluations[idx]; + constant_term_accumulator += scaling_factor * libra_evaluations[idx]; } // to save a scalar mul, add the sum of the batching scalars corresponding to the big sum evaluations @@ -701,9 +703,52 @@ template class ShpleminiVerifier_ { scalars.push_back(batching_scalars[3]); } + /** + * @brief Adds the Sumcheck data into the Shplemini BatchOpeningClaim. + * + * @details This method computes denominators for the evaluations of Sumcheck Round Unviariates, combines them with + * powers of the Shplonk batching challenge (\f$\nu\f$), and appends the resulting batched scalar factors to + * \p scalars. It also updates \p commitments with Sumcheck's round commitments. The \p constant_term_accumulator is + * incremented by each round's constant term contribution. + * + * Specifically, for round \f$i\f$ (with Sumcheck challenge \f$u_i\f$), we define: + * \f[ + * \alpha_i^0 = \frac{\nu^{k+3i}}{z}, \quad + * \alpha_i^1 = \frac{\nu^{k+3i+1}}{z - 1}, \quad + * \alpha_i^2 = \frac{\nu^{k+3i+2}}{z - u_i}, + * \f] + * where \f$ z\f$ is the Shplonk evaluation challenge, \f$\nu\f$ is the batching challenge, and \f$k\f$ is an + * offset exponent equal to CONST_PROOF_SIZE_LOG_N + 2 + NUM_LIBRA_EVALATIONS. Then: + * + * - The **batched scalar** appended to \p scalars is + * \f[ + * \text{batched_scaling_factor}_i \;=\; + * -\bigl(\alpha_i^0 + \alpha_i^1 + \alpha_i^2\bigr). + * \f] + * - The **constant term** contribution for round \f$i\f$ is + * \f[ + * \text{const_term_contribution}_i \;=\; + * \alpha_i^0 \cdot S_i(0) + * + \alpha_i^1 \cdot S_i(1) + * + \alpha_i^2 \cdot S_i\bigl(u_i\bigr), + * \f] + * where \f$S_i(x)\f$ denotes the Sumcheck round-\f$i\f$ univariate polynomial. This contribution is added to + * \p constant_term_accumulator. + * + * @param log_circuit_size + * @param commitments + * @param scalars + * @param constant_term_accumulator + * @param multilinear_challenge + * @param shplonk_batching_challenge + * @param shplonk_evaluation_challenge + * @param sumcheck_round_commitments + * @param sumcheck_round_evaluations + */ static void batch_sumcheck_round_claims(const size_t log_circuit_size, std::vector& commitments, std::vector& scalars, + Fr& constant_term_accumulator, const std::vector& multilinear_challenge, const Fr& shplonk_batching_challenge, const Fr& shplonk_evaluation_challenge, @@ -712,22 +757,28 @@ template class ShpleminiVerifier_ { { std::vector denominators = {}; + + // Compute the next power of Shplonk batching challenge \nu Fr shplonk_challenge_power = Fr{ 1 }; - for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_LIBRA_COMMITMENTS + 1; ++j) { + for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_LIBRA_EVALUATIONS; ++j) { shplonk_challenge_power *= shplonk_batching_challenge; } - Fr& constant_term = scalars[scalars.size() - 4]; - + // Denominators for the opening claims at 0 and 1. Need to be computed only once as opposed to the claims at the + // sumcheck round challenges. std::array const_denominators; const_denominators[0] = Fr(1) / (shplonk_evaluation_challenge); const_denominators[1] = Fr(1) / (shplonk_evaluation_challenge - Fr{ 1 }); + // Compute the denominators corresponding to the evaluation claims at the round challenges and add the + // commitments to the sumcheck round univariates to the vector of commitments for (const auto& [challenge, comm] : zip_view(multilinear_challenge, sumcheck_round_commitments)) { denominators.push_back(shplonk_evaluation_challenge - challenge); commitments.push_back(comm); } + + // Invert denominators if constexpr (!Curve::is_stdlib_type) { Fr::batch_invert(denominators); } else { @@ -735,39 +786,47 @@ template class ShpleminiVerifier_ { denominator = Fr{ 1 } / denominator; } } + + // Each commitment to a sumcheck round univariate [S_i] is multiplied by the sum of three scalars corresponding + // to the evaluations at 0, 1, and the round challenge u_i size_t round_idx = 0; for (const auto& [eval_array, denominator] : zip_view(sumcheck_round_evaluations, denominators)) { - Fr batched_scaling_factor = Fr(0); + // Initialize batched_scalar corresponding to 3 evaluations claims + Fr batched_scalar = Fr(0); Fr const_term_contribution = Fr(0); + // Compute the contribution from the evaluations at 0 and 1 for (size_t idx = 0; idx < 2; idx++) { Fr current_scaling_factor = const_denominators[idx] * shplonk_challenge_power; - batched_scaling_factor -= current_scaling_factor; + batched_scalar -= current_scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; const_term_contribution += current_scaling_factor * eval_array[idx]; } - Fr current_scaling_factor = denominator * shplonk_challenge_power; - batched_scaling_factor -= current_scaling_factor; + // Compute the contribution from the evaluation at the challenge u_i + Fr current_scaling_factor = denominator * shplonk_challenge_power; + batched_scalar -= current_scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; - const_term_contribution += current_scaling_factor * eval_array[2]; + // Pad the accumulators with dummy 0 values + const Fr zero = Fr(0); if constexpr (Curve::is_stdlib_type) { auto builder = shplonk_batching_challenge.get_context(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= log_circuit_size); - Fr zero = Fr(0); const_term_contribution = Fr::conditional_assign(dummy_round, zero, const_term_contribution); - batched_scaling_factor = Fr::conditional_assign(dummy_round, zero, batched_scaling_factor); + batched_scalar = Fr::conditional_assign(dummy_round, zero, batched_scalar); } else { if (round_idx >= log_circuit_size) { const_term_contribution = 0; - batched_scaling_factor = 0; + batched_scalar = 0; } } - constant_term += const_term_contribution; - scalars.push_back(batched_scaling_factor); + + // Update Shplonk constant term accumualator + constant_term_accumulator += const_term_contribution; + scalars.push_back(batched_scalar); round_idx++; } }; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp index afdcfa3a9c4..5c9177d986c 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp @@ -114,7 +114,7 @@ TEST_F(ECCVMTests, EqFails) ASSERT_FALSE(verified); } -TEST_F(ECCVMTests, CommitedSumcheck) +TEST_F(ECCVMTests, CommittedSumcheck) { using Flavor = ECCVMFlavor; using ProvingKey = ECCVMFlavor::ProvingKey; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 6fd67450da6..91a0992b52a 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -613,8 +613,6 @@ template class SumcheckVerifier { std::vector round_univariate_commitments = {}; std::vector> round_univariate_evaluations = {}; - typename Flavor::CircuitBuilder* builder; - // 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) @@ -784,7 +782,7 @@ template class SumcheckVerifier { multivariate_challenge.emplace_back(round_challenge); if constexpr (IsRecursiveFlavor) { - builder = round_challenge.get_context(); + typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); // Only utilize the checked value if this is not a constant proof size padding round @@ -820,6 +818,8 @@ template class SumcheckVerifier { // 1) need to make the vk constant // 2) ECCVMRecursive uses big_field where we need to self_reduce(). if constexpr (IsRecursiveFlavor) { + typename Flavor::CircuitBuilder* builder = libra_challenge.get_context(); + // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the rows // where all sumcheck relations are disabled const FF correcting_factor = diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp index 9b3ab52330b..bde613f3931 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp @@ -11,6 +11,7 @@ namespace bb { * @brief Contains the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N\f$ at the challenge point \f$\vec u * =(u_0,\ldots, u_{d-1})\f$. These are computed by \ref bb::SumcheckProver< Flavor > "Sumcheck Prover" and need to be * checked using Shplemini. + * @tparam Flavor */ template struct SumcheckOutput { using FF = typename Flavor::FF; @@ -33,4 +34,4 @@ template struct SumcheckOutput { // For ECCVMProver/Verifier: evaluations of round univariates at 0, 1, and round challenge std::vector> round_univariate_evaluations = {}; }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp index 512a2e57203..0701ebb2f52 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp @@ -241,6 +241,31 @@ template struct ZKSumcheckData { } } + /** + * @brief Upon receiving the challenge \f$u_i\f$, the prover updates Libra data. If \f$ i < d-1\f$ + + - update the table of Libra univariates by multiplying every term by \f$1/2\f$. + - computes the value \f$2^{d-i - 2} \cdot \texttt{libra_challenge} \cdot g_0(u_0)\f$ applying \ref + bb::Univariate::evaluate "evaluate" method to the first univariate in the table \f$\texttt{libra_univariates}\f$ + - places the value \f$ g_0(u_0)\f$ to the vector \f$ \texttt{libra_evaluations}\f$ + - update the running sum + \f{align}{ + \texttt{libra_running_sum} \gets 2^{d-i-2} \cdot \texttt{libra_challenge} \cdot g_0(u_0) + 2^{-1} + \cdot \left( \texttt{libra_running_sum} - (\texttt{libra_univariates}_{i+1}(0) + + \texttt{libra_univariates}_{i+1}(1)) \right) \f} If \f$ i = d-1\f$ + - compute the value \f$ g_{d-1}(u_{d-1})\f$ applying \ref bb::Univariate::evaluate "evaluate" method to the + last univariate in the table \f$\texttt{libra_univariates}\f$ and dividing the result by \f$ + \texttt{libra_challenge} \f$. + - update the table of Libra univariates by multiplying every term by \f$\texttt{libra_challenge}^{-1}\f$. + @todo Refactor once the Libra univariates are extracted from the Proving Key. Then the prover does not need to + update the first round_idx - 1 univariates and could release the memory. Also, use batch_invert / reduce + the number of divisions by 2. + * @param libra_univariates + * @param round_challenge + * @param round_idx + * @param libra_running_sum + * @param libra_evaluations + */ void update_zk_sumcheck_data(const FF round_challenge, const size_t round_idx) { static constexpr FF two_inv = FF(1) / FF(2); From 6731c5d33564276a6a46fc62bc52d68a667427d0 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 20 Jan 2025 16:40:31 +0000 Subject: [PATCH 19/33] more clean-up --- .../commitment_schemes/shplonk/shplonk.hpp | 1 - .../utils/instance_witness_generator.hpp | 2 + .../eccvm/eccvm_transcript.test.cpp | 6 - .../src/barretenberg/eccvm/eccvm_verifier.cpp | 2 +- .../eccvm_recursive_verifier.cpp | 8 +- .../eccvm_recursive_verifier.test.cpp | 104 ------------------ .../sumcheck/zk_sumcheck_data.hpp | 2 +- 7 files changed, 6 insertions(+), 119 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index 46a31c64485..f7cd6b15c02 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -93,7 +93,6 @@ template class ShplonkProver_ { // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) tmp = claim.polynomial; tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; - // info("prover const term", tmp.at(0)); tmp.factor_roots(claim.opening_pair.challenge); // Add the claim quotient to the batched quotient polynomial diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp index d7b8fd93f3f..60dd83fd301 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp @@ -65,6 +65,8 @@ template struct InstanceWitnessGenerator { idx++; } } + + // Generate zero polynomials to test edge cases in PCS InstanceWitnessGenerator(const size_t n, const size_t num_zero_polynomials, std::shared_ptr& commitment_key) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index bb525da244f..be64494b572 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -284,9 +284,6 @@ TEST_F(ECCVMTranscriptTests, ProverManifestConsistency) auto manifest_expected = this->construct_eccvm_honk_manifest(); auto prover_manifest = prover.transcript->get_manifest(); - manifest_expected.print(); - info("====="); - prover_manifest.print(); // Note: a manifest can be printed using manifest.print() for (size_t round = 0; round < manifest_expected.size(); ++round) { ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round; @@ -323,9 +320,6 @@ TEST_F(ECCVMTranscriptTests, VerifierManifestConsistency) // Check consistency between the manifests generated by the prover and verifier auto prover_manifest = prover.transcript->get_manifest(); auto verifier_manifest = verifier.transcript->get_manifest(); - prover_manifest.print(); - info("========"); - verifier_manifest.print(); // Note: a manifest can be printed using manifest.print() // The last challenge generated by the ECCVM Prover is the translation univariate batching challenge and, on the diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index e03d175dd7c..83ae8a677b9 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -65,7 +65,7 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); // If Sumcheck did not verify, return false - if (!sumcheck_output.verified) { + if (sumcheck_output.verified.has_value() && !sumcheck_output.verified.value()) { vinfo("eccvm sumcheck failed"); return false; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index 470dc9482f9..23ec6675d47 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -27,8 +27,6 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) using OpeningClaim = OpeningClaim; RelationParameters relation_parameters; - auto init_num_gates = builder->get_estimated_num_finalized_gates(); - info("before sumcheck", init_num_gates); StdlibProof stdlib_proof = bb::convert_native_proof_to_stdlib(builder, proof.pre_ipa_proof); StdlibProof stdlib_ipa_proof = bb::convert_native_proof_to_stdlib(builder, proof.ipa_proof); @@ -89,8 +87,6 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) // Compute the Shplemini accumulator consisting of the Shplonk evaluation and the commitments and scalars vector // produced by the unified protocol - auto num_gates = builder->get_estimated_num_finalized_gates(); - info("after sumcheck", num_gates - init_num_gates); bool consistency_checked = true; BatchOpeningClaim sumcheck_batch_opening_claims = Shplemini::compute_batch_opening_claim(circuit_size, @@ -152,8 +148,8 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) const OpeningClaim batch_opening_claim = Shplonk::reduce_verification(key->pcs_verification_key->get_g1_identity(), opening_claims, transcript); - info(" after shplemini ", builder->get_estimated_num_finalized_gates() - init_num_gates); - ASSERT(sumcheck_output.verified); + + ASSERT(sumcheck_output.verified.value()); return { batch_opening_claim, ipa_transcript }; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp index 72ec962ee90..d180fe037fa 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp @@ -72,56 +72,6 @@ template class ECCVMRecursiveTests : public ::testing InnerBuilder builder{ op_queue }; return builder; } - static InnerBuilder generate_circuit_diff_size(numeric::RNG* engine = nullptr) - { - using Curve = curve::BN254; - using G1 = Curve::Element; - using Fr = Curve::ScalarField; - - std::shared_ptr op_queue = std::make_shared(); - G1 a = G1::random_element(engine); - G1 b = G1::random_element(engine); - G1 c = G1::random_element(engine); - Fr x = Fr::random_element(engine); - Fr y = Fr::random_element(engine); - - op_queue->add_accumulate(a); - op_queue->mul_accumulate(a, x); - // op_queue->mul_accumulate(b, x); - op_queue->mul_accumulate(b, y); - op_queue->add_accumulate(a); - op_queue->mul_accumulate(b, x); - op_queue->eq_and_reset(); - op_queue->add_accumulate(c); - op_queue->mul_accumulate(a, x); - - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->eq_and_reset(); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->mul_accumulate(c, x); - InnerBuilder builder{ op_queue }; - return builder; - } static void test_recursive_verification() { @@ -173,56 +123,6 @@ template class ECCVMRecursiveTests : public ::testing ASSERT(verified); } } - static void test_recursive_verification2() - { - InnerBuilder builder = generate_circuit_diff_size(&engine); - InnerProver prover(builder); - ECCVMProof proof = prover.construct_proof(); - auto verification_key = std::make_shared(prover.key); - - info("ECCVM Recursive Verifier"); - OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, verification_key }; - auto [opening_claim, ipa_transcript] = verifier.verify_proof(proof); - - info("Recursive Verifier: num gates = ", outer_circuit.get_estimated_num_finalized_gates()); - - // Check for a failure flag in the recursive verifier circuit - EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err(); - - bool result = CircuitChecker::check(outer_circuit); - EXPECT_TRUE(result); - - InnerVerifier native_verifier(prover.key); - bool native_result = native_verifier.verify_proof(proof); - EXPECT_TRUE(native_result); - auto recursive_manifest = verifier.transcript->get_manifest(); - auto native_manifest = native_verifier.transcript->get_manifest(); - for (size_t i = 0; i < recursive_manifest.size(); ++i) { - EXPECT_EQ(recursive_manifest[i], native_manifest[i]) - << "Recursive Verifier/Verifier manifest discrepency in round " << i; - } - - // Ensure verification key is the same - EXPECT_EQ(verifier.key->circuit_size, verification_key->circuit_size); - EXPECT_EQ(verifier.key->log_circuit_size, verification_key->log_circuit_size); - EXPECT_EQ(verifier.key->num_public_inputs, verification_key->num_public_inputs); - for (auto [vk_poly, native_vk_poly] : zip_view(verifier.key->get_all(), verification_key->get_all())) { - EXPECT_EQ(vk_poly.get_value(), native_vk_poly); - } - - // Construct a full proof from the recursive verifier circuit - { - auto proving_key = std::make_shared(outer_circuit); - OuterProver prover(proving_key); - auto verification_key = std::make_shared(proving_key->proving_key); - OuterVerifier verifier(verification_key); - auto proof = prover.construct_proof(); - bool verified = verifier.verify_proof(proof); - - ASSERT(verified); - } - } static void test_recursive_verification_failure() { @@ -250,10 +150,6 @@ TYPED_TEST(ECCVMRecursiveTests, SingleRecursiveVerification) TestFixture::test_recursive_verification(); }; -TYPED_TEST(ECCVMRecursiveTests, SingleRecursiveVerificationSize2) -{ - TestFixture::test_recursive_verification2(); -}; TYPED_TEST(ECCVMRecursiveTests, SingleRecursiveVerificationFailure) { TestFixture::test_recursive_verification_failure(); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp index 0701ebb2f52..998b986b195 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp @@ -82,7 +82,7 @@ template struct ZKSumcheckData { // Initialize the Libra running sum libra_running_sum = libra_total_sum * libra_challenge; - // Setup the Libra data + // Prepare the Libra data for the first round of sumcheck setup_auxiliary_data(libra_univariates, libra_scaling_factor, libra_challenge, libra_running_sum); } From 48a1a186f5cc9837c0f9450a8506bff5f2ef467f Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 20 Jan 2025 17:45:52 +0000 Subject: [PATCH 20/33] eccvm recursive failure tests fixed --- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 6 ++++++ .../stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 9ca4c61dc97..7d09a544bb1 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -4,6 +4,7 @@ #include "barretenberg/ecc/curves/bn254/bn254.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" #include "barretenberg/sumcheck/zk_sumcheck_data.hpp" #include @@ -493,6 +494,11 @@ template class SmallSubgroupIPAVerifier { diff += lagrange_last * (big_sum_eval - inner_product_eval_claim) - vanishing_poly_eval * quotient_eval; if constexpr (Curve::is_stdlib_type) { + if constexpr (std::is_same_v>) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) + diff.self_reduce(); + } + diff.assert_equal(FF(0)); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. return (diff.get_value() == FF(0).get_value()); } else { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index 23ec6675d47..cdd92da6198 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -149,7 +149,6 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) const OpeningClaim batch_opening_claim = Shplonk::reduce_verification(key->pcs_verification_key->get_g1_identity(), opening_claims, transcript); - ASSERT(sumcheck_output.verified.value()); return { batch_opening_claim, ipa_transcript }; } From fdb62f1d434e173cfba94fb7c7f8fcdea37c4518 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 20 Jan 2025 19:30:42 +0000 Subject: [PATCH 21/33] bug fix --- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 7d09a544bb1..740439ead22 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -419,7 +419,9 @@ template class SmallSubgroupIPAVerifier { static constexpr size_t SUBGROUP_SIZE = Curve::SUBGROUP_SIZE; - static constexpr size_t LIBRA_UNIVARIATES_LENGTH = (std::is_same_v) ? 9 : 3; + static constexpr size_t LIBRA_UNIVARIATES_LENGTH = + (std::is_same_v || std::is_same_v>) ? 3 + : 9; public: /*! From aa3f90b8b4fbbd72dabe9c600e35fec4edc54e2e Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 21 Jan 2025 10:34:53 +0000 Subject: [PATCH 22/33] MegaZKRecursive const vk fix + test --- .../ultra_recursive_verifier.test.cpp | 3 ++- .../cpp/src/barretenberg/sumcheck/sumcheck.hpp | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp index 5e854a677a1..5d9887c5ac6 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp @@ -360,7 +360,8 @@ HEAVY_TYPED_TEST(RecursiveVerifierTest, IndependentVKHash) { if constexpr (IsAnyOf, - UltraRollupRecursiveFlavor_>) { + UltraRollupRecursiveFlavor_, + MegaZKRecursiveFlavor_>) { TestFixture::test_independent_vk_hash(); } else { GTEST_SKIP() << "Not built for this parameter"; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 91a0992b52a..9abf4c69733 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -609,6 +609,7 @@ template class SumcheckVerifier { FF libra_evaluation{ 0 }; FF libra_challenge; FF libra_total_sum; + FF correcting_factor; std::vector round_univariate_commitments = {}; std::vector> round_univariate_evaluations = {}; @@ -703,8 +704,15 @@ template class SumcheckVerifier { // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge if constexpr (Flavor::HasZK) { libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); - FF correcting_factor = - RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); + if constexpr (!IsRecursiveFlavor) { + correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); + } else { + typename Flavor::CircuitBuilder* builder = libra_evaluation.get_context(); + correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d, builder); + } + full_honk_purported_value = full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; } @@ -819,11 +827,12 @@ template class SumcheckVerifier { // 2) ECCVMRecursive uses big_field where we need to self_reduce(). if constexpr (IsRecursiveFlavor) { typename Flavor::CircuitBuilder* builder = libra_challenge.get_context(); - + info("before correcting factor ", builder->get_estimated_num_finalized_gates); // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the rows // where all sumcheck relations are disabled const FF correcting_factor = RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d, builder); + info("after correcting factor ", builder->get_estimated_num_finalized_gates); // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row and the // Libra polynomials From d2f45810191ad8e87421c99dbd7406bae290a104 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 21 Jan 2025 12:12:23 +0000 Subject: [PATCH 23/33] translator test added --- .../ultra_recursive_verifier.test.cpp | 2 +- .../translator_recursive_verifier.test.cpp | 107 ++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp index 5d9887c5ac6..2a080aa1ee0 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp @@ -137,7 +137,7 @@ template class RecursiveVerifierTest : public testing /** * @brief Ensures that the recursive verifier circuit for two inner circuits of different size is the same as the - * proofs are currently constant. This is done by taking each trace block in part and checking all it's selector + * proofs are currently constant. This is done by taking each trace block in part and checking all its selector * values. * */ diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index 9e7c0d5745d..589e765b573 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp @@ -121,6 +121,104 @@ template class TranslatorRecursiveTests : public ::te ASSERT(verified); } } + + static void test_independent_vk_hash() + { + + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + auto get_blocks = [](size_t inner_size) -> std::tuple> { + // Create an arbitrary inner circuit + auto P1 = InnerG1::random_element(); + auto P2 = InnerG1::random_element(); + auto z = InnerFF::random_element(); + + // Add the same operations to the ECC op queue; the native computation is performed under the hood. + auto op_queue = std::make_shared(); + op_queue->append_nonzero_ops(); + + for (size_t i = 0; i < inner_size; i++) { + op_queue->add_accumulate(P1); + op_queue->mul_accumulate(P2, z); + } + + auto prover_transcript = std::make_shared(); + prover_transcript->send_to_verifier("init", InnerBF::random_element()); + + // normally this would be the eccvm proof + auto fake_inital_proof = prover_transcript->export_proof(); + InnerBF translation_batching_challenge = + prover_transcript->template get_challenge("Translation:batching_challenge"); + InnerBF translation_evaluation_challenge = InnerBF::random_element(); + + auto inner_circuit = + InnerBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); + + // Generate a proof over the inner circuit + auto inner_proving_key = std::make_shared(inner_circuit); + InnerProver inner_prover(inner_proving_key, prover_transcript); + info("test circuit size: ", inner_proving_key->proving_key->circuit_size); + auto verification_key = + std::make_shared(inner_prover.key->proving_key); + auto inner_proof = inner_prover.construct_proof(); + + // Create a recursive verification circuit for the proof of the inner circuit + OuterBuilder outer_circuit; + + // Mock a previous verifier that would in reality be the ECCVM recursive verifier + StdlibProof stdlib_proof = + bb::convert_native_proof_to_stdlib(&outer_circuit, fake_inital_proof); + auto transcript = std::make_shared(stdlib_proof); + transcript->template receive_from_prover("init"); + + RecursiveVerifier verifier{ &outer_circuit, verification_key, transcript }; + + auto outer_proving_key = std::make_shared(outer_circuit); + auto outer_verification_key = + std::make_shared(outer_proving_key->proving_key); + + return { outer_circuit.blocks, outer_verification_key }; + }; + + bool broke(false); + auto check_eq = [&broke](auto& p1, auto& p2) { + EXPECT_TRUE(p1.size() == p2.size()); + for (size_t idx = 0; idx < p1.size(); idx++) { + if (p1[idx] != p2[idx]) { + broke = true; + break; + } + } + }; + + auto [blocks_10, verification_key_10] = get_blocks(256); + auto [blocks_11, verification_key_11] = get_blocks(512); + + size_t block_idx = 0; + for (auto [b_10, b_11] : zip_view(blocks_10.get(), blocks_11.get())) { + info("block index: ", block_idx); + EXPECT_TRUE(b_10.selectors.size() == 13); + EXPECT_TRUE(b_11.selectors.size() == 13); + for (auto [p_10, p_11] : zip_view(b_10.selectors, b_11.selectors)) { + check_eq(p_10, p_11); + } + block_idx++; + } + + typename OuterFlavor::CommitmentLabels labels; + for (auto [vk_10, vk_11, label] : + zip_view(verification_key_10->get_all(), verification_key_11->get_all(), labels.get_precomputed())) { + if (vk_10 != vk_11) { + broke = true; + info("Mismatch verification key label: ", label, " left: ", vk_10, " right: ", vk_11); + } + } + + EXPECT_TRUE(verification_key_10->circuit_size == verification_key_11->circuit_size); + EXPECT_TRUE(verification_key_10->num_public_inputs == verification_key_11->num_public_inputs); + + EXPECT_FALSE(broke); + }; }; using FlavorTypes = testing::Types, @@ -133,4 +231,13 @@ TYPED_TEST(TranslatorRecursiveTests, SingleRecursiveVerification) { TestFixture::test_recursive_verification(); }; + +TYPED_TEST(TranslatorRecursiveTests, IndependentVKHash) +{ + if constexpr (std::is_same_v>) { + TestFixture::test_independent_vk_hash(); + } else { + GTEST_SKIP() << "Not built for this parameter"; + } +}; } // namespace bb \ No newline at end of file From 4f878ab01d0dbc5a8a0207cae719c5f2055ee26c Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 21 Jan 2025 12:52:17 +0000 Subject: [PATCH 24/33] eccvm test added --- .../eccvm_recursive_verifier.test.cpp | 107 +++++++++++++++--- .../ultra_recursive_verifier.test.cpp | 1 - .../translator_recursive_verifier.test.cpp | 1 + .../src/barretenberg/sumcheck/sumcheck.hpp | 2 - 4 files changed, 92 insertions(+), 19 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp index d180fe037fa..06b0ccdde70 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp @@ -20,6 +20,8 @@ template class ECCVMRecursiveTests : public ::testing using InnerG1 = InnerFlavor::Commitment; using InnerFF = InnerFlavor::FF; using InnerBF = InnerFlavor::BF; + using InnerPK = InnerFlavor::ProvingKey; + using InnerVK = InnerFlavor::VerificationKey; using Transcript = InnerFlavor::Transcript; @@ -42,7 +44,7 @@ template class ECCVMRecursiveTests : public ::testing * @param engine * @return ECCVMCircuitBuilder */ - static InnerBuilder generate_circuit(numeric::RNG* engine = nullptr) + static InnerBuilder generate_circuit(numeric::RNG* engine = nullptr, const size_t num_iterations = 1) { using Curve = curve::BN254; using G1 = Curve::Element; @@ -54,21 +56,22 @@ template class ECCVMRecursiveTests : public ::testing G1 c = G1::random_element(engine); Fr x = Fr::random_element(engine); Fr y = Fr::random_element(engine); - - op_queue->add_accumulate(a); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->mul_accumulate(b, y); - op_queue->add_accumulate(a); - op_queue->mul_accumulate(b, x); - op_queue->eq_and_reset(); - op_queue->add_accumulate(c); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->eq_and_reset(); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->mul_accumulate(c, x); + for (size_t idx = 0; idx < num_iterations; idx++) { + op_queue->add_accumulate(a); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->mul_accumulate(b, y); + op_queue->add_accumulate(a); + op_queue->mul_accumulate(b, x); + op_queue->eq_and_reset(); + op_queue->add_accumulate(c); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->eq_and_reset(); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->mul_accumulate(c, x); + } InnerBuilder builder{ op_queue }; return builder; } @@ -140,6 +143,73 @@ template class ECCVMRecursiveTests : public ::testing // Check for a failure flag in the recursive verifier circuit EXPECT_FALSE(CircuitChecker::check(outer_circuit)); } + + static void test_independent_vk_hash() + { + + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + auto get_blocks = [](size_t inner_size) -> std::tuple> { + auto inner_circuit = generate_circuit(&engine, inner_size); + InnerProver inner_prover(inner_circuit); + info("test circuit size: ", inner_prover.key->circuit_size); + + ECCVMProof inner_proof = inner_prover.construct_proof(); + auto verification_key = std::make_shared(inner_prover.key); + + // Create a recursive verification circuit for the proof of the inner circuit + OuterBuilder outer_circuit; + + RecursiveVerifier verifier{ &outer_circuit, verification_key }; + + auto [opening_claim, ipa_transcript] = verifier.verify_proof(inner_proof); + + auto outer_proving_key = std::make_shared(outer_circuit); + auto outer_verification_key = + std::make_shared(outer_proving_key->proving_key); + + return { outer_circuit.blocks, outer_verification_key }; + }; + + bool broke(false); + auto check_eq = [&broke](auto& p1, auto& p2) { + EXPECT_TRUE(p1.size() == p2.size()); + for (size_t idx = 0; idx < p1.size(); idx++) { + if (p1[idx] != p2[idx]) { + broke = true; + break; + } + } + }; + + auto [blocks_10, verification_key_10] = get_blocks(20); + auto [blocks_11, verification_key_11] = get_blocks(50); + + size_t block_idx = 0; + for (auto [b_10, b_11] : zip_view(blocks_10.get(), blocks_11.get())) { + info("block index: ", block_idx); + EXPECT_TRUE(b_10.selectors.size() == 13); + EXPECT_TRUE(b_11.selectors.size() == 13); + for (auto [p_10, p_11] : zip_view(b_10.selectors, b_11.selectors)) { + check_eq(p_10, p_11); + } + block_idx++; + } + + typename OuterFlavor::CommitmentLabels labels; + for (auto [vk_10, vk_11, label] : + zip_view(verification_key_10->get_all(), verification_key_11->get_all(), labels.get_precomputed())) { + if (vk_10 != vk_11) { + broke = true; + info("Mismatch verification key label: ", label, " left: ", vk_10, " right: ", vk_11); + } + } + + EXPECT_TRUE(verification_key_10->circuit_size == verification_key_11->circuit_size); + EXPECT_TRUE(verification_key_10->num_public_inputs == verification_key_11->num_public_inputs); + + EXPECT_FALSE(broke); + }; }; using FlavorTypes = testing::Types>; @@ -154,4 +224,9 @@ TYPED_TEST(ECCVMRecursiveTests, SingleRecursiveVerificationFailure) { TestFixture::test_recursive_verification_failure(); }; + +TYPED_TEST(ECCVMRecursiveTests, IndependentVKHash) +{ + TestFixture::test_independent_vk_hash(); +}; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp index 2a080aa1ee0..9c65178da92 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp @@ -160,7 +160,6 @@ template class RecursiveVerifierTest : public testing // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; RecursiveVerifier verifier{ &outer_circuit, verification_key }; - HonkProof honk_proof; typename RecursiveVerifier::Output verifier_output = verifier.verify_proof( inner_proof, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index 589e765b573..a8a97ab810c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp @@ -172,6 +172,7 @@ template class TranslatorRecursiveTests : public ::te transcript->template receive_from_prover("init"); RecursiveVerifier verifier{ &outer_circuit, verification_key, transcript }; + verifier.verify_proof(inner_proof); auto outer_proving_key = std::make_shared(outer_circuit); auto outer_verification_key = diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 9abf4c69733..1031ac642c5 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -827,12 +827,10 @@ template class SumcheckVerifier { // 2) ECCVMRecursive uses big_field where we need to self_reduce(). if constexpr (IsRecursiveFlavor) { typename Flavor::CircuitBuilder* builder = libra_challenge.get_context(); - info("before correcting factor ", builder->get_estimated_num_finalized_gates); // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the rows // where all sumcheck relations are disabled const FF correcting_factor = RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d, builder); - info("after correcting factor ", builder->get_estimated_num_finalized_gates); // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row and the // Libra polynomials From 7ceaceaa414588f93250880ec666c76e3d133227 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 21 Jan 2025 15:25:38 +0000 Subject: [PATCH 25/33] some renaming --- .../client_ivc_recursive_verifier.test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp index 1e436faba75..cb8466e859f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp @@ -11,9 +11,9 @@ class ClientIVCRecursionTests : public testing::Test { using ClientIVCVerifier = ClientIVCRecursiveVerifier; using FoldVerifierInput = ClientIVCVerifier::FoldVerifierInput; using Proof = ClientIVC::Proof; - using Flavor = UltraRollupRecursiveFlavor_; - using NativeFlavor = Flavor::NativeFlavor; - using UltraRecursiveVerifier = UltraRecursiveVerifier_; + using RollupFlavor = UltraRollupRecursiveFlavor_; + using NativeFlavor = RollupFlavor::NativeFlavor; + using UltraRecursiveVerifier = UltraRecursiveVerifier_; using MockCircuitProducer = PrivateFunctionExecutionMockCircuitProducer; using IVCVerificationKey = ClientIVC::VerificationKey; @@ -131,12 +131,12 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) // Construct a base rollup circuit that recursively verifies the tube proof and forwards the IPA proof. Builder base_builder; auto native_vk = std::make_shared(proving_key->proving_key); - auto vk = std::make_shared(&base_builder, native_vk); + auto tube_vk = std::make_shared(&base_builder, native_vk); auto tube_proof = bb::convert_native_proof_to_stdlib(&base_builder, native_tube_proof); - UltraRecursiveVerifier base_verifier{ &base_builder, vk }; - UltraRecursiveVerifierOutput output = base_verifier.verify_proof( - tube_proof, stdlib::recursion::init_default_aggregation_state(base_builder)); - info("UH Recursive Verifier: num prefinalized gates = ", base_builder.num_gates); + UltraRecursiveVerifier base_verifier{ &base_builder, tube_vk }; + UltraRecursiveVerifierOutput output = base_verifier.verify_proof( + tube_proof, stdlib::recursion::init_default_aggregation_state(base_builder)); + info("Tube UH Recursive Verifier: num prefinalized gates = ", base_builder.num_gates); base_builder.add_pairing_point_accumulator(output.agg_obj.get_witness_indices()); base_builder.add_ipa_claim(output.ipa_opening_claim.get_witness_indices()); base_builder.ipa_proof = tube_prover.proving_key->proving_key.ipa_proof; From 4a3f07beeba9e42b67f4b2b550e2f43a9cad2569 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 21 Jan 2025 19:29:56 +0000 Subject: [PATCH 26/33] resolving comments --- .../commitment_schemes/shplonk/shplemini.hpp | 103 ++++++++++++------ .../shplonk/shplemini.test.cpp | 18 +-- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 14 ++- .../utils/instance_witness_generator.hpp | 44 +++++++- .../barretenberg/ecc/curves/bn254/bn254.hpp | 3 + .../ecc/curves/grumpkin/grumpkin.hpp | 4 + .../stdlib/primitives/curves/bn254.hpp | 3 + .../stdlib/primitives/curves/grumpkin.hpp | 4 + .../src/barretenberg/sumcheck/sumcheck.hpp | 18 +-- .../barretenberg/sumcheck/sumcheck_round.hpp | 5 +- .../sumcheck/zk_sumcheck_data.hpp | 4 +- 11 files changed, 151 insertions(+), 69 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index f77b4f1f950..71f763302a9 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -31,8 +31,8 @@ template class ShpleminiProver_ { const std::shared_ptr>& commitment_key, const std::shared_ptr& transcript, const std::array& libra_polynomials = {}, - const std::vector sumcheck_round_univariates = {}, - const std::vector> sumcheck_round_evaluations = {}, + const std::vector& sumcheck_round_univariates = {}, + const std::vector>& sumcheck_round_evaluations = {}, RefSpan concatenated_polynomials = {}, const std::vector>& groups_to_be_concatenated = {}) { @@ -48,52 +48,91 @@ template class ShpleminiProver_ { groups_to_be_concatenated, has_zk); // Create opening claims for Libra masking univariates and Sumcheck Round Univariates - std::vector libra_opening_claims; - OpeningClaim new_claim; + std::vector libra_opening_claims; if (has_zk) { - static constexpr FF subgroup_generator = Curve::subgroup_generator; const auto gemini_r = opening_claims[0].opening_pair.challenge; - - std::array libra_eval_labels = { - "Libra:concatenation_eval", "Libra:shifted_big_sum_eval", "Libra:big_sum_eval", "Libra:quotient_eval" - }; - const std::array evaluation_points = { - gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r - }; - for (size_t idx = 0; idx < 4; idx++) { - new_claim.polynomial = std::move(libra_polynomials[idx]); - new_claim.opening_pair.challenge = evaluation_points[idx]; - new_claim.opening_pair.evaluation = new_claim.polynomial.evaluate(evaluation_points[idx]); - transcript->send_to_verifier(libra_eval_labels[idx], new_claim.opening_pair.evaluation); - libra_opening_claims.push_back(new_claim); - } + libra_opening_claims = compute_libra_opening_claims(gemini_r, libra_polynomials, transcript); } // Currently, only used in ECCVM. std::vector sumcheck_round_claims; if (!sumcheck_round_univariates.empty()) { - const size_t log_circuit_size = numeric::get_msb(static_cast(circuit_size)); - for (size_t idx = 0; idx < log_circuit_size; idx++) { - const std::vector evaluation_points = { FF(0), FF(1), multilinear_challenge[idx] }; - size_t eval_idx = 0; - new_claim.polynomial = std::move(sumcheck_round_univariates[idx]); - - for (auto& eval_point : evaluation_points) { - new_claim.opening_pair.challenge = eval_point; - new_claim.opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx]; - sumcheck_round_claims.push_back(new_claim); - eval_idx++; - } - } + sumcheck_round_claims = compute_sumcheck_round_claims( + circuit_size, multilinear_challenge, sumcheck_round_univariates, sumcheck_round_evaluations); } const OpeningClaim batched_claim = ShplonkProver::prove( commitment_key, opening_claims, transcript, libra_opening_claims, sumcheck_round_claims); return batched_claim; }; + + /** + * @brief For ZK Flavors: Evaluate the polynomials used in SmallSubgroupIPA argument, send the evaluations to the + * verifier, and populate a vector of the opening claims. + * + */ + template + static std::vector compute_libra_opening_claims( + const FF gemini_r, + const std::array& libra_polynomials, + const std::shared_ptr& transcript) + { + OpeningClaim new_claim; + + std::vector libra_opening_claims = {}; + + static constexpr FF subgroup_generator = Curve::subgroup_generator; + + std::array libra_eval_labels = { + "Libra:concatenation_eval", "Libra:shifted_big_sum_eval", "Libra:big_sum_eval", "Libra:quotient_eval" + }; + const std::array evaluation_points = { + gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r + }; + for (size_t idx = 0; idx < 4; idx++) { + new_claim.polynomial = std::move(libra_polynomials[idx]); + new_claim.opening_pair.challenge = evaluation_points[idx]; + new_claim.opening_pair.evaluation = new_claim.polynomial.evaluate(evaluation_points[idx]); + transcript->send_to_verifier(libra_eval_labels[idx], new_claim.opening_pair.evaluation); + libra_opening_claims.push_back(new_claim); + } + + return libra_opening_claims; + } + + /** + * @brief Create a vector of 3*log_circuit_size opening claims for the evaluations of Sumcheck Round Univariates at + * 0, 1, and a round challenge. + * + */ + static std::vector compute_sumcheck_round_claims( + const FF circuit_size, + std::span multilinear_challenge, + const std::vector& sumcheck_round_univariates, + const std::vector>& sumcheck_round_evaluations) + { + OpeningClaim new_claim; + std::vector sumcheck_round_claims = {}; + + const size_t log_circuit_size = numeric::get_msb(static_cast(circuit_size)); + for (size_t idx = 0; idx < log_circuit_size; idx++) { + const std::vector evaluation_points = { FF(0), FF(1), multilinear_challenge[idx] }; + size_t eval_idx = 0; + new_claim.polynomial = std::move(sumcheck_round_univariates[idx]); + + for (auto& eval_point : evaluation_points) { + new_claim.opening_pair.challenge = eval_point; + new_claim.opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx]; + sumcheck_round_claims.push_back(new_claim); + eval_idx++; + } + } + + return sumcheck_round_claims; + } }; /** * \brief An efficient verifier for the evaluation proofs of multilinear polynomials and their shifts. diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp index bde4864e3e3..afe3ec55740 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -27,22 +27,14 @@ template class ShpleminiTest : public CommitmentTest>& round_univariates, std::vector& sumcheck_commitments, std::vector>& sumcheck_evaluations, @@ -50,7 +42,7 @@ template class ShpleminiTest : public CommitmentTest& ck) { // Generate valid sumcheck polynomials of given length - auto mock_sumcheck_polynomials = ZKSumcheckData(log_n, length); + auto mock_sumcheck_polynomials = ZKSumcheckData(log_n, sumcheck_univariate_length); for (size_t idx = 0; idx < log_n; idx++) { bb::Polynomial round_univariate = mock_sumcheck_polynomials.libra_univariates[idx]; @@ -427,7 +419,7 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) // Generate masking polynomials for Sumcheck Round Univariates ZKSumcheckData zk_sumcheck_data(this->log_n, prover_transcript, ck); // Generate mock witness - InstanceWitnessGenerator pcs_instance_witness(this->n, 1, ck); + InstanceWitnessGenerator pcs_instance_witness(this->n, 1); // Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges const Fr claimed_inner_product = diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 740439ead22..1cddeb6fd0b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -82,11 +82,11 @@ template class SmallSubgroupIPAProver { static constexpr size_t BATCHED_POLYNOMIAL_LENGTH = 2 * SUBGROUP_SIZE + 2; // Size of Q(X) static constexpr size_t QUOTIENT_LENGTH = SUBGROUP_SIZE + 2; - // The length of a random polynomial to mask Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we + // The length of a random polynomial masking Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we // send the coefficients of the univariates, hence we choose these value to be the max sumcheck univariate length // over Translator, Ultra, and Mega. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces the // required length from 23 to 3. - static constexpr size_t LIBRA_UNIVARIATES_LENGTH = (std::is_same_v) ? 9 : 3; + static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Curve::LIBRA_UNIVARIATES_LENGTH; // Fixed generator of H static constexpr FF subgroup_generator = Curve::subgroup_generator; @@ -192,7 +192,7 @@ template class SmallSubgroupIPAProver { * - Store these coefficients in `coeffs_lagrange_basis`. * More explicitly, * \f$ F = (1 , 1 , u_0, \ldots, u_0^{LIBRA_UNIVARIATES_LENGTH-1}, \ldots, 1, u_{D-1}, \ldots, - * u_{D-1}^{LIBRA_UNVIARIATES_LENGTH-1} ) \f$ in the Lagrange basis over \f$ H \f$. + * u_{D-1}^{LIBRA_UNIVARIATES_LENGTH-1} ) \f$ in the Lagrange basis over \f$ H \f$. * * ### Monomial Basis * If the curve is not `BN254`, the monomial polynomial is constructed directly using un-optimized Lagrange @@ -419,9 +419,11 @@ template class SmallSubgroupIPAVerifier { static constexpr size_t SUBGROUP_SIZE = Curve::SUBGROUP_SIZE; - static constexpr size_t LIBRA_UNIVARIATES_LENGTH = - (std::is_same_v || std::is_same_v>) ? 3 - : 9; + // The length of a random polynomial masking Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we + // send the coefficients of the univariates, hence we choose these value to be the max sumcheck univariate length + // over Translator, Ultra, and Mega. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces the + // required length from 23 to 3. + static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Curve::LIBRA_UNIVARIATES_LENGTH; public: /*! diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp index 60dd83fd301..88b76728ea9 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp @@ -67,18 +67,50 @@ template struct InstanceWitnessGenerator { } // Generate zero polynomials to test edge cases in PCS - InstanceWitnessGenerator(const size_t n, - const size_t num_zero_polynomials, - std::shared_ptr& commitment_key) - : ck(commitment_key) // Initialize the commitment key - , unshifted_polynomials(num_zero_polynomials) + InstanceWitnessGenerator(const size_t n, const size_t num_zero_polynomials) + : unshifted_polynomials(num_zero_polynomials) { for (size_t idx = 0; idx < num_zero_polynomials; idx++) { unshifted_polynomials[idx] = Polynomial(n); - unshifted_commitments.push_back(ck->commit(unshifted_polynomials[idx])); + unshifted_commitments.push_back(Commitment::infinity()); unshifted_evals.push_back(Fr(0)); } } + + template + void compute_sumcheck_opening_data(const size_t log_n, + const size_t sumcheck_univariate_length, + std::vector>& round_univariates, + std::vector& sumcheck_commitments, + std::vector>& sumcheck_evaluations, + std::vector& challenge, + std::shared_ptr& ck) + { + // Generate valid sumcheck polynomials of given length + auto mock_sumcheck_polynomials = ZKSumcheckData(log_n, sumcheck_univariate_length); + for (size_t idx = 0; idx < log_n; idx++) { + bb::Polynomial round_univariate = mock_sumcheck_polynomials.libra_univariates[idx]; + + round_univariate.at(0) += mock_sumcheck_polynomials.libra_running_sum; + + sumcheck_commitments.push_back(ck->commit(round_univariate)); + + sumcheck_evaluations.push_back({ round_univariate.at(0), + round_univariate.evaluate(Fr(1)), + round_univariate.evaluate(challenge[idx]) }); + + mock_sumcheck_polynomials.update_zk_sumcheck_data(challenge[idx], idx); + round_univariates.push_back(round_univariate); + } + + // Simulate the `const proof size` logic + auto round_univariate = bb::Polynomial(this->n); + for (size_t idx = this->log_n; idx < CONST_PROOF_SIZE_LOG_N; idx++) { + round_univariates.push_back(round_univariate); + sumcheck_commitments.push_back(ck->commit(round_univariate)); + sumcheck_evaluations.push_back({ Fr(0), Fr(0), Fr(0) }); + } + } }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/bn254.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/bn254.hpp index b8ea6f839c8..3106a73a861 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/bn254.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/bn254.hpp @@ -35,5 +35,8 @@ class BN254 { ScalarField(uint256_t("0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76")); static constexpr ScalarField subgroup_generator_inverse = ScalarField(uint256_t("0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6")); + // The length of the polynomials used to mask the Sumcheck Round Univariates. Computed as + // max(BATCHED_PARTIAL_RELATION_LENGTH) for BN254 Flavors with ZK + static constexpr uint32_t LIBRA_UNIVARIATES_LENGTH = 9; }; } // namespace bb::curve \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp index f195fbd7e53..ba5869c0d0c 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp @@ -67,5 +67,9 @@ class Grumpkin { ScalarField(uint256_t("0x147c647c09fb639514909e9f0513f31ec1a523bf8a0880bc7c24fbc962a9586b")); static constexpr ScalarField subgroup_generator_inverse = ScalarField("0x0c68e27477b5e78cfab790bd3b59806fa871771f71ec7452cde5384f6e3a1988"); + // The length of the polynomials used to mask the Sumcheck Round Univariates. In the ECCVM Sumcheck, the prover only + // sends 3 elements in every round - a commitment to the round univariate and its evaluations at 0 and 1. Therefore, + // length 3 is sufficient. + static constexpr uint32_t LIBRA_UNIVARIATES_LENGTH = 3; }; } // namespace bb::curve \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp index 5feb3b6e872..29504a56e71 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/bn254.hpp @@ -49,6 +49,9 @@ template struct bn254 { bb::fr(uint256_t("0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76")); static constexpr bb::fr subgroup_generator_inverse = bb::fr(uint256_t("0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6")); + // The length of the polynomials used to mask the Sumcheck Round Univariates. Computed as + // max(BATCHED_PARTIAL_RELATION_LENGTH) for BN254 Flavors with ZK + static constexpr uint32_t LIBRA_UNIVARIATES_LENGTH = 9; }; // namespace bn254 diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/grumpkin.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/grumpkin.hpp index c8630ac735e..fdaad5616c6 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/grumpkin.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/curves/grumpkin.hpp @@ -42,6 +42,10 @@ template struct grumpkin { bb::fq("0x147c647c09fb639514909e9f0513f31ec1a523bf8a0880bc7c24fbc962a9586b"); static constexpr bb::fq subgroup_generator_inverse = bb::fq("0x0c68e27477b5e78cfab790bd3b59806fa871771f71ec7452cde5384f6e3a1988"); + // The length of the polynomials used to mask the Sumcheck Round Univariates. In the ECCVM Sumcheck, the prover only + // sends 3 elements in every round - a commitment to the round univariate and its evaluations at 0 and 1. Therefore, + // length 3 is sufficient. + static constexpr uint32_t LIBRA_UNIVARIATES_LENGTH = 3; }; } // namespace bb::stdlib \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 91a0992b52a..d24b024ffe2 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -151,6 +151,7 @@ template class SumcheckProver { std::vector> round_evaluations = {}; std::vector> round_univariates = {}; std::vector eval_domain = {}; + FF libra_evaluation = FF{ 0 }; /** * @@ -237,8 +238,7 @@ template class SumcheckProver { } // Claimed evaluations of Prover polynomials are extracted and added to the transcript. When Flavor has ZK, the // evaluations of all witnesses are masked. - ClaimedEvaluations multivariate_evaluations; - multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); + ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all()); // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output @@ -269,6 +269,10 @@ template class SumcheckProver { if constexpr (IS_ECCVM) { ck = std::make_shared(BATCHED_RELATION_PARTIAL_LENGTH); + } else { + // Ensure that the length of Sumcheck Round Univariates does not exceed the length of Libra masking + // polynomials. + ASSERT(BATCHED_RELATION_PARTIAL_LENGTH <= Flavor::Curve::LIBRA_UNIVARIATES_LENGTH); } bb::GateSeparatorPolynomial gate_separators(gate_challenges, multivariate_d); @@ -379,17 +383,15 @@ template class SumcheckProver { // Claimed evaluations of Prover polynomials are extracted and added to the transcript. When Flavor has ZK, the // evaluations of all witnesses are masked. - ClaimedEvaluations multivariate_evaluations; - multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); + ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all()); // The evaluations of Libra uninvariates at \f$ g_0(u_0), \ldots, g_{d-1} (u_{d-1}) \f$ are added to the // transcript. - FF libra_evaluation{ 0 }; + FF libra_evaluation = zk_sumcheck_data.constant_term; for (const auto& libra_eval : zk_sumcheck_data.libra_evaluations) { libra_evaluation += libra_eval; } - libra_evaluation += zk_sumcheck_data.constant_term; transcript->send_to_verifier("Libra:claimed_evaluation", libra_evaluation); // The sum of the Libra constant term and the evaluations of Libra univariates at corresponding sumcheck @@ -515,8 +517,8 @@ polynomials that are sent in clear. const std::string idx = std::to_string(round_idx); // Transform to monomial form and commit to it - Polynomial round_poly_monomial = - Polynomial(eval_domain, std::span(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH); + Polynomial round_poly_monomial( + eval_domain, std::span(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH); transcript->send_to_verifier("Sumcheck:univariate_comm_" + idx, ck->commit(round_poly_monomial)); // Store round univariate in monomial, as it is required by Shplemini diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp index f1c81c62e3f..a8a188985d6 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp @@ -67,8 +67,9 @@ template class SumcheckProverRound { using SumcheckRoundUnivariate = bb::Univariate; SumcheckTupleOfTuplesOfUnivariates univariate_accumulators; - static constexpr size_t LIBRA_UNIVARIATES_LENGTH = - (std::is_same_v) ? BATCHED_RELATION_PARTIAL_LENGTH : 3; + // The length of the polynomials used to mask the Sumcheck Round Univariates. + static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Flavor::Curve::LIBRA_UNIVARIATES_LENGTH; + // Prover constructor SumcheckProverRound(size_t initial_round_size) : round_size(initial_round_size) diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp index 998b986b195..4c1a671eed4 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp @@ -21,8 +21,8 @@ template struct ZKSumcheckData { static constexpr FF subgroup_generator = Curve::subgroup_generator; - // The size of the LibraUnivariates. We ensure that they do not take extra space when Flavor runs non-ZK Sumcheck. - static constexpr size_t LIBRA_UNIVARIATES_LENGTH = (std::is_same_v) ? 9 : 3; + // The size of the LibraUnivariates. + static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Curve::LIBRA_UNIVARIATES_LENGTH; static constexpr FF one_half = FF(1) / FF(2); From 98d304fab4a77d743ba43c50bdd4c309a9097434 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 22 Jan 2025 11:14:26 +0000 Subject: [PATCH 27/33] killed optional bool in sumcheck output + resolving comments --- .../shplonk/shplemini.test.cpp | 23 ++++++------- .../utils/instance_witness_generator.hpp | 16 ++++++---- .../eccvm/eccvm_composer.test.cpp | 2 +- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 6 ++-- .../cpp/src/barretenberg/flavor/flavor.hpp | 2 ++ .../src/barretenberg/sumcheck/sumcheck.hpp | 32 +++++++++---------- .../barretenberg/sumcheck/sumcheck.test.cpp | 4 +-- .../barretenberg/sumcheck/sumcheck_output.hpp | 2 +- .../translator_vm/translator_verifier.cpp | 2 +- .../ultra_honk/decider_verifier.cpp | 4 +-- .../barretenberg/ultra_honk/sumcheck.test.cpp | 2 +- .../vm/avm/generated/recursive_verifier.cpp | 2 +- .../vm/avm/generated/verifier.cpp | 2 +- .../barretenberg/vm2/generated/verifier.cpp | 2 +- .../templates/recursive_verifier.cpp.hbs | 2 +- .../bb-pil-backend/templates/verifier.cpp.hbs | 2 +- 16 files changed, 54 insertions(+), 51 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp index afe3ec55740..e4c9e8564b3 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -403,17 +403,10 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) std::shared_ptr ck = create_commitment_key(4096); - // Generate Sumcheck challenge + // Generate Sumcheck challenge, current implementation of Sumcheck Round Univariates batching in Shplemini assumes + // that the challenge is of CONST_PROOF_SIZE_LOG_N std::vector challenge = this->random_evaluation_point(CONST_PROOF_SIZE_LOG_N); - // Initialize the corresponding PCS inputs - std::vector> round_univariates = {}; - std::vector sumcheck_commitments = {}; - std::vector> sumcheck_evaluations = {}; - - // Generate valid sumcheck polynomials of given length - this->compute_sumcheck_opening_data(round_univariates, sumcheck_commitments, sumcheck_evaluations, challenge, ck); - auto prover_transcript = TypeParam::Transcript::prover_init_empty(); // Generate masking polynomials for Sumcheck Round Univariates @@ -421,6 +414,10 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) // Generate mock witness InstanceWitnessGenerator pcs_instance_witness(this->n, 1); + // Generate valid sumcheck polynomials of given length + pcs_instance_witness.template compute_sumcheck_opening_data( + this->n, this->log_n, this->sumcheck_univariate_length, challenge, ck); + // Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges const Fr claimed_inner_product = SmallSubgroupIPAProver::compute_claimed_inner_product(zk_sumcheck_data, challenge, this->log_n); @@ -439,8 +436,8 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) ck, prover_transcript, small_subgroup_ipa_prover.get_witness_polynomials(), - round_univariates, - sumcheck_evaluations); + pcs_instance_witness.round_univariates, + pcs_instance_witness.sumcheck_evaluations); if constexpr (std::is_same_v) { IPA::compute_opening_proof(this->ck(), opening_claim, prover_transcript); @@ -486,8 +483,8 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) &consistency_checked, libra_commitments, libra_evaluation, - sumcheck_commitments, - sumcheck_evaluations); + pcs_instance_witness.sumcheck_commitments, + pcs_instance_witness.sumcheck_evaluations); // Verify claim using KZG or IPA if constexpr (std::is_same_v) { auto result = diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp index 88b76728ea9..2d36d1e535a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/instance_witness_generator.hpp @@ -27,6 +27,11 @@ template struct InstanceWitnessGenerator { std::vector unshifted_evals; std::vector shifted_evals; + // Containers for mock Sumcheck data + std::vector> round_univariates; + std::vector sumcheck_commitments; + std::vector> sumcheck_evaluations; + InstanceWitnessGenerator(const size_t n, const size_t num_polynomials, const size_t num_shiftable, @@ -78,16 +83,15 @@ template struct InstanceWitnessGenerator { } template - void compute_sumcheck_opening_data(const size_t log_n, + void compute_sumcheck_opening_data(const size_t n, + const size_t log_n, const size_t sumcheck_univariate_length, - std::vector>& round_univariates, - std::vector& sumcheck_commitments, - std::vector>& sumcheck_evaluations, std::vector& challenge, std::shared_ptr& ck) { // Generate valid sumcheck polynomials of given length auto mock_sumcheck_polynomials = ZKSumcheckData(log_n, sumcheck_univariate_length); + for (size_t idx = 0; idx < log_n; idx++) { bb::Polynomial round_univariate = mock_sumcheck_polynomials.libra_univariates[idx]; @@ -104,8 +108,8 @@ template struct InstanceWitnessGenerator { } // Simulate the `const proof size` logic - auto round_univariate = bb::Polynomial(this->n); - for (size_t idx = this->log_n; idx < CONST_PROOF_SIZE_LOG_N; idx++) { + auto round_univariate = bb::Polynomial(n); + for (size_t idx = log_n; idx < CONST_PROOF_SIZE_LOG_N; idx++) { round_univariates.push_back(round_univariate); sumcheck_commitments.push_back(ck->commit(round_univariate)); sumcheck_evaluations.push_back({ Fr(0), Fr(0), Fr(0) }); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp index 5c9177d986c..448b0094155 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp @@ -167,5 +167,5 @@ TEST_F(ECCVMTests, CommittedSumcheck) EXPECT_TRUE(prover_target_sum == verifier_output.round_univariate_evaluations[0][0] + verifier_output.round_univariate_evaluations[0][1]); - EXPECT_TRUE(verifier_output.verified.value()); + EXPECT_TRUE(verifier_output.verified); } diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 83ae8a677b9..04a9a3a0d1b 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -65,7 +65,7 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); // If Sumcheck did not verify, return false - if (sumcheck_output.verified.has_value() && !sumcheck_output.verified.value()) { + if (!sumcheck_output.verified) { vinfo("eccvm sumcheck failed"); return false; } @@ -135,8 +135,8 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) const bool batched_opening_verified = PCS::reduce_verify(key->pcs_verification_key, batch_opening_claim, ipa_transcript); - vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified.value()); + vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified); vinfo("batch opening verified?: ", batched_opening_verified); - return sumcheck_output.verified.value() && batched_opening_verified && consistency_checked; + return sumcheck_output.verified && batched_opening_verified && consistency_checked; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index 0dc5e962210..7a1cddb0069 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -419,6 +419,8 @@ concept IsRecursiveFlavor = IsAnyOf, AvmRecursiveFlavor_>; +// These concepts are relevant for Sumcheck, where the logic is different for BN254 and Grumpkin Flavors +template concept IsGrumpkinFlavor = IsAnyOf>; template concept IsECCVMRecursiveFlavor = IsAnyOf>; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index d24b024ffe2..4a5444bb43c 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -146,13 +146,16 @@ template class SumcheckProver { std::shared_ptr transcript; SumcheckProverRound round; - static constexpr bool IS_ECCVM = std::is_same_v; + std::vector multivariate_challenge; + std::vector round_univariate_commitments = {}; std::vector> round_evaluations = {}; std::vector> round_univariates = {}; std::vector eval_domain = {}; FF libra_evaluation = FF{ 0 }; + RowDisablingPolynomial row_disabling_polynomial; + /** * * @brief Container for partially evaluated Prover Polynomials at a current challenge. Upon computing challenge \f$ @@ -189,7 +192,6 @@ template class SumcheckProver { bb::GateSeparatorPolynomial gate_separators(gate_challenges, multivariate_d); - std::vector multivariate_challenge; multivariate_challenge.reserve(multivariate_d); // In the first round, we compute the first univariate polynomial and populate the book-keeping table of // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns. When the Flavor has ZK, @@ -267,8 +269,13 @@ template class SumcheckProver { { std::shared_ptr ck = nullptr; - if constexpr (IS_ECCVM) { + if constexpr (IsGrumpkinFlavor) { ck = std::make_shared(BATCHED_RELATION_PARTIAL_LENGTH); + // Compute the vector {0, 1, \ldots, BATCHED_RELATION_PARTIAL_LENGTH-1} needed to transform the round + // univariates from Lagrange to monomial basis + for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) { + eval_domain.push_back(FF(idx)); + } } else { // Ensure that the length of Sumcheck Round Univariates does not exceed the length of Libra masking // polynomials. @@ -277,10 +284,8 @@ template class SumcheckProver { bb::GateSeparatorPolynomial gate_separators(gate_challenges, multivariate_d); - std::vector multivariate_challenge; multivariate_challenge.reserve(multivariate_d); size_t round_idx = 0; - RowDisablingPolynomial row_disabling_polynomial; // In the first round, we compute the first univariate polynomial and populate the book-keeping table of // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns. When the Flavor has ZK, // compute_univariate also takes into account the zk_sumcheck_data. @@ -296,15 +301,10 @@ template class SumcheckProver { PROFILE_THIS_NAME("rest of sumcheck round 1"); - if constexpr (!IS_ECCVM) { + if constexpr (!IsGrumpkinFlavor) { // Place the evaluations of the round univariate into transcript. transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); } else { - // Compute the vector {0, 1, \ldots, BATCHED_RELATION_PARTIAL_LENGTH-1} needed to transform the round - // univariates from Lagrange to monomial basis - for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) { - eval_domain.push_back(FF(idx)); - } // Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure // needed in the PCS round @@ -337,7 +337,7 @@ template class SumcheckProver { alpha, zk_sumcheck_data, row_disabling_polynomial); - if constexpr (!IS_ECCVM) { + if constexpr (!IsGrumpkinFlavor) { // Place evaluations of Sumcheck Round Univariate in the transcript transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); } else { @@ -360,7 +360,7 @@ template class SumcheckProver { round.round_size = round.round_size >> 1; } - if constexpr (IS_ECCVM) { + if constexpr (IsGrumpkinFlavor) { round_evaluations[multivariate_d - 1][2] = round_univariate.evaluate(multivariate_challenge[multivariate_d - 1]); } @@ -369,7 +369,7 @@ template class SumcheckProver { // Zero univariates are used to pad the proof to the fixed size CONST_PROOF_SIZE_LOG_N. auto zero_univariate = bb::Univariate::zero(); for (size_t idx = multivariate_d; idx < CONST_PROOF_SIZE_LOG_N; idx++) { - if constexpr (!IS_ECCVM) { + if constexpr (!IsGrumpkinFlavor) { transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx), zero_univariate); } else { transcript->send_to_verifier("Sumcheck:univariate_comm_" + std::to_string(idx), @@ -396,7 +396,7 @@ template class SumcheckProver { // The sum of the Libra constant term and the evaluations of Libra univariates at corresponding sumcheck // challenges is included in the Sumcheck Output - if constexpr (!IS_ECCVM) { + if constexpr (!IsGrumpkinFlavor) { return SumcheckOutput{ .challenge = multivariate_challenge, .claimed_evaluations = multivariate_evaluations, .claimed_libra_evaluation = libra_evaluation }; @@ -742,7 +742,7 @@ template class SumcheckVerifier { SumcheckOutput verify(const bb::RelationParameters& relation_parameters, RelationSeparator alpha, const std::vector& gate_challenges) - requires std::is_same_v || IsECCVMRecursiveFlavor + requires IsGrumpkinFlavor { bool verified(false); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp index 0cf586f47eb..4d8aeee3c96 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp @@ -277,7 +277,7 @@ template class SumcheckTests : public ::testing::Test { } auto verifier_output = sumcheck_verifier.verify(relation_parameters, verifier_alpha, verifier_gate_challenges); - auto verified = verifier_output.verified.value(); + auto verified = verifier_output.verified; EXPECT_EQ(verified, true); }; @@ -367,7 +367,7 @@ template class SumcheckTests : public ::testing::Test { } auto verifier_output = sumcheck_verifier.verify(relation_parameters, verifier_alpha, verifier_gate_challenges); - auto verified = verifier_output.verified.value(); + auto verified = verifier_output.verified; EXPECT_EQ(verified, false); }; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp index bde613f3931..2d415ee23fe 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp @@ -24,7 +24,7 @@ template struct SumcheckOutput { ClaimedEvaluations claimed_evaluations; // Whether or not the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N \f$ and final Sumcheck evaluation // have been confirmed - std::optional verified = false; // optional b/c this struct is shared by the Prover/Verifier + bool verified = false; // For ZK Flavors: the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges FF claimed_libra_evaluation = FF{ 0 }; // For ECCVMVerifier: Commitments to round univariates diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp index 972a81f2979..c84942c3aec 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp @@ -105,7 +105,7 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false - if (sumcheck_output.verified.has_value() && !sumcheck_output.verified.value()) { + if (!sumcheck_output.verified) { return false; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp index 21065dd96e8..d75dbdd0e8f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp @@ -60,7 +60,7 @@ template bool DeciderVerifier_::verify() } // If Sumcheck did not verify, return false - if (sumcheck_output.verified.has_value() && !sumcheck_output.verified.value()) { + if (!sumcheck_output.verified) { info("Sumcheck verification failed."); return false; } @@ -81,7 +81,7 @@ template bool DeciderVerifier_::verify() sumcheck_output.claimed_libra_evaluation); const auto pairing_points = PCS::reduce_verify_batch_opening_claim(opening_claim, transcript); bool verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); - return sumcheck_output.verified.value() && verified && consistency_checked; + return sumcheck_output.verified && verified && consistency_checked; } template class DeciderVerifier_; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp index 5a84fb27069..69bd748e319 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp @@ -189,7 +189,7 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) auto verifier_output = sumcheck_verifier.verify(decider_pk->relation_parameters, verifier_alphas, verifier_gate_challenges); - auto verified = verifier_output.verified.value(); + auto verified = verifier_output.verified; ASSERT_TRUE(verified); } diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/recursive_verifier.cpp index d1766b839b1..dd40f449baf 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/recursive_verifier.cpp @@ -120,7 +120,7 @@ AvmRecursiveVerifier_::AggregationObject AvmRecursiveVerifier_:: // when called over a "circuit field" types. SumcheckOutput output = sumcheck.verify(relation_parameters, alpha, gate_challenges); - vinfo("verified sumcheck: ", (output.verified.has_value() && output.verified.value())); + vinfo("verified sumcheck: ", (output.verified)); // Public columns evaluation checks std::vector mle_challenge(output.challenge.begin(), diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp index a9d581a53e0..92dbb2175d5 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp @@ -88,7 +88,7 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, const std::vector output = sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false - if (!output.verified.has_value() || !output.verified.value()) { + if (!output.verified) { vinfo("Sumcheck verification failed"); return false; } diff --git a/barretenberg/cpp/src/barretenberg/vm2/generated/verifier.cpp b/barretenberg/cpp/src/barretenberg/vm2/generated/verifier.cpp index 717071f3c8f..ce863f34dd8 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/generated/verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/generated/verifier.cpp @@ -88,7 +88,7 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, const std::vector output = sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false - if (!output.verified.has_value() || !output.verified.value()) { + if (!output.verified) { vinfo("Sumcheck verification failed"); return false; } diff --git a/bb-pilcom/bb-pil-backend/templates/recursive_verifier.cpp.hbs b/bb-pilcom/bb-pil-backend/templates/recursive_verifier.cpp.hbs index 6e8f8b35829..737bad86df6 100644 --- a/bb-pilcom/bb-pil-backend/templates/recursive_verifier.cpp.hbs +++ b/bb-pilcom/bb-pil-backend/templates/recursive_verifier.cpp.hbs @@ -120,7 +120,7 @@ AvmRecursiveVerifier_::AggregationObject AvmRecursiveVerifier_:: // when called over a "circuit field" types. SumcheckOutput output = sumcheck.verify(relation_parameters, alpha, gate_challenges); - vinfo("verified sumcheck: ", (output.verified.has_value() && output.verified.value())); + vinfo("verified sumcheck: ", (output.verified)); // Public columns evaluation checks std::vector mle_challenge(output.challenge.begin(), diff --git a/bb-pilcom/bb-pil-backend/templates/verifier.cpp.hbs b/bb-pilcom/bb-pil-backend/templates/verifier.cpp.hbs index 32edcc25983..3abad919132 100644 --- a/bb-pilcom/bb-pil-backend/templates/verifier.cpp.hbs +++ b/bb-pilcom/bb-pil-backend/templates/verifier.cpp.hbs @@ -88,7 +88,7 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, const std::vector output = sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false - if (!output.verified.has_value() || !output.verified.value()) { + if (!output.verified) { vinfo("Sumcheck verification failed"); return false; } From db9c2b1eec8488c16476da558bcab8510705f1ef Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 22 Jan 2025 14:46:20 +0000 Subject: [PATCH 28/33] +tube_vk test --- .../client_ivc_recursive_verifier.test.cpp | 94 +++++++++++++++++-- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp index cb8466e859f..e3cfe413efd 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp @@ -34,11 +34,11 @@ class ClientIVCRecursionTests : public testing::Test { * @brief Construct a genuine ClientIVC prover output based on accumulation of an arbitrary set of mock circuits * */ - static ClientIVCProverOutput construct_client_ivc_prover_output(ClientIVC& ivc) + static ClientIVCProverOutput construct_client_ivc_prover_output(ClientIVC& ivc, const size_t NUM_CIRCUITS = 2) { // Construct and accumulate a series of mocked private function execution circuits MockCircuitProducer circuit_producer; - size_t NUM_CIRCUITS = 2; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { auto circuit = circuit_producer.create_next_circuit(ivc); ivc.accumulate(circuit); @@ -46,6 +46,8 @@ class ClientIVCRecursionTests : public testing::Test { return { ivc.prove(), ivc.get_vk() }; } + + static void test_independent_vk_hash(){}; }; /** @@ -120,6 +122,7 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) // Construct and verify a proof for the ClientIVC Recursive Verifier circuit auto proving_key = std::make_shared>(*tube_builder); UltraProver_ tube_prover{ proving_key }; + // Prove the CIVCRecursiveVerifier circuit auto native_tube_proof = tube_prover.construct_proof(); // Natively verify the tube proof @@ -130,12 +133,12 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) // Construct a base rollup circuit that recursively verifies the tube proof and forwards the IPA proof. Builder base_builder; - auto native_vk = std::make_shared(proving_key->proving_key); - auto tube_vk = std::make_shared(&base_builder, native_vk); - auto tube_proof = bb::convert_native_proof_to_stdlib(&base_builder, native_tube_proof); - UltraRecursiveVerifier base_verifier{ &base_builder, tube_vk }; + auto tube_vk = std::make_shared(proving_key->proving_key); + auto base_vk = std::make_shared(&base_builder, tube_vk); + auto base_tube_proof = bb::convert_native_proof_to_stdlib(&base_builder, native_tube_proof); + UltraRecursiveVerifier base_verifier{ &base_builder, base_vk }; UltraRecursiveVerifierOutput output = base_verifier.verify_proof( - tube_proof, stdlib::recursion::init_default_aggregation_state(base_builder)); + base_tube_proof, stdlib::recursion::init_default_aggregation_state(base_builder)); info("Tube UH Recursive Verifier: num prefinalized gates = ", base_builder.num_gates); base_builder.add_pairing_point_accumulator(output.agg_obj.get_witness_indices()); base_builder.add_ipa_claim(output.ipa_opening_claim.get_witness_indices()); @@ -150,4 +153,81 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) ipa_verification_key, output.ipa_opening_claim.get_native_opening_claim(), ipa_transcript); } +// Ensure that the Client IVC Recursive Verifier Circuit does not depend on the Client IVC input +TEST_F(ClientIVCRecursionTests, TubeVKIndependentOfInputCircuits) +{ + + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + auto get_blocks = [](size_t inner_size) + -> std::tuple> { + ClientIVC ivc{ trace_settings }; + + auto [proof, ivc_vk] = construct_client_ivc_prover_output(ivc, inner_size); + + auto tube_builder = std::make_shared(); + ClientIVCVerifier verifier{ tube_builder, ivc_vk }; + + auto client_ivc_rec_verifier_output = verifier.verify(proof); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1069): fix this by taking it from the output + // instead of + // just using default. + tube_builder->add_pairing_point_accumulator( + stdlib::recursion::init_default_agg_obj_indices(*tube_builder)); + // The tube only calls an IPA recursive verifier once, so we can just add this IPA claim and proof + tube_builder->add_ipa_claim(client_ivc_rec_verifier_output.opening_claim.get_witness_indices()); + tube_builder->ipa_proof = + convert_stdlib_proof_to_native(client_ivc_rec_verifier_output.ipa_transcript->proof_data); + + info("ClientIVC Recursive Verifier: num prefinalized gates = ", tube_builder->num_gates); + + EXPECT_EQ(tube_builder->failed(), false) << tube_builder->err(); + + // Construct and verify a proof for the ClientIVC Recursive Verifier circuit + auto proving_key = std::make_shared>(*tube_builder); + + auto tube_vk = std::make_shared(proving_key->proving_key); + + return { tube_builder->blocks, tube_vk }; + }; + + bool broke(false); + auto check_eq = [&broke](auto& p1, auto& p2) { + EXPECT_TRUE(p1.size() == p2.size()); + for (size_t idx = 0; idx < p1.size(); idx++) { + if (p1[idx] != p2[idx]) { + broke = true; + break; + } + } + }; + + auto [blocks_10, verification_key_10] = get_blocks(2); + auto [blocks_11, verification_key_11] = get_blocks(4); + + size_t block_idx = 0; + for (auto [b_10, b_11] : zip_view(blocks_10.get(), blocks_11.get())) { + info("block index: ", block_idx); + EXPECT_TRUE(b_10.selectors.size() == 13); + EXPECT_TRUE(b_11.selectors.size() == 13); + for (auto [p_10, p_11] : zip_view(b_10.selectors, b_11.selectors)) { + check_eq(p_10, p_11); + } + block_idx++; + } + + typename NativeFlavor::CommitmentLabels labels; + for (auto [vk_10, vk_11, label] : + zip_view(verification_key_10->get_all(), verification_key_11->get_all(), labels.get_precomputed())) { + if (vk_10 != vk_11) { + broke = true; + info("Mismatch verification key label: ", label, " left: ", vk_10, " right: ", vk_11); + } + } + + EXPECT_TRUE(verification_key_10->circuit_size == verification_key_11->circuit_size); + EXPECT_TRUE(verification_key_10->num_public_inputs == verification_key_11->num_public_inputs); + + EXPECT_FALSE(broke); +} } // namespace bb::stdlib::recursion::honk \ No newline at end of file From 37cf638707b0d6e7ff2599b28b340d53946c99bb Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 22 Jan 2025 15:50:00 +0000 Subject: [PATCH 29/33] isolated a method that compares recursive verifier circuits in various independence tests --- .../client_ivc_recursive_verifier.test.cpp | 41 +--------- .../eccvm_recursive_verifier.test.cpp | 42 ++-------- .../ultra_recursive_verifier.test.cpp | 38 +--------- .../ultra_verification_keys_comparator.hpp | 54 +++++++++++++ .../translator_recursive_verifier.test.cpp | 76 +++++-------------- 5 files changed, 83 insertions(+), 168 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp index e3cfe413efd..019c076841a 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp @@ -3,6 +3,7 @@ #include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/client_ivc/test_bench_shared.hpp" #include "barretenberg/common/test.hpp" +#include "barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp" namespace bb::stdlib::recursion::honk { class ClientIVCRecursionTests : public testing::Test { @@ -191,43 +192,9 @@ TEST_F(ClientIVCRecursionTests, TubeVKIndependentOfInputCircuits) return { tube_builder->blocks, tube_vk }; }; - bool broke(false); - auto check_eq = [&broke](auto& p1, auto& p2) { - EXPECT_TRUE(p1.size() == p2.size()); - for (size_t idx = 0; idx < p1.size(); idx++) { - if (p1[idx] != p2[idx]) { - broke = true; - break; - } - } - }; - - auto [blocks_10, verification_key_10] = get_blocks(2); - auto [blocks_11, verification_key_11] = get_blocks(4); - - size_t block_idx = 0; - for (auto [b_10, b_11] : zip_view(blocks_10.get(), blocks_11.get())) { - info("block index: ", block_idx); - EXPECT_TRUE(b_10.selectors.size() == 13); - EXPECT_TRUE(b_11.selectors.size() == 13); - for (auto [p_10, p_11] : zip_view(b_10.selectors, b_11.selectors)) { - check_eq(p_10, p_11); - } - block_idx++; - } - - typename NativeFlavor::CommitmentLabels labels; - for (auto [vk_10, vk_11, label] : - zip_view(verification_key_10->get_all(), verification_key_11->get_all(), labels.get_precomputed())) { - if (vk_10 != vk_11) { - broke = true; - info("Mismatch verification key label: ", label, " left: ", vk_10, " right: ", vk_11); - } - } - - EXPECT_TRUE(verification_key_10->circuit_size == verification_key_11->circuit_size); - EXPECT_TRUE(verification_key_10->num_public_inputs == verification_key_11->num_public_inputs); + auto [blocks_2, verification_key_2] = get_blocks(2); + auto [blocks_4, verification_key_4] = get_blocks(4); - EXPECT_FALSE(broke); + compare_ultra_verification_keys({ blocks_2, blocks_4 }, { verification_key_2, verification_key_4 }); } } // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp index 06b0ccdde70..9c47847abbb 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp @@ -2,6 +2,7 @@ #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/eccvm/eccvm_prover.hpp" #include "barretenberg/eccvm/eccvm_verifier.hpp" +#include "barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -171,44 +172,11 @@ template class ECCVMRecursiveTests : public ::testing return { outer_circuit.blocks, outer_verification_key }; }; - bool broke(false); - auto check_eq = [&broke](auto& p1, auto& p2) { - EXPECT_TRUE(p1.size() == p2.size()); - for (size_t idx = 0; idx < p1.size(); idx++) { - if (p1[idx] != p2[idx]) { - broke = true; - break; - } - } - }; - - auto [blocks_10, verification_key_10] = get_blocks(20); - auto [blocks_11, verification_key_11] = get_blocks(50); - - size_t block_idx = 0; - for (auto [b_10, b_11] : zip_view(blocks_10.get(), blocks_11.get())) { - info("block index: ", block_idx); - EXPECT_TRUE(b_10.selectors.size() == 13); - EXPECT_TRUE(b_11.selectors.size() == 13); - for (auto [p_10, p_11] : zip_view(b_10.selectors, b_11.selectors)) { - check_eq(p_10, p_11); - } - block_idx++; - } - - typename OuterFlavor::CommitmentLabels labels; - for (auto [vk_10, vk_11, label] : - zip_view(verification_key_10->get_all(), verification_key_11->get_all(), labels.get_precomputed())) { - if (vk_10 != vk_11) { - broke = true; - info("Mismatch verification key label: ", label, " left: ", vk_10, " right: ", vk_11); - } - } - - EXPECT_TRUE(verification_key_10->circuit_size == verification_key_11->circuit_size); - EXPECT_TRUE(verification_key_10->num_public_inputs == verification_key_11->num_public_inputs); + auto [blocks_20, verification_key_20] = get_blocks(20); + auto [blocks_40, verification_key_40] = get_blocks(40); - EXPECT_FALSE(broke); + compare_ultra_verification_keys({ blocks_20, blocks_40 }, + { verification_key_20, verification_key_40 }); }; }; using FlavorTypes = testing::Types>; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp index 9c65178da92..e23ecc625dc 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp @@ -7,6 +7,7 @@ #include "barretenberg/stdlib_circuit_builders/ultra_rollup_recursive_flavor.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" +#include "ultra_verification_keys_comparator.hpp" namespace bb::stdlib::recursion::honk { @@ -176,44 +177,11 @@ template class RecursiveVerifierTest : public testing return { outer_circuit.blocks, outer_verification_key }; }; - bool broke(false); - auto check_eq = [&broke](auto& p1, auto& p2) { - EXPECT_TRUE(p1.size() == p2.size()); - for (size_t idx = 0; idx < p1.size(); idx++) { - if (p1[idx] != p2[idx]) { - broke = true; - break; - } - } - }; - auto [blocks_10, verification_key_10] = get_blocks(10); auto [blocks_11, verification_key_11] = get_blocks(11); - size_t block_idx = 0; - for (auto [b_10, b_11] : zip_view(blocks_10.get(), blocks_11.get())) { - info("block index: ", block_idx); - EXPECT_TRUE(b_10.selectors.size() == 13); - EXPECT_TRUE(b_11.selectors.size() == 13); - for (auto [p_10, p_11] : zip_view(b_10.selectors, b_11.selectors)) { - check_eq(p_10, p_11); - } - block_idx++; - } - - typename OuterFlavor::CommitmentLabels labels; - for (auto [vk_10, vk_11, label] : - zip_view(verification_key_10->get_all(), verification_key_11->get_all(), labels.get_precomputed())) { - if (vk_10 != vk_11) { - broke = true; - info("Mismatch verification key label: ", label, " left: ", vk_10, " right: ", vk_11); - } - } - - EXPECT_TRUE(verification_key_10->circuit_size == verification_key_11->circuit_size); - EXPECT_TRUE(verification_key_10->num_public_inputs == verification_key_11->num_public_inputs); - - EXPECT_FALSE(broke); + compare_ultra_verification_keys({ blocks_10, blocks_11 }, + { verification_key_10, verification_key_11 }); } /** diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp new file mode 100644 index 00000000000..f2b6d936c90 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp @@ -0,0 +1,54 @@ + + +#include "barretenberg/common/assert.hpp" +#include "barretenberg/common/log.hpp" +#include +#include +namespace bb { + +template +static void compare_ultra_verification_keys( + std::array blocks, + std::array, 2> verification_keys) +{ + + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + + bool broke(false); + auto check_eq = [&broke](auto& p1, auto& p2) { + ASSERT(p1.size() == p2.size()); + for (size_t idx = 0; idx < p1.size(); idx++) { + if (p1[idx] != p2[idx]) { + broke = true; + break; + } + } + }; + + size_t block_idx = 0; + for (auto [block_0, block_1] : zip_view(blocks[0].get(), blocks[1].get())) { + info("block index: ", block_idx); + ASSERT(block_0.selectors.size() == 13); + ASSERT(block_1.selectors.size() == 13); + for (auto [p_10, p_11] : zip_view(block_0.selectors, block_1.selectors)) { + check_eq(p_10, p_11); + } + block_idx++; + } + + typename OuterFlavor::CommitmentLabels labels; + for (auto [vk_0, vk_1, label] : + zip_view(verification_keys[0]->get_all(), verification_keys[1]->get_all(), labels.get_precomputed())) { + if (vk_0 != vk_1) { + broke = true; + info("Mismatch verification key label: ", label, " left: ", vk_0, " right: ", vk_1); + } + } + + ASSERT(verification_keys[0]->circuit_size == verification_keys[1]->circuit_size); + ASSERT(verification_keys[0]->num_public_inputs == verification_keys[1]->num_public_inputs); + + ASSERT(broke); +} + +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index a8a97ab810c..d45e7d0f614 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp @@ -1,10 +1,6 @@ #include "barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp" #include "barretenberg/common/log.hpp" -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/relations/relation_parameters.hpp" -#include "barretenberg/sumcheck/sumcheck_round.hpp" -#include "barretenberg/translator_vm/translator_circuit_builder.hpp" -#include "barretenberg/translator_vm/translator_prover.hpp" +#include "barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp" #include "barretenberg/translator_vm/translator_verifier.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -44,7 +40,7 @@ template class TranslatorRecursiveTests : public ::te static void SetUpTestSuite() { bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path()); } - static void test_recursive_verification() + static std::shared_ptr create_op_queue(const size_t num_ops) { auto P1 = InnerG1::random_element(); auto P2 = InnerG1::random_element(); @@ -54,10 +50,17 @@ template class TranslatorRecursiveTests : public ::te auto op_queue = std::make_shared(); op_queue->append_nonzero_ops(); - for (size_t i = 0; i < 500; i++) { + for (size_t i = 0; i < num_ops; i++) { op_queue->add_accumulate(P1); op_queue->mul_accumulate(P2, z); } + return op_queue; + } + + static void test_recursive_verification() + { + // Add the same operations to the ECC op queue; the native computation is performed under the hood. + auto op_queue = create_op_queue(500); auto prover_transcript = std::make_shared(); prover_transcript->send_to_verifier("init", InnerBF::random_element()); @@ -126,21 +129,9 @@ template class TranslatorRecursiveTests : public ::te { // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit - auto get_blocks = [](size_t inner_size) -> std::tuple> { - // Create an arbitrary inner circuit - auto P1 = InnerG1::random_element(); - auto P2 = InnerG1::random_element(); - auto z = InnerFF::random_element(); - - // Add the same operations to the ECC op queue; the native computation is performed under the hood. - auto op_queue = std::make_shared(); - op_queue->append_nonzero_ops(); - - for (size_t i = 0; i < inner_size; i++) { - op_queue->add_accumulate(P1); - op_queue->mul_accumulate(P2, z); - } + auto get_blocks = [](size_t num_ops) -> std::tuple> { + auto op_queue = create_op_queue(num_ops); auto prover_transcript = std::make_shared(); prover_transcript->send_to_verifier("init", InnerBF::random_element()); @@ -181,44 +172,11 @@ template class TranslatorRecursiveTests : public ::te return { outer_circuit.blocks, outer_verification_key }; }; - bool broke(false); - auto check_eq = [&broke](auto& p1, auto& p2) { - EXPECT_TRUE(p1.size() == p2.size()); - for (size_t idx = 0; idx < p1.size(); idx++) { - if (p1[idx] != p2[idx]) { - broke = true; - break; - } - } - }; - - auto [blocks_10, verification_key_10] = get_blocks(256); - auto [blocks_11, verification_key_11] = get_blocks(512); - - size_t block_idx = 0; - for (auto [b_10, b_11] : zip_view(blocks_10.get(), blocks_11.get())) { - info("block index: ", block_idx); - EXPECT_TRUE(b_10.selectors.size() == 13); - EXPECT_TRUE(b_11.selectors.size() == 13); - for (auto [p_10, p_11] : zip_view(b_10.selectors, b_11.selectors)) { - check_eq(p_10, p_11); - } - block_idx++; - } - - typename OuterFlavor::CommitmentLabels labels; - for (auto [vk_10, vk_11, label] : - zip_view(verification_key_10->get_all(), verification_key_11->get_all(), labels.get_precomputed())) { - if (vk_10 != vk_11) { - broke = true; - info("Mismatch verification key label: ", label, " left: ", vk_10, " right: ", vk_11); - } - } - - EXPECT_TRUE(verification_key_10->circuit_size == verification_key_11->circuit_size); - EXPECT_TRUE(verification_key_10->num_public_inputs == verification_key_11->num_public_inputs); + auto [blocks_256, verification_key_256] = get_blocks(256); + auto [blocks_512, verification_key_512] = get_blocks(512); - EXPECT_FALSE(broke); + compare_ultra_verification_keys({ blocks_256, blocks_512 }, + { verification_key_256, verification_key_512 }); }; }; From af3b50205103de5952db6bb2aaaa61cefcae0cd3 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 23 Jan 2025 09:34:41 +0000 Subject: [PATCH 30/33] bad merge fix --- .../src/barretenberg/sumcheck/sumcheck.hpp | 843 ++++++++---------- 1 file changed, 354 insertions(+), 489 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 99883dae2c5..0ce28b7e5c0 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -123,13 +123,10 @@ template class SumcheckProver { using PartiallyEvaluatedMultivariates = typename Flavor::PartiallyEvaluatedMultivariates; using ClaimedEvaluations = typename Flavor::AllValues; using ZKData = ZKSumcheckData; - using ZKData = ZKSumcheckData; using Transcript = typename Flavor::Transcript; using RelationSeparator = typename Flavor::RelationSeparator; using CommitmentKey = typename Flavor::CommitmentKey; - using CommitmentKey = typename Flavor::CommitmentKey; - /** * @brief The total algebraic degree of the Sumcheck relation \f$ F \f$ as a polynomial in Prover Polynomials * \f$P_1,\ldots, P_N\f$. @@ -141,12 +138,9 @@ template class SumcheckProver { using SumcheckRoundUnivariate = typename bb::Univariate; - // The size of the hypercube, i.e. \f$ 2^d\f$. - // The size of the hypercube, i.e. \f$ 2^d\f$. const size_t multivariate_n; // The number of variables - // The number of variables const size_t multivariate_d; std::shared_ptr transcript; @@ -162,16 +156,6 @@ template class SumcheckProver { RowDisablingPolynomial row_disabling_polynomial; - std::vector multivariate_challenge; - - std::vector round_univariate_commitments = {}; - std::vector> round_evaluations = {}; - std::vector> round_univariates = {}; - std::vector eval_domain = {}; - FF libra_evaluation = FF{ 0 }; - - RowDisablingPolynomial row_disabling_polynomial; - /** * * @brief Container for partially evaluated Prover Polynomials at a current challenge. Upon computing challenge \f$ @@ -257,12 +241,9 @@ template class SumcheckProver { // Claimed evaluations of Prover polynomials are extracted and added to the transcript. When Flavor has ZK, the // evaluations of all witnesses are masked. ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); - ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all()); // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output - return SumcheckOutput{ .challenge = multivariate_challenge, - .claimed_evaluations = multivariate_evaluations }; return SumcheckOutput{ .challenge = multivariate_challenge, .claimed_evaluations = multivariate_evaluations }; vinfo("finished sumcheck"); @@ -288,20 +269,6 @@ template class SumcheckProver { { std::shared_ptr ck = nullptr; - if constexpr (IsGrumpkinFlavor) { - ck = std::make_shared(BATCHED_RELATION_PARTIAL_LENGTH); - // Compute the vector {0, 1, \ldots, BATCHED_RELATION_PARTIAL_LENGTH-1} needed to transform the round - // univariates from Lagrange to monomial basis - for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; idx++) { - eval_domain.push_back(FF(idx)); - } - } else { - // Ensure that the length of Sumcheck Round Univariates does not exceed the length of Libra masking - // polynomials. - ASSERT(BATCHED_RELATION_PARTIAL_LENGTH <= Flavor::Curve::LIBRA_UNIVARIATES_LENGTH); - } - std::shared_ptr ck = nullptr; - if constexpr (IsGrumpkinFlavor) { ck = std::make_shared(BATCHED_RELATION_PARTIAL_LENGTH); // Compute the vector {0, 1, \ldots, BATCHED_RELATION_PARTIAL_LENGTH-1} needed to transform the round @@ -347,25 +314,11 @@ template class SumcheckProver { const FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); - if constexpr (!IsGrumpkinFlavor) { - // Place the evaluations of the round univariate into transcript. - transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); - } else { - - // Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure - // needed in the PCS round - commit_to_round_univariate( - round_idx, round_univariate, eval_domain, transcript, ck, round_univariates, round_evaluations); - } - - const FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); - multivariate_challenge.emplace_back(round_challenge); // Prepare sumcheck book-keeping table for the next round partially_evaluate(full_polynomials, multivariate_n, round_challenge); // Prepare ZK Sumcheck data for the next round zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx); - zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx); row_disabling_polynomial.update_evaluations(round_challenge, round_idx); gate_separators.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; // TODO(#224)(Cody): Maybe partially_evaluate should do this and @@ -394,18 +347,6 @@ template class SumcheckProver { commit_to_round_univariate( round_idx, round_univariate, eval_domain, transcript, ck, round_univariates, round_evaluations); } - const FF round_challenge = - transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); - if constexpr (!IsGrumpkinFlavor) { - // Place evaluations of Sumcheck Round Univariate in the transcript - transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); - } else { - - // Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure - // needed in the PCS round - commit_to_round_univariate( - round_idx, round_univariate, eval_domain, transcript, ck, round_univariates, round_evaluations); - } const FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); multivariate_challenge.emplace_back(round_challenge); @@ -413,18 +354,12 @@ template class SumcheckProver { partially_evaluate(partially_evaluated_polynomials, round.round_size, round_challenge); // Prepare evaluation masking and libra structures for the next round (for ZK Flavors) zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx); - zk_sumcheck_data.update_zk_sumcheck_data(round_challenge, round_idx); row_disabling_polynomial.update_evaluations(round_challenge, round_idx); gate_separators.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; } - if constexpr (IsGrumpkinFlavor) { - round_evaluations[multivariate_d - 1][2] = - round_univariate.evaluate(multivariate_challenge[multivariate_d - 1]); - } - if constexpr (IsGrumpkinFlavor) { round_evaluations[multivariate_d - 1][2] = round_univariate.evaluate(multivariate_challenge[multivariate_d - 1]); @@ -434,14 +369,6 @@ template class SumcheckProver { // Zero univariates are used to pad the proof to the fixed size CONST_PROOF_SIZE_LOG_N. auto zero_univariate = bb::Univariate::zero(); for (size_t idx = multivariate_d; idx < CONST_PROOF_SIZE_LOG_N; idx++) { - if constexpr (!IsGrumpkinFlavor) { - transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx), zero_univariate); - } else { - transcript->send_to_verifier("Sumcheck:univariate_comm_" + std::to_string(idx), - ck->commit(Polynomial(std::span(zero_univariate)))); - transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx) + "_eval_0", FF(0)); - transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx) + "_eval_1", FF(0)); - } if constexpr (!IsGrumpkinFlavor) { transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx), zero_univariate); } else { @@ -457,13 +384,11 @@ template class SumcheckProver { // Claimed evaluations of Prover polynomials are extracted and added to the transcript. When Flavor has ZK, the // evaluations of all witnesses are masked. ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); - ClaimedEvaluations multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all()); // The evaluations of Libra uninvariates at \f$ g_0(u_0), \ldots, g_{d-1} (u_{d-1}) \f$ are added to the // transcript. FF libra_evaluation = zk_sumcheck_data.constant_term; - FF libra_evaluation = zk_sumcheck_data.constant_term; for (const auto& libra_eval : zk_sumcheck_data.libra_evaluations) { libra_evaluation += libra_eval; } @@ -482,17 +407,6 @@ template class SumcheckProver { .round_univariates = round_univariates, .round_univariate_evaluations = round_evaluations }; } - if constexpr (!IsGrumpkinFlavor) { - return SumcheckOutput{ .challenge = multivariate_challenge, - .claimed_evaluations = multivariate_evaluations, - .claimed_libra_evaluation = libra_evaluation }; - } else { - return SumcheckOutput{ .challenge = multivariate_challenge, - .claimed_evaluations = multivariate_evaluations, - .claimed_libra_evaluation = libra_evaluation, - .round_univariates = round_univariates, - .round_univariate_evaluations = round_evaluations }; - } vinfo("finished sumcheck"); }; @@ -580,9 +494,6 @@ polynomials that are sent in clear. }; /** - * @brief Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure - * needed in the PCS round - * * @brief Compute monomial coefficients of the round univariate, commit to it, populate an auxiliary structure * needed in the PCS round * @@ -622,421 +533,375 @@ polynomials that are sent in clear. if (round_idx > 0) { round_univariate_evaluations[round_idx - 1][2] = round_univariate.value_at(0) + round_univariate.value_at(1); - *@param round_univariate Sumcheck Round Univariate* @param eval_domain{ - 0, 1, ..., BATCHED_RELATION_PARTIAL_LENGTH - 1 - } * - @param transcript* @param ck Commitment key of size - BATCHED_RELATION_PARTIAL_LENGTH* @param round_univariates Auxiliary container to be fed to - Shplemini* @param round_univariate_evaluations Auxiliary container to be fed to Shplemini* / - void commit_to_round_univariate(const size_t round_idx, - bb::Univariate& round_univariate, - const std::vector& eval_domain, - const std::shared_ptr& transcript, - const std::shared_ptr& ck, - std::vector>& round_univariates, - std::vector>& round_univariate_evaluations) - { - - const std::string idx = std::to_string(round_idx); - - // Transform to monomial form and commit to it - Polynomial round_poly_monomial( - eval_domain, std::span(round_univariate.evaluations), BATCHED_RELATION_PARTIAL_LENGTH); - transcript->send_to_verifier("Sumcheck:univariate_comm_" + idx, ck->commit(round_poly_monomial)); - - // Store round univariate in monomial, as it is required by Shplemini - round_univariates.push_back(std::move(round_poly_monomial)); - - // Send the evaluations of the round univariate at 0 and 1 - transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_0", round_univariate.value_at(0)); - transcript->send_to_verifier("Sumcheck:univariate_" + idx + "_eval_1", round_univariate.value_at(1)); - - // Store the evaluations to be used by ShpleminiProver. - round_univariate_evaluations.push_back( - { round_univariate.value_at(0), round_univariate.value_at(1), FF(0) }); - if (round_idx > 0) { - round_univariate_evaluations[round_idx - 1][2] = - round_univariate.value_at(0) + round_univariate.value_at(1); - }; - } }; - /*! \brief Implementation of the sumcheck Verifier for statements of the form \f$\sum_{\vec \ell \in \{0,1\}^d} - pow_{\beta}(\vec \ell) \cdot F \left(P_1(\vec \ell),\ldots, P_N(\vec \ell) \right) = 0 \f$ for multilinear - polynomials \f$P_1, \ldots, P_N \f$. - * - \class SumcheckVerifier - \details - * Init: - * - Claimed Sumcheck sum: \f$\quad \sigma_{ 0 } \gets 0 \f$ - * - * For \f$ i = 0,\ldots, d-1\f$: - * - Extract Round Univariate's \f$\tilde{F}\f$ evaluations at \f$0,\ldots, D \f$ from the transcript using \ref - bb::BaseTranscript::receive_from_prover "receive_from_prover" method from \ref bb::BaseTranscript< - TranscriptParams > "Base Transcript Class". - * - \ref bb::SumcheckVerifierRound< Flavor >::check_sum "Check target sum": \f$\quad \sigma_{ - i } \stackrel{?}{=} \tilde{S}^i(0) + \tilde{S}^i(1) \f$ - * - Compute the challenge \f$u_i\f$ from the transcript using \ref bb::BaseTranscript::get_challenge - "get_challenge" method. - * - \ref bb::SumcheckVerifierRound< Flavor >::compute_next_target_sum "Compute next target sum" :\f$ \quad - \sigma_{i+1} \gets \tilde{S}^i(u_i) \f$ - * ### Verifier's Data before Final Step - * Entering the final round, the Verifier has already checked that \f$\quad \sigma_{ d-1 } = - \tilde{S}^{d-2}(u_{d-2}) \stackrel{?}{=} \tilde{S}^{d-1}(0) + \tilde{S}^{d-1}(1) \f$ and computed \f$\sigma_d - = \tilde{S}^{d-1}(u_{d-1})\f$. - * ### Final Verification Step - * - Extract \ref ClaimedEvaluations of prover polynomials \f$P_1,\ldots, P_N\f$ at the challenge point \f$ - (u_0,\ldots,u_{d-1}) \f$ from the transcript and \ref bb::SumcheckVerifierRound< Flavor - >::compute_full_relation_purported_value "compute evaluation:" - \f{align}{\tilde{F}\left( P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1}) \right)\f} - and store it at \f$ \texttt{full_honk_relation_purported_value} \f$. - * - Compare \f$ \sigma_d \f$ against the evaluation of \f$ \tilde{F} \f$ at \f$P_1(u_0,\ldots, u_{d-1}), - \ldots, P_N(u_0,\ldots, u_{d-1})\f$: - * \f{align}{\quad \sigma_{ d } \stackrel{?}{=} \tilde{F}\left(P_1(u_{0}, \ldots, u_{d-1}),\ldots, - P_N(u_0,\ldots, u_{d-1})\right)\f} - - \snippet cpp/src/barretenberg/sumcheck/sumcheck.hpp Final Verification Step - - */ - template class SumcheckVerifier { - - public: - using Utils = bb::RelationUtils; - using FF = typename Flavor::FF; - /** - * @brief Container type for the evaluations of Prover Polynomials \f$P_1,\ldots,P_N\f$ at the challenge - * point \f$(u_0,\ldots, u_{d-1}) \f$. - * - */ - using ClaimedEvaluations = typename Flavor::AllValues; - // For ZK Flavors: the verifier obtains a vector of evaluations of \f$ d \f$ univariate polynomials and uses - // them to compute full_honk_relation_purported_value - using ClaimedLibraEvaluations = typename std::vector; - using Transcript = typename Flavor::Transcript; - using RelationSeparator = typename Flavor::RelationSeparator; - using Commitment = typename Flavor::Commitment; - using Commitment = typename Flavor::Commitment; - - /** - * @brief Maximum partial algebraic degree of the relation \f$\tilde F = pow_{\beta} \cdot F \f$, i.e. \ref - * MAX_PARTIAL_RELATION_LENGTH "MAX_PARTIAL_RELATION_LENGTH + 1". - */ - static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; - /** - * @brief The number of Prover Polynomials \f$ P_1, \ldots, P_N \f$ specified by the Flavor. - * - */ - static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - /** - * @brief Number of variables in Prover Polynomials. - * - */ - const size_t multivariate_d; - - std::shared_ptr transcript; - SumcheckVerifierRound round; - FF libra_evaluation{ 0 }; - FF libra_challenge; - FF libra_total_sum; - FF correcting_factor; - - std::vector round_univariate_commitments = {}; - std::vector> round_univariate_evaluations = {}; - - // 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. - * - * @details If verification fails, returns std::nullopt, otherwise returns SumcheckOutput - * @param relation_parameters - * @param transcript - */ - SumcheckOutput verify(const bb::RelationParameters& relation_parameters, - RelationSeparator alpha, - const std::vector& gate_challenges) - { - bool verified(true); - - bb::GateSeparatorPolynomial gate_separators(gate_challenges); - // All but final round. - // target_total_sum is initialized to zero then mutated in place. - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1144): Add proper constraints for taking - // the log of a field_t link multivariate_d. - if (multivariate_d == 0) { - throw_or_abort("Number of variables in multivariate is 0."); - } + } +}; +/*! \brief Implementation of the sumcheck Verifier for statements of the form \f$\sum_{\vec \ell \in \{0,1\}^d} + pow_{\beta}(\vec \ell) \cdot F \left(P_1(\vec \ell),\ldots, P_N(\vec \ell) \right) = 0 \f$ for multilinear + polynomials \f$P_1, \ldots, P_N \f$. + * + \class SumcheckVerifier + \details + * Init: + * - Claimed Sumcheck sum: \f$\quad \sigma_{ 0 } \gets 0 \f$ + * + * For \f$ i = 0,\ldots, d-1\f$: + * - Extract Round Univariate's \f$\tilde{F}\f$ evaluations at \f$0,\ldots, D \f$ from the transcript using \ref +bb::BaseTranscript::receive_from_prover "receive_from_prover" method from \ref bb::BaseTranscript< TranscriptParams > +"Base Transcript Class". + * - \ref bb::SumcheckVerifierRound< Flavor >::check_sum "Check target sum": \f$\quad \sigma_{ + i } \stackrel{?}{=} \tilde{S}^i(0) + \tilde{S}^i(1) \f$ +* - Compute the challenge \f$u_i\f$ from the transcript using \ref bb::BaseTranscript::get_challenge "get_challenge" +method. +* - \ref bb::SumcheckVerifierRound< Flavor >::compute_next_target_sum "Compute next target sum" :\f$ \quad \sigma_{i+1} +\gets \tilde{S}^i(u_i) \f$ + * ### Verifier's Data before Final Step +* Entering the final round, the Verifier has already checked that \f$\quad \sigma_{ d-1 } = \tilde{S}^{d-2}(u_{d-2}) +\stackrel{?}{=} \tilde{S}^{d-1}(0) + \tilde{S}^{d-1}(1) \f$ and computed \f$\sigma_d = \tilde{S}^{d-1}(u_{d-1})\f$. + * ### Final Verification Step + * - Extract \ref ClaimedEvaluations of prover polynomials \f$P_1,\ldots, P_N\f$ at the challenge point \f$ + (u_0,\ldots,u_{d-1}) \f$ from the transcript and \ref bb::SumcheckVerifierRound< Flavor + >::compute_full_relation_purported_value "compute evaluation:" + \f{align}{\tilde{F}\left( P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1}) \right)\f} + and store it at \f$ \texttt{full_honk_relation_purported_value} \f$. +* - Compare \f$ \sigma_d \f$ against the evaluation of \f$ \tilde{F} \f$ at \f$P_1(u_0,\ldots, u_{d-1}), \ldots, +P_N(u_0,\ldots, u_{d-1})\f$: +* \f{align}{\quad \sigma_{ d } \stackrel{?}{=} \tilde{F}\left(P_1(u_{0}, \ldots, u_{d-1}),\ldots, P_N(u_0,\ldots, +u_{d-1})\right)\f} + + \snippet cpp/src/barretenberg/sumcheck/sumcheck.hpp Final Verification Step + + */ +template class SumcheckVerifier { - bb::Univariate round_univariate; + public: + using Utils = bb::RelationUtils; + using FF = typename Flavor::FF; + /** + * @brief Container type for the evaluations of Prover Polynomials \f$P_1,\ldots,P_N\f$ at the challenge point + * \f$(u_0,\ldots, u_{d-1}) \f$. + * + */ + using ClaimedEvaluations = typename Flavor::AllValues; + // For ZK Flavors: the verifier obtains a vector of evaluations of \f$ d \f$ univariate polynomials and uses them to + // compute full_honk_relation_purported_value + using ClaimedLibraEvaluations = typename std::vector; + using Transcript = typename Flavor::Transcript; + using RelationSeparator = typename Flavor::RelationSeparator; + using Commitment = typename Flavor::Commitment; - bb::Univariate round_univariate; + /** + * @brief Maximum partial algebraic degree of the relation \f$\tilde F = pow_{\beta} \cdot F \f$, i.e. \ref + * MAX_PARTIAL_RELATION_LENGTH "MAX_PARTIAL_RELATION_LENGTH + 1". + */ + static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; + /** + * @brief The number of Prover Polynomials \f$ P_1, \ldots, P_N \f$ specified by the Flavor. + * + */ + static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + /** + * @brief Number of variables in Prover Polynomials. + * + */ + const size_t multivariate_d; - if constexpr (Flavor::HasZK) { - // If running zero-knowledge sumcheck the target total sum is corrected by the claimed sum of libra - // masking multivariate over the hypercube - libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); - libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); - libra_challenge = transcript->template get_challenge("Libra:Challenge"); - round.target_total_sum += libra_total_sum * libra_challenge; - } + std::shared_ptr transcript; + SumcheckVerifierRound round; + FF libra_evaluation{ 0 }; + FF libra_challenge; + FF libra_total_sum; - std::vector multivariate_challenge; - multivariate_challenge.reserve(multivariate_d); - for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - // Obtain the round univariate from the transcript - std::string round_univariate_label = "Sumcheck:univariate_" + std::to_string(round_idx); - round_univariate = round_univariate = - transcript->template receive_from_prover>( - round_univariate_label); - FF round_challenge = - transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); - multivariate_challenge.emplace_back(round_challenge); - multivariate_challenge.emplace_back(round_challenge); - - if constexpr (IsRecursiveFlavor) { - typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round - // derivation! - stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); - bool checked = round.check_sum(round_univariate, dummy_round); - // Only utilize the checked value if this is not a constant proof size padding round - if (round_idx < multivariate_d) { - verified = verified && checked; - } - - round.compute_next_target_sum(round_univariate, round_challenge, dummy_round); - gate_separators.partially_evaluate(round_challenge, dummy_round); - - } else { - if (round_idx < multivariate_d) { - bool checked = round.check_sum(round_univariate); - verified = verified && checked; - round.compute_next_target_sum(round_univariate, round_challenge); - gate_separators.partially_evaluate(round_challenge); - } - } - } - // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra - // challenge Final round - ClaimedEvaluations purported_evaluations; - auto transcript_evaluations = - transcript->template receive_from_prover>("Sumcheck:evaluations"); - for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), transcript_evaluations)) { - eval = transcript_eval; - } + FF correcting_factor; - // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover - // polynomials. In ZK Flavors, the evaluation is corrected by full_libra_purported_value - FF full_honk_purported_value = round.compute_full_relation_purported_value( - purported_evaluations, relation_parameters, gate_separators, alpha); - - // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge - if constexpr (Flavor::HasZK) { - libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); - if constexpr (!IsRecursiveFlavor) { - correcting_factor = - RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); - } else { - typename Flavor::CircuitBuilder* builder = libra_evaluation.get_context(); - correcting_factor = RowDisablingPolynomial::evaluate_at_challenge( - multivariate_challenge, multivariate_d, builder); - } - - full_honk_purported_value = - full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; - } + std::vector round_univariate_commitments = {}; + std::vector> round_univariate_evaluations = {}; - //! [Final Verification Step] - if constexpr (IsRecursiveFlavor) { - verified = - verified && (full_honk_purported_value.get_value() == round.target_total_sum.get_value()); - } else { - verified = verified && (full_honk_purported_value == round.target_total_sum); - } + // 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. + * + * @details If verification fails, returns std::nullopt, otherwise returns SumcheckOutput + * @param relation_parameters + * @param transcript + */ + SumcheckOutput verify(const bb::RelationParameters& relation_parameters, + RelationSeparator alpha, + const std::vector& gate_challenges) + { + bool verified(true); - return SumcheckOutput{ .challenge = multivariate_challenge, - .claimed_evaluations = purported_evaluations, - .verified = verified, - .claimed_libra_evaluation = libra_evaluation }; - }; + bb::GateSeparatorPolynomial gate_separators(gate_challenges); + // All but final round. + // target_total_sum is initialized to zero then mutated in place. - /** - * @brief Sumcheck Verifier for ECCVM and ECCVMRecursive. - * @details The verifier receives commitments to RoundUnivariates, along with their evaluations at 0 and 1. - * These evaluations will be proved as a part of Shplemini. The only check that the Verifier performs in - * this version is the comparison of the target sumcheck sum with the claimed evaluations of the first - * sumcheck round univariate at 0 and 1. - * - * Note that the SumcheckOutput in this case contains a vector of commitments and a vector of arrays (of - * size 3) of evaluations at 0, 1, and a round challenge. - * - * @param relation_parameters - * @param alpha - * @param gate_challenges - * @return SumcheckOutput - */ - SumcheckOutput verify(const bb::RelationParameters& relation_parameters, - RelationSeparator alpha, - const std::vector& gate_challenges) - requires IsGrumpkinFlavor - { - bool verified(false); - - bb::GateSeparatorPolynomial gate_separators(gate_challenges); - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1144): Add proper constraints for taking - // the log of a field_t link multivariate_d. - if (multivariate_d == 0) { - throw_or_abort("Number of variables in multivariate is 0."); - } + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1144): Add proper constraints for taking the log of + // a field_t link multivariate_d. + if (multivariate_d == 0) { + throw_or_abort("Number of variables in multivariate is 0."); + } + + bb::Univariate round_univariate; + + if constexpr (Flavor::HasZK) { + // If running zero-knowledge sumcheck the target total sum is corrected by the claimed sum of libra masking + // multivariate over the hypercube + libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); + libra_challenge = transcript->template get_challenge("Libra:Challenge"); + round.target_total_sum += libra_total_sum * libra_challenge; + } + + std::vector multivariate_challenge; + multivariate_challenge.reserve(multivariate_d); + for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + // Obtain the round univariate from the transcript + std::string round_univariate_label = "Sumcheck:univariate_" + std::to_string(round_idx); + round_univariate = + transcript->template receive_from_prover>( + round_univariate_label); + FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + multivariate_challenge.emplace_back(round_challenge); - // get the claimed sum of libra masking multivariate over the hypercube - libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); - // get the challenge for the ZK Sumcheck claim - const FF libra_challenge = transcript->template get_challenge("Libra:Challenge"); - - std::vector multivariate_challenge; - multivariate_challenge.reserve(CONST_PROOF_SIZE_LOG_N); - // if Flavor has ZK, the target total sum is corrected by Libra total sum multiplied by the Libra - // challenge - round.target_total_sum += libra_total_sum * libra_challenge; - - for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - // Obtain the round univariate from the transcript - const std::string round_univariate_comm_label = - "Sumcheck:univariate_comm_" + std::to_string(round_idx); - const std::string univariate_eval_label_0 = - "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_0"; - const std::string univariate_eval_label_1 = - "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_1"; - - // Receive the commitment to the round univariate - round_univariate_commitments.push_back( - transcript->template receive_from_prover(round_univariate_comm_label)); - // Receive evals at 0 and 1 - round_univariate_evaluations.push_back( - { transcript->template receive_from_prover(univariate_eval_label_0), - transcript->template receive_from_prover(univariate_eval_label_1) }); - - const FF round_challenge = - transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); - multivariate_challenge.emplace_back(round_challenge); - - if constexpr (IsRecursiveFlavor) { - typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round - // derivation! - stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); - // Only utilize the checked value if this is not a constant proof size padding round - gate_separators.partially_evaluate(round_challenge, dummy_round); - - } else { - if (round_idx < multivariate_d) { - gate_separators.partially_evaluate(round_challenge); - } - } + if constexpr (IsRecursiveFlavor) { + typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round + // derivation! + stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); + bool checked = round.check_sum(round_univariate, dummy_round); + // Only utilize the checked value if this is not a constant proof size padding round + if (round_idx < multivariate_d) { + verified = verified && checked; } - FF first_sumcheck_round_evaluations_sum = - round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; + round.compute_next_target_sum(round_univariate, round_challenge, dummy_round); + gate_separators.partially_evaluate(round_challenge, dummy_round); - // Populate claimed evaluations at the challenge - ClaimedEvaluations purported_evaluations; - auto transcript_evaluations = - transcript->template receive_from_prover>("Sumcheck:evaluations"); - for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), transcript_evaluations)) { - eval = transcript_eval; + } else { + if (round_idx < multivariate_d) { + bool checked = round.check_sum(round_univariate); + verified = verified && checked; + round.compute_next_target_sum(round_univariate, round_challenge); + gate_separators.partially_evaluate(round_challenge); } - // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge - // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover - // polynomials. In ZK Flavors, the evaluation is corrected by full_libra_purported_value - FF full_honk_purported_value = round.compute_full_relation_purported_value( - purported_evaluations, relation_parameters, gate_separators, alpha); - - // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra - // challenge - const FF libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); - - // We have to branch here for two reasons: - // 1) need to make the vk constant - // 2) ECCVMRecursive uses big_field where we need to self_reduce(). - if constexpr (IsRecursiveFlavor) { - typename Flavor::CircuitBuilder* builder = libra_challenge.get_context(); - // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to - // the rows where all sumcheck relations are disabled - const FF correcting_factor = RowDisablingPolynomial::evaluate_at_challenge( - multivariate_challenge, multivariate_d, builder); - - // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row - // and the Libra polynomials - full_honk_purported_value = - full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) - full_honk_purported_value.self_reduce(); - - // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be - // checked as a part of Shplemini and pad claimed evaluations to the CONST_PROOF_SIZE_LOG_N - for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round - // derivation! - stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); - round_univariate_evaluations[round_idx - 1][2] = FF::conditional_assign( - dummy_round, - full_honk_purported_value, - round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]); - }; - - first_sumcheck_round_evaluations_sum.self_reduce(); - round.target_total_sum.self_reduce(); - - // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the - // claimed target total sum - first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); - verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); - } else { - // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to - // the rows where all sumcheck relations are disabled - const FF correcting_factor = - RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); - - // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row - // and the Libra polynomials - full_honk_purported_value = - full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; - - // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be - // checked as a part of Shplemini - for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { - round_univariate_evaluations[round_idx - 1][2] = - round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; - }; - - // Pad claimed evaluations to the CONST_PROOF_SIZE_LOG_N - for (size_t round_idx = multivariate_d; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - round_univariate_evaluations[round_idx - 1][2] = full_honk_purported_value; - }; - - // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the - // claimed target total sum - verified = (first_sumcheck_round_evaluations_sum == round.target_total_sum); + } + } + // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra + // challenge Final round + ClaimedEvaluations purported_evaluations; + auto transcript_evaluations = + transcript->template receive_from_prover>("Sumcheck:evaluations"); + for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), transcript_evaluations)) { + eval = transcript_eval; + } + + // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover + // polynomials. In ZK Flavors, the evaluation is corrected by full_libra_purported_value + FF full_honk_purported_value = round.compute_full_relation_purported_value( + purported_evaluations, relation_parameters, gate_separators, alpha); + + // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge + if constexpr (Flavor::HasZK) { + libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); + if constexpr (!IsRecursiveFlavor) { + correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); + } else { + typename Flavor::CircuitBuilder* builder = libra_evaluation.get_context(); + correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d, builder); + } + + full_honk_purported_value = + full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; + } + + //! [Final Verification Step] + if constexpr (IsRecursiveFlavor) { + verified = verified && (full_honk_purported_value.get_value() == round.target_total_sum.get_value()); + } else { + verified = verified && (full_honk_purported_value == round.target_total_sum); + } + + return SumcheckOutput{ .challenge = multivariate_challenge, + .claimed_evaluations = purported_evaluations, + .verified = verified, + .claimed_libra_evaluation = libra_evaluation }; + }; + + /** + * @brief Sumcheck Verifier for ECCVM and ECCVMRecursive. + * @details The verifier receives commitments to RoundUnivariates, along with their evaluations at 0 and 1. + * These evaluations will be proved as a part of Shplemini. The only check that the Verifier performs in + * this version is the comparison of the target sumcheck sum with the claimed evaluations of the first + * sumcheck round univariate at 0 and 1. + * + * Note that the SumcheckOutput in this case contains a vector of commitments and a vector of arrays (of + * size 3) of evaluations at 0, 1, and a round challenge. + * + * @param relation_parameters + * @param alpha + * @param gate_challenges + * @return SumcheckOutput + */ + SumcheckOutput verify(const bb::RelationParameters& relation_parameters, + RelationSeparator alpha, + const std::vector& gate_challenges) + requires IsGrumpkinFlavor + { + bool verified(false); + + bb::GateSeparatorPolynomial gate_separators(gate_challenges); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1144): Add proper constraints for taking + // the log of a field_t link multivariate_d. + if (multivariate_d == 0) { + throw_or_abort("Number of variables in multivariate is 0."); + } + + // get the claimed sum of libra masking multivariate over the hypercube + libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); + // get the challenge for the ZK Sumcheck claim + const FF libra_challenge = transcript->template get_challenge("Libra:Challenge"); + + std::vector multivariate_challenge; + multivariate_challenge.reserve(CONST_PROOF_SIZE_LOG_N); + // if Flavor has ZK, the target total sum is corrected by Libra total sum multiplied by the Libra + // challenge + round.target_total_sum += libra_total_sum * libra_challenge; + + for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + // Obtain the round univariate from the transcript + const std::string round_univariate_comm_label = "Sumcheck:univariate_comm_" + std::to_string(round_idx); + const std::string univariate_eval_label_0 = "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_0"; + const std::string univariate_eval_label_1 = "Sumcheck:univariate_" + std::to_string(round_idx) + "_eval_1"; + + // Receive the commitment to the round univariate + round_univariate_commitments.push_back( + transcript->template receive_from_prover(round_univariate_comm_label)); + // Receive evals at 0 and 1 + round_univariate_evaluations.push_back( + { transcript->template receive_from_prover(univariate_eval_label_0), + transcript->template receive_from_prover(univariate_eval_label_1) }); + + const FF round_challenge = + transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + multivariate_challenge.emplace_back(round_challenge); + + if constexpr (IsRecursiveFlavor) { + typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round + // derivation! + stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); + // Only utilize the checked value if this is not a constant proof size padding round + gate_separators.partially_evaluate(round_challenge, dummy_round); + + } else { + if (round_idx < multivariate_d) { + gate_separators.partially_evaluate(round_challenge); } + } + } + + FF first_sumcheck_round_evaluations_sum = + round_univariate_evaluations[0][0] + round_univariate_evaluations[0][1]; - //! [Final Verification Step] - // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output - return SumcheckOutput{ .challenge = multivariate_challenge, - .claimed_evaluations = purported_evaluations, - .verified = verified, - .claimed_libra_evaluation = libra_evaluation, - .round_univariate_commitments = round_univariate_commitments, - .round_univariate_evaluations = round_univariate_evaluations }; + // Populate claimed evaluations at the challenge + ClaimedEvaluations purported_evaluations; + auto transcript_evaluations = + transcript->template receive_from_prover>("Sumcheck:evaluations"); + for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), transcript_evaluations)) { + eval = transcript_eval; + } + // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge + // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover + // polynomials. In ZK Flavors, the evaluation is corrected by full_libra_purported_value + FF full_honk_purported_value = round.compute_full_relation_purported_value( + purported_evaluations, relation_parameters, gate_separators, alpha); + + // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra + // challenge + const FF libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); + + // We have to branch here for two reasons: + // 1) need to make the vk constant + // 2) ECCVMRecursive uses big_field where we need to self_reduce(). + if constexpr (IsRecursiveFlavor) { + typename Flavor::CircuitBuilder* builder = libra_challenge.get_context(); + // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to + // the rows where all sumcheck relations are disabled + const FF correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d, builder); + + // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row + // and the Libra polynomials + full_honk_purported_value = + full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) + full_honk_purported_value.self_reduce(); + + // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be + // checked as a part of Shplemini and pad claimed evaluations to the CONST_PROOF_SIZE_LOG_N + for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round + // derivation! + stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); + round_univariate_evaluations[round_idx - 1][2] = FF::conditional_assign( + dummy_round, + full_honk_purported_value, + round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]); }; - }; - } // namespace bb + first_sumcheck_round_evaluations_sum.self_reduce(); + round.target_total_sum.self_reduce(); + + // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the + // claimed target total sum + first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); + verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); + } else { + // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to + // the rows where all sumcheck relations are disabled + const FF correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); + + // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row + // and the Libra polynomials + full_honk_purported_value = + full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; + + // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be + // checked as a part of Shplemini + for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { + round_univariate_evaluations[round_idx - 1][2] = + round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; + }; + + // Pad claimed evaluations to the CONST_PROOF_SIZE_LOG_N + for (size_t round_idx = multivariate_d; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { + round_univariate_evaluations[round_idx - 1][2] = full_honk_purported_value; + }; + + // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the + // claimed target total sum + verified = (first_sumcheck_round_evaluations_sum == round.target_total_sum); + } + + //! [Final Verification Step] + // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output + return SumcheckOutput{ .challenge = multivariate_challenge, + .claimed_evaluations = purported_evaluations, + .verified = verified, + .claimed_libra_evaluation = libra_evaluation, + .round_univariate_commitments = round_univariate_commitments, + .round_univariate_evaluations = round_univariate_evaluations }; + }; +}; + +} // namespace bb From b811b5e46b66b519bfbe431f35c2c81835678e04 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 23 Jan 2025 09:41:04 +0000 Subject: [PATCH 31/33] remove noise in sumcheck docs --- .../src/barretenberg/sumcheck/sumcheck.hpp | 69 +++++++++---------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 0ce28b7e5c0..dd12305bc43 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -670,8 +670,7 @@ template class SumcheckVerifier { if constexpr (IsRecursiveFlavor) { typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round - // derivation! + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); bool checked = round.check_sum(round_univariate, dummy_round); // Only utilize the checked value if this is not a constant proof size padding round @@ -691,8 +690,8 @@ template class SumcheckVerifier { } } } - // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra - // challenge Final round + // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge + // Final round ClaimedEvaluations purported_evaluations; auto transcript_evaluations = transcript->template receive_from_prover>("Sumcheck:evaluations"); @@ -700,8 +699,8 @@ template class SumcheckVerifier { eval = transcript_eval; } - // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover - // polynomials. In ZK Flavors, the evaluation is corrected by full_libra_purported_value + // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover polynomials. + // In ZK Flavors, the evaluation is corrected by full_libra_purported_value FF full_honk_purported_value = round.compute_full_relation_purported_value( purported_evaluations, relation_parameters, gate_separators, alpha); @@ -736,13 +735,13 @@ template class SumcheckVerifier { /** * @brief Sumcheck Verifier for ECCVM and ECCVMRecursive. - * @details The verifier receives commitments to RoundUnivariates, along with their evaluations at 0 and 1. - * These evaluations will be proved as a part of Shplemini. The only check that the Verifier performs in - * this version is the comparison of the target sumcheck sum with the claimed evaluations of the first - * sumcheck round univariate at 0 and 1. + * @details The verifier receives commitments to RoundUnivariates, along with their evaluations at 0 and 1. These + * evaluations will be proved as a part of Shplemini. The only check that the Verifier performs in this version is + * the comparison of the target sumcheck sum with the claimed evaluations of the first sumcheck round univariate at + * 0 and 1. * - * Note that the SumcheckOutput in this case contains a vector of commitments and a vector of arrays (of - * size 3) of evaluations at 0, 1, and a round challenge. + * Note that the SumcheckOutput in this case contains a vector of commitments and a vector of arrays (of size 3) of + * evaluations at 0, 1, and a round challenge. * * @param relation_parameters * @param alpha @@ -758,8 +757,8 @@ template class SumcheckVerifier { bb::GateSeparatorPolynomial gate_separators(gate_challenges); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1144): Add proper constraints for taking - // the log of a field_t link multivariate_d. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1144): Add proper constraints for taking the log of + // a field_t link multivariate_d. if (multivariate_d == 0) { throw_or_abort("Number of variables in multivariate is 0."); } @@ -795,8 +794,7 @@ template class SumcheckVerifier { if constexpr (IsRecursiveFlavor) { typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round - // derivation! + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); // Only utilize the checked value if this is not a constant proof size padding round gate_separators.partially_evaluate(round_challenge, dummy_round); @@ -819,13 +817,12 @@ template class SumcheckVerifier { eval = transcript_eval; } // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge - // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover - // polynomials. In ZK Flavors, the evaluation is corrected by full_libra_purported_value + // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover polynomials. + // In ZK Flavors, the evaluation is corrected by full_libra_purported_value FF full_honk_purported_value = round.compute_full_relation_purported_value( purported_evaluations, relation_parameters, gate_separators, alpha); - // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra - // challenge + // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge const FF libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); // We have to branch here for two reasons: @@ -833,13 +830,14 @@ template class SumcheckVerifier { // 2) ECCVMRecursive uses big_field where we need to self_reduce(). if constexpr (IsRecursiveFlavor) { typename Flavor::CircuitBuilder* builder = libra_challenge.get_context(); - // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to - // the rows where all sumcheck relations are disabled + + // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the rows + // where all sumcheck relations are disabled const FF correcting_factor = RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d, builder); - // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row - // and the Libra polynomials + // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row and the + // Libra polynomials full_honk_purported_value = full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; @@ -849,8 +847,7 @@ template class SumcheckVerifier { // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be // checked as a part of Shplemini and pad claimed evaluations to the CONST_PROOF_SIZE_LOG_N for (size_t round_idx = 1; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round - // derivation! + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); round_univariate_evaluations[round_idx - 1][2] = FF::conditional_assign( dummy_round, @@ -861,23 +858,23 @@ template class SumcheckVerifier { first_sumcheck_round_evaluations_sum.self_reduce(); round.target_total_sum.self_reduce(); - // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the - // claimed target total sum + // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the claimed + // target total sum first_sumcheck_round_evaluations_sum.assert_equal(round.target_total_sum); verified = (first_sumcheck_round_evaluations_sum.get_value() == round.target_total_sum.get_value()); } else { - // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to - // the rows where all sumcheck relations are disabled + // Compute the evaluations of the polynomial (1 - \sum L_i) where the sum is for i corresponding to the rows + // where all sumcheck relations are disabled const FF correcting_factor = RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); - // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row - // and the Libra polynomials + // Verifier computes full ZK Honk value, taking into account the contribution from the disabled row and the + // Libra polynomials full_honk_purported_value = full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; - // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be - // checked as a part of Shplemini + // Populate claimed evaluations of Sumcheck Round Unviariates at the round challenges. These will be checked + // as a part of Shplemini for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { round_univariate_evaluations[round_idx - 1][2] = round_univariate_evaluations[round_idx][0] + round_univariate_evaluations[round_idx][1]; @@ -888,8 +885,8 @@ template class SumcheckVerifier { round_univariate_evaluations[round_idx - 1][2] = full_honk_purported_value; }; - // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the - // claimed target total sum + // Ensure that the sum of the evaluations of the first Sumcheck Round Univariate is equal to the claimed + // target total sum verified = (first_sumcheck_round_evaluations_sum == round.target_total_sum); } From 205b85887ea622e6aeeab18a4bf851d5ba8d74dd Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 23 Jan 2025 10:32:50 +0000 Subject: [PATCH 32/33] wrong assert fix --- .../stdlib/honk_verifier/ultra_verification_keys_comparator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp index f2b6d936c90..0255118a000 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp @@ -48,7 +48,7 @@ static void compare_ultra_verification_keys( ASSERT(verification_keys[0]->circuit_size == verification_keys[1]->circuit_size); ASSERT(verification_keys[0]->num_public_inputs == verification_keys[1]->num_public_inputs); - ASSERT(broke); + ASSERT(!broke); } } // namespace bb \ No newline at end of file From fcc8df78c9dc37577f460275b3c68a14663e6e66 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 24 Jan 2025 13:01:52 +0000 Subject: [PATCH 33/33] clean-up after review --- .../client_ivc_recursive_verifier.test.cpp | 5 ++--- .../eccvm_verifier/eccvm_recursive_verifier.test.cpp | 4 ++-- .../honk_verifier/ultra_recursive_verifier.test.cpp | 4 ++-- .../ultra_verification_keys_comparator.hpp | 11 +++++++---- .../translator_recursive_verifier.test.cpp | 4 ++-- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp index 019c076841a..b475bfd8d2a 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp @@ -47,8 +47,6 @@ class ClientIVCRecursionTests : public testing::Test { return { ivc.prove(), ivc.get_vk() }; } - - static void test_independent_vk_hash(){}; }; /** @@ -195,6 +193,7 @@ TEST_F(ClientIVCRecursionTests, TubeVKIndependentOfInputCircuits) auto [blocks_2, verification_key_2] = get_blocks(2); auto [blocks_4, verification_key_4] = get_blocks(4); - compare_ultra_verification_keys({ blocks_2, blocks_4 }, { verification_key_2, verification_key_4 }); + compare_ultra_blocks_and_verification_keys({ blocks_2, blocks_4 }, + { verification_key_2, verification_key_4 }); } } // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp index 9c47847abbb..88dadca1976 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp @@ -175,8 +175,8 @@ template class ECCVMRecursiveTests : public ::testing auto [blocks_20, verification_key_20] = get_blocks(20); auto [blocks_40, verification_key_40] = get_blocks(40); - compare_ultra_verification_keys({ blocks_20, blocks_40 }, - { verification_key_20, verification_key_40 }); + compare_ultra_blocks_and_verification_keys({ blocks_20, blocks_40 }, + { verification_key_20, verification_key_40 }); }; }; using FlavorTypes = testing::Types>; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp index e23ecc625dc..591a80722d0 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp @@ -180,8 +180,8 @@ template class RecursiveVerifierTest : public testing auto [blocks_10, verification_key_10] = get_blocks(10); auto [blocks_11, verification_key_11] = get_blocks(11); - compare_ultra_verification_keys({ blocks_10, blocks_11 }, - { verification_key_10, verification_key_11 }); + compare_ultra_blocks_and_verification_keys({ blocks_10, blocks_11 }, + { verification_key_10, verification_key_11 }); } /** diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp index 0255118a000..20b1ca21210 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp @@ -7,7 +7,7 @@ namespace bb { template -static void compare_ultra_verification_keys( +static void compare_ultra_blocks_and_verification_keys( std::array blocks, std::array, 2> verification_keys) { @@ -15,10 +15,11 @@ static void compare_ultra_verification_keys( // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit bool broke(false); - auto check_eq = [&broke](auto& p1, auto& p2) { + auto check_eq = [&broke](auto& p1, auto& p2, size_t block_idx, size_t selector_idx) { ASSERT(p1.size() == p2.size()); for (size_t idx = 0; idx < p1.size(); idx++) { if (p1[idx] != p2[idx]) { + info("Mismatch selector ", selector_idx, " in block ", block_idx, ", at ", idx); broke = true; break; } @@ -27,11 +28,12 @@ static void compare_ultra_verification_keys( size_t block_idx = 0; for (auto [block_0, block_1] : zip_view(blocks[0].get(), blocks[1].get())) { - info("block index: ", block_idx); ASSERT(block_0.selectors.size() == 13); ASSERT(block_1.selectors.size() == 13); + size_t selector_idx = 0; for (auto [p_10, p_11] : zip_view(block_0.selectors, block_1.selectors)) { - check_eq(p_10, p_11); + check_eq(p_10, p_11, block_idx, selector_idx); + selector_idx++; } block_idx++; } @@ -47,6 +49,7 @@ static void compare_ultra_verification_keys( ASSERT(verification_keys[0]->circuit_size == verification_keys[1]->circuit_size); ASSERT(verification_keys[0]->num_public_inputs == verification_keys[1]->num_public_inputs); + ASSERT(verification_keys[0]->pub_inputs_offset == verification_keys[1]->pub_inputs_offset); ASSERT(!broke); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index d45e7d0f614..abe273f388c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp @@ -175,8 +175,8 @@ template class TranslatorRecursiveTests : public ::te auto [blocks_256, verification_key_256] = get_blocks(256); auto [blocks_512, verification_key_512] = get_blocks(512); - compare_ultra_verification_keys({ blocks_256, blocks_512 }, - { verification_key_256, verification_key_512 }); + compare_ultra_blocks_and_verification_keys({ blocks_256, blocks_512 }, + { verification_key_256, verification_key_512 }); }; };