diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp index 4116ca97afb0..4ca6bbc1d7d2 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp @@ -27,23 +27,6 @@ template class OpeningPair { bool operator==(const OpeningPair& other) const = default; }; -/** - * @brief Opening vector \f$(r,\{a_1, \dots, a_m\}, {v_1, \dots, v_m})\f$ for some witness polynomials \f$\{p_1(X), - * p_m(X)\}\f$ such that \f$\sum_i a_i p_i(r) = \sum_i a_i v_i\f$. - * - * @tparam Params for the given commitment scheme - */ -template class OpeningVector { - using Fr = typename Curve::ScalarField; - - public: - Fr challenge; // r - std::vector coefficients; // (a_1, \dots, a_m) - std::vector evaluations; // \sum_i a_i p_i(r) = \sum_i a_i v_i - - bool operator==(const OpeningVector& other) const = default; -}; - /** * @brief Polynomial p and an opening pair (r,v) such that p(r) = v * @@ -162,6 +145,8 @@ template class OpeningClaim { * * @details This structure is used in the `reduce_verify_batch_opening_claim` method of KZG or IPA. * + * @note This structure always represents a zero evaluation claim. + * * @tparam Curve: BN254 or Grumpkin. */ template struct BatchOpeningClaim { diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index 8684869433f4..78f4d31ff8fe 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -390,40 +390,54 @@ template class ShplonkVerifier_ { } } + /** + * Structure used to update the internal state of the Shplonk verifier. It represents a claim which is constructed + * as a linear combination of the commitments stored by the Shplonk verifier. The structure is composed of: + * - A list of indices = \f$(i_1, \dots, i_k)\f$ + * - A list of scalar coefficients = \f$(a_1, \dots, a_k)\f$ + * - An opening pair \f$(x, v)\f$ + * The state of the Shplonk verifier is updated so to add the check: + * \f[ \sum_{j=1}^k a_j f_{i_j}(x) = v \f] + * where \f${f_i}_i\f$ are the polynomials whose commitments are stored in the Shplonk verifier + * + * @note The challenge \f$x\f$ is stored redundantly for the purpose of the `update` method, but it is useful to + * expose the method `reduce_verification_vector_claims_no_finalize` + */ + // It is composed + struct LinearCombinationOfClaims { + std::vector indices; + std::vector scalars; + OpeningPair opening_pair; + }; + /** * @brief Update the internal state of the Shplonk verifier * - * @details Given a list of indices = \f$(i_1, \dots, i_k)\f$, a list of coefficients = \f$(a_1, \dots, a_k)\f$, an - * evaluation challenge = \f$x\f$, and a series of evaluations = \f$(v_1, \dots, v_k)\f$, update the internal - * state of the Shplonk verifier so to add the check - * \f[ \sum_{j=1}^k a_j f_{i_j}(x) = \sum_{j=1}^k a_j v_j \f] - * This amounts to update: + * @details Given a list of indices = \f$(i_1, \dots, i_k)\f$, a list of scalar coefficients = \f$(a_1, \dots, + * a_k)\f$, an opening pair $\f(x,v)\f$, and the inverse vanishing eval \f$\frac{1}{z - x}\f$, update the internal + * state of the Shplonk verifier so to add the check \f[ \sum_{j=1}^k a_j f_{i_j}(x) = v \f] This amounts to update: * - \f$s_{i_j} -= \frac{\nu^{i-1} * a_j}{z - x}\f$ - * - \f$\theta += \sum_{j=1}^k \nu^{i-1} \frac{a_j v_j}{z - x}\f$ + * - \f$\theta += \nu^{i-1} \frac{v}{z - x}\f$ * - * @param indices - * @param coefficients - * @param evaluations + * @param update_data * @param inverse_vanishing_eval */ - void update(const std::vector& indices, - const std::vector& coefficients, - const std::vector& evaluations, - const Fr& inverse_vanishing_eval) + void update(const LinearCombinationOfClaims& update_data, const Fr& inverse_vanishing_eval) { // Compute \nu^{i-1} / (z - x) auto scalar_factor = pows_of_nu[pow_idx] * inverse_vanishing_eval; - for (const auto& [index, coefficient, evaluation] : zip_view(indices, coefficients, evaluations)) { + for (const auto& [index, coefficient] : zip_view(update_data.indices, update_data.scalars)) { // \nu^{i-1} * a_j / (z - x) auto scaling_factor = scalar_factor * coefficient; // s_{i_j} -= \nu^{i-1} * a_j / (z - x) scalars[index + 1] -= scaling_factor; - // \theta += \nu^{i-1} * a_j * v_j / (z - x) - identity_scalar_coefficient += scaling_factor * evaluation; } + // \theta += \nu^{i-1} * v / (z - x) + identity_scalar_coefficient += scalar_factor * update_data.opening_pair.evaluation; + // Update `pow_idx` pow_idx += 1; } @@ -478,7 +492,7 @@ template class ShplonkVerifier_ { /** * @brief Instantiate a Shplonk verifier and update its state with the provided claims. * - * @param claims list of opening claims \f$(C_j, x_j, v_j)\f$ for a witness polynomial \f$f_j(X)\f$, s.t. + * @param claims List of opening claims \f$(C_j, x_j, v_j)\f$ for a witness polynomial \f$f_j(X)\f$, s.t. * \f$f_j(x_j) = v_j\f$. * @param transcript */ @@ -510,22 +524,21 @@ template class ShplonkVerifier_ { } for (size_t idx = 0; idx < claims.size(); idx++) { - verifier.update({ idx }, { Fr(1) }, { claims[idx].opening_pair.evaluation }, inverse_vanishing_evals[idx]); + verifier.update({ { idx }, { Fr(1) }, claims[idx].opening_pair }, inverse_vanishing_evals[idx]); } return verifier; }; /** - * @brief Instantiate a Shplonk verifier and update its state with the provided opening vectors. + * @brief Instantiate a Shplonk verifier and update its state with the provided data. * - * @param indices List \f${ (i_{j_1}, \dots, i_{j_k}) }_k \f$ of indices - * @param claims List of opening vectors \f$\{ (r, (a_{j_1}, \dots, a_{j_k}), (v_1, \dots, v_{j_k})) \}_k\f$ s.t. - * \f[ \sum_{l=1}^k a_{j_l} f_{j_l}(r) = \sum_{l=1}^k a_{j_l} v_{j_r} \f] - * where \f$f_1, \dots, f_m\f$ are the polynomials whose commitments are held by the Shplonk verifier. + * @param claims List of LinearCombinationOfClaims \f$\{ ( (i_{j_1}, \dots, i_{j_k}), (a_{j_1}, \dots, a_{j_k}), + * (r_k, v_k) ) + * \}_k\f$ s.t. \f[ \sum_{l=1}^k a_{j_l} f_{j_l}(r_k) = v_k \f] where \f$f_1, \dots, f_m\f$ are the polynomials + * whose commitments are held by the Shplonk verifier. */ - void reduce_verification_vector_claims_no_finalize(std::span> indices, - std::span> claims) + void reduce_verification_vector_claims_no_finalize(std::span claims) { const size_t num_claims = claims.size(); @@ -534,17 +547,17 @@ template class ShplonkVerifier_ { inverse_vanishing_evals.reserve(num_claims); if constexpr (Curve::is_stdlib_type) { for (const auto& claim : claims) { - inverse_vanishing_evals.emplace_back((this->z_challenge - claim.challenge).invert()); + inverse_vanishing_evals.emplace_back((this->z_challenge - claim.opening_pair.challenge).invert()); } } else { for (const auto& claim : claims) { - inverse_vanishing_evals.emplace_back(this->z_challenge - claim.challenge); + inverse_vanishing_evals.emplace_back(this->z_challenge - claim.opening_pair.challenge); } Fr::batch_invert(inverse_vanishing_evals); } - for (const auto& [idx, claim, inv] : zip_view(indices, claims, inverse_vanishing_evals)) { - this->update(idx, claim.coefficients, claim.evaluations, inv); + for (const auto& [claim, inv] : zip_view(claims, inverse_vanishing_evals)) { + this->update(claim, inv); } } @@ -553,16 +566,15 @@ template class ShplonkVerifier_ { * the challenge r. No verification happens so this function always succeeds. * * @param g1_identity the identity element for the Curve - * @param indices List \f${ (i_{j_1}, \dots, i_{j_k}) }_k \f$ of indices - * @param claims List of opening vectors \f$\{ (r, (a_{j_1}, \dots, a_{j_k}), (v_1, \dots, v_{j_k})) \}_k\f$ s.t. - * \f[ \sum_{l=1}^k a_{j_l} f_{j_l}(r) = \sum_{l=1}^k a_{j_l} v_{j_r} \f] - * where \f$f_1, \dots, f_m\f$ are the polynomials whose commitments are held by the Shplonk verifier. + * @param claims List of LinearCombinationOfClaims \f$\{ ( (i_{j_1}, \dots, i_{j_k}), (a_{j_1}, \dots, a_{j_k}), + * (r_k, v_k) ) + * \}_k\f$ s.t. \f[ \sum_{l=1}^k a_{j_l} f_{j_l}(r_k) = v_k \f] where \f$f_1, \dots, f_m\f$ are the polynomials + * whose commitments are held by the Shplonk verifier. */ - OpeningClaim reduce_vector_claims_verification(Commitment g1_identity, - std::span> indices, - std::span> claims) + OpeningClaim reduce_verification_vector_claims(Commitment g1_identity, + std::span claims) { - this->reduce_verification_vector_claims_no_finalize(indices, claims); + this->reduce_verification_vector_claims_no_finalize(claims); return this->finalize(g1_identity); }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.test.cpp index 52940232bacf..bb27dd0835fb 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.test.cpp @@ -53,7 +53,6 @@ TYPED_TEST(ShplonkTest, ShplonkLinearlyDependent) using ShplonkProver = ShplonkProver_; using ShplonkVerifier = ShplonkVerifier_; using Fr = typename TypeParam::ScalarField; - using OpeningVector = OpeningVector; auto prover_transcript = NativeTranscript::prover_init_empty(); @@ -74,22 +73,17 @@ TYPED_TEST(ShplonkTest, ShplonkLinearlyDependent) // Shplonk verification auto verifier_opening_claims = ClaimData::verifier_opening_claims(setup); - std::vector opening_vectors = { - { verifier_opening_claims[0].opening_pair.challenge, - { Fr(1) }, - { verifier_opening_claims[0].opening_pair.evaluation } }, - { verifier_opening_claims[1].opening_pair.challenge, - { Fr(1) }, - { verifier_opening_claims[1].opening_pair.evaluation } }, - { verifier_opening_claims[2].opening_pair.challenge, coefficients, evals } + std::vector update_data = { + { { 0 }, { Fr(1) }, verifier_opening_claims[0].opening_pair }, + { { 1 }, { Fr(1) }, verifier_opening_claims[1].opening_pair }, + { { 0, 1 }, coefficients, verifier_opening_claims[2].opening_pair }, }; - std::vector> indices = { { 0 }, { 1 }, { 0, 1 } }; auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); ShplonkVerifier verifier(commitments, verifier_transcript, verifier_opening_claims.size()); // Execute the shplonk verifier functionality const auto batched_verifier_claim = - verifier.reduce_vector_claims_verification(this->vk().get_g1_identity(), indices, opening_vectors); + verifier.reduce_verification_vector_claims(this->vk().get_g1_identity(), update_data); this->verify_opening_claim(batched_verifier_claim, batched_opening_claim.polynomial); } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplonk.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplonk.test.cpp index 6184cff9d108..90077494ab20 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplonk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplonk.test.cpp @@ -106,7 +106,6 @@ TYPED_TEST(ShplonkRecursionTest, LineralyDependent) using GroupElement = Curve::Element; using Commitment = typename Curve::AffineElement; using OpeningClaim = OpeningClaim; - using OpeningVector = OpeningVector; using Transcript = bb::BaseTranscript>; using StdlibProof = stdlib::Proof; @@ -145,8 +144,12 @@ TYPED_TEST(ShplonkRecursionTest, LineralyDependent) // Compute last commitment as it would happen in a circuit Commitment commit = GroupElement::batch_mul( { stdlib_opening_claims[0].commitment, stdlib_opening_claims[1].commitment }, { coeff1, coeff2 }); + + // Opening pair for the linear combination as it would be received by the Verifier from the Prover Fr r = Fr::from_witness(&builder, native_opening_claims[2].opening_pair.challenge); Fr eval = Fr::from_witness(&builder, native_opening_claims[2].opening_pair.evaluation); + + // Opening claim for the linear combination stdlib_opening_claims.emplace_back(OpeningClaim({ r, eval }, commit)); auto verifier_transcript = std::make_shared(); @@ -178,16 +181,18 @@ TYPED_TEST(ShplonkRecursionTest, LineralyDependent) auto [stdlib_commitments, stdlib_opening_pairs] = this->native_to_stdlib_pairs_and_commitments( &builder, native_opening_claims, native_opening_claims.size() - 1); - // Shplonk verifier functionality - cheap way - std::vector opening_vectors = { - { stdlib_opening_pairs[0].challenge, { Fr(1) }, { stdlib_opening_pairs[0].evaluation } }, - { stdlib_opening_pairs[1].challenge, { Fr(1) }, { stdlib_opening_pairs[1].evaluation } }, - { Fr::from_witness(&builder, native_opening_claims[2].opening_pair.challenge), - { coeff1, coeff2 }, - { Fr::from_witness(&builder, evals[0]), Fr::from_witness(&builder, evals[1]) } } + // Opening pair for the linear combination as it would be received by the Verifier from the Prover + Fr r = Fr::from_witness(&builder, native_opening_claims[2].opening_pair.challenge); + Fr eval = Fr::from_witness(&builder, native_opening_claims[2].opening_pair.evaluation); + + // Update data + std::vector update_data = { + { { 0 }, { Fr(1) }, stdlib_opening_pairs[0] }, + { { 1 }, { Fr(1) }, stdlib_opening_pairs[1] }, + { { 0, 1 }, { coeff1, coeff2 }, { r, eval } } }; - std::vector> indices = { { 0 }, { 1 }, { 0, 1 } }; + // Shplonk verifier functionality - cheap way auto verifier_transcript = std::make_shared(); verifier_transcript->load_proof(stdlib_proof); [[maybe_unused]] auto _ = verifier_transcript->template receive_from_prover("Init"); @@ -196,7 +201,7 @@ TYPED_TEST(ShplonkRecursionTest, LineralyDependent) // Execute the shplonk verifier functionality [[maybe_unused]] auto batched_verifier_claim = - verifier.reduce_vector_claims_verification(this->vk().get_g1_identity(), indices, opening_vectors); + verifier.reduce_verification_vector_claims(this->vk().get_g1_identity(), update_data); EXPECT_TRUE(CircuitChecker::check(builder));