Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c0153a5
[empty] Start merge-train. Choo choo.
Jul 15, 2025
dfdc1b5
Merge branch 'next' into merge-train/barretenberg
Jul 15, 2025
3efb90e
Merge branch 'next' into merge-train/barretenberg
Jul 15, 2025
f447c5a
Merge branch 'next' into merge-train/barretenberg
Jul 15, 2025
0772339
feat!: Merge with degree check (#15562)
federicobarbacovi Jul 15, 2025
d7f0efe
Add merge verification data class
federicobarbacovi Jul 15, 2025
60e0109
Update tests
federicobarbacovi Jul 15, 2025
b500f22
Add setter method
federicobarbacovi Jul 15, 2025
d79ef31
Add setter method
federicobarbacovi Jul 15, 2025
759432d
Update goblin and client IVC interfaces
federicobarbacovi Jul 15, 2025
1e70c88
Update goblin rec verifier interface
federicobarbacovi Jul 15, 2025
082d155
Update goblin AVM rec verifier interface
federicobarbacovi Jul 15, 2025
b53006f
Update rec civc interface
federicobarbacovi Jul 15, 2025
9e9a29f
Comments
federicobarbacovi Jul 15, 2025
5fa5b98
Update tests
federicobarbacovi Jul 15, 2025
cd77300
Cleanup
federicobarbacovi Jul 15, 2025
de1b171
Fix tests
federicobarbacovi Jul 15, 2025
cf6498f
Further fixes
federicobarbacovi Jul 15, 2025
98c1c51
Add reset method for MergeVerificationData
federicobarbacovi Jul 16, 2025
a418fbc
Improve tests
federicobarbacovi Jul 16, 2025
9f27abb
[empty] Start merge-train. Choo choo.
Jul 16, 2025
6893736
Merge branch 'next' into merge-train/barretenberg
Jul 16, 2025
6cd32ca
Merge branch 'next' into merge-train/barretenberg
Jul 16, 2025
29c5a1f
Merge branch 'next' into merge-train/barretenberg
Jul 16, 2025
921cd03
Merge branch 'next' into merge-train/barretenberg
Jul 16, 2025
0968cf0
Merge branch 'next' into merge-train/barretenberg
Jul 16, 2025
de7c071
Merge branch 'next' into merge-train/barretenberg
Jul 16, 2025
8456fac
Merge branch 'next' into merge-train/barretenberg
Jul 16, 2025
ad3dea5
Merge branch 'next' into merge-train/barretenberg
Jul 16, 2025
7ea4056
Merge branch 'next' into merge-train/barretenberg
Jul 17, 2025
f62ee83
Update data structure
federicobarbacovi Jul 17, 2025
9921f2d
Merge remote-tracking branch 'origin/merge-train/barretenberg' into f…
federicobarbacovi Jul 17, 2025
68dfa18
Update comments
federicobarbacovi Jul 17, 2025
8b71509
Merge branch 'next' into merge-train/barretenberg
Jul 17, 2025
b59793a
Update goblin interface
federicobarbacovi Jul 17, 2025
f883938
Update rec goblin interface
federicobarbacovi Jul 17, 2025
4dc6bf9
Update ClientIVC interface
federicobarbacovi Jul 17, 2025
7efc962
Updates
federicobarbacovi Jul 17, 2025
9ac2ef8
Merge branch 'next' into merge-train/barretenberg
Jul 17, 2025
90dfe1f
Merge remote-tracking branch 'origin/merge-train/barretenberg' into f…
federicobarbacovi Jul 17, 2025
1cfbe26
Restore deleted files
federicobarbacovi Jul 17, 2025
e24a927
Comments and names
federicobarbacovi Jul 17, 2025
6c6b159
Address comments
federicobarbacovi Jul 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,22 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test {

using Commitment = MergeVerifier::Commitment;
using RecursiveCommitment = GoblinRecursiveVerifier::MergeVerifier::Commitment;
using MergeCommitments = 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;
RefArray<Commitment, MegaFlavor::NUM_WIRES> t_commitments;
std::array<Commitment, MegaFlavor::NUM_WIRES> t_commitments;
};

/**
* @brief Create a goblin proof and the VM verification keys needed by the goblin recursive verifier
*
* @return ProverOutput
*/
static ProverOutput create_goblin_prover_output(std::array<Commitment, MegaFlavor::NUM_WIRES>& 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
Expand All @@ -58,41 +58,18 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test {
GoblinMockCircuits::construct_simple_circuit(builder);

// Subtable values and commitments - needed for (Recursive)MergeVerifier
std::array<Commitment, MegaFlavor::NUM_WIRES> t_commitments;
auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns();
std::array<Commitment*, MegaFlavor::NUM_WIRES> ptr_t_commitments;
CommitmentKey<curve::BN254> 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];
t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]);
}

RefArray<Commitment, MegaFlavor::NUM_WIRES> t_commitments(ptr_t_commitments);

