diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp index 772b9130dfd..2f4b2cd88f4 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp @@ -60,7 +60,7 @@ void ipa_verify(State& state) noexcept auto verifier_transcript = std::make_shared(prover_transcript->proof_data); state.ResumeTiming(); - auto result = IPA::verify(vk, opening_claim, verifier_transcript); + auto result = IPA::reduce_verify(vk, opening_claim, verifier_transcript); ASSERT(result); } } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp index f6d98bbd7fa..cebb8c59c7a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp @@ -32,7 +32,7 @@ class ProxyCaller { const OpeningClaim& opening_claim, const std::shared_ptr& transcript) { - return IPA::verify_internal(vk, opening_claim, transcript); + return IPA::reduce_verify_internal(vk, opening_claim, transcript); } }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp index dfe6f6d94f0..ca7872285c6 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp @@ -35,7 +35,7 @@ namespace bb { * * @remark IPA is not a very intuitive algorithm, so here are a few things that might help internalize it: * - *1. Originally we have two vectors \f$\vec{a}\f$ and \f$\vec{b}\f$, which the product of which we want to prove, but + *1. Originally we have two vectors \f$\vec{a}\f$ and \f$\vec{b}\f$, whose product we want to prove, but *the prover can't just send vector \f$\vec{a}\f$ to the verifier, it can only provide a commitment \f$\langle\vec{a},\vec{G}\rangle\f$ *2. The verifier computes the \f$C'=C+\langle\vec{a},\vec{b}\rangle\cdot U\f$ to "bind" together the @@ -50,8 +50,8 @@ namespace bb { \alpha^{-1}\langle\vec{a}_{low},\vec{b}_{high}\rangle+\alpha \langle \vec{a}_{high},\vec{b}_{low}\rangle + \langle\vec{a}_{high},\vec{b}_{high}\rangle= \langle\vec{a},\vec{b}\rangle+\alpha^{-1}\langle\vec{a}_{low},\vec{b}_{high}\rangle+\alpha \langle - \vec{a}_{high},\vec{b}_{low}\rangle\f$, so if we provide commitments to - \f$\langle\vec{a}_{low},\vec{b}_{high}\rangle\f$ and \f$\langle \vec{a}_{high},\vec{b}_{low}\rangle\f$ the verifier + \vec{a}_{high},\vec{b}_{low}\rangle\f$, so if we provide commitments to the cross-terms + \f$\langle\vec{a}_{low},\vec{b}_{high}\rangle\f$ and \f$\langle \vec{a}_{high},\vec{b}_{low}\rangle\f$, the verifier can reduce initial commitment to the result \f$\langle \vec{a},\vec{b}\rangle U\f$ to the new commitment \f$\langle \vec{a}_{new},\vec{b}_{new}\rangle U\f$ *5. Analogously, if \f$\vec{G}_{new}=\vec{G}_{low}+\alpha^{-1}\vec{G}_{high}\f$, then we can reduce the initial @@ -71,14 +71,16 @@ namespace bb { * The old version of documentation is available at Old IPA documentation */ -template class IPA { - // clang-fromat on +template class IPA { + public: + using Curve = Curve_; using Fr = typename Curve::ScalarField; using GroupElement = typename Curve::Element; using Commitment = typename Curve::AffineElement; using CK = CommitmentKey; using VK = VerifierCommitmentKey; using Polynomial = bb::Polynomial; + using VerifierAccumulator = bool; // These allow access to internal functions so that we can never use a mock transcript unless it's fuzzing or testing of IPA specifically #ifdef IPA_TEST @@ -107,8 +109,10 @@ template class IPA { *1. Send the degree of \f$f(x)\f$ plus one, equal to \f$d\f$ to the verifier *2. Receive the generator challenge \f$u\f$ from the verifier. If it is zero, abort *3. Compute the auxiliary generator \f$U=u\cdot G\f$, where \f$G\f$ is a generator of \f$E(\mathbb{F}_p)\f$​ - *4. Set \f$\vec{G}_{k}=\vec{G}\f$, \f$\vec{a}_{k}=\vec{p}\f$ - *5. Compute the vector \f$\vec{b}_{k}=(1,\beta,\beta^2,...,\beta^{d-1})\f$ + *4. Set \f$\vec{G}_{k}=\vec{G}\f$, \f$\vec{a}_{k}=\vec{p}\f$ where \f$vec{p}\f$ represent the polynomial's + *coefficients + . *5. Compute the vector \f$\vec{b}_{k}=(1,\beta,\beta^2,...,\beta^{d-1})\f$ where \f$p(\beta)$\f is the + evaluation we wish to prove. *6. Perform \f$k\f$ rounds (for \f$i \in \{k,...,1\}\f$) of: * 1. Compute \f$L_{i-1}=\langle\vec{a}_{i\_low},\vec{G}_{i\_high}\rangle+\langle\vec{a}_{i\_low},\vec{b}_{i\_high}\rangle\cdot @@ -328,13 +332,11 @@ template class IPA { *9. Receive \f$\vec{a}_{0}\f$ of length 1 *10. Compute \f$C_{right}=a_{0}G_{s}+a_{0}b_{0}U\f$ *11. Check that \f$C_{right} = C_0\f$. If they match, return true. Otherwise return false. - * - * */ template - static bool verify_internal(const std::shared_ptr& vk, - const OpeningClaim& opening_claim, - const std::shared_ptr& transcript) + static VerifierAccumulator reduce_verify_internal(const std::shared_ptr& vk, + const OpeningClaim& opening_claim, + const std::shared_ptr& transcript) { // Step 1. // Receive polynomial_degree + 1 = d from the prover @@ -352,7 +354,6 @@ template class IPA { auto aux_generator = Commitment::one() * generator_challenge; auto log_poly_degree = static_cast(numeric::get_msb(poly_length)); - // Step 3. // Compute C' = C + f(\beta) ⋅ U GroupElement C_prime = opening_claim.commitment + (aux_generator * opening_claim.opening_pair.evaluation); @@ -495,11 +496,13 @@ template class IPA { * *@remark The verification procedure documentation is in \link IPA::verify_internal verify_internal \endlink */ - static bool verify(const std::shared_ptr& vk, - const OpeningClaim& opening_claim, - const std::shared_ptr& transcript) + // TODO(https://github.com/AztecProtocol/barretenberg/issues/912): Return the proper VerifierAccumulator once + // implemented + static VerifierAccumulator reduce_verify(const std::shared_ptr& vk, + const OpeningClaim& opening_claim, + const std::shared_ptr& transcript) { - return verify_internal(vk, opening_claim, transcript); + return reduce_verify_internal(vk, opening_claim, transcript); } }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp index 87f14d5630c..4defedb4500 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp @@ -1,3 +1,4 @@ + #include "../gemini/gemini.hpp" #include "../shplonk/shplonk.hpp" #include "./mock_transcript.hpp" @@ -71,7 +72,7 @@ TEST_F(IPATest, OpenZeroPolynomial) // initialize verifier transcript from proof data auto verifier_transcript = std::make_shared(prover_transcript->proof_data); - auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); + auto result = IPA::reduce_verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); } @@ -96,7 +97,7 @@ TEST_F(IPATest, OpenAtZero) // initialize verifier transcript from proof data auto verifier_transcript = std::make_shared(prover_transcript->proof_data); - auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); + auto result = IPA::reduce_verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); } @@ -144,7 +145,7 @@ TEST_F(IPATest, ChallengesAreZero) auto new_random_vector = random_vector; new_random_vector[i] = Fr::zero(); transcript->initialize(new_random_vector, lrs, { uint256_t(n) }); - EXPECT_ANY_THROW(IPA::verify_internal(this->vk(), opening_claim, transcript)); + EXPECT_ANY_THROW(IPA::reduce_verify_internal(this->vk(), opening_claim, transcript)); } } @@ -186,7 +187,7 @@ TEST_F(IPATest, AIsZeroAfterOneRound) transcript->reset_indices(); // Verify - EXPECT_TRUE(IPA::verify_internal(this->vk(), opening_claim, transcript)); + EXPECT_TRUE(IPA::reduce_verify_internal(this->vk(), opening_claim, transcript)); } #endif } // namespace bb @@ -225,7 +226,7 @@ TEST_F(IPATest, Open) // initialize verifier transcript from proof data auto verifier_transcript = std::make_shared(prover_transcript->proof_data); - auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); + auto result = IPA::reduce_verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); EXPECT_EQ(prover_transcript->get_manifest(), verifier_transcript->get_manifest()); @@ -321,7 +322,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) const auto shplonk_verifier_claim = ShplonkVerifier::reduce_verification(this->vk(), gemini_verifier_claim, verifier_transcript); - bool verified = IPA::verify(this->vk(), shplonk_verifier_claim, verifier_transcript); + auto result = IPA::reduce_verify(this->vk(), shplonk_verifier_claim, verifier_transcript); - EXPECT_EQ(verified, true); + EXPECT_EQ(result, true); } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp index ce360d83949..c763f3a2ecf 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp @@ -46,27 +46,6 @@ template class KZG { prover_trancript->send_to_verifier("KZG:W", quotient_commitment); }; - /** - * @brief Computes the KZG verification for an opening claim of a single polynomial commitment - * - * @param vk is the verification key which has a pairing check function - * @param claim OpeningClaim ({r, v}, C) - * @return e(P₀,[1]₁)e(P₁,[x]₂)≡ [1]ₜ where - * - P₀ = C − v⋅[1]₁ + r⋅[x]₁ - * - P₁ = [Q(x)]₁ - */ - static bool verify(const std::shared_ptr& vk, - const OpeningClaim& claim, - const std::shared_ptr& verifier_transcript) - { - auto quotient_commitment = verifier_transcript->template receive_from_prover("KZG:W"); - auto lhs = claim.commitment - (GroupElement::one() * claim.opening_pair.evaluation) + - (quotient_commitment * claim.opening_pair.challenge); - auto rhs = -quotient_commitment; - - return vk->pairing_check(lhs, rhs); - }; - /** * @brief Computes the input points for the pairing check needed to verify a KZG opening claim of a single * polynomial commitment. This reduction is non-interactive and always succeeds. @@ -102,7 +81,6 @@ template class KZG { } auto P_1 = -quotient_commitment; - return { P_0, P_1 }; }; }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp index 4ec38c45561..5271e92b890 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp @@ -44,9 +44,9 @@ TYPED_TEST(KZGTest, single) KZG::compute_opening_proof(this->ck(), opening_pair, witness, prover_transcript); auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); - bool verified = KZG::verify(this->vk(), opening_claim, verifier_transcript); + auto pairing_points = KZG::reduce_verify(opening_claim, verifier_transcript); - EXPECT_EQ(verified, true); + EXPECT_EQ(this->vk()->pairing_check(pairing_points[0], pairing_points[1]), true); } /** @@ -170,11 +170,11 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) // KZG verifier: // aggregates inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) - bool verified = KZG::verify(this->vk(), shplonk_verifier_claim, verifier_transcript); + auto pairing_points = KZG::reduce_verify(shplonk_verifier_claim, verifier_transcript); // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2) - EXPECT_EQ(verified, true); + EXPECT_EQ(this->vk()->pairing_check(pairing_points[0], pairing_points[1]), true); } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index d3cedc565a6..4811d32407a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -1,5 +1,7 @@ #pragma once +#include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/commitment_schemes/commitment_key.hpp" +#include "barretenberg/commitment_schemes/verification_key.hpp" #include "barretenberg/common/ref_span.hpp" #include "barretenberg/common/ref_vector.hpp" #include "barretenberg/common/zip_view.hpp" @@ -425,7 +427,6 @@ template class ZeroMorphProver_ { // Compute batched degree-check and ZM-identity quotient polynomial pi auto pi_polynomial = compute_batched_evaluation_and_degree_check_polynomial(zeta_x, Z_x, z_challenge); - // Compute opening proof for x_challenge using the underlying univariate PCS PCS::compute_opening_proof( commitment_key, { .challenge = x_challenge, .evaluation = FF(0) }, pi_polynomial, transcript); @@ -508,6 +509,7 @@ template class ZeroMorphVerifier_ { * * @note The concatenation term arises from an implementation detail in the Goblin Translator and is not part of the * conventional ZM protocol + * @param first_g1 first element in the SRS * @param f_commitments Commitments to unshifted polynomials [f_i] * @param g_commitments Commitments to to-be-shifted polynomials [g_i] * @param C_q_k Commitments to q_k @@ -518,7 +520,8 @@ template class ZeroMorphVerifier_ { * @param concatenation_groups_commitments * @return Commitment */ - static Commitment compute_C_Z_x(RefSpan f_commitments, + static Commitment compute_C_Z_x(Commitment first_g1, + RefSpan f_commitments, RefSpan g_commitments, std::span C_q_k, FF rho, @@ -541,11 +544,10 @@ template class ZeroMorphVerifier_ { if constexpr (Curve::is_stdlib_type) { auto builder = x_challenge.get_context(); scalars.emplace_back(FF(builder, -1) * batched_evaluation * x_challenge * phi_n_x); - commitments.emplace_back(Commitment::one(builder)); } else { scalars.emplace_back(FF(-1) * batched_evaluation * x_challenge * phi_n_x); - commitments.emplace_back(Commitment::one()); } + commitments.emplace_back(first_g1); // Add contribution: x * \sum_{i=0}^{m-1} \rho^i*[f_i] auto rho_pow = FF(1); @@ -626,23 +628,30 @@ template class ZeroMorphVerifier_ { } /** - * @brief Verify a set of multilinear evaluation claims for unshifted polynomials f_i and to-be-shifted - * polynomials g_i + * @brief Compute the univariate opening claim used in the last step of Zeromorph to verify the univariate PCS + * evaluation. * - * @param commitments Commitments to polynomials f_i and g_i (unshifted and to-be-shifted) - * @param claimed_evaluations Claimed evaluations v_i = f_i(u) and w_i = h_i(u) = g_i_shifted(u) - * @param multivariate_challenge Challenge point u + * @param unshifted_commitments + * @param to_be_shifted_commitments + * @param unshifted_evaluations + * @param shifted_evaluations + * @param multivariate_challenge + * @param first_g1 * @param transcript - * @return std::array Inputs to the final pairing check + * @param concatenation_group_commitments + * @param concatenated_evaluations + * @return OpeningClaim */ - static VerifierAccumulator verify(RefSpan unshifted_commitments, - RefSpan to_be_shifted_commitments, - RefSpan unshifted_evaluations, - RefSpan shifted_evaluations, - std::span multivariate_challenge, - auto& transcript, - const std::vector>& concatenation_group_commitments = {}, - RefSpan concatenated_evaluations = {}) + static OpeningClaim compute_univariate_evaluation_opening_claim( + RefSpan unshifted_commitments, + RefSpan to_be_shifted_commitments, + RefSpan unshifted_evaluations, + RefSpan shifted_evaluations, + std::span multivariate_challenge, + Commitment first_g1, + auto& transcript, + const std::vector>& concatenation_group_commitments = {}, + RefSpan concatenated_evaluations = {}) { size_t log_N = multivariate_challenge.size(); FF rho = transcript->template get_challenge("rho"); @@ -683,7 +692,8 @@ template class ZeroMorphVerifier_ { auto C_zeta_x = compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); // Compute commitment C_{Z_x} - Commitment C_Z_x = compute_C_Z_x(unshifted_commitments, + Commitment C_Z_x = compute_C_Z_x(first_g1, + unshifted_commitments, to_be_shifted_commitments, C_q_k, rho, @@ -694,26 +704,102 @@ template class ZeroMorphVerifier_ { // Compute commitment C_{\zeta,Z} Commitment C_zeta_Z; + FF evaluation; if constexpr (Curve::is_stdlib_type) { // Express operation as a batch_mul in order to use Goblinization if available auto builder = z_challenge.get_context(); std::vector scalars = { FF(builder, 1), z_challenge }; std::vector points = { C_zeta_x, C_Z_x }; C_zeta_Z = Commitment::batch_mul(points, scalars); + evaluation = FF(builder, 0); } else { C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; + evaluation = FF(0); } - // Define the evaluation (always zero by construction in this case) for the PCS opening - FF evaluation{ 0 }; - if constexpr (Curve::is_stdlib_type) { // add builder if in circuit context - auto builder = z_challenge.get_context(); - evaluation = FF(builder, 0); + return { .opening_pair = { .challenge = x_challenge, .evaluation = evaluation }, .commitment = C_zeta_Z }; + } + + /** + * @brief Verify a set of multilinear evaluation claims for unshifted polynomials f_i and to-be-shifted + * polynomials g_i + * + * @param commitments Commitments to polynomials f_i and g_i (unshifted and to-be-shifted) + * @param claimed_evaluations Claimed evaluations v_i = f_i(u) and w_i = h_i(u) = g_i_shifted(u) + * @param multivariate_challenge Challenge point u + * @param transcript + * @return VerifierAccumulator Inputs to the final PCS verification check that will be accumulated + */ + static VerifierAccumulator verify(RefSpan unshifted_commitments, + RefSpan to_be_shifted_commitments, + RefSpan unshifted_evaluations, + RefSpan shifted_evaluations, + std::span multivariate_challenge, + auto& transcript, + const std::vector>& concatenation_group_commitments = {}, + RefSpan concatenated_evaluations = {}) + { + Commitment first_g1; + + if constexpr (Curve::is_stdlib_type) { + auto builder = multivariate_challenge[0].get_context(); + first_g1 = Commitment::one(builder); + } else { + first_g1 = Commitment::one(); } + auto opening_claim = compute_univariate_evaluation_opening_claim(unshifted_commitments, + to_be_shifted_commitments, + unshifted_evaluations, + shifted_evaluations, + multivariate_challenge, + first_g1, + transcript, + concatenation_group_commitments, + concatenated_evaluations); + return PCS::reduce_verify(opening_claim, transcript); + } - return PCS::reduce_verify( - { .opening_pair = { .challenge = x_challenge, .evaluation = evaluation }, .commitment = C_zeta_Z }, - transcript); + /** + * @brief Verify a set of multilinear evaluation claims for unshifted polynomials f_i and to-be-shifted + * polynomials g_i. + * + * @details Identical purpose as the function above but used when the verification of the PCS evaluation protocol + * requires the verification key prior to the last step that is accumulated. + * + * @param commitments Commitments to polynomials f_i and g_i (unshifted and to-be-shifted) + * @param claimed_evaluations Claimed evaluations v_i = f_i(u) and w_i = h_i(u) = g_i_shifted(u) + * @param multivariate_challenge Challenge point u + * @param transcript + * @return VerifierAccumulator Inputs to the final PCS verification check that will be accumulated + */ + static VerifierAccumulator verify(RefSpan unshifted_commitments, + RefSpan to_be_shifted_commitments, + RefSpan unshifted_evaluations, + RefSpan shifted_evaluations, + std::span multivariate_challenge, + const std::shared_ptr>& vk, + auto& transcript, + const std::vector>& concatenation_group_commitments = {}, + RefSpan concatenated_evaluations = {}) + { + Commitment first_g1; + // Retrieve the first element in the SRS [1]_1 which will be different depending on the curve we operate on + if constexpr (Curve::is_stdlib_type) { + auto builder = multivariate_challenge[0].get_context(); + first_g1 = Commitment(builder, vk->srs->get_first_g1()); + } else { + first_g1 = vk->srs->get_first_g1(); + } + auto opening_claim = compute_univariate_evaluation_opening_claim(unshifted_commitments, + to_be_shifted_commitments, + unshifted_evaluations, + shifted_evaluations, + multivariate_challenge, + first_g1, + transcript, + concatenation_group_commitments, + concatenated_evaluations); + return PCS::reduce_verify(vk, opening_claim, transcript); } }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp index 7274300114e..3fcb56aa3af 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp @@ -1,5 +1,6 @@ #include "zeromorph.hpp" #include "../commitment_key.test.hpp" +#include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/commitment_schemes/kzg/kzg.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -14,6 +15,7 @@ template class ZeroMorphTest : public CommitmentTest; using Commitment = typename Curve::AffineElement; using GroupElement = typename Curve::Element; + using VerifierAccumulator = typename PCS::VerifierAccumulator; using ZeroMorphProver = ZeroMorphProver_; using ZeroMorphVerifier = ZeroMorphVerifier_; @@ -39,7 +41,7 @@ template class ZeroMorphTest : public CommitmentTest u_challenge = this->random_evaluation_point(log_N); @@ -90,15 +92,28 @@ template class ZeroMorphTest : public CommitmentTestvk()->pairing_check(pairing_points[0], pairing_points[1]); + VerifierAccumulator result; + bool verified = false; + if constexpr (std::same_as>) { + // Execute Verifier protocol without the need for vk prior the final check + result = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted + RefVector(g_commitments), // to-be-shifted + RefVector(v_evaluations), // unshifted + RefVector(w_evaluations), // shifted + u_challenge, + verifier_transcript); + verified = this->vk()->pairing_check(result[0], result[1]); + } else { + // Execute Verifier protocol with vk + result = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted + RefVector(g_commitments), // to-be-shifted + RefVector(v_evaluations), // unshifted + RefVector(w_evaluations), // shifted + u_challenge, + this->vk(), + verifier_transcript); + verified = result; + } // The prover and verifier manifests should agree EXPECT_EQ(prover_transcript->get_manifest(), verifier_transcript->get_manifest()); @@ -114,6 +129,7 @@ template class ZeroMorphWithConcatenationTest : public CommitmentTes using Polynomial = bb::Polynomial; using Commitment = typename Curve::AffineElement; using GroupElement = typename Curve::Element; + using VerifierAccumulator = typename PCS::VerifierAccumulator; using ZeroMorphProver = ZeroMorphProver_; using ZeroMorphVerifier = ZeroMorphVerifier_; @@ -243,27 +259,40 @@ template class ZeroMorphWithConcatenationTest : public CommitmentTes to_vector_of_ref_vectors(concatenation_groups)); auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); + VerifierAccumulator result; + if constexpr (std::same_as>) { + // Execute Verifier protocol without the need for vk prior the final check + result = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted + RefVector(g_commitments), // to-be-shifted + RefVector(v_evaluations), // unshifted + RefVector(w_evaluations), // shifted + u_challenge, + verifier_transcript, + to_vector_of_ref_vectors(concatenation_groups_commitments), + RefVector(c_evaluations)); + verified = this->vk()->pairing_check(result[0], result[1]); - // Execute Verifier protocol - auto pairing_points = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted - RefVector(g_commitments), // to-be-shifted - RefVector(v_evaluations), // unshifted - RefVector(w_evaluations), // shifted - u_challenge, - verifier_transcript, - to_vector_of_ref_vectors(concatenation_groups_commitments), - RefVector(c_evaluations)); - - verified = this->vk()->pairing_check(pairing_points[0], pairing_points[1]); + } else { + // Execute Verifier protocol with vk + result = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted + RefVector(g_commitments), // to-be-shifted + RefVector(v_evaluations), // unshifted + RefVector(w_evaluations), // shifted + u_challenge, + this->vk(), + verifier_transcript, + to_vector_of_ref_vectors(concatenation_groups_commitments), + RefVector(c_evaluations)); + verified = result; + } // The prover and verifier manifests should agree EXPECT_EQ(prover_transcript->get_manifest(), verifier_transcript->get_manifest()); - return verified; } }; -using PCSTypes = ::testing::Types>; +using PCSTypes = ::testing::Types, IPA>; TYPED_TEST_SUITE(ZeroMorphTest, PCSTypes); TYPED_TEST_SUITE(ZeroMorphWithConcatenationTest, PCSTypes); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index d7f8c7a6129..f7d367265ea 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -119,100 +119,19 @@ template void ECCVMProver_::execute_relation_chec } /** - * - Get rho challenge - * - Compute d+1 Fold polynomials and their evaluations. + * @brief Execute the ZeroMorph protocol to prove the multilinear evaluations produced by Sumcheck + * @details See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the unrolled protocol. * * */ -template void ECCVMProver_::execute_univariatization_round() +template void ECCVMProver_::execute_zeromorph_rounds() { - const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - - // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ - FF rho = transcript->template get_challenge("rho"); - std::vector rhos = gemini::powers_of_rho(rho, NUM_POLYNOMIALS); - - // Batch the unshifted polynomials and the to-be-shifted polynomials using ρ - Polynomial batched_poly_unshifted(key->circuit_size); // batched unshifted polynomials - size_t poly_idx = 0; // TODO(https://github.com/AztecProtocol/barretenberg/issues/391) zip - ASSERT(prover_polynomials.get_to_be_shifted().size() == prover_polynomials.get_shifted().size()); - - for (auto& unshifted_poly : prover_polynomials.get_unshifted()) { - ASSERT(poly_idx < rhos.size()); - batched_poly_unshifted.add_scaled(unshifted_poly, rhos[poly_idx]); - ++poly_idx; - } - - Polynomial batched_poly_to_be_shifted(key->circuit_size); // batched to-be-shifted polynomials - for (auto& to_be_shifted_poly : prover_polynomials.get_to_be_shifted()) { - ASSERT(poly_idx < rhos.size()); - batched_poly_to_be_shifted.add_scaled(to_be_shifted_poly, rhos[poly_idx]); - ++poly_idx; - }; - - // Compute d-1 polynomials Fold^(i), i = 1, ..., d-1. - gemini_polynomials = Gemini::compute_gemini_polynomials( - sumcheck_output.challenge, std::move(batched_poly_unshifted), std::move(batched_poly_to_be_shifted)); - - // Compute and add to trasnscript the commitments [Fold^(i)], i = 1, ..., d-1 - for (size_t l = 0; l < key->log_circuit_size - 1; ++l) { - transcript->send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1), - commitment_key->commit(gemini_polynomials[l + 2])); - } -} - -/** - * - Do Fiat-Shamir to get "r" challenge - * - Compute remaining two partially evaluated Fold polynomials Fold_{r}^(0) and Fold_{-r}^(0). - * - Compute and aggregate opening pairs (challenge, evaluation) for each of d Fold polynomials. - * - Add d-many Fold evaluations a_i, i = 0, ..., d-1 to the transcript, excluding eval of Fold_{r}^(0) - * */ -template void ECCVMProver_::execute_pcs_evaluation_round() -{ - const FF r_challenge = transcript->template get_challenge("Gemini:r"); - gemini_output = Gemini::compute_fold_polynomial_evaluations( - sumcheck_output.challenge, std::move(gemini_polynomials), r_challenge); - - for (size_t l = 0; l < key->log_circuit_size; ++l) { - std::string label = "Gemini:a_" + std::to_string(l); - const auto& evaluation = gemini_output.opening_pairs[l + 1].evaluation; - transcript->send_to_verifier(label, evaluation); - } -} - -/** - * - Do Fiat-Shamir to get "nu" challenge. - * - Compute commitment [Q]_1 - * */ -template void ECCVMProver_::execute_shplonk_batched_quotient_round() -{ - nu_challenge = transcript->template get_challenge("Shplonk:nu"); - - batched_quotient_Q = - Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge); - - // commit to Q(X) and add [Q] to the transcript - transcript->send_to_verifier("Shplonk:Q", commitment_key->commit(batched_quotient_Q)); -} - -/** - * - Do Fiat-Shamir to get "z" challenge. - * - Compute polynomial Q(X) - Q_z(X) - * */ -template void ECCVMProver_::execute_shplonk_partial_evaluation_round() -{ - const FF z_challenge = transcript->template get_challenge("Shplonk:z"); - - shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( - gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); -} -/** - * - Compute final PCS opening proof: - * - For KZG, this is the quotient commitment [W]_1 - * - For IPA, the vectors L and R - * */ -template void ECCVMProver_::execute_final_pcs_round() -{ - PCS::compute_opening_proof(commitment_key, shplonk_output.opening_pair, shplonk_output.witness, transcript); + ZeroMorph::prove(prover_polynomials.get_unshifted(), + prover_polynomials.get_to_be_shifted(), + sumcheck_output.claimed_evaluations.get_unshifted(), + sumcheck_output.claimed_evaluations.get_shifted(), + sumcheck_output.challenge, + commitment_key, + transcript); } /** @@ -266,7 +185,8 @@ template void ECCVMProver_::execute_transcript_co batching_scalar *= ipa_batching_challenge; } - // Compute a proof for the batched univariate opening + // TODO(https://github.com/AztecProtocol/barretenberg/issues/922): We are doing another round of IPA here with + // exactly the same labels and no domain separation so if/when labels are going to matter we are clashing. PCS::compute_opening_proof( commitment_key, { evaluation_challenge_x, batched_evaluation }, batched_univariate, transcript); @@ -294,15 +214,7 @@ template HonkProof& ECCVMProver_::construct_proof execute_relation_check_rounds(); - execute_univariatization_round(); - - execute_pcs_evaluation_round(); - - execute_shplonk_batched_quotient_round(); - - execute_shplonk_partial_evaluation_round(); - - execute_final_pcs_round(); + execute_zeromorph_rounds(); execute_transcript_consistency_univariate_opening_round(); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index 3d8aeead828..c4b895ecf88 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -1,6 +1,5 @@ #pragma once -#include "barretenberg/commitment_schemes/gemini/gemini.hpp" -#include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/flavor/ecc_vm.hpp" #include "barretenberg/goblin/translation_evaluations.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" @@ -24,6 +23,7 @@ template class ECCVMProver_ { using Curve = typename Flavor::Curve; using Transcript = typename Flavor::Transcript; using TranslationEvaluations = bb::TranslationEvaluations; + using ZeroMorph = ZeroMorphProver_; public: explicit ECCVMProver_(const std::shared_ptr& input_key, @@ -35,11 +35,7 @@ template class ECCVMProver_ { BB_PROFILE void execute_log_derivative_commitments_round(); BB_PROFILE void execute_grand_product_computation_round(); BB_PROFILE void execute_relation_check_rounds(); - BB_PROFILE void execute_univariatization_round(); - BB_PROFILE void execute_pcs_evaluation_round(); - BB_PROFILE void execute_shplonk_batched_quotient_round(); - BB_PROFILE void execute_shplonk_partial_evaluation_round(); - BB_PROFILE void execute_final_pcs_round(); + BB_PROFILE void execute_zeromorph_rounds(); BB_PROFILE void execute_transcript_consistency_univariate_opening_round(); HonkProof& export_proof(); @@ -72,13 +68,8 @@ template class ECCVMProver_ { FF translation_batching_challenge_v; // to be rederived by the translator verifier SumcheckOutput sumcheck_output; - GeminiProverOutput gemini_output; - ShplonkProverOutput shplonk_output; std::shared_ptr commitment_key; - using Gemini = GeminiProver_; - using Shplonk = ShplonkProver_; - private: HonkProof proof; }; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index d7f41fd4424..8b81dcf874e 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -31,11 +31,11 @@ template class ECCVMTranscriptTests : public ::testing::Test { * * @return TranscriptManifest */ - TranscriptManifest construct_eccvm_honk_manifest(size_t circuit_size, size_t ipa_poly_degree) + TranscriptManifest construct_eccvm_honk_manifest(size_t circuit_size, size_t log_ipa_poly_degree) { TranscriptManifest manifest_expected; - auto log_n = numeric::get_msb(circuit_size); + ASSERT(log_n == log_ipa_poly_degree); size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; // Size of types is number of bb::frs needed to represent the type @@ -147,31 +147,50 @@ template class ECCVMTranscriptTests : public ::testing::Test { manifest_expected.add_challenge(round, "rho"); round++; - for (size_t i = 1; i < log_n; ++i) { + for (size_t i = 0; i < log_n; ++i) { std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, frs_per_G); + manifest_expected.add_entry(round, "ZM:C_q_" + idx, frs_per_G); } - manifest_expected.add_challenge(round, "Gemini:r"); + manifest_expected.add_challenge(round, "ZM:y"); round++; + manifest_expected.add_entry(round, "ZM:C_q", frs_per_G); + manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); + + round++; + manifest_expected.add_entry(round, "IPA:poly_degree_plus_1", frs_per_uint32); + manifest_expected.add_challenge(round, "IPA:generator_challenge"); + for (size_t i = 0; i < log_n; ++i) { - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Gemini:a_" + idx, frs_per_Fr); + round++; + std::string idx = std::to_string(log_n - i - 1); + manifest_expected.add_entry(round, "IPA:L_" + idx, frs_per_G); + manifest_expected.add_entry(round, "IPA:R_" + idx, frs_per_G); + std::string label = "IPA:round_challenge_" + idx; + manifest_expected.add_challenge(round, label); } - manifest_expected.add_challenge(round, "Shplonk:nu"); round++; - manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G); - manifest_expected.add_challenge(round, "Shplonk:z"); + manifest_expected.add_entry(round, "IPA:a_0", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:hack_commitment", frs_per_G); + manifest_expected.add_challenge(round, "Translation:evaluation_challenge_x"); + + round++; + manifest_expected.add_entry(round, "Translation:op", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:Px", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:Py", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:z1", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:z2", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:hack_evaluation", frs_per_Fr); + manifest_expected.add_challenge(round, "Translation:ipa_batching_challenge"); round++; - manifest_expected.add_entry(round, "IPA:poly_degree", frs_per_uint32); + manifest_expected.add_entry(round, "IPA:poly_degree_plus_1", frs_per_uint32); manifest_expected.add_challenge(round, "IPA:generator_challenge"); - auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); - for (size_t i = 0; i < log_poly_degree; ++i) { + for (size_t i = 0; i < log_n; ++i) { round++; - std::string idx = std::to_string(i); + std::string idx = std::to_string(log_n - i - 1); manifest_expected.add_entry(round, "IPA:L_" + idx, frs_per_G); manifest_expected.add_entry(round, "IPA:R_" + idx, frs_per_G); std::string label = "IPA:round_challenge_" + idx; @@ -180,6 +199,7 @@ template class ECCVMTranscriptTests : public ::testing::Test { round++; manifest_expected.add_entry(round, "IPA:a_0", frs_per_Fr); + manifest_expected.add_challenge(round, "Translation:batching_challenge"); return manifest_expected; } @@ -227,8 +247,6 @@ TYPED_TEST_SUITE(ECCVMTranscriptTests, FlavorTypes); */ TYPED_TEST(ECCVMTranscriptTests, ProverManifestConsistency) { - GTEST_SKIP() << "TODO(https://github.com/AztecProtocol/barretenberg/issues/782): update and reinstate after the " - "protocol is finalized."; using Flavor = TypeParam; // Construct a simple circuit @@ -241,9 +259,8 @@ TYPED_TEST(ECCVMTranscriptTests, ProverManifestConsistency) // Check that the prover generated manifest agrees with the manifest hard coded in this suite auto manifest_expected = - this->construct_eccvm_honk_manifest(prover.key->circuit_size, prover.shplonk_output.witness.size()); + this->construct_eccvm_honk_manifest(prover.key->circuit_size, prover.sumcheck_output.challenge.size()); auto prover_manifest = prover.transcript->get_manifest(); - // Note: a manifest can be printed using manifest.print() for (size_t round = 0; round < manifest_expected.size(); ++round) { ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round; @@ -257,9 +274,6 @@ TYPED_TEST(ECCVMTranscriptTests, ProverManifestConsistency) */ TYPED_TEST(ECCVMTranscriptTests, VerifierManifestConsistency) { - GTEST_SKIP() << "TODO(https://github.com/AztecProtocol/barretenberg/issues/782): update and reinstate after the " - "protocol is finalized."; - using Flavor = TypeParam; // Construct a simple circuit @@ -279,7 +293,10 @@ TYPED_TEST(ECCVMTranscriptTests, VerifierManifestConsistency) auto verifier_manifest = verifier.transcript->get_manifest(); // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < prover_manifest.size(); ++round) { + // The last challenge generated by the ECCVM Prover is the translation univariate batching challenge and, on the + // verifier side, is only generated in the translator verifier hence the ECCVM prover's manifest will have one extra + // challenge + for (size_t round = 0; round < prover_manifest.size() - 1; ++round) { ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) << "Prover/Verifier manifest discrepency in round " << round; } @@ -313,9 +330,6 @@ TYPED_TEST(ECCVMTranscriptTests, ChallengeGenerationTest) TYPED_TEST(ECCVMTranscriptTests, StructureTest) { - GTEST_SKIP() << "TODO(https://github.com/AztecProtocol/barretenberg/issues/782): update and reinstate after the " - "protocol is finalized."; - using Flavor = TypeParam; // Construct a simple circuit @@ -331,16 +345,17 @@ TYPED_TEST(ECCVMTranscriptTests, StructureTest) // try deserializing and serializing with no changes and check proof is still valid prover.transcript->deserialize_full_transcript(); prover.transcript->serialize_full_transcript(); - EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid + EXPECT_TRUE( + verifier.verify_proof(prover.transcript->proof_data)); // we have changed nothing so proof is still valid typename Flavor::Commitment one_group_val = Flavor::Commitment::one(); auto rand_val = Flavor::FF::random_element(); prover.transcript->transcript_Px_comm = one_group_val * rand_val; // choose random object to modify EXPECT_TRUE(verifier.verify_proof( - prover.export_proof())); // we have not serialized it back to the proof so it should still be fine + prover.transcript->proof_data)); // we have not serialized it back to the proof so it should still be fine prover.transcript->serialize_full_transcript(); - EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it + EXPECT_FALSE(verifier.verify_proof(prover.transcript->proof_data)); // the proof is now wrong after serializing it prover.transcript->deserialize_full_transcript(); EXPECT_EQ(static_cast(prover.transcript->transcript_Px_comm), diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 71ce6e2ae6a..8db713a1034 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -1,6 +1,5 @@ #include "./eccvm_verifier.hpp" -#include "barretenberg/commitment_schemes/gemini/gemini.hpp" -#include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -32,15 +31,13 @@ template ECCVMVerifier_& ECCVMVerifier_::opera template bool ECCVMVerifier_::verify_proof(const HonkProof& proof) { using FF = typename Flavor::FF; - using GroupElement = typename Flavor::GroupElement; using Commitment = typename Flavor::Commitment; using PCS = typename Flavor::PCS; - using Curve = typename Flavor::Curve; - using Gemini = GeminiVerifier_; - using Shplonk = ShplonkVerifier_; + using ZeroMorph = ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; using Transcript = typename Flavor::Transcript; + using Curve = typename Flavor::Curve; RelationParameters relation_parameters; @@ -161,7 +158,7 @@ template bool ECCVMVerifier_::verify_proof(const HonkP gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } - auto [multivariate_challenge, purported_evaluations, sumcheck_verified] = + auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false @@ -169,69 +166,13 @@ template bool ECCVMVerifier_::verify_proof(const HonkP return false; } - // Execute Gemini/Shplonk verification: - - // Construct inputs for Gemini verifier: - // - Multivariate opening point u = (u_0, ..., u_{d-1}) - // - batched unshifted and to-be-shifted polynomial commitments - auto batched_commitment_unshifted = GroupElement::zero(); - auto batched_commitment_to_be_shifted = GroupElement::zero(); - const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - // Compute powers of batching challenge rho - FF rho = transcript->template get_challenge("rho"); - std::vector rhos = gemini::powers_of_rho(rho, NUM_POLYNOMIALS); - - // Compute batched multivariate evaluation - FF batched_evaluation = FF::zero(); - size_t evaluation_idx = 0; - for (auto& value : purported_evaluations.get_unshifted()) { - batched_evaluation += value * rhos[evaluation_idx]; - ++evaluation_idx; - } - for (auto& value : purported_evaluations.get_shifted()) { - batched_evaluation += value * rhos[evaluation_idx]; - ++evaluation_idx; - } - - // Construct batched commitment for NON-shifted polynomials - size_t commitment_idx = 0; - for (auto& commitment : commitments.get_unshifted()) { - // TODO(@zac-williamson)(https://github.com/AztecProtocol/barretenberg/issues/820) ensure ECCVM polynomial - // commitments are never points at infinity - if (commitment.y != 0) { - batched_commitment_unshifted += commitment * rhos[commitment_idx]; - } else { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/820) - } - ++commitment_idx; - } - - // Construct batched commitment for to-be-shifted polynomials - for (auto& commitment : commitments.get_to_be_shifted()) { - // TODO(@zac-williamson) ensure ECCVM polynomial commitments are never points at infinity (#2214) - if (commitment.y != 0) { - batched_commitment_to_be_shifted += commitment * rhos[commitment_idx]; - } else { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/820) - } - ++commitment_idx; - } - - // Produce a Gemini claim consisting of: - // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 - // - d+1 evaluations a_0_pos, and a_l, l = 0:d-1 - auto gemini_claim = Gemini::reduce_verification(multivariate_challenge, - batched_evaluation, - batched_commitment_unshifted, - batched_commitment_to_be_shifted, - transcript); - - // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) - auto shplonk_claim = Shplonk::reduce_verification(pcs_verification_key, gemini_claim, transcript); - - // Verify the Shplonk claim with KZG or IPA - auto multivariate_opening_verified = PCS::verify(pcs_verification_key, shplonk_claim, transcript); - + bool multivariate_opening_verified = ZeroMorph::verify(commitments.get_unshifted(), + commitments.get_to_be_shifted(), + claimed_evaluations.get_unshifted(), + claimed_evaluations.get_shifted(), + multivariate_challenge, + pcs_verification_key, + transcript); // Execute transcript consistency univariate opening round // TODO(#768): Find a better way to do this. See issue for details. bool univariate_opening_verified = false; @@ -271,7 +212,7 @@ template bool ECCVMVerifier_::verify_proof(const HonkP // Construct and verify batched opening claim OpeningClaim batched_univariate_claim = { { evaluation_challenge_x, batched_transcript_eval }, batched_commitment }; - univariate_opening_verified = PCS::verify(pcs_verification_key, batched_univariate_claim, transcript); + univariate_opening_verified = PCS::reduce_verify(pcs_verification_key, batched_univariate_claim, transcript); } return sumcheck_verified.value() && multivariate_opening_verified && univariate_opening_verified; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp index 72f62b589fe..aa77a8d1030 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp @@ -599,15 +599,23 @@ template class ECCVMBa Commitment lookup_inverses_comm; std::vector> sumcheck_univariates; std::array sumcheck_evaluations; - std::vector gemini_univariate_comms; - std::vector gemini_a_evals; - Commitment shplonk_q_comm; - Commitment kzg_w_comm; - // the rest are only for Grumpkin + std::vector zm_cq_comms; + Commitment zm_cq_comm; uint32_t ipa_poly_degree; std::vector ipa_l_comms; std::vector ipa_r_comms; FF ipa_a_0_eval; + Commitment translation_hack_comm; + FF translation_eval_op; + FF translation_eval_px; + FF translation_eval_py; + FF translation_eval_z1; + FF translation_eval_z2; + FF hack_eval; + uint32_t translation_ipa_poly_degree; + std::vector translation_ipa_l_comms; + std::vector translation_ipa_r_comms; + FF translation_ipa_a_0_eval; Transcript() = default; @@ -781,43 +789,60 @@ template class ECCVMBa } sumcheck_evaluations = NativeTranscript::template deserialize_from_buffer>( NativeTranscript::proof_data, num_frs_read); - for (size_t i = 0; i < log_n - 1; ++i) { - gemini_univariate_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read)); - } for (size_t i = 0; i < log_n; ++i) { - gemini_a_evals.emplace_back( - NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read)); + zm_cq_comms.push_back( + NativeTranscript::template deserialize_from_buffer(proof_data, num_frs_read)); + } + zm_cq_comm = NativeTranscript::template deserialize_from_buffer(proof_data, num_frs_read); + + ipa_poly_degree = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); + for (size_t i = 0; i < log_poly_degree; ++i) { + ipa_l_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); + ipa_r_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); } - shplonk_q_comm = NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read); - if (std::is_same>::value) { - kzg_w_comm = NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read); - } else if (std::is_same>::value) { - ipa_poly_degree = NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read); - auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); - for (size_t i = 0; i < log_poly_degree; ++i) { - ipa_l_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read)); - ipa_r_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read)); - } - ipa_a_0_eval = - NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); - } else { - throw_or_abort("Unsupported PCS"); + ipa_a_0_eval = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_hack_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + translation_eval_op = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_eval_px = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_eval_py = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_eval_z1 = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_eval_z2 = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + hack_eval = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + + translation_ipa_poly_degree = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + + for (size_t i = 0; i < log_poly_degree; ++i) { + translation_ipa_l_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); + translation_ipa_r_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); } + + translation_ipa_a_0_eval = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); } void serialize_full_transcript() { size_t old_proof_length = NativeTranscript::proof_data.size(); NativeTranscript::proof_data.clear(); - size_t log_n = numeric::get_msb(circuit_size); NativeTranscript::template serialize_to_buffer(circuit_size, NativeTranscript::proof_data); + size_t log_n = numeric::get_msb(circuit_size); + NativeTranscript::template serialize_to_buffer(transcript_add_comm, NativeTranscript::proof_data); NativeTranscript::template serialize_to_buffer(transcript_mul_comm, NativeTranscript::proof_data); NativeTranscript::template serialize_to_buffer(transcript_eq_comm, NativeTranscript::proof_data); @@ -903,26 +928,39 @@ template class ECCVMBa NativeTranscript::template serialize_to_buffer(sumcheck_univariates[i], NativeTranscript::proof_data); } NativeTranscript::template serialize_to_buffer(sumcheck_evaluations, NativeTranscript::proof_data); - for (size_t i = 0; i < log_n - 1; ++i) { - NativeTranscript::template serialize_to_buffer(gemini_univariate_comms[i], - NativeTranscript::proof_data); - } for (size_t i = 0; i < log_n; ++i) { - NativeTranscript::template serialize_to_buffer(gemini_a_evals[i], NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(zm_cq_comms[i], NativeTranscript::proof_data); } - NativeTranscript::template serialize_to_buffer(shplonk_q_comm, NativeTranscript::proof_data); - if (std::is_same>::value) { - NativeTranscript::template serialize_to_buffer(kzg_w_comm, NativeTranscript::proof_data); - } else if (std::is_same>::value) { - NativeTranscript::template serialize_to_buffer(ipa_poly_degree, NativeTranscript::proof_data); - auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); - for (size_t i = 0; i < log_poly_degree; ++i) { - NativeTranscript::template serialize_to_buffer(ipa_l_comms[i], NativeTranscript::proof_data); - NativeTranscript::template serialize_to_buffer(ipa_r_comms[i], NativeTranscript::proof_data); - } - - NativeTranscript::template serialize_to_buffer(ipa_a_0_eval, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(zm_cq_comm, NativeTranscript::proof_data); + + NativeTranscript::template serialize_to_buffer(ipa_poly_degree, NativeTranscript::proof_data); + + auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); + for (size_t i = 0; i < log_poly_degree; ++i) { + NativeTranscript::template serialize_to_buffer(ipa_l_comms[i], NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(ipa_r_comms[i], NativeTranscript::proof_data); } + + NativeTranscript::template serialize_to_buffer(ipa_a_0_eval, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_hack_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_op, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_px, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_py, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_z1, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_z2, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(hack_eval, NativeTranscript::proof_data); + + NativeTranscript::template serialize_to_buffer(translation_ipa_poly_degree, NativeTranscript::proof_data); + log_poly_degree = static_cast(numeric::get_msb(translation_ipa_poly_degree)); + for (size_t i = 0; i < log_poly_degree; ++i) { + NativeTranscript::template serialize_to_buffer(translation_ipa_l_comms[i], + NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_ipa_r_comms[i], + NativeTranscript::proof_data); + } + + serialize_to_buffer(translation_ipa_a_0_eval, proof_data); + ASSERT(NativeTranscript::proof_data.size() == old_proof_length); } }; diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index e4a033ece45..7f48253dffc 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -502,7 +502,7 @@ class GoblinUltraFlavor { std::array sumcheck_evaluations; std::vector zm_cq_comms; Commitment zm_cq_comm; - Commitment zm_pi_comm; + Commitment kzg_w_comm; Transcript_() = default; @@ -561,7 +561,7 @@ class GoblinUltraFlavor { zm_cq_comms.push_back(deserialize_from_buffer(proof_data, num_frs_read)); } zm_cq_comm = deserialize_from_buffer(proof_data, num_frs_read); - zm_pi_comm = deserialize_from_buffer(proof_data, num_frs_read); + kzg_w_comm = deserialize_from_buffer(proof_data, num_frs_read); } void serialize_full_transcript() @@ -597,7 +597,7 @@ class GoblinUltraFlavor { serialize_to_buffer(zm_cq_comms[i], proof_data); } serialize_to_buffer(zm_cq_comm, proof_data); - serialize_to_buffer(zm_pi_comm, proof_data); + serialize_to_buffer(kzg_w_comm, proof_data); ASSERT(proof_data.size() == old_proof_length); } diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index a2323eba35f..f807449ba57 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -474,7 +474,7 @@ class UltraFlavor { std::array sumcheck_evaluations; std::vector zm_cq_comms; Commitment zm_cq_comm; - Commitment zm_pi_comm; + Commitment kzg_w_comm; Transcript() = default; @@ -532,7 +532,7 @@ class UltraFlavor { zm_cq_comms.push_back(deserialize_from_buffer(proof_data, num_frs_read)); } zm_cq_comm = deserialize_from_buffer(proof_data, num_frs_read); - zm_pi_comm = deserialize_from_buffer(proof_data, num_frs_read); + kzg_w_comm = deserialize_from_buffer(proof_data, num_frs_read); } /** * @brief Serializes the structure variables into a FULL Ultra proof. Should be called only if @@ -565,7 +565,7 @@ class UltraFlavor { serialize_to_buffer(zm_cq_comms[i], proof_data); } serialize_to_buffer(zm_cq_comm, proof_data); - serialize_to_buffer(zm_pi_comm, proof_data); + serialize_to_buffer(kzg_w_comm, proof_data); // sanity check to make sure we generate the same length of proof as before. ASSERT(proof_data.size() == old_proof_length); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index 88905126d27..e217028e27b 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -55,8 +55,7 @@ template bool DeciderVerifier_::verify_proof(const Hon multivariate_challenge, transcript); - auto verified = - accumulator->verification_key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return sumcheck_verified.value() && verified; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp index 37138a4bfef..bf457cf0e18 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp @@ -116,13 +116,13 @@ std::array UltraRecursiveVerifier_::ve auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(relation_parameters, alpha, gate_challenges); // Execute ZeroMorph multilinear PCS evaluation verifier - auto pairing_points = ZeroMorph::verify(commitments.get_unshifted(), - commitments.get_to_be_shifted(), - claimed_evaluations.get_unshifted(), - claimed_evaluations.get_shifted(), - multivariate_challenge, - transcript); - return pairing_points; + auto verifier_accumulator = ZeroMorph::verify(commitments.get_unshifted(), + commitments.get_to_be_shifted(), + claimed_evaluations.get_unshifted(), + claimed_evaluations.get_shifted(), + multivariate_challenge, + transcript); + return verifier_accumulator; } template class UltraRecursiveVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp index 6cb2a9653d4..39288e665f4 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp @@ -244,7 +244,6 @@ bool GoblinTranslatorVerifier::verify_proof(const HonkProof& proof) // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { - info("sumcheck failed"); return false; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index 9ce6bada482..18e30a1cdaf 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -75,8 +75,8 @@ template bool MergeVerifier_::verify_proof(const HonkP OpeningClaim batched_claim = { { kappa, batched_eval }, batched_commitment }; - auto verified = PCS::verify(pcs_verification_key, batched_claim, transcript); - + auto pairing_points = PCS::reduce_verify(batched_claim, transcript); + auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return identity_checked && verified; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 6b20e56daa4..15f21c9ca74 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -76,18 +76,17 @@ template bool UltraVerifier_::verify_proof(const HonkP return false; } - // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the - // unrolled protocol. + // Execute ZeroMorph rounds and check the pcs verifier accumulator returned. See + // https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the unrolled protocol. auto pairing_points = ZeroMorph::verify(commitments.get_unshifted(), commitments.get_to_be_shifted(), claimed_evaluations.get_unshifted(), claimed_evaluations.get_shifted(), multivariate_challenge, transcript); - - auto verified = key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); - - return sumcheck_verified.value() && verified; + auto pcs_verified = key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + return sumcheck_verified.value() && pcs_verified; + ; } template class UltraVerifier_;