Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e0ecf10
fix: Origin Tags edgecase (#16921)
Rumata888 Sep 10, 2025
7308d27
Merge branch 'next' into merge-train/barretenberg
Sep 10, 2025
0275e5f
chore: cycle group cleanup #2 (#16876)
ledwards2225 Sep 10, 2025
22602e5
chore: civc tidy 3 (#16671)
ledwards2225 Sep 10, 2025
1c6e3d7
Merge branch 'next' into merge-train/barretenberg
Sep 10, 2025
c715bc0
Merge branch 'next' into merge-train/barretenberg
Sep 10, 2025
2e00bce
Merge branch 'next' into merge-train/barretenberg
Sep 10, 2025
6118e1b
Merge branch 'next' into merge-train/barretenberg
Sep 10, 2025
e547996
refactor(bb): optimize batch_mul_with_endomorphism (#16905)
ludamad Sep 10, 2025
9cdbace
Merge branch 'next' into merge-train/barretenberg
Sep 10, 2025
33da0be
feat: check op queue wires are zero past minicircuit in Translator (#…
Sep 10, 2025
b17134d
Merge branch 'next' into merge-train/barretenberg
Sep 10, 2025
4c1b16f
Merge branch 'next' into merge-train/barretenberg
Sep 10, 2025
20ad05d
Merge branch 'next' into merge-train/barretenberg
Sep 11, 2025
e7bbbf5
Merge branch 'next' into merge-train/barretenberg
Sep 11, 2025
4d85947
feat: Add CPU scaling benchmark script for remote execution (#16918)
johnathan79717 Sep 11, 2025
47fc343
fix: Add free witness tag to field constructor (#16827)
Rumata888 Sep 11, 2025
bd71547
Merge branch 'next' into merge-train/barretenberg
Sep 11, 2025
d38c9ea
Merge branch 'next' into merge-train/barretenberg
Sep 11, 2025
d7050ac
Merge branch 'next' into merge-train/barretenberg
Sep 11, 2025
deba98e
fix(bb): darwin build (#16957)
ludamad Sep 11, 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
3 changes: 2 additions & 1 deletion barretenberg/cpp/src/barretenberg/api/api_client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ bool ClientIVCAPI::prove_and_verify(const std::filesystem::path& input_path)
std::shared_ptr<ClientIVC> ivc = steps.accumulate();
// Construct the hiding kernel as the final step of the IVC

const bool verified = ivc->prove_and_verify();
auto proof = ivc->prove();
const bool verified = ClientIVC::verify(proof, ivc->get_vk());
return verified;
}

Expand Down
3 changes: 2 additions & 1 deletion barretenberg/cpp/src/barretenberg/bbapi/bbapi_client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ ClientIvcProve::Response ClientIvcProve::execute(BBApiRequest& request) &&
// We verify this proof. Another bb call to verify has some overhead of loading VK/proof/SRS,
// and it is mysterious if this transaction fails later in the lifecycle.
info("ClientIvcProve - verifying the generated proof as a sanity check");
if (!request.ivc_in_progress->verify(proof)) {
ClientIVC::VerificationKey vk = request.ivc_in_progress->get_vk();
if (!ClientIVC::verify(proof, vk)) {
throw_or_abort("Failed to verify the generated proof!");
}

Expand Down
89 changes: 24 additions & 65 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,6 @@ ClientIVC::perform_recursive_verification_and_databus_consistency_checks(
}
case QUEUE_TYPE::PG:
case QUEUE_TYPE::PG_TAIL: {
BB_ASSERT_NEQ(input_verifier_accumulator, nullptr);

output_verifier_accumulator = perform_pg_recursive_verification(circuit,
input_verifier_accumulator,
verifier_instance,
Expand All @@ -184,18 +182,10 @@ ClientIVC::perform_recursive_verification_and_databus_consistency_checks(
break;
}
case QUEUE_TYPE::PG_FINAL: {
BB_ASSERT_NEQ(input_verifier_accumulator, nullptr);
BB_ASSERT_EQ(stdlib_verification_queue.size(), size_t(1));

hide_op_queue_accumulation_result(circuit);

// Propagate the public inputs of the tail kernel by converting them to public inputs of the hiding circuit.
auto num_public_inputs = static_cast<size_t>(honk_vk->num_public_inputs);
num_public_inputs -= KernelIO::PUBLIC_INPUTS_SIZE; // exclude fixed kernel_io public inputs
for (size_t i = 0; i < num_public_inputs; i++) {
verifier_inputs.proof[i].set_public();
}

auto final_verifier_accumulator = perform_pg_recursive_verification(circuit,
input_verifier_accumulator,
verifier_instance,
Expand Down Expand Up @@ -245,7 +235,7 @@ ClientIVC::perform_recursive_verification_and_databus_consistency_checks(
kernel_input.output_pg_accum_hash.assert_equal(*prev_accum_hash);

if (!is_hiding_kernel) {
// The hiding kernel has no return data but uses the traditional public-inputs mechanism
// The hiding kernel has no return data; it uses the traditional public-inputs mechanism
bus_depot.set_kernel_return_data_commitment(witness_commitments.return_data);
}
} else {
Expand Down Expand Up @@ -384,7 +374,7 @@ HonkProof ClientIVC::construct_oink_proof(const std::shared_ptr<DeciderProvingKe
proving_key->gate_challenges =
prover_accumulation_transcript->template get_powers_of_challenge<FF>("gate_challenge", CONST_PG_LOG_N);

fold_output.accumulator = proving_key; // initialize the prover accum with the completed key
prover_accumulator = proving_key; // initialize the prover accum with the completed key

HonkProof oink_proof = oink_prover.export_proof();
vinfo("oink proof constructed");
Expand All @@ -406,13 +396,14 @@ HonkProof ClientIVC::construct_pg_proof(const std::shared_ptr<DeciderProvingKey>
info("Accumulator hash in PG prover: ", accum_hash);
}
auto verifier_instance = std::make_shared<DeciderVerificationKey_<Flavor>>(honk_vk);
FoldingProver folding_prover({ fold_output.accumulator, proving_key },
FoldingProver folding_prover({ prover_accumulator, proving_key },
{ native_verifier_accum, verifier_instance },
transcript,
trace_usage_tracker);
fold_output = folding_prover.prove();
auto output = folding_prover.prove();
prover_accumulator = output.accumulator; // update the prover accumulator
vinfo("pg proof constructed");
return fold_output.proof;
return output.proof;
}

/**
Expand Down Expand Up @@ -472,8 +463,6 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer
proving_key->commitment_key = bn254_commitment_key;
trace_usage_tracker.update(circuit);

honk_vk = precomputed_vk;

// We're accumulating a kernel if the verification queue is empty (because the kernel circuit contains recursive
// verifiers for all the entries previously present in the verification queue) and if it's not the first accumulate
// call (which will always be for an app circuit).
Expand All @@ -495,22 +484,22 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer
case QUEUE_TYPE::OINK:
vinfo("Accumulating first app circuit with OINK");
BB_ASSERT_EQ(is_kernel, false, "First circuit accumulated must always be an app");
proof = construct_oink_proof(proving_key, honk_vk, prover_accumulation_transcript);
proof = construct_oink_proof(proving_key, precomputed_vk, prover_accumulation_transcript);
break;
case QUEUE_TYPE::PG:
case QUEUE_TYPE::PG_TAIL:
proof = construct_pg_proof(proving_key, honk_vk, prover_accumulation_transcript, is_kernel);
proof = construct_pg_proof(proving_key, precomputed_vk, prover_accumulation_transcript, is_kernel);
break;
case QUEUE_TYPE::PG_FINAL:
proof = construct_pg_proof(proving_key, honk_vk, prover_accumulation_transcript, is_kernel);
proof = construct_pg_proof(proving_key, precomputed_vk, prover_accumulation_transcript, is_kernel);
decider_proof = construct_decider_proof(prover_accumulation_transcript);
break;
case QUEUE_TYPE::MEGA:
proof = construct_mega_proof_for_hiding_kernel(circuit);
proof = construct_honk_proof_for_hiding_kernel(circuit, precomputed_vk);
break;
}

VerifierInputs queue_entry{ std::move(proof), honk_vk, queue_type, is_kernel };
VerifierInputs queue_entry{ std::move(proof), precomputed_vk, queue_type, is_kernel };
verification_queue.push_back(queue_entry);

// Update native verifier accumulator and construct merge proof (excluded for hiding kernel since PG terminates with
Expand Down Expand Up @@ -612,14 +601,14 @@ void ClientIVC::hide_op_queue_content_in_hiding(ClientCircuit& circuit)
* @brief Construct a zero-knowledge proof for the hiding circuit, which recursively verifies the last folding,
* merge and decider proof.
*/
HonkProof ClientIVC::construct_mega_proof_for_hiding_kernel(ClientCircuit& circuit)
HonkProof ClientIVC::construct_honk_proof_for_hiding_kernel(
ClientCircuit& circuit, const std::shared_ptr<MegaVerificationKey>& verification_key)
{
// Note: a structured trace is not used for the hiding kernel
auto hiding_decider_pk = std::make_shared<DeciderZKProvingKey>(circuit, TraceSettings(), bn254_commitment_key);
honk_vk = std::make_shared<MegaZKVerificationKey>(hiding_decider_pk->get_precomputed());
auto& hiding_circuit_vk = honk_vk;

// Hiding circuit is proven by a MegaZKProver
MegaZKProver prover(hiding_decider_pk, hiding_circuit_vk, transcript);
MegaZKProver prover(hiding_decider_pk, verification_key, transcript);
HonkProof proof = prover.construct_proof();

return proof;
Expand All @@ -633,7 +622,7 @@ HonkProof ClientIVC::construct_mega_proof_for_hiding_kernel(ClientCircuit& circu
ClientIVC::Proof ClientIVC::prove()
{
// deallocate the protogalaxy accumulator
fold_output.accumulator = nullptr;
prover_accumulator = nullptr;
auto mega_proof = verification_queue.front().proof;

// A transcript is shared between the Hiding circuit prover and the Goblin prover
Expand Down Expand Up @@ -669,17 +658,6 @@ bool ClientIVC::verify(const Proof& proof, const VerificationKey& vk)
return goblin_verified && mega_verified;
}

/**
* @brief Verify a full proof of the IVC
*
* @param proof
* @return bool
*/
bool ClientIVC::verify(const Proof& proof) const
{
return verify(proof, get_vk());
}

/**
* @brief Internal method for constructing a decider proof
*
Expand All @@ -688,36 +666,12 @@ bool ClientIVC::verify(const Proof& proof) const
HonkProof ClientIVC::construct_decider_proof(const std::shared_ptr<Transcript>& transcript)
{
vinfo("prove decider...");
fold_output.accumulator->commitment_key = bn254_commitment_key;
MegaDeciderProver decider_prover(fold_output.accumulator, transcript);
prover_accumulator->commitment_key = bn254_commitment_key;
MegaDeciderProver decider_prover(prover_accumulator, transcript);
decider_prover.construct_proof();
return decider_prover.export_proof();
}

/**
* @brief Construct and verify a proof for the IVC
* @note Use of this method only makes sense when the prover and verifier are the same entity, e.g. in
* development/testing.
*
*/
bool ClientIVC::prove_and_verify()
{
auto start = std::chrono::steady_clock::now();
const auto proof = prove();
auto end = std::chrono::steady_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
vinfo("time to call ClientIVC::prove: ", diff.count(), " ms.");

start = end;
const bool verified = verify(proof);
end = std::chrono::steady_clock::now();

diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
vinfo("time to verify ClientIVC proof: ", diff.count(), " ms.");

return verified;
}

// Proof methods
size_t ClientIVC::Proof::size() const
{
Expand Down Expand Up @@ -842,7 +796,12 @@ ClientIVC::Proof ClientIVC::Proof::from_file_msgpack(const std::string& filename
// VerificationKey construction
ClientIVC::VerificationKey ClientIVC::get_vk() const
{
return { honk_vk, std::make_shared<ECCVMVerificationKey>(), std::make_shared<TranslatorVerificationKey>() };
BB_ASSERT_EQ(verification_queue.size(), 1UL);
BB_ASSERT_EQ(verification_queue.front().type == QUEUE_TYPE::MEGA, true);
auto verification_key = verification_queue.front().honk_vk;
return { verification_key,
std::make_shared<ECCVMVerificationKey>(),
std::make_shared<TranslatorVerificationKey>() };
}

void ClientIVC::update_native_verifier_accumulator(const VerifierInputs& queue_entry,
Expand Down
17 changes: 6 additions & 11 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ class ClientIVC {
ExecutionTraceUsageTracker trace_usage_tracker;

private:
using ProverFoldOutput = FoldingResult<Flavor>;

// Transcript for CIVC prover (shared between Hiding circuit, Merge, ECCVM, and Translator)
std::shared_ptr<Transcript> transcript = std::make_shared<Transcript>();

Expand All @@ -269,14 +267,13 @@ class ClientIVC {
public:
size_t num_circuits_accumulated = 0; // number of circuits accumulated so far

ProverFoldOutput fold_output; // prover accumulator and fold proof
HonkProof decider_proof; // decider proof to be verified in the hiding circuit
std::shared_ptr<DeciderProvingKey> prover_accumulator; // current PG prover accumulator instance
HonkProof decider_proof; // decider proof to be verified in the hiding circuit

std::shared_ptr<DeciderVerificationKey>
recursive_verifier_native_accum; // native verifier accumulator used in recursive folding
std::shared_ptr<DeciderVerificationKey>
native_verifier_accum; // native verifier accumulator used in prover folding
std::shared_ptr<MegaVerificationKey> honk_vk; // honk vk to be completed and folded into the accumulator
native_verifier_accum; // native verifier accumulator used in prover folding

// Set of tuples {proof, verification_key, type (Oink/PG)} to be recursively verified
VerificationQueue verification_queue;
Expand Down Expand Up @@ -327,14 +324,9 @@ class ClientIVC {
static void hide_op_queue_accumulation_result(ClientCircuit& circuit);
static void hide_op_queue_content_in_tail(ClientCircuit& circuit);
static void hide_op_queue_content_in_hiding(ClientCircuit& circuit);
HonkProof construct_mega_proof_for_hiding_kernel(ClientCircuit& circuit);

static bool verify(const Proof& proof, const VerificationKey& vk);

bool verify(const Proof& proof) const;

bool prove_and_verify();

HonkProof construct_decider_proof(const std::shared_ptr<Transcript>& transcript);

VerificationKey get_vk() const;
Expand All @@ -358,6 +350,9 @@ class ClientIVC {
const std::shared_ptr<Transcript>& transcript,
bool is_kernel);

HonkProof construct_honk_proof_for_hiding_kernel(ClientCircuit& circuit,
const std::shared_ptr<MegaVerificationKey>& verification_key);

QUEUE_TYPE get_queue_type() const;

static std::shared_ptr<RecursiveDeciderVerificationKey> perform_oink_recursive_verification(
Expand Down
24 changes: 13 additions & 11 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ class ClientIVCTests : public ::testing::Test {
ClientIVC ivc{ num_circuits, trace_settings };

for (size_t j = 0; j < num_circuits; ++j) {
// Use default test settings for the mock hiding kernel since it's size must always be consistent
if (j == num_circuits - 1) {
settings = TestSettings{};
}
circuit_producer.construct_and_accumulate_next_circuit(ivc, settings);
}
return { ivc.prove(), ivc.get_vk() };
Expand Down Expand Up @@ -112,7 +108,8 @@ TEST_F(ClientIVCTests, BadProofFailure)
for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
circuit_producer.construct_and_accumulate_next_circuit(ivc, settings);
}
EXPECT_TRUE(ivc.prove_and_verify());
auto proof = ivc.prove();
EXPECT_TRUE(ClientIVC::verify(proof, ivc.get_vk()));
}

// The IVC throws an exception if the FIRST fold proof is tampered with
Expand All @@ -139,7 +136,8 @@ TEST_F(ClientIVCTests, BadProofFailure)
num_public_inputs); // tamper with first proof
}
}
EXPECT_FALSE(ivc.prove_and_verify());
auto proof = ivc.prove();
EXPECT_FALSE(ClientIVC::verify(proof, ivc.get_vk()));
}

// The IVC fails if the SECOND fold proof is tampered with
Expand All @@ -160,7 +158,8 @@ TEST_F(ClientIVCTests, BadProofFailure)
circuit.num_public_inputs()); // tamper with second proof
}
}
EXPECT_FALSE(ivc.prove_and_verify());
auto proof = ivc.prove();
EXPECT_FALSE(ClientIVC::verify(proof, ivc.get_vk()));
}

EXPECT_TRUE(true);
Expand Down Expand Up @@ -313,7 +312,8 @@ TEST_F(ClientIVCTests, StructuredTraceOverflow)
log2_num_gates += 1;
}

EXPECT_TRUE(ivc.prove_and_verify());
auto proof = ivc.prove();
EXPECT_TRUE(ClientIVC::verify(proof, ivc.get_vk()));
};

/**
Expand Down Expand Up @@ -348,8 +348,9 @@ TEST_F(ClientIVCTests, DynamicTraceOverflow)
ivc, { .log2_num_gates = test.log2_num_arith_gates[idx] });
}

EXPECT_EQ(check_accumulator_target_sum_manual(ivc.fold_output.accumulator), true);
EXPECT_TRUE(ivc.prove_and_verify());
EXPECT_EQ(check_accumulator_target_sum_manual(ivc.prover_accumulator), true);
auto proof = ivc.prove();
EXPECT_TRUE(ClientIVC::verify(proof, ivc.get_vk()));
}
}

Expand Down Expand Up @@ -421,5 +422,6 @@ TEST_F(ClientIVCTests, DatabusFailure)
ivc.accumulate(circuit, vk);
}

EXPECT_FALSE(ivc.prove_and_verify());
auto proof = ivc.prove();
EXPECT_FALSE(ClientIVC::verify(proof, ivc.get_vk()));
};
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ class PrivateFunctionExecutionMockCircuitProducer {
std::pair<ClientCircuit, std::shared_ptr<VerificationKey>> create_next_circuit_and_vk(ClientIVC& ivc,
TestSettings settings = {})
{
// If this is a mock hiding kernel, remove the settings and use a default (non-structured) trace
if (ivc.num_circuits_accumulated == ivc.get_num_circuits() - 1) {
settings = TestSettings{};
ivc.trace_settings = TraceSettings{};
}
auto circuit = create_next_circuit(ivc, settings.log2_num_gates, settings.num_public_inputs);
return { circuit, get_verification_key(circuit, ivc.trace_settings) };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ TEST_F(MockKernelTest, PinFoldingKernelSizes)
auto [circuit, vk] = circuit_producer.create_next_circuit_and_vk(ivc);

ivc.accumulate(circuit, vk);
EXPECT_TRUE(circuit.blocks.has_overflow); // trace overflow mechanism should be triggered
// Expect trace overflow for all but the hiding kernel (final circuit)
if (idx < NUM_CIRCUITS - 1) {
EXPECT_TRUE(circuit.blocks.has_overflow);
EXPECT_EQ(ivc.prover_accumulator->log_dyadic_size(), 19);
} else {
EXPECT_FALSE(circuit.blocks.has_overflow);
}
}

EXPECT_EQ(ivc.fold_output.accumulator->log_dyadic_size(), 19);
}
17 changes: 0 additions & 17 deletions barretenberg/cpp/src/barretenberg/client_ivc/test_bench_shared.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,6 @@

namespace bb {

/**
* @brief Verify an IVC proof
*
*/
bool verify_ivc(ClientIVC::Proof& proof, ClientIVC& ivc)
{
bool verified = ivc.verify(proof);

// This is a benchmark, not a test, so just print success or failure to the log
if (verified) {
info("IVC successfully verified!");
} else {
info("IVC failed to verify.");
}
return verified;
}

/**
* @brief Perform a specified number of circuit accumulation rounds
*
Expand Down
Loading