From c0153a593f731e67bb4fa62d3a2e2ab8866732e6 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 15 Jul 2025 05:42:36 +0000 Subject: [PATCH 01/27] [empty] Start merge-train. Choo choo. From 07723395a098acd3c34385c1819e6ba7bddfcc2c Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 12:00:11 +0200 Subject: [PATCH 02/27] feat!: Merge with degree check (#15562) We modify the Merge protocol so that it enforces that the subtable polynomial `t_j` has degree smaller than `subtable_size` as read from the proof. Closes https://github.com/AztecProtocol/barretenberg/issues/1442 **Details** As per the linked issue, we want to support ecc operations in app circuits. To ensure that app ecc ops do not modify ecc ops that happened before them, we need to ensure that the subtable length `t.size()` is smaller than the constant `l` by which we right shift `T_prev`. This is to ensure that `t + X^{l-1} T_prev` is indeed the polynomial corresponding to the column `t || T_prev`. We enforce this degree check in the merge protocol by requiring the prover to commit to `g(X) := X^{l-1} t(1/X)` and provide openings `c`, `d` of `t`, `g` at challenges `1/kappa`, `kappa`, respectively, for which we check `c * kappa^{l-1} = d`. To save on the number of MSMs performed, we use Shplonk to verify the following claims: - `t(X)` opens to `c` at `1/kappa` - `p(X) = t(X) + X^{l-1} T_prev(X) - T(X)` opens to `0` at `kappa` - `g(X) := X^{l-1} t(1/X)` opens to `d` at `kappa` --------- Co-authored-by: AztecBot Co-authored-by: sergei iakovenko <105737703+iakovenkos@users.noreply.github.com> Co-authored-by: ludamad Co-authored-by: Suyash Bagad Co-authored-by: Jonathan Hao Co-authored-by: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Co-authored-by: Raju Krishnamoorthy Co-authored-by: notnotraju Co-authored-by: Lucas Xia Co-authored-by: Khashayar Barooti Co-authored-by: Jean M <132435771+jeanmon@users.noreply.github.com> Co-authored-by: Alex Gherghisan Co-authored-by: Santiago Palladino Co-authored-by: Santiago Palladino Co-authored-by: ludamad Co-authored-by: maramihali --- ...test_civc_standalone_vks_havent_changed.sh | 2 +- .../commitment_schemes/shplonk/shplonk.hpp | 5 +- .../cpp/src/barretenberg/constants.hpp | 2 +- .../dsl/acir_format/mock_verifier_inputs.cpp | 17 +- .../barretenberg/polynomials/polynomial.cpp | 12 ++ .../barretenberg/polynomials/polynomial.hpp | 9 + .../polynomials/polynomial.test.cpp | 33 +++- .../merge_recursive_verifier.cpp | 178 ++++++++++------- .../merge_recursive_verifier.hpp | 4 +- .../merge_verifier/merge_verifier.test.cpp | 101 +++++++++- .../ultra_honk/mega_honk.test.cpp | 18 -- .../barretenberg/ultra_honk/merge_prover.cpp | 140 ++++++++------ .../ultra_honk/merge_verifier.cpp | 182 +++++++++++------- .../ultra_honk/merge_verifier.hpp | 1 - barretenberg/sol/lib/forge-std | 1 - barretenberg/sol/lib/openzeppelin-contracts | 1 - barretenberg/sol/lib/solidity-stringutils | 1 - bb-pilcom/powdr | 1 - l1-contracts/lib/circuits | 1 - l1-contracts/lib/forge-std | 1 - l1-contracts/lib/openzeppelin-contracts | 1 - 21 files changed, 480 insertions(+), 231 deletions(-) delete mode 160000 barretenberg/sol/lib/forge-std delete mode 160000 barretenberg/sol/lib/openzeppelin-contracts delete mode 160000 barretenberg/sol/lib/solidity-stringutils delete mode 160000 bb-pilcom/powdr delete mode 160000 l1-contracts/lib/circuits delete mode 160000 l1-contracts/lib/forge-std delete mode 160000 l1-contracts/lib/openzeppelin-contracts diff --git a/barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh b/barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh index 184a0149e1d6..3ecdb6146f8c 100755 --- a/barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh +++ b/barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh @@ -11,7 +11,7 @@ cd .. # - Generate a hash for versioning: sha256sum bb-civc-inputs.tar.gz # - Upload the compressed results: aws s3 cp bb-civc-inputs.tar.gz s3://aztec-ci-artifacts/protocol/bb-civc-inputs-[hash(0:8)].tar.gz # Note: In case of the "Test suite failed to run ... Unexpected token 'with' " error, need to run: docker pull aztecprotocol/build:3.0 -pinned_civc_inputs_url="https://aztec-ci-artifacts.s3.us-east-2.amazonaws.com/protocol/bb-civc-inputs-c8814328.tar.gz" +pinned_civc_inputs_url="https://aztec-ci-artifacts.s3.us-east-2.amazonaws.com/protocol/bb-civc-inputs-79e2c5e0.tar.gz" # For easily rerunning the inputs generation if [[ "${1:-}" == "--update_inputs" ]]; then diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index 78f4d31ff8fe..bd126810043c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -381,7 +381,9 @@ template class ShplonkVerifier_ { commitments.insert(commitments.end(), polynomial_commitments.begin(), polynomial_commitments.end()); scalars.insert(scalars.end(), commitments.size() - 1, Fr(0)); // Initialised as circuit constants - for (size_t idx = 0; idx < num_claims; idx++) { + // The first two powers of nu have already been initialized, we need another `num_claims - 2` powers to batch + // all the claims + for (size_t idx = 0; idx < num_claims - 2; idx++) { pows_of_nu.emplace_back(pows_of_nu.back() * pows_of_nu[1]); } @@ -481,6 +483,7 @@ template class ShplonkVerifier_ { * @param g1_identity * @return BatchOpeningClaim */ + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1475): Compute g1_identity inside the function body BatchOpeningClaim export_batch_opening_claim(const Commitment& g1_identity) { commitments.emplace_back(g1_identity); diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 229ba0de2a90..389e2d2e30fd 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -37,7 +37,7 @@ static constexpr uint32_t NUM_LIBRA_COMMITMENTS = 3; // extra evaluations static constexpr uint32_t NUM_SMALL_IPA_EVALUATIONS = 4; -static constexpr uint32_t MERGE_PROOF_SIZE = 49; // used to ensure mock proofs are generated correctly +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 // ECCVM and Translator diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp index cd424849349d..dca385c80d7f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp @@ -177,11 +177,10 @@ Goblin::MergeProof create_mock_merge_proof() // Populate mock subtable size proof.emplace_back(mock_val); - // There are 8 entities in the merge protocol (4 columns x 2 components; aggregate transcript, previous aggregate - // transcript) and 12 evalations (4 columns x 3 components; aggregate transcript, previous aggregate - // transcript, current transcript) - const size_t NUM_TRANSCRIPT_ENTITIES = 8; - const size_t NUM_TRANSCRIPT_EVALUATIONS = 12; + // There are 12 entities in the merge protocol (4 columns x 3 components: T_{prev,j}, T_j, g_j(X) = X^{l-1} t_j(X)) + // and 8 evaluations (4 columns x 2 components: g_j(kappa), t_j(1/kappa)) + const size_t NUM_TRANSCRIPT_ENTITIES = 12; + const size_t NUM_TRANSCRIPT_EVALUATIONS = 8; // Transcript poly commitments for (size_t i = 0; i < NUM_TRANSCRIPT_ENTITIES; ++i) { @@ -193,7 +192,13 @@ Goblin::MergeProof create_mock_merge_proof() for (size_t i = 0; i < NUM_TRANSCRIPT_EVALUATIONS; ++i) { proof.emplace_back(mock_val); } - // Batched KZG quotient commitment + + // Shplonk proof: commitment to the quotient + for (const FF& val : mock_commitment_frs) { + proof.emplace_back(val); + } + + // KZG proof: commitment to W for (const FF& val : mock_commitment_frs) { proof.emplace_back(val); } diff --git a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp index f357c66eb941..12ab345ea45b 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp @@ -368,6 +368,18 @@ template Polynomial Polynomial::right_shifted(const size_t return result; } +template Polynomial Polynomial::reverse() const +{ + const size_t end_index = this->end_index(); + const size_t start_index = this->start_index(); + const size_t poly_size = this->size(); + Polynomial reversed(/*size=*/poly_size, /*virtual_size=*/end_index); + for (size_t idx = end_index; idx > start_index; --idx) { + reversed.at(end_index - idx) = this->at(idx - 1); + } + return reversed; +} + template class Polynomial; template class Polynomial; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp index 5fa813534f78..2a2382f83508 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp @@ -179,6 +179,15 @@ template class Polynomial { */ Polynomial right_shifted(const size_t magnitude) const; + /** + * @brief Returns the polynomial equal to the reverse of self + * + * @details If the coefficients of self are \f$(a_0, \dots, a_n)\f$, we return the polynomial with coefficients + * \f$(a_n, \dots, a_0)\f$ + * @note Resulting polynomial uses new backing memory; n = self->size() + */ + Polynomial reverse() const; + /** * @brief evaluate multi-linear extension p(X_0,…,X_{n-1}) = \sum_i a_i*L_i(X_0,…,X_{n-1}) at u = * (u_0,…,u_{n-1}) If the polynomial is embedded into a lower dimension k; + const size_t SIZE = 10; + const size_t VIRTUAL_SIZE = 20; + const size_t START_IDX = 2; + const size_t END_IDX = SIZE + START_IDX; + auto poly = Polynomial::random(SIZE, VIRTUAL_SIZE, START_IDX); + + // Instantiate the shift via the right_shifted method + auto poly_reversed = poly.reverse(); + + EXPECT_EQ(poly_reversed.size(), poly.size()); + EXPECT_EQ(poly_reversed.virtual_size(), poly.end_index()); + + // The reversed is indeed the reversed + for (size_t i = 0; i < END_IDX; ++i) { + EXPECT_EQ(poly_reversed.get(END_IDX - 1 - i), poly.get(i)); + } + + // If I change the original polynomial, the reversed polynomial is not updated + FF initial_value = poly.at(3); + poly.at(3) = 25; + EXPECT_EQ(poly_reversed.at(END_IDX - 4), initial_value); +} + // Simple test/demonstration of share functionality TEST(Polynomial, Share) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp index ec8958a957bd..ed313b4d1dfb 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp @@ -5,6 +5,7 @@ // ===================== #include "barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp" +#include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" namespace bb::stdlib::recursion::goblin { @@ -18,98 +19,139 @@ MergeRecursiveVerifier_::MergeRecursiveVerifier_(CircuitBuilder* {} /** - * @brief Computes inputs to a pairing check that, if verified, establishes proper construction of the aggregate Goblin - * ECC op queue polynomials T_j, j = 1,2,3,4. - * @details Let T_j be the jth column of the aggregate ecc op table after prepending the subtable columns t_j containing - * the contribution from a single circuit. T_{j,prev} corresponds to the columns of the aggregate table at the - * previous stage. For each column we have the relationship T_j = t_j + right_shift(T_{j,prev}, k), where k is the - * length of the subtable columns t_j. This protocol demonstrates, assuming the length of t is at most k, that the - * aggregate ecc op table has been constructed correctly via the simple Schwartz-Zippel check: + * @brief Computes inputs to a pairing check that, if verified, establishes proper construction of the aggregate + * Goblin ECC op queue polynomials T_j, j = 1,2,3,4. + * @details Let \f$l_j\f$, \f$r_j\f$, \f$m_j\f$ be three vectors. The Merge wants to convince the verifier that the + * polynomials l_j, r_j, m_j for which they have sent commitments [l_j], [r_j], [m_j] satisfy + * - m_j(X) = l_j(X) + X^l r_j(X) (1) + * - deg(l_j(X)) < k (2) + * where k = shift_size. * - * T_j(\kappa) = t_j(\kappa) + \kappa^k * (T_{j,prev}(\kappa)). + * To check condition (1), the verifier samples a challenge kappa and request from the prover a proof that + * the polynomial + * p_j(X) = l_j(kappa) + kappa^k r_j(kappa) - m_j(kappa) + * opens to 0 at kappa. + * + * To check condition (2), the verifier requests from the prover the commitment to a polynomial g_j, and + * then requests proofs that + * l_j(1/kappa) = c g_j(kappa) = d + * Then, they verify c * kappa^{k-1} = d, which implies, up to negligible probability, that + * g_j(X) = X^{l-1} l_j(1/X), which means that deg(l_j(X)) < l. + * + * The verifier must therefore check 12 opening claims: p_j(kappa) = 0, l_j(1/kappa), g_j(kappa) + * We use Shplonk to verify the claims with a single MSM (instead of computing [p_j] from [l_j], [r_j], [m_j] + * and then open it). We initialize the Shplonk verifier with the following commitments: + * [l_1], [r_1], [m_1], [g_1], ..., [l_4], [r_4], [m_4], [g_4] + * Then, we verify the various claims: + * - p_j(kappa) = 0: The commitment to p_j is constructed from the commitments to l_j, r_j, m_j, so + * the claim passed to the Shplonk verifier specifies the indices of these commitments in + * the above vector: {4 * (j-1), 4 * (j-1) + 1, 4 * (j-1) + 2}, the coefficients + * reconstructing p_j from l_j, r_j, m_j: {1, kappa^k, -1}, and the claimed + * evaluation: 0. + * - l_j(1/kappa) = v_j: The index in this case is {4 * (j-1)}, the coefficient is { 1 }, and the evaluation is + * v_j. + * - g_j(kappa) = w_j: The index is {3 + 4 * (j-1)}, the coefficient is { 1 }, and the evaluation is w_j. + * The claims are passed in the following order: + * {kappa, 0}, {kappa, 0}, {kappa, 0}, {kappa, 0}, {1/kappa, v_1}, {kappa, w_1}, .., {1/kappa, v_4}, {kappa, w_4} + * + * In the Goblin scenario, we have: + * - \f$l_j = t_j, r_j = T_{prev,j}, m_j = T_j\f$ if we are prepending the subtable + * - \f$l_j = T_{prev,j}, r_j = t_j, m_j = T_j\f$ if we are appending the subtable * * @tparam CircuitBuilder * @param proof - * @param t_commitments The commitments to t_j read from the transcript by the PG recursive verifier with which the - * Merge recursive verifier shares a transcript - * @return std::array Inputs to final pairing + * @param t_commitments The commitments to t_j read from the transcript by the PG recursive verifier with which + * the Merge recursive verifier shares a transcript + * @return PairingPoints Inputs to final pairing */ template MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_::verify_proof( const stdlib::Proof& proof, const RefArray t_commitments) { - // Transform proof into a stdlib object + using Claims = typename ShplonkVerifier_::LinearCombinationOfClaims; + transcript->load_proof(proof); - FF subtable_size = transcript->template receive_from_prover("subtable_size"); + FF shift_size = transcript->template receive_from_prover("shift_size"); + BB_ASSERT_GT(shift_size.get_value(), 0U, "Shift size should always be bigger than 0"); - // Receive table column polynomial commitments [T_{j,prev}], and [T_j], j = 1,2,3,4 - std::array T_prev_commitments; + // Vector of commitments to be passed to the Shplonk verifier + // The vector is composed of: [l_1], [r_1], [m_1], [g_1], ..., [l_4], [r_4], [m_4], [g_4] + std::vector table_commitments; for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - std::string suffix = std::to_string(idx); - T_prev_commitments[idx] = transcript->template receive_from_prover("T_PREV_" + suffix); - T_commitments[idx] = transcript->template receive_from_prover("T_CURRENT_" + suffix); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1473): remove receiving commitment to T_prev + auto T_prev_commitment = transcript->template receive_from_prover("T_PREV_" + std::to_string(idx)); + auto left_table = settings == MergeSettings::PREPEND ? t_commitments[idx] : T_prev_commitment; + auto right_table = settings == MergeSettings::PREPEND ? T_prev_commitment : t_commitments[idx]; + + table_commitments.emplace_back(left_table); + table_commitments.emplace_back(right_table); + table_commitments.emplace_back( + transcript->template receive_from_prover("MERGED_TABLE_" + std::to_string(idx))); + table_commitments.emplace_back( + transcript->template receive_from_prover("LEFT_TABLE_REVERSED_" + std::to_string(idx))); } - FF kappa = transcript->template get_challenge("kappa"); - - // Receive evaluations t_j(\kappa), T_{j,prev}(\kappa), T_j(\kappa), j = 1,2,3,4 - std::array t_evals; - std::array T_prev_evals; - std::array T_evals; - std::vector opening_claims; - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - t_evals[idx] = transcript->template receive_from_prover("t_eval_" + std::to_string(idx + 1)); - opening_claims.emplace_back(OpeningClaim{ { kappa, t_evals[idx] }, t_commitments[idx] }); - } - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - T_prev_evals[idx] = transcript->template receive_from_prover("T_prev_eval_" + std::to_string(idx + 1)); - opening_claims.emplace_back(OpeningClaim{ { kappa, T_prev_evals[idx] }, T_prev_commitments[idx] }); - } - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - T_evals[idx] = transcript->template receive_from_prover("T_eval_" + std::to_string(idx + 1)); - opening_claims.emplace_back(OpeningClaim{ { kappa, T_evals[idx] }, T_commitments[idx] }); + // Store T_commitments of the verifier + size_t commitment_idx = 2; // Index of [m_j = T_j] in the vector of commitments + for (auto& commitment : T_commitments) { + commitment = table_commitments[commitment_idx]; + commitment_idx += NUM_WIRES; } - // Check the appropriate identity based on the given merge settings + // Evaluation challenge + const FF kappa = transcript->template get_challenge("kappa"); + const FF kappa_inv = kappa.invert(); + const FF pow_kappa = kappa.pow(shift_size); + const FF pow_kappa_minus_one = pow_kappa * kappa_inv; + + // Opening claims to be passed to the Shplonk verifier + std::vector opening_claims; + + // Add opening claim for p_j(X) = l_j(X) + X^k r_j(X) - m_j(X) + commitment_idx = 0; for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - if (settings == MergeSettings::PREPEND) { - // T_j(\kappa) = t_j(\kappa) + \kappa^m * T_{j,prev}(\kappa) - FF T_prev_shifted_eval_reconstructed = T_prev_evals[idx] * kappa.pow(subtable_size); - T_evals[idx].assert_equal(t_evals[idx] + T_prev_shifted_eval_reconstructed); - } else { - // T_j(\kappa) = T_{j,prev}(\kappa) + \kappa^m * t_j(\kappa) - FF t_shifted_eval_reconstructed = t_evals[idx] * kappa.pow(subtable_size); - T_evals[idx].assert_equal(T_prev_evals[idx] + t_shifted_eval_reconstructed); - } + opening_claims.emplace_back(Claims{ { /*index of [l_j]*/ commitment_idx, + /*index of [r_j]*/ commitment_idx + 1, + /*index of [m_j]*/ commitment_idx + 2 }, + { FF(1), pow_kappa, FF(-1) }, + { kappa, FF(0) } }); + + // Move commitment_idx to the index of [l_{j+1}] + commitment_idx += NUM_WIRES; } - FF alpha = transcript->template get_challenge("alpha"); - - // Constuct inputs to batched commitment and batched evaluation from constituents using batching challenge \alpha - std::vector scalars; - std::vector commitments; - scalars.emplace_back(FF(builder, 1)); - commitments.emplace_back(opening_claims[0].commitment); - auto batched_eval = opening_claims[0].opening_pair.evaluation; - auto alpha_pow = alpha; - for (size_t idx = 1; idx < opening_claims.size(); ++idx) { - auto& claim = opening_claims[idx]; - scalars.emplace_back(alpha_pow); - commitments.emplace_back(claim.commitment); - batched_eval += alpha_pow * claim.opening_pair.evaluation; - if (idx < opening_claims.size() - 1) { - alpha_pow *= alpha; - } + // Add opening claim for l_j(1/kappa), g_j(kappa) and check g_j(kappa) = l_j(1/kappa) * kappa^{k-1} + commitment_idx = 0; + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { + // Opening claim for l_j(1/kappa) + FF left_table_eval_kappa_inv = + transcript->template receive_from_prover("left_table_eval_kappa_inv_" + std::to_string(idx)); + opening_claims.emplace_back( + Claims{ { /*index of [l_j]*/ commitment_idx }, { FF(1) }, { kappa_inv, left_table_eval_kappa_inv } }); + + // Opening claim for g_j(kappa) + FF left_table_reversed_eval = + transcript->template receive_from_prover("left_table_reversed_eval_" + std::to_string(idx)); + opening_claims.emplace_back( + Claims{ { /*index of [g_j]*/ commitment_idx + 3 }, { FF(1) }, { kappa, left_table_reversed_eval } }); + + // Move commitment_idx to index of left_table_{j+1} + commitment_idx += NUM_WIRES; + + // Degree identity + left_table_reversed_eval.assert_equal(left_table_eval_kappa_inv * pow_kappa_minus_one); } - auto batched_commitment = Commitment::batch_mul(commitments, scalars, /*max_num_bits=*/0, /*with_edgecases=*/true); - - OpeningClaim batched_claim = { { kappa, batched_eval }, batched_commitment }; + // Initialize Shplonk verifier + ShplonkVerifier_ verifier(table_commitments, transcript, opening_claims.size()); + verifier.reduce_verification_vector_claims_no_finalize(opening_claims); - auto pairing_points = KZG::reduce_verify(batched_claim, transcript); + // Export batched claim + auto batch_opening_claim = verifier.export_batch_opening_claim(Commitment::one(kappa.get_context())); - return { pairing_points[0], pairing_points[1] }; + // KZG verifier + return KZG::reduce_verify_batch_opening_claim(batch_opening_claim, transcript); } template class MergeRecursiveVerifier_; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp index 237f56607007..f94b87c9ad7f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp @@ -20,7 +20,6 @@ template class MergeRecursiveVerifier_ { using Commitment = typename Curve::Element; using GroupElement = typename Curve::Element; using KZG = ::bb::KZG; - using OpeningClaim = ::bb::OpeningClaim; using Transcript = bb::BaseTranscript>; using PairingPoints = stdlib::recursion::PairingPoints; @@ -28,7 +27,10 @@ template class MergeRecursiveVerifier_ { std::shared_ptr transcript; MergeSettings settings; + // Number of columns that jointly constitute the op_queue, should be the same as the number of wires in the + // MegaCircuitBuilder static constexpr size_t NUM_WIRES = MegaExecutionTraceBlocks::NUM_WIRES; + std::array T_commitments; explicit MergeRecursiveVerifier_(CircuitBuilder* builder, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp index 0d0eca7c9691..80be3db381fb 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp @@ -1,6 +1,7 @@ #include "barretenberg/ultra_honk/merge_verifier.hpp" #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" +#include "barretenberg/ecc/fields/field_conversion.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" @@ -31,11 +32,48 @@ template class RecursiveMergeVerifierTest : public test using Commitment = InnerFlavor::Commitment; using FF = InnerFlavor::FF; using VerifierCommitmentKey = bb::VerifierCommitmentKey; + using MergeProof = MergeProver::MergeProof; + + enum class TamperProofMode { None, Shift, MCommitment, LEval }; public: static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } - static void prove_and_verify_merge(const std::shared_ptr& op_queue) + static void tamper_with_proof(MergeProof& merge_proof, const TamperProofMode tampering_mode) + { + const size_t shift_idx = 0; // Index of shift_size in the merge proof + const size_t m_commitment_idx = 5; // Index of first commitment to merged table in merge proof + const size_t l_eval_idx = 50; // Index of first evaluation of l(1/kappa) in merge proof + + switch (tampering_mode) { + case TamperProofMode::Shift: + // Tamper with the shift size in the proof + merge_proof[shift_idx] += 1; + break; + case TamperProofMode::MCommitment: { + // Tamper with the commitment in the proof + Commitment m_commitment = bb::field_conversion::convert_from_bn254_frs( + std::span{ merge_proof }.subspan(m_commitment_idx, 4)); + m_commitment = m_commitment + Commitment::one(); + auto m_commitment_frs = bb::field_conversion::convert_to_bn254_frs(m_commitment); + for (size_t idx = 0; idx < 4; ++idx) { + merge_proof[m_commitment_idx + idx] = m_commitment_frs[idx]; + } + break; + } + case TamperProofMode::LEval: + // Tamper with the evaluation in the proof + merge_proof[l_eval_idx] -= FF(1); + break; + default: + // Nothing to do + break; + } + } + + static void prove_and_verify_merge(const std::shared_ptr& op_queue, + const TamperProofMode tampering_mode = TamperProofMode::None, + const bool expected = true) { RecursiveBuilder outer_circuit; @@ -57,26 +95,29 @@ template class RecursiveMergeVerifierTest : public test // Construct Merge proof auto merge_proof = merge_prover.construct_proof(); + tamper_with_proof(merge_proof, tampering_mode); // Create a recursive merge verification circuit for the merge proof RecursiveMergeVerifier verifier{ &outer_circuit }; + verifier.transcript->enable_manifest(); verifier.settings = op_queue->get_current_settings(); const stdlib::Proof stdlib_merge_proof(outer_circuit, merge_proof); auto pairing_points = verifier.verify_proof(stdlib_merge_proof, t_commitments_rec); // Check for a failure flag in the recursive verifier circuit - EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err(); + EXPECT_EQ(outer_circuit.failed(), !expected) << outer_circuit.err(); // Check 1: Perform native merge verification then perform the pairing on the outputs of the recursive merge // verifier and check that the result agrees. MergeVerifier native_verifier; + native_verifier.transcript->enable_manifest(); native_verifier.settings = op_queue->get_current_settings(); bool verified_native = native_verifier.verify_proof(merge_proof, t_commitments); VerifierCommitmentKey pcs_verification_key; - auto verified_recursive = + bool verified_recursive = pcs_verification_key.pairing_check(pairing_points.P0.get_value(), pairing_points.P1.get_value()); EXPECT_EQ(verified_native, verified_recursive); - EXPECT_TRUE(verified_recursive); + EXPECT_EQ(verified_recursive, expected); // Check 2: Ensure that the underlying native and recursive merge verification algorithms agree by ensuring // the manifests produced by each agree. @@ -85,9 +126,42 @@ template class RecursiveMergeVerifierTest : public test for (size_t i = 0; i < recursive_manifest.size(); ++i) { EXPECT_EQ(recursive_manifest[i], native_manifest[i]); } + } - // Check the recursive merge verifier circuit - CircuitChecker::check(outer_circuit); + /** + * @brief Test failure when degree(l) > shift_size (as read from the proof) + */ + static void test_degree_check_failure() + { + auto op_queue = std::make_shared(); + + InnerBuilder circuit{ op_queue }; + GoblinMockCircuits::construct_simple_circuit(circuit); + prove_and_verify_merge(op_queue, TamperProofMode::Shift, false); + } + + /** + * @brief Test failure when m \neq l + X^k r + */ + static void test_merge_failure() + { + auto op_queue = std::make_shared(); + + InnerBuilder circuit{ op_queue }; + GoblinMockCircuits::construct_simple_circuit(circuit); + prove_and_verify_merge(op_queue, TamperProofMode::MCommitment, false); + } + + /** + * @brief Test failure g_j(kappa) = kappa^{k-1} * l_j(1/kappa) + */ + static void test_eval_failure() + { + auto op_queue = std::make_shared(); + + InnerBuilder circuit{ op_queue }; + GoblinMockCircuits::construct_simple_circuit(circuit); + prove_and_verify_merge(op_queue, TamperProofMode::LEval, false); } /** @@ -124,4 +198,19 @@ TYPED_TEST(RecursiveMergeVerifierTest, SingleRecursiveVerification) TestFixture::test_recursive_merge_verification(); }; +TYPED_TEST(RecursiveMergeVerifierTest, DegreeCheckFailure) +{ + TestFixture::test_degree_check_failure(); +}; + +TYPED_TEST(RecursiveMergeVerifierTest, MergeFailure) +{ + TestFixture::test_merge_failure(); +}; + +TYPED_TEST(RecursiveMergeVerifierTest, EvalFailure) +{ + TestFixture::test_eval_failure(); +}; + } // namespace bb::stdlib::recursion::goblin diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp index 4094f1ccda40..966c4b4cb7fe 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp @@ -310,24 +310,6 @@ TYPED_TEST(MegaHonkTests, MultipleCircuitsMergeOnly) } } -TYPED_TEST(MegaHonkTests, MultipleCircuitsMergeOnlyAppend) -{ - using Flavor = TypeParam; - // Instantiate EccOpQueue. This will be shared across all circuits in the series - auto op_queue = std::make_shared(); - // Construct multiple test circuits that share an ECC op queue. Generate and verify a proof for each. - size_t NUM_CIRCUITS = 3; - for (size_t i = 0; i < NUM_CIRCUITS; ++i) { - auto builder = typename Flavor::CircuitBuilder{ op_queue, MergeSettings::APPEND }; - - GoblinMockCircuits::construct_simple_circuit(builder); - - // Construct and verify Goblin ECC op queue Merge proof - auto merge_verified = this->construct_and_verify_merge_proof(op_queue); - EXPECT_TRUE(merge_verified); - } -} - TYPED_TEST(MegaHonkTests, MultipleCircuitsMergeOnlyPrependThenAppend) { using Flavor = TypeParam; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp index 0ac5d7662447..b5e28c963da3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp @@ -5,6 +5,7 @@ // ===================== #include "merge_prover.hpp" +#include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" #include "barretenberg/flavor/mega_zk_flavor.hpp" namespace bb { @@ -18,94 +19,125 @@ MergeProver::MergeProver(const std::shared_ptr& op_queue, const CommitmentKey& commitment_key, const std::shared_ptr& transcript) : op_queue(op_queue) - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1420): pass commitment keys by value , pcs_commitment_key(commitment_key.initialized() ? commitment_key : CommitmentKey(op_queue->get_ultra_ops_table_num_rows())) , transcript(transcript){}; /** * @brief Prove proper construction of the aggregate Goblin ECC op queue polynomials T_j, j = 1,2,3,4. - * @details Let T_j be the jth column of the aggregate ecc op table after prepending the subtable columns t_j containing - * the contribution from the present circuit. T_{j,prev} corresponds to the columns of the aggregate table at the - * previous stage. For each column we have the relationship T_j = t_j + right_shift(T_{j,prev}, k), where k is the - * length of the subtable columns t_j. This protocol demonstrates, assuming the length of t is at most k, that the - * aggregate ecc op table has been constructed correctly via the simple Schwartz-Zippel check: + * @details Let \f$l_j\f$, \f$r_j\f$, \f$m_j\f$ be three vectors. The Merge prover wants to convince the verifier that, + * for j = 1, 2, 3, 4: + * - m_j(X) = l_j(X) + X^l r_j(X) (1) + * - deg(l_j(X)) < k (2) + * where k = shift_size. * - * T_j(\kappa) = t_j(\kappa) + \kappa^k * (T_{j,prev}(\kappa)). + * Condition (1) is equivalent, up to negligible probability, to: + * l_j(kappa) + kappa^k r_j(kappa) - m_j(kappa) = 0 + * so the prover constructs the polynomial + * p_j(X) := l_j(X) + kappa^{k-1} r_j(X) - m_j(X) + * and proves that it opens to 0 at kappa. * - * @note: the prover doesn't commit to t_j because it shares a transcript with the PG instance that folds the present + * To convince the verifier of (2), the prover commits to g_j(X) (allegedly equal to X^{k-1} l_j(1/X)) and provides + * openings: + * c = l_j(1/kappa) d = g_j(kappa) + * The verifier then checks that: c * kappa^{k-1} = d. This check is equivalent, up to negligible probability, to + * \f$g_j(X) = X^{k-1} l_j(1/X)\f$, which implies \f$deg(l_j) < k$. + * + * In the Goblin scenario, we have: + * - \f$l_j = t_j, r_j = T_{prev,j}, m_j = T_j\f$ if we are prepending the subtable + * - \f$l_j = T_{prev,j}, r_j = t_j, m_j = T_j\f$ if we are appending the subtable + * + * @note The prover doesn't commit to t_j because it shares a transcript with the PG instance that folds the present * circuit, and therefore t_j has already been added to the transcript by PG. * - * @return honk::proof + * @return MergeProver::MergeProof */ MergeProver::MergeProof MergeProver::construct_proof() { - // Extract columns of the full table T_j, the previous table T_{j,prev}, and the current subtable t_j - std::array T_current = op_queue->construct_ultra_ops_table_columns(); - std::array T_prev = op_queue->construct_previous_ultra_ops_table_columns(); - std::array t_current = op_queue->construct_current_ultra_ops_subtable_columns(); + std::array left_table; + std::array right_table; + std::array merged_table = op_queue->construct_ultra_ops_table_columns(); // T + std::array left_table_reversed; - const size_t current_table_size = T_current[0].size(); + if (op_queue->get_current_settings() == MergeSettings::PREPEND) { + left_table = op_queue->construct_current_ultra_ops_subtable_columns(); // t + right_table = op_queue->construct_previous_ultra_ops_table_columns(); // T_prev + } else { + left_table = op_queue->construct_previous_ultra_ops_table_columns(); // T_prev + right_table = op_queue->construct_current_ultra_ops_subtable_columns(); // t + } + // Compute g_j(X) + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { + left_table_reversed[idx] = left_table[idx].reverse(); + } + + const size_t merged_table_size = merged_table[0].size(); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1341): Once the op queue is fixed, we won't have to // send the shift size in the append mode. This is desirable to ensure we don't reveal the number of ecc ops in a // subtable when sending a merge proof to the rollup. - const size_t shift_size = - op_queue->get_current_settings() == MergeSettings::PREPEND ? t_current[0].size() : T_prev[0].size(); + const size_t shift_size = left_table[0].size(); transcript->send_to_verifier("shift_size", static_cast(shift_size)); - // Compute/get commitments [t^{shift}], [T_prev], and [T] and add to transcript + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1473): remove generation of commitment to T_prev + // Compute commitments [T_prev], [m_j], [g_j], and send to the verifier for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - // Compute commitments - Commitment T_prev_commitment = pcs_commitment_key.commit(T_prev[idx]); - Commitment T_commitment = pcs_commitment_key.commit(T_current[idx]); - - std::string suffix = std::to_string(idx); - transcript->send_to_verifier("T_PREV_" + suffix, T_prev_commitment); - transcript->send_to_verifier("T_CURRENT_" + suffix, T_commitment); + // Note: This is hacky at the moment because the prover still needs to commit to T_prev. Once we connect two + // steps of the Merge, T_prev will not be sent by the Merge prover, so the following lines will be removed + auto previous_table = + op_queue->get_current_settings() == MergeSettings::PREPEND ? right_table[idx] : left_table[idx]; + transcript->send_to_verifier("T_PREV" + std::to_string(idx), pcs_commitment_key.commit(previous_table)); + transcript->send_to_verifier("MERGED_TABLE_" + std::to_string(idx), + pcs_commitment_key.commit(merged_table[idx])); + transcript->send_to_verifier("LEFT_TABLE_REVERSED_" + std::to_string(idx), + pcs_commitment_key.commit(left_table_reversed[idx])); } - // Compute evaluations T_j(\kappa), T_{j,prev}(\kappa), t_j(\kappa), add to transcript. For each polynomial we add a - // univariate opening claim {p(X), (\kappa, p(\kappa))} to the set of claims to be checked via batched KZG. + // Compute evaluation challenge const FF kappa = transcript->template get_challenge("kappa"); + const FF pow_kappa = kappa.pow(shift_size); + const FF kappa_inv = kappa.invert(); - // Add univariate opening claims for each polynomial. + // Opening claims for each polynomial p_j, l_j, g_j + // + // The opening claims are sent in the following order: + // {kappa, 0}, {kappa, 0}, {kappa, 0}, {kappa, 0}, + // {1/kappa, l_1(1/kappa)}, {kappa, g_1(kappa)}, + // {1/kappa, l_2(1/kappa)}, {kappa, g_2(kappa)}, + // {1/kappa, l_3(1/kappa)}, {kappa, g_3(kappa)}, + // {1/kappa, l_4(1/kappa)}, {kappa, g_4(kappa)} std::vector opening_claims; - // Compute evaluation t(\kappa) - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - FF evaluation = t_current[idx].evaluate(kappa); - transcript->send_to_verifier("t_eval_" + std::to_string(idx), evaluation); - opening_claims.emplace_back(OpeningClaim{ std::move(t_current[idx]), { kappa, evaluation } }); - } - // Compute evaluation T_prev(\kappa) + + // Set opening claims p_j(\kappa) = l_j(X) + kappa^l r_j(X) - m_j(X) for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - FF evaluation = T_prev[idx].evaluate(kappa); - transcript->send_to_verifier("T_prev_eval_" + std::to_string(idx), evaluation); - opening_claims.emplace_back(OpeningClaim{ T_prev[idx], { kappa, evaluation } }); + Polynomial partially_evaluated_difference(merged_table_size); + partially_evaluated_difference += left_table[idx]; + partially_evaluated_difference.add_scaled(right_table[idx], pow_kappa); + partially_evaluated_difference -= merged_table[idx]; + + opening_claims.emplace_back(OpeningClaim{ partially_evaluated_difference, { kappa, FF(0) } }); } - // Compute evaluation T(\kappa) + // Compute evaluation l_j(1/kappa), g_j(\kappa), send to verifier, and set opening claims for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - FF evaluation = T_current[idx].evaluate(kappa); - transcript->send_to_verifier("T_eval_" + std::to_string(idx), evaluation); - opening_claims.emplace_back(OpeningClaim{ std::move(T_current[idx]), { kappa, evaluation } }); - } + FF evaluation; - FF alpha = transcript->template get_challenge("alpha"); + // Evaluate l_j(1/kappa) + evaluation = left_table[idx].evaluate(kappa_inv); + transcript->send_to_verifier("left_table_eval_kappa_inv_" + std::to_string(idx), evaluation); + opening_claims.emplace_back(OpeningClaim{ left_table[idx], { kappa_inv, evaluation } }); - // Construct batched polynomial to be opened via KZG - Polynomial batched_polynomial(current_table_size); - FF batched_eval(0); - FF alpha_pow(1); - for (auto& claim : opening_claims) { - batched_polynomial.add_scaled(claim.polynomial, alpha_pow); - batched_eval += alpha_pow * claim.opening_pair.evaluation; - alpha_pow *= alpha; + // Evaluate g_j(\kappa) + evaluation = left_table_reversed[idx].evaluate(kappa); + transcript->send_to_verifier("left_table_reversed_eval" + std::to_string(idx), evaluation); + opening_claims.emplace_back(OpeningClaim{ left_table_reversed[idx], { kappa, evaluation } }); } - // Construct and commit to KZG quotient polynomial q = (f - v) / (X - kappa) - OpeningClaim batched_claim = { std::move(batched_polynomial), { kappa, batched_eval } }; - PCS::compute_opening_proof(pcs_commitment_key, batched_claim, transcript); + // Shplonk prover + OpeningClaim shplonk_opening_claim = ShplonkProver_::prove(pcs_commitment_key, opening_claims, transcript); + + // KZG prover + PCS::compute_opening_proof(pcs_commitment_key, shplonk_opening_claim, transcript); return transcript->export_proof(); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index 688906006895..158b616f7a7b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -5,6 +5,7 @@ // ===================== #include "merge_verifier.hpp" +#include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" #include "barretenberg/flavor/mega_zk_flavor.hpp" #include "barretenberg/flavor/ultra_flavor.hpp" @@ -16,94 +17,145 @@ MergeVerifier::MergeVerifier(const std::shared_ptr& transcript, Merg /** * @brief Verify proper construction of the aggregate Goblin ECC op queue polynomials T_j, j = 1,2,3,4. - * @details Let T_j be the jth column of the aggregate ecc op table after prepending the subtable columns t_j containing - * the contribution from a single circuit. T_{j,prev} corresponds to the columns of the aggregate table at the - * previous stage. For each column we have the relationship T_j = t_j + right_shift(T_{j,prev}, k), where k is the - * length of the subtable columns t_j. This protocol demonstrates, assuming the length of t is at most k, that the - * aggregate ecc op table has been constructed correctly via the simple Schwartz-Zippel check: + * @details Let \f$l_j\f$, \f$r_j\f$, \f$m_j\f$ be three vectors. The Merge wants to convince the verifier that the + * polynomials l_j, r_j, m_j for which they have sent commitments [l_j], [r_j], [m_j] satisfy + * - m_j(X) = l_j(X) + X^l r_j(X) (1) + * - deg(l_j(X)) < k (2) + * where k = shift_size. * - * T_j(\kappa) = t_j(\kappa) + \kappa^k * (T_{j,prev}(\kappa)). + * To check condition (1), the verifier samples a challenge kappa and request from the prover a proof that + * the polynomial + * p_j(X) = l_j(kappa) + kappa^k r_j(kappa) - m_j(kappa) + * opens to 0 at kappa. * - * @tparam Flavor - * @param t_commitments The commitments to t_j read from the transcript by the PG verifier with which the Merge verifier - * shares a transcript + * To check condition (2), the verifier requests from the prover the commitment to a polynomial g_j, and + * then requests proofs that + * l_j(1/kappa) = c g_j(kappa) = d + * Then, they verify c * kappa^{k-1} = d, which implies, up to negligible probability, that + * g_j(X) = X^{l-1} l_j(1/X), which means that deg(l_j(X)) < l. + * + * The verifier must therefore check 12 opening claims: p_j(kappa) = 0, l_j(1/kappa), g_j(kappa) + * We use Shplonk to verify the claims with a single MSM (instead of computing [p_j] from [l_j], [r_j], [m_j] + * and then open it). We initialize the Shplonk verifier with the following commitments: + * [l_1], [r_1], [m_1], [g_1], ..., [l_4], [r_4], [m_4], [g_4] + * Then, we verify the various claims: + * - p_j(kappa) = 0: The commitment to p_j is constructed from the commitments to l_j, r_j, m_j, so + * the claim passed to the Shplonk verifier specifies the indices of these commitments in + * the above vector: {4 * (j-1), 4 * (j-1) + 1, 4 * (j-1) + 2}, the coefficients + * reconstructing p_j from l_j, r_j, m_j: {1, kappa^k, -1}, and the claimed + * evaluation: 0. + * - l_j(1/kappa) = v_j: The index in this case is {4 * (j-1)}, the coefficient is { 1 }, and the evaluation is + * v_j. + * - g_j(kappa) = w_j: The index is {3 + 4 * (j-1)}, the coefficient is { 1 }, and the evaluation is w_j. + * The claims are passed in the following order: + * {kappa, 0}, {kappa, 0}, {kappa, 0}, {kappa, 0}, {1/kappa, v_1}, {kappa, w_1}, .., {1/kappa, v_4}, {kappa, w_4} + * + * In the Goblin scenario, we have: + * - \f$l_j = t_j, r_j = T_{prev,j}, m_j = T_j\f$ if we are prepending the subtable + * - \f$l_j = T_{prev,j}, r_j = t_j, m_j = T_j\f$ if we are appending the subtable + * + * @param proof + * @param t_commitments The commitments to t_j read from the transcript by the PG verifier with which the Merge + * verifier shares a transcript * @return bool Verification result */ bool MergeVerifier::verify_proof(const HonkProof& proof, const RefArray& t_commitments) { + using Claims = typename ShplonkVerifier_::LinearCombinationOfClaims; + transcript->load_proof(proof); const uint32_t shift_size = transcript->template receive_from_prover("shift_size"); + BB_ASSERT_GT(shift_size, 0U, "Shift size should always be bigger than 0"); - // Receive table column polynomial commitments [T_{j,prev}], and [T_j], j = 1,2,3,4 - std::array T_prev_commitments; + // Vector of commitments to be passed to the Shplonk verifier + // The vector is composed of: [l_1], [r_1], [m_1], [g_1], ..., [l_4], [r_4], [m_4], [g_4] + std::vector table_commitments; for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - std::string suffix = std::to_string(idx); - T_prev_commitments[idx] = transcript->template receive_from_prover("T_PREV_" + suffix); - T_commitments[idx] = transcript->template receive_from_prover("T_CURRENT_" + suffix); - } - - FF kappa = transcript->template get_challenge("kappa"); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1473): remove receiving commitment to T_prev + auto T_prev_commitment = transcript->template receive_from_prover("T_PREV_" + std::to_string(idx)); + auto left_table = settings == MergeSettings::PREPEND ? t_commitments[idx] : T_prev_commitment; + auto right_table = settings == MergeSettings::PREPEND ? T_prev_commitment : t_commitments[idx]; - // Receive evaluations t_j(\kappa), T_{j,prev}(\kappa), T_j(\kappa), j = 1,2,3,4 - std::array t_evals; - std::array T_prev_evals; - std::array T_evals; - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - t_evals[idx] = transcript->template receive_from_prover("t_eval_" + std::to_string(idx)); - } - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - T_prev_evals[idx] = transcript->template receive_from_prover("T_prev_eval_" + std::to_string(idx)); - } - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - T_evals[idx] = transcript->template receive_from_prover("T_eval_" + std::to_string(idx)); + table_commitments.emplace_back(left_table); + table_commitments.emplace_back(right_table); + table_commitments.emplace_back( + transcript->template receive_from_prover("MERGED_TABLE_" + std::to_string(idx))); + table_commitments.emplace_back( + transcript->template receive_from_prover("LEFT_TABLE_REVERSED_" + std::to_string(idx))); } - // Check the identity according to whether the current subtable is prepended or appended. If it fails, return false - bool identity_checked = true; - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - bool current_check = false; - if (settings == MergeSettings::PREPEND) { - // In prepend mode we shift the evaluation of the previous table and check the identity - // T_j(\kappa) = t_j(\kappa) + \kappa^m * T_{j,prev}(\kappa) - FF T_prev_shifted_eval = T_prev_evals[idx] * kappa.pow(shift_size); - current_check = T_evals[idx] == t_evals[idx] + T_prev_shifted_eval; - } else { - // In append mode we shift the evaluation of the new subtable and check the identity - // T_j(\kappa) = T_{j,prev}(\kappa) + \kappa^m * t_j(\kappa) - FF t_shifted_eval = t_evals[idx] * kappa.pow(shift_size); - current_check = T_evals[idx] == T_prev_evals[idx] + t_shifted_eval; - } - identity_checked = identity_checked && current_check; + // Store T_commitments of the verifier + size_t commitment_idx = 2; // Index of [m_j = T_j] in the vector of commitments + for (auto& commitment : T_commitments) { + commitment = table_commitments[commitment_idx]; + commitment_idx += NUM_WIRES; } - FF alpha = transcript->template get_challenge("alpha"); + // Evaluation challenge + const FF kappa = transcript->template get_challenge("kappa"); + const FF kappa_inv = kappa.invert(); + const FF pow_kappa = kappa.pow(shift_size); - // Construct batched commitment and evaluation from constituents - Commitment batched_commitment = t_commitments[0]; - FF batched_eval = t_evals[0]; - auto alpha_pow = alpha; - for (size_t idx = 1; idx < NUM_WIRES; ++idx) { - batched_commitment = batched_commitment + (t_commitments[idx] * alpha_pow); - batched_eval += alpha_pow * t_evals[idx]; - alpha_pow *= alpha; - } + // Opening claims to be passed to the Shplonk verifier + std::vector opening_claims; + + // Add opening claim for p_j(X) = l_j(X) + X^k r_j(X) - m_j(X) + commitment_idx = 0; for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - batched_commitment = batched_commitment + (T_prev_commitments[idx] * alpha_pow); - batched_eval += alpha_pow * T_prev_evals[idx]; - alpha_pow *= alpha; + Claims claim{ { /*index of [l_j]*/ commitment_idx, + /*index of [r_j]*/ commitment_idx + 1, + /*index of [m_j]*/ commitment_idx + 2 }, + { FF::one(), pow_kappa, FF::neg_one() }, + { kappa, FF::zero() } }; + opening_claims.emplace_back(claim); + + // Move commitment_idx to the index of [l_{j+1}] + commitment_idx += NUM_WIRES; } + + // Boolean keeping track of the degree identities + bool degree_check_verified = true; + + // Add opening claim for l_j(1/kappa), g_j(kappa) and check g_j(kappa) = l_j(1/kappa) * kappa^{k-1} + commitment_idx = 0; for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - batched_commitment = batched_commitment + (T_commitments[idx] * alpha_pow); - batched_eval += alpha_pow * T_evals[idx]; - alpha_pow *= alpha; + Claims claim; + + // Opening claim for l_j(1/kappa) + FF left_table_eval_kappa_inv = + transcript->template receive_from_prover("left_table_eval_kappa_inv_" + std::to_string(idx)); + claim = { { commitment_idx }, { FF::one() }, { kappa_inv, left_table_eval_kappa_inv } }; + opening_claims.emplace_back(claim); + + // Move commitment_idx to index of g_j + commitment_idx += 3; + + // Opening claim for g_j(kappa) + FF left_table_reversed_eval = + transcript->template receive_from_prover("left_table_reversed_eval_" + std::to_string(idx)); + claim = { { commitment_idx }, { FF::one() }, { kappa, left_table_reversed_eval } }; + opening_claims.emplace_back(claim); + + // Move commitment_idx to index of left_table_{j+1} + commitment_idx += 1; + + // Degree identity + degree_check_verified &= (left_table_eval_kappa_inv * kappa.pow(shift_size - 1) == left_table_reversed_eval); } - OpeningClaim batched_claim = { { kappa, batched_eval }, batched_commitment }; + // Initialize Shplonk verifier + ShplonkVerifier_ verifier(table_commitments, transcript, opening_claims.size()); + verifier.reduce_verification_vector_claims_no_finalize(opening_claims); + + // Export batched claim + auto batch_opening_claim = verifier.export_batch_opening_claim(Commitment::one()); - auto pairing_points = PCS::reduce_verify(batched_claim, transcript); + // KZG verifier + auto pairing_points = PCS::reduce_verify_batch_opening_claim(batch_opening_claim, transcript); VerifierCommitmentKey pcs_vkey{}; - auto verified = pcs_vkey.pairing_check(pairing_points[0], pairing_points[1]); - return identity_checked && verified; + bool claims_verified = pcs_vkey.pairing_check(pairing_points[0], pairing_points[1]); + + return degree_check_verified && claims_verified; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index f8ab5b5e804d..c521259964f6 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -23,7 +23,6 @@ class MergeVerifier { using Curve = curve::BN254; using FF = typename Curve::ScalarField; using PCS = bb::KZG; - using OpeningClaim = bb::OpeningClaim; using VerifierCommitmentKey = bb::VerifierCommitmentKey; using Transcript = NativeTranscript; diff --git a/barretenberg/sol/lib/forge-std b/barretenberg/sol/lib/forge-std deleted file mode 160000 index 74cfb77e308d..000000000000 --- a/barretenberg/sol/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 74cfb77e308dd188d2f58864aaf44963ae6b88b1 diff --git a/barretenberg/sol/lib/openzeppelin-contracts b/barretenberg/sol/lib/openzeppelin-contracts deleted file mode 160000 index e50c24f5839d..000000000000 --- a/barretenberg/sol/lib/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e50c24f5839db17f46991478384bfda14acfb830 diff --git a/barretenberg/sol/lib/solidity-stringutils b/barretenberg/sol/lib/solidity-stringutils deleted file mode 160000 index 46983c6d9462..000000000000 --- a/barretenberg/sol/lib/solidity-stringutils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 46983c6d9462a80229cf0d5bab8ea3b3ee31066c diff --git a/bb-pilcom/powdr b/bb-pilcom/powdr deleted file mode 160000 index c3006c11819d..000000000000 --- a/bb-pilcom/powdr +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c3006c11819d9b53fb183c9c12a10b83481bb631 diff --git a/l1-contracts/lib/circuits b/l1-contracts/lib/circuits deleted file mode 160000 index 82aac79b466e..000000000000 --- a/l1-contracts/lib/circuits +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 82aac79b466e3430f4946f99919e0866a5ad82f0 diff --git a/l1-contracts/lib/forge-std b/l1-contracts/lib/forge-std deleted file mode 160000 index 0e7097750918..000000000000 --- a/l1-contracts/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0e7097750918380d84dd3cfdef595bee74dabb70 diff --git a/l1-contracts/lib/openzeppelin-contracts b/l1-contracts/lib/openzeppelin-contracts deleted file mode 160000 index 448efeea6640..000000000000 --- a/l1-contracts/lib/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 448efeea6640bbbc09373f03fbc9c88e280147ba From d7f0efead785eee943e0ee965274e029b3c78794 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 10:31:35 +0000 Subject: [PATCH 03/27] Add merge verification data class --- .../merge_verifier/merge_recursive_verifier.cpp | 10 ++++++---- .../merge_verifier/merge_recursive_verifier.hpp | 11 +++++++++-- .../src/barretenberg/ultra_honk/merge_verifier.cpp | 14 ++++++++------ .../src/barretenberg/ultra_honk/merge_verifier.hpp | 12 ++++++++++-- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp index ed313b4d1dfb..068b623748e9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp @@ -66,7 +66,7 @@ MergeRecursiveVerifier_::MergeRecursiveVerifier_(CircuitBuilder* */ template MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_::verify_proof( - const stdlib::Proof& proof, const RefArray t_commitments) + const stdlib::Proof& proof, MergeVerificationData& merge_verification_data) { using Claims = typename ShplonkVerifier_::LinearCombinationOfClaims; @@ -81,8 +81,10 @@ MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_template receive_from_prover("T_PREV_" + std::to_string(idx)); - auto left_table = settings == MergeSettings::PREPEND ? t_commitments[idx] : T_prev_commitment; - auto right_table = settings == MergeSettings::PREPEND ? T_prev_commitment : t_commitments[idx]; + auto left_table = + settings == MergeSettings::PREPEND ? merge_verification_data.t_commitments[idx] : T_prev_commitment; + auto right_table = + settings == MergeSettings::PREPEND ? T_prev_commitment : merge_verification_data.t_commitments[idx]; table_commitments.emplace_back(left_table); table_commitments.emplace_back(right_table); @@ -94,7 +96,7 @@ MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_ class MergeRecursiveVerifier_ { // MegaCircuitBuilder static constexpr size_t NUM_WIRES = MegaExecutionTraceBlocks::NUM_WIRES; - std::array T_commitments; + class MergeVerificationData { + public: + std::array t_commitments; + std::array T_prev_commitments; + std::array T_commitments; + + MergeVerificationData() = default; + }; explicit MergeRecursiveVerifier_(CircuitBuilder* builder, const std::shared_ptr& transcript = std::make_shared(), MergeSettings settings = MergeSettings::PREPEND); [[nodiscard("Pairing points should be accumulated")]] PairingPoints verify_proof( - const stdlib::Proof& proof, const RefArray t_commitments); + const stdlib::Proof& proof, MergeVerificationData& merge_verification_data); }; } // namespace bb::stdlib::recursion::goblin diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index 158b616f7a7b..d3ea597e6cf5 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -55,11 +55,11 @@ MergeVerifier::MergeVerifier(const std::shared_ptr& transcript, Merg * - \f$l_j = T_{prev,j}, r_j = t_j, m_j = T_j\f$ if we are appending the subtable * * @param proof - * @param t_commitments The commitments to t_j read from the transcript by the PG verifier with which the Merge - * verifier shares a transcript + * @param merge_verification_data The verification data, containing the commitments to t_j read from the transcript by + * the PG verifier with which the Merge verifier shares a transcript * @return bool Verification result */ -bool MergeVerifier::verify_proof(const HonkProof& proof, const RefArray& t_commitments) +bool MergeVerifier::verify_proof(const HonkProof& proof, MergeVerificationData& merge_verification_data) { using Claims = typename ShplonkVerifier_::LinearCombinationOfClaims; @@ -74,8 +74,10 @@ bool MergeVerifier::verify_proof(const HonkProof& proof, const RefArraytemplate receive_from_prover("T_PREV_" + std::to_string(idx)); - auto left_table = settings == MergeSettings::PREPEND ? t_commitments[idx] : T_prev_commitment; - auto right_table = settings == MergeSettings::PREPEND ? T_prev_commitment : t_commitments[idx]; + auto left_table = + settings == MergeSettings::PREPEND ? merge_verification_data.t_commitments[idx] : T_prev_commitment; + auto right_table = + settings == MergeSettings::PREPEND ? T_prev_commitment : merge_verification_data.t_commitments[idx]; table_commitments.emplace_back(left_table); table_commitments.emplace_back(right_table); @@ -87,7 +89,7 @@ bool MergeVerifier::verify_proof(const HonkProof& proof, const RefArray transcript; - std::array T_commitments; MergeSettings settings; + class MergeVerificationData { + public: + std::array t_commitments; + std::array T_prev_commitments; + std::array T_commitments; + + MergeVerificationData() = default; + }; + explicit MergeVerifier(const std::shared_ptr& transcript = std::make_shared(), MergeSettings settings = MergeSettings::PREPEND); - bool verify_proof(const HonkProof& proof, const RefArray& t_commitments); + bool verify_proof(const HonkProof& proof, MergeVerificationData& merge_verification_data); }; } // namespace bb From 60e010980a18203a6e2f966d9d412dded420f3b6 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 10:56:42 +0000 Subject: [PATCH 04/27] Update tests --- .../merge_verifier/merge_verifier.test.cpp | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp index 80be3db381fb..4798da31bca4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp @@ -22,6 +22,7 @@ template class RecursiveMergeVerifierTest : public test // Types for recursive verifier circuit using RecursiveMergeVerifier = MergeRecursiveVerifier_; + using RecursiveMergeVerificationData = MergeRecursiveVerifier_::MergeVerificationData; // Define types relevant for inner circuit using InnerFlavor = MegaFlavor; @@ -33,6 +34,7 @@ template class RecursiveMergeVerifierTest : public test using FF = InnerFlavor::FF; using VerifierCommitmentKey = bb::VerifierCommitmentKey; using MergeProof = MergeProver::MergeProof; + using MergeVerificationData = MergeVerifier::MergeVerificationData; enum class TamperProofMode { None, Shift, MCommitment, LEval }; @@ -80,19 +82,15 @@ template class RecursiveMergeVerifierTest : public test MergeProver merge_prover{ op_queue }; // Subtable values and commitments - needed for (Recursive)MergeVerifier + MergeVerificationData merge_verification_data; + RecursiveMergeVerificationData recursive_merge_verification_data; auto t_current = op_queue->construct_current_ultra_ops_subtable_columns(); - std::array t_commitments_val; - std::array t_commitments_rec_val; for (size_t idx = 0; idx < InnerFlavor::NUM_WIRES; idx++) { - t_commitments_val[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); - t_commitments_rec_val[idx] = - RecursiveMergeVerifier::Commitment::from_witness(&outer_circuit, t_commitments_val[idx]); + merge_verification_data.t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); + recursive_merge_verification_data.t_commitments[idx] = RecursiveMergeVerifier::Commitment::from_witness( + &outer_circuit, merge_verification_data.t_commitments[idx]); } - RefArray t_commitments(t_commitments_val); - RefArray t_commitments_rec( - t_commitments_rec_val); - // Construct Merge proof auto merge_proof = merge_prover.construct_proof(); tamper_with_proof(merge_proof, tampering_mode); @@ -102,7 +100,7 @@ template class RecursiveMergeVerifierTest : public test verifier.transcript->enable_manifest(); verifier.settings = op_queue->get_current_settings(); const stdlib::Proof stdlib_merge_proof(outer_circuit, merge_proof); - auto pairing_points = verifier.verify_proof(stdlib_merge_proof, t_commitments_rec); + auto pairing_points = verifier.verify_proof(stdlib_merge_proof, recursive_merge_verification_data); // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(outer_circuit.failed(), !expected) << outer_circuit.err(); @@ -112,7 +110,7 @@ template class RecursiveMergeVerifierTest : public test MergeVerifier native_verifier; native_verifier.transcript->enable_manifest(); native_verifier.settings = op_queue->get_current_settings(); - bool verified_native = native_verifier.verify_proof(merge_proof, t_commitments); + bool verified_native = native_verifier.verify_proof(merge_proof, merge_verification_data); VerifierCommitmentKey pcs_verification_key; bool verified_recursive = pcs_verification_key.pairing_check(pairing_points.P0.get_value(), pairing_points.P1.get_value()); From b500f227a23f6103d4ff59b66c488e1040613084 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:04:51 +0000 Subject: [PATCH 05/27] Add setter method --- .../stdlib/merge_verifier/merge_recursive_verifier.hpp | 9 ++++++++- .../cpp/src/barretenberg/ultra_honk/merge_verifier.hpp | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp index 6ab7aee2f7dd..a1c414b99dcc 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp @@ -34,10 +34,17 @@ template class MergeRecursiveVerifier_ { class MergeVerificationData { public: std::array t_commitments; - std::array T_prev_commitments; + // std::array T_prev_commitments; std::array T_commitments; MergeVerificationData() = default; + + void set_t_commitments(const RefArray& t_commitments_ref) + { + for (size_t idx = 0; idx < NUM_WIRES; idx++) { + t_commitments[idx] = t_commitments_ref[idx]; + } + } }; explicit MergeRecursiveVerifier_(CircuitBuilder* builder, diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index 77b997570706..6cc9c3f0ead7 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -39,7 +39,7 @@ class MergeVerifier { class MergeVerificationData { public: std::array t_commitments; - std::array T_prev_commitments; + // std::array T_prev_commitments; std::array T_commitments; MergeVerificationData() = default; From d79ef3103052a29d9666307058ba9b4d8ef88c56 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:09:08 +0000 Subject: [PATCH 06/27] Add setter method --- .../cpp/src/barretenberg/ultra_honk/merge_verifier.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index 6cc9c3f0ead7..d5f2cfcb2bd8 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -43,6 +43,13 @@ class MergeVerifier { std::array T_commitments; MergeVerificationData() = default; + + void set_t_commitments(const RefArray& t_commitments_ref) + { + for (size_t idx = 0; idx < NUM_WIRES; idx++) { + t_commitments[idx] = t_commitments_ref[idx]; + } + } }; explicit MergeVerifier(const std::shared_ptr& transcript = std::make_shared(), From 759432d2563cd499499d3e17243f964aca12d78a Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:10:43 +0000 Subject: [PATCH 07/27] Update goblin and client IVC interfaces --- .../barretenberg/client_ivc/client_ivc.cpp | 27 +++++++++++++------ .../barretenberg/client_ivc/client_ivc.hpp | 5 ++++ .../cpp/src/barretenberg/goblin/goblin.cpp | 15 +++++------ .../cpp/src/barretenberg/goblin/goblin.hpp | 14 +++++----- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 3e1437b58623..a6508af7b31f 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -131,9 +131,12 @@ ClientIVC::PairingPoints ClientIVC::perform_recursive_verification_and_databus_c } } + // Extract the commitments to the subtable corresponding to the incoming circuit + merge_verification_data.set_t_commitments(decider_vk->witness_commitments.get_ecc_op_wires()); + // Recursively verify the corresponding merge proof - PairingPoints pairing_points = goblin.recursively_verify_merge( - circuit, decider_vk->witness_commitments.get_ecc_op_wires(), accumulation_recursive_transcript); + PairingPoints pairing_points = + goblin.recursively_verify_merge(circuit, merge_verification_data, accumulation_recursive_transcript); PairingPoints nested_pairing_points; // to be extracted from public inputs of app or kernel proof just verified @@ -381,9 +384,12 @@ std::shared_ptr ClientIVC::construct_hiding_circ kernel_input.kernel_return_data.assert_equal(tail_kernel_decider_vk->witness_commitments.calldata); kernel_input.app_return_data.assert_equal(tail_kernel_decider_vk->witness_commitments.secondary_calldata); + // Extract the commitments to the subtable corresponding to the incoming circuit + merge_verification_data.set_t_commitments(tail_kernel_decider_vk->witness_commitments.get_ecc_op_wires()); + // Perform recursive verification of the last merge proof - PairingPoints points_accumulator = goblin.recursively_verify_merge( - builder, tail_kernel_decider_vk->witness_commitments.get_ecc_op_wires(), pg_merge_transcript); + PairingPoints points_accumulator = + goblin.recursively_verify_merge(builder, merge_verification_data, pg_merge_transcript); points_accumulator.aggregate(kernel_input.pairing_inputs); // Perform recursive decider verification @@ -440,13 +446,18 @@ bool ClientIVC::verify(const Proof& proof, const VerificationKey& vk) // Create a transcript to be shared by MegaZK-, Merge-, ECCVM-, and Translator- Verifiers. std::shared_ptr civc_verifier_transcript = std::make_shared(); // Verify the hiding circuit proof - MegaZKVerifier verifer{ vk.mega, /*ipa_verification_key=*/{}, civc_verifier_transcript }; - bool mega_verified = verifer.verify_proof(proof.mega_proof); + MegaZKVerifier verifier{ vk.mega, /*ipa_verification_key=*/{}, civc_verifier_transcript }; + bool mega_verified = verifier.verify_proof(proof.mega_proof); vinfo("Mega verified: ", mega_verified); + + // Extract the commitments to the subtable corresponding to the incoming circuit + MergeVerifier::MergeVerificationData merge_verification_data; + merge_verification_data.set_t_commitments(verifier.verification_key->witness_commitments.get_ecc_op_wires()); + // Goblin verification (final merge, eccvm, translator) - bool goblin_verified = Goblin::verify( - proof.goblin_proof, verifer.verification_key->witness_commitments.get_ecc_op_wires(), civc_verifier_transcript); + bool goblin_verified = Goblin::verify(proof.goblin_proof, merge_verification_data, civc_verifier_transcript); vinfo("Goblin verified: ", goblin_verified); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1396): State tracking in CIVC verifiers. return goblin_verified && mega_verified; } diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 24de2b74ce36..30310f7331cc 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -77,6 +77,8 @@ class ClientIVC { using KernelIO = bb::stdlib::recursion::honk::KernelIO; using AppIO = bb::stdlib::recursion::honk::AppIO; using StdlibProof = stdlib::Proof; + using MergeVerificationData = + stdlib::recursion::goblin::MergeRecursiveVerifier_::MergeVerificationData; /** * @brief A full proof for the IVC scheme containing a Mega proof showing correctness of the hiding circuit (which @@ -178,6 +180,9 @@ class ClientIVC { // Management of linking databus commitments between circuits in the IVC DataBusDepot bus_depot; + // Management of linking merge commitments between circuits in the IVC + MergeVerificationData merge_verification_data; + // Settings related to the use of fixed block sizes for each gate in the execution trace TraceSettings trace_settings; diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp index 525eb0cc330d..501a3416f5f6 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp @@ -72,10 +72,9 @@ GoblinProof Goblin::prove() return goblin_proof; } -Goblin::PairingPoints Goblin::recursively_verify_merge( - MegaBuilder& builder, - const RefArray& t_commitments, - const std::shared_ptr& transcript) +Goblin::PairingPoints Goblin::recursively_verify_merge(MegaBuilder& builder, + RecursiveMergeVerificationData& merge_verification_data, + const std::shared_ptr& transcript) { ASSERT(!merge_verification_queue.empty()); // Recursively verify the next merge proof in the verification queue in a FIFO manner @@ -83,7 +82,7 @@ Goblin::PairingPoints Goblin::recursively_verify_merge( const stdlib::Proof stdlib_merge_proof(builder, merge_proof); MergeRecursiveVerifier merge_verifier{ &builder, transcript }; - PairingPoints pairing_points = merge_verifier.verify_proof(stdlib_merge_proof, t_commitments); + PairingPoints pairing_points = merge_verifier.verify_proof(stdlib_merge_proof, merge_verification_data); merge_verification_queue.pop_front(); // remove the processed proof from the queue @@ -91,11 +90,11 @@ Goblin::PairingPoints Goblin::recursively_verify_merge( } bool Goblin::verify(const GoblinProof& proof, - const RefArray& t_commitments, + MergeVerificationData& merge_verification_data, const std::shared_ptr& transcript) { MergeVerifier merge_verifier(transcript); - bool merge_verified = merge_verifier.verify_proof(proof.merge_proof, t_commitments); + bool merge_verified = merge_verifier.verify_proof(proof.merge_proof, merge_verification_data); ECCVMVerifier eccvm_verifier(transcript); bool eccvm_verified = eccvm_verifier.verify_proof(proof.eccvm_proof); @@ -111,7 +110,7 @@ bool Goblin::verify(const GoblinProof& proof, // Verify the consistency between the commitments to polynomials representing the op queue received by translator // and final merge verifier bool op_queue_consistency_verified = - translator_verifier.verify_consistency_with_final_merge(merge_verifier.T_commitments); + translator_verifier.verify_consistency_with_final_merge(merge_verification_data.T_commitments); vinfo("merge verified?: ", merge_verified); vinfo("eccvm verified?: ", eccvm_verified); diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 463034e6c9fe..76eb59b325e0 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -38,6 +38,8 @@ class Goblin { using TranslatorVerificationKey = TranslatorFlavor::VerificationKey; using MergeRecursiveVerifier = stdlib::recursion::goblin::MergeRecursiveVerifier_; using PairingPoints = MergeRecursiveVerifier::PairingPoints; + using MergeVerificationData = MergeVerifier::MergeVerificationData; + using RecursiveMergeVerificationData = MergeRecursiveVerifier::MergeVerificationData; using RecursiveTranscript = bb::BaseTranscript>; std::shared_ptr op_queue = std::make_shared(); @@ -91,14 +93,14 @@ class Goblin { * @details Proofs are verified in a FIFO manner * * @param builder The circuit in which the recursive verification will be performed. - * @param t_commitments The commitments to the subtable for which the merge is being verified. + * @param merge_verification_data The merge verification data, containing the commitments to the subtable for which + * the merge is being verified. * @param transcript The transcript to be passed to the MergeRecursiveVerifier. * @return PairingPoints */ - PairingPoints recursively_verify_merge( - MegaBuilder& builder, - const RefArray& t_commitments, - const std::shared_ptr& transcript); + PairingPoints recursively_verify_merge(MegaBuilder& builder, + RecursiveMergeVerificationData& merge_verification_data, + const std::shared_ptr& transcript); /** * @brief Verify a full Goblin proof (ECCVM, Translator, merge) @@ -111,7 +113,7 @@ class Goblin { * @return false */ static bool verify(const GoblinProof& proof, - const RefArray& t_commitments, + MergeVerificationData& merge_verification_data, const std::shared_ptr& transcript); }; From 1e70c88490e8004f138613836e0e195d6c93e088 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:14:24 +0000 Subject: [PATCH 08/27] Update goblin rec verifier interface --- .../goblin_verifier/goblin_recursive_verifier.cpp | 11 ++++++----- .../goblin_verifier/goblin_recursive_verifier.hpp | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp index e05884b8f60a..414ac78827ef 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp @@ -16,10 +16,10 @@ namespace bb::stdlib::recursion::honk { * */ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( - const GoblinProof& proof, const RefArray& t_commitments) + const GoblinProof& proof, MergeVerifier::MergeVerificationData& merge_verification_data) { StdlibProof stdlib_proof(*builder, proof); - return verify(stdlib_proof, t_commitments); + return verify(stdlib_proof, merge_verification_data); } /** @@ -30,11 +30,12 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( * */ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( - const StdlibProof& proof, const RefArray& t_commitments) + const StdlibProof& proof, MergeVerifier::MergeVerificationData& merge_verification_data) { // Verify the final merge step MergeVerifier merge_verifier{ builder, transcript }; - PairingPoints merge_pairing_points = merge_verifier.verify_proof(proof.merge_proof, t_commitments); + PairingPoints merge_pairing_points = + merge_verifier.verify_proof(proof.merge_proof, merge_verification_data); // Run the ECCVM recursive verifier ECCVMVerifier eccvm_verifier{ builder, verification_keys.eccvm_verification_key, transcript }; @@ -53,7 +54,7 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( // Verify the consistency between the commitments to polynomials representing the op queue received by translator // and final merge verifier - translator_verifier.verify_consistency_with_final_merge(merge_verifier.T_commitments); + translator_verifier.verify_consistency_with_final_merge(merge_verification_data.T_commitments); return { translator_pairing_points, opening_claim, ipa_proof }; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp index 46e27c2cb57e..de6713e7b51e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp @@ -62,9 +62,9 @@ class GoblinRecursiveVerifier { , transcript(transcript){}; [[nodiscard("IPA claim and Pairing points should be accumulated")]] GoblinRecursiveVerifierOutput verify( - const GoblinProof&, const RefArray& t_commitments); + const GoblinProof&, MergeVerifier::MergeVerificationData& merge_verification_data); [[nodiscard("IPA claim and Pairing points should be accumulated")]] GoblinRecursiveVerifierOutput verify( - const StdlibProof&, const RefArray& t_commitments); + const StdlibProof&, MergeVerifier::MergeVerificationData& merge_verification_data); private: Builder* builder; From 082d155be3c0715c5d42fdc7fd9ad15830838769 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:33:30 +0000 Subject: [PATCH 09/27] Update goblin AVM rec verifier interface --- .../recursion/goblin_avm_recursive_verifier.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp index e2cf347ada1d..ca83f7196379 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp @@ -116,6 +116,8 @@ class AvmGoblinRecursiveVerifier { using MegaRecursiveVerifier = stdlib::recursion::honk::UltraRecursiveVerifier_; using GoblinRecursiveVerifier = stdlib::recursion::honk::GoblinRecursiveVerifier; using GoblinRecursiveVerifierOutput = stdlib::recursion::honk::GoblinRecursiveVerifierOutput; + using MergeVerificationData = + stdlib::recursion::goblin::MergeRecursiveVerifier_::MergeVerificationData; using FF = MegaRecursiveFlavor::FF; // Construct hash buffer containing the AVM proof, public inputs, and VK @@ -136,9 +138,11 @@ class AvmGoblinRecursiveVerifier { auto mega_verifier_output = mega_verifier.verify_proof(mega_proof); // Recursively verify the goblin proof\pi_G in the Ultra circuit + MergeVerificationData merge_verification_data; + merge_verification_data.set_t_commitments(mega_verifier.key->witness_commitments.get_ecc_op_wires()); GoblinRecursiveVerifier goblin_verifier{ &ultra_builder, inner_output.goblin_vk, transcript }; - GoblinRecursiveVerifierOutput goblin_verifier_output = goblin_verifier.verify( - inner_output.goblin_proof, mega_verifier.key->witness_commitments.get_ecc_op_wires()); + GoblinRecursiveVerifierOutput goblin_verifier_output = + goblin_verifier.verify(inner_output.goblin_proof, merge_verification_data); goblin_verifier_output.points_accumulator.aggregate(mega_verifier_output.points_accumulator); // Validate the consistency of the AVM2 verifier inputs {\pi, pub_inputs, VK}_{AVM2} between the inner (Mega) From b53006f5d1f7eb2440242d3e7753cdeeb4ed352f Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 13:11:44 +0000 Subject: [PATCH 10/27] Update rec civc interface --- .../client_ivc_verifier/client_ivc_recursive_verifier.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp index 7fff21d2ba47..6db1f2ea5923 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp @@ -16,6 +16,7 @@ namespace bb::stdlib::recursion::honk { */ ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const StdlibProof& proof) { + using MergeVerificationData = goblin::MergeRecursiveVerifier_::MergeVerificationData; std::shared_ptr civc_rec_verifier_transcript(std::make_shared()); // Construct stdlib Mega verification key auto stdlib_mega_vk_and_hash = std::make_shared(*builder, ivc_verification_key.mega); @@ -26,9 +27,10 @@ ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const Stdl // Perform Goblin recursive verification GoblinVerificationKey goblin_verification_key{}; + MergeVerificationData merge_verification_data; + merge_verification_data.set_t_commitments(verifier.key->witness_commitments.get_ecc_op_wires()); GoblinVerifier goblin_verifier{ builder.get(), goblin_verification_key, civc_rec_verifier_transcript }; - GoblinRecursiveVerifierOutput output = - goblin_verifier.verify(proof.goblin_proof, verifier.key->witness_commitments.get_ecc_op_wires()); + GoblinRecursiveVerifierOutput output = goblin_verifier.verify(proof.goblin_proof, merge_verification_data); output.points_accumulator.aggregate(mega_output.points_accumulator); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1396): State tracking in CIVC verifiers return { output }; From 9e9a29fb71ddf312b693743928775c9e9d125dd1 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:27:14 +0000 Subject: [PATCH 11/27] Comments --- .../stdlib/merge_verifier/merge_recursive_verifier.hpp | 5 +++++ .../cpp/src/barretenberg/ultra_honk/merge_verifier.hpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp index a1c414b99dcc..aa27cecd3703 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp @@ -39,6 +39,11 @@ template class MergeRecursiveVerifier_ { MergeVerificationData() = default; + /** + * @brief Set t_commitments from RefArray + * + * @param t_commitments_ref + */ void set_t_commitments(const RefArray& t_commitments_ref) { for (size_t idx = 0; idx < NUM_WIRES; idx++) { diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index d5f2cfcb2bd8..2f6148bbabaa 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -44,6 +44,11 @@ class MergeVerifier { MergeVerificationData() = default; + /** + * @brief Set t_commitments from RefArray + * + * @param t_commitments_ref + */ void set_t_commitments(const RefArray& t_commitments_ref) { for (size_t idx = 0; idx < NUM_WIRES; idx++) { From 5fa5b980fd0abb6008e3f4c0c398a8fe17a7c09f Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:34:09 +0000 Subject: [PATCH 12/27] Update tests --- .../graph_description_goblin.test.cpp | 52 ++----- .../goblin_recursive_verifier.test.cpp | 142 +++++++----------- .../ultra_honk/mega_honk.test.cpp | 27 +--- 3 files changed, 73 insertions(+), 148 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp index 8000282c4a1e..5a88784414d8 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp @@ -24,13 +24,15 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { using Commitment = MergeVerifier::Commitment; using RecursiveCommitment = GoblinRecursiveVerifier::MergeVerifier::Commitment; + using RecursiveMergeVerificationData = GoblinRecursiveVerifier::MergeVerifier::MergeVerificationData; static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } struct ProverOutput { + Builder builder; GoblinProof proof; Goblin::VerificationKey verifier_input; - RefArray t_commitments; + RecursiveMergeVerificationData recursive_merge_verification_data; }; /** @@ -38,8 +40,7 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { * * @return ProverOutput */ - static ProverOutput create_goblin_prover_output(std::array& t_commitments_val, - const size_t NUM_CIRCUITS = 3) + static ProverOutput create_goblin_prover_output(const size_t NUM_CIRCUITS = 3) { Goblin goblin; // Construct and accumulate multiple circuits @@ -58,40 +59,21 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { GoblinMockCircuits::construct_simple_circuit(builder); // Subtable values and commitments - needed for (Recursive)MergeVerifier + Builder outer_builder; + + RecursiveMergeVerificationData recursive_merge_verification_data; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); - std::array ptr_t_commitments; CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - t_commitments_val[idx] = pcs_commitment_key.commit(t_current[idx]); - ptr_t_commitments[idx] = &t_commitments_val[idx]; + recursive_merge_verification_data.t_commitments[idx] = + RecursiveCommitment::from_witness(&outer_builder, pcs_commitment_key.commit(t_current[idx])); } - RefArray t_commitments(ptr_t_commitments); - // Output is a goblin proof plus ECCVM/Translator verification keys - return { goblin_final.prove(), + return { outer_builder, + goblin_final.prove(), { std::make_shared(), std::make_shared() }, - t_commitments }; - } - - /** - * @brief Transform native subtable commitments into recursive subtable commitments - * - */ - static RefArray convert_native_t_commitments_to_stdlib( - Builder* builder, - std::array t_commitments_rec_val, - const std::array& t_commitments_val) - { - std::array ptr_t_commitments_rec; - for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - t_commitments_rec_val[idx] = RecursiveCommitment::from_witness(builder, t_commitments_val[idx]); - ptr_t_commitments_rec[idx] = &t_commitments_rec_val[idx]; - } - - RefArray t_commitments_rec(ptr_t_commitments_rec); - - return t_commitments_rec; + recursive_merge_verification_data }; } }; @@ -101,16 +83,10 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { */ TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic) { - std::array t_commitments_val; - auto [proof, verifier_input, _] = create_goblin_prover_output(t_commitments_val); - - Builder builder; - - std::array t_commitments_rec_val; - auto t_commitments = convert_native_t_commitments_to_stdlib(&builder, t_commitments_rec_val, t_commitments_val); + auto [builder, proof, verifier_input, recursive_merge_verification_data] = create_goblin_prover_output(); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - GoblinRecursiveVerifierOutput output = verifier.verify(proof, t_commitments); + GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); output.points_accumulator.set_public(); // Construct and verify a proof for the Goblin Recursive Verifier circuit { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index 62dccac52e89..ea831ecf162d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp @@ -22,43 +22,16 @@ class GoblinRecursiveVerifierTests : public testing::Test { using Commitment = MergeVerifier::Commitment; using RecursiveCommitment = GoblinRecursiveVerifier::MergeVerifier::Commitment; + using RecursiveMergeVerificationData = GoblinRecursiveVerifier::MergeVerifier::MergeVerificationData; static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } - struct TestData { - GoblinProof proof; - Goblin::VerificationKey verifier_input; - RefArray native_t_commitments; - RefArray recursive_t_commitments; - - // Storage arrays for the commitment values - std::array t_commitments_val; - std::array t_commitments_rec_val; - }; - - static TestData create_test_data(Builder* builder = nullptr, const size_t NUM_CIRCUITS = 3) - { - TestData setup; - // Generate the proof and verification input - auto [proof, verifier_input] = create_goblin_prover_output(setup.t_commitments_val, NUM_CIRCUITS); - setup.proof = proof; - setup.verifier_input = verifier_input; - - // Set up native commitment RefArray - setup.native_t_commitments = RefArray(setup.t_commitments_val); - - // Set up recursive commitment RefArray if builder is provided - if (builder != nullptr) { - setup.recursive_t_commitments = - convert_native_t_commitments_to_stdlib(builder, setup.t_commitments_rec_val, setup.t_commitments_val); - } - - return setup; - } - struct ProverOutput { + Builder builder; GoblinProof proof; Goblin::VerificationKey verifier_input; + MergeVerifier::MergeVerificationData merge_verification_data; + RecursiveMergeVerificationData recursive_merge_verification_data; }; /** @@ -66,8 +39,7 @@ class GoblinRecursiveVerifierTests : public testing::Test { * * @return ProverOutput */ - static ProverOutput create_goblin_prover_output(std::array& t_commitments_val, - const size_t NUM_CIRCUITS = 3) + static ProverOutput create_goblin_prover_output(const size_t NUM_CIRCUITS = 3) { Goblin goblin; @@ -84,33 +56,26 @@ class GoblinRecursiveVerifierTests : public testing::Test { builder.queue_ecc_no_op(); GoblinMockCircuits::construct_simple_circuit(builder); + Builder outer_builder; + // Subtable values and commitments - needed for (Recursive)MergeVerifier + MergeVerifier::MergeVerificationData merge_verification_data; + RecursiveMergeVerificationData recursive_merge_verification_data; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - t_commitments_val[idx] = pcs_commitment_key.commit(t_current[idx]); + auto cm = pcs_commitment_key.commit(t_current[idx]); + merge_verification_data.t_commitments[idx] = cm; + recursive_merge_verification_data.t_commitments[idx] = + RecursiveCommitment::from_witness(&outer_builder, cm); } // Output is a goblin proof plus ECCVM/Translator verification keys - return { goblin_final.prove(), { std::make_shared(), std::make_shared() } }; - } - - /** - * @brief Transform native subtable commitments into recursive subtable commitments - * - */ - static RefArray convert_native_t_commitments_to_stdlib( - Builder* builder, - std::array& t_commitments_rec_val, - const std::array& t_commitments_val) - { - for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - t_commitments_rec_val[idx] = RecursiveCommitment::from_witness(builder, t_commitments_val[idx]); - } - - RefArray t_commitments_rec(t_commitments_rec_val); - - return t_commitments_rec; + return { outer_builder, + goblin_final.prove(), + { std::make_shared(), std::make_shared() }, + merge_verification_data, + recursive_merge_verification_data }; } }; @@ -120,11 +85,12 @@ class GoblinRecursiveVerifierTests : public testing::Test { */ TEST_F(GoblinRecursiveVerifierTests, NativeVerification) { - auto setup = create_test_data(); + auto [builder, proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + create_goblin_prover_output(); std::shared_ptr verifier_transcript = std::make_shared(); - EXPECT_TRUE(Goblin::verify(setup.proof, setup.native_t_commitments, verifier_transcript)); + EXPECT_TRUE(Goblin::verify(proof, merge_verification_data, verifier_transcript)); } /** @@ -133,11 +99,10 @@ TEST_F(GoblinRecursiveVerifierTests, NativeVerification) */ TEST_F(GoblinRecursiveVerifierTests, Basic) { - Builder builder; - auto setup = create_test_data(&builder); + auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = create_goblin_prover_output(); - GoblinRecursiveVerifier verifier{ &builder, setup.verifier_input }; - GoblinRecursiveVerifierOutput output = verifier.verify(setup.proof, setup.recursive_t_commitments); + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; + GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); output.points_accumulator.set_public(); info("Recursive Verifier: num gates = ", builder.num_gates); @@ -165,11 +130,11 @@ TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit auto get_blocks = [](size_t inner_size) -> std::tuple> { - Builder builder; - auto setup = create_test_data(&builder, inner_size); + auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = + create_goblin_prover_output(inner_size); - GoblinRecursiveVerifier verifier{ &builder, setup.verifier_input }; - GoblinRecursiveVerifierOutput output = verifier.verify(setup.proof, setup.recursive_t_commitments); + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; + GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); output.points_accumulator.set_public(); info("Recursive Verifier: num gates = ", builder.num_gates); @@ -196,20 +161,19 @@ TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) */ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) { - Builder builder; - auto setup = create_test_data(&builder); + auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = create_goblin_prover_output(); // Tamper with the ECCVM proof - for (auto& val : setup.proof.eccvm_proof.pre_ipa_proof) { + for (auto& val : proof.eccvm_proof.pre_ipa_proof) { if (val > 0) { // tamper by finding the first non-zero value and incrementing it by 1 val += 1; break; } } - GoblinRecursiveVerifier verifier{ &builder, setup.verifier_input }; + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; GoblinRecursiveVerifierOutput goblin_rec_verifier_output = - verifier.verify(setup.proof, setup.recursive_t_commitments); + verifier.verify(proof, recursive_merge_verification_data); srs::init_file_crs_factory(bb::srs::bb_crs_path()); auto crs_factory = srs::get_grumpkin_crs_factory(); @@ -230,12 +194,11 @@ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) */ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) { - Builder builder; - auto setup = create_test_data(); + auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = create_goblin_prover_output(); // Tamper with the Translator proof preamble { - GoblinProof tampered_proof = setup.proof; + GoblinProof tampered_proof = proof; for (auto& val : tampered_proof.translator_proof) { if (val > 0) { // tamper by finding the first non-zero value and incrementing it by 1 val += 1; @@ -244,15 +207,14 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) } Builder builder; - GoblinRecursiveVerifier verifier{ &builder, setup.verifier_input }; - auto t_commitments = - convert_native_t_commitments_to_stdlib(&builder, setup.t_commitments_rec_val, setup.t_commitments_val); - [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(tampered_proof, t_commitments); + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; + [[maybe_unused]] auto goblin_rec_verifier_output = + verifier.verify(tampered_proof, recursive_merge_verification_data); EXPECT_FALSE(CircuitChecker::check(builder)); } // Tamper with the Translator proof non-preamble values { - auto tampered_proof = setup.proof; + auto tampered_proof = proof; int seek = 10; for (auto& val : tampered_proof.translator_proof) { if (val > 0) { // tamper by finding the tenth non-zero value and incrementing it by 1 @@ -264,10 +226,9 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) } Builder builder; - GoblinRecursiveVerifier verifier{ &builder, setup.verifier_input }; - auto t_commitments = - convert_native_t_commitments_to_stdlib(&builder, setup.t_commitments_rec_val, setup.t_commitments_val); - [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(tampered_proof, t_commitments); + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; + [[maybe_unused]] auto goblin_rec_verifier_output = + verifier.verify(tampered_proof, recursive_merge_verification_data); EXPECT_FALSE(CircuitChecker::check(builder)); } } @@ -278,17 +239,16 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) */ TEST_F(GoblinRecursiveVerifierTests, TranslationEvaluationsFailure) { - Builder builder; - auto setup = create_test_data(&builder); + auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = create_goblin_prover_output(); // Tamper with the evaluation of `op` witness. The index is computed manually. // TODO(https://github.com/AztecProtocol/barretenberg/issues/1298): // Better recursion testing - create more flexible proof tampering tests. const size_t op_limb_index = 593; - setup.proof.eccvm_proof.pre_ipa_proof[op_limb_index] += 1; + proof.eccvm_proof.pre_ipa_proof[op_limb_index] += 1; - GoblinRecursiveVerifier verifier{ &builder, setup.verifier_input }; - [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(setup.proof, setup.recursive_t_commitments); + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; + [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(proof, recursive_merge_verification_data); EXPECT_FALSE(CircuitChecker::check(builder)); } @@ -305,13 +265,13 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure) using FF = TranslatorFlavor::FF; using BF = TranslatorFlavor::BF; - Builder builder; - auto setup = create_test_data(&builder); + auto [builder, proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + create_goblin_prover_output(); std::shared_ptr verifier_transcript = std::make_shared(); // Check natively that the proof is correct. - EXPECT_TRUE(Goblin::verify(setup.proof, setup.native_t_commitments, verifier_transcript)); + EXPECT_TRUE(Goblin::verify(proof, merge_verification_data, verifier_transcript)); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1298): // Better recursion testing - create more flexible proof tampering tests. @@ -334,11 +294,11 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure) translator_proof.begin() + static_cast(offset)); }; - tamper_with_op_commitment(setup.proof.translator_proof); + tamper_with_op_commitment(proof.translator_proof); // Construct and check the Goblin Recursive Verifier circuit - GoblinRecursiveVerifier verifier{ &builder, setup.verifier_input }; - [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(setup.proof, setup.recursive_t_commitments); + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; + [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(proof, recursive_merge_verification_data); EXPECT_FALSE(CircuitChecker::check(builder)); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp index 966c4b4cb7fe..3840b3798201 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp @@ -72,22 +72,6 @@ template class MegaHonkTests : public ::testing::Test { return verified; } - RefArray construct_subtable_commitments_from_op_queue( - auto& op_queue, - const MergeProver& merge_prover, - std::array& t_commitments_val) - { - std::array t_current = - op_queue->construct_current_ultra_ops_subtable_columns(); - for (size_t idx = 0; idx < Flavor::NUM_WIRES; idx++) { - t_commitments_val[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); - } - - RefArray t_commitments(t_commitments_val); - - return t_commitments; - } - /** * @brief Construct and verify a Goblin ECC op queue merge proof * @@ -98,10 +82,15 @@ template class MegaHonkTests : public ::testing::Test { MergeVerifier merge_verifier; merge_verifier.settings = op_queue->get_current_settings(); auto merge_proof = merge_prover.construct_proof(); - std::array t_commitments_val; - bool verified = merge_verifier.verify_proof( - merge_proof, this->construct_subtable_commitments_from_op_queue(op_queue, merge_prover, t_commitments_val)); + // Construct MergeVerificationData + MergeVerifier::MergeVerificationData merge_verification_data; + auto t_current = op_queue->construct_current_ultra_ops_subtable_columns(); + for (size_t idx = 0; idx < Flavor::NUM_WIRES; idx++) { + merge_verification_data.t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); + } + + bool verified = merge_verifier.verify_proof(merge_proof, merge_verification_data); return verified; } From cd77300d59acb10bb4d9bb44be523a68cf210d33 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:31:15 +0000 Subject: [PATCH 13/27] Cleanup --- .../graph_description_goblin.test.cpp | 2 +- .../client_ivc_verifier/client_ivc_recursive_verifier.cpp | 2 +- .../stdlib/merge_verifier/merge_verifier.test.cpp | 7 ++++--- .../recursion/goblin_avm_recursive_verifier.hpp | 3 +-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp index 5a88784414d8..5eabe242fd99 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp @@ -58,9 +58,9 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { builder.queue_ecc_no_op(); GoblinMockCircuits::construct_simple_circuit(builder); - // Subtable values and commitments - needed for (Recursive)MergeVerifier Builder outer_builder; + // Subtable values and commitments - needed for (Recursive)MergeVerifier RecursiveMergeVerificationData recursive_merge_verification_data; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp index 6db1f2ea5923..81e703740a87 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp @@ -16,7 +16,7 @@ namespace bb::stdlib::recursion::honk { */ ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const StdlibProof& proof) { - using MergeVerificationData = goblin::MergeRecursiveVerifier_::MergeVerificationData; + using MergeVerificationData = ClientIVCRecursiveVerifier::GoblinVerifier::MergeVerifier::MergeVerificationData; std::shared_ptr civc_rec_verifier_transcript(std::make_shared()); // Construct stdlib Mega verification key auto stdlib_mega_vk_and_hash = std::make_shared(*builder, ivc_verification_key.mega); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp index 4798da31bca4..c0f648e2a2a9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp @@ -86,9 +86,10 @@ template class RecursiveMergeVerifierTest : public test RecursiveMergeVerificationData recursive_merge_verification_data; auto t_current = op_queue->construct_current_ultra_ops_subtable_columns(); for (size_t idx = 0; idx < InnerFlavor::NUM_WIRES; idx++) { - merge_verification_data.t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); - recursive_merge_verification_data.t_commitments[idx] = RecursiveMergeVerifier::Commitment::from_witness( - &outer_circuit, merge_verification_data.t_commitments[idx]); + auto cm = merge_prover.pcs_commitment_key.commit(t_current[idx]); + merge_verification_data.t_commitments[idx] = cm; + recursive_merge_verification_data.t_commitments[idx] = + RecursiveMergeVerifier::Commitment::from_witness(&outer_circuit, cm); } // Construct Merge proof diff --git a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp index ca83f7196379..95242d0d603a 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp @@ -116,8 +116,7 @@ class AvmGoblinRecursiveVerifier { using MegaRecursiveVerifier = stdlib::recursion::honk::UltraRecursiveVerifier_; using GoblinRecursiveVerifier = stdlib::recursion::honk::GoblinRecursiveVerifier; using GoblinRecursiveVerifierOutput = stdlib::recursion::honk::GoblinRecursiveVerifierOutput; - using MergeVerificationData = - stdlib::recursion::goblin::MergeRecursiveVerifier_::MergeVerificationData; + using MergeVerificationData = GoblinRecursiveVerifier::MergeVerifier::MergeVerificationData; using FF = MegaRecursiveFlavor::FF; // Construct hash buffer containing the AVM proof, public inputs, and VK From de1b171a543809d2467d125fdda674d1b5ef4e90 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 16:27:25 +0000 Subject: [PATCH 14/27] Fix tests --- .../graph_description_goblin.test.cpp | 26 +++--- .../goblin_recursive_verifier.test.cpp | 80 ++++++++++++++----- 2 files changed, 73 insertions(+), 33 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp index 5eabe242fd99..5c8dc262013a 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp @@ -29,10 +29,9 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } struct ProverOutput { - Builder builder; GoblinProof proof; Goblin::VerificationKey verifier_input; - RecursiveMergeVerificationData recursive_merge_verification_data; + std::array t_commitments; }; /** @@ -58,22 +57,18 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { builder.queue_ecc_no_op(); GoblinMockCircuits::construct_simple_circuit(builder); - Builder outer_builder; - // Subtable values and commitments - needed for (Recursive)MergeVerifier - RecursiveMergeVerificationData recursive_merge_verification_data; + std::array t_commitments; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - recursive_merge_verification_data.t_commitments[idx] = - RecursiveCommitment::from_witness(&outer_builder, pcs_commitment_key.commit(t_current[idx])); + t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]); } // Output is a goblin proof plus ECCVM/Translator verification keys - return { outer_builder, - goblin_final.prove(), + return { goblin_final.prove(), { std::make_shared(), std::make_shared() }, - recursive_merge_verification_data }; + t_commitments }; } }; @@ -83,7 +78,16 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { */ TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic) { - auto [builder, proof, verifier_input, recursive_merge_verification_data] = create_goblin_prover_output(); + auto [proof, verifier_input, t_commitments] = create_goblin_prover_output(); + + Builder builder; + + // MergeVerificationData + RecursiveMergeVerificationData recursive_merge_verification_data; + for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { + recursive_merge_verification_data.t_commitments[idx] = + RecursiveCommitment::from_witness(&builder, t_commitments[idx]); + } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index ea831ecf162d..22c6145c1993 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp @@ -22,16 +22,15 @@ class GoblinRecursiveVerifierTests : public testing::Test { using Commitment = MergeVerifier::Commitment; using RecursiveCommitment = GoblinRecursiveVerifier::MergeVerifier::Commitment; + using MergeVerificationData = MergeVerifier::MergeVerificationData; using RecursiveMergeVerificationData = GoblinRecursiveVerifier::MergeVerifier::MergeVerificationData; static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } struct ProverOutput { - Builder builder; GoblinProof proof; Goblin::VerificationKey verifier_input; - MergeVerifier::MergeVerificationData merge_verification_data; - RecursiveMergeVerificationData recursive_merge_verification_data; + MergeVerificationData merge_verification_data; }; /** @@ -60,22 +59,32 @@ class GoblinRecursiveVerifierTests : public testing::Test { // Subtable values and commitments - needed for (Recursive)MergeVerifier MergeVerifier::MergeVerificationData merge_verification_data; - RecursiveMergeVerificationData recursive_merge_verification_data; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - auto cm = pcs_commitment_key.commit(t_current[idx]); - merge_verification_data.t_commitments[idx] = cm; - recursive_merge_verification_data.t_commitments[idx] = - RecursiveCommitment::from_witness(&outer_builder, cm); + merge_verification_data.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]); } // Output is a goblin proof plus ECCVM/Translator verification keys - return { outer_builder, - goblin_final.prove(), + return { goblin_final.prove(), { std::make_shared(), std::make_shared() }, - merge_verification_data, - recursive_merge_verification_data }; + merge_verification_data }; + } + + /** + * @brief Build MergeVerificationData for recursive verification + * + */ + static RecursiveMergeVerificationData construct_recursive_merge_verification_data( + Builder* builder, const MergeVerificationData& merge_verification_data) + { + RecursiveMergeVerificationData recursive_merge_verification_data; + for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { + recursive_merge_verification_data.t_commitments[idx] = + RecursiveCommitment::from_witness(builder, merge_verification_data.t_commitments[idx]); + } + + return recursive_merge_verification_data; } }; @@ -85,8 +94,7 @@ class GoblinRecursiveVerifierTests : public testing::Test { */ TEST_F(GoblinRecursiveVerifierTests, NativeVerification) { - auto [builder, proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = - create_goblin_prover_output(); + auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); std::shared_ptr verifier_transcript = std::make_shared(); @@ -99,7 +107,12 @@ TEST_F(GoblinRecursiveVerifierTests, NativeVerification) */ TEST_F(GoblinRecursiveVerifierTests, Basic) { - auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); + + Builder builder; + + RecursiveMergeVerificationData recursive_merge_verification_data = + construct_recursive_merge_verification_data(&builder, merge_verification_data); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); @@ -130,8 +143,12 @@ TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit auto get_blocks = [](size_t inner_size) -> std::tuple> { - auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = - create_goblin_prover_output(inner_size); + auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(inner_size); + + Builder builder; + + RecursiveMergeVerificationData recursive_merge_verification_data = + construct_recursive_merge_verification_data(&builder, merge_verification_data); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); @@ -161,7 +178,12 @@ TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) */ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) { - auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); + + Builder builder; + + RecursiveMergeVerificationData recursive_merge_verification_data = + construct_recursive_merge_verification_data(&builder, merge_verification_data); // Tamper with the ECCVM proof for (auto& val : proof.eccvm_proof.pre_ipa_proof) { @@ -194,7 +216,12 @@ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) */ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) { - auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); + + Builder builder; + + RecursiveMergeVerificationData recursive_merge_verification_data = + construct_recursive_merge_verification_data(&builder, merge_verification_data); // Tamper with the Translator proof preamble { @@ -239,7 +266,12 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) */ TEST_F(GoblinRecursiveVerifierTests, TranslationEvaluationsFailure) { - auto [builder, proof, verifier_input, _, recursive_merge_verification_data] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); + + Builder builder; + + RecursiveMergeVerificationData recursive_merge_verification_data = + construct_recursive_merge_verification_data(&builder, merge_verification_data); // Tamper with the evaluation of `op` witness. The index is computed manually. // TODO(https://github.com/AztecProtocol/barretenberg/issues/1298): @@ -265,8 +297,12 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure) using FF = TranslatorFlavor::FF; using BF = TranslatorFlavor::BF; - auto [builder, proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = - create_goblin_prover_output(); + auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); + + Builder builder; + + RecursiveMergeVerificationData recursive_merge_verification_data = + construct_recursive_merge_verification_data(&builder, merge_verification_data); std::shared_ptr verifier_transcript = std::make_shared(); From cf6498f6d4672bdbe9d3ea86816cf1a1ef9d58ae Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 15 Jul 2025 16:36:22 +0000 Subject: [PATCH 15/27] Further fixes --- .../goblin_recursive_verifier.test.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index 22c6145c1993..7b59d959aadb 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp @@ -218,11 +218,6 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) { auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); - Builder builder; - - RecursiveMergeVerificationData recursive_merge_verification_data = - construct_recursive_merge_verification_data(&builder, merge_verification_data); - // Tamper with the Translator proof preamble { GoblinProof tampered_proof = proof; @@ -234,6 +229,10 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) } Builder builder; + + RecursiveMergeVerificationData recursive_merge_verification_data = + construct_recursive_merge_verification_data(&builder, merge_verification_data); + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(tampered_proof, recursive_merge_verification_data); @@ -253,6 +252,10 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) } Builder builder; + + RecursiveMergeVerificationData recursive_merge_verification_data = + construct_recursive_merge_verification_data(&builder, merge_verification_data); + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(tampered_proof, recursive_merge_verification_data); From 98c1c51a9ccba5270e1d926630260aa2e4b73563 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Wed, 16 Jul 2025 07:07:18 +0000 Subject: [PATCH 16/27] Add reset method for MergeVerificationData --- .../cpp/src/barretenberg/client_ivc/client_ivc.cpp | 3 +++ .../merge_verifier/merge_recursive_verifier.hpp | 11 +++++++++++ .../src/barretenberg/ultra_honk/merge_verifier.hpp | 11 +++++++++++ 3 files changed, 25 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index a6508af7b31f..8ef0671ebbce 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -209,6 +209,9 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) kernel_output.app_return_data = bus_depot.get_app_return_data_commitment(circuit); kernel_output.set_public(); + + // Reset MergeVerificationData after recursive verification + merge_verification_data.reset(); } /** diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp index aa27cecd3703..1e77584a25d8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp @@ -50,6 +50,17 @@ template class MergeRecursiveVerifier_ { t_commitments[idx] = t_commitments_ref[idx]; } } + + /** + * @brief Reset + * + */ + void reset() + { + t_commitments = {}; + // T_prev_commitments = {}; + T_commitments = {}; + } }; explicit MergeRecursiveVerifier_(CircuitBuilder* builder, diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index 2f6148bbabaa..9348c784e7d0 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -55,6 +55,17 @@ class MergeVerifier { t_commitments[idx] = t_commitments_ref[idx]; } } + + /** + * @brief Reset + * + */ + void reset() + { + t_commitments = {}; + // T_prev_commitments = {}; + T_commitments = {}; + } }; explicit MergeVerifier(const std::shared_ptr& transcript = std::make_shared(), From a418fbc18a5051d2a0cd2481e4d8ab302fd096ad Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Wed, 16 Jul 2025 08:00:24 +0000 Subject: [PATCH 17/27] Improve tests --- .../goblin_recursive_verifier.test.cpp | 82 ++++++++----------- 1 file changed, 35 insertions(+), 47 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index 7b59d959aadb..c899f5035192 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp @@ -31,6 +31,7 @@ class GoblinRecursiveVerifierTests : public testing::Test { GoblinProof proof; Goblin::VerificationKey verifier_input; MergeVerificationData merge_verification_data; + RecursiveMergeVerificationData recursive_merge_verification_data; }; /** @@ -38,7 +39,7 @@ class GoblinRecursiveVerifierTests : public testing::Test { * * @return ProverOutput */ - static ProverOutput create_goblin_prover_output(const size_t NUM_CIRCUITS = 3) + static ProverOutput create_goblin_prover_output(Builder* outer_builder = nullptr, const size_t NUM_CIRCUITS = 3) { Goblin goblin; @@ -55,36 +56,27 @@ class GoblinRecursiveVerifierTests : public testing::Test { builder.queue_ecc_no_op(); GoblinMockCircuits::construct_simple_circuit(builder); - Builder outer_builder; - // Subtable values and commitments - needed for (Recursive)MergeVerifier - MergeVerifier::MergeVerificationData merge_verification_data; + MergeVerificationData merge_verification_data; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { merge_verification_data.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]); } - // Output is a goblin proof plus ECCVM/Translator verification keys - return { goblin_final.prove(), - { std::make_shared(), std::make_shared() }, - merge_verification_data }; - } - - /** - * @brief Build MergeVerificationData for recursive verification - * - */ - static RecursiveMergeVerificationData construct_recursive_merge_verification_data( - Builder* builder, const MergeVerificationData& merge_verification_data) - { RecursiveMergeVerificationData recursive_merge_verification_data; - for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - recursive_merge_verification_data.t_commitments[idx] = - RecursiveCommitment::from_witness(builder, merge_verification_data.t_commitments[idx]); + if (outer_builder != nullptr) { + for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { + recursive_merge_verification_data.t_commitments[idx] = + RecursiveCommitment::from_witness(outer_builder, merge_verification_data.t_commitments[idx]); + } } - return recursive_merge_verification_data; + // Output is a goblin proof plus ECCVM/Translator verification keys + return { goblin_final.prove(), + { std::make_shared(), std::make_shared() }, + merge_verification_data, + recursive_merge_verification_data }; } }; @@ -94,7 +86,7 @@ class GoblinRecursiveVerifierTests : public testing::Test { */ TEST_F(GoblinRecursiveVerifierTests, NativeVerification) { - auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_verification_data, _] = create_goblin_prover_output(); std::shared_ptr verifier_transcript = std::make_shared(); @@ -107,12 +99,10 @@ TEST_F(GoblinRecursiveVerifierTests, NativeVerification) */ TEST_F(GoblinRecursiveVerifierTests, Basic) { - auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); - Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data = - construct_recursive_merge_verification_data(&builder, merge_verification_data); + auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + create_goblin_prover_output(&builder); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); @@ -143,12 +133,10 @@ TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit auto get_blocks = [](size_t inner_size) -> std::tuple> { - auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(inner_size); - Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data = - construct_recursive_merge_verification_data(&builder, merge_verification_data); + auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + create_goblin_prover_output(&builder, inner_size); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); @@ -178,12 +166,10 @@ TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) */ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) { - auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); - Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data = - construct_recursive_merge_verification_data(&builder, merge_verification_data); + auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + create_goblin_prover_output(&builder); // Tamper with the ECCVM proof for (auto& val : proof.eccvm_proof.pre_ipa_proof) { @@ -216,7 +202,7 @@ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) */ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) { - auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_verification_data, _] = create_goblin_prover_output(); // Tamper with the Translator proof preamble { @@ -230,8 +216,11 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data = - construct_recursive_merge_verification_data(&builder, merge_verification_data); + RecursiveMergeVerificationData recursive_merge_verification_data; + for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { + recursive_merge_verification_data.t_commitments[idx] = + RecursiveCommitment::from_witness(&builder, merge_verification_data.t_commitments[idx]); + } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; [[maybe_unused]] auto goblin_rec_verifier_output = @@ -253,8 +242,11 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data = - construct_recursive_merge_verification_data(&builder, merge_verification_data); + RecursiveMergeVerificationData recursive_merge_verification_data; + for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { + recursive_merge_verification_data.t_commitments[idx] = + RecursiveCommitment::from_witness(&builder, merge_verification_data.t_commitments[idx]); + } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; [[maybe_unused]] auto goblin_rec_verifier_output = @@ -269,12 +261,10 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) */ TEST_F(GoblinRecursiveVerifierTests, TranslationEvaluationsFailure) { - auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); - Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data = - construct_recursive_merge_verification_data(&builder, merge_verification_data); + auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + create_goblin_prover_output(&builder); // Tamper with the evaluation of `op` witness. The index is computed manually. // TODO(https://github.com/AztecProtocol/barretenberg/issues/1298): @@ -300,12 +290,10 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure) using FF = TranslatorFlavor::FF; using BF = TranslatorFlavor::BF; - auto [proof, verifier_input, merge_verification_data] = create_goblin_prover_output(); - Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data = - construct_recursive_merge_verification_data(&builder, merge_verification_data); + auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + create_goblin_prover_output(&builder); std::shared_ptr verifier_transcript = std::make_shared(); From 9f27abbf320f3e0ea1a3d80ffe01d954c9650154 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 16 Jul 2025 16:21:05 +0000 Subject: [PATCH 18/27] [empty] Start merge-train. Choo choo. From f62ee833f6807eb5637b863df8e4ee4cf6bfe6f2 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 08:54:30 +0000 Subject: [PATCH 19/27] Update data structure --- .../merge_recursive_verifier.cpp | 10 +++++--- .../merge_recursive_verifier.hpp | 25 ++++++++----------- .../merge_verifier/merge_verifier.test.cpp | 20 +++++++++------ .../ultra_honk/merge_verifier.cpp | 10 +++++--- .../ultra_honk/merge_verifier.hpp | 25 ++++++++----------- 5 files changed, 46 insertions(+), 44 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp index 068b623748e9..7dd0b022343e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp @@ -66,7 +66,9 @@ MergeRecursiveVerifier_::MergeRecursiveVerifier_(CircuitBuilder* */ template MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_::verify_proof( - const stdlib::Proof& proof, MergeVerificationData& merge_verification_data) + const stdlib::Proof& proof, + const SubtableWitnessCommitments& subtable_commitments, + std::array& merged_table_commitment) { using Claims = typename ShplonkVerifier_::LinearCombinationOfClaims; @@ -82,9 +84,9 @@ MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_template receive_from_prover("T_PREV_" + std::to_string(idx)); auto left_table = - settings == MergeSettings::PREPEND ? merge_verification_data.t_commitments[idx] : T_prev_commitment; + settings == MergeSettings::PREPEND ? subtable_commitments.t_commitments[idx] : T_prev_commitment; auto right_table = - settings == MergeSettings::PREPEND ? T_prev_commitment : merge_verification_data.t_commitments[idx]; + settings == MergeSettings::PREPEND ? T_prev_commitment : subtable_commitments.t_commitments[idx]; table_commitments.emplace_back(left_table); table_commitments.emplace_back(right_table); @@ -96,7 +98,7 @@ MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_ class MergeRecursiveVerifier_ { // MegaCircuitBuilder static constexpr size_t NUM_WIRES = MegaExecutionTraceBlocks::NUM_WIRES; - class MergeVerificationData { + class SubtableWitnessCommitments { public: std::array t_commitments; // std::array T_prev_commitments; - std::array T_commitments; - MergeVerificationData() = default; + SubtableWitnessCommitments() = default; /** * @brief Set t_commitments from RefArray @@ -50,17 +49,13 @@ template class MergeRecursiveVerifier_ { t_commitments[idx] = t_commitments_ref[idx]; } } + }; - /** - * @brief Reset - * - */ - void reset() - { - t_commitments = {}; - // T_prev_commitments = {}; - T_commitments = {}; - } + class WitnessCommitments : public SubtableWitnessCommitments { + public: + std::array T_commitments; + + WitnessCommitments() = default; }; explicit MergeRecursiveVerifier_(CircuitBuilder* builder, @@ -68,7 +63,9 @@ template class MergeRecursiveVerifier_ { MergeSettings settings = MergeSettings::PREPEND); [[nodiscard("Pairing points should be accumulated")]] PairingPoints verify_proof( - const stdlib::Proof& proof, MergeVerificationData& merge_verification_data); + const stdlib::Proof& proof, + const SubtableWitnessCommitments& subtable_commitments, + std::array& merged_table_commitment); }; } // namespace bb::stdlib::recursion::goblin diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp index c0f648e2a2a9..4f3717b756ec 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp @@ -22,7 +22,8 @@ template class RecursiveMergeVerifierTest : public test // Types for recursive verifier circuit using RecursiveMergeVerifier = MergeRecursiveVerifier_; - using RecursiveMergeVerificationData = MergeRecursiveVerifier_::MergeVerificationData; + using RecursiveSubtableCommitments = MergeRecursiveVerifier_::SubtableWitnessCommitments; + using RecursiveMergeCommitments = MergeRecursiveVerifier_::WitnessCommitments; // Define types relevant for inner circuit using InnerFlavor = MegaFlavor; @@ -34,7 +35,8 @@ template class RecursiveMergeVerifierTest : public test using FF = InnerFlavor::FF; using VerifierCommitmentKey = bb::VerifierCommitmentKey; using MergeProof = MergeProver::MergeProof; - using MergeVerificationData = MergeVerifier::MergeVerificationData; + using SubtableCommitments = MergeVerifier::SubtableWitnessCommitments; + using MergeCommitments = MergeVerifier::WitnessCommitments; enum class TamperProofMode { None, Shift, MCommitment, LEval }; @@ -82,13 +84,13 @@ template class RecursiveMergeVerifierTest : public test MergeProver merge_prover{ op_queue }; // Subtable values and commitments - needed for (Recursive)MergeVerifier - MergeVerificationData merge_verification_data; - RecursiveMergeVerificationData recursive_merge_verification_data; + MergeCommitments merge_commitments; + RecursiveMergeCommitments recursive_merge_commitments; auto t_current = op_queue->construct_current_ultra_ops_subtable_columns(); for (size_t idx = 0; idx < InnerFlavor::NUM_WIRES; idx++) { auto cm = merge_prover.pcs_commitment_key.commit(t_current[idx]); - merge_verification_data.t_commitments[idx] = cm; - recursive_merge_verification_data.t_commitments[idx] = + merge_commitments.t_commitments[idx] = cm; + recursive_merge_commitments.t_commitments[idx] = RecursiveMergeVerifier::Commitment::from_witness(&outer_circuit, cm); } @@ -101,7 +103,8 @@ template class RecursiveMergeVerifierTest : public test verifier.transcript->enable_manifest(); verifier.settings = op_queue->get_current_settings(); const stdlib::Proof stdlib_merge_proof(outer_circuit, merge_proof); - auto pairing_points = verifier.verify_proof(stdlib_merge_proof, recursive_merge_verification_data); + auto pairing_points = verifier.verify_proof( + stdlib_merge_proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(outer_circuit.failed(), !expected) << outer_circuit.err(); @@ -111,7 +114,8 @@ template class RecursiveMergeVerifierTest : public test MergeVerifier native_verifier; native_verifier.transcript->enable_manifest(); native_verifier.settings = op_queue->get_current_settings(); - bool verified_native = native_verifier.verify_proof(merge_proof, merge_verification_data); + bool verified_native = + native_verifier.verify_proof(merge_proof, merge_commitments, merge_commitments.T_commitments); VerifierCommitmentKey pcs_verification_key; bool verified_recursive = pcs_verification_key.pairing_check(pairing_points.P0.get_value(), pairing_points.P1.get_value()); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index d3ea597e6cf5..cceb1a08238b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -59,7 +59,9 @@ MergeVerifier::MergeVerifier(const std::shared_ptr& transcript, Merg * the PG verifier with which the Merge verifier shares a transcript * @return bool Verification result */ -bool MergeVerifier::verify_proof(const HonkProof& proof, MergeVerificationData& merge_verification_data) +bool MergeVerifier::verify_proof(const HonkProof& proof, + const SubtableWitnessCommitments& subtable_commitments, + std::array& merged_table_commitment) { using Claims = typename ShplonkVerifier_::LinearCombinationOfClaims; @@ -75,9 +77,9 @@ bool MergeVerifier::verify_proof(const HonkProof& proof, MergeVerificationData& // TODO(https://github.com/AztecProtocol/barretenberg/issues/1473): remove receiving commitment to T_prev auto T_prev_commitment = transcript->template receive_from_prover("T_PREV_" + std::to_string(idx)); auto left_table = - settings == MergeSettings::PREPEND ? merge_verification_data.t_commitments[idx] : T_prev_commitment; + settings == MergeSettings::PREPEND ? subtable_commitments.t_commitments[idx] : T_prev_commitment; auto right_table = - settings == MergeSettings::PREPEND ? T_prev_commitment : merge_verification_data.t_commitments[idx]; + settings == MergeSettings::PREPEND ? T_prev_commitment : subtable_commitments.t_commitments[idx]; table_commitments.emplace_back(left_table); table_commitments.emplace_back(right_table); @@ -89,7 +91,7 @@ bool MergeVerifier::verify_proof(const HonkProof& proof, MergeVerificationData& // Store T_commitments of the verifier size_t commitment_idx = 2; // Index of [m_j = T_j] in the vector of commitments - for (auto& commitment : merge_verification_data.T_commitments) { + for (auto& commitment : merged_table_commitment) { commitment = table_commitments[commitment_idx]; commitment_idx += NUM_WIRES; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index 9348c784e7d0..c64baa2907da 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -36,13 +36,12 @@ class MergeVerifier { std::shared_ptr transcript; MergeSettings settings; - class MergeVerificationData { + class SubtableWitnessCommitments { public: std::array t_commitments; // std::array T_prev_commitments; - std::array T_commitments; - MergeVerificationData() = default; + SubtableWitnessCommitments() = default; /** * @brief Set t_commitments from RefArray @@ -55,22 +54,20 @@ class MergeVerifier { t_commitments[idx] = t_commitments_ref[idx]; } } + }; - /** - * @brief Reset - * - */ - void reset() - { - t_commitments = {}; - // T_prev_commitments = {}; - T_commitments = {}; - } + class WitnessCommitments : public SubtableWitnessCommitments { + public: + std::array T_commitments; + + WitnessCommitments() = default; }; explicit MergeVerifier(const std::shared_ptr& transcript = std::make_shared(), MergeSettings settings = MergeSettings::PREPEND); - bool verify_proof(const HonkProof& proof, MergeVerificationData& merge_verification_data); + bool verify_proof(const HonkProof& proof, + const SubtableWitnessCommitments& subtable_commitments, + std::array& merged_table_commitment); }; } // namespace bb From 68dfa184c2fe919ec4d28a7a2776831fec0186bc Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 08:57:17 +0000 Subject: [PATCH 20/27] Update comments --- .../stdlib/merge_verifier/merge_recursive_verifier.cpp | 5 +++-- .../cpp/src/barretenberg/ultra_honk/merge_verifier.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp index 7dd0b022343e..0bbec6f13b8a 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp @@ -60,8 +60,9 @@ MergeRecursiveVerifier_::MergeRecursiveVerifier_(CircuitBuilder* * * @tparam CircuitBuilder * @param proof - * @param t_commitments The commitments to t_j read from the transcript by the PG recursive verifier with which - * the Merge recursive verifier shares a transcript + * @param subtable_commitments The subtable comittments data, containing the commitments to t_j read from the transcript + * by the PG verifier with which the Merge verifier shares a transcript + * @param merged_table_commitment The commitment to the merged table as read from the proof * @return PairingPoints Inputs to final pairing */ template diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index cceb1a08238b..0d57cfbfefde 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -55,8 +55,9 @@ MergeVerifier::MergeVerifier(const std::shared_ptr& transcript, Merg * - \f$l_j = T_{prev,j}, r_j = t_j, m_j = T_j\f$ if we are appending the subtable * * @param proof - * @param merge_verification_data The verification data, containing the commitments to t_j read from the transcript by - * the PG verifier with which the Merge verifier shares a transcript + * @param subtable_commitments The subtable comittments data, containing the commitments to t_j read from the transcript + * by the PG verifier with which the Merge verifier shares a transcript + * @param merged_table_commitment The commitment to the merged table as read from the proof * @return bool Verification result */ bool MergeVerifier::verify_proof(const HonkProof& proof, From b59793a79e4ea626b8589d89197820fb2a0510ad Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 10:35:34 +0000 Subject: [PATCH 21/27] Update goblin interface --- .../cpp/src/barretenberg/goblin/goblin.cpp | 18 +++++++------ .../cpp/src/barretenberg/goblin/goblin.hpp | 25 ++++++++++++------- .../merge_recursive_verifier.cpp | 2 +- .../ultra_honk/merge_verifier.cpp | 2 +- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp index 501a3416f5f6..08e34d14eac3 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp @@ -72,9 +72,11 @@ GoblinProof Goblin::prove() return goblin_proof; } -Goblin::PairingPoints Goblin::recursively_verify_merge(MegaBuilder& builder, - RecursiveMergeVerificationData& merge_verification_data, - const std::shared_ptr& transcript) +Goblin::PairingPoints Goblin::recursively_verify_merge( + MegaBuilder& builder, + const RecursiveMergeSubtableCommitments& subtable_commitments, + std::array& merged_table_commitment, + const std::shared_ptr& transcript) { ASSERT(!merge_verification_queue.empty()); // Recursively verify the next merge proof in the verification queue in a FIFO manner @@ -82,7 +84,8 @@ Goblin::PairingPoints Goblin::recursively_verify_merge(MegaBuilder& builder, const stdlib::Proof stdlib_merge_proof(builder, merge_proof); MergeRecursiveVerifier merge_verifier{ &builder, transcript }; - PairingPoints pairing_points = merge_verifier.verify_proof(stdlib_merge_proof, merge_verification_data); + PairingPoints pairing_points = + merge_verifier.verify_proof(stdlib_merge_proof, subtable_commitments, merged_table_commitment); merge_verification_queue.pop_front(); // remove the processed proof from the queue @@ -90,11 +93,12 @@ Goblin::PairingPoints Goblin::recursively_verify_merge(MegaBuilder& builder, } bool Goblin::verify(const GoblinProof& proof, - MergeVerificationData& merge_verification_data, + const MergeSubtableCommitments& subtable_commitments, + std::array& merged_table_commitment, const std::shared_ptr& transcript) { MergeVerifier merge_verifier(transcript); - bool merge_verified = merge_verifier.verify_proof(proof.merge_proof, merge_verification_data); + bool merge_verified = merge_verifier.verify_proof(proof.merge_proof, subtable_commitments, merged_table_commitment); ECCVMVerifier eccvm_verifier(transcript); bool eccvm_verified = eccvm_verifier.verify_proof(proof.eccvm_proof); @@ -110,7 +114,7 @@ bool Goblin::verify(const GoblinProof& proof, // Verify the consistency between the commitments to polynomials representing the op queue received by translator // and final merge verifier bool op_queue_consistency_verified = - translator_verifier.verify_consistency_with_final_merge(merge_verification_data.T_commitments); + translator_verifier.verify_consistency_with_final_merge(merged_table_commitment); vinfo("merge verified?: ", merge_verified); vinfo("eccvm verified?: ", eccvm_verified); diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 76eb59b325e0..22078d55d7e6 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -38,8 +38,9 @@ class Goblin { using TranslatorVerificationKey = TranslatorFlavor::VerificationKey; using MergeRecursiveVerifier = stdlib::recursion::goblin::MergeRecursiveVerifier_; using PairingPoints = MergeRecursiveVerifier::PairingPoints; - using MergeVerificationData = MergeVerifier::MergeVerificationData; - using RecursiveMergeVerificationData = MergeRecursiveVerifier::MergeVerificationData; + using MergeSubtableCommitments = MergeVerifier::SubtableWitnessCommitments; + using RecursiveMergeSubtableCommitments = MergeRecursiveVerifier::SubtableWitnessCommitments; + using RecursiveCommitment = MergeRecursiveVerifier::Commitment; using RecursiveTranscript = bb::BaseTranscript>; std::shared_ptr op_queue = std::make_shared(); @@ -93,27 +94,33 @@ class Goblin { * @details Proofs are verified in a FIFO manner * * @param builder The circuit in which the recursive verification will be performed. - * @param merge_verification_data The merge verification data, containing the commitments to the subtable for which - * the merge is being verified. + * @param subtable_commitments The subtable commitments data, containing the commitments to t_j read from the + * transcript by the PG verifier with which the Merge verifier shares a transcript + * @param merged_table_commitment The commitment to the merged table as read from the proof * @param transcript The transcript to be passed to the MergeRecursiveVerifier. * @return PairingPoints */ - PairingPoints recursively_verify_merge(MegaBuilder& builder, - RecursiveMergeVerificationData& merge_verification_data, - const std::shared_ptr& transcript); + PairingPoints recursively_verify_merge( + MegaBuilder& builder, + const RecursiveMergeSubtableCommitments& subtable_commitments, + std::array& merged_table_commitment, + const std::shared_ptr& transcript); /** * @brief Verify a full Goblin proof (ECCVM, Translator, merge) * * @param proof - * @param t_commitments // The commitments to the subtable for which the merge is being verified + * @param subtable_commitments The subtable commitments data, containing the commitments to t_j read from the + * transcript by the PG verifier with which the Merge verifier shares a transcript + * @param merged_table_commitment The commitment to the merged table as read from the proof * @param transcript * * @return true * @return false */ static bool verify(const GoblinProof& proof, - MergeVerificationData& merge_verification_data, + const MergeSubtableCommitments& subtable_commitments, + std::array& merged_table_commitment, const std::shared_ptr& transcript); }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp index 0bbec6f13b8a..73bc172de90f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp @@ -60,7 +60,7 @@ MergeRecursiveVerifier_::MergeRecursiveVerifier_(CircuitBuilder* * * @tparam CircuitBuilder * @param proof - * @param subtable_commitments The subtable comittments data, containing the commitments to t_j read from the transcript + * @param subtable_commitments The subtable commitments data, containing the commitments to t_j read from the transcript * by the PG verifier with which the Merge verifier shares a transcript * @param merged_table_commitment The commitment to the merged table as read from the proof * @return PairingPoints Inputs to final pairing diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index 0d57cfbfefde..554296ef13bd 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -55,7 +55,7 @@ MergeVerifier::MergeVerifier(const std::shared_ptr& transcript, Merg * - \f$l_j = T_{prev,j}, r_j = t_j, m_j = T_j\f$ if we are appending the subtable * * @param proof - * @param subtable_commitments The subtable comittments data, containing the commitments to t_j read from the transcript + * @param subtable_commitments The subtable commitments data, containing the commitments to t_j read from the transcript * by the PG verifier with which the Merge verifier shares a transcript * @param merged_table_commitment The commitment to the merged table as read from the proof * @return bool Verification result From f88393811c4ff17affef8926af7ed2b903b4ee01 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 10:38:32 +0000 Subject: [PATCH 22/27] Update rec goblin interface --- .../goblin_verifier/goblin_recursive_verifier.cpp | 14 +++++++++----- .../goblin_verifier/goblin_recursive_verifier.hpp | 12 ++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp index 414ac78827ef..0ce916704916 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp @@ -16,10 +16,12 @@ namespace bb::stdlib::recursion::honk { * */ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( - const GoblinProof& proof, MergeVerifier::MergeVerificationData& merge_verification_data) + const GoblinProof& proof, + const SubtableCommitments& subtable_commitments, + std::array& merged_table_commitment) { StdlibProof stdlib_proof(*builder, proof); - return verify(stdlib_proof, merge_verification_data); + return verify(stdlib_proof, subtable_commitments, merged_table_commitment); } /** @@ -30,12 +32,14 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( * */ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( - const StdlibProof& proof, MergeVerifier::MergeVerificationData& merge_verification_data) + const StdlibProof& proof, + const SubtableCommitments& subtable_commitments, + std::array& merged_table_commitment) { // Verify the final merge step MergeVerifier merge_verifier{ builder, transcript }; PairingPoints merge_pairing_points = - merge_verifier.verify_proof(proof.merge_proof, merge_verification_data); + merge_verifier.verify_proof(proof.merge_proof, subtable_commitments, merged_table_commitment); // Run the ECCVM recursive verifier ECCVMVerifier eccvm_verifier{ builder, verification_keys.eccvm_verification_key, transcript }; @@ -54,7 +58,7 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( // Verify the consistency between the commitments to polynomials representing the op queue received by translator // and final merge verifier - translator_verifier.verify_consistency_with_final_merge(merge_verification_data.T_commitments); + translator_verifier.verify_consistency_with_final_merge(merged_table_commitment); return { translator_pairing_points, opening_claim, ipa_proof }; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp index de6713e7b51e..7513c7b32e6f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp @@ -38,6 +38,10 @@ class GoblinRecursiveVerifier { // ECCVM and Translator verification keys using VerificationKey = Goblin::VerificationKey; + // Merge commitments + using SubtableCommitments = MergeVerifier::SubtableWitnessCommitments; + using Commitment = MergeVerifier::Commitment; + struct StdlibProof { using StdlibHonkProof = bb::stdlib::Proof; using StdlibEccvmProof = ECCVMVerifier::StdlibProof; @@ -62,9 +66,13 @@ class GoblinRecursiveVerifier { , transcript(transcript){}; [[nodiscard("IPA claim and Pairing points should be accumulated")]] GoblinRecursiveVerifierOutput verify( - const GoblinProof&, MergeVerifier::MergeVerificationData& merge_verification_data); + const GoblinProof&, + const SubtableCommitments& subtable_commitments, + std::array& merged_table_commitment); [[nodiscard("IPA claim and Pairing points should be accumulated")]] GoblinRecursiveVerifierOutput verify( - const StdlibProof&, MergeVerifier::MergeVerificationData& merge_verification_data); + const StdlibProof&, + const SubtableCommitments& subtable_commitments, + std::array& merged_table_commitment); private: Builder* builder; From 4dc6bf9658005ad39d6c3d624bc4e5420fb436c0 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:19:36 +0000 Subject: [PATCH 23/27] Update ClientIVC interface --- .../barretenberg/client_ivc/client_ivc.cpp | 34 +++++++++++-------- .../barretenberg/client_ivc/client_ivc.hpp | 12 ++++--- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 8ef0671ebbce..0f724a9d1676 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -77,16 +77,20 @@ void ClientIVC::instantiate_stdlib_verification_queue( * proof and (2) the associated databus commitment consistency checks. * @details The recursive verifier will be either Oink or Protogalaxy depending on the specified proof type. In either * case, the verifier accumulator is updated in place via the verification algorithm. Databus commitment consistency - * checks are performed on the witness commitments and public inputs extracted from the proof by the verifier. + * checks are performed on the witness commitments and public inputs extracted from the proof by the verifier. Merge + * verification is performed with commitments to the subtable t_j extracted from the PG verifier. The computed + * commitment T is propagated to the next step of recursive verification. * * @param circuit * @param verifier_inputs {proof, vkey, type (Oink/PG)} A set of inputs for recursive verification + * @param merge_commitments Container for the commitments for the Merge recursive verification to be performed * @param accumulation_recursive_transcript Transcript shared across recursive verification of the folding of * K_{i-1} (kernel), A_{i,1} (app), .., A_{i, n} (app) */ ClientIVC::PairingPoints ClientIVC::perform_recursive_verification_and_databus_consistency_checks( ClientCircuit& circuit, const StdlibVerifierInputs& verifier_inputs, + MergeCommitments& merge_commitments, const std::shared_ptr& accumulation_recursive_transcript) { // Store the decider vk for the incoming circuit; its data is used in the databus consistency checks below @@ -132,11 +136,11 @@ ClientIVC::PairingPoints ClientIVC::perform_recursive_verification_and_databus_c } // Extract the commitments to the subtable corresponding to the incoming circuit - merge_verification_data.set_t_commitments(decider_vk->witness_commitments.get_ecc_op_wires()); + merge_commitments.set_t_commitments(decider_vk->witness_commitments.get_ecc_op_wires()); // Recursively verify the corresponding merge proof - PairingPoints pairing_points = - goblin.recursively_verify_merge(circuit, merge_verification_data, accumulation_recursive_transcript); + PairingPoints pairing_points = goblin.recursively_verify_merge( + circuit, merge_commitments, merge_commitments.T_commitments, accumulation_recursive_transcript); PairingPoints nested_pairing_points; // to be extracted from public inputs of app or kernel proof just verified @@ -183,6 +187,9 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) // .., A_{i, n} (app) auto accumulation_recursive_transcript = std::make_shared(); + // Merge commitments to be used in the recursive verifications + MergeCommitments merge_commitments; + // Instantiate stdlib verifier inputs from their native counterparts if (stdlib_verification_queue.empty()) { instantiate_stdlib_verification_queue(circuit); @@ -193,7 +200,7 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) while (!stdlib_verification_queue.empty()) { const StdlibVerifierInputs& verifier_input = stdlib_verification_queue.front(); PairingPoints pairing_points = perform_recursive_verification_and_databus_consistency_checks( - circuit, verifier_input, accumulation_recursive_transcript); + circuit, verifier_input, merge_commitments, accumulation_recursive_transcript); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1376): Optimize recursion aggregation - seems we // can use `batch_mul` here to decrease the size of the `ECCOpQueue`, but must be cautious with FS security. @@ -209,9 +216,6 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) kernel_output.app_return_data = bus_depot.get_app_return_data_commitment(circuit); kernel_output.set_public(); - - // Reset MergeVerificationData after recursive verification - merge_verification_data.reset(); } /** @@ -388,11 +392,12 @@ std::shared_ptr ClientIVC::construct_hiding_circ kernel_input.app_return_data.assert_equal(tail_kernel_decider_vk->witness_commitments.secondary_calldata); // Extract the commitments to the subtable corresponding to the incoming circuit - merge_verification_data.set_t_commitments(tail_kernel_decider_vk->witness_commitments.get_ecc_op_wires()); + MergeCommitments merge_commitments; + merge_commitments.set_t_commitments(tail_kernel_decider_vk->witness_commitments.get_ecc_op_wires()); // Perform recursive verification of the last merge proof - PairingPoints points_accumulator = - goblin.recursively_verify_merge(builder, merge_verification_data, pg_merge_transcript); + PairingPoints points_accumulator = goblin.recursively_verify_merge( + builder, merge_commitments, merge_commitments.T_commitments, pg_merge_transcript); points_accumulator.aggregate(kernel_input.pairing_inputs); // Perform recursive decider verification @@ -454,11 +459,12 @@ bool ClientIVC::verify(const Proof& proof, const VerificationKey& vk) vinfo("Mega verified: ", mega_verified); // Extract the commitments to the subtable corresponding to the incoming circuit - MergeVerifier::MergeVerificationData merge_verification_data; - merge_verification_data.set_t_commitments(verifier.verification_key->witness_commitments.get_ecc_op_wires()); + MergeVerifier::WitnessCommitments merge_commitments; + merge_commitments.set_t_commitments(verifier.verification_key->witness_commitments.get_ecc_op_wires()); // Goblin verification (final merge, eccvm, translator) - bool goblin_verified = Goblin::verify(proof.goblin_proof, merge_verification_data, civc_verifier_transcript); + bool goblin_verified = Goblin::verify( + proof.goblin_proof, merge_commitments, merge_commitments.T_commitments, civc_verifier_transcript); vinfo("Goblin verified: ", goblin_verified); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1396): State tracking in CIVC verifiers. diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 30310f7331cc..4f6ade9f07c4 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -77,8 +77,12 @@ class ClientIVC { using KernelIO = bb::stdlib::recursion::honk::KernelIO; using AppIO = bb::stdlib::recursion::honk::AppIO; using StdlibProof = stdlib::Proof; - using MergeVerificationData = - stdlib::recursion::goblin::MergeRecursiveVerifier_::MergeVerificationData; + + // Merge commitments + using Commitment = stdlib::recursion::goblin::MergeRecursiveVerifier_::Commitment; + using SubtableCommitments = + stdlib::recursion::goblin::MergeRecursiveVerifier_::SubtableWitnessCommitments; + using MergeCommitments = stdlib::recursion::goblin::MergeRecursiveVerifier_::WitnessCommitments; /** * @brief A full proof for the IVC scheme containing a Mega proof showing correctness of the hiding circuit (which @@ -180,9 +184,6 @@ class ClientIVC { // Management of linking databus commitments between circuits in the IVC DataBusDepot bus_depot; - // Management of linking merge commitments between circuits in the IVC - MergeVerificationData merge_verification_data; - // Settings related to the use of fixed block sizes for each gate in the execution trace TraceSettings trace_settings; @@ -201,6 +202,7 @@ class ClientIVC { perform_recursive_verification_and_databus_consistency_checks( ClientCircuit& circuit, const StdlibVerifierInputs& verifier_inputs, + MergeCommitments& merge_commitments, const std::shared_ptr& accumulation_recursive_transcript); // Complete the logic of a kernel circuit (e.g. PG/merge recursive verification, databus consistency checks) From 7efc9627d0f1e8302c28e062083f64cc5960c506 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:26:23 +0000 Subject: [PATCH 24/27] Updates --- .../graph_description_goblin.test.cpp | 11 +-- .../client_ivc_recursive_verifier.cpp | 9 +-- .../goblin_recursive_verifier.test.cpp | 70 ++++++++++--------- .../ultra_honk/mega_honk.test.cpp | 8 +-- .../goblin_avm_recursive_verifier.hpp | 8 +-- 5 files changed, 56 insertions(+), 50 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp index 5c8dc262013a..0fffaf172146 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp @@ -24,7 +24,7 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { using Commitment = MergeVerifier::Commitment; using RecursiveCommitment = GoblinRecursiveVerifier::MergeVerifier::Commitment; - using RecursiveMergeVerificationData = GoblinRecursiveVerifier::MergeVerifier::MergeVerificationData; + using MergeCommitments = GoblinRecursiveVerifier::MergeVerifier::WitnessCommitments; static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } @@ -82,15 +82,16 @@ TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic) Builder builder; - // MergeVerificationData - RecursiveMergeVerificationData recursive_merge_verification_data; + // Merge commitments + MergeCommitments recursive_merge_commitments; for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - recursive_merge_verification_data.t_commitments[idx] = + recursive_merge_commitments.t_commitments[idx] = RecursiveCommitment::from_witness(&builder, t_commitments[idx]); } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); + GoblinRecursiveVerifierOutput output = + verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); output.points_accumulator.set_public(); // Construct and verify a proof for the Goblin Recursive Verifier circuit { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp index 81e703740a87..74346ea090d8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp @@ -16,7 +16,7 @@ namespace bb::stdlib::recursion::honk { */ ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const StdlibProof& proof) { - using MergeVerificationData = ClientIVCRecursiveVerifier::GoblinVerifier::MergeVerifier::MergeVerificationData; + using MergeCommitments = ClientIVCRecursiveVerifier::GoblinVerifier::MergeVerifier::WitnessCommitments; std::shared_ptr civc_rec_verifier_transcript(std::make_shared()); // Construct stdlib Mega verification key auto stdlib_mega_vk_and_hash = std::make_shared(*builder, ivc_verification_key.mega); @@ -27,10 +27,11 @@ ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const Stdl // Perform Goblin recursive verification GoblinVerificationKey goblin_verification_key{}; - MergeVerificationData merge_verification_data; - merge_verification_data.set_t_commitments(verifier.key->witness_commitments.get_ecc_op_wires()); + MergeCommitments merge_commitments; + merge_commitments.set_t_commitments(verifier.key->witness_commitments.get_ecc_op_wires()); GoblinVerifier goblin_verifier{ builder.get(), goblin_verification_key, civc_rec_verifier_transcript }; - GoblinRecursiveVerifierOutput output = goblin_verifier.verify(proof.goblin_proof, merge_verification_data); + GoblinRecursiveVerifierOutput output = + goblin_verifier.verify(proof.goblin_proof, merge_commitments, merge_commitments.T_commitments); output.points_accumulator.aggregate(mega_output.points_accumulator); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1396): State tracking in CIVC verifiers return { output }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index c899f5035192..7ac0cc04bc33 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp @@ -22,16 +22,16 @@ class GoblinRecursiveVerifierTests : public testing::Test { using Commitment = MergeVerifier::Commitment; using RecursiveCommitment = GoblinRecursiveVerifier::MergeVerifier::Commitment; - using MergeVerificationData = MergeVerifier::MergeVerificationData; - using RecursiveMergeVerificationData = GoblinRecursiveVerifier::MergeVerifier::MergeVerificationData; + using MergeCommitments = MergeVerifier::WitnessCommitments; + using RecursiveMergeCommitments = GoblinRecursiveVerifier::MergeVerifier::WitnessCommitments; static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } struct ProverOutput { GoblinProof proof; Goblin::VerificationKey verifier_input; - MergeVerificationData merge_verification_data; - RecursiveMergeVerificationData recursive_merge_verification_data; + MergeCommitments merge_commitments; + RecursiveMergeCommitments recursive_merge_commitments; }; /** @@ -57,26 +57,26 @@ class GoblinRecursiveVerifierTests : public testing::Test { GoblinMockCircuits::construct_simple_circuit(builder); // Subtable values and commitments - needed for (Recursive)MergeVerifier - MergeVerificationData merge_verification_data; + MergeCommitments merge_commitments; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - merge_verification_data.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]); + merge_commitments.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]); } - RecursiveMergeVerificationData recursive_merge_verification_data; + RecursiveMergeCommitments recursive_merge_commitments; if (outer_builder != nullptr) { for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - recursive_merge_verification_data.t_commitments[idx] = - RecursiveCommitment::from_witness(outer_builder, merge_verification_data.t_commitments[idx]); + recursive_merge_commitments.t_commitments[idx] = + RecursiveCommitment::from_witness(outer_builder, merge_commitments.t_commitments[idx]); } } // Output is a goblin proof plus ECCVM/Translator verification keys return { goblin_final.prove(), { std::make_shared(), std::make_shared() }, - merge_verification_data, - recursive_merge_verification_data }; + merge_commitments, + recursive_merge_commitments }; } }; @@ -86,11 +86,11 @@ class GoblinRecursiveVerifierTests : public testing::Test { */ TEST_F(GoblinRecursiveVerifierTests, NativeVerification) { - auto [proof, verifier_input, merge_verification_data, _] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_commitments, _] = create_goblin_prover_output(); std::shared_ptr verifier_transcript = std::make_shared(); - EXPECT_TRUE(Goblin::verify(proof, merge_verification_data, verifier_transcript)); + EXPECT_TRUE(Goblin::verify(proof, merge_commitments, merge_commitments.T_commitments, verifier_transcript)); } /** @@ -101,11 +101,12 @@ TEST_F(GoblinRecursiveVerifierTests, Basic) { Builder builder; - auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] = create_goblin_prover_output(&builder); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); + GoblinRecursiveVerifierOutput output = + verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); output.points_accumulator.set_public(); info("Recursive Verifier: num gates = ", builder.num_gates); @@ -135,11 +136,12 @@ TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) -> std::tuple> { Builder builder; - auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] = create_goblin_prover_output(&builder, inner_size); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_verification_data); + GoblinRecursiveVerifierOutput output = + verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); output.points_accumulator.set_public(); info("Recursive Verifier: num gates = ", builder.num_gates); @@ -168,7 +170,7 @@ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) { Builder builder; - auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] = create_goblin_prover_output(&builder); // Tamper with the ECCVM proof @@ -181,7 +183,7 @@ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) GoblinRecursiveVerifier verifier{ &builder, verifier_input }; GoblinRecursiveVerifierOutput goblin_rec_verifier_output = - verifier.verify(proof, recursive_merge_verification_data); + verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); srs::init_file_crs_factory(bb::srs::bb_crs_path()); auto crs_factory = srs::get_grumpkin_crs_factory(); @@ -202,7 +204,7 @@ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) */ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) { - auto [proof, verifier_input, merge_verification_data, _] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_commitments, _] = create_goblin_prover_output(); // Tamper with the Translator proof preamble { @@ -216,15 +218,15 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data; + RecursiveMergeCommitments recursive_merge_commitments; for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - recursive_merge_verification_data.t_commitments[idx] = - RecursiveCommitment::from_witness(&builder, merge_verification_data.t_commitments[idx]); + recursive_merge_commitments.t_commitments[idx] = + RecursiveCommitment::from_witness(&builder, merge_commitments.t_commitments[idx]); } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; [[maybe_unused]] auto goblin_rec_verifier_output = - verifier.verify(tampered_proof, recursive_merge_verification_data); + verifier.verify(tampered_proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); EXPECT_FALSE(CircuitChecker::check(builder)); } // Tamper with the Translator proof non-preamble values @@ -242,15 +244,15 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) Builder builder; - RecursiveMergeVerificationData recursive_merge_verification_data; + RecursiveMergeCommitments recursive_merge_commitments; for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - recursive_merge_verification_data.t_commitments[idx] = - RecursiveCommitment::from_witness(&builder, merge_verification_data.t_commitments[idx]); + recursive_merge_commitments.t_commitments[idx] = + RecursiveCommitment::from_witness(&builder, merge_commitments.t_commitments[idx]); } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; [[maybe_unused]] auto goblin_rec_verifier_output = - verifier.verify(tampered_proof, recursive_merge_verification_data); + verifier.verify(tampered_proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); EXPECT_FALSE(CircuitChecker::check(builder)); } } @@ -263,7 +265,7 @@ TEST_F(GoblinRecursiveVerifierTests, TranslationEvaluationsFailure) { Builder builder; - auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] = create_goblin_prover_output(&builder); // Tamper with the evaluation of `op` witness. The index is computed manually. @@ -273,7 +275,8 @@ TEST_F(GoblinRecursiveVerifierTests, TranslationEvaluationsFailure) proof.eccvm_proof.pre_ipa_proof[op_limb_index] += 1; GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(proof, recursive_merge_verification_data); + [[maybe_unused]] auto goblin_rec_verifier_output = + verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); EXPECT_FALSE(CircuitChecker::check(builder)); } @@ -292,13 +295,13 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure) Builder builder; - auto [proof, verifier_input, merge_verification_data, recursive_merge_verification_data] = + auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] = create_goblin_prover_output(&builder); std::shared_ptr verifier_transcript = std::make_shared(); // Check natively that the proof is correct. - EXPECT_TRUE(Goblin::verify(proof, merge_verification_data, verifier_transcript)); + EXPECT_TRUE(Goblin::verify(proof, merge_commitments, merge_commitments.T_commitments, verifier_transcript)); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1298): // Better recursion testing - create more flexible proof tampering tests. @@ -325,7 +328,8 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure) // Construct and check the Goblin Recursive Verifier circuit GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(proof, recursive_merge_verification_data); + [[maybe_unused]] auto goblin_rec_verifier_output = + verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); EXPECT_FALSE(CircuitChecker::check(builder)); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp index 3840b3798201..8d2e3a3e4864 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp @@ -83,14 +83,14 @@ template class MegaHonkTests : public ::testing::Test { merge_verifier.settings = op_queue->get_current_settings(); auto merge_proof = merge_prover.construct_proof(); - // Construct MergeVerificationData - MergeVerifier::MergeVerificationData merge_verification_data; + // Construct Merge commitments + MergeVerifier::WitnessCommitments merge_commitments; auto t_current = op_queue->construct_current_ultra_ops_subtable_columns(); for (size_t idx = 0; idx < Flavor::NUM_WIRES; idx++) { - merge_verification_data.t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); + merge_commitments.t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); } - bool verified = merge_verifier.verify_proof(merge_proof, merge_verification_data); + bool verified = merge_verifier.verify_proof(merge_proof, merge_commitments, merge_commitments.T_commitments); return verified; } diff --git a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp index 95242d0d603a..372251e4eac1 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp @@ -116,7 +116,7 @@ class AvmGoblinRecursiveVerifier { using MegaRecursiveVerifier = stdlib::recursion::honk::UltraRecursiveVerifier_; using GoblinRecursiveVerifier = stdlib::recursion::honk::GoblinRecursiveVerifier; using GoblinRecursiveVerifierOutput = stdlib::recursion::honk::GoblinRecursiveVerifierOutput; - using MergeVerificationData = GoblinRecursiveVerifier::MergeVerifier::MergeVerificationData; + using MergeCommitments = GoblinRecursiveVerifier::MergeVerifier::WitnessCommitments; using FF = MegaRecursiveFlavor::FF; // Construct hash buffer containing the AVM proof, public inputs, and VK @@ -137,11 +137,11 @@ class AvmGoblinRecursiveVerifier { auto mega_verifier_output = mega_verifier.verify_proof(mega_proof); // Recursively verify the goblin proof\pi_G in the Ultra circuit - MergeVerificationData merge_verification_data; - merge_verification_data.set_t_commitments(mega_verifier.key->witness_commitments.get_ecc_op_wires()); + MergeCommitments merge_commitments; + merge_commitments.set_t_commitments(mega_verifier.key->witness_commitments.get_ecc_op_wires()); GoblinRecursiveVerifier goblin_verifier{ &ultra_builder, inner_output.goblin_vk, transcript }; GoblinRecursiveVerifierOutput goblin_verifier_output = - goblin_verifier.verify(inner_output.goblin_proof, merge_verification_data); + goblin_verifier.verify(inner_output.goblin_proof, merge_commitments, merge_commitments.T_commitments); goblin_verifier_output.points_accumulator.aggregate(mega_verifier_output.points_accumulator); // Validate the consistency of the AVM2 verifier inputs {\pi, pub_inputs, VK}_{AVM2} between the inner (Mega) From 1cfbe261cf47b1e76ae2db43f25f7f9facab29f2 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:16:08 +0000 Subject: [PATCH 25/27] Restore deleted files --- barretenberg/sol/lib/forge-std | 1 + barretenberg/sol/lib/openzeppelin-contracts | 1 + barretenberg/sol/lib/solidity-stringutils | 1 + bb-pilcom/powdr | 1 + l1-contracts/lib/circuits | 1 + l1-contracts/lib/forge-std | 1 + l1-contracts/lib/openzeppelin-contracts | 1 + 7 files changed, 7 insertions(+) create mode 160000 barretenberg/sol/lib/forge-std create mode 160000 barretenberg/sol/lib/openzeppelin-contracts create mode 160000 barretenberg/sol/lib/solidity-stringutils create mode 160000 bb-pilcom/powdr create mode 160000 l1-contracts/lib/circuits create mode 160000 l1-contracts/lib/forge-std create mode 160000 l1-contracts/lib/openzeppelin-contracts diff --git a/barretenberg/sol/lib/forge-std b/barretenberg/sol/lib/forge-std new file mode 160000 index 000000000000..74cfb77e308d --- /dev/null +++ b/barretenberg/sol/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 74cfb77e308dd188d2f58864aaf44963ae6b88b1 diff --git a/barretenberg/sol/lib/openzeppelin-contracts b/barretenberg/sol/lib/openzeppelin-contracts new file mode 160000 index 000000000000..e50c24f5839d --- /dev/null +++ b/barretenberg/sol/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit e50c24f5839db17f46991478384bfda14acfb830 diff --git a/barretenberg/sol/lib/solidity-stringutils b/barretenberg/sol/lib/solidity-stringutils new file mode 160000 index 000000000000..46983c6d9462 --- /dev/null +++ b/barretenberg/sol/lib/solidity-stringutils @@ -0,0 +1 @@ +Subproject commit 46983c6d9462a80229cf0d5bab8ea3b3ee31066c diff --git a/bb-pilcom/powdr b/bb-pilcom/powdr new file mode 160000 index 000000000000..c3006c11819d --- /dev/null +++ b/bb-pilcom/powdr @@ -0,0 +1 @@ +Subproject commit c3006c11819d9b53fb183c9c12a10b83481bb631 diff --git a/l1-contracts/lib/circuits b/l1-contracts/lib/circuits new file mode 160000 index 000000000000..82aac79b466e --- /dev/null +++ b/l1-contracts/lib/circuits @@ -0,0 +1 @@ +Subproject commit 82aac79b466e3430f4946f99919e0866a5ad82f0 diff --git a/l1-contracts/lib/forge-std b/l1-contracts/lib/forge-std new file mode 160000 index 000000000000..0e7097750918 --- /dev/null +++ b/l1-contracts/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 0e7097750918380d84dd3cfdef595bee74dabb70 diff --git a/l1-contracts/lib/openzeppelin-contracts b/l1-contracts/lib/openzeppelin-contracts new file mode 160000 index 000000000000..448efeea6640 --- /dev/null +++ b/l1-contracts/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 448efeea6640bbbc09373f03fbc9c88e280147ba From e24a9271776872057e6d4cb075f2c9012ed420f6 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:26:19 +0000 Subject: [PATCH 26/27] Comments and names --- barretenberg/cpp/src/barretenberg/goblin/goblin.cpp | 4 ++-- barretenberg/cpp/src/barretenberg/goblin/goblin.hpp | 8 ++++---- .../stdlib/merge_verifier/merge_recursive_verifier.hpp | 8 ++++++++ .../cpp/src/barretenberg/ultra_honk/merge_verifier.hpp | 8 ++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp index 08e34d14eac3..01e6af5696df 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp @@ -74,7 +74,7 @@ GoblinProof Goblin::prove() Goblin::PairingPoints Goblin::recursively_verify_merge( MegaBuilder& builder, - const RecursiveMergeSubtableCommitments& subtable_commitments, + const RecursiveSubtableCommitments& subtable_commitments, std::array& merged_table_commitment, const std::shared_ptr& transcript) { @@ -93,7 +93,7 @@ Goblin::PairingPoints Goblin::recursively_verify_merge( } bool Goblin::verify(const GoblinProof& proof, - const MergeSubtableCommitments& subtable_commitments, + const SubtableCommitments& subtable_commitments, std::array& merged_table_commitment, const std::shared_ptr& transcript) { diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 22078d55d7e6..e9af2a069b00 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -38,8 +38,8 @@ class Goblin { using TranslatorVerificationKey = TranslatorFlavor::VerificationKey; using MergeRecursiveVerifier = stdlib::recursion::goblin::MergeRecursiveVerifier_; using PairingPoints = MergeRecursiveVerifier::PairingPoints; - using MergeSubtableCommitments = MergeVerifier::SubtableWitnessCommitments; - using RecursiveMergeSubtableCommitments = MergeRecursiveVerifier::SubtableWitnessCommitments; + using SubtableCommitments = MergeVerifier::SubtableWitnessCommitments; + using RecursiveSubtableCommitments = MergeRecursiveVerifier::SubtableWitnessCommitments; using RecursiveCommitment = MergeRecursiveVerifier::Commitment; using RecursiveTranscript = bb::BaseTranscript>; @@ -102,7 +102,7 @@ class Goblin { */ PairingPoints recursively_verify_merge( MegaBuilder& builder, - const RecursiveMergeSubtableCommitments& subtable_commitments, + const RecursiveSubtableCommitments& subtable_commitments, std::array& merged_table_commitment, const std::shared_ptr& transcript); @@ -119,7 +119,7 @@ class Goblin { * @return false */ static bool verify(const GoblinProof& proof, - const MergeSubtableCommitments& subtable_commitments, + const SubtableCommitments& subtable_commitments, std::array& merged_table_commitment, const std::shared_ptr& transcript); }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp index ceb380859a3e..e9a4262bd642 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp @@ -31,6 +31,10 @@ template class MergeRecursiveVerifier_ { // MegaCircuitBuilder static constexpr size_t NUM_WIRES = MegaExecutionTraceBlocks::NUM_WIRES; + /** + * @brief Commitments to the subtable t_j on which the Merge verifier operates + * + */ class SubtableWitnessCommitments { public: std::array t_commitments; @@ -51,6 +55,10 @@ template class MergeRecursiveVerifier_ { } }; + /** + * @brief Commitments used by the Merge verifier during the protocol + * + */ class WitnessCommitments : public SubtableWitnessCommitments { public: std::array T_commitments; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index c64baa2907da..1c043816c417 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -36,6 +36,10 @@ class MergeVerifier { std::shared_ptr transcript; MergeSettings settings; + /** + * @brief Commitments to the subtable t_j on which the Merge verifier operates + * + */ class SubtableWitnessCommitments { public: std::array t_commitments; @@ -56,6 +60,10 @@ class MergeVerifier { } }; + /** + * @brief Commitments used by the Merge verifier during the protocol + * + */ class WitnessCommitments : public SubtableWitnessCommitments { public: std::array T_commitments; From 6c6b15969b0025b5f47f160087465f7e0cf37f0b Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Thu, 17 Jul 2025 15:53:44 +0000 Subject: [PATCH 27/27] Address comments --- barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 4f6ade9f07c4..461859cf529c 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -79,9 +79,6 @@ class ClientIVC { using StdlibProof = stdlib::Proof; // Merge commitments - using Commitment = stdlib::recursion::goblin::MergeRecursiveVerifier_::Commitment; - using SubtableCommitments = - stdlib::recursion::goblin::MergeRecursiveVerifier_::SubtableWitnessCommitments; using MergeCommitments = stdlib::recursion::goblin::MergeRecursiveVerifier_::WitnessCommitments; /**