diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 040c32cce97c..55a855f46146 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -31,7 +31,7 @@ template class ShpleminiProver_ { std::span multilinear_challenge, const std::shared_ptr>& commitment_key, const std::shared_ptr& transcript, - const std::array& libra_polynomials = {}, + const std::array& libra_polynomials = {}, const std::vector& sumcheck_round_univariates = {}, const std::vector>& sumcheck_round_evaluations = {}, RefSpan concatenated_polynomials = {}, @@ -77,7 +77,7 @@ template class ShpleminiProver_ { template static std::vector compute_libra_opening_claims( const FF gemini_r, - const std::array& libra_polynomials, + const std::array& libra_polynomials, const std::shared_ptr& transcript) { OpeningClaim new_claim; @@ -86,10 +86,10 @@ template class ShpleminiProver_ { static constexpr FF subgroup_generator = Curve::subgroup_generator; - std::array libra_eval_labels = { - "Libra:concatenation_eval", "Libra:shifted_big_sum_eval", "Libra:big_sum_eval", "Libra:quotient_eval" + std::array libra_eval_labels = { + "Libra:concatenation_eval", "Libra:shifted_grand_sum_eval", "Libra:grand_sum_eval", "Libra:quotient_eval" }; - const std::array evaluation_points = { + const std::array evaluation_points = { gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r }; for (size_t idx = 0; idx < 4; idx++) { @@ -251,11 +251,11 @@ template class ShpleminiVerifier_ { const std::vector gemini_eval_challenge_powers = gemini::powers_of_evaluation_challenge(gemini_evaluation_challenge, CONST_PROOF_SIZE_LOG_N); - std::array libra_evaluations; + std::array libra_evaluations; if (has_zk) { libra_evaluations[0] = transcript->template receive_from_prover("Libra:concatenation_eval"); - libra_evaluations[1] = transcript->template receive_from_prover("Libra:shifted_big_sum_eval"); - libra_evaluations[2] = transcript->template receive_from_prover("Libra:big_sum_eval"); + libra_evaluations[1] = transcript->template receive_from_prover("Libra:shifted_grand_sum_eval"); + libra_evaluations[2] = transcript->template receive_from_prover("Libra:grand_sum_eval"); libra_evaluations[3] = transcript->template receive_from_prover("Libra:quotient_eval"); } @@ -373,7 +373,7 @@ template class ShpleminiVerifier_ { shplonk_batching_challenge, shplonk_evaluation_challenge); - *consistency_checked = SmallSubgroupIPAVerifier::check_evaluations_consistency( + *consistency_checked = SmallSubgroupIPAVerifier::check_libra_evaluations_consistency( libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation); } @@ -664,7 +664,7 @@ template class ShpleminiVerifier_ { std::vector& scalars, Fr& constant_term_accumulator, const std::array& libra_commitments, - const std::array& libra_evaluations, + const std::array& libra_evaluations, const Fr& gemini_evaluation_challenge, const Fr& shplonk_batching_challenge, const Fr& shplonk_evaluation_challenge) @@ -682,8 +682,8 @@ template class ShpleminiVerifier_ { } // compute corresponding scalars and the correction to the constant term - std::array denominators; - std::array batching_scalars; + std::array denominators; + std::array batching_scalars; // compute Shplonk denominators and invert them denominators[0] = Fr(1) / (shplonk_evaluation_challenge - gemini_evaluation_challenge); denominators[1] = @@ -693,7 +693,7 @@ template class ShpleminiVerifier_ { // compute the scalars to be multiplied against the commitments [libra_concatenated], [big_sum], [big_sum], and // [libra_quotient] - for (size_t idx = 0; idx < NUM_LIBRA_EVALUATIONS; idx++) { + for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; idx++) { Fr scaling_factor = denominators[idx] * shplonk_challenge_power; batching_scalars[idx] = -scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; @@ -763,7 +763,7 @@ template class ShpleminiVerifier_ { // Compute the next power of Shplonk batching challenge \nu Fr shplonk_challenge_power = Fr{ 1 }; - for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_LIBRA_EVALUATIONS; ++j) { + for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_SMALL_IPA_EVALUATIONS; ++j) { shplonk_challenge_power *= shplonk_batching_challenge; } @@ -834,4 +834,4 @@ template class ShpleminiVerifier_ { } }; }; -} // namespace bb \ No newline at end of file +} // 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 eeb5b0fbb59f..08e2a222f7a1 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -323,6 +323,7 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) // Instantiate SmallSubgroupIPAProver, this prover sends commitments to Big Sum and Quotient polynomials SmallSubgroupIPAProver small_subgroup_ipa_prover( zk_sumcheck_data, const_size_mle_opening_point, claimed_inner_product, prover_transcript, ck); + small_subgroup_ipa_prover.prove(); // Reduce to KZG or IPA based on the curve used in the test Flavor const auto opening_claim = ShpleminiProver::prove(this->n, @@ -357,7 +358,7 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) EXPECT_EQ(libra_evaluation, claimed_inner_product); // Finalize the array of Libra/SmallSubgroupIpa commitments - libra_commitments[1] = verifier_transcript->template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[1] = verifier_transcript->template receive_from_prover("Libra:grand_sum_commitment"); libra_commitments[2] = verifier_transcript->template receive_from_prover("Libra:quotient_commitment"); // Used to verify the consistency of the evaluations of the concatenated libra polynomial, big sum polynomial, and @@ -430,6 +431,7 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) // Instantiate SmallSubgroupIPAProver, this prover sends commitments to Big Sum and Quotient polynomials SmallSubgroupIPAProver small_subgroup_ipa_prover( zk_sumcheck_data, challenge, claimed_inner_product, prover_transcript, ck); + small_subgroup_ipa_prover.prove(); // Reduce proving to a single claimed fed to KZG or IPA const auto opening_claim = ShpleminiProver::prove(this->n, @@ -465,7 +467,7 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) EXPECT_EQ(libra_evaluation, claimed_inner_product); // Finalize the array of Libra/SmallSubgroupIpa commitments - libra_commitments[1] = verifier_transcript->template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[1] = verifier_transcript->template receive_from_prover("Libra:grand_sum_commitment"); libra_commitments[2] = verifier_transcript->template receive_from_prover("Libra:quotient_commitment"); bool consistency_checked = true; @@ -495,4 +497,4 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) EXPECT_EQ(this->vk()->pairing_check(pairing_points[0], pairing_points[1]), true); } } -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp new file mode 100644 index 000000000000..c0c6434faa63 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp @@ -0,0 +1,451 @@ +#include "barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp" +#include "barretenberg/commitment_schemes/utils/test_settings.hpp" +#include "barretenberg/constants.hpp" +#include "barretenberg/ecc/curves/bn254/bn254.hpp" +#include "barretenberg/eccvm/eccvm_flavor.hpp" +#include "barretenberg/eccvm/eccvm_translation_data.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" +#include "barretenberg/stdlib_circuit_builders/mega_zk_flavor.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp" +#include "barretenberg/sumcheck/zk_sumcheck_data.hpp" +#include "barretenberg/translator_vm/translator_flavor.hpp" + +#include +#include + +namespace bb { + +// Default constructor to initialize all common members. +template +SmallSubgroupIPAProver::SmallSubgroupIPAProver(const std::shared_ptr& transcript, + std::shared_ptr& commitment_key) + : interpolation_domain{} + , concatenated_polynomial(MASKED_CONCATENATED_WITNESS_LENGTH) + , concatenated_lagrange_form(SUBGROUP_SIZE) + , challenge_polynomial(SUBGROUP_SIZE) + , challenge_polynomial_lagrange(SUBGROUP_SIZE) + , grand_sum_polynomial_unmasked(SUBGROUP_SIZE) + , grand_sum_polynomial(MASKED_GRAND_SUM_LENGTH) + , grand_sum_identity_polynomial(GRAND_SUM_IDENTITY_LENGTH) + , grand_sum_identity_quotient(QUOTIENT_LENGTH) + , transcript(transcript) +{ + // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has + // polynomials that may exceed the circuit size. + if (commitment_key->dyadic_size < MASKED_GRAND_SUM_LENGTH) { + commitment_key = std::make_shared(MASKED_GRAND_SUM_LENGTH); + }; + this->commitment_key = commitment_key; +}; + +/** + * @brief Construct SmallSubgroupIPAProver from a ZKSumcheckData object and a sumcheck evaluation challenge. + * + * @param zk_sumcheck_data Contains the witness polynomial \f$ G \f$ called Libra concatenated polynomial. + * @param multivariate_challenge \f$ (u_0,\ldots, u_{d-1})\f$, needed to compute the challenge polynomial \f$ F \f$. + * @param claimed_inner_product The inner product of \f$ G \f$ and the challenge polynomial \f$ F \f$. + */ +template +SmallSubgroupIPAProver::SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, + const std::vector& multivariate_challenge, + const FF claimed_inner_product, + const std::shared_ptr& transcript, + std::shared_ptr& commitment_key) + : SmallSubgroupIPAProver(transcript, commitment_key) +{ + this->claimed_inner_product = claimed_inner_product; + interpolation_domain = zk_sumcheck_data.interpolation_domain; + concatenated_polynomial = zk_sumcheck_data.libra_concatenated_monomial_form; + concatenated_lagrange_form = zk_sumcheck_data.libra_concatenated_lagrange_form; + + label_prefix = "Libra:"; + // Extract the evaluation domain computed by ZKSumcheckData + if constexpr (std::is_same_v) { + bn_evaluation_domain = std::move(zk_sumcheck_data.bn_evaluation_domain); + } + + // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients + compute_challenge_polynomial(multivariate_challenge); +} + +/** + * @brief Construct SmallSubgroupIPAProver from a TranslationData object and two challenges. It is Grumkin-specific. + * + * @param translation_data Contains the witness polynomial \f$ G \f$ which is a concatenation of last MASKING_OFFSET + * coefficients of NUM_TRANSLATION_EVALUATIONS polynomials fed to TranslationData constructor. + * @param evaluation_challenge_x A challenge used to evaluate the univariates fed to TranslationData. + * @param batching_challenge_v A challenge used to batch the evaluations at \f$ x \f$. Both challenges are required to + * compute the challenge polynomial \f$ F \f$. + * @param claimed_inner_product The inner product of \f$ G \f$ and the challenge polynomial \f$ F \f$. + */ +template +SmallSubgroupIPAProver::SmallSubgroupIPAProver(TranslationData& translation_data, + const FF evaluation_challenge_x, + const FF batching_challenge_v, + const FF claimed_inner_product, + const std::shared_ptr& transcript, + std::shared_ptr& commitment_key) + : SmallSubgroupIPAProver(transcript, commitment_key) + +{ + // TranslationData is Grumpkin-specific + if constexpr (IsAnyOf) { + this->claimed_inner_product = claimed_inner_product; + label_prefix = "Translation:"; + interpolation_domain = translation_data.interpolation_domain; + concatenated_polynomial = translation_data.masked_concatenated_polynomial; + concatenated_lagrange_form = translation_data.concatenated_polynomial_lagrange; + + // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients + compute_eccvm_challenge_polynomial(evaluation_challenge_x, batching_challenge_v); + } +} + +/** + * @brief Compute the derived witnesses \f$ A \f$ and \f$ Q \f$ and commit to them. + * @details + * 1. Define **grand sum polynomial** \f$ A(X) \f$ by \f$ A_i = \sum_{j=0}^i F_i \cdot G_i \f$, where the coefficients + * are computed in the Lagrange basis over \f$ H \f$. Note that it is analogous to the grand product polynomial used + * to prove claims about \f$ \prod_{h\in H} F(h) \cdot G(h) \f$. + * \f$ A \f$ is uniquely defined by the following properties: + * - \f$ A(1) = 0 \f$, + * - \f$ A(g^i) = A(g^{i-1}) + F(g^{i-1}) G(g^{i-1}) \f$ for \f$ i = 1, \ldots, |H|-1 \f$. + * 2. Mask \f$ A(X) \f$ by adding \f$ Z_H(X) R(X) \f$, where \f$ R(X) \f$ is a random polynomial of degree 3. + * 3. Commit to \f$ A(X) + Z_H(X) \cdot R(X) \f$ and send the commitment to the verifier. + * + * ### Grand Sum Identity + * + * \f$ A(X) \f$ is honestly constructed, i.e. + * - \f$ A_0 = 0\f$, + * - \f$ A_{i} = A_{i-1} + F_{i-1} * G_{i-1}\f$ (Lagrange coefficients over \f$ H \f$) for \f$ i = 1,\ldots, |H|\f$ + * - \f$ A_{|H|} \f$ is equal to the claimed inner product \f$s\f$. + * if and only if the following identity holds: + * \f{align}{ L_1(X) A(X) + (X - g^{-1}) (A(g \cdot X) - A(X) - + * F(X) G(X)) + L_{|H|}(X) (A(X) - s) = Z_H(X) Q(X), \f} where \f$ Q(X) \f$ is the quotient of the left-hand side + * by \f$ Z_H(X) \f$. The second summand is the translation of the second condition using the fact that the coefficients + * of \f$ A(gX) \f$ are given by a cyclic shift of the coefficients of \f$ A(X) \f$. + * + * The methods of this class allow the prover to compute \f$ A(X) \f$ and \f$ Q(X) \f$. + * + * After receiving a random evaluation challenge \f$ r \f$, the prover will send \f$ G(r), A(g\cdot r), A(r), Q(r) \f$ + * to the verifier. In the ZKSumcheckData case, \f$ r \f$ is the Gemini evaluation challenge, and this further part is + * taken care of by Shplemini. In the TranslationData case, \f$ r \f$ is an evaluation challenge that will be sampled in + * the translation evaluations sub-protocol of ECCVM. + */ +template void SmallSubgroupIPAProver::prove() +{ + + // Construct unmasked grand sum polynomial in Lagrange basis, compute its monomial coefficients and mask it + compute_grand_sum_polynomial(); + + // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 + transcript->template send_to_verifier(label_prefix + "grand_sum_commitment", + commitment_key->commit(grand_sum_polynomial)); + + // Compute C(X) + compute_grand_sum_identity_polynomial(); + + // Compute Q(X) + compute_grand_sum_identity_quotient(); + + // Send commitment [Q] to the verifier + transcript->template send_to_verifier(label_prefix + "quotient_commitment", + commitment_key->commit(grand_sum_identity_quotient)); +} + +/** + * @brief Computes the challenge polynomial F(X) based on the provided multivariate challenges. + * + * This method generates a polynomial in both Lagrange basis and monomial basis from Sumcheck's + * multivariate_challenge vector. The result is stored in `challenge_polynomial_lagrange` and + * `challenge_polynomial`. The former is re-used in the computation of the grand sum polynomial A(X) + * + * ### Lagrange Basis + * The Lagrange basis polynomial is constructed as follows: + * - Initialize the first coefficient as `1`. + * - For each challenge index `idx_poly` in the `CONST_PROOF_SIZE_LOG_N` range, compute a sequence of coefficients + * recursively as powers of the corresponding multivariate challenge. + * - Store these coefficients in `coeffs_lagrange_basis`. + * More explicitly, + * \f$ F = (1 , 1 , u_0, \ldots, u_0^{\text{LIBRA_UNIVARIATES_LENGTH}-1}, \ldots, 1, u_{D-1}, \ldots, + * u_{D-1}^{\text{LIBRA_UNIVARIATES_LENGTH}-1} ) \f$ in the Lagrange basis over \f$ H \f$. + * + * ### Monomial Basis + * If the curve is not `BN254`, the monomial polynomial is constructed directly using un-optimized Lagrange + * interpolation. Otherwise, an IFFT is used to convert the Lagrange basis coefficients into monomial basis + * coefficients. + * + * @param multivariate_challenge A vector of field elements used to compute the challenge polynomial. + */ +template +void SmallSubgroupIPAProver::compute_challenge_polynomial(const std::vector& multivariate_challenge) +{ + std::vector coeffs_lagrange_basis = + compute_challenge_polynomial_coeffs(multivariate_challenge); + + challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); + + // Compute monomial coefficients + challenge_polynomial = + compute_monomial_coefficients(coeffs_lagrange_basis, interpolation_domain, bn_evaluation_domain); +} +/** + * @brief Compute a (public) challenge polynomial from the evaluation and batching challenges. + * @details While proving the batched evaluation of the masking term used to blind the ECCVM Transcript wires, the + * prover needs to compute the polynomial whose coefficients in the Lagrange basis over the small subgroup are given + * by \f$ (1, x , \ldots, x^{\text{MASKING_OFFSET} - 1}, v, x \cdot v, \ldots, x^{\text{MASKING_OFFSET} - 1}\cdot + * v^{\text{NUM_TRANSLATION_EVALUATIONS} - 1}, 0, \ldots, 0) \f$. + * @param evaluation_challenge_x + * @param batching_challenge_v + */ +template +void SmallSubgroupIPAProver::compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, + const FF batching_challenge_v) +{ + + std::vector coeffs_lagrange_basis = + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v); + + challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); + + // Compute monomial coefficients + challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); +} +/** + * @brief Computes the grand sum polynomial \f$ A(X) \f$. + * + * #### Lagrange Basis + * - First, we recursively compute the coefficients of the unmasked grand sum polynomial, i.e. we set the first + * coefficient to `0`. + * - For each i, the coefficient is updated as: + * \f$ \texttt{grand_sum_lagrange_coeffs} (g^{i}) = + * \texttt{grand_sum_lagrange_coeffs} (g^{i-1}) + + * \texttt{challenge_polynomial_lagrange[prev_idx]} (g^{i-1}) \cdot + * \texttt{concatenated_lagrange_form[prev_idx]} (g^{i-1}) \f$ + * #### Masking Term + * - A random polynomial of degree 2 is generated and added to the Grand Sum Polynomial. + * - The masking term is applied as \f$ Z_H(X) \cdot \texttt{masking_term} \f$, where \f$ Z_H(X) \f$ is the + * vanishing polynomial. + * + */ +template void SmallSubgroupIPAProver::compute_grand_sum_polynomial() +{ + grand_sum_lagrange_coeffs[0] = 0; + + // Compute the grand sum coefficients recursively + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + size_t prev_idx = idx - 1; + grand_sum_lagrange_coeffs[idx] = + grand_sum_lagrange_coeffs[prev_idx] + + challenge_polynomial_lagrange.at(prev_idx) * concatenated_lagrange_form.at(prev_idx); + }; + + // Get the coefficients in the monomial basis + grand_sum_polynomial_unmasked = + compute_monomial_coefficients(grand_sum_lagrange_coeffs, interpolation_domain, bn_evaluation_domain); + + // Generate random masking_term of degree 2 + auto masking_term = bb::Univariate::get_random(); + + grand_sum_polynomial += grand_sum_polynomial_unmasked; + // Since Z_H(X) = X^|H| - 1, its product with the masking term R(X) is given by X^{H}*R(X) - R(X). Therefore + // to mask A, we subtract the coefficients of R from the first GRAND_SUM_MASKING_TERM_LENGTH coefficients + // of A and by set the coefficients A_{i+SUBGROUP_SIZE} to be equal to R_i + for (size_t idx = 0; idx < GRAND_SUM_MASKING_TERM_LENGTH; idx++) { + grand_sum_polynomial.at(idx) -= masking_term.value_at(idx); + grand_sum_polynomial.at(idx + SUBGROUP_SIZE) += masking_term.value_at(idx); + } +}; + +/** + * @brief Compute \f$ L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) \f$, where \f$ g + * \f$ is the fixed generator of \f$ H \f$. + * + */ +template void SmallSubgroupIPAProver::compute_grand_sum_identity_polynomial() +{ + // Compute shifted grand sum polynomial A(gX) + Polynomial shifted_grand_sum(MASKED_GRAND_SUM_LENGTH); + + for (size_t idx = 0; idx < MASKED_GRAND_SUM_LENGTH; idx++) { + shifted_grand_sum.at(idx) = grand_sum_polynomial.at(idx) * interpolation_domain[idx % SUBGROUP_SIZE]; + } + + const auto& [lagrange_first, lagrange_last] = + compute_lagrange_first_and_last(interpolation_domain, bn_evaluation_domain); + + // Compute -F(X)*G(X), the negated product of challenge_polynomial and concatenated_polynomial + for (size_t i = 0; i < MASKED_CONCATENATED_WITNESS_LENGTH; ++i) { + for (size_t j = 0; j < SUBGROUP_SIZE; ++j) { + grand_sum_identity_polynomial.at(i + j) -= concatenated_polynomial.at(i) * challenge_polynomial.at(j); + } + } + + // Compute - F(X) * G(X) + A(gX) - A(X) + for (size_t idx = 0; idx < MASKED_GRAND_SUM_LENGTH; idx++) { + grand_sum_identity_polynomial.at(idx) += shifted_grand_sum.at(idx) - grand_sum_polynomial.at(idx); + } + + // Mutiply - F(X) * G(X) + A(gX) - A(X) by X-g: + // 1. Multiply by X + for (size_t idx = GRAND_SUM_IDENTITY_LENGTH - 1; idx > 0; idx--) { + grand_sum_identity_polynomial.at(idx) = grand_sum_identity_polynomial.at(idx - 1); + } + grand_sum_identity_polynomial.at(0) = FF(0); + // 2. Subtract 1/g(A(gX) - A(X) - F(X) * G(X)) + for (size_t idx = 0; idx < GRAND_SUM_IDENTITY_LENGTH - 1; idx++) { + grand_sum_identity_polynomial.at(idx) -= + grand_sum_identity_polynomial.at(idx + 1) * interpolation_domain[SUBGROUP_SIZE - 1]; + } + + // Add (L_1 + L_{|H|}) * A(X) to the result + for (size_t i = 0; i < MASKED_GRAND_SUM_LENGTH; ++i) { + for (size_t j = 0; j < SUBGROUP_SIZE; ++j) { + grand_sum_identity_polynomial.at(i + j) += + grand_sum_polynomial.at(i) * (lagrange_first.at(j) + lagrange_last.at(j)); + } + } + // Subtract L_{|H|} * s + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + grand_sum_identity_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_inner_product; + } +} +/** + * @brief Compute monomial coefficients of the first and last Lagrange polynomials + * + * @param interpolation_domain + * @param bn_evaluation_domain + * @return std::array, 2> + */ +template +std::array, 2> SmallSubgroupIPAProver< + Flavor>::compute_lagrange_first_and_last(const std::array& interpolation_domain, + const EvaluationDomain& bn_evaluation_domain) +{ + // Compute the monomial coefficients of L_1 + std::array lagrange_coeffs; + lagrange_coeffs[0] = FF(1); + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + lagrange_coeffs[idx] = FF(0); + } + + Polynomial lagrange_first_monomial = + compute_monomial_coefficients(lagrange_coeffs, interpolation_domain, bn_evaluation_domain); + + // Compute the monomial coefficients of L_{|H|}, the last Lagrange polynomial + lagrange_coeffs[0] = FF(0); + lagrange_coeffs[SUBGROUP_SIZE - 1] = FF(1); + + Polynomial lagrange_last_monomial = + compute_monomial_coefficients(lagrange_coeffs, interpolation_domain, bn_evaluation_domain); + + return { lagrange_first_monomial, lagrange_last_monomial }; +} + +/** @brief Efficiently compute the quotient of the grand sum identity polynomial \f$ C \f$ by \f$ Z_H = X ^ { | H | } - + * 1\f$. + */ +template void SmallSubgroupIPAProver::compute_grand_sum_identity_quotient() +{ + + auto remainder = grand_sum_identity_polynomial; + for (size_t idx = GRAND_SUM_IDENTITY_LENGTH - 1; idx >= SUBGROUP_SIZE; idx--) { + grand_sum_identity_quotient.at(idx - SUBGROUP_SIZE) = remainder.at(idx); + remainder.at(idx - SUBGROUP_SIZE) += remainder.at(idx); + } +} + +/** + * @brief For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck + * challenges. + * + * @param zk_sumcheck_data Contains Libra constant term and scaled Libra univariates + * @param multivariate_challenge Sumcheck challenge + * @param log_circuit_size + */ +template +typename Flavor::Curve::ScalarField SmallSubgroupIPAProver::compute_claimed_inner_product( + ZKSumcheckData& zk_sumcheck_data, + const std::vector& multivariate_challenge, + const size_t& log_circuit_size) +{ + const FF libra_challenge_inv = zk_sumcheck_data.libra_challenge.invert(); + // Compute claimed inner product similarly to the SumcheckProver + FF claimed_inner_product = FF{ 0 }; + size_t idx = 0; + for (const auto& univariate : zk_sumcheck_data.libra_univariates) { + claimed_inner_product += univariate.evaluate(multivariate_challenge[idx]); + idx++; + } + // Libra Univariates are mutiplied by the Libra challenge in setup_auxiliary_data(), needs to be undone + claimed_inner_product *= libra_challenge_inv / FF(1 << (log_circuit_size - 1)); + claimed_inner_product += zk_sumcheck_data.constant_term; + return claimed_inner_product; +} + +/** + * @brief For test purposes: compute the batched evaluation of the last MASKING_OFFSET rows of the ECCVM transcript + * polynomials `Op`, `Px`, `Py`, `z1`, `z2`. + * + * @param translation_data Contains concatenated ECCVM Transcript polynomials. + * @param evaluation_challenge_x We evaluate the transcript polynomials at x as univariates. + * @param batching_challenge_v The evaluations at x are batched using v. + */ +template +typename Flavor::Curve::ScalarField SmallSubgroupIPAProver::compute_claimed_translation_inner_product( + TranslationData& translation_data, + const FF& evaluation_challenge_x, + const FF& batching_challenge_v) +{ + FF claimed_inner_product{ 0 }; + if constexpr (IsAnyOf) { + const std::vector coeffs_lagrange_basis = + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v); + + Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); + + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + claimed_inner_product += + translation_data.concatenated_polynomial_lagrange.at(idx) * challenge_polynomial_lagrange.at(idx); + } + } + return claimed_inner_product; +} + +/** + * @brief Given a vector of coefficients of a polynomial in the Lagrange basis over \f$ H \f$, compute its coefficients + * in the monomial basis. We use IFFT over BN254 ScalarField and a generic method compute_efficient_interpolation, which + * has quadratic complexity and has to be used with caution. + * + */ +template +Polynomial SmallSubgroupIPAProver::compute_monomial_coefficients( + std::span lagrange_coeffs, + const std::array& interpolation_domain, + const EvaluationDomain& bn_evaluation_domain) +{ + using FF = typename Flavor::Curve::ScalarField; + if constexpr (!std::is_same_v) { + return Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); + } else { + std::vector lagrange_last_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_last_ifft.data(), bn_evaluation_domain); + return Polynomial(lagrange_last_ifft); + } +} + +// Instantiate with ZK Flavors +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; + +// Instantiations used in tests +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 791bb6a601f7..714e484b39c7 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -1,7 +1,9 @@ #pragma once +#include "barretenberg/commitment_schemes/utils/test_settings.hpp" #include "barretenberg/constants.hpp" #include "barretenberg/ecc/curves/bn254/bn254.hpp" +#include "barretenberg/eccvm/eccvm_translation_data.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" @@ -11,77 +13,72 @@ #include namespace bb { - /** - * @brief Small Subgroup IPA Prover for Zero-Knowledge Opening of Libra Polynomials. + * @brief A Curve-agnostic ZK protocol to prove inner products of small vectors. + * + * @details Implementation of the protocol described in [Ariel's HackMD](https://hackmd.io/xYHn1qqvQjey1yJutcuXdg). + * Although we could in principle prove statements about a general witness polynomial \f$ G \f$ and a challenge + * polynomial \f$ F \f$ and a claim that \f$ \langle F, G \rangle = s \f$, we specialize to the following cases: + * + * - \f$ G \f$ is obtained by concatenating Libra polynomials used in ZK-Sumcheck. \f$ F \f$ is a concatenation of the + * consecutive powers of the sumcheck challenge entries. See details below and in the corresponding method's docs. * - * @details Implements a less general version of the protocol described in - * [Ariel's HackMD](https://hackmd.io/xYHn1qqvQjey1yJutcuXdg). This version is specialized for making - * commitments and openings of Libra polynomials zero-knowledge. + * - \f$ G \f$ is a concatenation of last MASKING_OFFSET coefficients of NUM_TRANSLATION_EVALUATIONS polynomials fed to + * TranslationData constructor. \f$ F \f$ consists of products \f$ x^i \cdot v^j \f$. See details below in the + * corresponding method's docs. * - * ### Overview + * ## Constructing SmallSubgroupIPAProver + * + * In both cases, we extract the witness polynomial \f$ G \f$ from the input. The main difference is in the construction + * of the challenge polynomial \f$ F \f$. Once \f$ F\f$ is computed by the corresponding method, we could call the + * common \ref prove method on an object of this class. + * + * ### ZKSumcheckData Specifics * * Let \f$ G \f$ be the masked concatenated Libra polynomial. Without masking, it is defined by concatenating Libra * constant term and the monomial coefficients of the Libra univariates \f$ g_i \f$ in the Lagrange basis over \f$ H * \f$. More explicitly, unmasked concatenated Libra polynomial is given by the following vector of coefficients: - * \f[ \big( \text{libra_constant_term}, g_{0,0}, \ldots, g_{0, - * \text{LIBRA_UNIVARIATES_LENGTH} - 1}, \ldots, g_{d-1, 0}, g_{d-1, \text{LIBRA_UNIVARIATES_LENGTH} - 1} \big) \f], - * where \f$ d = \text{log_circuit_size}\f$. - * It is masked by adding \f$ (r_0 + r_1 X) Z_{H}(X)\f$, where \f$ Z_H(X) \f$ is the vanishing polynomial for \f$ H \f$. - * - * This class enables the prover to: + * \f{align}{ + * \big( \text{libra_constant_term}, g_{0,0}, \ldots, g_{0, + * \text{LIBRA_UNIVARIATES_LENGTH} - 1}, \ldots, g_{d-1, 0}, \ldots, g_{d-1, \text{LIBRA_UNIVARIATES_LENGTH} - 1} + * \big) \f}, where \f$ d = \text{log_circuit_size}\f$. It is masked by adding \f$ (r_0 + r_1 X) Z_{H}(X)\f$, where \f$ + * Z_H(X) \f$ is the vanishing polynomial for \f$ H \f$. * - * - Open the commitment to concatenated Libra polynomial with zero-knowledge while proving correctness of the claimed - * inner product. The concatenated polynomial is commited to during the construction of ZKSumcheckData structure. + * ### TranslationData Specifics * - * ### Inputs - * The prover receives: - * - **ZKSumcheckData:** Contains: - * - Monomial coefficients of the masked concatenated Libra polynomial \f$ G \f$. - * - Interpolation domain for a small subgroup \( H \subset \mathbb{F}^\ast \), where \(\mathbb{F} \) is the - * ScalarField of a given curve. - * - **Sumcheck challenges:** \( u_0, \ldots, u_{D-1} \), where \( D = \text{CONST_PROOF_SIZE_LOG_N} \). - * - **Claimed inner product:** \( s = \text{claimed\_ipa\_eval} \), defined as: - * \f[ - * s = \sum_{i=1}^{|H|} F(g^i) G(g^i), - * \f] - * where \( F(X) \) is the ``challenge`` polynomial constructed from the Sumcheck round challenges (see the formula - * below) and \( G(X) \) is the concatenated Libra polynomial. + * Let \f$ G \f$ be the concatenated polynomial from the TranslationData class. Without masking, it is defined by + * concatenating NUM_TRANSLATION_EVALUATIONS polynomials of size MASKING_OFFSET in the Lagrange + * basis over \f$ H \f$. It is masked by adding \f$ (r_0 + r_1 X) Z_{H}(X)\f$, where \f$ Z_H(X) \f$ is the vanishing + * polynomial for \f$ H \f$. * - * ### Prover's Construction - * 1. Define a polynomial \( A(X) \), called the **big sum polynomial**, which is analogous to the big product - * polynomial used to prove claims about \f$ \prod_{h\in H} f(h) \cdot g(h) \f$. It is uniquely defined by the - * following: - * - \( A(1) = 0 \), - * - \( A(g^i) = A(g^{i-1}) + F(g^{i-1}) G(g^{i-1}) \) for \( i = 1, \ldots, |H|-1 \). - * 2. Mask \( A(X) \) by adding \( Z_H(X) R(X) \), where \( R(X) \) is a random polynomial of degree 3. - * 3. Commit to \( A(X) \) and send the commitment to the verifier. + * ### This class enables the prover to: * - * ### Key Identity - * \( A(X) \) is honestly constructed, i.e. - * - \f$ A_0 = 0\f$, - * - \f$ A_{i} = A_{i-1} + F_{i-1} * G_{i-1}\f$ (Lagrange coefficients over \f$ H \f$) for \f$ i = 1,\ldots, |H|\f$ - * - \f$ A_{|H|} \f$ is equal to the claimed inner product \f$s\f$. - * if and only if the following identity holds: - * \f[ L_1(X) A(X) + (X - g^{-1}) (A(g \cdot X) - A(X) - - * F(X) G(X)) + L_{|H|}(X) (A(X) - s) = Z_H(X) Q(X), \f] where \( Q(X) \) is the quotient of the left-hand side by \( - * Z_H(X) \). The second summand is the translation of the second condition using the fact that the coefficients of \f$ - * A(gX) \f$ are given by a cyclic shift of the coefficients of \f$ A(X) \f$. + * - Compute the derived witnesses \f$ A \f$ (= Grand Sum Polynomial) and \f$ Q \f$ (= Grand Sum Identity Quotient) + * required to prove the correctness of the claimed inner product while preserving ZK. For details, see \ref prove + * method docs. Note that the concatenated polynomial \f$ G \f$ is committed to during the construction of the + * ZKSumcheckData or TranslationData object. * - * The methods of this class allow the prover to compute \( A(X) \) and \( Q(X) \). - * - * After receiveing a random evaluation challenge \f$ r \f$ , the prover sends \f$ G(r), A(g\cdot r), A(r), Q(r) \f$ to - * the verifier. In our case, \f$ r \f$ is the Gemini evaluation challenge, and this part is taken care of by Shplemini. */ template class SmallSubgroupIPAProver { using Curve = typename Flavor::Curve; using FF = typename Curve::ScalarField; // The size of a multiplicative subgroup in the ScalarField of a curve static constexpr size_t SUBGROUP_SIZE = Curve::SUBGROUP_SIZE; - // Size of the polynomial to be divided by Z_H - static constexpr size_t BATCHED_POLYNOMIAL_LENGTH = 2 * SUBGROUP_SIZE + 2; - // Size of Q(X) - static constexpr size_t QUOTIENT_LENGTH = SUBGROUP_SIZE + 2; + + // A masking term of length 2 (degree 1) is required to mask [G] and G(r). + static constexpr size_t WITNESS_MASKING_TERM_LENGTH = 2; + static constexpr size_t MASKED_CONCATENATED_WITNESS_LENGTH = SUBGROUP_SIZE + WITNESS_MASKING_TERM_LENGTH; + + // A masking term of length 3 (degree 2) is required to mask [A], A(r), and A(g*r) + static constexpr size_t GRAND_SUM_MASKING_TERM_LENGTH = 3; + static constexpr size_t MASKED_GRAND_SUM_LENGTH = SUBGROUP_SIZE + GRAND_SUM_MASKING_TERM_LENGTH; + + // Length of the big sum identity polynomial C. It is equal to the length of the highest degree term X * F(X) * G(X) + static constexpr size_t GRAND_SUM_IDENTITY_LENGTH = MASKED_CONCATENATED_WITNESS_LENGTH + SUBGROUP_SIZE; + + // Length of the big sum identity quotient Q(X) = length(C) - length(Z_H) + 1 + static constexpr size_t QUOTIENT_LENGTH = GRAND_SUM_IDENTITY_LENGTH - SUBGROUP_SIZE; + // The length of a random polynomial masking Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we // send the coefficients of the univariates, hence we choose these value to be the max sumcheck univariate length // over Translator, Ultra, and Mega. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces the @@ -90,407 +87,169 @@ template class SmallSubgroupIPAProver { // Fixed generator of H static constexpr FF subgroup_generator = Curve::subgroup_generator; + // The SmallSubgroupIPA claim + FF claimed_inner_product; + // Interpolation domain {1, g, \ldots, g^{SUBGROUP_SIZE - 1}} used by ECCVM std::array interpolation_domain; // We use IFFT over BN254 scalar field EvaluationDomain bn_evaluation_domain; - // Monomial coefficients of the concatenated Libra masking polynomial extracted from ZKSumcheckData + // Monomial coefficients of the concatenated polynomial extracted from ZKSumcheckData or TranslationData Polynomial concatenated_polynomial; - // Lagrange coefficeints of the concatenated Libra masking polynomial = constant_term || g_0 || ... || g_{d-1} - Polynomial libra_concatenated_lagrange_form; - - // Claimed evaluation s = constant_term + g_0(u_0) + ... + g_{d-1}(u_{d-1}), where g_i is the i'th Libra masking - // univariate - FF claimed_evaluation; + // Lagrange coefficeints of the concatenated polynomial + Polynomial concatenated_lagrange_form; - // The polynomial obtained by concatenated powers of sumcheck challenges + // The polynomial obtained by concatenated powers of sumcheck challenges or the productcs of + // `evaluation_challenge_x` and `batching_challenge_v` Polynomial challenge_polynomial; Polynomial challenge_polynomial_lagrange; - // Big sum polynomial A(X) - Polynomial big_sum_polynomial_unmasked; - Polynomial big_sum_polynomial; - std::array big_sum_lagrange_coeffs; + // Grand sum polynomial A(X) + Polynomial grand_sum_polynomial_unmasked; + Polynomial grand_sum_polynomial; + std::array grand_sum_lagrange_coeffs; // The RHS of the key identity, denoted C(X) in the HackMD - Polynomial batched_polynomial; + Polynomial grand_sum_identity_polynomial; - // Quotient of the batched polynomial C(X) by the subgroup vanishing polynomial X^{|H|} - 1 - Polynomial batched_quotient; - - public: - SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, - const std::vector& multivariate_challenge, - const FF claimed_ipa_eval, - std::shared_ptr transcript, - std::shared_ptr& commitment_key) - : interpolation_domain(zk_sumcheck_data.interpolation_domain) - , concatenated_polynomial(zk_sumcheck_data.libra_concatenated_monomial_form) - , libra_concatenated_lagrange_form(zk_sumcheck_data.libra_concatenated_lagrange_form) - , challenge_polynomial(SUBGROUP_SIZE) - , challenge_polynomial_lagrange(SUBGROUP_SIZE) - , big_sum_polynomial_unmasked(SUBGROUP_SIZE) - , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking - , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) - , batched_quotient(QUOTIENT_LENGTH) - - { - // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has - // polynomials that may exceed the circuit size. - if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { - commitment_key = std::make_shared(SUBGROUP_SIZE + 3); - } - // Extract the evaluation domain computed by ZKSumcheckData - if constexpr (std::is_same_v) { - bn_evaluation_domain = std::move(zk_sumcheck_data.bn_evaluation_domain); - } + // Quotient of the grand sum identity polynomial C(X) by the vanishing polynomial Z_H = X^{|H|} - 1 + Polynomial grand_sum_identity_quotient; - // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients - compute_challenge_polynomial(multivariate_challenge); + // Either "Translation:" or "Libra:". + std::string label_prefix; - // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it - compute_big_sum_polynomial(); - - // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 - transcript->template send_to_verifier("Libra:big_sum_commitment", commitment_key->commit(big_sum_polynomial)); - - // Compute C(X) - compute_batched_polynomial(claimed_ipa_eval); - - // Compute Q(X) - compute_batched_quotient(); - - // Send commitment [Q] to the verifier - if (commitment_key) { - transcript->template send_to_verifier("Libra:quotient_commitment", - commitment_key->commit(batched_quotient)); - } - } - - // Getter to pass the witnesses to ShpleminiProver. Big sum polynomial is evaluated at 2 points (and is small) - std::array, NUM_LIBRA_EVALUATIONS> get_witness_polynomials() const - { - return { concatenated_polynomial, big_sum_polynomial, big_sum_polynomial, batched_quotient }; - } - // Getters for test purposes - const Polynomial& get_batched_polynomial() const { return batched_polynomial; } - const Polynomial& get_challenge_polynomial() const { return challenge_polynomial; } - - /** - * @brief Computes the challenge polynomial F(X) based on the provided multivariate challenges. - * - * This method generates a polynomial in both Lagrange basis and monomial basis from Sumcheck's - * multivariate_challenge vector. The result is stored in `challenge_polynomial_lagrange` and - * `challenge_polynomial`. The former is re-used in the computation of the big sum polynomial A(X) - * - * ### Lagrange Basis - * The Lagrange basis polynomial is constructed as follows: - * - Initialize the first coefficient as `1`. - * - For each challenge index `idx_poly` in the `CONST_PROOF_SIZE_LOG_N` range, compute a sequence of coefficients - * recursively as powers of the corresponding multivariate challenge. - * - Store these coefficients in `coeffs_lagrange_basis`. - * More explicitly, - * \f$ F = (1 , 1 , u_0, \ldots, u_0^{LIBRA_UNIVARIATES_LENGTH-1}, \ldots, 1, u_{D-1}, \ldots, - * u_{D-1}^{LIBRA_UNIVARIATES_LENGTH-1} ) \f$ in the Lagrange basis over \f$ H \f$. - * - * ### Monomial Basis - * If the curve is not `BN254`, the monomial polynomial is constructed directly using un-optimized Lagrange - * interpolation. Otherwise, an IFFT is used to convert the Lagrange basis coefficients into monomial basis - * coefficients. - * - * @param multivariate_challenge A vector of field elements used to compute the challenge polynomial. - */ - void compute_challenge_polynomial(const std::vector& multivariate_challenge) - { - std::vector coeffs_lagrange_basis(SUBGROUP_SIZE); - coeffs_lagrange_basis[0] = FF(1); - - for (size_t challenge_idx = 0; challenge_idx < CONST_PROOF_SIZE_LOG_N; challenge_idx++) { - // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH - const size_t poly_to_concatenate_start = 1 + LIBRA_UNIVARIATES_LENGTH * challenge_idx; - coeffs_lagrange_basis[poly_to_concatenate_start] = FF(1); - for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + LIBRA_UNIVARIATES_LENGTH; - idx++) { - // Recursively compute the powers of the challenge - coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * multivariate_challenge[challenge_idx]; - } - } + std::shared_ptr transcript; + std::shared_ptr commitment_key; - challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); - - // Compute monomial coefficients - if constexpr (!std::is_same_v) { - challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); - } else { - std::vector challenge_polynomial_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft( - coeffs_lagrange_basis.data(), challenge_polynomial_ifft.data(), bn_evaluation_domain); - challenge_polynomial = Polynomial(challenge_polynomial_ifft); - } - } - - /** - * @brief Computes the big sum polynomial A(X) - * - * #### Lagrange Basis - * - First, we recursively compute the coefficients of the unmasked big sum polynomial, i.e. we set the first - * coefficient to `0`. - * - For each i, the coefficient is updated as: - * \f$ \texttt{big_sum_lagrange_coeffs} (g^{i}) = - * \texttt{big_sum_lagrange_coeffs} (g^{i-1}) + - * \texttt{challenge_polynomial_lagrange[prev_idx]} (g^{i-1}) \cdot - * \texttt{libra_concatenated_lagrange_form[prev_idx]} (g^{i-1}) \f$ - * #### Masking Term - * - A random polynomial of degree 2 is generated and added to the Big Sum Polynomial. - * - The masking term is applied as \f$ Z_H(X) \cdot \texttt{masking_term} \f$, where \f$ Z_H(X) \f$ is the - * vanishing polynomial. - * - */ - void compute_big_sum_polynomial() - { - big_sum_lagrange_coeffs[0] = 0; - - // Compute the big sum coefficients recursively - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - size_t prev_idx = idx - 1; - big_sum_lagrange_coeffs[idx] = - big_sum_lagrange_coeffs[prev_idx] + - challenge_polynomial_lagrange.at(prev_idx) * libra_concatenated_lagrange_form.at(prev_idx); - }; - - // Get the coefficients in the monomial basis - if constexpr (!std::is_same_v) { - big_sum_polynomial_unmasked = Polynomial(interpolation_domain, big_sum_lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector big_sum_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(big_sum_lagrange_coeffs.data(), big_sum_ifft.data(), bn_evaluation_domain); - big_sum_polynomial_unmasked = Polynomial(big_sum_ifft); - } - // Generate random masking_term of degree 2, add Z_H(X) * masking_term - bb::Univariate masking_term = bb::Univariate::get_random(); - big_sum_polynomial += big_sum_polynomial_unmasked; - - for (size_t idx = 0; idx < masking_term.size(); idx++) { - big_sum_polynomial.at(idx) -= masking_term.value_at(idx); - big_sum_polynomial.at(idx + SUBGROUP_SIZE) += masking_term.value_at(idx); - } - }; + public: + // Default constructor to initialize all polynomials, transcript, and commitment key. + SmallSubgroupIPAProver(const std::shared_ptr& transcript, + std::shared_ptr& commitment_key); - /** - * @brief Compute \f$ L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) \f$, where \f$ g - * \f$ is the fixed generator of \f$ H \f$. - * - */ - void compute_batched_polynomial(const FF& claimed_evaluation) - { - // Compute shifted big sum polynomial A(gX) - Polynomial shifted_big_sum(SUBGROUP_SIZE + 3); + // Construct prover from ZKSumcheckData. Used by all ZK Provers. + SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, + const std::vector& multivariate_challenge, + const FF claimed_inner_product, + const std::shared_ptr& transcript, + std::shared_ptr& commitment_key); - for (size_t idx = 0; idx < SUBGROUP_SIZE + 3; idx++) { - shifted_big_sum.at(idx) = big_sum_polynomial.at(idx) * interpolation_domain[idx % SUBGROUP_SIZE]; - } + // Construct prover from TranslationData. Used by ECCVMProver. + SmallSubgroupIPAProver(TranslationData& translation_data, + const FF evaluation_challenge_x, + const FF batching_challenge_v, + const FF claimed_inner_product, + const std::shared_ptr& transcript, + std::shared_ptr& commitment_key); - const auto& [lagrange_first, lagrange_last] = - compute_lagrange_polynomials(interpolation_domain, bn_evaluation_domain); + void prove(); - // Compute -F(X)*G(X), the negated product of challenge_polynomial and libra_concatenated_monomial_form - for (size_t i = 0; i < concatenated_polynomial.size(); ++i) { - for (size_t j = 0; j < challenge_polynomial.size(); ++j) { - batched_polynomial.at(i + j) -= concatenated_polynomial.at(i) * challenge_polynomial.at(j); - } - } + void compute_challenge_polynomial(const std::vector& multivariate_challenge); - // Compute - F(X) * G(X) + A(gX) - A(X) - for (size_t idx = 0; idx < shifted_big_sum.size(); idx++) { - batched_polynomial.at(idx) += shifted_big_sum.at(idx) - big_sum_polynomial.at(idx); - } + void compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, const FF batching_challenge_v); - // Mutiply - F(X) * G(X) + A(gX) - A(X) by X-g: - // 1. Multiply by X - for (size_t idx = batched_polynomial.size() - 1; idx > 0; idx--) { - batched_polynomial.at(idx) = batched_polynomial.at(idx - 1); - } - batched_polynomial.at(0) = FF(0); - // 2. Subtract 1/g(A(gX) - A(X) - F(X) * G(X)) - for (size_t idx = 0; idx < batched_polynomial.size() - 1; idx++) { - batched_polynomial.at(idx) -= batched_polynomial.at(idx + 1) * interpolation_domain[SUBGROUP_SIZE - 1]; - } + void compute_grand_sum_polynomial(); - // Add (L_1 + L_{|H|}) * A(X) to the result - for (size_t i = 0; i < big_sum_polynomial.size(); ++i) { - for (size_t j = 0; j < SUBGROUP_SIZE; ++j) { - batched_polynomial.at(i + j) += big_sum_polynomial.at(i) * (lagrange_first.at(j) + lagrange_last.at(j)); - } - } - // Subtract L_{|H|} * s - for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { - batched_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_evaluation; - } - } - /** - * @brief Compute monomial coefficients of the first and last Lagrange polynomials - * - * @param interpolation_domain - * @param bn_evaluation_domain - * @return std::array, 2> - */ - std::array, 2> static compute_lagrange_polynomials( - const std::array& interpolation_domain, const EvaluationDomain& bn_evaluation_domain) - { - // Compute the monomial coefficients of L_1 - std::array lagrange_coeffs; - lagrange_coeffs[0] = FF(1); - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - lagrange_coeffs[idx] = FF(0); - } + void compute_grand_sum_identity_polynomial(); - Polynomial lagrange_first_monomial(SUBGROUP_SIZE); - if constexpr (!std::is_same_v) { - lagrange_first_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector lagrange_first_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_first_ifft.data(), bn_evaluation_domain); - lagrange_first_monomial = Polynomial(lagrange_first_ifft); - } + std::array, 2> static compute_lagrange_first_and_last( + const std::array& interpolation_domain, const EvaluationDomain& bn_evaluation_domain); - // Compute the monomial coefficients of L_{|H|}, the last Lagrange polynomial - lagrange_coeffs[0] = FF(0); - lagrange_coeffs[SUBGROUP_SIZE - 1] = FF(1); + void compute_grand_sum_identity_quotient(); - Polynomial lagrange_last_monomial; - if constexpr (!std::is_same_v) { - lagrange_last_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector lagrange_last_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_last_ifft.data(), bn_evaluation_domain); - lagrange_last_monomial = Polynomial(lagrange_last_ifft); - } + static FF compute_claimed_inner_product(ZKSumcheckData& zk_sumcheck_data, + const std::vector& multivariate_challenge, + const size_t& log_circuit_size); - return { lagrange_first_monomial, lagrange_last_monomial }; - } - /** @brief Efficiently compute the quotient of batched_polynomial by Z_H = X ^ { | H | } - 1 - */ - void compute_batched_quotient() - { + static FF compute_claimed_translation_inner_product(TranslationData& translation_data, + const FF& evaluation_challenge_x, + const FF& batching_challenge_v); - auto remainder = batched_polynomial; - for (size_t idx = BATCHED_POLYNOMIAL_LENGTH - 1; idx >= SUBGROUP_SIZE; idx--) { - batched_quotient.at(idx - SUBGROUP_SIZE) = remainder.at(idx); - remainder.at(idx - SUBGROUP_SIZE) += remainder.at(idx); - } - } + Polynomial static compute_monomial_coefficients(std::span lagrange_coeffs, + const std::array& interpolation_domain, + const EvaluationDomain& bn_evaluation_domain); - /** - * @brief For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck - * challenges. - * - * @param zk_sumcheck_data Contains Libra constant term and scaled Libra univariates - * @param multivariate_challenge Sumcheck challenge - * @param log_circuit_size - */ - static FF compute_claimed_inner_product(ZKSumcheckData& zk_sumcheck_data, - const std::vector& multivariate_challenge, - const size_t& log_circuit_size) + // Getter to pass the witnesses to ShpleminiProver. Grand sum polynomial appears twice, because it is evaluated at 2 + // points (and is small). + std::array, NUM_SMALL_IPA_EVALUATIONS> get_witness_polynomials() const { - const FF libra_challenge_inv = zk_sumcheck_data.libra_challenge.invert(); - // Compute claimed inner product similarly to the SumcheckProver - FF claimed_inner_product = FF{ 0 }; - size_t idx = 0; - for (const auto& univariate : zk_sumcheck_data.libra_univariates) { - claimed_inner_product += univariate.evaluate(multivariate_challenge[idx]); - idx++; - } - // Libra Univariates are mutiplied by the Libra challenge in setup_auxiliary_data(), needs to be undone - claimed_inner_product *= libra_challenge_inv / FF(1 << (log_circuit_size - 1)); - claimed_inner_product += zk_sumcheck_data.constant_term; - return claimed_inner_product; + return { concatenated_polynomial, grand_sum_polynomial, grand_sum_polynomial, grand_sum_identity_quotient }; } + // Getters for test purposes + const Polynomial& get_batched_polynomial() const { return grand_sum_identity_polynomial; } + const Polynomial& get_challenge_polynomial() const { return challenge_polynomial; } }; -/** - * @brief Verifier class for Small Subgroup IPA Prover. +/*! + * @brief Verifies the consistency of polynomial evaluations provided by the + * the prover. + * + * @details + * Given a subgroup of \f$ \mathbb{F}^\ast \f$, its generator \f$ g\f$, this function checks whether the following + * equation holds: \f[ L_1(r) A(r) + (r - g^{-1}) \left( A(g*r) - A(r) - F(r) G(r) \right) + L_{|H|}(r) \left( A(r) - s + * \right) = T(r) Z_H(r) \f] + * where the following evaluations are sent by the prover: + * - \f$ A(r), A(g\cdot r) \f$ are the evaluations of the "grand sum polynomial" + * - \f$ G(r) \f$ is the evaluation of the witness polynomial + * - \f$ Q(r) \f$ is the evaluation of the quotient of the big sum identity polynomial by the vanishing polynomial for + * \f$H\f$; and the following evaluations are computed by the verifier + * - \f$ L_1(r) \f$ and \f$ L_{|H|}(r) \f$ are the evaluations of Lagrange polynomials corresponding to \f$ 1 \f$ and + * \f$ g^{-1} \f$. + * - \f$ F(r) \f$ is the evaluation of a public polynomial formed from the challenges. + * - \f$ Z_H(r) \f$ is the vanishing polynomial \f$ X^{|H|} - 1\f$ evaluated at the challenge point. * - * @details Checks the consistency of polynomial evaluations provided by the prover against - * the values derived from the sumcheck challenge and a random evaluation challenge. */ template class SmallSubgroupIPAVerifier { using FF = typename Curve::ScalarField; static constexpr size_t SUBGROUP_SIZE = Curve::SUBGROUP_SIZE; + // The verifier has to evaluate 3 polynomials on its own, namely, the challenge polynomial F, Lagrange first + // L_1, and Lagrange last L_{H}. + static constexpr size_t NUM_BARYCENTRIC_EVALUATIONS = 3; + // The length of a random polynomial masking Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we // send the coefficients of the univariates, hence we choose these value to be the max sumcheck univariate length - // over Translator, Ultra, and Mega. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces the - // required length from 23 to 3. + // over Translator, UltraZK, and MegaZK. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces + // the required length from 23 to 3. static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Curve::LIBRA_UNIVARIATES_LENGTH; public: - /*! - * @brief Verifies the consistency of polynomial evaluations provided by the prover. - * - * @details - * Given a subgroup of \f$ \mathbb{F}^\ast \f$, its generator \f$ g\f$, this function checks whether the following - * equation holds: - * \f[ L_1(r) A(r) + (r - g^{-1}) \left( A(g*r) - A(r) - F(r) G(r) \right) + L_{|H|}(r) \left( A(r) - s - * \right) = T(r) Z_H(r) \f] Where the following are sent by the prover - * - \f$ A(r), A(g\cdot r) \f$ are the evaluation of the "big sum polynomial" - * - \f$ G(r) \f$ is the evaluation of the concatenation of the coefficients of the masking Libra polynomials - * - * - \f$ T(r) \f$ is the evaluation of the quotient of the left hand side above by the vanishing polynomial for - * \f$H\f$ - * and the following evaluations computed by the verifier - * - \f$ L_1 \f$ and \f$ L_{|H|} \f$ are the Lagrange polynomials corresponding to \f$ 1 \f$ and \f$ g^{-1} \f$. - * - \f$ F(r) \f$ is the evaluation of the polynomial obtained by concatenating powers of sumcheck round challenges - * - \f$ Z_H(r) \f$ is the vanishing polynomial \f$ X^{|H|} - 1\f$ evaluated at the challenge point. + /** + * @brief Generic consistency check agnostic to challenge polynomial \f$ F\f$. * - * @param libra_evaluations A vector of polynomial evaluations containing: - * - \f$ G(r), A(g\cdot r), A(r), T(r) \f$. - * @param gemini_evaluation_challenge The challenge point \f$ r \f$ at which evaluations are verified. - * @param multilinear_challenge A vector of sumcheck round challenges. - * @param eval_claim The claimed inner proudct of the coefficients of \f$G\f$ and \f$F\f$. - * @return True if the consistency check passes, false otherwise. + * @param small_ipa_evaluations \f$ G(r) \f$ , \f$ A(g* r) \f$, \f$ A(r) \f$ , \f$ Q(r)\f$. + * @param small_ipa_eval_challenge + * @param challenge_polynomial The polynomial \f$ F \f$ that the verifier computes and evaluates on its own. + * @param inner_product_eval_claim \f$ \f$ where the polynomials are treated as vectors of coefficients (in + * Lagrange basis). + * @param vanishing_poly_eval \f$ Z_H(r) \f$ + * @return true + * @return false */ - static bool check_evaluations_consistency(const std::array& libra_evaluations, - const FF& gemini_evaluation_challenge, - const std::vector& multilinear_challenge, - const FF& inner_product_eval_claim) + static bool check_consistency(const std::array& small_ipa_evaluations, + const FF& small_ipa_eval_challenge, + const std::vector& challenge_polynomial, + const FF& inner_product_eval_claim, + const FF& vanishing_poly_eval) { - - // Compute the evaluation of the vanishing polynomia Z_H(X) at X = gemini_evaluation_challenge - const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). Handle edge cases in PCS - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. - bool gemini_challenge_in_small_subgroup = false; - if constexpr (Curve::is_stdlib_type) { - gemini_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value()); - } else { - gemini_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0)); - } - // The probability of this event is negligible but it has to be processed correctly - if (gemini_challenge_in_small_subgroup) { - throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); - } - // Construct the challenge polynomial from the sumcheck challenge, the verifier has to evaluate it on its own - const std::vector challenge_polynomial_lagrange = compute_challenge_polynomial(multilinear_challenge); - - // Compute the evaluations of the challenge polynomial, Lagrange first, and Lagrange last for the fixed small - // subgroup + // Check if Z_H(r) = 0. + handle_edge_cases(vanishing_poly_eval); + // Compute evaluations at r of F, Lagrange first, and Lagrange last for the fixed small subgroup auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( - challenge_polynomial_lagrange, gemini_evaluation_challenge, vanishing_poly_eval); + challenge_polynomial, small_ipa_eval_challenge, vanishing_poly_eval); - const FF& concatenated_at_r = libra_evaluations[0]; - const FF& big_sum_shifted_eval = libra_evaluations[1]; - const FF& big_sum_eval = libra_evaluations[2]; - const FF& quotient_eval = libra_evaluations[3]; + const FF& concatenated_at_r = small_ipa_evaluations[0]; + const FF& grand_sum_shifted_eval = small_ipa_evaluations[1]; + const FF& grand_sum_eval = small_ipa_evaluations[2]; + const FF& quotient_eval = small_ipa_evaluations[3]; - // Compute the evaluation of - // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) - FF diff = lagrange_first * big_sum_eval; - diff += (gemini_evaluation_challenge - Curve::subgroup_generator_inverse) * - (big_sum_shifted_eval - big_sum_eval - concatenated_at_r * challenge_poly); - diff += lagrange_last * (big_sum_eval - inner_product_eval_claim) - vanishing_poly_eval * quotient_eval; + // Compute the evaluation of L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) - + // Z_H(X) * Q(X) + FF diff = lagrange_first * grand_sum_eval; + diff += (small_ipa_eval_challenge - Curve::subgroup_generator_inverse) * + (grand_sum_shifted_eval - grand_sum_eval - concatenated_at_r * challenge_poly); + diff += lagrange_last * (grand_sum_eval - inner_product_eval_claim) - vanishing_poly_eval * quotient_eval; if constexpr (Curve::is_stdlib_type) { if constexpr (std::is_same_v>) { @@ -498,42 +257,92 @@ template class SmallSubgroupIPAVerifier { diff.self_reduce(); } diff.assert_equal(FF(0)); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). + // Insecure pattern. return (diff.get_value() == FF(0).get_value()); } else { return (diff == FF(0)); }; + }; + + /** + * @brief A method required by ZKSumcheck. The challenge polynomial is concatenated from the powers of the sumcheck + * challenges. + * + * @param libra_evaluations Evaluations of the SmallSubgroupIPA witness polynomials when \f$ G \f$ is a + * concatenation of a masking constant term and Libra univariates. + * @param gemini_evaluation_challenge Random challenge \f$ r \f$ at which the Gemini fold polynomials are evaluated. + * @param multilinear_challenge Sumcheck challenge \f$ (u_0, \ldots, u_{d-1})\f$. + * @param inner_product_eval_claim Claimed inner product of \f$ F \f$ and \f$ G\f$. + * @return true + * @return false + */ + static bool check_libra_evaluations_consistency(const std::array& libra_evaluations, + const FF& gemini_evaluation_challenge, + const std::vector& multilinear_challenge, + const FF& inner_product_eval_claim) + { + + // Compute the evaluation of the vanishing polynomia Z_H(X) at X = + // gemini_evaluation_challenge + const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); + + return check_consistency(libra_evaluations, + gemini_evaluation_challenge, + compute_challenge_polynomial_coeffs(multilinear_challenge), + inner_product_eval_claim, + vanishing_poly_eval); + } + /** + * @brief A method required for the verification Translation Evaluations in the ECCVMVerifier. The challenge + * polynomial is concatenated from the products \f$ x^i \cdot v^j\f$. See the corresponding method for details. + * + * @param small_ipa_evaluations Evaluations of the SmallSubgroupIPA witness polynomials when \f$ G \f$ is a + * concatenation of the last MASKING_OFFSET entries in the NUM_TRANSLATION_EVALUATIONS polynomials. + * @param evaluation_challenge A random challenge sampled to obtain `small_ipa_evaluations` + * @param evaluation_challenge_x Evaluation challenge for NUM_TRANSLATION_EVALUATIONS univariate polynomials + * @param batching_challenge_v A challenge used to batch the evaluations at \f$ x \f$ . + * @param inner_product_eval_claim Claimed inner product of \f$ F \f$ and \f$ G\f$. + */ + static bool check_eccvm_evaluations_consistency( + const std::array& small_ipa_evaluations, + const FF& evaluation_challenge, + const FF& evaluation_challenge_x, + const FF& batching_challenge_v, + const FF& inner_product_eval_claim) + { + + // Compute the evaluation of the vanishing polynomia Z_H(X) at `evaluation_challenge` + const FF vanishing_poly_eval = evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); + + return check_consistency(small_ipa_evaluations, + evaluation_challenge, + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v), + inner_product_eval_claim, + vanishing_poly_eval); } /** - * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, u_{D-1})\f$, where \f$ D = - * \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier has to construct and evaluate the polynomial whose - * coefficients are given by \f$ (1, u_0, u_0^2, u_1,\ldots, 1, u_{D-1}, u_{D-1}^2) \f$. We spend \f$ D \f$ - * multiplications to construct the coefficients. + * @brief Check if the random evaluation challenge is in the SmallSubgroup. * - * @param multivariate_challenge - * @return Polynomial + * @param vanishing_poly_eval \f$ Z_H(r) = r^{\text{SUBGROUP_SIZE}} - 1 \f$. */ - static std::vector compute_challenge_polynomial(const std::vector& multivariate_challenge) + static void handle_edge_cases(const FF& vanishing_poly_eval) { - std::vector challenge_polynomial_lagrange(SUBGROUP_SIZE); - - challenge_polynomial_lagrange[0] = FF{ 1 }; - - // Populate the vector with the powers of the challenges - size_t round_idx = 0; - for (auto challenge : multivariate_challenge) { - size_t current_idx = 1 + LIBRA_UNIVARIATES_LENGTH * round_idx; // Compute the current index into the vector - challenge_polynomial_lagrange[current_idx] = FF(1); - for (size_t idx = current_idx + 1; idx < current_idx + LIBRA_UNIVARIATES_LENGTH; idx++) { - // Recursively compute the powers of the challenge up to the length of libra univariates - challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge; - } - round_idx++; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). Handle edge cases in PCS + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + bool evaluation_challenge_in_small_subgroup = false; + if constexpr (Curve::is_stdlib_type) { + evaluation_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value()); + } else { + evaluation_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0)); + } + // The probability of this event is negligible but it has to be processed correctly + if (evaluation_challenge_in_small_subgroup) { + throw_or_abort("Evaluation challenge is in the SmallSubgroup."); } - return challenge_polynomial_lagrange; } - /** * @brief Efficient batch evaluation of the challenge polynomial, Lagrange first, and Lagrange last * @@ -545,15 +354,15 @@ template class SmallSubgroupIPAVerifier { * @param coeffs Coefficients of the polynomial to be evaluated, in our case it is the challenge polynomial * @param r Evaluation point, we are using the Gemini evaluation challenge * @param inverse_root_of_unity Inverse of the generator of the subgroup H - * @return std::array + * @return std::array */ - static std::array compute_batched_barycentric_evaluations(const std::vector& coeffs, - const FF& r, - const FF& vanishing_poly_eval) + static std::array compute_batched_barycentric_evaluations( + const std::vector& coeffs, const FF& r, const FF& vanishing_poly_eval) { FF one = FF{ 1 }; - // Construct the denominators of the Lagrange polynomials evaluated at r + // Construct the denominators of the Lagrange polynomials evaluated + // at r std::array denominators; FF running_power = one; for (size_t i = 0; i < SUBGROUP_SIZE; ++i) { @@ -572,12 +381,82 @@ template class SmallSubgroupIPAVerifier { // Construct the evaluation of the polynomial using its evaluations over H, Lagrange first evaluated at r, // Lagrange last evaluated at r FF numerator = vanishing_poly_eval * FF(SUBGROUP_SIZE).invert(); // (r^n - 1) / n - std::array result{ std::inner_product(coeffs.begin(), coeffs.end(), denominators.begin(), FF(0)), - denominators[0], - denominators[SUBGROUP_SIZE - 1] }; + std::array result{ + std::inner_product(coeffs.begin(), coeffs.end(), denominators.begin(), FF(0)), + denominators[0], + denominators[SUBGROUP_SIZE - 1] + }; std::transform( result.begin(), result.end(), result.begin(), [&](FF& denominator) { return denominator * numerator; }); return result; } }; -} // namespace bb \ No newline at end of file + +/** + * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, u_{D-1})\f$, where \f$ D = + * \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier has to construct and evaluate the polynomial whose coefficients are + * given by \f$ (1, u_0, u_0^2, u_1,\ldots, 1, u_{D-1}, u_{D-1}^2) \f$. We spend \f$ D \f$ multiplications to construct + * the coefficients. + * + * @param multivariate_challenge + * @return Polynomial + */ +template +static std::vector compute_challenge_polynomial_coeffs( + const std::vector& multivariate_challenge) +{ + using FF = typename Curve::ScalarField; + + std::vector challenge_polynomial_lagrange(Curve::SUBGROUP_SIZE); + static constexpr size_t libra_univariates_length = Curve::LIBRA_UNIVARIATES_LENGTH; + + challenge_polynomial_lagrange[0] = FF{ 1 }; + + // Populate the vector with the powers of the challenges + size_t round_idx = 0; + for (auto challenge : multivariate_challenge) { + size_t current_idx = 1 + libra_univariates_length * round_idx; + challenge_polynomial_lagrange[current_idx] = FF(1); + for (size_t idx = current_idx + 1; idx < current_idx + libra_univariates_length; idx++) { + // Recursively compute the powers of the challenge up to the length of libra univariates + challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge; + } + round_idx++; + } + return challenge_polynomial_lagrange; +} + +/** + * @brief Denote \f$ M = \text{MASKING_OFFSET} \f$ and \f$ N = NUM_SMALL_IPA_EVALUTIONS\f$. Given an evaluation + * challenge \f$ x \f$ and a batching challenge \f$v\f$, compute the polynomial whose coefficients are given by the + * vector \f$ (1, x , x^2 , \ldots, x^{M - 1 }, v\cdot x, \ldots, v^{N-1} \cdot x^{M-2}, v^{N-1}, \cdot x^{M-1}, 0, + * \ldots, 0)\f$ in the Lagrange basis over the Small Subgroup. + * + * @tparam FF + * @param evaluation_challenge_x + * @param batching_challenge_v + * @param subgroup_size + * @return std::vector + */ +template +std::vector compute_eccvm_challenge_coeffs( + const typename Curve::ScalarField& evaluation_challenge_x, const typename Curve::ScalarField& batching_challenge_v) +{ + using FF = typename Curve::ScalarField; + std::vector coeffs_lagrange_basis(Curve::SUBGROUP_SIZE, FF{ 0 }); + + FF v_power = FF{ 1 }; + for (size_t poly_idx = 0; poly_idx < NUM_TRANSLATION_EVALUATIONS; poly_idx++) { + const size_t start = MASKING_OFFSET * poly_idx; + coeffs_lagrange_basis[start] = v_power; + + for (size_t idx = start + 1; idx < start + MASKING_OFFSET; idx++) { + coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; + } + + v_power *= batching_challenge_v; + } + + return coeffs_lagrange_basis; +} +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index cd58a2c854a8..061d6cb2e0f7 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -14,6 +14,8 @@ template class SmallSubgroupIPATest : public ::testing::Test { using Transcript = typename Flavor::Transcript; using FF = typename Curve::ScalarField; + static constexpr FF subgroup_generator = Curve::subgroup_generator; + static constexpr size_t log_circuit_size = 7; static constexpr size_t circuit_size = 1ULL << log_circuit_size; @@ -29,6 +31,17 @@ template class SmallSubgroupIPATest : public ::testing::Test { } return multivariate_challenge; } + + // A helper to evaluate the four IPA witness polynomials at x, x*g, x, x + std::array evaluate_small_ipa_witnesses( + const std::array, 4>& witness_polynomials) + { + // Hard-coded pattern of evaluation: (x, x*g, x, x) + return { witness_polynomials[0].evaluate(evaluation_challenge), + witness_polynomials[1].evaluate(evaluation_challenge * subgroup_generator), + witness_polynomials[2].evaluate(evaluation_challenge), + witness_polynomials[3].evaluate(evaluation_challenge) }; + } }; using TestFlavors = ::testing::Types; @@ -61,6 +74,8 @@ TYPED_TEST(SmallSubgroupIPATest, ProverComputationsCorrectness) SmallSubgroupIPA small_subgroup_ipa_prover = SmallSubgroupIPA(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck); + small_subgroup_ipa_prover.prove(); + const Polynomial batched_polynomial = small_subgroup_ipa_prover.get_batched_polynomial(); const Polynomial libra_concatenated_polynomial = small_subgroup_ipa_prover.get_witness_polynomials()[0]; const Polynomial batched_quotient = small_subgroup_ipa_prover.get_witness_polynomials()[3]; @@ -156,7 +171,7 @@ TYPED_TEST(SmallSubgroupIPATest, VerifierEvaluations) // Simulate the interaction between the prover and the verifier leading to the consistency check performed by the // verifier. -TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimple) +TYPED_TEST(SmallSubgroupIPATest, LibraEvaluationsConsistency) { using FF = typename TypeParam::FF; using Curve = typename TypeParam::Curve; @@ -182,24 +197,19 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimple) Prover small_subgroup_ipa_prover = Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck); - const std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = - small_subgroup_ipa_prover.get_witness_polynomials(); + small_subgroup_ipa_prover.prove(); - std::array libra_evaluations = { - witness_polynomials[0].evaluate(this->evaluation_challenge), - witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), - witness_polynomials[2].evaluate(this->evaluation_challenge), - witness_polynomials[3].evaluate(this->evaluation_challenge) - }; + const std::array small_ipa_evaluations = + this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); - bool consistency_checked = Verifier::check_evaluations_consistency( - libra_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); + bool consistency_checked = Verifier::check_libra_evaluations_consistency( + small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); EXPECT_TRUE(consistency_checked); } // Check that consistency check fails when some of the prover's data is corrupted. -TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) +TYPED_TEST(SmallSubgroupIPATest, LibraEvaluationsConsistencyFailure) { using FF = typename TypeParam::FF; using Curve = typename TypeParam::Curve; @@ -225,24 +235,139 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) Prover small_subgroup_ipa_prover = Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck); - std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = + small_subgroup_ipa_prover.prove(); + + std::array, NUM_SMALL_IPA_EVALUATIONS> witness_polynomials = small_subgroup_ipa_prover.get_witness_polynomials(); // Tamper with witness polynomials witness_polynomials[0].at(0) = FF::random_element(); - std::array libra_evaluations = { - witness_polynomials[0].evaluate(this->evaluation_challenge), - witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), - witness_polynomials[2].evaluate(this->evaluation_challenge), - witness_polynomials[3].evaluate(this->evaluation_challenge) - }; + const std::array small_ipa_evaluations = + this->evaluate_small_ipa_witnesses(witness_polynomials); - bool consistency_checked = Verifier::check_evaluations_consistency( - libra_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); + bool consistency_checked = Verifier::check_libra_evaluations_consistency( + small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); // Since witness polynomials were modified, the consistency check must fail EXPECT_FALSE(consistency_checked); } -} // namespace bb \ No newline at end of file +// Simulate the interaction between the prover and the verifier leading to the consistency check performed by the +// verifier. +TYPED_TEST(SmallSubgroupIPATest, TranslationMaskingTermConsistency) +{ + // TranslationData class is Grumpkin-specific + if constexpr (std::is_same_v) { + GTEST_SKIP(); + } else { + using Curve = typename TypeParam::Curve; + using FF = typename Curve::ScalarField; + using Verifier = SmallSubgroupIPAVerifier; + using Prover = SmallSubgroupIPAProver; + using CK = typename TypeParam::CommitmentKey; + + auto prover_transcript = TypeParam::Transcript::prover_init_empty(); + // Must satisfy num_wires * MASKING_OFFSET + 1 < SUBGROUP_SIZE + const size_t num_wires = 5; + + // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck. + static constexpr size_t log_subgroup_size = static_cast(numeric::get_msb(Curve::SUBGROUP_SIZE)); + std::shared_ptr ck = + create_commitment_key(std::max(this->circuit_size, 1ULL << (log_subgroup_size + 1))); + + // Generate transcript polynomials + std::vector> transcript_polynomials; + + for (size_t idx = 0; idx < num_wires; idx++) { + transcript_polynomials.push_back(Polynomial::random(this->circuit_size)); + } + + TranslationData translation_data( + RefVector>(transcript_polynomials), prover_transcript, ck); + + const FF evaluation_challenge_x = FF::random_element(); + const FF batching_challenge_v = FF::random_element(); + + const FF claimed_inner_product = Prover::compute_claimed_translation_inner_product( + translation_data, evaluation_challenge_x, batching_challenge_v); + + Prover small_subgroup_ipa_prover(translation_data, + evaluation_challenge_x, + batching_challenge_v, + claimed_inner_product, + prover_transcript, + ck); + small_subgroup_ipa_prover.prove(); + + const std::array small_ipa_evaluations = + this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); + + bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations, + this->evaluation_challenge, + evaluation_challenge_x, + batching_challenge_v, + claimed_inner_product); + + EXPECT_TRUE(consistency_checked); + } +}; +// Simulate the interaction between the prover and the verifier leading to the consistency check performed by the +// verifier. +TYPED_TEST(SmallSubgroupIPATest, TranslationMaskingTermConsistencyFailure) +{ + // TranslationData class is Grumpkin-specific + if constexpr (std::is_same_v) { + GTEST_SKIP(); + } else { + using Curve = typename TypeParam::Curve; + using FF = typename Curve::ScalarField; + using Verifier = SmallSubgroupIPAVerifier; + using Prover = SmallSubgroupIPAProver; + using CK = typename TypeParam::CommitmentKey; + + auto prover_transcript = TypeParam::Transcript::prover_init_empty(); + // Must satisfy num_wires * MASKING_OFFSET + 1 < SUBGROUP_SIZE + const size_t num_wires = 5; + + // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck. + static constexpr size_t log_subgroup_size = static_cast(numeric::get_msb(Curve::SUBGROUP_SIZE)); + std::shared_ptr ck = + create_commitment_key(std::max(this->circuit_size, 1ULL << (log_subgroup_size + 1))); + + // Generate transcript polynomials + std::vector> transcript_polynomials; + + for (size_t idx = 0; idx < num_wires; idx++) { + transcript_polynomials.push_back(Polynomial::random(this->circuit_size)); + } + + TranslationData translation_data( + RefVector>(transcript_polynomials), prover_transcript, ck); + + const FF evaluation_challenge_x = FF::random_element(); + const FF batching_challenge_v = FF::random_element(); + + const FF claimed_inner_product = FF::random_element(); + + Prover small_subgroup_ipa_prover(translation_data, + evaluation_challenge_x, + batching_challenge_v, + claimed_inner_product, + prover_transcript, + ck); + small_subgroup_ipa_prover.prove(); + + const std::array small_ipa_evaluations = + this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); + + bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations, + this->evaluation_challenge, + evaluation_challenge_x, + batching_challenge_v, + claimed_inner_product); + + EXPECT_TRUE(!consistency_checked); + } +} +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 29192b6016a8..698fa4df4e5b 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -23,7 +23,9 @@ static constexpr uint32_t MAX_DATABUS_SIZE = 10000; static constexpr uint32_t MASKING_OFFSET = 4; // For ZK Flavors: the number of the commitments required by Libra and SmallSubgroupIPA. static constexpr uint32_t NUM_LIBRA_COMMITMENTS = 3; -static constexpr uint32_t NUM_LIBRA_EVALUATIONS = 4; +// The SmallSubgroupIPA is a sub-protocol used in several Flavors, to prove claimed inner product, the Prover sends 4 +// extra evaluations +static constexpr uint32_t NUM_SMALL_IPA_EVALUATIONS = 4; static constexpr uint32_t MERGE_PROOF_SIZE = 65; // used to ensure mock proofs are generated correctly // There are 5 distinguished wires in ECCVM that have to be opened as univariates to establish the connection between diff --git a/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt index 55caefab48f5..4792ba1cc87e 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(eccvm sumcheck) \ No newline at end of file +barretenberg_module(eccvm sumcheck commitment_schemes) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp index d189d5efb53e..ba0272d69ccf 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp @@ -999,12 +999,12 @@ class ECCVMFlavor { std::array sumcheck_round_commitments; std::array, CONST_PROOF_SIZE_LOG_N> sumcheck_round_evaluations; FF libra_claimed_evaluation; - Commitment libra_big_sum_commitment; + Commitment libra_grand_sum_commitment; Commitment libra_quotient_commitment; std::array sumcheck_evaluations; FF libra_concatenation_eval; - FF libra_shifted_big_sum_eval; - FF libra_big_sum_eval; + FF libra_shifted_grand_sum_eval; + FF libra_grand_sum_eval; FF libra_quotient_eval; Commitment hiding_polynomial_commitment; FF hiding_polynomial_eval; @@ -1220,7 +1220,7 @@ class ECCVMFlavor { libra_claimed_evaluation = NativeTranscript::template deserialize_from_buffer(proof_data, num_frs_read); sumcheck_evaluations = NativeTranscript::template deserialize_from_buffer>( NativeTranscript::proof_data, num_frs_read); - libra_big_sum_commitment = + libra_grand_sum_commitment = NativeTranscript::template deserialize_from_buffer(proof_data, num_frs_read); libra_quotient_commitment = NativeTranscript::template deserialize_from_buffer(proof_data, num_frs_read); @@ -1235,8 +1235,8 @@ class ECCVMFlavor { gemini_fold_evals.push_back(deserialize_from_buffer(proof_data, num_frs_read)); } libra_concatenation_eval = deserialize_from_buffer(proof_data, num_frs_read); - libra_shifted_big_sum_eval = deserialize_from_buffer(proof_data, num_frs_read); - libra_big_sum_eval = deserialize_from_buffer(proof_data, num_frs_read); + libra_shifted_grand_sum_eval = deserialize_from_buffer(proof_data, num_frs_read); + libra_grand_sum_eval = deserialize_from_buffer(proof_data, num_frs_read); libra_quotient_eval = deserialize_from_buffer(proof_data, num_frs_read); shplonk_q_comm = deserialize_from_buffer(proof_data, num_frs_read); @@ -1375,7 +1375,7 @@ class ECCVMFlavor { NativeTranscript::template serialize_to_buffer(libra_claimed_evaluation, proof_data); NativeTranscript::template serialize_to_buffer(sumcheck_evaluations, NativeTranscript::proof_data); - NativeTranscript::template serialize_to_buffer(libra_big_sum_commitment, proof_data); + NativeTranscript::template serialize_to_buffer(libra_grand_sum_commitment, proof_data); NativeTranscript::template serialize_to_buffer(libra_quotient_commitment, proof_data); NativeTranscript::template serialize_to_buffer(hiding_polynomial_commitment, NativeTranscript::proof_data); NativeTranscript::template serialize_to_buffer(hiding_polynomial_eval, NativeTranscript::proof_data); @@ -1386,8 +1386,8 @@ class ECCVMFlavor { NativeTranscript::template serialize_to_buffer(gemini_fold_evals[i], proof_data); } NativeTranscript::template serialize_to_buffer(libra_concatenation_eval, proof_data); - NativeTranscript::template serialize_to_buffer(libra_shifted_big_sum_eval, proof_data); - NativeTranscript::template serialize_to_buffer(libra_big_sum_eval, proof_data); + NativeTranscript::template serialize_to_buffer(libra_shifted_grand_sum_eval, proof_data); + NativeTranscript::template serialize_to_buffer(libra_grand_sum_eval, proof_data); NativeTranscript::template serialize_to_buffer(libra_quotient_eval, proof_data); NativeTranscript::template serialize_to_buffer(shplonk_q_comm, proof_data); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index 4cd0e95814c9..a25631c6a3e9 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -141,6 +141,8 @@ void ECCVMProver::execute_pcs_rounds() sumcheck_output.claimed_libra_evaluation, transcript, key->commitment_key); + small_subgroup_ipa_prover.prove(); + // 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); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index c146e7ae1c69..6ae4ae9ba0cd 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -155,7 +155,7 @@ class ECCVMTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals); manifest_expected.add_entry(round, "Libra:claimed_evaluation", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:big_sum_commitment", frs_per_G); + manifest_expected.add_entry(round, "Libra:grand_sum_commitment", frs_per_G); manifest_expected.add_entry(round, "Libra:quotient_commitment", frs_per_G); manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G); manifest_expected.add_entry(round, "Gemini:masking_poly_eval", frs_per_Fr); @@ -174,8 +174,8 @@ class ECCVMTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "Gemini:a_" + idx, frs_per_Fr); } manifest_expected.add_entry(round, "Libra:concatenation_eval", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:shifted_big_sum_eval", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:big_sum_eval", frs_per_Fr); + manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", frs_per_Fr); + manifest_expected.add_entry(round, "Libra:grand_sum_eval", frs_per_Fr); manifest_expected.add_entry(round, "Libra:quotient_eval", frs_per_Fr); manifest_expected.add_challenge(round, "Shplonk:nu"); round++; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp new file mode 100644 index 000000000000..f5e0e577f49f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp @@ -0,0 +1,122 @@ +#pragma once +#include "barretenberg/eccvm/eccvm_flavor.hpp" +#include "barretenberg/goblin/translation_evaluations.hpp" +#include "barretenberg/transcript/transcript.hpp" + +namespace bb { + +/** + * @brief A class designed to accept the ECCVM `Transcript Polynomials`, concatenate their masking terms in Lagrange + * basis over the SmallSubgroup, and commit to the concatenation. + * + * @tparam Transcript + */ +template class TranslationData { + public: + using Flavor = ECCVMFlavor; + using FF = typename Flavor::FF; + using BF = typename Flavor::BF; + using Commitment = typename Flavor::Commitment; + using CommitmentKey = typename Flavor::CommitmentKey; + using Polynomial = typename Flavor::Polynomial; + static constexpr size_t SUBGROUP_SIZE = Flavor::Curve::SUBGROUP_SIZE; + + // A masking term of length 2 (degree 1) is required to mask [G] and G(r). + static constexpr size_t WITNESS_MASKING_TERM_LENGTH = 2; + static constexpr size_t MASKED_CONCATENATED_WITNESS_LENGTH = SUBGROUP_SIZE + WITNESS_MASKING_TERM_LENGTH; + + // M(X) whose Lagrange coefficients are given by (m_0||m_1|| ... || m_{NUM_TRANSLATION_EVALUATIONS-1} || 0 ||...||0) + Polynomial concatenated_polynomial_lagrange; + + // M(X) + Z_H(X) * R(X), where R(X) is a random polynomial of length = WITNESS_MASKING_TERM_LENGTH + Polynomial masked_concatenated_polynomial; + + // Interpolation domain {1, g, \ldots, g^{SUBGROUP_SIZE - 1}} required for Lagrange interpolation + std::array interpolation_domain; + + /** + * @brief Given masked `transcript_polynomials` \f$ \tilde{T}_i(X) = T_i(X) + X^{n - 1 - \text{MASKING_OFFSET}} + * \cdot m_i(X) \f$, for \f$ i = 0, \ldots, \text{NUM_TRANSLATION_EVALUATIONS}-1\f$, we extract and concatenate + * their masking terms \f$ m_i\f$. Let \f$ M(X) \f$ be the polynomial whose first + * \f$ \text{MASKING_OFFSET}* \text{NUM_TRANSLATION_EVALUATIONS}\f$ Lagrange coefficients over \f$ H \f$ are given + * by the concatenation of \f$ m_i \f$ padded by zeroes. To mask \f$ M(X) \f$ and commit to the masked polynomial, + * we need to compute its coefficients in the monomial basis. + * + * An object of this class is fed to the SmallSubgroupIPA prover to establish the claims about the inner product of + * Lagrange coefficients of \f$ M \f$ against the vectors of the following form.\f$(1, 1, x , x^2 , + * x^{\text{MASKING_OFFSET} - 1}, v , v\cdot x ,\ldots, ... , v^{T - 1}, v^{T-1} x , v^{T-1} x^2 , v^{T-1} + * x^{\text{MASKING_OFFSET} - 1} ).\f$ + * + * @param transcript_polynomials + * @param transcript + * @param commitment_key + */ + TranslationData(const RefVector& transcript_polynomials, + const std::shared_ptr& transcript, + std::shared_ptr& commitment_key) + : concatenated_polynomial_lagrange(SUBGROUP_SIZE) + , masked_concatenated_polynomial(MASKED_CONCATENATED_WITNESS_LENGTH) + { + // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has + // polynomials that may exceed the circuit size. + if (commitment_key->dyadic_size < MASKED_CONCATENATED_WITNESS_LENGTH) { + commitment_key = std::make_shared(MASKED_CONCATENATED_WITNESS_LENGTH); + } + // Create interpolation domain required for Lagrange interpolation + interpolation_domain[0] = FF{ 1 }; + + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + interpolation_domain[idx] = interpolation_domain[idx - 1] * Flavor::Curve::subgroup_generator; + } + // Concatenate the last entries of the `transcript_polynomials`. + compute_concatenated_polynomials(transcript_polynomials); + + // Commit to M(X) + Z_H(X)*R(X), where R is a random polynomial of WITNESS_MASKING_TERM_LENGTH. + transcript->template send_to_verifier("Translation:masking_term_commitment", + commitment_key->commit(masked_concatenated_polynomial)); + } + /** + * @brief Let \f$ T = NUM_TRANSLATION_EVALUATIONS \f$ and let \f$ m_0, ..., m_{T-1}\f$ be the vectors of last \f$ + * \text{MASKING_OFFSET} \f$ coeffs in each transcript poly \f$ \tilde{T}_i \f$, we compute the concatenation \f$ + * (m_0 || ... || m_{T-1})\f$ in Lagrange and monomial basis and mask the latter. + * + * @param transcript_polynomials + */ + void compute_concatenated_polynomials(const RefVector& transcript_polynomials) + { + const size_t circuit_size = transcript_polynomials[0].size(); + + std::array coeffs_lagrange_subgroup; + + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + coeffs_lagrange_subgroup[idx] = FF{ 0 }; + } + + // Extract the Lagrange coefficients of the concatenated masking term from the transcript polynomials + for (size_t poly_idx = 0; poly_idx < NUM_TRANSLATION_EVALUATIONS; poly_idx++) { + for (size_t idx = 0; idx < MASKING_OFFSET; idx++) { + size_t idx_to_populate = poly_idx * MASKING_OFFSET + idx; + coeffs_lagrange_subgroup[idx_to_populate] = + transcript_polynomials[poly_idx].at(circuit_size - MASKING_OFFSET + idx); + } + } + concatenated_polynomial_lagrange = Polynomial(coeffs_lagrange_subgroup); + + // Generate the masking term + auto masking_scalars = bb::Univariate::get_random(); + + // Compute monomial coefficients of the concatenated polynomial + Polynomial concatenated_monomial_form_unmasked(interpolation_domain, coeffs_lagrange_subgroup, SUBGROUP_SIZE); + + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + masked_concatenated_polynomial.at(idx) = concatenated_monomial_form_unmasked.at(idx); + } + + // Mask the polynomial in monomial form. + for (size_t idx = 0; idx < masking_scalars.size(); idx++) { + masked_concatenated_polynomial.at(idx) -= masking_scalars.value_at(idx); + masked_concatenated_polynomial.at(SUBGROUP_SIZE + idx) += masking_scalars.value_at(idx); + } + } +}; +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 6aa86917754f..580b1353fe49 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -66,7 +66,7 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); - libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[1] = transcript->template receive_from_prover("Libra:grand_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); // If Sumcheck did not verify, return false diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index 74ad13be5708..c4f7659823e5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -83,7 +83,7 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges); - libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[1] = transcript->template receive_from_prover("Libra:grand_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); // Compute the Shplemini accumulator consisting of the Shplonk evaluation and the commitments and scalars vector diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp index af2d5633cec9..011117161d99 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp @@ -117,7 +117,7 @@ UltraRecursiveVerifier_::Output UltraRecursiveVerifier_::verify_ // For MegaZKFlavor: the sumcheck output contains claimed evaluations of the Libra polynomials if constexpr (Flavor::HasZK) { - libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[1] = transcript->template receive_from_prover("Libra:grand_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); } // Execute Shplemini to produce a batch opening claim subsequently verified by a univariate PCS diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp index 60fa119d0bdb..6810b11ab3b4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp @@ -116,7 +116,7 @@ std::array TranslatorRecursiveVerifier_template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[1] = transcript->template receive_from_prover("Libra:grand_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); // Execute Shplemini diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_zk_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_zk_flavor.hpp index 7ed3964002d9..54288b7e6cd8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_zk_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_zk_flavor.hpp @@ -26,11 +26,11 @@ class MegaZKFlavor : public bb::MegaFlavor { Commitment libra_concatenation_commitment; FF libra_sum; FF libra_claimed_evaluation; - Commitment libra_big_sum_commitment; + Commitment libra_grand_sum_commitment; Commitment libra_quotient_commitment; FF libra_concatenation_eval; - FF libra_shifted_big_sum_eval; - FF libra_big_sum_eval; + FF libra_shifted_grand_sum_eval; + FF libra_grand_sum_eval; FF libra_quotient_eval; Commitment hiding_polynomial_commitment; FF hiding_polynomial_eval; @@ -102,7 +102,7 @@ class MegaZKFlavor : public bb::MegaFlavor { libra_claimed_evaluation = deserialize_from_buffer(proof_data, num_frs_read); this->sumcheck_evaluations = deserialize_from_buffer>(proof_data, num_frs_read); - libra_big_sum_commitment = deserialize_from_buffer(proof_data, num_frs_read); + libra_grand_sum_commitment = deserialize_from_buffer(proof_data, num_frs_read); libra_quotient_commitment = deserialize_from_buffer(proof_data, num_frs_read); hiding_polynomial_commitment = deserialize_from_buffer(proof_data, num_frs_read); hiding_polynomial_eval = deserialize_from_buffer(proof_data, num_frs_read); @@ -113,8 +113,8 @@ class MegaZKFlavor : public bb::MegaFlavor { this->gemini_fold_evals.push_back(deserialize_from_buffer(proof_data, num_frs_read)); } libra_concatenation_eval = deserialize_from_buffer(proof_data, num_frs_read); - libra_shifted_big_sum_eval = deserialize_from_buffer(proof_data, num_frs_read); - libra_big_sum_eval = deserialize_from_buffer(proof_data, num_frs_read); + libra_shifted_grand_sum_eval = deserialize_from_buffer(proof_data, num_frs_read); + libra_grand_sum_eval = deserialize_from_buffer(proof_data, num_frs_read); libra_quotient_eval = deserialize_from_buffer(proof_data, num_frs_read); this->shplonk_q_comm = deserialize_from_buffer(proof_data, num_frs_read); @@ -165,7 +165,7 @@ class MegaZKFlavor : public bb::MegaFlavor { serialize_to_buffer(libra_claimed_evaluation, proof_data); serialize_to_buffer(this->sumcheck_evaluations, proof_data); - serialize_to_buffer(libra_big_sum_commitment, proof_data); + serialize_to_buffer(libra_grand_sum_commitment, proof_data); serialize_to_buffer(libra_quotient_commitment, proof_data); serialize_to_buffer(hiding_polynomial_commitment, proof_data); serialize_to_buffer(hiding_polynomial_eval, proof_data); @@ -176,8 +176,8 @@ class MegaZKFlavor : public bb::MegaFlavor { serialize_to_buffer(this->gemini_fold_evals[i], proof_data); } serialize_to_buffer(libra_concatenation_eval, proof_data); - serialize_to_buffer(libra_shifted_big_sum_eval, proof_data); - serialize_to_buffer(libra_big_sum_eval, proof_data); + serialize_to_buffer(libra_shifted_grand_sum_eval, proof_data); + serialize_to_buffer(libra_grand_sum_eval, proof_data); serialize_to_buffer(libra_quotient_eval, proof_data); serialize_to_buffer(this->shplonk_q_comm, proof_data); serialize_to_buffer(this->kzg_w_comm, proof_data); @@ -187,4 +187,4 @@ class MegaZKFlavor : public bb::MegaFlavor { }; }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp index 22695ea3a0f7..c7dd08dddbd8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp @@ -24,11 +24,11 @@ class UltraKeccakZKFlavor : public UltraKeccakFlavor { Commitment libra_concatenation_commitment; FF libra_sum; FF libra_claimed_evaluation; - Commitment libra_big_sum_commitment; + Commitment libra_grand_sum_commitment; Commitment libra_quotient_commitment; FF libra_concatenation_eval; - FF libra_shifted_big_sum_eval; - FF libra_big_sum_eval; + FF libra_shifted_grand_sum_eval; + FF libra_grand_sum_eval; FF libra_quotient_eval; Commitment hiding_polynomial_commitment; FF hiding_polynomial_eval; @@ -94,7 +94,7 @@ class UltraKeccakZKFlavor : public UltraKeccakFlavor { libra_claimed_evaluation = Base::template deserialize_from_buffer(proof_data, num_frs_read); this->sumcheck_evaluations = Base::template deserialize_from_buffer>(proof_data, num_frs_read); - libra_big_sum_commitment = Base::template deserialize_from_buffer(proof_data, num_frs_read); + libra_grand_sum_commitment = Base::template deserialize_from_buffer(proof_data, num_frs_read); libra_quotient_commitment = Base::template deserialize_from_buffer(proof_data, num_frs_read); hiding_polynomial_commitment = Base::template deserialize_from_buffer(proof_data, num_frs_read); hiding_polynomial_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); @@ -106,8 +106,8 @@ class UltraKeccakZKFlavor : public UltraKeccakFlavor { this->gemini_fold_evals.push_back(Base::template deserialize_from_buffer(proof_data, num_frs_read)); } libra_concatenation_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); - libra_shifted_big_sum_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); - libra_big_sum_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); + libra_shifted_grand_sum_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); + libra_grand_sum_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); libra_quotient_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); this->shplonk_q_comm = Base::template deserialize_from_buffer(proof_data, num_frs_read); @@ -148,7 +148,7 @@ class UltraKeccakZKFlavor : public UltraKeccakFlavor { Base::template serialize_to_buffer(libra_claimed_evaluation, proof_data); Base::template serialize_to_buffer(this->sumcheck_evaluations, proof_data); - Base::template serialize_to_buffer(libra_big_sum_commitment, proof_data); + Base::template serialize_to_buffer(libra_grand_sum_commitment, proof_data); Base::template serialize_to_buffer(libra_quotient_commitment, proof_data); Base::template serialize_to_buffer(hiding_polynomial_commitment, proof_data); Base::template serialize_to_buffer(hiding_polynomial_eval, proof_data); @@ -159,8 +159,8 @@ class UltraKeccakZKFlavor : public UltraKeccakFlavor { Base::template serialize_to_buffer(this->gemini_fold_evals[i], proof_data); } Base::template serialize_to_buffer(libra_concatenation_eval, proof_data); - Base::template serialize_to_buffer(libra_shifted_big_sum_eval, proof_data); - Base::template serialize_to_buffer(libra_big_sum_eval, proof_data); + Base::template serialize_to_buffer(libra_shifted_grand_sum_eval, proof_data); + Base::template serialize_to_buffer(libra_grand_sum_eval, proof_data); Base::template serialize_to_buffer(libra_quotient_eval, proof_data); Base::template serialize_to_buffer(this->shplonk_q_comm, proof_data); Base::template serialize_to_buffer(this->kzg_w_comm, proof_data); @@ -169,4 +169,4 @@ class UltraKeccakZKFlavor : public UltraKeccakFlavor { } }; }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp index c5b10e22e7bf..ce05c1ce3e7e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp @@ -33,11 +33,11 @@ class UltraZKFlavor : public UltraFlavor { Commitment libra_concatenation_commitment; FF libra_sum; FF libra_claimed_evaluation; - Commitment libra_big_sum_commitment; + Commitment libra_grand_sum_commitment; Commitment libra_quotient_commitment; FF libra_concatenation_eval; - FF libra_shifted_big_sum_eval; - FF libra_big_sum_eval; + FF libra_shifted_grand_sum_eval; + FF libra_grand_sum_eval; FF libra_quotient_eval; Commitment hiding_polynomial_commitment; FF hiding_polynomial_eval; @@ -103,7 +103,7 @@ class UltraZKFlavor : public UltraFlavor { libra_claimed_evaluation = Base::template deserialize_from_buffer(proof_data, num_frs_read); this->sumcheck_evaluations = Base::template deserialize_from_buffer>(proof_data, num_frs_read); - libra_big_sum_commitment = Base::template deserialize_from_buffer(proof_data, num_frs_read); + libra_grand_sum_commitment = Base::template deserialize_from_buffer(proof_data, num_frs_read); libra_quotient_commitment = Base::template deserialize_from_buffer(proof_data, num_frs_read); hiding_polynomial_commitment = Base::template deserialize_from_buffer(proof_data, num_frs_read); hiding_polynomial_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); @@ -115,8 +115,8 @@ class UltraZKFlavor : public UltraFlavor { this->gemini_fold_evals.push_back(Base::template deserialize_from_buffer(proof_data, num_frs_read)); } libra_concatenation_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); - libra_shifted_big_sum_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); - libra_big_sum_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); + libra_shifted_grand_sum_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); + libra_grand_sum_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); libra_quotient_eval = Base::template deserialize_from_buffer(proof_data, num_frs_read); this->shplonk_q_comm = Base::template deserialize_from_buffer(proof_data, num_frs_read); @@ -157,7 +157,7 @@ class UltraZKFlavor : public UltraFlavor { Base::template serialize_to_buffer(libra_claimed_evaluation, proof_data); Base::template serialize_to_buffer(this->sumcheck_evaluations, proof_data); - Base::template serialize_to_buffer(libra_big_sum_commitment, proof_data); + Base::template serialize_to_buffer(libra_grand_sum_commitment, proof_data); Base::template serialize_to_buffer(libra_quotient_commitment, proof_data); Base::template serialize_to_buffer(hiding_polynomial_commitment, proof_data); Base::template serialize_to_buffer(hiding_polynomial_eval, proof_data); @@ -168,8 +168,8 @@ class UltraZKFlavor : public UltraFlavor { Base::template serialize_to_buffer(this->gemini_fold_evals[i], proof_data); } Base::template serialize_to_buffer(libra_concatenation_eval, proof_data); - Base::template serialize_to_buffer(libra_shifted_big_sum_eval, proof_data); - Base::template serialize_to_buffer(libra_big_sum_eval, proof_data); + Base::template serialize_to_buffer(libra_shifted_grand_sum_eval, proof_data); + Base::template serialize_to_buffer(libra_grand_sum_eval, proof_data); Base::template serialize_to_buffer(libra_quotient_eval, proof_data); Base::template serialize_to_buffer(this->shplonk_q_comm, proof_data); Base::template serialize_to_buffer(this->kzg_w_comm, proof_data); @@ -179,4 +179,4 @@ class UltraZKFlavor : public UltraFlavor { }; using Transcript = Transcript_; }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt index 74967d50486e..492ba2d5bcd0 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(translator_vm sumcheck) \ No newline at end of file +barretenberg_module(translator_vm sumcheck commitment_schemes) diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp index d57028525e5c..7218260192e0 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp @@ -149,6 +149,7 @@ void TranslatorProver::execute_pcs_rounds() sumcheck_output.claimed_libra_evaluation, transcript, key->proving_key->commitment_key); + small_subgroup_ipa_prover.prove(); PolynomialBatcher polynomial_batcher(key->proving_key->circuit_size); polynomial_batcher.set_unshifted(key->proving_key->polynomials.get_unshifted_without_concatenated()); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp index c83eaeb1643a..e1655cb45d00 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp @@ -110,7 +110,7 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof, return false; } - libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[1] = transcript->template receive_from_prover("Libra:grand_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); // Execute Shplemini diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt index cc7df8118f2c..2d4ac70e7efc 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(ultra_honk sumcheck stdlib_primitives stdlib_keccak stdlib_sha256) \ No newline at end of file +barretenberg_module(ultra_honk sumcheck commitment_schemes stdlib_primitives stdlib_keccak stdlib_sha256) diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp index 178756cff147..23e14c8e20d7 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp @@ -79,6 +79,7 @@ template void DeciderProver_::execute_pcs_rounds( SmallSubgroupIPA small_subgroup_ipa_prover( zk_sumcheck_data, sumcheck_output.challenge, sumcheck_output.claimed_libra_evaluation, transcript, ck); + small_subgroup_ipa_prover.prove(); prover_opening_claim = ShpleminiProver_::prove(proving_key->proving_key.circuit_size, polynomial_batcher, diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp index 3a09dd196191..aae52adbaf92 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp @@ -57,7 +57,7 @@ template bool DeciderVerifier_::verify() // For MegaZKFlavor: the sumcheck output contains claimed evaluations of the Libra polynomials if constexpr (Flavor::HasZK) { - libra_commitments[1] = transcript->template receive_from_prover("Libra:big_sum_commitment"); + libra_commitments[1] = transcript->template receive_from_prover("Libra:grand_sum_commitment"); libra_commitments[2] = transcript->template receive_from_prover("Libra:quotient_commitment"); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_transcript.test.cpp index b3fe19b10b67..1f8bf04d0bfb 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_transcript.test.cpp @@ -114,7 +114,7 @@ template class MegaTranscriptTests : public ::testing::Test { if constexpr (Flavor::HasZK) { manifest_expected.add_entry(round, "Libra:claimed_evaluation", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:big_sum_commitment", frs_per_G); + manifest_expected.add_entry(round, "Libra:grand_sum_commitment", frs_per_G); manifest_expected.add_entry(round, "Libra:quotient_commitment", frs_per_G); manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G); manifest_expected.add_entry(round, "Gemini:masking_poly_eval", frs_per_Fr); @@ -135,8 +135,8 @@ template class MegaTranscriptTests : public ::testing::Test { } if constexpr (Flavor::HasZK) { manifest_expected.add_entry(round, "Libra:concatenation_eval", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:shifted_big_sum_eval", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:big_sum_eval", frs_per_Fr); + manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", frs_per_Fr); + manifest_expected.add_entry(round, "Libra:grand_sum_eval", frs_per_Fr); manifest_expected.add_entry(round, "Libra:quotient_eval", frs_per_Fr); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index 26aefc31c462..8696ecd06633 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -113,7 +113,7 @@ template class UltraTranscriptTests : public ::testing::Test { if constexpr (Flavor::HasZK) { manifest_expected.add_entry(round, "Libra:claimed_evaluation", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:big_sum_commitment", frs_per_G); + manifest_expected.add_entry(round, "Libra:grand_sum_commitment", frs_per_G); manifest_expected.add_entry(round, "Libra:quotient_commitment", frs_per_G); manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G); manifest_expected.add_entry(round, "Gemini:masking_poly_eval", frs_per_Fr); @@ -135,8 +135,8 @@ template class UltraTranscriptTests : public ::testing::Test { if constexpr (Flavor::HasZK) { manifest_expected.add_entry(round, "Libra:concatenation_eval", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:shifted_big_sum_eval", frs_per_Fr); - manifest_expected.add_entry(round, "Libra:big_sum_eval", frs_per_Fr); + manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", frs_per_Fr); + manifest_expected.add_entry(round, "Libra:grand_sum_eval", frs_per_Fr); manifest_expected.add_entry(round, "Libra:quotient_eval", frs_per_Fr); }