// Output is a goblin proof plus ECCVM/Translator verification keys
return { goblin_final.prove(),
{ std::make_shared<ECCVMVK>(), std::make_shared<TranslatorVK>() },
t_commitments };
}

/**
* @brief Transform native subtable commitments into recursive subtable commitments
*
*/
static RefArray<RecursiveCommitment, MegaFlavor::NUM_WIRES> convert_native_t_commitments_to_stdlib(
Builder* builder,
std::array<RecursiveCommitment, MegaFlavor::NUM_WIRES> t_commitments_rec_val,
const std::array<Commitment, MegaFlavor::NUM_WIRES>& t_commitments_val)
{
std::array<RecursiveCommitment*, MegaFlavor::NUM_WIRES> 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<RecursiveCommitment, MegaFlavor::NUM_WIRES> t_commitments_rec(ptr_t_commitments_rec);

return t_commitments_rec;
}
};

/**
Expand All @@ -101,16 +78,20 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test {
*/
TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic)
{
std::array<Commitment, MegaFlavor::NUM_WIRES> t_commitments_val;
auto [proof, verifier_input, _] = create_goblin_prover_output(t_commitments_val);
auto [proof, verifier_input, t_commitments] = create_goblin_prover_output();

Builder builder;

std::array<RecursiveCommitment, MegaFlavor::NUM_WIRES> t_commitments_rec_val;
auto t_commitments = convert_native_t_commitments_to_stdlib(&builder, t_commitments_rec_val, t_commitments_val);
// Merge commitments
MergeCommitments recursive_merge_commitments;
for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
recursive_merge_commitments.t_commitments[idx] =
RecursiveCommitment::from_witness(&builder, t_commitments[idx]);
}

GoblinRecursiveVerifier verifier{ &builder, verifier_input };
GoblinRecursiveVerifierOutput output = verifier.verify(proof, t_commitments);
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
{
Expand Down
34 changes: 27 additions & 7 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<RecursiveTranscript>& accumulation_recursive_transcript)
{
// Store the decider vk for the incoming circuit; its data is used in the databus consistency checks below
Expand Down Expand Up @@ -131,9 +135,12 @@ ClientIVC::PairingPoints ClientIVC::perform_recursive_verification_and_databus_c
}
}

// Extract the commitments to the subtable corresponding to the incoming circuit
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, decider_vk->witness_commitments.get_ecc_op_wires(), accumulation_recursive_transcript);
circuit, merge_commitments, merge_commitments.T_commitments, accumulation_recursive_transcript);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate what you've done here but I do still find it to be a bit funny because we're passing in the same data (T_commitments) twice, albeit as a const ref in one case. It does make it slightly clearer because I know exactly what data might be altered.

Is it eventually the case that we'll always pass in {t, T_prev} and always return T? If so it seems pretty natural to have those inputs passed in to the method (as a const) and have the output passed out (making the output {pairing_points, T}. FWIW I'm perfectly happy to merge this as it is and continue to iterate. I think it will become clearer what to do as this work progresses

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is always going to be the case that we pass in {t, T_prev}, and return T. I thought it would be better to have them all in one structure (mostly for ClientIVC), but maybe you're right and it's better to simply return T. We can discuss in next iterations.


PairingPoints nested_pairing_points; // to be extracted from public inputs of app or kernel proof just verified

Expand Down Expand Up @@ -180,6 +187,9 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit)
// .., A_{i, n} (app)
auto accumulation_recursive_transcript = std::make_shared<RecursiveTranscript>();

// 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);
Expand All @@ -190,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.
Expand Down Expand Up @@ -381,9 +391,13 @@ std::shared_ptr<ClientIVC::DeciderZKProvingKey> 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
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, tail_kernel_decider_vk->witness_commitments.get_ecc_op_wires(), pg_merge_transcript);
builder, merge_commitments, merge_commitments.T_commitments, pg_merge_transcript);
points_accumulator.aggregate(kernel_input.pairing_inputs);

