From 2dfa8f7fc4534a21999075ca58184193bad9cce4 Mon Sep 17 00:00:00 2001 From: maramihali Date: Thu, 26 Sep 2024 17:57:42 +0100 Subject: [PATCH] feat: make shplemini proof constant (#8826) Make Shplemini proofs constant using the same approach as in other places, add relevant github issues for handling the dummy rounds properly, make the shplemini recursion test do full verification and ensure recursive shplemini verifiers actually stay constant. --- .../commitment_schemes/gemini/gemini.hpp | 55 ++++-- .../commitment_schemes/gemini/gemini_impl.hpp | 18 +- .../commitment_schemes/shplonk/shplemini.hpp | 33 +++- .../shplonk/shplemini.test.cpp | 1 - .../commitment_schemes/shplonk/shplonk.hpp | 64 ++++--- .../zeromorph/zeromorph.hpp | 3 +- .../shplemini.test.cpp | 179 ++++++++++-------- .../src/barretenberg/sumcheck/sumcheck.hpp | 1 + 8 files changed, 217 insertions(+), 137 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index 0766722893e..61b0d36b5d3 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -95,6 +95,7 @@ template inline std::vector powers_of_evaluation_challenge(const template class GeminiProver_ { using Fr = typename Curve::ScalarField; + using Commitment = typename Curve::AffineElement; using Polynomial = bb::Polynomial; using Claim = ProverOpeningClaim; @@ -168,7 +169,7 @@ template class GeminiVerifier_ { // compute vector of powers of random evaluation point r const Fr r = transcript->template get_challenge("Gemini:r"); - const std::vector r_squares = gemini::powers_of_evaluation_challenge(r, num_variables); + const std::vector r_squares = gemini::powers_of_evaluation_challenge(r, CONST_PROOF_SIZE_LOG_N); // Get evaluations a_i, i = 0,...,m-1 from transcript const std::vector evaluations = get_gemini_evaluations(num_variables, transcript); @@ -197,22 +198,24 @@ template class GeminiVerifier_ { return fold_polynomial_opening_claims; } - static std::vector get_fold_commitments(const size_t log_circuit_size, auto& transcript) + static std::vector get_fold_commitments([[maybe_unused]] const size_t log_circuit_size, + auto& transcript) { std::vector fold_commitments; - fold_commitments.reserve(log_circuit_size - 1); - for (size_t i = 0; i < log_circuit_size - 1; ++i) { + fold_commitments.reserve(CONST_PROOF_SIZE_LOG_N - 1); + for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { const Commitment commitment = transcript->template receive_from_prover("Gemini:FOLD_" + std::to_string(i + 1)); fold_commitments.emplace_back(commitment); } return fold_commitments; } - static std::vector get_gemini_evaluations(const size_t log_circuit_size, auto& transcript) + static std::vector get_gemini_evaluations([[maybe_unused]] const size_t log_circuit_size, auto& transcript) { std::vector gemini_evaluations; - gemini_evaluations.reserve(log_circuit_size); - for (size_t i = 1; i <= log_circuit_size; ++i) { + gemini_evaluations.reserve(CONST_PROOF_SIZE_LOG_N); + + for (size_t i = 1; i <= CONST_PROOF_SIZE_LOG_N; ++i) { const Fr evaluation = transcript->template receive_from_prover("Gemini:a_" + std::to_string(i)); gemini_evaluations.emplace_back(evaluation); } @@ -241,29 +244,43 @@ 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(size_t evaluation_point_size, - Fr& batched_eval_accumulator, - std::span evaluation_point, - std::span challenge_powers, - std::span fold_polynomial_evals) + static Fr compute_gemini_batched_univariate_evaluation( + const size_t num_variables, + Fr& batched_eval_accumulator, + std::span evaluation_point, // CONST_PROOF_SIZE + std::span challenge_powers, // r_squares CONST_PROOF_SIZE_LOG_N + std::span fold_polynomial_evals) { - const size_t num_variables = evaluation_point_size; - const auto& evals = fold_polynomial_evals; // Solve the sequence of linear equations - for (size_t l = num_variables; l != 0; --l) { + for (size_t l = CONST_PROOF_SIZE_LOG_N; l != 0; --l) { // Get r²⁽ˡ⁻¹⁾ const Fr& challenge_power = challenge_powers[l - 1]; - // Get A₍ₗ₋₁₎(−r²⁽ˡ⁻¹⁾) - const Fr& eval_neg = evals[l - 1]; // Get uₗ₋₁ const Fr& u = evaluation_point[l - 1]; + const Fr& eval_neg = evals[l - 1]; + // Get A₍ₗ₋₁₎(−r²⁽ˡ⁻¹⁾) // Compute the numerator - batched_eval_accumulator = + Fr batched_eval_round_acc = ((challenge_power * batched_eval_accumulator * 2) - eval_neg * (challenge_power * (Fr(1) - u) - u)); // Divide by the denominator - batched_eval_accumulator *= (challenge_power * (Fr(1) - u) + u).invert(); + batched_eval_round_acc *= (challenge_power * (Fr(1) - u) + u).invert(); + + bool is_dummy_round = (l > num_variables); + + if constexpr (Curve::is_stdlib_type) { + auto builder = evaluation_point[0].get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! + stdlib::bool_t dummy_round = stdlib::bool_t(builder, is_dummy_round); + batched_eval_accumulator = + Fr::conditional_assign(dummy_round, batched_eval_accumulator, batched_eval_round_acc); + + } else { + if (!is_dummy_round) { + batched_eval_accumulator = batched_eval_round_acc; + } + } } return batched_eval_accumulator; 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 05a1cd99447..fde94fdcdb1 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp @@ -73,15 +73,23 @@ std::vector::Claim> GeminiProver_::prove( auto fold_polynomials = compute_fold_polynomials( log_n, multilinear_challenge, std::move(batched_unshifted), std::move(batched_to_be_shifted)); - for (size_t l = 0; l < log_n - 1; l++) { - transcript->send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1), - commitment_key->commit(fold_polynomials[l + 2])); + for (size_t l = 0; l < CONST_PROOF_SIZE_LOG_N - 1; l++) { + if (l < log_n - 1) { + transcript->send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1), + commitment_key->commit(fold_polynomials[l + 2])); + } else { + transcript->send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1), Commitment::one()); + } } const Fr r_challenge = transcript->template get_challenge("Gemini:r"); std::vector claims = compute_fold_polynomial_evaluations(log_n, std::move(fold_polynomials), r_challenge); - for (size_t l = 1; l <= log_n; l++) { - transcript->send_to_verifier("Gemini:a_" + std::to_string(l), claims[l].opening_pair.evaluation); + for (size_t l = 1; l <= CONST_PROOF_SIZE_LOG_N; l++) { + if (l <= log_n) { + transcript->send_to_verifier("Gemini:a_" + std::to_string(l), claims[l].opening_pair.evaluation); + } else { + transcript->send_to_verifier("Gemini:a_" + std::to_string(l), Fr::zero()); + } } 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 98f4aa22147..e39b61292a3 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -128,9 +128,9 @@ 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(log_circuit_size, transcript); - // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size + // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size, I think this should be CONST_PROOF_SIZE const std::vector gemini_eval_challenge_powers = - gemini::powers_of_evaluation_challenge(gemini_evaluation_challenge, log_circuit_size); + gemini::powers_of_evaluation_challenge(gemini_evaluation_challenge, CONST_PROOF_SIZE_LOG_N); // Process Shplonk transcript data: // - Get Shplonk batching challenge @@ -143,7 +143,7 @@ template class ShpleminiVerifier_ { // Get Shplonk opening point z const Fr shplonk_evaluation_challenge = transcript->template get_challenge("Shplonk:z"); // Start computing the scalar to be multiplied by [1]₁ - Fr constant_term_accumulator{ 0 }; + Fr constant_term_accumulator = Fr(0); // Initialize the vector of scalars placing the scalar 1 correposnding to Q_commitment std::vector scalars; @@ -167,7 +167,7 @@ template class ShpleminiVerifier_ { // Place the commitments to prover polynomials in the commitments vector. Compute the evaluation of the // batched multilinear polynomial. Populate the vector of scalars for the final batch mul - Fr batched_evaluation{ 0 }; + Fr batched_evaluation = Fr(0); batch_multivariate_opening_claims(unshifted_commitments, shifted_commitments, unshifted_evaluations, @@ -334,17 +334,34 @@ template class ShpleminiVerifier_ { std::vector& scalars, Fr& constant_term_accumulator) { + // Initialize batching challenge as ν² - Fr current_batching_challenge = shplonk_batching_challenge * shplonk_batching_challenge; - for (size_t j = 0; j < log_circuit_size - 1; ++j) { + Fr current_batching_challenge = shplonk_batching_challenge.sqr(); + for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N - 1; ++j) { + bool is_dummy_round = j >= (log_circuit_size - 1); // Compute the scaling factor (ν²⁺ⁱ) / (z + r²⁽ⁱ⁺²⁾) for i = 0, … , d-2 Fr scaling_factor = current_batching_challenge * inverse_vanishing_evals[j + 2]; - // Place the scaling factor to the 'scalars' vector - scalars.emplace_back(-scaling_factor); + + if constexpr (Curve::is_stdlib_type) { + auto builder = shplonk_batching_challenge.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! + stdlib::bool_t dummy_round = stdlib::bool_t(builder, is_dummy_round); + Fr zero = Fr(0); + zero.convert_constant_to_fixed_witness(builder); + scaling_factor = Fr::conditional_assign(dummy_round, zero, scaling_factor); + } else { + if (is_dummy_round) { + scaling_factor = 0; + } + } + // Add Aᵢ(−r²ⁱ) for i = 1, … , n-1 to the constant term accumulator constant_term_accumulator += scaling_factor * gemini_evaluations[j + 1]; // Update the batching challenge current_batching_challenge *= shplonk_batching_challenge; + + // Place the scaling factor to the 'scalars' vector + scalars.emplace_back(-scaling_factor); // 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 b1aad152f59..55739360179 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -216,7 +216,6 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) scalars, expected_constant_term_accumulator); - EXPECT_EQ(commitments.size(), prover_commitments.size()); // Compute the group element using the output of Shplemini method GroupElement shplemini_result = batch_mul_native(commitments, scalars); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index f8db79c9a2a..c5b4d8334b0 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -31,7 +31,7 @@ template class ShplonkProver_ { public: /** - * @brief Compute batched quotient polynomial Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) + * @brief Compute batched quotient polynomial Q(X) = ∑ⱼ νʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) * * @param opening_claims list of prover opening claims {fⱼ(X), (xⱼ, vⱼ)} for a witness polynomial fⱼ(X), s.t. fⱼ(xⱼ) * = vⱼ. @@ -45,7 +45,7 @@ template class ShplonkProver_ { for (const auto& claim : opening_claims) { max_poly_size = std::max(max_poly_size, claim.polynomial.size()); } - // Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) + // Q(X) = ∑ⱼ νʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) Polynomial Q(max_poly_size); Polynomial tmp(max_poly_size); @@ -71,7 +71,7 @@ template class ShplonkProver_ { * * @param opening_pairs list of opening pairs (xⱼ, vⱼ) for a witness polynomial fⱼ(X), s.t. fⱼ(xⱼ) = vⱼ. * @param witness_polynomials list of polynomials fⱼ(X). - * @param batched_quotient_Q Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) + * @param batched_quotient_Q Q(X) = ∑ⱼ νʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) * @param nu_challenge * @param z_challenge * @return Output{OpeningPair, Polynomial} @@ -92,21 +92,21 @@ template class ShplonkProver_ { } Fr::batch_invert(inverse_vanishing_evals); - // G(X) = Q(X) - Q_z(X) = Q(X) - ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ ), + // G(X) = Q(X) - Q_z(X) = Q(X) - ∑ⱼ νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ), // s.t. G(r) = 0 Polynomial G(std::move(batched_quotient_Q)); // G(X) = Q(X) - // G₀ = ∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ) + // G₀ = ∑ⱼ νʲ ⋅ vⱼ / ( z − xⱼ ) Fr current_nu = Fr::one(); Polynomial tmp(G.size()); size_t idx = 0; for (const auto& claim : opening_claims) { - // tmp = ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ ) + // 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]; // = ρʲ / ( r − xⱼ ) + Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ ) - // G -= ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ ) + // G -= νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ) G.add_scaled(tmp, -scaling_factor); current_nu *= nu_challenge; @@ -174,15 +174,15 @@ template class ShplonkVerifier_ { const Fr z_challenge = transcript->template get_challenge("Shplonk:z"); - // [G] = [Q] - ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] + G₀⋅[1] - // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )] + // [G] = [Q] - ∑ⱼ ρʲ / (z − xⱼ )⋅[fⱼ] + G₀⋅[1] + // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / (z − xⱼ )] GroupElement G_commitment; // compute simulated commitment to [G] as a linear combination of // [Q], { [fⱼ] }, [1]: // [G] = [Q] - ∑ⱼ (1/zⱼ(r))[Bⱼ] + ( ∑ⱼ (1/zⱼ(r)) Tⱼ(r) )[1] // = [Q] - ∑ⱼ (1/zⱼ(r))[Bⱼ] + G₀ [1] - // G₀ = ∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ) + // G₀ = ∑ⱼ ρʲ ⋅ vⱼ / (z − xⱼ ) auto G_commitment_constant = Fr(0); // TODO(#673): The recursive and non-recursive (native) logic is completely separated via the following @@ -196,8 +196,8 @@ template class ShplonkVerifier_ { std::vector commitments; std::vector scalars; - // [G] = [Q] - ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] + G₀⋅[1] - // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )] + // [G] = [Q] - ∑ⱼ νʲ / (z − xⱼ )⋅[fⱼ] + G₀⋅[1] + // = [Q] - [∑ⱼ νʲ ⋅ ( fⱼ(X) − vⱼ) / (z − xⱼ )] commitments.emplace_back(Q_commitment); scalars.emplace_back(Fr(builder, 1)); // Fr(1) @@ -215,9 +215,9 @@ template class ShplonkVerifier_ { // (Cⱼ, xⱼ, vⱼ) const auto& [opening_pair, commitment] = claims[j]; - Fr scaling_factor = current_nu * inverse_vanishing_evals[j]; // = ρʲ / ( r − xⱼ ) + Fr scaling_factor = current_nu * inverse_vanishing_evals[j]; // = νʲ / (z − xⱼ ) - // G₀ += ρʲ / ( r − xⱼ ) ⋅ vⱼ + // G₀ += νʲ / (z − xⱼ ) ⋅ vⱼ G_commitment_constant += scaling_factor * opening_pair.evaluation; current_nu *= nu; @@ -230,12 +230,12 @@ template class ShplonkVerifier_ { commitments.emplace_back(g1_identity); scalars.emplace_back(G_commitment_constant); - // [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1] + // [G] += G₀⋅[1] = [G] + (∑ⱼ νʲ ⋅ vⱼ / (z − xⱼ ))⋅[1] G_commitment = GroupElement::batch_mul(commitments, scalars); } else { - // [G] = [Q] - ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] + G₀⋅[1] - // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )] + // [G] = [Q] - ∑ⱼ νʲ / (z − xⱼ )⋅[fⱼ] + G₀⋅[1] + // = [Q] - [∑ⱼ νʲ ⋅ ( fⱼ(X) − vⱼ) / (z − xⱼ )] G_commitment = Q_commitment; // Compute {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ) @@ -252,18 +252,18 @@ template class ShplonkVerifier_ { // (Cⱼ, xⱼ, vⱼ) const auto& [opening_pair, commitment] = claims[j]; - Fr scaling_factor = current_nu * inverse_vanishing_evals[j]; // = ρʲ / ( r − xⱼ ) + Fr scaling_factor = current_nu * inverse_vanishing_evals[j]; // = νʲ / (z − xⱼ ) - // G₀ += ρʲ / ( r − xⱼ ) ⋅ vⱼ + // G₀ += νʲ / (z − xⱼ ) ⋅ vⱼ G_commitment_constant += scaling_factor * opening_pair.evaluation; - // [G] -= ρʲ / ( r − xⱼ )⋅[fⱼ] + // [G] -= νʲ / (z − xⱼ )⋅[fⱼ] G_commitment -= commitment * scaling_factor; current_nu *= nu; } - // [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1] + // [G] += G₀⋅[1] = [G] + (∑ⱼ νʲ ⋅ vⱼ / (z − xⱼ ))⋅[1] G_commitment += g1_identity * G_commitment_constant; } @@ -273,7 +273,7 @@ template class ShplonkVerifier_ { /** * @brief Computes \f$ \frac{1}{z - r}, \frac{1}{z+r}, \ldots, \frac{1}{z+r^{2^{d-1}}} \f$. * - * @param log_circuit_size \f$ d \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] @@ -285,8 +285,24 @@ template class ShplonkVerifier_ { std::vector inverted_denominators; inverted_denominators.reserve(num_gemini_claims); inverted_denominators.emplace_back((shplonk_eval_challenge - gemini_eval_challenge_powers[0]).invert()); + size_t i = 0; for (const auto& gemini_eval_challenge_power : gemini_eval_challenge_powers) { - inverted_denominators.emplace_back((shplonk_eval_challenge + gemini_eval_challenge_power).invert()); + bool is_dummy_round = i > num_gemini_claims; + Fr round_inverted_denominator = (shplonk_eval_challenge + gemini_eval_challenge_power).invert(); + if constexpr (Curve::is_stdlib_type) { + auto builder = shplonk_eval_challenge.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! + stdlib::bool_t dummy_round = stdlib::bool_t(builder, is_dummy_round); + Fr zero = Fr(0); + zero.convert_constant_to_fixed_witness(builder); + round_inverted_denominator = Fr::conditional_assign(dummy_round, zero, round_inverted_denominator); + } else { + if (is_dummy_round) { + round_inverted_denominator = 0; + } + } + inverted_denominators.emplace_back(round_inverted_denominator); + i++; } return inverted_denominators; } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index e1ee3b92fcd..e7a59d8b3a0 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -526,7 +526,8 @@ template class ZeroMorphVerifier_ { scalar *= FF(-1); if constexpr (Curve::is_stdlib_type) { auto builder = x_challenge.get_context(); - FF zero = FF::from_witness(builder, 0); + FF zero = FF(0); + zero.convert_constant_to_fixed_witness(builder); stdlib::bool_t dummy_round = stdlib::witness_t(builder, is_dummy_round); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1039): is it kosher to reassign like this? scalar = FF::conditional_assign(dummy_round, zero, scalar); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp index 1398cefe7e8..02e2de4e920 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp @@ -19,7 +19,8 @@ template class ShpleminiRecursionTest : public CommitmentTest; using Transcript = bb::BaseTranscript>; - constexpr size_t N = 16; - constexpr size_t log_circuit_size = 4; - constexpr size_t NUM_UNSHIFTED = 2; - constexpr size_t NUM_SHIFTED = 1; - srs::init_crs_factory("../srs_db/ignition"); + auto run_shplemini = [](size_t log_circuit_size) { + size_t N = 1 << log_circuit_size; + constexpr size_t NUM_UNSHIFTED = 2; + constexpr size_t NUM_SHIFTED = 1; + std::vector u_challenge(log_circuit_size); + for (size_t idx = 0; idx < log_circuit_size; ++idx) { + u_challenge[idx] = NativeFr::random_element(&shplemini_engine); + }; + // Construct some random multilinear polynomials f_i and their evaluations v_i = f_i(u) + std::vector f_polynomials; // unshifted polynomials + std::vector v_evaluations; + for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { + f_polynomials.emplace_back(Polynomial::random(N, /*shiftable*/ 1)); + v_evaluations.emplace_back(f_polynomials[i].evaluate_mle(u_challenge)); + } - std::vector u_challenge(log_circuit_size); - for (size_t idx = 0; idx < log_circuit_size; ++idx) { - u_challenge[idx] = NativeFr::random_element(&shplemini_engine); - }; - // Construct some random multilinear polynomials f_i and their evaluations v_i = f_i(u) - std::vector f_polynomials; // unshifted polynomials - std::vector v_evaluations; - for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { - f_polynomials.emplace_back(Polynomial::random(N, /*shiftable*/ 1)); - v_evaluations.emplace_back(f_polynomials[i].evaluate_mle(u_challenge)); - } + // Construct some "shifted" multilinear polynomials h_i as the left-shift-by-1 of f_i + std::vector g_polynomials; // to-be-shifted polynomials + std::vector h_polynomials; // shifts of the to-be-shifted polynomials + std::vector w_evaluations; + if constexpr (NUM_SHIFTED > 0) { + for (size_t i = 0; i < NUM_SHIFTED; ++i) { + g_polynomials.emplace_back(f_polynomials[i]); + h_polynomials.emplace_back(g_polynomials[i].shifted()); + w_evaluations.emplace_back(f_polynomials[i].evaluate_mle(u_challenge, true)); + } + } - // Construct some "shifted" multilinear polynomials h_i as the left-shift-by-1 of f_i - std::vector g_polynomials; // to-be-shifted polynomials - std::vector h_polynomials; // shifts of the to-be-shifted polynomials - std::vector w_evaluations; - if constexpr (NUM_SHIFTED > 0) { + // Compute commitments [f_i] + std::vector f_commitments; + auto commitment_key = std::make_shared(16384); + for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { + f_commitments.emplace_back(commitment_key->commit(f_polynomials[i])); + } + // Construct container of commitments of the "to-be-shifted" polynomials [g_i] (= [f_i]) + std::vector g_commitments; for (size_t i = 0; i < NUM_SHIFTED; ++i) { - g_polynomials.emplace_back(f_polynomials[i]); - h_polynomials.emplace_back(g_polynomials[i].shifted()); - w_evaluations.emplace_back(f_polynomials[i].evaluate_mle(u_challenge, true)); + g_commitments.emplace_back(f_commitments[i]); } - } - // Compute commitments [f_i] - std::vector f_commitments; - auto commitment_key = std::make_shared(4096); - for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { - f_commitments.emplace_back(commitment_key->commit(f_polynomials[i])); - } - // Construct container of commitments of the "to-be-shifted" polynomials [g_i] (= [f_i]) - std::vector g_commitments; - for (size_t i = 0; i < NUM_SHIFTED; ++i) { - g_commitments.emplace_back(f_commitments[i]); - } + // Initialize an empty NativeTranscript + auto prover_transcript = NativeTranscript::prover_init_empty(); + auto prover_opening_claims = ShpleminiProver::prove( + N, RefVector(f_polynomials), RefVector(g_polynomials), u_challenge, commitment_key, prover_transcript); + KZG::compute_opening_proof(commitment_key, prover_opening_claims, prover_transcript); + Builder builder; + StdlibProof stdlib_proof = bb::convert_proof_to_witness(&builder, prover_transcript->proof_data); + auto stdlib_verifier_transcript = std::make_shared(stdlib_proof); + stdlib_verifier_transcript->template receive_from_prover("Init"); - // Initialize an empty NativeTranscript - auto prover_transcript = NativeTranscript::prover_init_empty(); - auto prover_opening_claims = ShpleminiProver::prove( - N, RefVector(f_polynomials), RefVector(g_polynomials), u_challenge, commitment_key, prover_transcript); + // Execute Verifier protocol without the need for vk prior the final check + const auto commitments_to_witnesses = [&builder](const auto& commitments) { + std::vector commitments_in_biggroup(commitments.size()); + std::transform(commitments.begin(), + commitments.end(), + commitments_in_biggroup.begin(), + [&builder](const auto& native_commitment) { + return Commitment::from_witness(&builder, native_commitment); + }); + return commitments_in_biggroup; + }; + const auto elements_to_witness = [&](const auto& elements) { + std::vector elements_in_circuit(elements.size()); + std::transform( + elements.begin(), elements.end(), elements_in_circuit.begin(), [&builder](const auto& native_element) { + return Fr::from_witness(&builder, native_element); + }); + return elements_in_circuit; + }; + auto stdlib_f_commitments = commitments_to_witnesses(f_commitments); + auto stdlib_g_commitments = commitments_to_witnesses(g_commitments); + auto stdlib_v_evaluations = elements_to_witness(v_evaluations); + auto stdlib_w_evaluations = elements_to_witness(w_evaluations); - Builder builder; - StdlibProof stdlib_proof = bb::convert_proof_to_witness(&builder, prover_transcript->proof_data); - auto stdlib_verifier_transcript = std::make_shared(stdlib_proof); - [[maybe_unused]] auto _ = stdlib_verifier_transcript->template receive_from_prover("Init"); + std::vector u_challenge_in_circuit; + u_challenge_in_circuit.reserve(CONST_PROOF_SIZE_LOG_N); + auto u_iter = u_challenge.begin(); - // Execute Verifier protocol without the need for vk prior the final check - const auto commitments_to_witnesses = [&builder](const auto& commitments) { - std::vector commitments_in_biggroup(commitments.size()); - std::transform(commitments.begin(), - commitments.end(), - commitments_in_biggroup.begin(), - [&builder](const auto& native_commitment) { - return Commitment::from_witness(&builder, native_commitment); - }); - return commitments_in_biggroup; - }; - const auto elements_to_witness = [&](const auto& elements) { - std::vector elements_in_circuit(elements.size()); - std::transform(elements.begin(), - elements.end(), - elements_in_circuit.begin(), - [&builder](const auto& native_element) { return Fr::from_witness(&builder, native_element); }); - return elements_in_circuit; - }; - auto stdlib_f_commitments = commitments_to_witnesses(f_commitments); - auto stdlib_g_commitments = commitments_to_witnesses(g_commitments); - auto stdlib_v_evaluations = elements_to_witness(v_evaluations); - auto stdlib_w_evaluations = elements_to_witness(w_evaluations); + std::generate_n(std::back_inserter(u_challenge_in_circuit), CONST_PROOF_SIZE_LOG_N, [&] { + // We still need to do the same + Fr zero = Fr(0); + zero.convert_constant_to_fixed_witness(&builder); + if (u_iter < u_challenge.end()) { + return Fr::from_witness(&builder, *u_iter++); + } + return zero; + }); - std::vector u_challenge_in_circuit = elements_to_witness(u_challenge); + auto opening_claim = ShpleminiVerifier::compute_batch_opening_claim(Fr::from_witness(&builder, N), + RefVector(stdlib_f_commitments), + RefVector(stdlib_g_commitments), + RefVector(stdlib_v_evaluations), + RefVector(stdlib_w_evaluations), + u_challenge_in_circuit, + Commitment::one(&builder), + stdlib_verifier_transcript); + auto pairing_points = KZG::reduce_verify_batch_opening_claim(opening_claim, stdlib_verifier_transcript); + EXPECT_TRUE(CircuitChecker::check(builder)); - [[maybe_unused]] auto opening_claim = - ShpleminiVerifier::compute_batch_opening_claim(Fr::from_witness(&builder, N), - RefVector(stdlib_f_commitments), - RefVector(stdlib_g_commitments), - RefVector(stdlib_v_evaluations), - RefVector(stdlib_w_evaluations), - u_challenge_in_circuit, - Commitment::one(&builder), - stdlib_verifier_transcript); + auto vk = std::make_shared>(); + EXPECT_EQ(vk->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()), true); + + // Return finalised number of gates; + return builder.num_gates; + }; - EXPECT_TRUE(CircuitChecker::check(builder)); + size_t num_gates_6 = run_shplemini(6); + size_t num_gates_13 = run_shplemini(13); + EXPECT_EQ(num_gates_6, num_gates_13); } diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index fccab56b551..ef46da4014c 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -737,6 +737,7 @@ template class SumcheckVerifier { if constexpr (IsRecursiveFlavor) { typename Flavor::CircuitBuilder* builder = round_challenge.get_context(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1114): insecure! stdlib::bool_t dummy_round = stdlib::witness_t(builder, round_idx >= multivariate_d); bool checked = round.check_sum(round_univariate, dummy_round); // Only utilize the checked value if this is not a constant proof size padding round