From 269231b69ff2f12114229d1522faa048ebebc4f0 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 10 Mar 2025 13:37:13 +0000 Subject: [PATCH 01/24] shplemini works, gemini tests need to be re-designed --- .../barretenberg/commitment_schemes/claim.hpp | 1 + .../commitment_schemes/gemini/gemini.hpp | 26 +++++-- .../commitment_schemes/gemini/gemini_impl.hpp | 5 +- .../commitment_schemes/shplonk/shplemini.hpp | 49 +++++++------ .../shplonk/shplemini.test.cpp | 1 + .../commitment_schemes/shplonk/shplonk.hpp | 72 ++++++++++++++++--- 6 files changed, 119 insertions(+), 35 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp index 1afb02a3c66b..57fcd8a4688a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp @@ -33,6 +33,7 @@ template class ProverOpeningClaim { public: Polynomial polynomial; // p OpeningPair opening_pair; // (challenge r, evaluation v = p(r)) + bool gemini_fold = false; }; /** diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index c5b8affd1363..28c61a604c8e 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -444,10 +444,17 @@ template class GeminiVerifier_ { } // Compute the full of evaluation A₀(r) = A₀₊(r) + P₊(r^s) - Fr full_a_0_pos = compute_gemini_batched_univariate_evaluation( + std::vector gemini_fold_pos_evaluations = compute_fold_pos_evaluations( num_variables, batched_evaluation, multilinear_challenge, r_squares, evaluations, p_neg); + + size_t idx = 0; + for (auto eval : gemini_fold_pos_evaluations) { + info("verifier ", idx, " ", eval); + idx++; + } + auto full_a_0_pos = gemini_fold_pos_evaluations[0]; std::vector> fold_polynomial_opening_claims; - fold_polynomial_opening_claims.reserve(num_variables + 1); + fold_polynomial_opening_claims.reserve(2 * num_variables + 2); // ( [A₀₊], r, A₀₊(r) ) fold_polynomial_opening_claims.emplace_back(OpeningClaim{ { r, full_a_0_pos - p_pos }, C0_r_pos }); @@ -457,6 +464,9 @@ template class GeminiVerifier_ { // ([A₀₋], −r^{2ˡ}, Aₗ(−r^{2ˡ}) ) fold_polynomial_opening_claims.emplace_back( OpeningClaim{ { -r_squares[l + 1], evaluations[l + 1] }, commitments[l] }); + + fold_polynomial_opening_claims.emplace_back( + OpeningClaim{ { r_squares[l + 1], gemini_fold_pos_evaluations[l + 1] }, commitments[l] }); } if (has_interleaved) { size_t interleaved_group_size = claim_batcher.get_groups_to_be_interleaved_size(); @@ -514,7 +524,7 @@ template class GeminiVerifier_ { * @param fold_polynomial_evals Evaluations \f$ A_{i-1}(-r^{2^{i-1}}) \f$. * @return Evaluation \f$ A_0(r) \f$. */ - static Fr compute_gemini_batched_univariate_evaluation( + static std::vector compute_fold_pos_evaluations( const size_t num_variables, Fr& batched_eval_accumulator, std::span evaluation_point, // CONST_PROOF_SIZE @@ -524,6 +534,9 @@ template class GeminiVerifier_ { { std::vector evals(fold_polynomial_evals.begin(), fold_polynomial_evals.end()); + std::vector gemini_fold_pos_evaluations; + gemini_fold_pos_evaluations.reserve(CONST_PROOF_SIZE_LOG_N - 1); //? + // Add the contribution of P-((-r)ˢ) to get A_0(-r), which is 0 if there are no interleaved polynomials evals[0] += p_neg; @@ -540,7 +553,6 @@ template class GeminiVerifier_ { ((challenge_power * batched_eval_accumulator * 2) - eval_neg * (challenge_power * (Fr(1) - u) - u)); // Divide by the denominator batched_eval_round_acc *= (challenge_power * (Fr(1) - u) + u).invert(); - if constexpr (Curve::is_stdlib_type) { auto builder = evaluation_point[0].get_context(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! @@ -551,11 +563,15 @@ template class GeminiVerifier_ { } else { if (l <= num_variables) { batched_eval_accumulator = batched_eval_round_acc; + gemini_fold_pos_evaluations.emplace_back(batched_eval_accumulator); + } else { + gemini_fold_pos_evaluations.emplace_back(Fr(0)); } } } + std::reverse(gemini_fold_pos_evaluations.begin(), gemini_fold_pos_evaluations.end()); - return batched_eval_accumulator; + return gemini_fold_pos_evaluations; } }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp index 5e7a2daad601..0836dd9310b2 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp @@ -222,7 +222,6 @@ std::vector::Claim> GeminiProver_::construc const Fr& r_challenge) { std::vector claims; - // Compute evaluation of partially evaluated batch polynomial (positive) A₀₊(r) Fr a_0_pos = A_0_pos.evaluate(r_challenge); claims.emplace_back(Claim{ std::move(A_0_pos), { r_challenge, a_0_pos } }); @@ -233,10 +232,12 @@ std::vector::Claim> GeminiProver_::construc // Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, ..., m-1 std::vector r_squares = gemini::powers_of_evaluation_challenge(r_challenge, log_n); + const bool gemini_fold = true; + // Compute the remaining m opening pairs {−r^{2ˡ}, Aₗ(−r^{2ˡ})}, l = 1, ..., m-1. for (size_t l = 0; l < log_n - 1; ++l) { Fr evaluation = fold_polynomials[l].evaluate(-r_squares[l + 1]); - claims.emplace_back(Claim{ std::move(fold_polynomials[l]), { -r_squares[l + 1], evaluation } }); + claims.emplace_back(Claim{ std::move(fold_polynomials[l]), { -r_squares[l + 1], evaluation }, gemini_fold }); } return claims; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 22536c1762bf..310eb7173331 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -295,8 +295,8 @@ template class ShpleminiVerifier_ { // Compute the additional factors to be multiplied with unshifted and shifted commitments when lazily // reconstructing the commitment of Q_z - claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[0], // 1/(z − r) - inverse_vanishing_evals[1], // 1/(z + r) + claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[1], // 1/(z − r) + inverse_vanishing_evals[0], // 1/(z + r) shplonk_batching_challenge, gemini_evaluation_challenge, interleaving_vanishing_eval); @@ -321,7 +321,7 @@ template class ShpleminiVerifier_ { Fr shplonk_batching_pos = Fr{ 0 }; Fr shplonk_batching_neg = Fr{ 0 }; if (claim_batcher.interleaved) { - shplonk_batching_pos = shplonk_batching_challenge.pow(log_circuit_size + 1); + shplonk_batching_pos = shplonk_batching_challenge.pow(2 * log_circuit_size); shplonk_batching_neg = shplonk_batching_pos * shplonk_batching_challenge; constant_term_accumulator += p_pos * interleaving_vanishing_eval * shplonk_batching_pos + p_neg * interleaving_vanishing_eval * shplonk_batching_neg; @@ -335,34 +335,35 @@ template class ShpleminiVerifier_ { shplonk_batching_pos, shplonk_batching_neg); + // Compute A₀(r) = A₀₊(r) + P₊(r^s) + const std::vector gemini_fold_pos_evaluations = + GeminiVerifier_::compute_fold_pos_evaluations(log_circuit_size, + batched_evaluation, + multivariate_challenge, + gemini_eval_challenge_powers, + gemini_evaluations, + p_neg); + // Place the commitments to Gemini fold polynomials Aᵢ in the vector of batch_mul commitments, compute the // contributions from Aᵢ(−r²ⁱ) for i=1, … , n−1 to the constant term accumulator, add corresponding scalars for // the batch mul batch_gemini_claims_received_from_prover(log_circuit_size, fold_commitments, gemini_evaluations, + gemini_fold_pos_evaluations, inverse_vanishing_evals, shplonk_batching_challenge, commitments, scalars, constant_term_accumulator); - - // Compute A₀(r) = A₀₊(r) + P₊(r^s) - const Fr full_a_0_pos = - GeminiVerifier_::compute_gemini_batched_univariate_evaluation(log_circuit_size, - batched_evaluation, - multivariate_challenge, - gemini_eval_challenge_powers, - gemini_evaluations, - p_neg); - + const Fr full_a_0_pos = gemini_fold_pos_evaluations[0]; // Retrieve the contribution without P₊(r^s) Fr a_0_pos = full_a_0_pos - p_pos; // Add contributions from A₀₊(r) and A₀₋(-r) to constant_term_accumulator: // Add A₀₊(r)/(z−r) to the constant term accumulator - constant_term_accumulator += a_0_pos * inverse_vanishing_evals[0]; + constant_term_accumulator += a_0_pos * inverse_vanishing_evals[1]; // Add A₀₋(-r)/(z+r) to the constant term accumulator - constant_term_accumulator += gemini_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[1]; + constant_term_accumulator += gemini_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[0]; remove_repeated_commitments(commitments, scalars, repeated_commitments, has_zk); @@ -440,6 +441,7 @@ template class ShpleminiVerifier_ { static void batch_gemini_claims_received_from_prover(const size_t log_circuit_size, const std::vector& fold_commitments, const std::vector& gemini_evaluations, + const std::vector& gemini_fold_pos_evaluations, const std::vector& inverse_vanishing_evals, const Fr& shplonk_batching_challenge, std::vector& commitments, @@ -452,10 +454,15 @@ template class ShpleminiVerifier_ { // TODO(https://github.com/AztecProtocol/barretenberg/issues/1159): Decouple constants from primitives. for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N - 1; ++j) { // Compute the scaling factor (ν²⁺ⁱ) / (z + r²⁽ⁱ⁺²⁾) for i = 0, … , d-2 - Fr scaling_factor = current_batching_challenge * inverse_vanishing_evals[j + 2]; + size_t pos_location = 2 * j + 2; + Fr scaling_factor_neg = current_batching_challenge * inverse_vanishing_evals[pos_location]; + current_batching_challenge *= shplonk_batching_challenge; + + Fr scaling_factor_pos = current_batching_challenge * inverse_vanishing_evals[pos_location + 1]; // Add Aᵢ(−r²ⁱ) for i = 1, … , n-1 to the constant term accumulator - constant_term_accumulator += scaling_factor * gemini_evaluations[j + 1]; + constant_term_accumulator += scaling_factor_neg * gemini_evaluations[j + 1] + + scaling_factor_pos * gemini_fold_pos_evaluations[j + 1]; // Update the batching challenge current_batching_challenge *= shplonk_batching_challenge; @@ -465,14 +472,16 @@ template class ShpleminiVerifier_ { // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! stdlib::bool_t dummy_round = stdlib::witness_t(builder, j >= (log_circuit_size - 1)); Fr zero = Fr(0); - scaling_factor = Fr::conditional_assign(dummy_round, zero, scaling_factor); + scaling_factor_neg = Fr::conditional_assign(dummy_round, zero, scaling_factor_neg); + scaling_factor_pos = Fr::conditional_assign(dummy_round, zero, scaling_factor_pos); } else { if (j >= (log_circuit_size - 1)) { - scaling_factor = 0; + scaling_factor_neg = 0; + scaling_factor_pos = 0; } } // Place the scaling factor to the 'scalars' vector - scalars.emplace_back(-scaling_factor); + scalars.emplace_back(-scaling_factor_neg - scaling_factor_pos); // Move com(Aᵢ) to the 'commitments' vector commitments.emplace_back(std::move(fold_commitments[j])); } 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 542526480699..98191b6c6bec 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -263,6 +263,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) ShpleminiVerifier::batch_gemini_claims_received_from_prover(this->log_n, prover_commitments, prover_evaluations, + {}, inverse_vanishing_evals, shplonk_batching_challenge, commitments, diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index f7cd6b15c02a..7f0d0448b57f 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -41,6 +41,7 @@ template class ShplonkProver_ { */ static Polynomial compute_batched_quotient(std::span> opening_claims, const Fr& nu, + std::span gemini_fold_pos_evaluations, std::span> libra_opening_claims, std::span> sumcheck_round_claims) { @@ -61,6 +62,8 @@ template class ShplonkProver_ { Polynomial tmp(max_poly_size); Fr current_nu = Fr::one(); + + size_t fold_idx = 0; for (const auto& claim : opening_claims) { // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) tmp = claim.polynomial; @@ -69,6 +72,16 @@ template class ShplonkProver_ { // Add the claim quotient to the batched quotient polynomial Q.add_scaled(tmp, current_nu); current_nu *= nu; + + if (claim.gemini_fold) { + tmp = claim.polynomial; + tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx]; + 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; + fold_idx++; + } } // We use the same batching challenge for Gemini and Libra opening claims. The number of the claims @@ -118,6 +131,7 @@ template class ShplonkProver_ { Polynomial& batched_quotient_Q, const Fr& nu_challenge, const Fr& z_challenge, + std::span gemini_fold_pos_evaluations, std::span> libra_opening_claims = {}, std::span> sumcheck_opening_claims = {}) { @@ -128,6 +142,9 @@ template class ShplonkProver_ { inverse_vanishing_evals.reserve(num_opening_claims); for (const auto& claim : opening_claims) { inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge); + if (claim.gemini_fold) { + inverse_vanishing_evals.emplace_back(z_challenge + claim.opening_pair.challenge); + } } // Add the terms (z - uₖ) for k = 0, …, d−1 where d is the number of rounds in Sumcheck @@ -150,6 +167,7 @@ template class ShplonkProver_ { Polynomial tmp(G.size()); size_t idx = 0; + size_t fold_idx = 0; for (const auto& claim : opening_claims) { // tmp = νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) tmp = claim.polynomial; @@ -161,6 +179,18 @@ template class ShplonkProver_ { current_nu *= nu_challenge; idx++; + if (claim.gemini_fold) { + tmp = claim.polynomial; + tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx]; + info("prover ", fold_idx, " eval ", gemini_fold_pos_evaluations[fold_idx]); + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ ) + // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) + G.add_scaled(tmp, -scaling_factor); + + current_nu *= nu_challenge; + fold_idx++; + idx++; + } } // Take into account the constant proof size in Gemini @@ -194,6 +224,22 @@ template class ShplonkProver_ { return { .polynomial = G, .opening_pair = { .challenge = z_challenge, .evaluation = Fr::zero() } }; }; + static std::vector compute_gemini_fold_pos_evaluations( + std::span> opening_claims) + { + std::vector gemini_fold_pos_evaluations; + gemini_fold_pos_evaluations.reserve(opening_claims.size()); + + for (const auto claim : opening_claims) { + if (claim.gemini_fold) { + const Fr evaluation_point = -claim.opening_pair.challenge; + const Fr evaluation = claim.polynomial.evaluate(evaluation_point); + gemini_fold_pos_evaluations.emplace_back(evaluation); + } + } + return gemini_fold_pos_evaluations; + } + /** * @brief Returns a batched opening claim equivalent to a set of opening claims consisting of polynomials, each * opened at a single point. @@ -211,13 +257,21 @@ template class ShplonkProver_ { 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, sumcheck_round_claims); + + std::vector gemini_fold_pos_evaluations = compute_gemini_fold_pos_evaluations(opening_claims); + + auto batched_quotient = compute_batched_quotient( + opening_claims, nu, gemini_fold_pos_evaluations, 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, sumcheck_round_claims); + return compute_partially_evaluated_batched_quotient(opening_claims, + batched_quotient, + nu, + z, + gemini_fold_pos_evaluations, + libra_opening_claims, + sumcheck_round_claims); } }; @@ -368,11 +422,13 @@ template class ShplonkVerifier_ { const std::vector& gemini_eval_challenge_powers) { std::vector inverted_denominators; - inverted_denominators.reserve(num_gemini_claims); - inverted_denominators.emplace_back((shplonk_eval_challenge - gemini_eval_challenge_powers[0]).invert()); + inverted_denominators.reserve(2 * num_gemini_claims); + for (const auto& gemini_eval_challenge_power : gemini_eval_challenge_powers) { - Fr round_inverted_denominator = (shplonk_eval_challenge + gemini_eval_challenge_power).invert(); - inverted_denominators.emplace_back(round_inverted_denominator); + Fr round_inverted_neg_denominator = (shplonk_eval_challenge + gemini_eval_challenge_power).invert(); + inverted_denominators.emplace_back(round_inverted_neg_denominator); + Fr round_inverted_pos_denominator = (shplonk_eval_challenge - gemini_eval_challenge_power).invert(); + inverted_denominators.emplace_back(round_inverted_pos_denominator); } return inverted_denominators; } From 75d411cefdf6614b556f81b2fd3717bafc09633f Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 10 Mar 2025 20:10:12 +0000 Subject: [PATCH 02/24] interleaving fails --- .../barretenberg/commitment_schemes/claim.hpp | 2 + .../commitment_schemes/claim_batcher.hpp | 8 +- .../commitment_schemes/shplonk/shplemini.hpp | 98 ++++++++++--------- .../shplonk/shplemini.test.cpp | 31 ++++-- .../commitment_schemes/shplonk/shplonk.hpp | 54 +++++----- 5 files changed, 111 insertions(+), 82 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp index 57fcd8a4688a..97a1e51e4187 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp @@ -33,6 +33,8 @@ template class ProverOpeningClaim { public: Polynomial polynomial; // p OpeningPair opening_pair; // (challenge r, evaluation v = p(r)) + // Gemini Folds have to be opened at `challenge` and -`challenge`. Instead of copying a polynomial into 2 claims, we + // raise the flag that turns on relevant claim processing logic in Shplonk. bool gemini_fold = false; }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp index b717807c3d93..5f7e365fd06b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp @@ -71,13 +71,13 @@ template struct ClaimBatcher_ { * \right) * \f] * - * @param inverse_vanishing_eval_pos 1/(z-r) - * @param inverse_vanishing_eval_neg 1/(z+r) + * @param inverse_vanishing_eval_pos 1/(z+r) + * @param inverse_vanishing_eval_neg 1/(z-r) * @param nu_challenge ν (shplonk batching challenge) * @param r_challenge r (gemini evaluation challenge) */ - void compute_scalars_for_each_batch(const Fr& inverse_vanishing_eval_pos, - const Fr& inverse_vanishing_eval_neg, + void compute_scalars_for_each_batch(const Fr& inverse_vanishing_eval_neg, + const Fr& inverse_vanishing_eval_pos, const Fr& nu_challenge, const Fr& r_challenge, const Fr& interleaving_vanishing_eval = { 0 }) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 310eb7173331..ed274892bf80 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -188,6 +188,7 @@ template class ShpleminiVerifier_ { using ShplonkVerifier = ShplonkVerifier_; using GeminiVerifier = GeminiVerifier_; using ClaimBatcher = ClaimBatcher_; + static constexpr size_t NUM_GEMINI_FOLD_CLAIMS = 2 * CONST_PROOF_SIZE_LOG_N; public: template @@ -236,7 +237,7 @@ template class ShpleminiVerifier_ { const Fr gemini_evaluation_challenge = transcript->template get_challenge("Gemini:r"); // - Get evaluations (A₀(−r), A₁(−r²), ... , Aₙ₋₁(−r²⁽ⁿ⁻¹⁾)) - const std::vector gemini_evaluations = GeminiVerifier::get_gemini_evaluations(transcript); + const std::vector gemini_fold_neg_evaluations = GeminiVerifier::get_gemini_evaluations(transcript); // Get evaluations of partially evaluated batched interleaved polynomials P₊(rˢ) and P₋((-r)ˢ) Fr p_pos = Fr(0); @@ -261,6 +262,9 @@ template class ShpleminiVerifier_ { // Process Shplonk transcript data: // - Get Shplonk batching challenge const Fr shplonk_batching_challenge = transcript->template get_challenge("Shplonk:nu"); + + const std::vector shplonk_batching_challenge_powers = compute_shplonk_batching_challenge_powers( + shplonk_batching_challenge, has_zk, !sumcheck_round_evaluations.empty()); // - Get the quotient commitment for the Shplonk batching of Gemini opening claims const auto Q_commitment = transcript->template receive_from_prover("Shplonk:Q"); @@ -295,8 +299,8 @@ template class ShpleminiVerifier_ { // Compute the additional factors to be multiplied with unshifted and shifted commitments when lazily // reconstructing the commitment of Q_z - claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[1], // 1/(z − r) - inverse_vanishing_evals[0], // 1/(z + r) + claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[0], // 1/(z + r) + inverse_vanishing_evals[1], // 1/(z - r) shplonk_batching_challenge, gemini_evaluation_challenge, interleaving_vanishing_eval); @@ -321,8 +325,8 @@ template class ShpleminiVerifier_ { Fr shplonk_batching_pos = Fr{ 0 }; Fr shplonk_batching_neg = Fr{ 0 }; if (claim_batcher.interleaved) { - shplonk_batching_pos = shplonk_batching_challenge.pow(2 * log_circuit_size); - shplonk_batching_neg = shplonk_batching_pos * shplonk_batching_challenge; + shplonk_batching_pos = shplonk_batching_challenge_powers[2 * log_circuit_size - 1]; + shplonk_batching_neg = shplonk_batching_challenge_powers[2 * log_circuit_size]; constant_term_accumulator += p_pos * interleaving_vanishing_eval * shplonk_batching_pos + p_neg * interleaving_vanishing_eval * shplonk_batching_neg; } @@ -341,7 +345,7 @@ template class ShpleminiVerifier_ { batched_evaluation, multivariate_challenge, gemini_eval_challenge_powers, - gemini_evaluations, + gemini_fold_neg_evaluations, p_neg); // Place the commitments to Gemini fold polynomials Aᵢ in the vector of batch_mul commitments, compute the @@ -349,10 +353,10 @@ template class ShpleminiVerifier_ { // the batch mul batch_gemini_claims_received_from_prover(log_circuit_size, fold_commitments, - gemini_evaluations, + gemini_fold_neg_evaluations, gemini_fold_pos_evaluations, inverse_vanishing_evals, - shplonk_batching_challenge, + shplonk_batching_challenge_powers, commitments, scalars, constant_term_accumulator); @@ -363,7 +367,8 @@ template class ShpleminiVerifier_ { // Add A₀₊(r)/(z−r) to the constant term accumulator constant_term_accumulator += a_0_pos * inverse_vanishing_evals[1]; // Add A₀₋(-r)/(z+r) to the constant term accumulator - constant_term_accumulator += gemini_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[0]; + constant_term_accumulator += + gemini_fold_neg_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[0]; remove_repeated_commitments(commitments, scalars, repeated_commitments, has_zk); @@ -376,7 +381,7 @@ template class ShpleminiVerifier_ { libra_commitments, libra_evaluations, gemini_evaluation_challenge, - shplonk_batching_challenge, + shplonk_batching_challenge_powers, shplonk_evaluation_challenge); *consistency_checked = SmallSubgroupIPAVerifier::check_libra_evaluations_consistency( @@ -390,7 +395,7 @@ template class ShpleminiVerifier_ { scalars, constant_term_accumulator, multivariate_challenge, - shplonk_batching_challenge, + shplonk_batching_challenge_powers, shplonk_evaluation_challenge, sumcheck_round_commitments, sumcheck_round_evaluations); @@ -443,32 +448,27 @@ template class ShpleminiVerifier_ { const std::vector& gemini_evaluations, const std::vector& gemini_fold_pos_evaluations, const std::vector& inverse_vanishing_evals, - const Fr& shplonk_batching_challenge, + const std::vector& shplonk_batching_challenge_powers, std::vector& commitments, std::vector& scalars, Fr& constant_term_accumulator) { - // Initialize batching challenge as ν² - Fr current_batching_challenge = shplonk_batching_challenge.sqr(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1159): Decouple constants from primitives. for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N - 1; ++j) { // Compute the scaling factor (ν²⁺ⁱ) / (z + r²⁽ⁱ⁺²⁾) for i = 0, … , d-2 size_t pos_location = 2 * j + 2; - Fr scaling_factor_neg = current_batching_challenge * inverse_vanishing_evals[pos_location]; - current_batching_challenge *= shplonk_batching_challenge; - - Fr scaling_factor_pos = current_batching_challenge * inverse_vanishing_evals[pos_location + 1]; + Fr scaling_factor_neg = + shplonk_batching_challenge_powers[pos_location] * inverse_vanishing_evals[pos_location]; + Fr scaling_factor_pos = + shplonk_batching_challenge_powers[pos_location + 1] * inverse_vanishing_evals[pos_location + 1]; // Add Aᵢ(−r²ⁱ) for i = 1, … , n-1 to the constant term accumulator constant_term_accumulator += scaling_factor_neg * gemini_evaluations[j + 1] + scaling_factor_pos * gemini_fold_pos_evaluations[j + 1]; - // Update the batching challenge - current_batching_challenge *= shplonk_batching_challenge; - if constexpr (Curve::is_stdlib_type) { - auto builder = shplonk_batching_challenge.get_context(); + auto builder = gemini_evaluations[0].get_context(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! stdlib::bool_t dummy_round = stdlib::witness_t(builder, j >= (log_circuit_size - 1)); Fr zero = Fr(0); @@ -589,16 +589,10 @@ template class ShpleminiVerifier_ { const std::array& libra_commitments, const std::array& libra_evaluations, const Fr& gemini_evaluation_challenge, - const Fr& shplonk_batching_challenge, + const std::vector& shplonk_batching_challenge_powers, const Fr& shplonk_evaluation_challenge) { - // compute current power of Shplonk batching challenge taking into account the const proof size - Fr shplonk_challenge_power = Fr{ 1 }; - for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2; ++j) { - shplonk_challenge_power *= shplonk_batching_challenge; - } - // add Libra commitments to the vector of commitments for (size_t idx = 0; idx < libra_commitments.size(); idx++) { commitments.push_back(libra_commitments[idx]); @@ -616,10 +610,11 @@ template class ShpleminiVerifier_ { // compute the scalars to be multiplied against the commitments [libra_concatenated], [grand_sum], [grand_sum], // and [libra_quotient] + size_t power = NUM_GEMINI_FOLD_CLAIMS + 2; for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; idx++) { - Fr scaling_factor = denominators[idx] * shplonk_challenge_power; + Fr scaling_factor = denominators[idx] * shplonk_batching_challenge_powers[power++]; + info(" ver scal factor ", scaling_factor); batching_scalars[idx] = -scaling_factor; - shplonk_challenge_power *= shplonk_batching_challenge; constant_term_accumulator += scaling_factor * libra_evaluations[idx]; } @@ -676,7 +671,7 @@ template class ShpleminiVerifier_ { std::vector& scalars, Fr& constant_term_accumulator, const std::vector& multilinear_challenge, - const Fr& shplonk_batching_challenge, + const std::vector& shplonk_batching_challenge_powers, const Fr& shplonk_evaluation_challenge, const std::vector& sumcheck_round_commitments, const std::vector>& sumcheck_round_evaluations) @@ -684,12 +679,6 @@ 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_SMALL_IPA_EVALUATIONS; ++j) { - shplonk_challenge_power *= shplonk_batching_challenge; - } - // 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; @@ -716,29 +705,27 @@ template class ShpleminiVerifier_ { // 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; + size_t power = NUM_GEMINI_FOLD_CLAIMS + 2 + NUM_SMALL_IPA_EVALUATIONS; for (const auto& [eval_array, denominator] : zip_view(sumcheck_round_evaluations, denominators)) { // 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; + Fr current_scaling_factor = const_denominators[idx] * shplonk_batching_challenge_powers[power++]; batched_scalar -= current_scaling_factor; - shplonk_challenge_power *= shplonk_batching_challenge; const_term_contribution += current_scaling_factor * eval_array[idx]; } // Compute the contribution from the evaluation at the challenge u_i - Fr current_scaling_factor = denominator * shplonk_challenge_power; + Fr current_scaling_factor = denominator * shplonk_batching_challenge_powers[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(); + auto builder = shplonk_evaluation_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); const_term_contribution = Fr::conditional_assign(dummy_round, zero, const_term_contribution); @@ -756,5 +743,28 @@ template class ShpleminiVerifier_ { round_idx++; } }; + + static std::vector compute_shplonk_batching_challenge_powers(const Fr& shplonk_batching_challenge, + bool has_zk = false, + bool committed_sumcheck = false) + { + size_t num_powers = NUM_GEMINI_FOLD_CLAIMS + 2; + + if (has_zk) { + num_powers += NUM_SMALL_IPA_EVALUATIONS; + } + + if (committed_sumcheck) { + num_powers += CONST_PROOF_SIZE_LOG_N; + } + + std::vector result; + result.reserve(num_powers); + result.emplace_back(Fr{ 1 }); + for (size_t idx = 1; idx < num_powers; idx++) { + result.emplace_back(result[idx - 1] * shplonk_batching_challenge); + } + return result; + } }; } // namespace bb 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 98191b6c6bec..4d0da2d2e19e 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -163,7 +163,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching) Fr inverted_vanishing_eval_neg = (shplonk_eval_challenge + gemini_eval_challenge).invert(); mock_claims.claim_batcher.compute_scalars_for_each_batch( - inverted_vanishing_eval_pos, inverted_vanishing_eval_neg, shplonk_batching_challenge, gemini_eval_challenge); + inverted_vanishing_eval_neg, inverted_vanishing_eval_pos, shplonk_batching_challenge, gemini_eval_challenge); rho_power = Fr{ 1 }; mock_claims.claim_batcher.update_batch_mul_inputs_and_batched_evaluation( @@ -196,6 +196,8 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) Fr rho = Fr::random_element(); Fr gemini_eval_challenge = Fr::random_element(); Fr shplonk_batching_challenge = Fr::random_element(); + std::vector shplonk_batching_challenge_powers = + ShpleminiVerifier::compute_shplonk_batching_challenge_powers(shplonk_batching_challenge); Fr shplonk_eval_challenge = Fr::random_element(); std::vector mle_opening_point = this->random_evaluation_point(this->log_n); @@ -239,16 +241,19 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) std::vector r_squares = gemini::powers_of_evaluation_challenge(gemini_eval_challenge, this->log_n); GroupElement expected_result = GroupElement::zero(); - std::vector expected_inverse_vanishing_evals(this->log_n + 1); + std::vector expected_inverse_vanishing_evals; + expected_inverse_vanishing_evals.reserve(2 * this->log_n); // Compute expected inverses - expected_inverse_vanishing_evals[0] = (shplonk_eval_challenge - r_squares[0]).invert(); - for (size_t idx = 1; idx < this->log_n + 1; idx++) { - expected_inverse_vanishing_evals[idx] = (shplonk_eval_challenge + r_squares[idx - 1]).invert(); + for (size_t idx = 0; idx < this->log_n; idx++) { + expected_inverse_vanishing_evals.emplace_back((shplonk_eval_challenge + r_squares[idx]).invert()); + expected_inverse_vanishing_evals.emplace_back((shplonk_eval_challenge - r_squares[idx]).invert()); } Fr current_challenge{ shplonk_batching_challenge * shplonk_batching_challenge }; for (size_t idx = 0; idx < prover_commitments.size(); ++idx) { - expected_result -= prover_commitments[idx] * current_challenge * expected_inverse_vanishing_evals[idx + 2]; + expected_result -= prover_commitments[idx] * current_challenge * expected_inverse_vanishing_evals[2 * idx + 2]; + current_challenge *= shplonk_batching_challenge; + expected_result -= prover_commitments[idx] * current_challenge * expected_inverse_vanishing_evals[2 * idx + 3]; current_challenge *= shplonk_batching_challenge; } @@ -256,16 +261,24 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) std::vector inverse_vanishing_evals = ShplonkVerifier::compute_inverted_gemini_denominators(this->log_n + 1, shplonk_eval_challenge, r_squares); + Fr expected_constant_term_accumulator{ 0 }; + + std::vector gemini_fold_pos_evaluations = + GeminiVerifier_::compute_fold_pos_evaluations(this->log_n, + expected_constant_term_accumulator, + mle_opening_point, + r_squares, + prover_evaluations, + expected_constant_term_accumulator); std::vector commitments; std::vector scalars; - Fr expected_constant_term_accumulator{ 0 }; ShpleminiVerifier::batch_gemini_claims_received_from_prover(this->log_n, prover_commitments, prover_evaluations, - {}, + gemini_fold_pos_evaluations, inverse_vanishing_evals, - shplonk_batching_challenge, + shplonk_batching_challenge_powers, commitments, scalars, expected_constant_term_accumulator); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index 7f0d0448b57f..db96f18af018 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -73,6 +73,7 @@ template class ShplonkProver_ { Q.add_scaled(tmp, current_nu); current_nu *= nu; + // Gemini Fold Polynomials have to be opened at -r^{2^j} and r^{2^j}. if (claim.gemini_fold) { tmp = claim.polynomial; tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx]; @@ -86,9 +87,7 @@ template class ShplonkProver_ { // We use the same batching challenge for Gemini and Libra opening claims. The number of the claims // batched before adding Libra commitments and evaluations is bounded by CONST_PROOF_SIZE_LOG_N+2 - for (size_t idx = opening_claims.size(); idx < CONST_PROOF_SIZE_LOG_N + 2; idx++) { - current_nu *= nu; - }; + current_nu = nu.pow(2 * CONST_PROOF_SIZE_LOG_N + 2); for (const auto& claim : libra_opening_claims) { // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) @@ -172,52 +171,48 @@ template class ShplonkProver_ { // tmp = νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) tmp = claim.polynomial; tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; - Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ ) + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) G.add_scaled(tmp, -scaling_factor); current_nu *= nu_challenge; - idx++; + if (claim.gemini_fold) { tmp = claim.polynomial; tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx]; info("prover ", fold_idx, " eval ", gemini_fold_pos_evaluations[fold_idx]); - Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ ) + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) G.add_scaled(tmp, -scaling_factor); current_nu *= nu_challenge; fold_idx++; - idx++; } } // Take into account the constant proof size in Gemini - for (size_t idx = opening_claims.size(); idx < CONST_PROOF_SIZE_LOG_N + 2; idx++) { - current_nu *= nu_challenge; - }; + current_nu = nu_challenge.pow(2 * CONST_PROOF_SIZE_LOG_N + 2); for (const auto& claim : libra_opening_claims) { // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) tmp = claim.polynomial; + info("zk current nu ", current_nu); tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; - Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ ) - + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) + info(scaling_factor); // Add the claim quotient to the batched quotient polynomial G.add_scaled(tmp, -scaling_factor); - idx++; current_nu *= nu_challenge; } - + info("prover nu before sumcheck op claims ", current_nu); 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ⱼ ) + 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) @@ -410,27 +405,36 @@ template class ShplonkVerifier_ { return { { z_challenge, evaluation }, G_commitment }; }; /** - * @brief Computes \f$ \frac{1}{z - r}, \frac{1}{z+r}, \ldots, \frac{1}{z+r^{2^{d-1}}} \f$. + * @brief Computes \f$ \frac{1}{z + r}, \frac{1}{z-r}, \ldots, \frac{1}{z+r^{2^{d-1}}}, \frac{1}{z-r^{2^{d-1}}} \f$. * * @param num_gemini_claims \f$ d + 1 \f$ where d = log_circuit_size * @param shplonk_eval_challenge \f$ z \f$ * @param gemini_eval_challenge_powers \f$ (r , r^2, \ldots, r^{2^{d-1}}) \f$ - * @return \f[ \left( \frac{1}{z - r}, \frac{1}{z+r}, \ldots, \frac{1}{z+r^{2^{d-1}}} \right) \f] + * @return \f[ \left( \frac{1}{z + r}, \frac{1}{z-r}, \ldots, \frac{1}{z+r^{2^{d-1}}}, \frac{1}{z-r^{2^{d-1}}} + * \right) \f] */ static std::vector compute_inverted_gemini_denominators(const size_t num_gemini_claims, const Fr& shplonk_eval_challenge, const std::vector& gemini_eval_challenge_powers) { - std::vector inverted_denominators; - inverted_denominators.reserve(2 * num_gemini_claims); + std::vector denominators; + denominators.reserve(2 * num_gemini_claims); for (const auto& gemini_eval_challenge_power : gemini_eval_challenge_powers) { - Fr round_inverted_neg_denominator = (shplonk_eval_challenge + gemini_eval_challenge_power).invert(); - inverted_denominators.emplace_back(round_inverted_neg_denominator); - Fr round_inverted_pos_denominator = (shplonk_eval_challenge - gemini_eval_challenge_power).invert(); - inverted_denominators.emplace_back(round_inverted_pos_denominator); + // Place 1/(z + r ^ {2^j}) + denominators.emplace_back(shplonk_eval_challenge + gemini_eval_challenge_power); + // Place 1/(z - r ^ {2^j}) + denominators.emplace_back(shplonk_eval_challenge - gemini_eval_challenge_power); + } + + if constexpr (Curve::is_stdlib_type) { + Fr::batch_invert(denominators); + } else { + for (auto& denominator : denominators) { + denominator = denominator.invert(); + } } - return inverted_denominators; + return denominators; } }; } // namespace bb From f1c9981952c2a79eaa90411e5fcb68e24a3bbff5 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 10 Mar 2025 20:22:17 +0000 Subject: [PATCH 03/24] interleaving fixed --- .../src/barretenberg/commitment_schemes/kzg/kzg.test.cpp | 2 +- .../barretenberg/commitment_schemes/shplonk/shplemini.hpp | 5 ++--- .../src/barretenberg/commitment_schemes/shplonk/shplonk.hpp | 6 ++---- 3 files changed, 5 insertions(+), 8 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 2aba6e60c54a..571e359ec878 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp @@ -199,7 +199,7 @@ TEST_F(KZGTest, ShpleminiKzgWithShift) EXPECT_EQ(vk->pairing_check(pairing_points[0], pairing_points[1]), true); } -TEST_F(KZGTest, ShpleminiKzgWithShiftAndConcatenation) +TEST_F(KZGTest, ShpleminiKzgWithShiftAndInterleaving) { std::vector mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u' // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index ed274892bf80..1d7a277f1600 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -325,8 +325,8 @@ template class ShpleminiVerifier_ { Fr shplonk_batching_pos = Fr{ 0 }; Fr shplonk_batching_neg = Fr{ 0 }; if (claim_batcher.interleaved) { - shplonk_batching_pos = shplonk_batching_challenge_powers[2 * log_circuit_size - 1]; - shplonk_batching_neg = shplonk_batching_challenge_powers[2 * log_circuit_size]; + shplonk_batching_pos = shplonk_batching_challenge_powers[2 * log_circuit_size]; + shplonk_batching_neg = shplonk_batching_challenge_powers[2 * log_circuit_size + 1]; constant_term_accumulator += p_pos * interleaving_vanishing_eval * shplonk_batching_pos + p_neg * interleaving_vanishing_eval * shplonk_batching_neg; } @@ -613,7 +613,6 @@ template class ShpleminiVerifier_ { size_t power = NUM_GEMINI_FOLD_CLAIMS + 2; for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; idx++) { Fr scaling_factor = denominators[idx] * shplonk_batching_challenge_powers[power++]; - info(" ver scal factor ", scaling_factor); batching_scalars[idx] = -scaling_factor; constant_term_accumulator += scaling_factor * libra_evaluations[idx]; } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index db96f18af018..1915fc14c35b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -181,7 +181,6 @@ template class ShplonkProver_ { if (claim.gemini_fold) { tmp = claim.polynomial; tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx]; - info("prover ", fold_idx, " eval ", gemini_fold_pos_evaluations[fold_idx]); Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) G.add_scaled(tmp, -scaling_factor); @@ -197,15 +196,14 @@ template class ShplonkProver_ { for (const auto& claim : libra_opening_claims) { // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) tmp = claim.polynomial; - info("zk current nu ", current_nu); tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) - info(scaling_factor); + // Add the claim quotient to the batched quotient polynomial G.add_scaled(tmp, -scaling_factor); current_nu *= nu_challenge; } - info("prover nu before sumcheck op claims ", current_nu); + for (const auto& claim : sumcheck_opening_claims) { tmp = claim.polynomial; tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; From 9b7af30440804d5b73120462ef2e881be9194436 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 11 Mar 2025 15:18:39 +0000 Subject: [PATCH 04/24] gemini tests --- .../commitment_schemes/gemini/gemini.hpp | 5 - .../commitment_schemes/gemini/gemini.test.cpp | 96 ++++++++++++++++--- 2 files changed, 83 insertions(+), 18 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index 28c61a604c8e..c0261fc33646 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -447,11 +447,6 @@ template class GeminiVerifier_ { std::vector gemini_fold_pos_evaluations = compute_fold_pos_evaluations( num_variables, batched_evaluation, multilinear_challenge, r_squares, evaluations, p_neg); - size_t idx = 0; - for (auto eval : gemini_fold_pos_evaluations) { - info("verifier ", idx, " ", eval); - idx++; - } auto full_a_0_pos = gemini_fold_pos_evaluations[0]; std::vector> fold_polynomial_opening_claims; fold_polynomial_opening_claims.reserve(2 * num_variables + 2); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp index 60bcaa42ee06..2fa7bb036816 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp @@ -12,7 +12,7 @@ template class GeminiTest : public CommitmentTest { using Commitment = typename Curve::AffineElement; public: - static constexpr size_t log_n = 4; + static constexpr size_t log_n = 3; static constexpr size_t n = 1UL << log_n; using CK = CommitmentKey; @@ -38,20 +38,43 @@ template class GeminiTest : public CommitmentTest { auto prover_output = GeminiProver::prove( this->n, mock_claims.polynomial_batcher, multilinear_evaluation_point, ck, prover_transcript); + // The prover output needs to be completed by adding the "positive" Fold claims, i.e. evaluations of Fold^(i) at + // r^{2^i} for i=1, ..., d-1. Although here we are copying polynomials, it is not the case when GeminiProver is + // combined with ShplonkProver. + std::vector> prover_claims_with_pos_evals; + prover_claims_with_pos_evals.reserve(2 * log_n); + + for (auto& claim : prover_output) { + prover_claims_with_pos_evals.emplace_back(claim); + if (claim.gemini_fold) { + if (claim.gemini_fold) { + // "positive" evaluation challenge r^{2^i} for i = 0, ..., d-1 + const Fr evaluation_challenge = -claim.opening_pair.challenge; + // Fold^(i) at r^{2^i} for i=0, ..., d-1 + const Fr pos_evaluation = claim.polynomial.evaluate(evaluation_challenge); + // Add the positive Fold claims to the vector of claims + ProverOpeningClaim pos_fold_claim = { .polynomial = claim.polynomial, + .opening_pair = { .challenge = evaluation_challenge, + .evaluation = pos_evaluation } }; + prover_claims_with_pos_evals.emplace_back(pos_fold_claim); + } + } + } + // Check that the Fold polynomials have been evaluated correctly in the prover - this->verify_batch_opening_pair(prover_output); + this->verify_batch_opening_pair(prover_claims_with_pos_evals); auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); // Compute: - // - Single opening pair: {r, \hat{a}_0} + // - d opening pairs: {r^{2^i}, \hat{a}_i} for i = 0, ..., d-1 // - 2 partially evaluated Fold polynomial commitments [Fold_{r}^(0)] and [Fold_{-r}^(0)] - // Aggregate: d+1 opening pairs and d+1 Fold poly commitments into verifier claim + // Aggregate: 2d opening pairs and 2d Fold poly commitments into verifier claim auto verifier_claims = GeminiVerifier::reduce_verification( multilinear_evaluation_point, mock_claims.claim_batcher, verifier_transcript); // Check equality of the opening pairs computed by prover and verifier - for (auto [prover_claim, verifier_claim] : zip_view(prover_output, verifier_claims)) { + for (auto [prover_claim, verifier_claim] : zip_view(prover_claims_with_pos_evals, verifier_claims)) { this->verify_opening_claim(verifier_claim, prover_claim.polynomial, ck); ASSERT_EQ(prover_claim.opening_pair, verifier_claim.opening_pair); } @@ -124,11 +147,18 @@ TYPED_TEST(GeminiTest, DoubleWithShiftAndConcatenation) */ TYPED_TEST(GeminiTest, SoundnessRegression) { + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; + using Claim = ProverOpeningClaim; + using Commitment = TypeParam::AffineElement; using Fr = TypeParam::ScalarField; const size_t log_n = 3; const size_t n = 8; auto prover_transcript = NativeTranscript::prover_init_empty(); + const Fr rho = prover_transcript->template get_challenge("rho"); + std::vector> fold_polynomials; + fold_polynomials.reserve(log_n); bb::Polynomial zero_polynomial(n); auto u = this->random_evaluation_point(this->log_n); @@ -158,11 +188,18 @@ TYPED_TEST(GeminiTest, SoundnessRegression) fold_1.at(2) = -(Fr(1) - u[1]) * fold_1.at(1) * u[1].invert(); // fold₁[2] = -(1 - u₁) ⋅ fold₁[1] / u₁ fold_1.at(3) = Fr(0); + prover_transcript->template send_to_verifier("Gemini:FOLD_1", this->ck->commit(fold_1)); + prover_transcript->template send_to_verifier("Gemini:FOLD_2", this->ck->commit(fold_2)); + + for (size_t idx = log_n; idx < CONST_PROOF_SIZE_LOG_N; idx++) { + prover_transcript->template send_to_verifier("Gemini:FOLD_" + std::to_string(idx), Commitment::one()); + } + // Get Gemini evaluation challenge - const Fr gemini_r = Fr::random_element(); + const Fr gemini_r = prover_transcript->template get_challenge("Gemini:r"); // Place honest eval of fold₀(-r) to the vector of evals - fold_evals.emplace_back(Fr(0)); + fold_evals.emplace_back(zero_polynomial.evaluate(-gemini_r)); // Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, 2 std::vector r_squares = gemini::powers_of_evaluation_challenge(gemini_r, log_n); @@ -170,18 +207,51 @@ TYPED_TEST(GeminiTest, SoundnessRegression) // Compute honest evaluations fold₁(-r²) and fold₂(-r⁴) fold_evals.emplace_back(fold_1.evaluate(-r_squares[1])); fold_evals.emplace_back(fold_2.evaluate(-r_squares[2])); + prover_transcript->template send_to_verifier("Gemini:a_1", fold_evals[0]); + prover_transcript->template send_to_verifier("Gemini:a_2", fold_evals[1]); + prover_transcript->template send_to_verifier("Gemini:a_3", fold_evals[2]); + for (size_t idx = log_n + 1; idx <= CONST_PROOF_SIZE_LOG_N; idx++) { + prover_transcript->template send_to_verifier("Gemini:a_" + std::to_string(idx), Fr{ 0 }); + } // Compute the powers of r used by the verifier. It is an artifact of the const proof size logic. const std::vector gemini_eval_challenge_powers = gemini::powers_of_evaluation_challenge(gemini_r, CONST_PROOF_SIZE_LOG_N); - // Compute fold₀(r) as Verifier would compute it - const Fr full_a_0_pos = GeminiVerifier_::compute_gemini_batched_univariate_evaluation( - log_n, claimed_multilinear_eval, u, gemini_eval_challenge_powers, fold_evals); + std::vector prover_opening_claims; + prover_opening_claims.reserve(2 * log_n); + + prover_opening_claims.emplace_back(Claim{ zero_polynomial, { gemini_r, Fr{ 0 } } }); + prover_opening_claims.emplace_back(Claim{ zero_polynomial, { -gemini_r, Fr{ 0 } } }); + prover_opening_claims.emplace_back(Claim{ fold_1, { -r_squares[1], fold_evals[1] } }); + prover_opening_claims.emplace_back(Claim{ fold_1, { r_squares[1], fold_1.evaluate(r_squares[1]) } }); + prover_opening_claims.emplace_back(Claim{ fold_2, { -r_squares[2], fold_evals[2] } }); + prover_opening_claims.emplace_back(Claim{ fold_2, { r_squares[2], fold_2.evaluate(r_squares[2]) } }); + + // Check that the Fold polynomials have been evaluated correctly in the prover + this->verify_batch_opening_pair(prover_opening_claims); - // Check that fold₀(r) = 0. Therefore, a malicious prover could open it using the commitment to the zero - // polynomial. - EXPECT_TRUE(full_a_0_pos == Fr(0)); + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); + + std::vector unshifted_commitments = { this->ck->commit(zero_polynomial) }; + std::vector unshifted_evals = { claimed_multilinear_eval * rho.pow(0) }; + + std::vector shifted_commitments = {}; + std::vector shifted_evals = {}; + + ClaimBatcher claim_batcher{ .unshifted = ClaimBatch{ RefVector(unshifted_commitments), RefVector(unshifted_evals) }, + .shifted = ClaimBatch{ RefVector(shifted_commitments), RefVector(shifted_evals) } }; + + auto verifier_claims = GeminiVerifier_::reduce_verification(u, claim_batcher, verifier_transcript); + std::vector matching_claim_indices{ 0, 1, 2, 4, 5 }; + std::vector mismatching_claim_indices = { 3 }; + for (auto idx : matching_claim_indices) { + EXPECT_TRUE(prover_opening_claims[idx].opening_pair == verifier_claims[idx].opening_pair); + } + + for (auto idx : mismatching_claim_indices) { + EXPECT_FALSE(prover_opening_claims[idx].opening_pair == verifier_claims[idx].opening_pair); + } } template std::shared_ptr::CK> GeminiTest::ck = nullptr; From 12eca3f1e3c0cb47650b855ee4033f66602c3a19 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 11 Mar 2025 19:09:27 +0000 Subject: [PATCH 05/24] recursion fixed --- .../commitment_schemes/gemini/gemini.hpp | 41 ++++++++++++------- .../commitment_schemes/shplonk/shplonk.hpp | 2 +- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index c0261fc33646..e83d10947bad 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -521,7 +521,7 @@ template class GeminiVerifier_ { */ static std::vector compute_fold_pos_evaluations( const size_t num_variables, - Fr& batched_eval_accumulator, + const Fr& batched_evaluation, std::span evaluation_point, // CONST_PROOF_SIZE std::span challenge_powers, // r_squares CONST_PROOF_SIZE_LOG_N std::span fold_polynomial_evals, @@ -529,8 +529,17 @@ template class GeminiVerifier_ { { std::vector evals(fold_polynomial_evals.begin(), fold_polynomial_evals.end()); + Fr eval_pos_prev = batched_evaluation; + + Fr zero{ 0 }; + if constexpr (Curve::is_stdlib_type) { + zero.convert_constant_to_fixed_witness(fold_polynomial_evals[0].get_context()); + } + std::vector gemini_fold_pos_evaluations; - gemini_fold_pos_evaluations.reserve(CONST_PROOF_SIZE_LOG_N - 1); //? + gemini_fold_pos_evaluations.reserve(CONST_PROOF_SIZE_LOG_N); + // Either a computed eval of A_i at r^{2^i}, or 0 + Fr value_to_emplace; // Add the contribution of P-((-r)ˢ) to get A_0(-r), which is 0 if there are no interleaved polynomials evals[0] += p_neg; @@ -544,26 +553,30 @@ template class GeminiVerifier_ { const Fr& eval_neg = evals[l - 1]; // Get A₍ₗ₋₁₎(−r²⁽ˡ⁻¹⁾) // Compute the numerator - Fr batched_eval_round_acc = - ((challenge_power * batched_eval_accumulator * 2) - eval_neg * (challenge_power * (Fr(1) - u) - u)); + Fr eval_pos = ((challenge_power * eval_pos_prev * 2) - eval_neg * (challenge_power * (Fr(1) - u) - u)); // Divide by the denominator - batched_eval_round_acc *= (challenge_power * (Fr(1) - u) + u).invert(); + eval_pos *= (challenge_power * (Fr(1) - u) + u).invert(); + if constexpr (Curve::is_stdlib_type) { auto builder = evaluation_point[0].get_context(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure dummy_round derivation! stdlib::bool_t dummy_round = stdlib::witness_t(builder, l > num_variables); - batched_eval_accumulator = - Fr::conditional_assign(dummy_round, batched_eval_accumulator, batched_eval_round_acc); + // If current index is bigger than log_circuit_size, we propagate `batched_evaluation` to the next + // round. Otherwise, current `eval_pos` A₍ₗ₋₁₎(−r²⁽ˡ⁻¹⁾) becomes `eval_pos_prev` in the round l-2. + eval_pos_prev = Fr::conditional_assign(dummy_round, eval_pos_prev, eval_pos); + // If current index is bigger than log_circuit_size, we emplace 0, which is later multiplied against + // Commitment::one(). + value_to_emplace = Fr::conditional_assign(dummy_round, zero, eval_pos_prev); } else { - if (l <= num_variables) { - batched_eval_accumulator = batched_eval_round_acc; - gemini_fold_pos_evaluations.emplace_back(batched_eval_accumulator); - } else { - gemini_fold_pos_evaluations.emplace_back(Fr(0)); - } - } + // Perform the same logic as above natively + bool dummy_round = l > num_variables; + eval_pos_prev = dummy_round ? eval_pos_prev : eval_pos; + value_to_emplace = dummy_round ? zero : eval_pos_prev; + }; + gemini_fold_pos_evaluations.emplace_back(value_to_emplace); } + std::reverse(gemini_fold_pos_evaluations.begin(), gemini_fold_pos_evaluations.end()); return gemini_fold_pos_evaluations; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index 1915fc14c35b..d1d0179a509d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -425,7 +425,7 @@ template class ShplonkVerifier_ { denominators.emplace_back(shplonk_eval_challenge - gemini_eval_challenge_power); } - if constexpr (Curve::is_stdlib_type) { + if constexpr (!Curve::is_stdlib_type) { Fr::batch_invert(denominators); } else { for (auto& denominator : denominators) { From 07a605f578dc7b16c1d5646e27a0fc794a81fc56 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 12 Mar 2025 10:35:46 +0000 Subject: [PATCH 06/24] more consistency --- .../commitment_schemes/claim_batcher.hpp | 8 +-- .../commitment_schemes/gemini/gemini.hpp | 6 +- .../commitment_schemes/gemini/gemini.test.cpp | 39 ++++++----- .../commitment_schemes/shplonk/shplemini.hpp | 41 +++--------- .../shplonk/shplemini.test.cpp | 8 ++- .../commitment_schemes/shplonk/shplonk.hpp | 66 +++++++++++++------ 6 files changed, 89 insertions(+), 79 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp index 5f7e365fd06b..b717807c3d93 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp @@ -71,13 +71,13 @@ template struct ClaimBatcher_ { * \right) * \f] * - * @param inverse_vanishing_eval_pos 1/(z+r) - * @param inverse_vanishing_eval_neg 1/(z-r) + * @param inverse_vanishing_eval_pos 1/(z-r) + * @param inverse_vanishing_eval_neg 1/(z+r) * @param nu_challenge ν (shplonk batching challenge) * @param r_challenge r (gemini evaluation challenge) */ - void compute_scalars_for_each_batch(const Fr& inverse_vanishing_eval_neg, - const Fr& inverse_vanishing_eval_pos, + void compute_scalars_for_each_batch(const Fr& inverse_vanishing_eval_pos, + const Fr& inverse_vanishing_eval_neg, const Fr& nu_challenge, const Fr& r_challenge, const Fr& interleaving_vanishing_eval = { 0 }) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index e83d10947bad..87eeb7191b77 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -456,12 +456,12 @@ template class GeminiVerifier_ { // ( [A₀₋], -r, A₀-(-r) ) fold_polynomial_opening_claims.emplace_back(OpeningClaim{ { -r, evaluations[0] }, C0_r_neg }); for (size_t l = 0; l < num_variables - 1; ++l) { - // ([A₀₋], −r^{2ˡ}, Aₗ(−r^{2ˡ}) ) - fold_polynomial_opening_claims.emplace_back( - OpeningClaim{ { -r_squares[l + 1], evaluations[l + 1] }, commitments[l] }); fold_polynomial_opening_claims.emplace_back( OpeningClaim{ { r_squares[l + 1], gemini_fold_pos_evaluations[l + 1] }, commitments[l] }); + // ([A₀₋], −r^{2ˡ}, Aₗ(−r^{2ˡ}) ) + fold_polynomial_opening_claims.emplace_back( + OpeningClaim{ { -r_squares[l + 1], evaluations[l + 1] }, commitments[l] }); } if (has_interleaved) { size_t interleaved_group_size = claim_batcher.get_groups_to_be_interleaved_size(); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp index 2fa7bb036816..2db5858aab35 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp @@ -45,7 +45,6 @@ template class GeminiTest : public CommitmentTest { prover_claims_with_pos_evals.reserve(2 * log_n); for (auto& claim : prover_output) { - prover_claims_with_pos_evals.emplace_back(claim); if (claim.gemini_fold) { if (claim.gemini_fold) { // "positive" evaluation challenge r^{2^i} for i = 0, ..., d-1 @@ -59,6 +58,7 @@ template class GeminiTest : public CommitmentTest { prover_claims_with_pos_evals.emplace_back(pos_fold_claim); } } + prover_claims_with_pos_evals.emplace_back(claim); } // Check that the Fold polynomials have been evaluated correctly in the prover @@ -160,7 +160,10 @@ TYPED_TEST(GeminiTest, SoundnessRegression) std::vector> fold_polynomials; fold_polynomials.reserve(log_n); - bb::Polynomial zero_polynomial(n); + Polynomial fold_0(n); + Polynomial fold_1(n / 2); + Polynomial fold_2(n / 4); + auto u = this->random_evaluation_point(this->log_n); // Generate a random evaluation v, the prover claims that `zero_polynomial`(u) = v @@ -169,8 +172,6 @@ TYPED_TEST(GeminiTest, SoundnessRegression) // Go through the Gemini Prover steps: compute fold polynomials and their evaluations std::vector fold_evals; fold_evals.reserve(log_n); - Polynomial fold_2(2); - Polynomial fold_1(4); // By defining the coefficients of fold polynomials as below, a malicious prover can make sure that the values // fold₁(r²) = 0, and hence fold₀(r), computed by the verifier, are 0. At the same time, the prover can open @@ -199,7 +200,7 @@ TYPED_TEST(GeminiTest, SoundnessRegression) const Fr gemini_r = prover_transcript->template get_challenge("Gemini:r"); // Place honest eval of fold₀(-r) to the vector of evals - fold_evals.emplace_back(zero_polynomial.evaluate(-gemini_r)); + fold_evals.emplace_back(fold_0.evaluate(-gemini_r)); // Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, 2 std::vector r_squares = gemini::powers_of_evaluation_challenge(gemini_r, log_n); @@ -221,34 +222,38 @@ TYPED_TEST(GeminiTest, SoundnessRegression) std::vector prover_opening_claims; prover_opening_claims.reserve(2 * log_n); - prover_opening_claims.emplace_back(Claim{ zero_polynomial, { gemini_r, Fr{ 0 } } }); - prover_opening_claims.emplace_back(Claim{ zero_polynomial, { -gemini_r, Fr{ 0 } } }); - prover_opening_claims.emplace_back(Claim{ fold_1, { -r_squares[1], fold_evals[1] } }); + prover_opening_claims.emplace_back(Claim{ fold_0, { gemini_r, Fr{ 0 } } }); + prover_opening_claims.emplace_back(Claim{ fold_0, { -gemini_r, Fr{ 0 } } }); prover_opening_claims.emplace_back(Claim{ fold_1, { r_squares[1], fold_1.evaluate(r_squares[1]) } }); - prover_opening_claims.emplace_back(Claim{ fold_2, { -r_squares[2], fold_evals[2] } }); + prover_opening_claims.emplace_back(Claim{ fold_1, { -r_squares[1], fold_evals[1] } }); prover_opening_claims.emplace_back(Claim{ fold_2, { r_squares[2], fold_2.evaluate(r_squares[2]) } }); + prover_opening_claims.emplace_back(Claim{ fold_2, { -r_squares[2], fold_evals[2] } }); // Check that the Fold polynomials have been evaluated correctly in the prover this->verify_batch_opening_pair(prover_opening_claims); auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); - std::vector unshifted_commitments = { this->ck->commit(zero_polynomial) }; + std::vector unshifted_commitments = { this->ck->commit(fold_0) }; std::vector unshifted_evals = { claimed_multilinear_eval * rho.pow(0) }; - std::vector shifted_commitments = {}; - std::vector shifted_evals = {}; - - ClaimBatcher claim_batcher{ .unshifted = ClaimBatch{ RefVector(unshifted_commitments), RefVector(unshifted_evals) }, - .shifted = ClaimBatch{ RefVector(shifted_commitments), RefVector(shifted_evals) } }; + ClaimBatcher claim_batcher{ .unshifted = + ClaimBatch{ RefVector(unshifted_commitments), RefVector(unshifted_evals) } }; auto verifier_claims = GeminiVerifier_::reduce_verification(u, claim_batcher, verifier_transcript); - std::vector matching_claim_indices{ 0, 1, 2, 4, 5 }; - std::vector mismatching_claim_indices = { 3 }; + + // Malicious prover could honestly prove all "negative" evaluations and several "positive evaluations". In + // particular, the evaluation of `fold_0` at r. + std::vector matching_claim_indices{ 0, 1, 3, 4, 5 }; + // However, the evaluation of `fold_1` at r^2 that the verifier computes assuming that fold has been performed + // correctly, does not match the actual evaluation of tampered fold_1 that the prover can open. + std::vector mismatching_claim_indices = { 2 }; for (auto idx : matching_claim_indices) { EXPECT_TRUE(prover_opening_claims[idx].opening_pair == verifier_claims[idx].opening_pair); } + // The mismatch in claims below leads to Gemini and Shplemini Verifier rejecting the tampered proof and confirms the + // necessity of opening `fold_i` at r^{2^i} for i = 1, ..., log_n - 1. for (auto idx : mismatching_claim_indices) { EXPECT_FALSE(prover_opening_claims[idx].opening_pair == verifier_claims[idx].opening_pair); } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 1d7a277f1600..190448b6e853 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -84,7 +84,7 @@ template class ShpleminiProver_ { const std::array evaluation_points = { gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r }; - for (size_t idx = 0; idx < 4; idx++) { + for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; 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]); @@ -287,10 +287,10 @@ template class ShpleminiVerifier_ { scalars.emplace_back(Fr(1)); } - // Compute 1/(z − r), 1/(z + r), 1/(z + r²), … , 1/(z + r²⁽ⁿ⁻¹⁾) + // Compute 1/(z − r), 1/(z + r), 1/(z - r²), 1/(z + r²), … , 1/(z - r²⁽ⁿ⁻¹⁾), 1/(z + r²⁽ⁿ⁻¹⁾) // These represent the denominators of the summand terms in Shplonk partially evaluated polynomial Q_z const std::vector inverse_vanishing_evals = ShplonkVerifier::compute_inverted_gemini_denominators( - log_circuit_size + 1, shplonk_evaluation_challenge, gemini_eval_challenge_powers); + log_circuit_size, shplonk_evaluation_challenge, gemini_eval_challenge_powers); // Compute the Shplonk denominator for the interleaved opening claims 1/(z − r^s) where s is the group size const Fr interleaving_vanishing_eval = (shplonk_evaluation_challenge - @@ -299,8 +299,8 @@ template class ShpleminiVerifier_ { // Compute the additional factors to be multiplied with unshifted and shifted commitments when lazily // reconstructing the commitment of Q_z - claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[0], // 1/(z + r) - inverse_vanishing_evals[1], // 1/(z - r) + claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[0], // 1/(z - r) + inverse_vanishing_evals[1], // 1/(z + r) shplonk_batching_challenge, gemini_evaluation_challenge, interleaving_vanishing_eval); @@ -365,10 +365,10 @@ template class ShpleminiVerifier_ { Fr a_0_pos = full_a_0_pos - p_pos; // Add contributions from A₀₊(r) and A₀₋(-r) to constant_term_accumulator: // Add A₀₊(r)/(z−r) to the constant term accumulator - constant_term_accumulator += a_0_pos * inverse_vanishing_evals[1]; + constant_term_accumulator += a_0_pos * inverse_vanishing_evals[0]; // Add A₀₋(-r)/(z+r) to the constant term accumulator constant_term_accumulator += - gemini_fold_neg_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[0]; + gemini_fold_neg_evaluations[0] * shplonk_batching_challenge * inverse_vanishing_evals[1]; remove_repeated_commitments(commitments, scalars, repeated_commitments, has_zk); @@ -458,9 +458,9 @@ template class ShpleminiVerifier_ { for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N - 1; ++j) { // Compute the scaling factor (ν²⁺ⁱ) / (z + r²⁽ⁱ⁺²⁾) for i = 0, … , d-2 size_t pos_location = 2 * j + 2; - Fr scaling_factor_neg = - shplonk_batching_challenge_powers[pos_location] * inverse_vanishing_evals[pos_location]; Fr scaling_factor_pos = + shplonk_batching_challenge_powers[pos_location] * inverse_vanishing_evals[pos_location]; + Fr scaling_factor_neg = shplonk_batching_challenge_powers[pos_location + 1] * inverse_vanishing_evals[pos_location + 1]; // Add Aᵢ(−r²ⁱ) for i = 1, … , n-1 to the constant term accumulator @@ -742,28 +742,5 @@ template class ShpleminiVerifier_ { round_idx++; } }; - - static std::vector compute_shplonk_batching_challenge_powers(const Fr& shplonk_batching_challenge, - bool has_zk = false, - bool committed_sumcheck = false) - { - size_t num_powers = NUM_GEMINI_FOLD_CLAIMS + 2; - - if (has_zk) { - num_powers += NUM_SMALL_IPA_EVALUATIONS; - } - - if (committed_sumcheck) { - num_powers += CONST_PROOF_SIZE_LOG_N; - } - - std::vector result; - result.reserve(num_powers); - result.emplace_back(Fr{ 1 }); - for (size_t idx = 1; idx < num_powers; idx++) { - result.emplace_back(result[idx - 1] * shplonk_batching_challenge); - } - return result; - } }; } // namespace bb 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 4d0da2d2e19e..9d3f29e3f932 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -163,7 +163,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching) Fr inverted_vanishing_eval_neg = (shplonk_eval_challenge + gemini_eval_challenge).invert(); mock_claims.claim_batcher.compute_scalars_for_each_batch( - inverted_vanishing_eval_neg, inverted_vanishing_eval_pos, shplonk_batching_challenge, gemini_eval_challenge); + inverted_vanishing_eval_pos, inverted_vanishing_eval_neg, shplonk_batching_challenge, gemini_eval_challenge); rho_power = Fr{ 1 }; mock_claims.claim_batcher.update_batch_mul_inputs_and_batched_evaluation( @@ -196,8 +196,10 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) Fr rho = Fr::random_element(); Fr gemini_eval_challenge = Fr::random_element(); Fr shplonk_batching_challenge = Fr::random_element(); + std::vector shplonk_batching_challenge_powers = - ShpleminiVerifier::compute_shplonk_batching_challenge_powers(shplonk_batching_challenge); + compute_shplonk_batching_challenge_powers(shplonk_batching_challenge); + Fr shplonk_eval_challenge = Fr::random_element(); std::vector mle_opening_point = this->random_evaluation_point(this->log_n); @@ -245,8 +247,8 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) expected_inverse_vanishing_evals.reserve(2 * this->log_n); // Compute expected inverses for (size_t idx = 0; idx < this->log_n; idx++) { - expected_inverse_vanishing_evals.emplace_back((shplonk_eval_challenge + r_squares[idx]).invert()); expected_inverse_vanishing_evals.emplace_back((shplonk_eval_challenge - r_squares[idx]).invert()); + expected_inverse_vanishing_evals.emplace_back((shplonk_eval_challenge + r_squares[idx]).invert()); } Fr current_challenge{ shplonk_batching_challenge * shplonk_batching_challenge }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index d1d0179a509d..a7486fbfe87c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -65,13 +65,6 @@ template class ShplonkProver_ { size_t fold_idx = 0; for (const auto& claim : opening_claims) { - // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) - tmp = claim.polynomial; - tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; - 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; // Gemini Fold Polynomials have to be opened at -r^{2^j} and r^{2^j}. if (claim.gemini_fold) { @@ -83,6 +76,14 @@ template class ShplonkProver_ { current_nu *= nu; fold_idx++; } + + // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) + tmp = claim.polynomial; + tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; + 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; } // We use the same batching challenge for Gemini and Libra opening claims. The number of the claims @@ -140,10 +141,10 @@ template class ShplonkProver_ { std::vector inverse_vanishing_evals; inverse_vanishing_evals.reserve(num_opening_claims); for (const auto& claim : opening_claims) { - inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge); if (claim.gemini_fold) { inverse_vanishing_evals.emplace_back(z_challenge + claim.opening_pair.challenge); } + inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge); } // Add the terms (z - uₖ) for k = 0, …, d−1 where d is the number of rounds in Sumcheck @@ -168,15 +169,6 @@ template class ShplonkProver_ { size_t fold_idx = 0; for (const auto& claim : opening_claims) { - // tmp = νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) - tmp = claim.polynomial; - tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; - Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) - - // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) - G.add_scaled(tmp, -scaling_factor); - - current_nu *= nu_challenge; if (claim.gemini_fold) { tmp = claim.polynomial; @@ -188,6 +180,15 @@ template class ShplonkProver_ { current_nu *= nu_challenge; fold_idx++; } + // tmp = νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) + tmp = claim.polynomial; + tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) + + // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) + G.add_scaled(tmp, -scaling_factor); + + current_nu *= nu_challenge; } // Take into account the constant proof size in Gemini @@ -223,7 +224,7 @@ template class ShplonkProver_ { std::vector gemini_fold_pos_evaluations; gemini_fold_pos_evaluations.reserve(opening_claims.size()); - for (const auto claim : opening_claims) { + for (const auto& claim : opening_claims) { if (claim.gemini_fold) { const Fr evaluation_point = -claim.opening_pair.challenge; const Fr evaluation = claim.polynomial.evaluate(evaluation_point); @@ -419,10 +420,10 @@ template class ShplonkVerifier_ { denominators.reserve(2 * num_gemini_claims); for (const auto& gemini_eval_challenge_power : gemini_eval_challenge_powers) { - // Place 1/(z + r ^ {2^j}) - denominators.emplace_back(shplonk_eval_challenge + gemini_eval_challenge_power); // Place 1/(z - r ^ {2^j}) denominators.emplace_back(shplonk_eval_challenge - gemini_eval_challenge_power); + // Place 1/(z + r ^ {2^j}) + denominators.emplace_back(shplonk_eval_challenge + gemini_eval_challenge_power); } if constexpr (!Curve::is_stdlib_type) { @@ -435,4 +436,29 @@ template class ShplonkVerifier_ { return denominators; } }; + +template +static std::vector compute_shplonk_batching_challenge_powers(const Fr& shplonk_batching_challenge, + bool has_zk = false, + bool committed_sumcheck = false) +{ + static constexpr size_t NUM_INTERLEAVED_CLAIMS = 2; + size_t num_powers = 2 * CONST_PROOF_SIZE_LOG_N + NUM_INTERLEAVED_CLAIMS; + + if (has_zk) { + num_powers += NUM_SMALL_IPA_EVALUATIONS; + } + + if (committed_sumcheck) { + num_powers += CONST_PROOF_SIZE_LOG_N; + } + + std::vector result; + result.reserve(num_powers); + result.emplace_back(Fr{ 1 }); + for (size_t idx = 1; idx < num_powers; idx++) { + result.emplace_back(result[idx - 1] * shplonk_batching_challenge); + } + return result; +} } // namespace bb From 32b3ddaa780b27af051c14969725d828528a0c0d Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 12 Mar 2025 11:49:35 +0000 Subject: [PATCH 07/24] cleanup --- .../commitment_schemes/gemini/gemini.hpp | 4 ++-- .../commitment_schemes/gemini/gemini.test.cpp | 4 ++-- .../commitment_schemes/gemini/gemini_impl.hpp | 2 ++ .../commitment_schemes/shplonk/shplemini.hpp | 12 +++++++----- .../commitment_schemes/shplonk/shplemini.test.cpp | 2 +- .../commitment_schemes/shplonk/shplonk.hpp | 14 +++++--------- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index 87eeb7191b77..053853183950 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -456,10 +456,10 @@ template class GeminiVerifier_ { // ( [A₀₋], -r, A₀-(-r) ) fold_polynomial_opening_claims.emplace_back(OpeningClaim{ { -r, evaluations[0] }, C0_r_neg }); for (size_t l = 0; l < num_variables - 1; ++l) { - + // ([Aₗ], r^{2ˡ}, Aₗ(r^{2ˡ}) ) fold_polynomial_opening_claims.emplace_back( OpeningClaim{ { r_squares[l + 1], gemini_fold_pos_evaluations[l + 1] }, commitments[l] }); - // ([A₀₋], −r^{2ˡ}, Aₗ(−r^{2ˡ}) ) + // ([Aₗ], −r^{2ˡ}, Aₗ(−r^{2ˡ}) ) fold_polynomial_opening_claims.emplace_back( OpeningClaim{ { -r_squares[l + 1], evaluations[l + 1] }, commitments[l] }); } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp index 2db5858aab35..00767d145a88 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp @@ -12,7 +12,7 @@ template class GeminiTest : public CommitmentTest { using Commitment = typename Curve::AffineElement; public: - static constexpr size_t log_n = 3; + static constexpr size_t log_n = 4; static constexpr size_t n = 1UL << log_n; using CK = CommitmentKey; @@ -164,7 +164,7 @@ TYPED_TEST(GeminiTest, SoundnessRegression) Polynomial fold_1(n / 2); Polynomial fold_2(n / 4); - auto u = this->random_evaluation_point(this->log_n); + auto u = this->random_evaluation_point(log_n); // Generate a random evaluation v, the prover claims that `zero_polynomial`(u) = v Fr claimed_multilinear_eval = Fr::random_element(); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp index 0836dd9310b2..dc1a9aaf7ce3 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp @@ -232,6 +232,8 @@ std::vector::Claim> GeminiProver_::construc // Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, ..., m-1 std::vector r_squares = gemini::powers_of_evaluation_challenge(r_challenge, log_n); + // Each fold polynomial Aₗ has to be opened at −r^{2ˡ} and r^{2ˡ}. To avoid storing two copies of Aₗ for l = 0,..., + // m-1, we use a flag that is processed by ShplonkProver.. const bool gemini_fold = true; // Compute the remaining m opening pairs {−r^{2ˡ}, Aₗ(−r^{2ˡ})}, l = 1, ..., m-1. diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 190448b6e853..067d8d6080f2 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -208,6 +208,8 @@ template class ShpleminiVerifier_ { const std::vector>& sumcheck_round_evaluations = {}) { + const bool committed_sumcheck = !sumcheck_round_evaluations.empty(); + // Extract log_circuit_size size_t log_circuit_size{ 0 }; if constexpr (Curve::is_stdlib_type) { @@ -263,8 +265,8 @@ template class ShpleminiVerifier_ { // - Get Shplonk batching challenge const Fr shplonk_batching_challenge = transcript->template get_challenge("Shplonk:nu"); - const std::vector shplonk_batching_challenge_powers = compute_shplonk_batching_challenge_powers( - shplonk_batching_challenge, has_zk, !sumcheck_round_evaluations.empty()); + const std::vector shplonk_batching_challenge_powers = + compute_shplonk_batching_challenge_powers(shplonk_batching_challenge, has_zk, committed_sumcheck); // - Get the quotient commitment for the Shplonk batching of Gemini opening claims const auto Q_commitment = transcript->template receive_from_prover("Shplonk:Q"); @@ -290,7 +292,7 @@ template class ShpleminiVerifier_ { // Compute 1/(z − r), 1/(z + r), 1/(z - r²), 1/(z + r²), … , 1/(z - r²⁽ⁿ⁻¹⁾), 1/(z + r²⁽ⁿ⁻¹⁾) // These represent the denominators of the summand terms in Shplonk partially evaluated polynomial Q_z const std::vector inverse_vanishing_evals = ShplonkVerifier::compute_inverted_gemini_denominators( - log_circuit_size, shplonk_evaluation_challenge, gemini_eval_challenge_powers); + shplonk_evaluation_challenge, gemini_eval_challenge_powers); // Compute the Shplonk denominator for the interleaved opening claims 1/(z − r^s) where s is the group size const Fr interleaving_vanishing_eval = (shplonk_evaluation_challenge - @@ -299,7 +301,7 @@ template class ShpleminiVerifier_ { // Compute the additional factors to be multiplied with unshifted and shifted commitments when lazily // reconstructing the commitment of Q_z - claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[0], // 1/(z - r) + claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[0], // 1/(z − r) inverse_vanishing_evals[1], // 1/(z + r) shplonk_batching_challenge, gemini_evaluation_challenge, @@ -389,7 +391,7 @@ template class ShpleminiVerifier_ { } // Currently, only used in ECCVM - if (!sumcheck_round_evaluations.empty()) { + if (committed_sumcheck) { batch_sumcheck_round_claims(log_circuit_size, commitments, scalars, 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 9d3f29e3f932..9c651bb5a1c8 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -261,7 +261,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) // Run the ShepliminiVerifier batching method std::vector inverse_vanishing_evals = - ShplonkVerifier::compute_inverted_gemini_denominators(this->log_n + 1, shplonk_eval_challenge, r_squares); + ShplonkVerifier::compute_inverted_gemini_denominators(shplonk_eval_challenge, r_squares); Fr expected_constant_term_accumulator{ 0 }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index a7486fbfe87c..106bc75e1dd6 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -69,12 +69,11 @@ template class ShplonkProver_ { // Gemini Fold Polynomials have to be opened at -r^{2^j} and r^{2^j}. if (claim.gemini_fold) { tmp = claim.polynomial; - tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx]; + tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx++]; 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; - fold_idx++; } // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) @@ -172,13 +171,12 @@ template class ShplonkProver_ { if (claim.gemini_fold) { tmp = claim.polynomial; - tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx]; + tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx++]; Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) G.add_scaled(tmp, -scaling_factor); current_nu *= nu_challenge; - fold_idx++; } // tmp = νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) tmp = claim.polynomial; @@ -412,12 +410,11 @@ template class ShplonkVerifier_ { * @return \f[ \left( \frac{1}{z + r}, \frac{1}{z-r}, \ldots, \frac{1}{z+r^{2^{d-1}}}, \frac{1}{z-r^{2^{d-1}}} * \right) \f] */ - static std::vector compute_inverted_gemini_denominators(const size_t num_gemini_claims, - const Fr& shplonk_eval_challenge, + static std::vector compute_inverted_gemini_denominators(const Fr& shplonk_eval_challenge, const std::vector& gemini_eval_challenge_powers) { std::vector denominators; - denominators.reserve(2 * num_gemini_claims); + denominators.reserve(2 * CONST_PROOF_SIZE_LOG_N + 2); for (const auto& gemini_eval_challenge_power : gemini_eval_challenge_powers) { // Place 1/(z - r ^ {2^j}) @@ -442,8 +439,7 @@ static std::vector compute_shplonk_batching_challenge_powers(const Fr& shplo bool has_zk = false, bool committed_sumcheck = false) { - static constexpr size_t NUM_INTERLEAVED_CLAIMS = 2; - size_t num_powers = 2 * CONST_PROOF_SIZE_LOG_N + NUM_INTERLEAVED_CLAIMS; + size_t num_powers = 2 * CONST_PROOF_SIZE_LOG_N + 2; if (has_zk) { num_powers += NUM_SMALL_IPA_EVALUATIONS; From 510531900c3723e0dc0f352445be2ff05b549eed Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 12 Mar 2025 12:30:11 +0000 Subject: [PATCH 08/24] fix client ivc --- .../commitment_schemes/gemini/gemini.test.cpp | 11 +++++++---- .../commitment_schemes/shplonk/shplemini.hpp | 6 ++---- .../commitment_schemes/shplonk/shplonk.hpp | 10 +++++----- barretenberg/cpp/src/barretenberg/constants.hpp | 2 ++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp index 00767d145a88..14cbd8bde55a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp @@ -42,14 +42,17 @@ template class GeminiTest : public CommitmentTest { // r^{2^i} for i=1, ..., d-1. Although here we are copying polynomials, it is not the case when GeminiProver is // combined with ShplonkProver. std::vector> prover_claims_with_pos_evals; - prover_claims_with_pos_evals.reserve(2 * log_n); + // `prover_output` consists of d+1 opening claims, we add another d-1 claims for each positive evaluation + // Fold^i(r^{2^i}) for i = 1, ..., d-1 + const size_t total_num_claims = 2 * log_n; + prover_claims_with_pos_evals.reserve(total_num_claims); for (auto& claim : prover_output) { if (claim.gemini_fold) { if (claim.gemini_fold) { - // "positive" evaluation challenge r^{2^i} for i = 0, ..., d-1 + // "positive" evaluation challenge r^{2^i} for i = 1, ..., d-1 const Fr evaluation_challenge = -claim.opening_pair.challenge; - // Fold^(i) at r^{2^i} for i=0, ..., d-1 + // Fold^(i) at r^{2^i} for i=1, ..., d-1 const Fr pos_evaluation = claim.polynomial.evaluate(evaluation_challenge); // Add the positive Fold claims to the vector of claims ProverOpeningClaim pos_fold_claim = { .polynomial = claim.polynomial, @@ -125,7 +128,7 @@ TYPED_TEST(GeminiTest, DoubleWithShift) this->execute_gemini_and_verify_claims(u, mock_claims); } -TYPED_TEST(GeminiTest, DoubleWithShiftAndConcatenation) +TYPED_TEST(GeminiTest, DoubleWithShiftAndInterleaving) { auto u = this->random_evaluation_point(this->log_n); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 067d8d6080f2..ba9a12781325 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -188,7 +188,6 @@ template class ShpleminiVerifier_ { using ShplonkVerifier = ShplonkVerifier_; using GeminiVerifier = GeminiVerifier_; using ClaimBatcher = ClaimBatcher_; - static constexpr size_t NUM_GEMINI_FOLD_CLAIMS = 2 * CONST_PROOF_SIZE_LOG_N; public: template @@ -612,9 +611,8 @@ template class ShpleminiVerifier_ { // compute the scalars to be multiplied against the commitments [libra_concatenated], [grand_sum], [grand_sum], // and [libra_quotient] - size_t power = NUM_GEMINI_FOLD_CLAIMS + 2; for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; idx++) { - Fr scaling_factor = denominators[idx] * shplonk_batching_challenge_powers[power++]; + Fr scaling_factor = denominators[idx] * shplonk_batching_challenge_powers[NUM_GEMINI_CLAIMS + idx]; batching_scalars[idx] = -scaling_factor; constant_term_accumulator += scaling_factor * libra_evaluations[idx]; } @@ -706,7 +704,7 @@ template class ShpleminiVerifier_ { // 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; - size_t power = NUM_GEMINI_FOLD_CLAIMS + 2 + NUM_SMALL_IPA_EVALUATIONS; + size_t power = NUM_GEMINI_CLAIMS + NUM_SMALL_IPA_EVALUATIONS; for (const auto& [eval_array, denominator] : zip_view(sumcheck_round_evaluations, denominators)) { // Initialize batched_scalar corresponding to 3 evaluations claims Fr batched_scalar = Fr(0); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index 106bc75e1dd6..25a2ab184a11 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_ { // We use the same batching challenge for Gemini and Libra opening claims. The number of the claims // batched before adding Libra commitments and evaluations is bounded by CONST_PROOF_SIZE_LOG_N+2 - current_nu = nu.pow(2 * CONST_PROOF_SIZE_LOG_N + 2); + current_nu = nu.pow(NUM_GEMINI_CLAIMS); for (const auto& claim : libra_opening_claims) { // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) @@ -190,7 +190,7 @@ template class ShplonkProver_ { } // Take into account the constant proof size in Gemini - current_nu = nu_challenge.pow(2 * CONST_PROOF_SIZE_LOG_N + 2); + current_nu = nu_challenge.pow(NUM_GEMINI_CLAIMS); for (const auto& claim : libra_opening_claims) { // Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ ) @@ -414,7 +414,7 @@ template class ShplonkVerifier_ { const std::vector& gemini_eval_challenge_powers) { std::vector denominators; - denominators.reserve(2 * CONST_PROOF_SIZE_LOG_N + 2); + denominators.reserve(NUM_GEMINI_CLAIMS); for (const auto& gemini_eval_challenge_power : gemini_eval_challenge_powers) { // Place 1/(z - r ^ {2^j}) @@ -439,14 +439,14 @@ static std::vector compute_shplonk_batching_challenge_powers(const Fr& shplo bool has_zk = false, bool committed_sumcheck = false) { - size_t num_powers = 2 * CONST_PROOF_SIZE_LOG_N + 2; + size_t num_powers = NUM_GEMINI_CLAIMS; if (has_zk) { num_powers += NUM_SMALL_IPA_EVALUATIONS; } if (committed_sumcheck) { - num_powers += CONST_PROOF_SIZE_LOG_N; + num_powers += 3 * CONST_PROOF_SIZE_LOG_N; } std::vector result; diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 698fa4df4e5b..58cdd895778a 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -31,4 +31,6 @@ static constexpr uint32_t MERGE_PROOF_SIZE = 65; // used to ensure mock proofs a // There are 5 distinguished wires in ECCVM that have to be opened as univariates to establish the connection between // ECCVM and Translator static constexpr uint32_t NUM_TRANSLATION_EVALUATIONS = 5; +// Upper bound on the number of claims produced GeminiProver. +static constexpr uint32_t NUM_GEMINI_CLAIMS = 2 * CONST_PROOF_SIZE_LOG_N + 2; } // namespace bb From 0acc32d836832486e41eb4beaedc90e305d64a4f Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 13 Mar 2025 10:51:06 +0000 Subject: [PATCH 09/24] docs + constants --- .../commitment_schemes/gemini/gemini.hpp | 57 ++++++++++--------- .../cpp/src/barretenberg/constants.hpp | 5 +- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index 053853183950..9318b4ac4713 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -38,15 +38,15 @@ * - A₀₊(X) = F(X) + G(X)/r * - A₀₋(X) = F(X) − G(X)/r * So that A₀₊(r) = A₀(r) and A₀₋(-r) = A₀(-r). - * The verifier is able to computed the simulated commitments to A₀₊(X) and A₀₋(X) + * The verifier is able to compute the simulated commitments to A₀₊(X) and A₀₋(X) * since they are linear-combinations of the commitments [fⱼ] and [gⱼ]. */ namespace bb { /** * @brief Prover output (evalutation pair, witness) that can be passed on to Shplonk batch opening. - * @details Evaluation pairs {r, A₀₊(r)}, {-r, A₀₋(-r)}, {-r^{2^j}, Aⱼ(-r^{2^j)}, j = [1, ..., m-1] - * and witness (Fold) polynomials + * @details Evaluation pairs {r, A₀₊(r)}, {-r, A₀₋(-r)}, {r^{2^j}, Aⱼ(r^{2^j)}, {-r^{2^j}, Aⱼ(-r^{2^j)}, j = [1, ..., + * m-1] and witness (Fold) polynomials * [ * A₀₊(X) = F(X) + r⁻¹⋅G(X) * A₀₋(X) = F(X) - r⁻¹⋅G(X) @@ -443,10 +443,10 @@ template class GeminiVerifier_ { p_neg = transcript->template receive_from_prover("Gemini:P_0_neg"); } - // Compute the full of evaluation A₀(r) = A₀₊(r) + P₊(r^s) + // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1 std::vector gemini_fold_pos_evaluations = compute_fold_pos_evaluations( num_variables, batched_evaluation, multilinear_challenge, r_squares, evaluations, p_neg); - + // Extract the evaluation A₀(r) = A₀₊(r) + P₊(r^s) auto full_a_0_pos = gemini_fold_pos_evaluations[0]; std::vector> fold_polynomial_opening_claims; fold_polynomial_opening_claims.reserve(2 * num_variables + 2); @@ -498,25 +498,26 @@ template class GeminiVerifier_ { } /** - * @brief Compute the expected evaluation of the univariate commitment to the batched polynomial. + * @brief Compute \f$ A_0(r), A_1(r^2), \ldots, A_{d-1}(r^{2^{d-1}})\f$ * - * Compute the evaluation \f$ A_0(r) = \sum \rho^i \cdot f_i + \frac{1}{r} \cdot \sum \rho^{i+k} g_i \f$, where \f$ + * Recall that \f$ A_0(r) = \sum \rho^i \cdot f_i + \frac{1}{r} \cdot \sum \rho^{i+k} g_i \f$, where \f$ * k \f$ is the number of "unshifted" commitments. * - * @details Initialize \f$ A_{d}(r) \f$ with the batched evaluation \f$ \sum \rho^i f_i(\vec{u}) + \sum \rho^{i+k} - * g_i(\vec{u}) \f$. The folding property ensures that - * \f{align}{ - * A_\ell\left(r^{2^\ell}\right) = (1 - u_{\ell-1}) \cdot \frac{A_{\ell-1}\left(r^{2^{\ell-1}}\right) + - * A_{\ell-1}\left(-r^{2^{\ell-1}}\right)}{2} - * + u_{\ell-1} \cdot \frac{A_{\ell-1}\left(r^{2^{\ell-1}}\right) - - * A_{\ell-1}\left(-r^{2^{\ell-1}}\right)}{2r^{2^{\ell-1}}} - * \f} - * Therefore, the verifier can recover \f$ A_0(r) \f$ by solving several linear equations. + * @details Initialize `a_pos` = \f$ A_{d}(r) \f$ with the batched evaluation \f$ \sum \rho^i f_i(\vec{u}) + \sum + * \rho^{i+k} g_i(\vec{u}) \f$. The verifier recovers \f$ A_{l-1}(r^{2^{l-1}}) \f$ from the "negative" value \f$ + * A_{l-1}\left(-r^{2^{l-1}}\right) \f$ received from the prover and the value \f$ A_{l}\left(r^{2^{l}}\right) \f$ + * computed at the previous step. Namely, the verifier computes + * \f{align}{ A_{l-1}\left(r^{2^{l-1}}\right) = + * \frac{2 \cdot r^{2^{l-1}} \cdot A_{l}\left(r^{2^l}\right) - A_{l-1}\left( -r^{2^{l-1}} \right)\cdot + * \left(r^{2^{l-1}} (1-u_{l-1}) - u_{l-1}\right)} {r^{2^{l-1}} (1- u_{l-1}) + u_{l-1}}. \f} + * + * In the case of interleaving, the first "negative" evaluation has to be corrected by the contribution from \f$ + * P_{-}(-r^s)\f$, where \f$ s \f$ is the size of the group to be interleaved. * - * @param batched_mle_eval The evaluation of the batched polynomial at \f$ (u_0, \ldots, u_{d-1})\f$. - * @param evaluation_point Evaluation point \f$ (u_0, \ldots, u_{d-1}) \f$. - * @param challenge_powers Powers of \f$ r \f$, \f$ r^2 \), ..., \( r^{2^{m-1}} \f$. - * @param fold_polynomial_evals Evaluations \f$ A_{i-1}(-r^{2^{i-1}}) \f$. + * @param batched_evaluation The evaluation of the batched polynomial at \f$ (u_0, \ldots, u_{d-1})\f$. + * @param evaluation_point Evaluation point \f$ (u_0, \ldots, u_{d-1}) \f$ padded to CONST_PROOF_SIZE_LOG_N. + * @param challenge_powers Powers of \f$ r \f$, \f$ r^2 \), ..., \( r^{2^{d-1}} \f$. + * @param fold_neg_evals Evaluations \f$ A_{i-1}(-r^{2^{i-1}}) \f$. * @return Evaluation \f$ A_0(r) \f$. */ static std::vector compute_fold_pos_evaluations( @@ -524,20 +525,20 @@ template class GeminiVerifier_ { const Fr& batched_evaluation, std::span evaluation_point, // CONST_PROOF_SIZE std::span challenge_powers, // r_squares CONST_PROOF_SIZE_LOG_N - std::span fold_polynomial_evals, + std::span fold_neg_evals, Fr p_neg = Fr(0)) { - std::vector evals(fold_polynomial_evals.begin(), fold_polynomial_evals.end()); + std::vector evals(fold_neg_evals.begin(), fold_neg_evals.end()); Fr eval_pos_prev = batched_evaluation; Fr zero{ 0 }; if constexpr (Curve::is_stdlib_type) { - zero.convert_constant_to_fixed_witness(fold_polynomial_evals[0].get_context()); + zero.convert_constant_to_fixed_witness(fold_neg_evals[0].get_context()); } - std::vector gemini_fold_pos_evaluations; - gemini_fold_pos_evaluations.reserve(CONST_PROOF_SIZE_LOG_N); + std::vector fold_pos_evaluations; + fold_pos_evaluations.reserve(CONST_PROOF_SIZE_LOG_N); // Either a computed eval of A_i at r^{2^i}, or 0 Fr value_to_emplace; @@ -574,12 +575,12 @@ template class GeminiVerifier_ { eval_pos_prev = dummy_round ? eval_pos_prev : eval_pos; value_to_emplace = dummy_round ? zero : eval_pos_prev; }; - gemini_fold_pos_evaluations.emplace_back(value_to_emplace); + fold_pos_evaluations.emplace_back(value_to_emplace); } - std::reverse(gemini_fold_pos_evaluations.begin(), gemini_fold_pos_evaluations.end()); + std::reverse(fold_pos_evaluations.begin(), fold_pos_evaluations.end()); - return gemini_fold_pos_evaluations; + return fold_pos_evaluations; } }; diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 58cdd895778a..18c826cd831c 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -31,6 +31,9 @@ static constexpr uint32_t MERGE_PROOF_SIZE = 65; // used to ensure mock proofs a // There are 5 distinguished wires in ECCVM that have to be opened as univariates to establish the connection between // ECCVM and Translator static constexpr uint32_t NUM_TRANSLATION_EVALUATIONS = 5; -// Upper bound on the number of claims produced GeminiProver. +// Upper bound on the number of claims produced GeminiProver: +// - Each fold polynomial is opened at two points, the number of resulting claims is bounded by 2*CONST_PROOF_SIZE_LOG_N +// - The interleaving trick needed for Translator adds 2 extra claims +// TODO() static constexpr uint32_t NUM_GEMINI_CLAIMS = 2 * CONST_PROOF_SIZE_LOG_N + 2; } // namespace bb From 73d2b18b9fe8edf5b195826b984379c8bc1b77d2 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 14 Mar 2025 10:27:46 +0000 Subject: [PATCH 10/24] computation of a_0_pos returns array of all pos evals --- barretenberg/sol/src/honk/BaseHonkVerifier.sol | 12 ++++++++---- barretenberg/sol/src/honk/BaseZKHonkVerifier.sol | 12 ++++++++---- barretenberg/sol/src/honk/CommitmentScheme.sol | 8 +++++--- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index 2f879189793d..53f29e1eb228 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -63,12 +63,14 @@ abstract contract BaseHonkVerifier is IVerifier { // Generate the fiat shamir challenges for the whole protocol // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely. - Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, vk.circuitSize, numPublicInputs, /*pubInputsOffset=*/1); + Transcript memory t = + TranscriptLib.generateTranscript(p, publicInputs, vk.circuitSize, numPublicInputs, /*pubInputsOffset=*/ 1); // Derive public input delta // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely. - t.relationParameters.publicInputsDelta = - computePublicInputDelta(publicInputs, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/1); + t.relationParameters.publicInputsDelta = computePublicInputDelta( + publicInputs, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/ 1 + ); // Sumcheck bool sumcheckVerified = verifySumcheck(p, t); @@ -350,7 +352,7 @@ abstract contract BaseHonkVerifier is IVerifier { // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: // Compute evaluation A₀(r) - Fr a_0_pos = PCS.computeGeminiBatchedUnivariateEvaluation( + mem.foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( tp.sumCheckUChallenges, mem.batchedEvaluation, proof.geminiAEvaluations, @@ -358,6 +360,8 @@ abstract contract BaseHonkVerifier is IVerifier { logN ); + Fr a_0_pos = mem.foldPosEvaluations[0]; + mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * inverse_vanishing_evals[0]); mem.constantTermAccumulator = mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * inverse_vanishing_evals[1]); diff --git a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol index d8604c65664d..d3e4834a9b42 100644 --- a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol @@ -73,12 +73,14 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Generate the fiat shamir challenges for the whole protocol // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely. - ZKTranscript memory t = ZKTranscriptLib.generateTranscript(p, publicInputs, vk.circuitSize, numPublicInputs, /*pubInputsOffset=*/1); + ZKTranscript memory t = + ZKTranscriptLib.generateTranscript(p, publicInputs, vk.circuitSize, numPublicInputs, /*pubInputsOffset=*/ 1); // Derive public input delta // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely. - t.relationParameters.publicInputsDelta = - computePublicInputDelta(publicInputs, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/1); + t.relationParameters.publicInputsDelta = computePublicInputDelta( + publicInputs, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/ 1 + ); // Sumcheck if (!verifySumcheck(p, t)) revert SumcheckFailed(); @@ -354,7 +356,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: // Compute evaluation A₀(r) - Fr a_0_pos = PCS.computeGeminiBatchedUnivariateEvaluation( + mem.foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( tp.sumCheckUChallenges, mem.batchedEvaluation, proof.geminiAEvaluations, @@ -362,6 +364,8 @@ abstract contract BaseZKHonkVerifier is IVerifier { logN ); + Fr a_0_pos = mem.foldPosEvaluations[0]; + mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * mem.inverse_vanishing_denominators[0]); mem.constantTermAccumulator = mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.inverse_vanishing_denominators[1]); diff --git a/barretenberg/sol/src/honk/CommitmentScheme.sol b/barretenberg/sol/src/honk/CommitmentScheme.sol index 1be6ca8ab1b0..66136c040792 100644 --- a/barretenberg/sol/src/honk/CommitmentScheme.sol +++ b/barretenberg/sol/src/honk/CommitmentScheme.sol @@ -33,6 +33,7 @@ library CommitmentSchemeLib { Fr[4] denominators; Fr[4] batchingScalars; Fr[CONST_PROOF_SIZE_LOG_N + 1] inverse_vanishing_denominators; + Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; } function computeSquares(Fr r) internal pure returns (Fr[CONST_PROOF_SIZE_LOG_N] memory squares) { @@ -64,7 +65,7 @@ library CommitmentSchemeLib { Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations, Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvalChallengePowers, uint256 logSize - ) internal view returns (Fr a_0_pos) { + ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations) { for (uint256 i = CONST_PROOF_SIZE_LOG_N; i > 0; --i) { Fr challengePower = geminiEvalChallengePowers[i - 1]; Fr u = sumcheckUChallenges[i - 1]; @@ -78,9 +79,10 @@ library CommitmentSchemeLib { if (i <= logSize) { batchedEvalAccumulator = batchedEvalRoundAcc; + foldPosEvaluations[CONST_PROOF_SIZE_LOG_N - i] = batchedEvalRoundAcc; + } else { + foldPosEvaluations[CONST_PROOF_SIZE_LOG_N - i] = ZERO; } } - - a_0_pos = batchedEvalAccumulator; } } From 9284bfdd40ffca3f686d1c69f360ce71ec31dd76 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 14 Mar 2025 10:43:34 +0000 Subject: [PATCH 11/24] computeInvertedGeminiDenominators modified --- barretenberg/sol/src/honk/BaseHonkVerifier.sol | 17 +++++++++-------- barretenberg/sol/src/honk/CommitmentScheme.sol | 15 ++++++++------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index 53f29e1eb228..b5a73b0fb4bb 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -212,12 +212,13 @@ abstract contract BaseHonkVerifier is IVerifier { Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars; Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory commitments; - Fr[CONST_PROOF_SIZE_LOG_N + 1] memory inverse_vanishing_evals = + mem.inverse_vanishing_denominators = PCS.computeInvertedGeminiDenominators(tp.shplonkZ, powers_of_evaluation_challenge, logN); - mem.unshiftedScalar = inverse_vanishing_evals[0] + (tp.shplonkNu * inverse_vanishing_evals[1]); - mem.shiftedScalar = - tp.geminiR.invert() * (inverse_vanishing_evals[0] - (tp.shplonkNu * inverse_vanishing_evals[1])); + mem.unshiftedScalar = + mem.inverse_vanishing_denominators[0] + (tp.shplonkNu * mem.inverse_vanishing_denominators[1]); + mem.shiftedScalar = tp.geminiR.invert() + * (mem.inverse_vanishing_denominators[0] - (tp.shplonkNu * mem.inverse_vanishing_denominators[1])); scalars[0] = ONE; commitments[0] = convertProofPoint(proof.shplonkQ); @@ -339,7 +340,7 @@ abstract contract BaseHonkVerifier is IVerifier { Fr scalingFactor = ZERO; if (!dummy_round) { - scalingFactor = mem.batchingChallenge * inverse_vanishing_evals[i + 2]; + scalingFactor = mem.batchingChallenge * mem.inverse_vanishing_denominators[i + 2]; scalars[NUMBER_OF_ENTITIES + 1 + i] = scalingFactor.neg(); } @@ -362,9 +363,9 @@ abstract contract BaseHonkVerifier is IVerifier { Fr a_0_pos = mem.foldPosEvaluations[0]; - mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * inverse_vanishing_evals[0]); - mem.constantTermAccumulator = - mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * inverse_vanishing_evals[1]); + mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * mem.inverse_vanishing_denominators[0]); + mem.constantTermAccumulator = mem.constantTermAccumulator + + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.inverse_vanishing_denominators[1]); // Finalise the batch opening claim commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2}); diff --git a/barretenberg/sol/src/honk/CommitmentScheme.sol b/barretenberg/sol/src/honk/CommitmentScheme.sol index 66136c040792..ae1eb0e80115 100644 --- a/barretenberg/sol/src/honk/CommitmentScheme.sol +++ b/barretenberg/sol/src/honk/CommitmentScheme.sol @@ -32,7 +32,7 @@ library CommitmentSchemeLib { Fr batchedEvaluation; Fr[4] denominators; Fr[4] batchingScalars; - Fr[CONST_PROOF_SIZE_LOG_N + 1] inverse_vanishing_denominators; + Fr[2 * CONST_PROOF_SIZE_LOG_N] inverse_vanishing_denominators; Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; } @@ -47,15 +47,16 @@ library CommitmentSchemeLib { Fr shplonkZ, Fr[CONST_PROOF_SIZE_LOG_N] memory eval_challenge_powers, uint256 logSize - ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N + 1] memory inverse_vanishing_evals) { - inverse_vanishing_evals[0] = (shplonkZ - eval_challenge_powers[0]).invert(); - + ) internal view returns (Fr[2 * CONST_PROOF_SIZE_LOG_N] memory inverse_vanishing_evals) { for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; ++i) { - Fr round_inverted_denominator = ZERO; + Fr negInvertedDenominator = ZERO; + Fr posInvertedDenominator = ZERO; if (i <= logSize + 1) { - round_inverted_denominator = (shplonkZ + eval_challenge_powers[i]).invert(); + posInvertedDenominator = (shplonkZ - eval_challenge_powers[i]).invert(); + negInvertedDenominator = (shplonkZ + eval_challenge_powers[i]).invert(); } - inverse_vanishing_evals[i + 1] = round_inverted_denominator; + inverse_vanishing_evals[2 * i] = posInvertedDenominator; + inverse_vanishing_evals[2 * i + 1] = negInvertedDenominator; } } From b9beafba39786ab98b3686b9601beda73b20b638 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 14 Mar 2025 11:21:13 +0000 Subject: [PATCH 12/24] modified the batching loop --- .../sol/src/honk/BaseHonkVerifier.sol | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index b5a73b0fb4bb..bf799335a657 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -332,35 +332,40 @@ abstract contract BaseHonkVerifier is IVerifier { * \f] * and adds them to the 'constant_term_accumulator'. */ + + // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: + // Compute evaluation A₀(r) + mem.foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( + tp.sumCheckUChallenges, + mem.batchedEvaluation, + proof.geminiAEvaluations, + powers_of_evaluation_challenge, + logN + ); + mem.constantTermAccumulator = ZERO; mem.batchingChallenge = tp.shplonkNu.sqr(); for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { bool dummy_round = i >= (logN - 1); - - Fr scalingFactor = ZERO; + uint256 posLocation = 2 * i + 2; + Fr scalingFactorNeg = ZERO; + Fr scalingFactorPos = ZERO; if (!dummy_round) { - scalingFactor = mem.batchingChallenge * mem.inverse_vanishing_denominators[i + 2]; - scalars[NUMBER_OF_ENTITIES + 1 + i] = scalingFactor.neg(); + scalingFactorPos = mem.batchingChallenge * mem.inverse_vanishing_denominators[posLocation]; + scalingFactorNeg = + mem.batchingChallenge * tp.shplonkNu * mem.inverse_vanishing_denominators[posLocation + 1]; + scalars[NUMBER_OF_ENTITIES + 1 + i] = scalingFactorNeg.neg() + scalingFactorPos.neg(); } - mem.constantTermAccumulator = - mem.constantTermAccumulator + (scalingFactor * proof.geminiAEvaluations[i + 1]); - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; + Fr accumContribution = scalingFactorNeg * proof.geminiAEvaluations[i + 1]; + accumContribution = accumContribution + scalingFactorPos * mem.foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu.sqr(); commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]); } - // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: - // Compute evaluation A₀(r) - mem.foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( - tp.sumCheckUChallenges, - mem.batchedEvaluation, - proof.geminiAEvaluations, - powers_of_evaluation_challenge, - logN - ); - Fr a_0_pos = mem.foldPosEvaluations[0]; mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * mem.inverse_vanishing_denominators[0]); From 14380d85ea8e11615cbd9668a0487a879bf540f9 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 14 Mar 2025 14:25:44 +0000 Subject: [PATCH 13/24] stack too deep resolved --- .../sol/src/honk/BaseHonkVerifier.sol | 43 +++++++------- .../sol/src/honk/BaseZKHonkVerifier.sol | 59 ++++++++++--------- .../sol/src/honk/CommitmentScheme.sol | 22 ++----- 3 files changed, 56 insertions(+), 68 deletions(-) diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index bf799335a657..3ad0c499f71a 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -212,13 +212,12 @@ abstract contract BaseHonkVerifier is IVerifier { Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars; Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory commitments; - mem.inverse_vanishing_denominators = - PCS.computeInvertedGeminiDenominators(tp.shplonkZ, powers_of_evaluation_challenge, logN); + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); - mem.unshiftedScalar = - mem.inverse_vanishing_denominators[0] + (tp.shplonkNu * mem.inverse_vanishing_denominators[1]); - mem.shiftedScalar = tp.geminiR.invert() - * (mem.inverse_vanishing_denominators[0] - (tp.shplonkNu * mem.inverse_vanishing_denominators[1])); + mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); + mem.shiftedScalar = + tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); scalars[0] = ONE; commitments[0] = convertProofPoint(proof.shplonkQ); @@ -344,34 +343,34 @@ abstract contract BaseHonkVerifier is IVerifier { ); mem.constantTermAccumulator = ZERO; + + mem.constantTermAccumulator = + mem.constantTermAccumulator + (mem.foldPosEvaluations[0] * mem.posInvertedDenominator); + mem.constantTermAccumulator = + mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + mem.batchingChallenge = tp.shplonkNu.sqr(); for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { bool dummy_round = i >= (logN - 1); - uint256 posLocation = 2 * i + 2; - Fr scalingFactorNeg = ZERO; - Fr scalingFactorPos = ZERO; + if (!dummy_round) { - scalingFactorPos = mem.batchingChallenge * mem.inverse_vanishing_denominators[posLocation]; - scalingFactorNeg = - mem.batchingChallenge * tp.shplonkNu * mem.inverse_vanishing_denominators[posLocation + 1]; - scalars[NUMBER_OF_ENTITIES + 1 + i] = scalingFactorNeg.neg() + scalingFactorPos.neg(); + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + + mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; + mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; + scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); } - Fr accumContribution = scalingFactorNeg * proof.geminiAEvaluations[i + 1]; - accumContribution = accumContribution + scalingFactorPos * mem.foldPosEvaluations[i + 1]; + Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; + accumContribution = accumContribution + mem.scalingFactorPos * mem.foldPosEvaluations[i + 1]; mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu.sqr(); + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]); } - Fr a_0_pos = mem.foldPosEvaluations[0]; - - mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * mem.inverse_vanishing_denominators[0]); - mem.constantTermAccumulator = mem.constantTermAccumulator - + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.inverse_vanishing_denominators[1]); - // Finalise the batch opening claim commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2}); scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = mem.constantTermAccumulator; diff --git a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol index d3e4834a9b42..07893988a2ae 100644 --- a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol @@ -210,13 +210,12 @@ abstract contract BaseZKHonkVerifier is IVerifier { Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + LIBRA_COMMITMENTS + 3] memory scalars; Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + LIBRA_COMMITMENTS + 3] memory commitments; - mem.inverse_vanishing_denominators = - PCS.computeInvertedGeminiDenominators(tp.shplonkZ, powers_of_evaluation_challenge, logN); + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); - mem.unshiftedScalar = - mem.inverse_vanishing_denominators[0] + (tp.shplonkNu * mem.inverse_vanishing_denominators[1]); - mem.shiftedScalar = tp.geminiR.invert() - * (mem.inverse_vanishing_denominators[0] - (tp.shplonkNu * mem.inverse_vanishing_denominators[1])); + mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); + mem.shiftedScalar = + tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); scalars[0] = Fr.wrap(1); commitments[0] = convertProofPoint(proof.shplonkQ); @@ -332,44 +331,48 @@ abstract contract BaseZKHonkVerifier is IVerifier { * \f] * and adds them to the 'constant_term_accumulator'. */ + + // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: + // Compute evaluation A₀(r) + mem.foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( + tp.sumCheckUChallenges, + mem.batchedEvaluation, + proof.geminiAEvaluations, + powers_of_evaluation_challenge, + logN + ); + mem.constantTermAccumulator = Fr.wrap(0); + mem.constantTermAccumulator = + mem.constantTermAccumulator + (mem.foldPosEvaluations[0] * mem.posInvertedDenominator); + mem.constantTermAccumulator = + mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + mem.batchingChallenge = tp.shplonkNu.sqr(); uint256 boundary = NUMBER_OF_ENTITIES + 2; for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { bool dummy_round = i >= (logN - 1); - Fr scalingFactor = Fr.wrap(0); if (!dummy_round) { - scalingFactor = mem.batchingChallenge * mem.inverse_vanishing_denominators[i + 2]; - scalars[boundary + i] = scalingFactor.neg(); + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + + mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; + mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; + scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); } - mem.constantTermAccumulator = - mem.constantTermAccumulator + (scalingFactor * proof.geminiAEvaluations[i + 1]); - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; + Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; + accumContribution = accumContribution + mem.scalingFactorPos * mem.foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; commitments[boundary + i] = convertProofPoint(proof.geminiFoldComms[i]); } boundary += CONST_PROOF_SIZE_LOG_N - 1; - // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: - // Compute evaluation A₀(r) - mem.foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( - tp.sumCheckUChallenges, - mem.batchedEvaluation, - proof.geminiAEvaluations, - powers_of_evaluation_challenge, - logN - ); - - Fr a_0_pos = mem.foldPosEvaluations[0]; - - mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * mem.inverse_vanishing_denominators[0]); - mem.constantTermAccumulator = mem.constantTermAccumulator - + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.inverse_vanishing_denominators[1]); - // Finalise the batch opening claim mem.denominators[0] = Fr.wrap(1).div(tp.shplonkZ - tp.geminiR); mem.denominators[1] = Fr.wrap(1).div(tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR); diff --git a/barretenberg/sol/src/honk/CommitmentScheme.sol b/barretenberg/sol/src/honk/CommitmentScheme.sol index ae1eb0e80115..310b4d259550 100644 --- a/barretenberg/sol/src/honk/CommitmentScheme.sol +++ b/barretenberg/sol/src/honk/CommitmentScheme.sol @@ -32,7 +32,10 @@ library CommitmentSchemeLib { Fr batchedEvaluation; Fr[4] denominators; Fr[4] batchingScalars; - Fr[2 * CONST_PROOF_SIZE_LOG_N] inverse_vanishing_denominators; + Fr negInvertedDenominator; + Fr posInvertedDenominator; + Fr scalingFactorNeg; + Fr scalingFactorPos; Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; } @@ -43,23 +46,6 @@ library CommitmentSchemeLib { } } - function computeInvertedGeminiDenominators( - Fr shplonkZ, - Fr[CONST_PROOF_SIZE_LOG_N] memory eval_challenge_powers, - uint256 logSize - ) internal view returns (Fr[2 * CONST_PROOF_SIZE_LOG_N] memory inverse_vanishing_evals) { - for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; ++i) { - Fr negInvertedDenominator = ZERO; - Fr posInvertedDenominator = ZERO; - if (i <= logSize + 1) { - posInvertedDenominator = (shplonkZ - eval_challenge_powers[i]).invert(); - negInvertedDenominator = (shplonkZ + eval_challenge_powers[i]).invert(); - } - inverse_vanishing_evals[2 * i] = posInvertedDenominator; - inverse_vanishing_evals[2 * i + 1] = negInvertedDenominator; - } - } - function computeGeminiBatchedUnivariateEvaluation( Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges, Fr batchedEvalAccumulator, From 80adaba21a58dd06d244fcc0d969e9fd27e58db1 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 14 Mar 2025 18:26:25 +0000 Subject: [PATCH 14/24] debugging --- .../solidity_helpers/honk_proof_gen.cpp | 2 +- barretenberg/sol/scripts/run_fuzzer.sh | 2 +- .../sol/src/honk/BaseHonkVerifier.sol | 29 ++++++++++++------- .../sol/src/honk/BaseZKHonkVerifier.sol | 7 ++--- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/solidity_helpers/honk_proof_gen.cpp b/barretenberg/cpp/src/barretenberg/solidity_helpers/honk_proof_gen.cpp index 6fc3eaf6a453..c409f0d4fd98 100644 --- a/barretenberg/cpp/src/barretenberg/solidity_helpers/honk_proof_gen.cpp +++ b/barretenberg/cpp/src/barretenberg/solidity_helpers/honk_proof_gen.cpp @@ -115,4 +115,4 @@ int main(int argc, char** argv) info("Only honk flavor allowed"); return 1; } -} \ No newline at end of file +} diff --git a/barretenberg/sol/scripts/run_fuzzer.sh b/barretenberg/sol/scripts/run_fuzzer.sh index 5565f0d3af88..9428847bff64 100755 --- a/barretenberg/sol/scripts/run_fuzzer.sh +++ b/barretenberg/sol/scripts/run_fuzzer.sh @@ -16,4 +16,4 @@ if [ "$FLAVOR" == "honk" ] || [ "$FLAVOR" == "honk_zk" ] ; then fi # @note This needs to be updated to point to the generator -$BIN $FLAVOR $CIRCUIT $SRS_PATH $INPUTS \ No newline at end of file +$BIN $FLAVOR $CIRCUIT $SRS_PATH $INPUTS diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index 3ad0c499f71a..0701891975e0 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -2,6 +2,9 @@ // Copyright 2024 Aztec Labs pragma solidity >=0.8.21; +import "forge-std/console.sol"; +import "forge-std/console2.sol"; + import {IVerifier} from "../interfaces/IVerifier.sol"; import { Honk, @@ -14,7 +17,7 @@ import { CONST_PROOF_SIZE_LOG_N } from "./HonkTypes.sol"; -import {negateInplace, convertProofPoint, pairing} from "./utils.sol"; +import {negateInplace, convertProofPoint, pairing, logFr} from "./utils.sol"; // Field arithmetic libraries - prevent littering the code with modmul / addmul import {MODULUS as P, MINUS_ONE, ONE, ZERO, Fr, FrLib} from "./Fr.sol"; @@ -212,6 +215,9 @@ abstract contract BaseHonkVerifier is IVerifier { Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars; Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory commitments; + logFr("geminiR ", tp.geminiR); + logFr("geminiR ? ", powers_of_evaluation_challenge[0]); + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); @@ -334,7 +340,7 @@ abstract contract BaseHonkVerifier is IVerifier { // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: // Compute evaluation A₀(r) - mem.foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( + Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( tp.sumCheckUChallenges, mem.batchedEvaluation, proof.geminiAEvaluations, @@ -342,14 +348,13 @@ abstract contract BaseHonkVerifier is IVerifier { logN ); - mem.constantTermAccumulator = ZERO; + mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; - mem.constantTermAccumulator = - mem.constantTermAccumulator + (mem.foldPosEvaluations[0] * mem.posInvertedDenominator); mem.constantTermAccumulator = mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); mem.batchingChallenge = tp.shplonkNu.sqr(); + logFr("batched eval ", mem.batchedEvaluation); for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { bool dummy_round = i >= (logN - 1); @@ -361,16 +366,20 @@ abstract contract BaseHonkVerifier is IVerifier { mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); - } - Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; - accumContribution = accumContribution + mem.scalingFactorPos * mem.foldPosEvaluations[i + 1]; - mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; + accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + } commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]); + console.log(i + 1); + logFr("gemini fold pos ", foldPosEvaluations[i + 1]); + logFr("gemini fold neg ", proof.geminiAEvaluations[i + 1]); } + logFr("a_0_pos", foldPosEvaluations[0]); // Finalise the batch opening claim commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2}); scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = mem.constantTermAccumulator; diff --git a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol index 07893988a2ae..c310a012010f 100644 --- a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol @@ -334,7 +334,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: // Compute evaluation A₀(r) - mem.foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( + Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( tp.sumCheckUChallenges, mem.batchedEvaluation, proof.geminiAEvaluations, @@ -343,8 +343,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { ); mem.constantTermAccumulator = Fr.wrap(0); - mem.constantTermAccumulator = - mem.constantTermAccumulator + (mem.foldPosEvaluations[0] * mem.posInvertedDenominator); + mem.constantTermAccumulator = mem.constantTermAccumulator + (foldPosEvaluations[0] * mem.posInvertedDenominator); mem.constantTermAccumulator = mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); @@ -364,7 +363,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { } Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; - accumContribution = accumContribution + mem.scalingFactorPos * mem.foldPosEvaluations[i + 1]; + accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; From 9eccb434ace445908d238d08616bb64420cdc0c2 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Fri, 14 Mar 2025 19:57:54 +0000 Subject: [PATCH 15/24] basic sol tests fixed --- barretenberg/sol/src/honk/BaseHonkVerifier.sol | 6 ++++-- barretenberg/sol/src/honk/BaseZKHonkVerifier.sol | 12 ++++++------ barretenberg/sol/src/honk/CommitmentScheme.sol | 5 +---- .../sol/src/ultra/keys/Add2UltraVerificationKey.sol | 4 ++-- .../sol/src/ultra/keys/BlakeUltraVerificationKey.sol | 4 ++-- .../sol/src/ultra/keys/EcdsaUltraVerificationKey.sol | 4 ++-- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index 0701891975e0..fdd8dfddc4cb 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -355,6 +355,7 @@ abstract contract BaseHonkVerifier is IVerifier { mem.batchingChallenge = tp.shplonkNu.sqr(); logFr("batched eval ", mem.batchedEvaluation); + console2.log("circ size ", logN); for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { bool dummy_round = i >= (logN - 1); @@ -371,12 +372,13 @@ abstract contract BaseHonkVerifier is IVerifier { accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + logFr("gemini fold pos ", foldPosEvaluations[i + 1]); + logFr("gemini fold neg ", proof.geminiAEvaluations[i + 1]); } + logFr("const term accum ", mem.constantTermAccumulator); commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]); console.log(i + 1); - logFr("gemini fold pos ", foldPosEvaluations[i + 1]); - logFr("gemini fold neg ", proof.geminiAEvaluations[i + 1]); } logFr("a_0_pos", foldPosEvaluations[0]); diff --git a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol index c310a012010f..78fd9d04e4cd 100644 --- a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol @@ -342,8 +342,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { logN ); - mem.constantTermAccumulator = Fr.wrap(0); - mem.constantTermAccumulator = mem.constantTermAccumulator + (foldPosEvaluations[0] * mem.posInvertedDenominator); + mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; mem.constantTermAccumulator = mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); @@ -360,11 +359,12 @@ abstract contract BaseZKHonkVerifier is IVerifier { mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + + Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; + accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; } - Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; - accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; - mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; commitments[boundary + i] = convertProofPoint(proof.geminiFoldComms[i]); @@ -378,7 +378,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { mem.denominators[2] = mem.denominators[0]; mem.denominators[3] = mem.denominators[0]; - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; for (uint256 i = 0; i < LIBRA_EVALUATIONS; i++) { Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; mem.batchingScalars[i] = scalingFactor.neg(); diff --git a/barretenberg/sol/src/honk/CommitmentScheme.sol b/barretenberg/sol/src/honk/CommitmentScheme.sol index 310b4d259550..d5152c348ff8 100644 --- a/barretenberg/sol/src/honk/CommitmentScheme.sol +++ b/barretenberg/sol/src/honk/CommitmentScheme.sol @@ -63,12 +63,9 @@ library CommitmentSchemeLib { ); // Divide by the denominator batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (ONE - u) + u).invert(); - if (i <= logSize) { batchedEvalAccumulator = batchedEvalRoundAcc; - foldPosEvaluations[CONST_PROOF_SIZE_LOG_N - i] = batchedEvalRoundAcc; - } else { - foldPosEvaluations[CONST_PROOF_SIZE_LOG_N - i] = ZERO; + foldPosEvaluations[i - 1] = batchedEvalRoundAcc; } } } diff --git a/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol index 89c44572fbbe..f6b5c071a320 100644 --- a/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 594d0af354947ea7aa13eece55ec3ccdce54dff437d9354a8a50cb2a0438a86a +// Verification Key Hash: 52b5c39ccd4966230bccd3c5313992f8e8b0c4ca8120939c1a053b41d23ff61c // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library Add2UltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x594d0af354947ea7aa13eece55ec3ccdce54dff437d9354a8a50cb2a0438a86a; + return 0x52b5c39ccd4966230bccd3c5313992f8e8b0c4ca8120939c1a053b41d23ff61c; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { diff --git a/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol index d81948a7761b..ffd447c56fa0 100644 --- a/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 4dd3c85ec6b387fe6e6b3dc9b4eb16c522fec0c8b0e6bdc6b34bf32af822b2d8 +// Verification Key Hash: 3e90f6833288b5b3f8c6006ddff945b552ee9e6b00f3e047b1cb50927248e165 // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library BlakeUltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x4dd3c85ec6b387fe6e6b3dc9b4eb16c522fec0c8b0e6bdc6b34bf32af822b2d8; + return 0x3e90f6833288b5b3f8c6006ddff945b552ee9e6b00f3e047b1cb50927248e165; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { diff --git a/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol index eeffbdec7523..b2b4e268ff02 100644 --- a/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 051da9b5f32346e9d0892040b55aa70862447630aa29cecc3abe3cb74517137c +// Verification Key Hash: 7d146c779845c11f731974db664e09fa3d3f98c34d1a982e72f0e76a747b59fc // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library EcdsaUltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x051da9b5f32346e9d0892040b55aa70862447630aa29cecc3abe3cb74517137c; + return 0x7d146c779845c11f731974db664e09fa3d3f98c34d1a982e72f0e76a747b59fc; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { From cc99398602511388d5a145f6c9e9f380fd582cac Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Mar 2025 12:02:48 +0000 Subject: [PATCH 16/24] porting changes --- .../dsl/acir_proofs/honk_contract.hpp | 104 +++++++++--------- .../dsl/acir_proofs/honk_zk_contract.hpp | 93 +++++++++------- .../sol/src/honk/BaseHonkVerifier.sol | 24 +--- .../sol/src/honk/BaseZKHonkVerifier.sol | 2 +- .../sol/src/honk/CommitmentScheme.sol | 12 +- .../ultra/keys/Add2UltraVerificationKey.sol | 4 +- .../ultra/keys/EcdsaUltraVerificationKey.sol | 4 +- 7 files changed, 126 insertions(+), 117 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index 280743556ea0..be0817348a09 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -1347,6 +1347,17 @@ struct ShpleminiIntermediates { Fr batchingChallenge; // Linear combination of multilinear (sumcheck) evaluations and powers of rho Fr batchedEvaluation; + // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated + Fr posInvertedDenominator; + // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated + Fr negInvertedDenominator; + // v^{2i} * 1/(z - r^{2^i}) + Fr scalingFactorPos; + // v^{2i+1} * 1/(z + r^{2^i}) + Fr scalingFactorNeg; + + // Fold_i(r^{2^i}) reconstructed by Verifier + Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; } library CommitmentSchemeLib { @@ -1358,53 +1369,33 @@ library CommitmentSchemeLib { squares[i] = squares[i - 1].sqr(); } } - - function computeInvertedGeminiDenominators( - Fr shplonkZ, - Fr[CONST_PROOF_SIZE_LOG_N] memory eval_challenge_powers, - uint256 logSize - ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N + 1] memory inverse_vanishing_evals) { - Fr eval_challenge = shplonkZ; - inverse_vanishing_evals[0] = (eval_challenge - eval_challenge_powers[0]).invert(); - - for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; ++i) { - Fr round_inverted_denominator = Fr.wrap(0); - if (i <= logSize + 1) { - round_inverted_denominator = (eval_challenge + eval_challenge_powers[i]).invert(); - } - inverse_vanishing_evals[i + 1] = round_inverted_denominator; - } - } - - function computeGeminiBatchedUnivariateEvaluation( + // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1 + function computeFoldPosEvaluations( Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges, Fr batchedEvalAccumulator, Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations, Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvalChallengePowers, uint256 logSize - ) internal view returns (Fr a_0_pos) { + ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations) { for (uint256 i = CONST_PROOF_SIZE_LOG_N; i > 0; --i) { Fr challengePower = geminiEvalChallengePowers[i - 1]; Fr u = sumcheckUChallenges[i - 1]; - Fr evalNeg = geminiEvaluations[i - 1]; Fr batchedEvalRoundAcc = ( (challengePower * batchedEvalAccumulator * Fr.wrap(2)) - - evalNeg * (challengePower * (Fr.wrap(1) - u) - u) + - geminiEvaluations[i - 1] * (challengePower * (Fr.wrap(1) - u) - u) ); // Divide by the denominator batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (Fr.wrap(1) - u) + u).invert(); - - bool is_dummy_round = (i > logSize); - if (!is_dummy_round) { + if (i <= logSize) { batchedEvalAccumulator = batchedEvalRoundAcc; + foldPosEvaluations[i - 1] = batchedEvalRoundAcc; } } - - a_0_pos = batchedEvalAccumulator; } } + interface IVerifier { function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool); } @@ -1595,12 +1586,13 @@ abstract contract BaseHonkVerifier is IVerifier { Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars; Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory commitments; - Fr[CONST_PROOF_SIZE_LOG_N + 1] memory inverse_vanishing_evals = - CommitmentSchemeLib.computeInvertedGeminiDenominators(tp.shplonkZ, powers_of_evaluation_challenge, logN); + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); + - mem.unshiftedScalar = inverse_vanishing_evals[0] + (tp.shplonkNu * inverse_vanishing_evals[1]); + mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); mem.shiftedScalar = - tp.geminiR.invert() * (inverse_vanishing_evals[0] - (tp.shplonkNu * inverse_vanishing_evals[1])); + tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); scalars[0] = Fr.wrap(1); commitments[0] = convertProofPoint(proof.shplonkQ); @@ -1665,28 +1657,9 @@ abstract contract BaseHonkVerifier is IVerifier { commitments[39] = convertProofPoint(proof.w4); commitments[40] = convertProofPoint(proof.zPerm); - mem.constantTermAccumulator = Fr.wrap(0); - mem.batchingChallenge = tp.shplonkNu.sqr(); - - for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { - bool dummy_round = i >= (logN - 1); - - Fr scalingFactor = Fr.wrap(0); - if (!dummy_round) { - scalingFactor = mem.batchingChallenge * inverse_vanishing_evals[i + 2]; - scalars[NUMBER_OF_ENTITIES + 1 + i] = scalingFactor.neg(); - } - - mem.constantTermAccumulator = - mem.constantTermAccumulator + (scalingFactor * proof.geminiAEvaluations[i + 1]); - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; - - commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]); - } - // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: - // Compute evaluation A₀(r) - Fr a_0_pos = CommitmentSchemeLib.computeGeminiBatchedUnivariateEvaluation( + // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., logN - 1 + Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations( tp.sumCheckUChallenges, mem.batchedEvaluation, proof.geminiAEvaluations, @@ -1694,9 +1667,32 @@ abstract contract BaseHonkVerifier is IVerifier { logN ); - mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * inverse_vanishing_evals[0]); + // Compute the Shplonk constant term contributions from A₀(±r) + mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; mem.constantTermAccumulator = - mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * inverse_vanishing_evals[1]); + mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + + // Compute Shplonk constant term contributions from Aₗ(±r^{2ˡ}) for l = 1, ..., m-1; + // Compute scalar multipliers for each fold commitment + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { + bool dummy_round = i >= (logN - 1); + + if (!dummy_round) { + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + + mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; + mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; + scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + + Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; + accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + } + + commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]); + } // Finalise the batch opening claim commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2}); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index ccbdcbe39b71..42cd80875c85 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -1414,7 +1414,17 @@ struct ShpleminiIntermediates { Fr batchedEvaluation; Fr[4] denominators; Fr[4] batchingScalars; - Fr[CONST_PROOF_SIZE_LOG_N + 1] inverse_vanishing_denominators; + // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated + Fr posInvertedDenominator; + // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated + Fr negInvertedDenominator; + // ν^{2i} * 1/(z - r^{2^i}) + Fr scalingFactorPos; + // ν^{2i+1} * 1/(z + r^{2^i}) + Fr scalingFactorNeg; + + // Fold_i(r^{2^i}) reconstructed by Verifier + Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; } @@ -1444,29 +1454,29 @@ library CommitmentSchemeLib { } } - function computeGeminiBatchedUnivariateEvaluation( + // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1 + function computeFoldPosEvaluations( Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges, Fr batchedEvalAccumulator, Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations, - Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvalChallengePowers - ) internal view returns (Fr a_0_pos) { + Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvalChallengePowers, + uint256 logSize + ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations) { for (uint256 i = CONST_PROOF_SIZE_LOG_N; i > 0; --i) { Fr challengePower = geminiEvalChallengePowers[i - 1]; Fr u = sumcheckUChallenges[i - 1]; Fr batchedEvalRoundAcc = ( (challengePower * batchedEvalAccumulator * Fr.wrap(2)) - - geminiEvaluations[i - 1] * (challengePower * (ONE - u) - u) + - geminiEvaluations[i - 1] * (challengePower * (Fr.wrap(1) - u) - u) ); // Divide by the denominator - batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (ONE - u) + u).invert(); - - if (i <= LOG_N) { + batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (Fr.wrap(1) - u) + u).invert(); + if (i <= logSize) { batchedEvalAccumulator = batchedEvalRoundAcc; + foldPosEvaluations[i - 1] = batchedEvalRoundAcc; } - } - - a_0_pos = batchedEvalAccumulator; + } } } @@ -1638,13 +1648,13 @@ interface IVerifier { Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 3 + 3] memory scalars; Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 3 + 3] memory commitments; - mem.inverse_vanishing_denominators = - CommitmentSchemeLib.computeInvertedGeminiDenominators(tp.shplonkZ, powers_of_evaluation_challenge, LOG_N); + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); + - mem.unshiftedScalar = - mem.inverse_vanishing_denominators[0] + (tp.shplonkNu * mem.inverse_vanishing_denominators[1]); - mem.shiftedScalar = tp.geminiR.invert() - * (mem.inverse_vanishing_denominators[0] - (tp.shplonkNu * mem.inverse_vanishing_denominators[1])); + mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); + mem.shiftedScalar = + tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); scalars[0] = ONE; commitments[0] = convertProofPoint(proof.shplonkQ); @@ -1711,40 +1721,47 @@ interface IVerifier { commitments[40] = convertProofPoint(proof.w4); commitments[41] = convertProofPoint(proof.zPerm); - mem.constantTermAccumulator = ZERO; + + // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: + // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., logN - 1 + Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations( + tp.sumCheckUChallenges, + mem.batchedEvaluation, + proof.geminiAEvaluations, + powers_of_evaluation_challenge, + logN + ); + + mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; + mem.constantTermAccumulator = + mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + mem.batchingChallenge = tp.shplonkNu.sqr(); uint256 boundary = NUMBER_OF_ENTITIES + 2; for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { - bool dummy_round = i >= (LOG_N - 1); + bool dummy_round = i >= (logN - 1); - Fr scalingFactor = ZERO; if (!dummy_round) { - scalingFactor = mem.batchingChallenge * mem.inverse_vanishing_denominators[i + 2]; - scalars[boundary + i] = scalingFactor.neg(); + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + + mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; + mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; + scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + + Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; + accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; } - mem.constantTermAccumulator = - mem.constantTermAccumulator + (scalingFactor * proof.geminiAEvaluations[i + 1]); - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; commitments[boundary + i] = convertProofPoint(proof.geminiFoldComms[i]); } boundary += CONST_PROOF_SIZE_LOG_N - 1; - // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: - // Compute evaluation A₀(r) - Fr a_0_pos = CommitmentSchemeLib.computeGeminiBatchedUnivariateEvaluation( - tp.sumCheckUChallenges, - mem.batchedEvaluation, - proof.geminiAEvaluations, - powers_of_evaluation_challenge - ); - - mem.constantTermAccumulator = mem.constantTermAccumulator + (a_0_pos * mem.inverse_vanishing_denominators[0]); - mem.constantTermAccumulator = mem.constantTermAccumulator - + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.inverse_vanishing_denominators[1]); // Finalise the batch opening claim mem.denominators[0] = ONE.div(tp.shplonkZ - tp.geminiR); @@ -1752,6 +1769,8 @@ interface IVerifier { mem.denominators[2] = mem.denominators[0]; mem.denominators[3] = mem.denominators[0]; + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; for (uint256 i = 0; i < 4; i++) { Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index fdd8dfddc4cb..8b6fb9105870 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -2,9 +2,6 @@ // Copyright 2024 Aztec Labs pragma solidity >=0.8.21; -import "forge-std/console.sol"; -import "forge-std/console2.sol"; - import {IVerifier} from "../interfaces/IVerifier.sol"; import { Honk, @@ -17,7 +14,7 @@ import { CONST_PROOF_SIZE_LOG_N } from "./HonkTypes.sol"; -import {negateInplace, convertProofPoint, pairing, logFr} from "./utils.sol"; +import {negateInplace, convertProofPoint, pairing} from "./utils.sol"; // Field arithmetic libraries - prevent littering the code with modmul / addmul import {MODULUS as P, MINUS_ONE, ONE, ZERO, Fr, FrLib} from "./Fr.sol"; @@ -215,9 +212,6 @@ abstract contract BaseHonkVerifier is IVerifier { Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars; Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory commitments; - logFr("geminiR ", tp.geminiR); - logFr("geminiR ? ", powers_of_evaluation_challenge[0]); - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); @@ -338,9 +332,8 @@ abstract contract BaseHonkVerifier is IVerifier { * and adds them to the 'constant_term_accumulator'. */ - // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: - // Compute evaluation A₀(r) - Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( + // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., logN - 1 + Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = PCS.computeFoldPosEvaluations( tp.sumCheckUChallenges, mem.batchedEvaluation, proof.geminiAEvaluations, @@ -348,15 +341,15 @@ abstract contract BaseHonkVerifier is IVerifier { logN ); + // Compute the Shplonk constant term contributions from A₀(±r) mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; - mem.constantTermAccumulator = mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); mem.batchingChallenge = tp.shplonkNu.sqr(); - logFr("batched eval ", mem.batchedEvaluation); - console2.log("circ size ", logN); + // Compute Shplonk constant term contributions from Aₗ(± r^{2ˡ}) for l = 1, ..., m-1; + // Compute scalar multipliers for each fold commitment for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { bool dummy_round = i >= (logN - 1); @@ -372,16 +365,11 @@ abstract contract BaseHonkVerifier is IVerifier { accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; - logFr("gemini fold pos ", foldPosEvaluations[i + 1]); - logFr("gemini fold neg ", proof.geminiAEvaluations[i + 1]); } - logFr("const term accum ", mem.constantTermAccumulator); commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]); - console.log(i + 1); } - logFr("a_0_pos", foldPosEvaluations[0]); // Finalise the batch opening claim commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2}); scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = mem.constantTermAccumulator; diff --git a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol index 78fd9d04e4cd..12c7f3babcc3 100644 --- a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol @@ -334,7 +334,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: // Compute evaluation A₀(r) - Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = PCS.computeGeminiBatchedUnivariateEvaluation( + Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = PCS.computeFoldPosEvaluations( tp.sumCheckUChallenges, mem.batchedEvaluation, proof.geminiAEvaluations, diff --git a/barretenberg/sol/src/honk/CommitmentScheme.sol b/barretenberg/sol/src/honk/CommitmentScheme.sol index d5152c348ff8..4ff835271693 100644 --- a/barretenberg/sol/src/honk/CommitmentScheme.sol +++ b/barretenberg/sol/src/honk/CommitmentScheme.sol @@ -32,10 +32,15 @@ library CommitmentSchemeLib { Fr batchedEvaluation; Fr[4] denominators; Fr[4] batchingScalars; - Fr negInvertedDenominator; + // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated Fr posInvertedDenominator; - Fr scalingFactorNeg; + // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated + Fr negInvertedDenominator; + // ν^{2i} * 1/(z - r^{2^i}) Fr scalingFactorPos; + // ν^{2i+1} * 1/(z + r^{2^i}) + Fr scalingFactorNeg; + // Fold_i(r^{2^i}) reconstructed by Verifier Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; } @@ -45,8 +50,9 @@ library CommitmentSchemeLib { squares[i] = squares[i - 1].sqr(); } } + // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1 - function computeGeminiBatchedUnivariateEvaluation( + function computeFoldPosEvaluations( Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges, Fr batchedEvalAccumulator, Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations, diff --git a/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol index f6b5c071a320..8e167c64a53c 100644 --- a/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 52b5c39ccd4966230bccd3c5313992f8e8b0c4ca8120939c1a053b41d23ff61c +// Verification Key Hash: 60e7a45faded1ebd0b0c5f4af19227a38f702cc4836dd653cb3f386717e4c0ac // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library Add2UltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x52b5c39ccd4966230bccd3c5313992f8e8b0c4ca8120939c1a053b41d23ff61c; + return 0x60e7a45faded1ebd0b0c5f4af19227a38f702cc4836dd653cb3f386717e4c0ac; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { diff --git a/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol index b2b4e268ff02..eeffbdec7523 100644 --- a/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 7d146c779845c11f731974db664e09fa3d3f98c34d1a982e72f0e76a747b59fc +// Verification Key Hash: 051da9b5f32346e9d0892040b55aa70862447630aa29cecc3abe3cb74517137c // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library EcdsaUltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x7d146c779845c11f731974db664e09fa3d3f98c34d1a982e72f0e76a747b59fc; + return 0x051da9b5f32346e9d0892040b55aa70862447630aa29cecc3abe3cb74517137c; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { From 1a1a938913c9fe3ecc2eee810c6f4a93b27767c3 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Mar 2025 13:26:27 +0000 Subject: [PATCH 17/24] fix character --- .../cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index 42cd80875c85..71121deb44d3 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -1418,9 +1418,9 @@ struct ShpleminiIntermediates { Fr posInvertedDenominator; // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated Fr negInvertedDenominator; - // ν^{2i} * 1/(z - r^{2^i}) + // v^{2i} * 1/(z - r^{2^i}) Fr scalingFactorPos; - // ν^{2i+1} * 1/(z + r^{2^i}) + // v^{2i+1} * 1/(z + r^{2^i}) Fr scalingFactorNeg; // Fold_i(r^{2^i}) reconstructed by Verifier From 181d907af7efd06e62350acadb695dcfd355c91f Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Mar 2025 14:44:37 +0000 Subject: [PATCH 18/24] logN-> LOG_N --- .../barretenberg/dsl/acir_proofs/honk_contract.hpp | 14 +++++++------- .../dsl/acir_proofs/honk_zk_contract.hpp | 8 ++------ .../src/barretenberg/honk/utils/honk_key_gen.hpp | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index be0817348a09..0b9e440838e9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -1355,9 +1355,8 @@ struct ShpleminiIntermediates { Fr scalingFactorPos; // v^{2i+1} * 1/(z + r^{2^i}) Fr scalingFactorNeg; - - // Fold_i(r^{2^i}) reconstructed by Verifier - Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; + // // Fold_i(r^{2^i}) reconstructed by Verifier + // Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; } library CommitmentSchemeLib { @@ -1369,7 +1368,8 @@ library CommitmentSchemeLib { squares[i] = squares[i - 1].sqr(); } } - // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1 + + // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., m-1 function computeFoldPosEvaluations( Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges, Fr batchedEvalAccumulator, @@ -1387,15 +1387,16 @@ library CommitmentSchemeLib { ); // Divide by the denominator batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (Fr.wrap(1) - u) + u).invert(); + if (i <= logSize) { batchedEvalAccumulator = batchedEvalRoundAcc; foldPosEvaluations[i - 1] = batchedEvalRoundAcc; } } + } } - interface IVerifier { function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool); } @@ -1589,7 +1590,6 @@ abstract contract BaseHonkVerifier is IVerifier { mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); - mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); mem.shiftedScalar = tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); @@ -1658,7 +1658,7 @@ abstract contract BaseHonkVerifier is IVerifier { commitments[40] = convertProofPoint(proof.zPerm); // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: - // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., logN - 1 + // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., logN - 1 Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations( tp.sumCheckUChallenges, mem.batchedEvaluation, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index 71121deb44d3..5cf047c29aa9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -1422,10 +1422,6 @@ struct ShpleminiIntermediates { Fr scalingFactorPos; // v^{2i+1} * 1/(z + r^{2^i}) Fr scalingFactorNeg; - - // Fold_i(r^{2^i}) reconstructed by Verifier - Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; - } library CommitmentSchemeLib { @@ -1729,7 +1725,7 @@ interface IVerifier { mem.batchedEvaluation, proof.geminiAEvaluations, powers_of_evaluation_challenge, - logN + LOG_N ); mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; @@ -1740,7 +1736,7 @@ interface IVerifier { uint256 boundary = NUMBER_OF_ENTITIES + 2; for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { - bool dummy_round = i >= (logN - 1); + bool dummy_round = i >= (LOG_N - 1); if (!dummy_round) { mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); diff --git a/barretenberg/cpp/src/barretenberg/honk/utils/honk_key_gen.hpp b/barretenberg/cpp/src/barretenberg/honk/utils/honk_key_gen.hpp index 8f6b6a0a26c6..878f76be5b3c 100644 --- a/barretenberg/cpp/src/barretenberg/honk/utils/honk_key_gen.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/utils/honk_key_gen.hpp @@ -103,4 +103,4 @@ inline void output_vk_sol_ultra_honk(std::ostream& os, "}\n"; os << std::flush; -} \ No newline at end of file +} From 059fa93d2900449bc65cff9aad1edc4f5de6e9d4 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Mar 2025 15:38:45 +0000 Subject: [PATCH 19/24] update shplonkNuChallengeElements --- .../cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp | 4 ++-- .../cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index 0b9e440838e9..400b0e7b361a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -521,10 +521,10 @@ library TranscriptLib { pure returns (Fr shplonkNu, Fr nextPreviousChallenge) { - uint256[(CONST_PROOF_SIZE_LOG_N) + 1] memory shplonkNuChallengeElements; + uint256[2* (CONST_PROOF_SIZE_LOG_N) + 2] memory shplonkNuChallengeElements; shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); - for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { + for (uint256 i = 0; i < 2 * CONST_PROOF_SIZE_LOG_N + 2; i++) { shplonkNuChallengeElements[i + 1] = Fr.unwrap(proof.geminiAEvaluations[i]); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index 5cf047c29aa9..a712d4b78c6c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -574,10 +574,10 @@ library ZKTranscriptLib { pure returns (Fr shplonkNu, Fr nextPreviousChallenge) { - uint256[(CONST_PROOF_SIZE_LOG_N) + 1 + 4] memory shplonkNuChallengeElements; + uint256[2*(CONST_PROOF_SIZE_LOG_N) + 4] memory shplonkNuChallengeElements; shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); - for (uint256 i = 1; i <= CONST_PROOF_SIZE_LOG_N; i++) { + for (uint256 i = 1; i <= 2 * CONST_PROOF_SIZE_LOG_N; i++) { shplonkNuChallengeElements[i] = Fr.unwrap(proof.geminiAEvaluations[i - 1]); } From b01d919f776da64a6bc2ed8402dfb8b47ba38e33 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Mar 2025 16:08:55 +0000 Subject: [PATCH 20/24] undo last modifications --- .../cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp | 4 ++-- .../cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index 400b0e7b361a..0b9e440838e9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -521,10 +521,10 @@ library TranscriptLib { pure returns (Fr shplonkNu, Fr nextPreviousChallenge) { - uint256[2* (CONST_PROOF_SIZE_LOG_N) + 2] memory shplonkNuChallengeElements; + uint256[(CONST_PROOF_SIZE_LOG_N) + 1] memory shplonkNuChallengeElements; shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); - for (uint256 i = 0; i < 2 * CONST_PROOF_SIZE_LOG_N + 2; i++) { + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { shplonkNuChallengeElements[i + 1] = Fr.unwrap(proof.geminiAEvaluations[i]); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index a712d4b78c6c..5cf047c29aa9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -574,10 +574,10 @@ library ZKTranscriptLib { pure returns (Fr shplonkNu, Fr nextPreviousChallenge) { - uint256[2*(CONST_PROOF_SIZE_LOG_N) + 4] memory shplonkNuChallengeElements; + uint256[(CONST_PROOF_SIZE_LOG_N) + 1 + 4] memory shplonkNuChallengeElements; shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); - for (uint256 i = 1; i <= 2 * CONST_PROOF_SIZE_LOG_N; i++) { + for (uint256 i = 1; i <= CONST_PROOF_SIZE_LOG_N; i++) { shplonkNuChallengeElements[i] = Fr.unwrap(proof.geminiAEvaluations[i - 1]); } From f87162715eb3531cd440b684967d9bf3eb08c4c1 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Mar 2025 16:17:43 +0000 Subject: [PATCH 21/24] fix tests --- .../cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp | 1 + .../cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index 0b9e440838e9..d99bce8b5864 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -1671,6 +1671,7 @@ abstract contract BaseHonkVerifier is IVerifier { mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; mem.constantTermAccumulator = mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + mem.batchingChallenge = tp.shplonkNu.sqr(); // Compute Shplonk constant term contributions from Aₗ(±r^{2ˡ}) for l = 1, ..., m-1; // Compute scalar multipliers for each fold commitment diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index 5cf047c29aa9..9d7420e8f825 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -1766,8 +1766,6 @@ interface IVerifier { mem.denominators[3] = mem.denominators[0]; mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; - - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; for (uint256 i = 0; i < 4; i++) { Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; mem.batchingScalars[i] = scalingFactor.neg(); From 147c36d8a71d51403e41e8e578c43d1da52db7a8 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Mar 2025 18:46:21 +0000 Subject: [PATCH 22/24] docs --- .../commitment_schemes/gemini/gemini.hpp | 2 +- .../commitment_schemes/gemini/gemini_impl.hpp | 3 +- .../commitment_schemes/shplonk/shplemini.hpp | 20 +++++++--- .../commitment_schemes/shplonk/shplonk.hpp | 40 ++++++++++++++----- .../cpp/src/barretenberg/constants.hpp | 2 +- .../dsl/acir_proofs/honk_contract.hpp | 6 +++ .../dsl/acir_proofs/honk_zk_contract.hpp | 9 ++++- .../sol/src/honk/BaseHonkVerifier.sol | 6 +++ .../sol/src/honk/BaseZKHonkVerifier.sol | 11 ++++- .../ultra/keys/Add2UltraVerificationKey.sol | 4 +- .../ultra/keys/BlakeUltraVerificationKey.sol | 4 +- .../ultra/keys/EcdsaUltraVerificationKey.sol | 4 +- 12 files changed, 84 insertions(+), 27 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index 9318b4ac4713..4af3fdb5f559 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -570,7 +570,7 @@ template class GeminiVerifier_ { value_to_emplace = Fr::conditional_assign(dummy_round, zero, eval_pos_prev); } else { - // Perform the same logic as above natively + // Perform the same logic natively bool dummy_round = l > num_variables; eval_pos_prev = dummy_round ? eval_pos_prev : eval_pos; value_to_emplace = dummy_round ? zero : eval_pos_prev; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp index dc1a9aaf7ce3..a4cd886555c8 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp @@ -222,6 +222,7 @@ std::vector::Claim> GeminiProver_::construc const Fr& r_challenge) { std::vector claims; + // Compute evaluation of partially evaluated batch polynomial (positive) A₀₊(r) Fr a_0_pos = A_0_pos.evaluate(r_challenge); claims.emplace_back(Claim{ std::move(A_0_pos), { r_challenge, a_0_pos } }); @@ -233,7 +234,7 @@ std::vector::Claim> GeminiProver_::construc std::vector r_squares = gemini::powers_of_evaluation_challenge(r_challenge, log_n); // Each fold polynomial Aₗ has to be opened at −r^{2ˡ} and r^{2ˡ}. To avoid storing two copies of Aₗ for l = 0,..., - // m-1, we use a flag that is processed by ShplonkProver.. + // m-1, we use a flag that is processed by ShplonkProver. const bool gemini_fold = true; // Compute the remaining m opening pairs {−r^{2ˡ}, Aₗ(−r^{2ˡ})}, l = 1, ..., m-1. diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index ba9a12781325..701922544894 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -264,6 +264,8 @@ template class ShpleminiVerifier_ { // - Get Shplonk batching challenge const Fr shplonk_batching_challenge = transcript->template get_challenge("Shplonk:nu"); + // Compute the powers of ν that are required for batching Gemini, SmallSubgroupIPA, and committed sumcheck + // univariate opening claims. const std::vector shplonk_batching_challenge_powers = compute_shplonk_batching_challenge_powers(shplonk_batching_challenge, has_zk, committed_sumcheck); // - Get the quotient commitment for the Shplonk batching of Gemini opening claims @@ -326,8 +328,12 @@ template class ShpleminiVerifier_ { Fr shplonk_batching_pos = Fr{ 0 }; Fr shplonk_batching_neg = Fr{ 0 }; if (claim_batcher.interleaved) { - shplonk_batching_pos = shplonk_batching_challenge_powers[2 * log_circuit_size]; - shplonk_batching_neg = shplonk_batching_challenge_powers[2 * log_circuit_size + 1]; + // Currently, the prover places the Interleaving claims before the Gemini dummy claims. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1293): Decouple Gemini from Interleaving. + const size_t interleaved_pos_index = 2 * log_circuit_size; + const size_t interleaved_neg_index = interleaved_pos_index + 1; + shplonk_batching_pos = shplonk_batching_challenge_powers[interleaved_pos_index]; + shplonk_batching_neg = shplonk_batching_challenge_powers[interleaved_neg_index]; constant_term_accumulator += p_pos * interleaving_vanishing_eval * shplonk_batching_pos + p_neg * interleaving_vanishing_eval * shplonk_batching_neg; } @@ -340,7 +346,9 @@ template class ShpleminiVerifier_ { shplonk_batching_pos, shplonk_batching_neg); - // Compute A₀(r) = A₀₊(r) + P₊(r^s) + // Reconstruct Aᵢ(r²ⁱ) for i=0, ..., n-1 from the batched evaluation of the multilinear polynomials and Aᵢ(−r²ⁱ) + // for i = 0, ..., n-1. + // In the case of interleaving, we compute A₀(r) as A₀₊(r) + P₊(r^s). const std::vector gemini_fold_pos_evaluations = GeminiVerifier_::compute_fold_pos_evaluations(log_circuit_size, batched_evaluation, @@ -457,14 +465,16 @@ template class ShpleminiVerifier_ { // TODO(https://github.com/AztecProtocol/barretenberg/issues/1159): Decouple constants from primitives. for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N - 1; ++j) { - // Compute the scaling factor (ν²⁺ⁱ) / (z + r²⁽ⁱ⁺²⁾) for i = 0, … , d-2 + // Compute the "positive" scaling factor (ν^{2j+1}) / (z - r^{2^{j}}) size_t pos_location = 2 * j + 2; Fr scaling_factor_pos = shplonk_batching_challenge_powers[pos_location] * inverse_vanishing_evals[pos_location]; + // Compute the "negative" scaling factor (ν^{2j+2}) / (z + r^{2^{j}}) Fr scaling_factor_neg = shplonk_batching_challenge_powers[pos_location + 1] * inverse_vanishing_evals[pos_location + 1]; - // Add Aᵢ(−r²ⁱ) for i = 1, … , n-1 to the constant term accumulator + // Accumulate the const term contribution given by + // v^{2j+1} * A_j(r^{2^j}) /(z-r^{2^j}) + v^{2j+2} * A_j(-r^{2^j}) /(z+ r^{2^j}) constant_term_accumulator += scaling_factor_neg * gemini_evaluations[j + 1] + scaling_factor_pos * gemini_fold_pos_evaluations[j + 1]; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index 25a2ab184a11..a8a20b30982d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -172,7 +172,7 @@ template class ShplonkProver_ { if (claim.gemini_fold) { tmp = claim.polynomial; tmp.at(0) = tmp[0] - gemini_fold_pos_evaluations[fold_idx++]; - Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ ) // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) G.add_scaled(tmp, -scaling_factor); @@ -181,12 +181,13 @@ template class ShplonkProver_ { // tmp = νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) tmp = claim.polynomial; tmp.at(0) = tmp[0] - claim.opening_pair.evaluation; - Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ ) // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) G.add_scaled(tmp, -scaling_factor); current_nu *= nu_challenge; + idx++; } // Take into account the constant proof size in Gemini @@ -196,26 +197,34 @@ 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; - Fr scaling_factor = current_nu * inverse_vanishing_evals[idx++]; // = νʲ / (z − xⱼ ) + 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; } 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ⱼ ) + 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() } }; }; - + /** + * @brief Compute evaluations of fold polynomials Fold_i at r^{2^i} for i>0. + * TODO(https://github.com/AztecProtocol/barretenberg/issues/1223): Reconsider minor performance/memory + * optimizations in Gemini. + * @param opening_claims + * @return std::vector + */ static std::vector compute_gemini_fold_pos_evaluations( std::span> opening_claims) { @@ -224,7 +233,9 @@ template class ShplonkProver_ { for (const auto& claim : opening_claims) { if (claim.gemini_fold) { + // -r^{2^i} is stored in the claim const Fr evaluation_point = -claim.opening_pair.challenge; + // Compute Fold_i(r^{2^i}) const Fr evaluation = claim.polynomial.evaluate(evaluation_point); gemini_fold_pos_evaluations.emplace_back(evaluation); } @@ -250,6 +261,7 @@ template class ShplonkProver_ { { const Fr nu = transcript->template get_challenge("Shplonk:nu"); + // Compute the evaluations Fold_i(r^{2^i}) for i>0. std::vector gemini_fold_pos_evaluations = compute_gemini_fold_pos_evaluations(opening_claims); auto batched_quotient = compute_batched_quotient( @@ -402,13 +414,13 @@ template class ShplonkVerifier_ { return { { z_challenge, evaluation }, G_commitment }; }; /** - * @brief Computes \f$ \frac{1}{z + r}, \frac{1}{z-r}, \ldots, \frac{1}{z+r^{2^{d-1}}}, \frac{1}{z-r^{2^{d-1}}} \f$. + * @brief Computes \f$ \frac{1}{z - r}, \frac{1}{z + r}, \ldots, \frac{1}{z - r^{2^{d-1}}}, \frac{1}{z + + * r^{2^{d-1}}} \f$. * - * @param num_gemini_claims \f$ d + 1 \f$ where d = log_circuit_size * @param shplonk_eval_challenge \f$ z \f$ * @param gemini_eval_challenge_powers \f$ (r , r^2, \ldots, r^{2^{d-1}}) \f$ - * @return \f[ \left( \frac{1}{z + r}, \frac{1}{z-r}, \ldots, \frac{1}{z+r^{2^{d-1}}}, \frac{1}{z-r^{2^{d-1}}} - * \right) \f] + * @return \f[ \left( \frac{1}{z - r}, \frac{1}{z + r}, \ldots, \frac{1}{z - r^{2^{d-1}}}, \frac{1}{z + + * r^{2^{d-1}}} \right) \f] */ static std::vector compute_inverted_gemini_denominators(const Fr& shplonk_eval_challenge, const std::vector& gemini_eval_challenge_powers) @@ -434,19 +446,27 @@ template class ShplonkVerifier_ { } }; +/** + * @brief A helper used by Shplemini Verifier. Precomputes a vector of the powers of \f$ \nu \f$ needed to batch all + * univariate claims. + * + */ template static std::vector compute_shplonk_batching_challenge_powers(const Fr& shplonk_batching_challenge, bool has_zk = false, bool committed_sumcheck = false) { size_t num_powers = NUM_GEMINI_CLAIMS; + // Each round univariate is opened at 0, 1, and a round challenge. + static constexpr size_t NUM_COMMITTED_SUMCHECK_CLAIMS_PER_ROUND = 3; + // Shplonk evaluation and batching challenges are re-used in SmallSubgroupIPA. if (has_zk) { num_powers += NUM_SMALL_IPA_EVALUATIONS; } if (committed_sumcheck) { - num_powers += 3 * CONST_PROOF_SIZE_LOG_N; + num_powers += NUM_COMMITTED_SUMCHECK_CLAIMS_PER_ROUND * CONST_PROOF_SIZE_LOG_N; } std::vector result; diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 18c826cd831c..7f8959b5e312 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -34,6 +34,6 @@ static constexpr uint32_t NUM_TRANSLATION_EVALUATIONS = 5; // Upper bound on the number of claims produced GeminiProver: // - Each fold polynomial is opened at two points, the number of resulting claims is bounded by 2*CONST_PROOF_SIZE_LOG_N // - The interleaving trick needed for Translator adds 2 extra claims -// TODO() +// TODO(https://github.com/AztecProtocol/barretenberg/issues/1293): Decouple Gemini from Interleaving static constexpr uint32_t NUM_GEMINI_CLAIMS = 2 * CONST_PROOF_SIZE_LOG_N + 2; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index d99bce8b5864..97dfd3057212 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -1679,16 +1679,22 @@ abstract contract BaseHonkVerifier is IVerifier { bool dummy_round = i >= (logN - 1); if (!dummy_round) { + // Update inverted denominators mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; + // [Aₗ] is multiplied by -v^{2l}/(z-r^{2^l}) - v^{2l+1} /(z+ r^{2^l}) scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + // Accumulate the const term contribution given by + // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + // Update the running power of v mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index 9d7420e8f825..d540e8463826 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -1735,22 +1735,28 @@ interface IVerifier { mem.batchingChallenge = tp.shplonkNu.sqr(); uint256 boundary = NUMBER_OF_ENTITIES + 2; + // Compute Shplonk constant term contributions from Aₗ(± r^{2ˡ}) for l = 1, ..., m-1; + // Compute scalar multipliers for each fold commitment for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { bool dummy_round = i >= (LOG_N - 1); if (!dummy_round) { + // Update inverted denominators mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + // Accumulate the const term contribution given by + // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; } - + // Update the running power of v mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; commitments[boundary + i] = convertProofPoint(proof.geminiFoldComms[i]); @@ -1765,6 +1771,7 @@ interface IVerifier { mem.denominators[2] = mem.denominators[0]; mem.denominators[3] = mem.denominators[0]; + // Artifact of interleaving, see TODO(https://github.com/AztecProtocol/barretenberg/issues/1293): Decouple Gemini from Interleaving mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; for (uint256 i = 0; i < 4; i++) { Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index 8b6fb9105870..9ecafd76207a 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -354,16 +354,22 @@ abstract contract BaseHonkVerifier is IVerifier { bool dummy_round = i >= (logN - 1); if (!dummy_round) { + // Update inverted denominators mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; + // [Aₗ] is multiplied by -v^{2l}/(z-r^{2^l}) - v^{2l+1} /(z+ r^{2^l}) scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + // Accumulate the const term contribution given by + // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + // Update the running power of v mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; } diff --git a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol index 12c7f3babcc3..6cc6a472578b 100644 --- a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol @@ -333,7 +333,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { */ // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: - // Compute evaluation A₀(r) + // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., logN - 1 Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = PCS.computeFoldPosEvaluations( tp.sumCheckUChallenges, mem.batchedEvaluation, @@ -349,22 +349,28 @@ abstract contract BaseZKHonkVerifier is IVerifier { mem.batchingChallenge = tp.shplonkNu.sqr(); uint256 boundary = NUMBER_OF_ENTITIES + 2; + // Compute Shplonk constant term contributions from Aₗ(± r^{2ˡ}) for l = 1, ..., m-1; + // Compute scalar multipliers for each fold commitment for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { bool dummy_round = i >= (logN - 1); if (!dummy_round) { + // Update inverted denominators mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + // Accumulate the const term contribution given by + // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; } - + // Update the running power of v mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; commitments[boundary + i] = convertProofPoint(proof.geminiFoldComms[i]); @@ -378,6 +384,7 @@ abstract contract BaseZKHonkVerifier is IVerifier { mem.denominators[2] = mem.denominators[0]; mem.denominators[3] = mem.denominators[0]; + // Artifact of interleaving, see TODO(https://github.com/AztecProtocol/barretenberg/issues/1293): Decouple Gemini from Interleaving mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; for (uint256 i = 0; i < LIBRA_EVALUATIONS; i++) { Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; diff --git a/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol index 8e167c64a53c..89c44572fbbe 100644 --- a/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/Add2UltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 60e7a45faded1ebd0b0c5f4af19227a38f702cc4836dd653cb3f386717e4c0ac +// Verification Key Hash: 594d0af354947ea7aa13eece55ec3ccdce54dff437d9354a8a50cb2a0438a86a // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library Add2UltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x60e7a45faded1ebd0b0c5f4af19227a38f702cc4836dd653cb3f386717e4c0ac; + return 0x594d0af354947ea7aa13eece55ec3ccdce54dff437d9354a8a50cb2a0438a86a; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { diff --git a/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol index ffd447c56fa0..d81948a7761b 100644 --- a/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 3e90f6833288b5b3f8c6006ddff945b552ee9e6b00f3e047b1cb50927248e165 +// Verification Key Hash: 4dd3c85ec6b387fe6e6b3dc9b4eb16c522fec0c8b0e6bdc6b34bf32af822b2d8 // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library BlakeUltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x3e90f6833288b5b3f8c6006ddff945b552ee9e6b00f3e047b1cb50927248e165; + return 0x4dd3c85ec6b387fe6e6b3dc9b4eb16c522fec0c8b0e6bdc6b34bf32af822b2d8; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { diff --git a/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol index eeffbdec7523..b2b4e268ff02 100644 --- a/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 051da9b5f32346e9d0892040b55aa70862447630aa29cecc3abe3cb74517137c +// Verification Key Hash: 7d146c779845c11f731974db664e09fa3d3f98c34d1a982e72f0e76a747b59fc // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library EcdsaUltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x051da9b5f32346e9d0892040b55aa70862447630aa29cecc3abe3cb74517137c; + return 0x7d146c779845c11f731974db664e09fa3d3f98c34d1a982e72f0e76a747b59fc; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { From d8e1fded8116cd2fd78a3f8a10bbef7b0c0151e9 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Mar 2025 20:32:59 +0000 Subject: [PATCH 23/24] fix missing counter update --- .../src/barretenberg/commitment_schemes/shplonk/shplonk.hpp | 1 + barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol | 4 ++-- barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index a8a20b30982d..d70b9e05ee18 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -177,6 +177,7 @@ template class ShplonkProver_ { G.add_scaled(tmp, -scaling_factor); current_nu *= nu_challenge; + idx++; } // tmp = νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) tmp = claim.polynomial; diff --git a/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol index d81948a7761b..6bf25e6238fb 100644 --- a/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/BlakeUltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 4dd3c85ec6b387fe6e6b3dc9b4eb16c522fec0c8b0e6bdc6b34bf32af822b2d8 +// Verification Key Hash: 6c68aa62aa452a4dbb84e1246b10262e6fb6ff860b59d906db6fb0807d11b872 // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library BlakeUltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x4dd3c85ec6b387fe6e6b3dc9b4eb16c522fec0c8b0e6bdc6b34bf32af822b2d8; + return 0x6c68aa62aa452a4dbb84e1246b10262e6fb6ff860b59d906db6fb0807d11b872; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { diff --git a/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol b/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol index b2b4e268ff02..29b3cd73f1a9 100644 --- a/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol +++ b/barretenberg/sol/src/ultra/keys/EcdsaUltraVerificationKey.sol @@ -1,11 +1,11 @@ -// Verification Key Hash: 7d146c779845c11f731974db664e09fa3d3f98c34d1a982e72f0e76a747b59fc +// Verification Key Hash: 543ba4bb3b055949d65bec2da67f0c096105b2fbde342418408e48a04c96b193 // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library EcdsaUltraVerificationKey { function verificationKeyHash() internal pure returns (bytes32) { - return 0x7d146c779845c11f731974db664e09fa3d3f98c34d1a982e72f0e76a747b59fc; + return 0x543ba4bb3b055949d65bec2da67f0c096105b2fbde342418408e48a04c96b193; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { From 62a02b6826225b3d8872373a8cc721e33b4ec12b Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 18 Mar 2025 12:21:25 +0000 Subject: [PATCH 24/24] docs improvements + minor simplification after review --- .../commitment_schemes/gemini/gemini_impl.hpp | 2 +- .../commitment_schemes/shplonk/shplemini.hpp | 80 +++++++++++-------- .../commitment_schemes/shplonk/shplonk.hpp | 4 +- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp index a4cd886555c8..cc40f4308f5a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp @@ -233,7 +233,7 @@ std::vector::Claim> GeminiProver_::construc // Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, ..., m-1 std::vector r_squares = gemini::powers_of_evaluation_challenge(r_challenge, log_n); - // Each fold polynomial Aₗ has to be opened at −r^{2ˡ} and r^{2ˡ}. To avoid storing two copies of Aₗ for l = 0,..., + // Each fold polynomial Aₗ has to be opened at −r^{2ˡ} and r^{2ˡ}. To avoid storing two copies of Aₗ for l = 1,..., // m-1, we use a flag that is processed by ShplonkProver. const bool gemini_fold = true; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 701922544894..ab23b0e76fb8 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -418,11 +418,11 @@ template class ShpleminiVerifier_ { }; /** - * @brief Populates the 'commitments' and 'scalars' vectors with the commitments to Gemini fold polynomials \f$ - * A_i \f$. + * @brief Place fold polynomial commitments to `commitments` and compute the corresponding scalar multipliers. * - * @details Once the commitments to Gemini "fold" polynomials \f$ A_i \f$ and their evaluations at \f$ -r^{2^i} - * \f$, where \f$ i = 1, \ldots, n-1 \f$, are received by the verifier, it performs the following operations: + * @details Once the commitments to Gemini "fold" polynomials \f$ A_i \f$ and their negative evaluations, i.e. \f$ + * A_i(-r^{2^i}) \f$, for \f$ i = 1, \ldots, n-1 \f$, are obtained, and the verifier has reconstructed the positive + * fold evaluation \f$ A_i(r^{2^i}) \f$ for \f$ i=1, \ldots, n - 1 \f$, it performs the following operations: * * 1. Moves the vector * \f[ @@ -430,32 +430,38 @@ template class ShpleminiVerifier_ { * \f] * to the 'commitments' vector. * - * 2. Computes the scalars: - * \f[ - * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}} - * \f] - * and places them into the 'scalars' vector. + * 2. Computes the scalars + * \f{align}{ + * \frac{\nu^2}{z - r^2} + \frac{\nu^3}{z + r^2}, + * \frac{\nu^4}{z - r^4} + \frac{\nu^5}{z + r^4}, + * \ldots, + * \frac{\nu^{2 \cdot n} } {z - r^{2^{n-1}}} + \frac{\nu^{2 \cdot n + 1}}{z + r^{2^{n-1}}}. \f} + * The commitments \f$ [A_1]_1, \ldots, [A_{n-1}]_1 \f$ are multiplied by these scalars in the final `batch_mul` + * perfomed by KZG or IPA. * * 3. Accumulates the summands of the constant term: - * \f[ - * \sum_{i=2}^{n-1} \frac{\nu^{i} \cdot A_i(-r^{2^i})}{z + r^{2^i}} - * \f] - * and adds them to the 'constant_term_accumulator'. + * \f{align}{ + * \frac{\nu^{2 i} \cdot A_i\left(r^{2^i} \right)}{z - r^{2^i}} + \frac{\nu^{2 \cdot i+1} \cdot + * A_i\left(-r^{2^i}\right)}{z+ r^{2^i}} \f} for \f$ i = 1, \ldots, n-1 \f$ and adds them to the + * 'constant_term_accumulator'. * * @param log_circuit_size The logarithm of the circuit size, determining the depth of the Gemini protocol. * @param fold_commitments A vector containing the commitments to the Gemini fold polynomials \f$ A_i \f$. - * @param gemini_evaluations A vector containing the evaluations of the Gemini fold polynomials \f$ A_i \f$ at - * points \f$ -r^{2^i} \f$. - * @param inverse_vanishing_evals A vector containing the inverse evaluations of the vanishing polynomial. - * @param shplonk_batching_challenge The batching challenge \f$ \nu \f$ used in the SHPLONK protocol. + * @param gemini_neg_evaluations The evaluations of Gemini fold polynomials \f$ A_i \f$ at \f$ -r^{2^i} \f$ for \f$ + * i = 0, \ldots, n - 1 \f$. + * @param gemini_pos_evaluations The evaluations of Gemini fold polynomials \f$ A_i \f$ at \f$ r^{2^i} \f$ for \f$ + * i = 0, \ldots, n - 1 \f$ + * @param inverse_vanishing_evals \f$ 1/(z − r), 1/(z + r), 1/(z - r^2), 1/(z + r^2), \ldots, 1/(z - r^{2^{n-1}}), + * 1/(z + r^{2^{n-1}}) \f$ + * @param shplonk_batching_challenge_powers A vector of powers of \f$ \nu \f$ used to batch all univariate claims. * @param commitments Output vector where the commitments to the Gemini fold polynomials will be stored. * @param scalars Output vector where the computed scalars will be stored. - * @param constant_term_accumulator The accumulator for the summands of the constant term. + * @param constant_term_accumulator The accumulator for the summands of the Shplonk constant term. */ static void batch_gemini_claims_received_from_prover(const size_t log_circuit_size, const std::vector& fold_commitments, - const std::vector& gemini_evaluations, - const std::vector& gemini_fold_pos_evaluations, + const std::vector& gemini_neg_evaluations, + const std::vector& gemini_pos_evaluations, const std::vector& inverse_vanishing_evals, const std::vector& shplonk_batching_challenge_powers, std::vector& commitments, @@ -464,29 +470,33 @@ template class ShpleminiVerifier_ { { // TODO(https://github.com/AztecProtocol/barretenberg/issues/1159): Decouple constants from primitives. - for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N - 1; ++j) { - // Compute the "positive" scaling factor (ν^{2j+1}) / (z - r^{2^{j}}) - size_t pos_location = 2 * j + 2; - Fr scaling_factor_pos = - shplonk_batching_challenge_powers[pos_location] * inverse_vanishing_evals[pos_location]; - // Compute the "negative" scaling factor (ν^{2j+2}) / (z + r^{2^{j}}) - Fr scaling_factor_neg = - shplonk_batching_challenge_powers[pos_location + 1] * inverse_vanishing_evals[pos_location + 1]; + // Start from 1, because the commitment to A_0 is reconstructed from the commitments to the multilinear + // polynomials. The corresponding evaluations are also handled separately. + for (size_t j = 1; j < CONST_PROOF_SIZE_LOG_N; ++j) { + // The index of 1/ (z - r^{2^{j}}) in the vector of inverted Gemini denominators + const size_t pos_index = 2 * j; + // The index of 1/ (z + r^{2^{j}}) in the vector of inverted Gemini denominators + const size_t neg_index = 2 * j + 1; + + // Compute the "positive" scaling factor (ν^{2j}) / (z - r^{2^{j}}) + Fr scaling_factor_pos = shplonk_batching_challenge_powers[pos_index] * inverse_vanishing_evals[pos_index]; + // Compute the "negative" scaling factor (ν^{2j+1}) / (z + r^{2^{j}}) + Fr scaling_factor_neg = shplonk_batching_challenge_powers[neg_index] * inverse_vanishing_evals[neg_index]; // Accumulate the const term contribution given by - // v^{2j+1} * A_j(r^{2^j}) /(z-r^{2^j}) + v^{2j+2} * A_j(-r^{2^j}) /(z+ r^{2^j}) - constant_term_accumulator += scaling_factor_neg * gemini_evaluations[j + 1] + - scaling_factor_pos * gemini_fold_pos_evaluations[j + 1]; + // v^{2j} * A_j(r^{2^j}) /(z - r^{2^j}) + v^{2j+1} * A_j(-r^{2^j}) /(z+ r^{2^j}) + constant_term_accumulator += + scaling_factor_neg * gemini_neg_evaluations[j] + scaling_factor_pos * gemini_pos_evaluations[j]; if constexpr (Curve::is_stdlib_type) { - auto builder = gemini_evaluations[0].get_context(); + auto builder = gemini_neg_evaluations[0].get_context(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! - stdlib::bool_t dummy_round = stdlib::witness_t(builder, j >= (log_circuit_size - 1)); + stdlib::bool_t dummy_round = stdlib::witness_t(builder, j >= log_circuit_size); Fr zero = Fr(0); scaling_factor_neg = Fr::conditional_assign(dummy_round, zero, scaling_factor_neg); scaling_factor_pos = Fr::conditional_assign(dummy_round, zero, scaling_factor_pos); } else { - if (j >= (log_circuit_size - 1)) { + if (j >= log_circuit_size) { scaling_factor_neg = 0; scaling_factor_pos = 0; } @@ -494,7 +504,7 @@ template class ShpleminiVerifier_ { // Place the scaling factor to the 'scalars' vector scalars.emplace_back(-scaling_factor_neg - scaling_factor_pos); // Move com(Aᵢ) to the 'commitments' vector - commitments.emplace_back(std::move(fold_commitments[j])); + commitments.emplace_back(std::move(fold_commitments[j - 1])); } } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index d70b9e05ee18..0bac8b1dca4c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -86,7 +86,9 @@ template class ShplonkProver_ { } // We use the same batching challenge for Gemini and Libra opening claims. The number of the claims - // batched before adding Libra commitments and evaluations is bounded by CONST_PROOF_SIZE_LOG_N+2 + // batched before adding Libra commitments and evaluations is bounded by 2 * CONST_PROOF_SIZE_LOG_N + 2, where + // 2 * CONST_PROOF_SIZE_LOG_N is the number of fold claims including the dummy ones, and +2 is reserved for + // interleaving. current_nu = nu.pow(NUM_GEMINI_CLAIMS); for (const auto& claim : libra_opening_claims) {