// Perform recursive decider verification
Expand Down Expand Up @@ -440,13 +454,19 @@ 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<Goblin::Transcript> civc_verifier_transcript = std::make_shared<Goblin::Transcript>();
// 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::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, verifer.verification_key->witness_commitments.get_ecc_op_wires(), civc_verifier_transcript);
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.
return goblin_verified && mega_verified;
}
Expand Down
4 changes: 4 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class ClientIVC {
using AppIO = bb::stdlib::recursion::honk::AppIO;
using StdlibProof = stdlib::Proof<ClientCircuit>;

// Merge commitments
using MergeCommitments = stdlib::recursion::goblin::MergeRecursiveVerifier_<ClientCircuit>::WitnessCommitments;

/**
* @brief A full proof for the IVC scheme containing a Mega proof showing correctness of the hiding circuit (which
* recursive verified the last folding and decider proof) and a Goblin proof (translator VM, ECCVM and last merge
Expand Down Expand Up @@ -196,6 +199,7 @@ class ClientIVC {
perform_recursive_verification_and_databus_consistency_checks(
ClientCircuit& circuit,
const StdlibVerifierInputs& verifier_inputs,
MergeCommitments& merge_commitments,
const std::shared_ptr<RecursiveTranscript>& accumulation_recursive_transcript);

// Complete the logic of a kernel circuit (e.g. PG/merge recursive verification, databus consistency checks)
Expand Down
13 changes: 8 additions & 5 deletions barretenberg/cpp/src/barretenberg/goblin/goblin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ GoblinProof Goblin::prove()

Goblin::PairingPoints Goblin::recursively_verify_merge(
MegaBuilder& builder,
const RefArray<MergeRecursiveVerifier::Commitment, MegaFlavor::NUM_WIRES>& t_commitments,
const RecursiveSubtableCommitments& subtable_commitments,
std::array<RecursiveCommitment, MegaFlavor::NUM_WIRES>& merged_table_commitment,
const std::shared_ptr<RecursiveTranscript>& transcript)
{
ASSERT(!merge_verification_queue.empty());
Expand All @@ -83,19 +84,21 @@ Goblin::PairingPoints Goblin::recursively_verify_merge(
const stdlib::Proof<MegaBuilder> 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, subtable_commitments, merged_table_commitment);

merge_verification_queue.pop_front(); // remove the processed proof from the queue

return pairing_points;
}

bool Goblin::verify(const GoblinProof& proof,
const RefArray<MergeVerifier::Commitment, MegaFlavor::NUM_WIRES>& t_commitments,
const SubtableCommitments& subtable_commitments,
std::array<Commitment, MegaFlavor::NUM_WIRES>& merged_table_commitment,
const std::shared_ptr<Transcript>& 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, subtable_commitments, merged_table_commitment);

ECCVMVerifier eccvm_verifier(transcript);
bool eccvm_verified = eccvm_verifier.verify_proof(proof.eccvm_proof);
Expand All @@ -111,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_verifier.T_commitments);
translator_verifier.verify_consistency_with_final_merge(merged_table_commitment);

vinfo("merge verified?: ", merge_verified);
vinfo("eccvm verified?: ", eccvm_verified);
Expand Down
17 changes: 13 additions & 4 deletions barretenberg/cpp/src/barretenberg/goblin/goblin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class Goblin {
using TranslatorVerificationKey = TranslatorFlavor::VerificationKey;
using MergeRecursiveVerifier = stdlib::recursion::goblin::MergeRecursiveVerifier_<MegaBuilder>;
using PairingPoints = MergeRecursiveVerifier::PairingPoints;
using SubtableCommitments = MergeVerifier::SubtableWitnessCommitments;
using RecursiveSubtableCommitments = MergeRecursiveVerifier::SubtableWitnessCommitments;
using RecursiveCommitment = MergeRecursiveVerifier::Commitment;
using RecursiveTranscript = bb::BaseTranscript<bb::stdlib::recursion::honk::StdlibTranscriptParams<MegaBuilder>>;

std::shared_ptr<OpQueue> op_queue = std::make_shared<OpQueue>();
Expand Down Expand Up @@ -91,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 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 The transcript to be passed to the MergeRecursiveVerifier.
* @return PairingPoints
*/
PairingPoints recursively_verify_merge(
MegaBuilder& builder,
const RefArray<MergeRecursiveVerifier::Commitment, MegaFlavor::NUM_WIRES>& t_commitments,
const RecursiveSubtableCommitments& subtable_commitments,
std::array<RecursiveCommitment, MegaFlavor::NUM_WIRES>& merged_table_commitment,
const std::shared_ptr<RecursiveTranscript>& 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,
const RefArray<MergeVerifier::Commitment, MegaFlavor::NUM_WIRES>& t_commitments,
const SubtableCommitments& subtable_commitments,
std::array<Commitment, MegaFlavor::NUM_WIRES>& merged_table_commitment,
const std::shared_ptr<Transcript>& transcript);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace bb::stdlib::recursion::honk {
*/
ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const StdlibProof& proof)
{
using MergeCommitments = ClientIVCRecursiveVerifier::GoblinVerifier::MergeVerifier::WitnessCommitments;
std::shared_ptr<Transcript> civc_rec_verifier_transcript(std::make_shared<Transcript>());
// Construct stdlib Mega verification key
auto stdlib_mega_vk_and_hash = std::make_shared<RecursiveVKAndHash>(*builder, ivc_verification_key.mega);
Expand All @@ -26,9 +27,11 @@ ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const Stdl

// Perform Goblin recursive verification
GoblinVerificationKey goblin_verification_key{};
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, verifier.key->witness_commitments.get_ecc_op_wires());
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 };
Expand Down
Loading
Loading