Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1e1aa97
Progress towards not using global honk_vk
ledwards2225 Aug 29, 2025
007db1e
remove honk_vk altogether
ledwards2225 Aug 29, 2025
c016a25
WiP replace fold_output with prover_accumulator
ledwards2225 Aug 29, 2025
ae13c4a
fix cast issue
ledwards2225 Aug 30, 2025
674d53a
add worktodo
ledwards2225 Aug 30, 2025
07cac06
remove redundant verify methods
ledwards2225 Aug 30, 2025
3e562a5
tidy
ledwards2225 Aug 30, 2025
65ba35d
Merge branch 'merge-train/barretenberg' into lde/civc-tidy-3
ledwards2225 Aug 30, 2025
f9c8770
fix assert
ledwards2225 Aug 30, 2025
acc73bc
fix build
ledwards2225 Aug 30, 2025
be7457c
Merge branch 'merge-train/barretenberg' into lde/civc-tidy-3
ledwards2225 Sep 2, 2025
063b712
restore randomly deleted components
ledwards2225 Sep 2, 2025
cb3f22b
tidy
ledwards2225 Sep 2, 2025
cb6e829
add option to not use structured trace when computing standalone vk
ledwards2225 Sep 2, 2025
045a909
update cli to allow nonstructured hiding circuit VK
ledwards2225 Sep 2, 2025
8d9097b
Merge branch 'merge-train/barretenberg' into lde/civc-tidy-3
ledwards2225 Sep 2, 2025
9dca508
nargo fmt
ledwards2225 Sep 2, 2025
6b792ed
again
ledwards2225 Sep 2, 2025
0308e4f
Merge branch 'merge-train/barretenberg' into lde/civc-tidy-3
ledwards2225 Sep 3, 2025
824cf8c
fmt?
ledwards2225 Sep 3, 2025
2989802
unformat??
ledwards2225 Sep 3, 2025
c0f85e4
again
ledwards2225 Sep 3, 2025
17da7bb
bump prover full timeout
ledwards2225 Sep 3, 2025
7e1d814
test: bump timeout to 25
ledwards2225 Sep 3, 2025
c7bcd9f
Merge branch 'merge-train/barretenberg' into lde/civc-tidy-3
ledwards2225 Sep 3, 2025
5c1ed1a
wasm fix
ledwards2225 Sep 4, 2025
8f089ef
remove no longer needed tail pub input propagation
ledwards2225 Sep 4, 2025
0351a10
touch more cleanup
ledwards2225 Sep 4, 2025
be46a3f
Merge branch 'merge-train/barretenberg' into lde/civc-tidy-3
ledwards2225 Sep 5, 2025
ec09536
Merge branch 'merge-train/barretenberg' into lde/civc-tidy-3
ledwards2225 Sep 8, 2025
4ebd6f1
update noir protocol boot
ledwards2225 Sep 8, 2025
0543364
Merge branch 'merge-train/barretenberg' into lde/civc-tidy-3
ledwards2225 Sep 9, 2025
578e8fe
cleanup
ledwards2225 Sep 9, 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);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the tail now uses the databus - it has no public inputs to propagate

Copy link
Contributor

Choose a reason for hiding this comment

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

ah great! I think I removed it and had some tests failing in my previous clean up.

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 },
Copy link
Contributor

Choose a reason for hiding this comment

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

quite funny. I think we were only using the accumulator of the fold_output but keeping the whole object. did we historically use another member of it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the other member was the proof. Can't remember if we ever used it but wouldnt make much sense since its stored in the queue anyway

{ 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());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

prior to this PR we were recomputing the hiding VK on the fly rather than using the precomputed one. This is why we weren't getting errors even though the precomputed VK was incorrectly using a structured trace

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);
Copy link
Contributor

Choose a reason for hiding this comment

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

just to make sure I understand correctly. We do not keep the honk_vk member anymore (that use to keep the vk of the last proof that needs to be recursively verified in the hiding circuit) and we're just passing it as an input here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah ever since the updates from you/leila that final VK (hiding VK) is a precomputed input just like for all of the other circuits - until now we just weren't using it and instead recomputed it on the fly

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);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we now just extract the hiding kernel VK from the queue

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
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we only track the accumulator since the proof is stored internal to the verification queue

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) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is now handled internal to the mock circuit produced

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
Copy link
Contributor

Choose a reason for hiding this comment

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

oops seems like I forgot about this when refactoring the tests. thanks!

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)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

unused

{
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
Loading