diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index f0be1533a5c..7b4aaf0f035 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -100,14 +100,133 @@ template class GeminiProver_ { using Claim = ProverOpeningClaim; public: + /** + * @brief Class responsible for computation of the batched multilinear polynomials required by the Gemini protocol + * @details Opening multivariate polynomials using Gemini requires the computation of three batched polynomials. The + * first, here denoted A₀, is a linear combination of all polynomials to be opened. If we denote the linear + * combinations (based on challenge rho) of the unshifted and the to-be-shited-by-1 polynomials by F and G, + * respectively, then A₀ = F + G/X. This polynomial is "folded" in Gemini to produce d-1 univariate polynomials + * Fold_i, i = 1, ..., d-1. The second and third are the partially evaluated batched polynomials A₀₊ = F + G/r, and + * A₀₋ = F - G/r. These are required in order to prove the opening of shifted polynomials G_i/X from the commitments + * to their unshifted counterparts G_i. + * @note TODO(https://github.com/AztecProtocol/barretenberg/issues/1223): There are certain operations herein that + * could be made more efficient by e.g. reusing already initialized polynomials, possibly at the expense of clarity. + */ + class PolynomialBatcher { + + size_t full_batched_size = 0; // size of the full batched polynomial (generally the circuit size) + bool batched_unshifted_initialized = false; + + Polynomial random_polynomial; // random polynomial used for ZK + bool has_random_polynomial = false; + + RefVector unshifted; // set of unshifted polynomials + RefVector to_be_shifted_by_one; // set of polynomials to be left shifted by 1 + + Polynomial batched_unshifted; // linear combination of unshifted polynomials + Polynomial batched_to_be_shifted_by_one; // linear combination of to-be-shifted polynomials + + public: + PolynomialBatcher(const size_t full_batched_size) + : full_batched_size(full_batched_size) + , batched_unshifted(full_batched_size) + , batched_to_be_shifted_by_one(Polynomial::shiftable(full_batched_size)) + {} + + bool has_unshifted() const { return unshifted.size() > 0; } + bool has_to_be_shifted_by_one() const { return to_be_shifted_by_one.size() > 0; } + + // Set references to the polynomials to be batched + void set_unshifted(RefVector polynomials) { unshifted = polynomials; } + void set_to_be_shifted_by_one(RefVector polynomials) { to_be_shifted_by_one = polynomials; } + + // Initialize the random polynomial used to add randomness to the batched polynomials for ZK + void set_random_polynomial(Polynomial&& random) + { + has_random_polynomial = true; + random_polynomial = random; + } + + /** + * @brief Compute batched polynomial A₀ = F + G/X as the linear combination of all polynomials to be opened + * @details If the random polynomial is set, it is added to the batched polynomial for ZK + * + * @param challenge batching challenge + * @param running_scalar power of the batching challenge + * @return Polynomial A₀ + */ + Polynomial compute_batched(const Fr& challenge, Fr& running_scalar) + { + // lambda for batching polynomials; updates the running scalar in place + auto batch = [&](Polynomial& batched, const RefVector& polynomials_to_batch) { + for (auto& poly : polynomials_to_batch) { + batched.add_scaled(poly, running_scalar); + running_scalar *= challenge; + } + }; + + Polynomial full_batched(full_batched_size); + + // if necessary, add randomness to the full batched polynomial for ZK + if (has_random_polynomial) { + full_batched += random_polynomial; + } + + // compute the linear combination F of the unshifted polynomials + if (has_unshifted()) { + batch(batched_unshifted, unshifted); + full_batched += batched_unshifted; // A₀ = F + } + + // compute the linear combination G of the to-be-shifted polynomials + if (has_to_be_shifted_by_one()) { + batch(batched_to_be_shifted_by_one, to_be_shifted_by_one); + full_batched += batched_to_be_shifted_by_one.shifted(); // A₀ = F + G/X + } + + return full_batched; + } + + /** + * @brief Compute partially evaluated batched polynomials A₀(X, r) = A₀₊ = F + G/r, A₀(X, -r) = A₀₋ = F - G/r + * @details If the random polynomial is set, it is added to each batched polynomial for ZK + * + * @param r_challenge partial evaluation challenge + * @return std::pair {A₀₊, A₀₋} + */ + std::pair compute_partially_evaluated_batch_polynomials(const Fr& r_challenge) + { + // Initialize A₀₊ and compute A₀₊ += Random and A₀₊ += F as necessary + Polynomial A_0_pos(full_batched_size); // A₀₊ + + if (has_random_polynomial) { + A_0_pos += random_polynomial; // A₀₊ += random + } + if (has_unshifted()) { + A_0_pos += batched_unshifted; // A₀₊ += F + } + + Polynomial A_0_neg = A_0_pos; + + if (has_to_be_shifted_by_one()) { + Fr r_inv = r_challenge.invert(); // r⁻¹ + batched_to_be_shifted_by_one *= r_inv; // G = G/r + + A_0_pos += batched_to_be_shifted_by_one; // A₀₊ = F + G/r + A_0_neg -= batched_to_be_shifted_by_one; // A₀₋ = F - G/r + } + + return { A_0_pos, A_0_neg }; + }; + }; + static std::vector compute_fold_polynomials(const size_t log_n, std::span multilinear_challenge, const Polynomial& A_0); static std::pair compute_partially_evaluated_batch_polynomials( const size_t log_n, - Polynomial&& batched_F, - Polynomial&& batched_G, + PolynomialBatcher& polynomial_batcher, const Fr& r_challenge, const std::vector& batched_groups_to_be_concatenated = {}); @@ -119,8 +238,7 @@ template class GeminiProver_ { template static std::vector prove(const Fr circuit_size, - RefSpan f_polynomials, - RefSpan g_polynomials, + PolynomialBatcher& polynomial_batcher, std::span multilinear_challenge, const std::shared_ptr>& commitment_key, const std::shared_ptr& transcript, 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 af478b9743f..b372ce60306 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp @@ -7,6 +7,7 @@ using namespace bb; template class GeminiTest : public CommitmentTest { using GeminiProver = GeminiProver_; + using PolynomialBatcher = GeminiProver::PolynomialBatcher; using GeminiVerifier = GeminiVerifier_; using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; @@ -15,22 +16,24 @@ template class GeminiTest : public CommitmentTest { void execute_gemini_and_verify_claims(std::vector& multilinear_evaluation_point, RefVector multilinear_evaluations_unshifted, RefVector multilinear_evaluations_shifted, - RefSpan> multilinear_polynomials, - RefSpan> multilinear_polynomials_to_be_shifted, + RefVector> multilinear_polynomials, + RefVector> multilinear_polynomials_to_be_shifted, RefVector multilinear_commitments, RefVector multilinear_commitments_to_be_shifted) { auto prover_transcript = NativeTranscript::prover_init_empty(); + size_t circuit_size = 1 << multilinear_evaluation_point.size(); + + PolynomialBatcher polynomial_batcher(circuit_size); + polynomial_batcher.set_unshifted(multilinear_polynomials); + polynomial_batcher.set_to_be_shifted_by_one(multilinear_polynomials_to_be_shifted); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 - auto prover_output = GeminiProver::prove(1 << multilinear_evaluation_point.size(), - multilinear_polynomials, - multilinear_polynomials_to_be_shifted, - multilinear_evaluation_point, - this->commitment_key, - prover_transcript); + auto prover_output = GeminiProver::prove( + circuit_size, polynomial_batcher, multilinear_evaluation_point, this->commitment_key, prover_transcript); // Check that the Fold polynomials have been evaluated correctly in the prover this->verify_batch_opening_pair(prover_output); @@ -59,8 +62,8 @@ template class GeminiTest : public CommitmentTest { std::vector& multilinear_evaluation_point, RefVector multilinear_evaluations_unshifted, RefVector multilinear_evaluations_shifted, - RefSpan> multilinear_polynomials, - RefSpan> multilinear_polynomials_to_be_shifted, + RefVector> multilinear_polynomials, + RefVector> multilinear_polynomials_to_be_shifted, RefVector multilinear_commitments, RefVector multilinear_commitments_to_be_shifted, RefSpan> concatenated_polynomials = {}, @@ -71,12 +74,17 @@ template class GeminiTest : public CommitmentTest { { auto prover_transcript = NativeTranscript::prover_init_empty(); + size_t circuit_size = 1 << multilinear_evaluation_point.size(); + + PolynomialBatcher polynomial_batcher(circuit_size); + polynomial_batcher.set_unshifted(multilinear_polynomials); + polynomial_batcher.set_to_be_shifted_by_one(multilinear_polynomials_to_be_shifted); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 - auto prover_output = GeminiProver::prove(1 << multilinear_evaluation_point.size(), - multilinear_polynomials, - multilinear_polynomials_to_be_shifted, + auto prover_output = GeminiProver::prove(circuit_size, + polynomial_batcher, multilinear_evaluation_point, this->commitment_key, prover_transcript, 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 f863a17e6c2..bf20517fb70 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini_impl.hpp @@ -43,8 +43,7 @@ template template std::vector::Claim> GeminiProver_::prove( Fr circuit_size, - RefSpan f_polynomials, // unshifted - RefSpan g_polynomials, // to-be-shifted + PolynomialBatcher& polynomial_batcher, std::span multilinear_challenge, const std::shared_ptr>& commitment_key, const std::shared_ptr& transcript, @@ -57,37 +56,24 @@ std::vector::Claim> GeminiProver_::prove( const bool has_concatenations = concatenated_polynomials.size() > 0; - // Compute batched polynomials - Polynomial batched_unshifted(n); - Polynomial batched_to_be_shifted = Polynomial::shiftable(n); - // To achieve ZK, we mask the batched polynomial by a random polynomial of the same size if (has_zk) { - batched_unshifted = Polynomial::random(n); - transcript->send_to_verifier("Gemini:masking_poly_comm", commitment_key->commit(batched_unshifted)); + Polynomial random_polynomial(n); + transcript->send_to_verifier("Gemini:masking_poly_comm", commitment_key->commit(random_polynomial)); // In the provers, the size of multilinear_challenge is CONST_PROOF_SIZE_LOG_N, but we need to evaluate the // hiding polynomial as multilinear in log_n variables transcript->send_to_verifier("Gemini:masking_poly_eval", - batched_unshifted.evaluate_mle(multilinear_challenge.subspan(0, log_n))); + random_polynomial.evaluate_mle(multilinear_challenge.subspan(0, log_n))); + // Initialize batched unshifted poly with the random masking poly so that the full batched poly is masked + polynomial_batcher.set_random_polynomial(std::move(random_polynomial)); } // Get the batching challenge const Fr rho = transcript->template get_challenge("rho"); - Fr rho_challenge{ 1 }; - if (has_zk) { - // ρ⁰ is used to batch the hiding polynomial - rho_challenge *= rho; - } + Fr running_scalar = has_zk ? rho : 1; // ρ⁰ is used to batch the hiding polynomial - for (size_t i = 0; i < f_polynomials.size(); i++) { - batched_unshifted.add_scaled(f_polynomials[i], rho_challenge); - rho_challenge *= rho; - } - for (size_t i = 0; i < g_polynomials.size(); i++) { - batched_to_be_shifted.add_scaled(g_polynomials[i], rho_challenge); - rho_challenge *= rho; - } + Polynomial A_0 = polynomial_batcher.compute_batched(rho, running_scalar); size_t num_groups = groups_to_be_concatenated.size(); size_t num_chunks_per_group = groups_to_be_concatenated.empty() ? 0 : groups_to_be_concatenated[0].size(); @@ -102,18 +88,13 @@ std::vector::Claim> GeminiProver_::prove( } for (size_t i = 0; i < num_groups; ++i) { - batched_concatenated.add_scaled(concatenated_polynomials[i], rho_challenge); + batched_concatenated.add_scaled(concatenated_polynomials[i], running_scalar); for (size_t j = 0; j < num_chunks_per_group; ++j) { - batched_group[j].add_scaled(groups_to_be_concatenated[i][j], rho_challenge); + batched_group[j].add_scaled(groups_to_be_concatenated[i][j], running_scalar); } - rho_challenge *= rho; + running_scalar *= rho; } - } - - // Construct the batched polynomial A₀(X) = F(X) + G↺(X) = F(X) + G(X)/X - Polynomial A_0 = batched_unshifted; - A_0 += batched_to_be_shifted.shifted(); - if (has_concatenations) { // If proving for translator, add contribution of the batched concatenation polynomials + // If proving for translator, add contribution of the batched concatenation polynomials A_0 += batched_concatenated; } @@ -141,8 +122,8 @@ std::vector::Claim> GeminiProver_::prove( } // Compute polynomials A₀₊(X) = F(X) + G(X)/r and A₀₋(X) = F(X) - G(X)/r - auto [A_0_pos, A_0_neg] = compute_partially_evaluated_batch_polynomials( - log_n, std::move(batched_unshifted), std::move(batched_to_be_shifted), r_challenge, batched_group); + auto [A_0_pos, A_0_neg] = + compute_partially_evaluated_batch_polynomials(log_n, polynomial_batcher, r_challenge, batched_group); // Construct claims for the d + 1 univariate evaluations A₀₊(r), A₀₋(-r), and Foldₗ(−r^{2ˡ}), l = 1, ..., d-1 std::vector claims = construct_univariate_opening_claims( @@ -237,20 +218,11 @@ std::vector::Polynomial> GeminiProver_::com template std::pair::Polynomial, typename GeminiProver_::Polynomial> GeminiProver_:: compute_partially_evaluated_batch_polynomials(const size_t log_n, - Polynomial&& batched_F, - Polynomial&& batched_G, + PolynomialBatcher& polynomial_batcher, const Fr& r_challenge, const std::vector& batched_groups_to_be_concatenated) { - Polynomial& A_0_pos = batched_F; // A₀₊ = F - Polynomial A_0_neg = batched_F; // A₀₋ = F - - // Compute G/r - Fr r_inv = r_challenge.invert(); - batched_G *= r_inv; - - A_0_pos += batched_G; // A₀₊ = F + G/r - A_0_neg -= batched_G; // A₀₋ = F - G/r + auto [A_0_pos, A_0_neg] = polynomial_batcher.compute_partially_evaluated_batch_polynomials(r_challenge); // Reconstruct the batched concatenated polynomial from the batched groups, partially evaluated at r and -r and add // the result to A₀₊(X) and A₀₋(X). Explanation (for simplification assume a single concatenated polynomial): @@ -279,7 +251,7 @@ std::pair::Polynomial, typename GeminiProver_ { using VK = VerifierCommitmentKey; using Polynomial = bb::Polynomial; using Commitment = typename Curve::AffineElement; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; }; } // namespace @@ -255,11 +256,15 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) // Run the full prover PCS protocol: + PolynomialBatcher polynomial_batcher(n); + polynomial_batcher.set_unshifted({ poly1, poly2 }); + polynomial_batcher.set_to_be_shifted_by_one({ poly2 }); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 - auto prover_opening_claims = GeminiProver::prove( - n, RefArray{ poly1, poly2 }, RefArray{ poly2 }, mle_opening_point, this->ck(), prover_transcript); + auto prover_opening_claims = + GeminiProver::prove(n, polynomial_batcher, mle_opening_point, this->ck(), prover_transcript); const auto opening_claim = ShplonkProver::prove(this->ck(), prover_opening_claims, prover_transcript); IPA::compute_opening_proof(this->ck(), opening_claim, prover_transcript); @@ -306,11 +311,15 @@ TEST_F(IPATest, ShpleminiIPAWithShift) // Run the full prover PCS protocol: + PolynomialBatcher polynomial_batcher(n); + polynomial_batcher.set_unshifted({ poly1, poly2 }); + polynomial_batcher.set_to_be_shifted_by_one({ poly2 }); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 - auto prover_opening_claims = GeminiProver::prove( - n, RefArray{ poly1, poly2 }, RefArray{ poly2 }, mle_opening_point, this->ck(), prover_transcript); + auto prover_opening_claims = + GeminiProver::prove(n, polynomial_batcher, mle_opening_point, this->ck(), prover_transcript); const auto opening_claim = ShplonkProver::prove(this->ck(), prover_opening_claims, prover_transcript); IPA::compute_opening_proof(this->ck(), opening_claim, prover_transcript); @@ -372,15 +381,15 @@ TEST_F(IPATest, ShpleminiIPAShiftsRemoval) // Run the full prover PCS protocol: + PolynomialBatcher polynomial_batcher(n); + polynomial_batcher.set_unshifted({ poly1, poly2, poly3, poly4 }); + polynomial_batcher.set_to_be_shifted_by_one({ poly2, poly3 }); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 - auto prover_opening_claims = GeminiProver::prove(n, - RefArray{ poly1, poly2, poly3, poly4 }, - RefArray{ poly2, poly3 }, - mle_opening_point, - this->ck(), - prover_transcript); + auto prover_opening_claims = + GeminiProver::prove(n, polynomial_batcher, mle_opening_point, this->ck(), prover_transcript); const auto opening_claim = ShplonkProver::prove(this->ck(), prover_opening_claims, prover_transcript); IPA::compute_opening_proof(this->ck(), opening_claim, prover_transcript); 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 1612747e470..644f55c8384 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp @@ -93,6 +93,7 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) using Fr = typename TypeParam::ScalarField; using Commitment = typename TypeParam::AffineElement; using Polynomial = typename bb::Polynomial; + using PolynomialBatcher = GeminiProver::PolynomialBatcher; const size_t n = 16; const size_t log_n = 4; @@ -117,11 +118,15 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) // Run the full prover PCS protocol: + PolynomialBatcher polynomial_batcher(n); + polynomial_batcher.set_unshifted({ poly1, poly2 }); + polynomial_batcher.set_to_be_shifted_by_one({ poly2 }); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 - auto prover_opening_claims = GeminiProver::prove( - n, RefArray{ poly1, poly2 }, RefArray{ poly2 }, mle_opening_point, this->ck(), prover_transcript); + auto prover_opening_claims = + GeminiProver::prove(n, polynomial_batcher, mle_opening_point, this->ck(), prover_transcript); // Shplonk prover output: // - opening pair: (z_challenge, 0) @@ -167,6 +172,7 @@ TYPED_TEST(KZGTest, ShpleminiKzgWithShift) using Fr = typename TypeParam::ScalarField; using Commitment = typename TypeParam::AffineElement; using Polynomial = typename bb::Polynomial; + using PolynomialBatcher = GeminiProver::PolynomialBatcher; const size_t n = 16; const size_t log_n = 4; @@ -198,15 +204,15 @@ TYPED_TEST(KZGTest, ShpleminiKzgWithShift) // Run the full prover PCS protocol: + PolynomialBatcher polynomial_batcher(n); + polynomial_batcher.set_unshifted({ poly1, poly2, poly3, poly4 }); + polynomial_batcher.set_to_be_shifted_by_one({ poly1, poly3 }); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 - auto prover_opening_claims = GeminiProver::prove(n, - RefArray{ poly1, poly2, poly3, poly4 }, - RefArray{ poly1, poly3 }, - mle_opening_point, - this->ck(), - prover_transcript); + auto prover_opening_claims = + GeminiProver::prove(n, polynomial_batcher, mle_opening_point, this->ck(), prover_transcript); // Shplonk prover output: // - opening pair: (z_challenge, 0) @@ -247,6 +253,7 @@ TYPED_TEST(KZGTest, ShpleminiKzgWithShiftAndConcatenation) using Fr = typename TypeParam::ScalarField; using Commitment = typename TypeParam::AffineElement; using Polynomial = typename bb::Polynomial; + using PolynomialBatcher = GeminiProver::PolynomialBatcher; const size_t n = 16; const size_t log_n = 4; @@ -282,12 +289,15 @@ TYPED_TEST(KZGTest, ShpleminiKzgWithShiftAndConcatenation) // Run the full prover PCS protocol: + PolynomialBatcher polynomial_batcher(n); + polynomial_batcher.set_unshifted({ poly1, poly2, poly3, poly4 }); + polynomial_batcher.set_to_be_shifted_by_one({ poly1, poly3 }); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 auto prover_opening_claims = GeminiProver::prove(n, - RefArray{ poly1, poly2, poly3, poly4 }, - RefArray{ poly1, poly3 }, + polynomial_batcher, mle_opening_point, this->ck(), prover_transcript, @@ -342,6 +352,7 @@ TYPED_TEST(KZGTest, ShpleminiKzgShiftsRemoval) using Fr = typename TypeParam::ScalarField; using Commitment = typename TypeParam::AffineElement; using Polynomial = typename bb::Polynomial; + using PolynomialBatcher = GeminiProver::PolynomialBatcher; const size_t n = 16; const size_t log_n = 4; @@ -373,15 +384,15 @@ TYPED_TEST(KZGTest, ShpleminiKzgShiftsRemoval) // Run the full prover PCS protocol: + PolynomialBatcher polynomial_batcher(n); + polynomial_batcher.set_unshifted({ poly1, poly2, poly3, poly4 }); + polynomial_batcher.set_to_be_shifted_by_one({ poly2, poly3 }); + // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 - auto prover_opening_claims = GeminiProver::prove(n, - RefArray{ poly1, poly2, poly3, poly4 }, - RefArray{ poly2, poly3 }, - mle_opening_point, - this->ck(), - prover_transcript); + auto prover_opening_claims = + GeminiProver::prove(n, polynomial_batcher, mle_opening_point, this->ck(), prover_transcript); // Shplonk prover output: // - opening pair: (z_challenge, 0) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 71f763302a9..d0a67090fcf 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -22,11 +22,11 @@ template class ShpleminiProver_ { using VK = CommitmentKey; using ShplonkProver = ShplonkProver_; using GeminiProver = GeminiProver_; + using PolynomialBatcher = GeminiProver::PolynomialBatcher; template static OpeningClaim prove(const FF circuit_size, - RefSpan f_polynomials, - RefSpan g_polynomials, + PolynomialBatcher& polynomial_batcher, std::span multilinear_challenge, const std::shared_ptr>& commitment_key, const std::shared_ptr& transcript, @@ -39,8 +39,7 @@ template class ShpleminiProver_ { // While Shplemini is not templated on Flavor, we derive ZK flag this way const bool has_zk = (libra_polynomials[0].size() > 0); std::vector opening_claims = GeminiProver::prove(circuit_size, - f_polynomials, - g_polynomials, + polynomial_batcher, multilinear_challenge, commitment_key, transcript, 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 d7ba379ae3b..b85da1977f9 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -173,6 +173,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) { using Curve = TypeParam::Curve; using GeminiProver = GeminiProver_; + using PolynomialBatcher = GeminiProver::PolynomialBatcher; using ShpleminiVerifier = ShpleminiVerifier_; using ShplonkVerifier = ShplonkVerifier_; using Fr = typename Curve::ScalarField; @@ -197,22 +198,12 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) // Collect multilinear evaluations std::vector rhos = gemini::powers_of_rho(rho, this->num_polynomials + this->num_shiftable); - Polynomial batched_unshifted(this->n); - Polynomial batched_to_be_shifted = Polynomial::shiftable(this->n); + PolynomialBatcher polynomial_batcher(this->n); + polynomial_batcher.set_unshifted(RefVector(pcs_instance_witness.unshifted_polynomials)); + polynomial_batcher.set_to_be_shifted_by_one(RefVector(pcs_instance_witness.to_be_shifted_polynomials)); - size_t idx = 0; - for (auto& poly : pcs_instance_witness.unshifted_polynomials) { - batched_unshifted.add_scaled(poly, rhos[idx]); - idx++; - } - - for (auto& poly : pcs_instance_witness.to_be_shifted_polynomials) { - batched_to_be_shifted.add_scaled(poly, rhos[idx]); - idx++; - } - - Polynomial batched = batched_unshifted; - batched += batched_to_be_shifted; + Fr running_scalar = Fr(1); + Polynomial batched = polynomial_batcher.compute_batched(rho, running_scalar); // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 @@ -226,7 +217,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) } auto [A_0_pos, A_0_neg] = GeminiProver::compute_partially_evaluated_batch_polynomials( - this->log_n, std::move(batched_unshifted), std::move(batched_to_be_shifted), gemini_eval_challenge); + this->log_n, polynomial_batcher, gemini_eval_challenge); const auto opening_claims = GeminiProver::construct_univariate_opening_claims( this->log_n, std::move(A_0_pos), std::move(A_0_neg), std::move(fold_polynomials), gemini_eval_challenge); @@ -290,6 +281,7 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using CK = typename TypeParam::CommitmentKey; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; // Initialize transcript and commitment key auto prover_transcript = TypeParam::Transcript::prover_init_empty(); @@ -321,10 +313,13 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) SmallSubgroupIPAProver small_subgroup_ipa_prover( zk_sumcheck_data, const_size_mle_opening_point, claimed_inner_product, prover_transcript, ck); + PolynomialBatcher polynomial_batcher(this->n); + polynomial_batcher.set_unshifted(RefVector(pcs_instance_witness.unshifted_polynomials)); + polynomial_batcher.set_to_be_shifted_by_one(RefVector(pcs_instance_witness.to_be_shifted_polynomials)); + // Reduce to KZG or IPA based on the curve used in the test Flavor const auto opening_claim = ShpleminiProver::prove(this->n, - RefVector(pcs_instance_witness.unshifted_polynomials), - RefVector(pcs_instance_witness.to_be_shifted_polynomials), + polynomial_batcher, const_size_mle_opening_point, ck, prover_transcript, @@ -405,6 +400,7 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) using ShpleminiProver = ShpleminiProver_; using ShpleminiVerifier = ShpleminiVerifier_; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; std::shared_ptr ck = create_commitment_key(4096); @@ -433,10 +429,13 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) SmallSubgroupIPAProver small_subgroup_ipa_prover( zk_sumcheck_data, challenge, claimed_inner_product, prover_transcript, ck); + PolynomialBatcher polynomial_batcher(this->n); + polynomial_batcher.set_unshifted(RefVector(pcs_instance_witness.unshifted_polynomials)); + polynomial_batcher.set_to_be_shifted_by_one(RefVector(pcs_instance_witness.to_be_shifted_polynomials)); + // Reduce proving to a single claimed fed to KZG or IPA const auto opening_claim = ShpleminiProver::prove(this->n, - RefVector(pcs_instance_witness.unshifted_polynomials), - RefVector(pcs_instance_witness.to_be_shifted_polynomials), + polynomial_batcher, challenge, ck, prover_transcript, 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 3716d39da34..618fec2d6d9 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp @@ -40,6 +40,7 @@ TEST(ShpleminiRecursionTest, ProveAndVerifySingle) using NativeFr = typename Curve::NativeCurve::ScalarField; using Polynomial = bb::Polynomial; using Transcript = bb::BaseTranscript>; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; srs::init_crs_factory(bb::srs::get_ignition_crs_path()); auto run_shplemini = [](size_t log_circuit_size) { @@ -82,10 +83,14 @@ TEST(ShpleminiRecursionTest, ProveAndVerifySingle) g_commitments.emplace_back(f_commitments[i]); } + PolynomialBatcher polynomial_batcher(N); + polynomial_batcher.set_unshifted(RefVector(f_polynomials)); + polynomial_batcher.set_to_be_shifted_by_one(RefVector(g_polynomials)); + // 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); + auto prover_opening_claims = + ShpleminiProver::prove(N, polynomial_batcher, u_challenge, commitment_key, prover_transcript); KZG::compute_opening_proof(commitment_key, prover_opening_claims, prover_transcript); Builder builder; StdlibProof stdlib_proof = bb::convert_native_proof_to_stdlib(&builder, prover_transcript->proof_data); diff --git a/barretenberg/cpp/src/barretenberg/common/ref_vector.hpp b/barretenberg/cpp/src/barretenberg/common/ref_vector.hpp index 850053110d2..da618b2e9c8 100644 --- a/barretenberg/cpp/src/barretenberg/common/ref_vector.hpp +++ b/barretenberg/cpp/src/barretenberg/common/ref_vector.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/common/assert.hpp" +#include "barretenberg/common/ref_array.hpp" #include #include #include @@ -38,6 +39,15 @@ template class RefVector { (storage.push_back(&rest), ...); } + template + RefVector(const RefArray& ref_array) + : storage(ref_array.size()) + { + for (std::size_t i = 0; i < ref_array.size(); ++i) { + storage[i] = &ref_array[i]; + } + } + T& operator[](std::size_t idx) const { ASSERT(idx < storage.size()); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index 1defb569f97..d042cf5848f 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -121,6 +121,7 @@ void ECCVMProver::execute_pcs_rounds() using Shplemini = ShpleminiProver_; using Shplonk = ShplonkProver_; using OpeningClaim = ProverOpeningClaim; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; SmallSubgroupIPA small_subgroup_ipa_prover(zk_sumcheck_data, sumcheck_output.challenge, @@ -129,10 +130,13 @@ void ECCVMProver::execute_pcs_rounds() key->commitment_key); // Execute the Shplemini (Gemini + Shplonk) protocol to produce a univariate opening claim for the multilinear // evaluations produced by Sumcheck + PolynomialBatcher polynomial_batcher(key->circuit_size); + polynomial_batcher.set_unshifted(key->polynomials.get_unshifted()); + polynomial_batcher.set_to_be_shifted_by_one(key->polynomials.get_to_be_shifted()); + const OpeningClaim multivariate_to_univariate_opening_claim = Shplemini::prove(key->circuit_size, - key->polynomials.get_unshifted(), - key->polynomials.get_to_be_shifted(), + polynomial_batcher, sumcheck_output.challenge, key->commitment_key, transcript, diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp index ee6be78d732..71898f46fad 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp @@ -135,10 +135,9 @@ void TranslatorProver::execute_relation_check_rounds() void TranslatorProver::execute_pcs_rounds() { using Curve = typename Flavor::Curve; - using OpeningClaim = ProverOpeningClaim; - using SmallSubgroupIPA = SmallSubgroupIPAProver; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; SmallSubgroupIPA small_subgroup_ipa_prover(zk_sumcheck_data, sumcheck_output.challenge, @@ -146,10 +145,13 @@ void TranslatorProver::execute_pcs_rounds() transcript, key->proving_key->commitment_key); + PolynomialBatcher polynomial_batcher(key->proving_key->circuit_size); + polynomial_batcher.set_unshifted(key->proving_key->polynomials.get_unshifted_without_concatenated()); + polynomial_batcher.set_to_be_shifted_by_one(key->proving_key->polynomials.get_to_be_shifted()); + const OpeningClaim prover_opening_claim = ShpleminiProver_::prove(key->proving_key->circuit_size, - key->proving_key->polynomials.get_unshifted_without_concatenated(), - key->proving_key->polynomials.get_to_be_shifted(), + polynomial_batcher, sumcheck_output.challenge, key->proving_key->commitment_key, transcript, diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp index 27eb56068c9..178756cff14 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp @@ -62,26 +62,26 @@ template void DeciderProver_::execute_relation_ch template void DeciderProver_::execute_pcs_rounds() { using OpeningClaim = ProverOpeningClaim; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; auto& ck = proving_key->proving_key.commitment_key; ck = ck ? ck : std::make_shared(proving_key->proving_key.circuit_size); + PolynomialBatcher polynomial_batcher(proving_key->proving_key.circuit_size); + polynomial_batcher.set_unshifted(proving_key->proving_key.polynomials.get_unshifted()); + polynomial_batcher.set_to_be_shifted_by_one(proving_key->proving_key.polynomials.get_to_be_shifted()); + OpeningClaim prover_opening_claim; if constexpr (!Flavor::HasZK) { - prover_opening_claim = ShpleminiProver_::prove(proving_key->proving_key.circuit_size, - proving_key->proving_key.polynomials.get_unshifted(), - proving_key->proving_key.polynomials.get_to_be_shifted(), - sumcheck_output.challenge, - ck, - transcript); + prover_opening_claim = ShpleminiProver_::prove( + proving_key->proving_key.circuit_size, polynomial_batcher, sumcheck_output.challenge, ck, transcript); } else { SmallSubgroupIPA small_subgroup_ipa_prover( zk_sumcheck_data, sumcheck_output.challenge, sumcheck_output.claimed_libra_evaluation, transcript, ck); prover_opening_claim = ShpleminiProver_::prove(proving_key->proving_key.circuit_size, - proving_key->proving_key.polynomials.get_unshifted(), - proving_key->proving_key.polynomials.get_to_be_shifted(), + polynomial_batcher, sumcheck_output.challenge, ck, transcript, diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/prover.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/prover.cpp index fee5a695efc..7455d305808 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/prover.cpp @@ -111,13 +111,14 @@ void AvmProver::execute_relation_check_rounds() void AvmProver::execute_pcs_rounds() { using OpeningClaim = ProverOpeningClaim; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; - const OpeningClaim prover_opening_claim = ShpleminiProver_::prove(key->circuit_size, - prover_polynomials.get_unshifted(), - prover_polynomials.get_to_be_shifted(), - sumcheck_output.challenge, - commitment_key, - transcript); + PolynomialBatcher polynomial_batcher(key->circuit_size); + polynomial_batcher.set_unshifted(prover_polynomials.get_unshifted()); + polynomial_batcher.set_to_be_shifted_by_one(prover_polynomials.get_to_be_shifted()); + + const OpeningClaim prover_opening_claim = ShpleminiProver_::prove( + key->circuit_size, polynomial_batcher, sumcheck_output.challenge, commitment_key, transcript); PCS::compute_opening_proof(commitment_key, prover_opening_claim, transcript); } diff --git a/barretenberg/cpp/src/barretenberg/vm2/generated/prover.cpp b/barretenberg/cpp/src/barretenberg/vm2/generated/prover.cpp index 76aec65e31c..d46b2056b76 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/generated/prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/generated/prover.cpp @@ -111,13 +111,14 @@ void AvmProver::execute_relation_check_rounds() void AvmProver::execute_pcs_rounds() { using OpeningClaim = ProverOpeningClaim; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; - const OpeningClaim prover_opening_claim = ShpleminiProver_::prove(key->circuit_size, - prover_polynomials.get_unshifted(), - prover_polynomials.get_to_be_shifted(), - sumcheck_output.challenge, - commitment_key, - transcript); + PolynomialBatcher polynomial_batcher(key->circuit_size); + polynomial_batcher.set_unshifted(prover_polynomials.get_unshifted()); + polynomial_batcher.set_to_be_shifted_by_one(prover_polynomials.get_to_be_shifted()); + + const OpeningClaim prover_opening_claim = ShpleminiProver_::prove( + key->circuit_size, polynomial_batcher, sumcheck_output.challenge, commitment_key, transcript); PCS::compute_opening_proof(commitment_key, prover_opening_claim, transcript); } diff --git a/bb-pilcom/bb-pil-backend/templates/prover.cpp.hbs b/bb-pilcom/bb-pil-backend/templates/prover.cpp.hbs index 58025caf813..ce4dd4e37cf 100644 --- a/bb-pilcom/bb-pil-backend/templates/prover.cpp.hbs +++ b/bb-pilcom/bb-pil-backend/templates/prover.cpp.hbs @@ -110,13 +110,14 @@ void AvmProver::execute_relation_check_rounds() void AvmProver::execute_pcs_rounds() { using OpeningClaim = ProverOpeningClaim; + using PolynomialBatcher = GeminiProver_::PolynomialBatcher; - const OpeningClaim prover_opening_claim = ShpleminiProver_::prove(key->circuit_size, - prover_polynomials.get_unshifted(), - prover_polynomials.get_to_be_shifted(), - sumcheck_output.challenge, - commitment_key, - transcript); + PolynomialBatcher polynomial_batcher(key->circuit_size); + polynomial_batcher.set_unshifted(prover_polynomials.get_unshifted()); + polynomial_batcher.set_to_be_shifted_by_one(prover_polynomials.get_to_be_shifted()); + + const OpeningClaim prover_opening_claim = ShpleminiProver_::prove( + key->circuit_size, polynomial_batcher, sumcheck_output.challenge, commitment_key, transcript); PCS::compute_opening_proof(commitment_key, prover_opening_claim, transcript); }