Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
chonk.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
22#include <array>
23
24namespace bb {
25
26#ifndef NDEBUG
27template <typename NativeFlavor>
29 const VerifierInputs& queue_entry)
30{
31 auto verifier_inst =
33
34 // Cross-check the prover's instance claim against the native verifier's, claim by claim, as the group is built.
35 // The group's claims are folded together before the next kernel (see update_native_verifier_accumulator).
36 bool sumcheck_verified =
37 native_folding_verifier->template accumulate_instance<NativeFlavor>(verifier_inst, queue_entry.proof);
38 info("Sumcheck: instance to accumulator verified: ", sumcheck_verified ? "true" : "false");
39
40 info("Chonk accumulate: prover and verifier sumcheck claims match: ",
41 folding_prover->get_cached_claims().back().compare_with_verifier_claim(
42 native_folding_verifier->get_cached_claims().back())
43 ? "true"
44 : "false");
45}
46
47template <typename InstanceFlavor>
49 const std::shared_ptr<ProverInstance_<InstanceFlavor>>& prover_instance,
51{
52 info("======= DEBUGGING INFO FOR INCOMING CIRCUIT =======");
53
54 info("Accumulating circuit ", num_circuits_accumulated + 1, " of ", num_circuits);
55 info("Is the circuit valid? ", CircuitChecker::check(circuit) ? "true" : "false");
56 info("Did we find a failure? ", circuit.failed() ? "true" : "false");
57 if (circuit.failed()) {
58 info("\t\t\tError message? ", circuit.err());
59 }
60
61 // Compare precomputed VK with the one generated during accumulation.
62 auto vk = std::make_shared<typename InstanceFlavor::VerificationKey>(prover_instance->get_precomputed());
63 info("Does the precomputed vk match with the one generated during accumulation? ",
64 vk->compare(*precomputed_vk, typename InstanceFlavor::CommitmentLabels().get_precomputed()) ? "true"
65 : "false");
66
67 info("======= END OF DEBUGGING INFO FOR INCOMING CIRCUIT =======");
68}
69
71{
72 info("======= DEBUGGING INFO FOR NATIVE SUMCHECK STEP =======");
73
74 if (queue_entry.is_kernel()) {
75 run_native_instance_sumcheck<KernelFlavor>(queue_entry.kernel_honk_vk, queue_entry);
76 } else {
77 run_native_instance_sumcheck<AppFlavor>(queue_entry.app_honk_vk, queue_entry);
78 }
79
80 info("======= END OF DEBUGGING INFO FOR NATIVE SUMCHECK STEP =======");
81}
82
84{
85 info("======= DEBUGGING INFO FOR NATIVE MULTILINEAR BATCHING STEP =======");
86
87 // Finalise the native cross-check verifier over the same claims the prover folded (the previous accumulator, absent
88 // for the init group, followed by the group's claims). For a single-claim group the batching proof is empty.
89 std::optional<VerifierAccumulator> previous_accumulator =
91 auto [batching_verified, new_accumulator] =
92 native_folding_verifier->finalize(multilinear_batch_proof, std::move(previous_accumulator));
93 native_verifier_accum = std::move(new_accumulator);
95 info("Multilinear batching: claims to accumulator verified: ", batching_verified ? "true" : "false");
96
97 info("Chonk accumulate: prover and verifier accumulators match: ",
99
100 Transcript hash_transcript;
101 info("Chonk accumulate: hash of verifier accumulator computed natively: ",
102 native_verifier_accum.hash_with_origin_tagging(hash_transcript));
103
104 info("======= END OF DEBUGGING INFO FOR NATIVE MULTILINEAR BATCHING STEP =======");
105}
106
108{
109 info("======= DEBUGGING INFO FOR NATIVE DECIDER STEP =======");
110
112 bb::PairingPoints<curve::BN254> pairing_points =
114 info("Decider: pairing points verified? ", pairing_points.check() ? "true" : "false");
115
116 info("======= END OF DEBUGGING INFO FOR NATIVE DECIDER STEP =======");
117}
118#endif
119
120// Constructor
121Chonk::Chonk(std::vector<CircuitKind> circuit_kinds)
122 : circuit_kinds(std::move(circuit_kinds))
123 , num_circuits(this->circuit_kinds.size())
124{
125 // Not BB_ASSERTs: the kinds arrive from msgpack (ChonkStart::kinds / folding stack). A stack with fewer
126 // than 4 circuits cannot hold the app + init/tail/hiding kernel structure the IVC requires, so reject
127 // malformed stacks clearly in release/WASM too.
128 if (num_circuits < 4U) {
129 throw_or_abort("Chonk: number of circuits must be at least 4, got " + std::to_string(num_circuits));
130 }
131
132 for (size_t idx = 0; idx < num_circuits; ++idx) {
133 const CircuitKind kind = this->circuit_kinds[idx];
134 const bool is_valid_kind =
136 if (!is_valid_kind) {
137 throw_or_abort("Chonk: invalid CircuitKind at position " + std::to_string(idx));
138 }
139 const bool is_valid_hiding_kernel_position = (kind == CircuitKind::HidingKernel) == (idx == num_circuits - 1);
140 if (!is_valid_hiding_kernel_position) {
141 throw_or_abort("Chonk: HidingKernel must be the final circuit in the IVC stack and nowhere else");
142 }
143 const bool is_first_circuit_app = this->circuit_kinds.front() == CircuitKind::App;
144 if (!is_first_circuit_app) {
145 throw_or_abort("Chonk: the first circuit in the IVC stack must be an app");
146 }
147 }
148}
149
161 const std::vector<StdlibCircuitVKAndHash>& input_keys)
162{
163 const bool vkeys_provided = !input_keys.empty();
164 if (vkeys_provided) {
166 input_keys.size(),
167 "Incorrect number of verification keys provided in "
168 "stdlib verification queue instantiation.");
169 }
170
171 size_t input_idx = 0;
172 while (!verification_queue.empty()) {
173 const VerifierInputs& entry = verification_queue.front();
174
175 StdlibProof stdlib_proof(circuit, entry.proof);
176
177 if (entry.is_kernel()) {
178 auto stdlib_vk_and_hash = vkeys_provided
181 stdlib_verification_queue.emplace_back(stdlib_proof, stdlib_vk_and_hash);
182 } else {
183 auto stdlib_vk_and_hash = vkeys_provided
186 stdlib_verification_queue.emplace_back(stdlib_proof, stdlib_vk_and_hash);
187 }
188 ++input_idx;
189 verification_queue.pop_front(); // the native data is not needed beyond this point
190 }
191}
192
208 KernelWitnessCommitments& witness_commitments,
209 const std::optional<StdlibFF>& prev_accum_hash)
210{
211 KernelIO kernel_input; // pairing points, ecc op tables, databus commitments
212 kernel_input.reconstruct_from_public(public_inputs);
213
214 // ============= Perform databus consistency checks ===============================
215
216#ifndef NDEBUG
217 bool kernel_return_data_match =
218 kernel_input.kernel_return_data.get_value() == witness_commitments.kernel_calldata().get_value();
219 if (!kernel_return_data_match) {
220 info("kernel_return_data mismatch: proof contains ",
221 kernel_input.kernel_return_data.get_value(),
222 " but kernel_calldata commitment is ",
223 witness_commitments.kernel_calldata().get_value());
224 }
225#endif
226 kernel_input.kernel_return_data.incomplete_assert_equal(witness_commitments.kernel_calldata());
227
228 const std::array app_calldata_commitments{ &witness_commitments.first_app_calldata(),
229 &witness_commitments.second_app_calldata(),
230 &witness_commitments.third_app_calldata(),
231 &witness_commitments.fourth_app_calldata(),
232 &witness_commitments.fifth_app_calldata() };
233 static_assert(std::tuple_size_v<decltype(app_calldata_commitments)> == MAX_APPS_PER_KERNEL,
234 "app_calldata_commitments must list one commitment per app bus column");
235 for (size_t idx = 0; idx < MAX_APPS_PER_KERNEL; ++idx) {
236#ifndef NDEBUG
237 bool app_return_data_match =
238 kernel_input.app_return_data[idx].get_value() == app_calldata_commitments[idx]->get_value();
239 if (!app_return_data_match) {
240 info("app_return_data mismatch: proof contains ",
241 kernel_input.app_return_data[idx].get_value(),
242 " but app calldata commitment ",
243 idx,
244 " is ",
245 app_calldata_commitments[idx]->get_value());
246 }
247#endif
248 kernel_input.app_return_data[idx].incomplete_assert_equal(*app_calldata_commitments[idx]);
249 }
250
251 // ============= Perform accumulator hash consistency check =========================
252
253 info("Accumulator hash from IO: ", kernel_input.output_hn_accum_hash);
254 BB_ASSERT(prev_accum_hash.has_value());
255#ifndef NDEBUG
256 bool accum_hash_match = kernel_input.output_hn_accum_hash.get_value() == prev_accum_hash->get_value();
257 if (!accum_hash_match) {
258 info("output_hn_accum_hash mismatch: proof contains ",
259 kernel_input.output_hn_accum_hash.get_value(),
260 " but expected ",
261 prev_accum_hash->get_value());
262 }
263#endif
264 kernel_input.output_hn_accum_hash.assert_equal(*prev_accum_hash);
265
267
268 return { std::move(kernel_input.pairing_inputs), std::move(kernel_input.ecc_op_hash) };
269}
270
272 AppWitnessCommitments& witness_commitments)
273{
274 AppIO app_input; // pairing points
275 app_input.reconstruct_from_public(public_inputs);
277 return { std::move(app_input.pairing_inputs), std::nullopt };
278}
279
294 const StdlibVerifierInputs& verifier_inputs,
295 HypernovaFoldingRecursiveVerifier& folding_verifier,
296 const std::optional<StdlibFF>& prev_stdlib_acc_hash,
297 const std::optional<EccOpRunningHash>& running_ecc_op_hash)
298{
299 BB_BENCH_NAME("Chonk::recursive_verification_and_consistency_checks");
300
301 // Step 1: Run sumcheck on the incoming instance and cache its claim in the folding verifier.
302 PublicInputsResult public_inputs_result;
303 std::vector<RecursiveCommitment> ecc_op_col_commitments_vec;
304
305 if (verifier_inputs.is_kernel()) {
306 auto verifier_instance =
308 folding_verifier.accumulate_instance<KernelRecursiveFlavor>(verifier_instance, verifier_inputs.proof);
309
310 KernelWitnessCommitments witness_commitments = std::move(verifier_instance->witness_commitments);
311 std::vector<StdlibFF> public_inputs = std::move(verifier_instance->public_inputs);
312 public_inputs_result = process_kernel_public_inputs(public_inputs, witness_commitments, prev_stdlib_acc_hash);
313
314 auto ecc_op_col_commitments = witness_commitments.get_ecc_op_wires().get_copy();
315 ecc_op_col_commitments_vec.assign(ecc_op_col_commitments.begin(), ecc_op_col_commitments.end());
316 } else {
317 auto verifier_instance = std::make_shared<AppRecursiveVerifierInstance>(verifier_inputs.app_honk_vk_and_hash);
318 folding_verifier.accumulate_instance<AppRecursiveFlavor>(verifier_instance, verifier_inputs.proof);
319
320 AppWitnessCommitments witness_commitments = std::move(verifier_instance->witness_commitments);
321 std::vector<StdlibFF> public_inputs = std::move(verifier_instance->public_inputs);
322 public_inputs_result = process_app_public_inputs(public_inputs, witness_commitments);
323
324 auto ecc_op_col_commitments = witness_commitments.get_ecc_op_wires().get_copy();
325 ecc_op_col_commitments_vec.assign(ecc_op_col_commitments.begin(), ecc_op_col_commitments.end());
326 }
327
328 // Step 2: Update the running ECC op hash with this circuit's ECC op column commitments.
329 std::optional<StdlibFF> updated_hash = running_ecc_op_hash;
330 if (public_inputs_result.ecc_op_hash.has_value()) {
331 BB_ASSERT_EQ(verifier_inputs.is_kernel(), true, "previous_ecc_op_hash should only be set for kernels");
332 BB_ASSERT(!running_ecc_op_hash.has_value(),
333 "Running ECC op hash should not be set when recursively verifying a kernel");
334 updated_hash = public_inputs_result.ecc_op_hash.value();
335 }
336
337 updated_hash = Goblin::BatchMergeRecursiveVerifier::ecc_op_hash_step(ecc_op_col_commitments_vec, updated_hash);
338
339 return { public_inputs_result.pairing_points, updated_hash.value() };
340}
341
356{
357 BB_BENCH_NAME("Chonk::complete_kernel_circuit_logic");
358 // Step 1: SETUP - Initialize state and determine kernel type
359
360 // Transcript is shared across recursive verification of the sumchecks of K_{i-1} (kernel) and A_{i}, \dots,
361 // A_{i + N} (apps) where N is the number of apps in the group being accumulated in this kernel
362 auto accumulation_recursive_transcript = std::make_shared<RecursiveTranscript>();
363
364 // Running Poseidon2 hash over ECC op column commitments, propagated through kernel public inputs.
365 std::optional<EccOpRunningHash> running_ecc_op_hash = std::nullopt;
366
367 // Convert native verification queue to circuit witnesses
368 if (stdlib_verification_queue.empty()) {
370 }
371
372 // Determine kernel type from circuit kinds and the queued group. The init kernel's group begins with the
373 // first app's proof; every later kernel's group begins with the previous kernel's proof. Whether
374 // this is the hiding kernel is read directly from the circuit kinds supplied at construction.
375 const bool is_init = is_init_kernel();
376 const bool is_hiding = is_hiding_kernel();
377
378 // The ECC-op subtable for a kernel begins with an eq-and-reset to ensure that the preceding circuit's subtable
379 // cannot affect the ECC-op accumulator for the kernel.
380 circuit.queue_ecc_eq();
381
383 "DataBusDepot has stale app return-data slots at kernel-completion boundary");
384
385 // The number of claims this kernel batches: the previous accumulator (absent for the
386 // init kernel) plus one sumcheck claim per proof in the group. A single-claim init kernel needs no batching -
387 // its lone sumcheck claim is already the accumulator.
388 const size_t group_size = stdlib_verification_queue.size();
389 const size_t num_claims = group_claim_count(/*has_previous_accumulator=*/!is_init, group_size);
390 BB_ASSERT_LTE(num_claims, CHONK_MAX_CLAIMS_PER_KERNEL, "Per-kernel batch width exceeds the supported maximum");
391
392 // Step 2: RECURSIVE VERIFIER - Fold each proof in the group into the folding verifier.
393
394 std::vector<PairingPoints> points_accumulator;
395
396 // The previous accumulator is claim 0 of this kernel's batch. It is absent for the init
397 // kernel, which only verifies app circuits.
398 std::optional<RecursiveVerifierAccumulator> prev_stdlib_verifier_accumulator;
399 std::optional<StdlibFF> prev_stdlib_accum_hash;
400 if (!is_init) {
401 prev_stdlib_verifier_accumulator =
402 RecursiveVerifierAccumulator::stdlib_from_native<RecursiveCurve>(&circuit, recursive_verifier_native_accum);
403 prev_stdlib_accum_hash =
404 prev_stdlib_verifier_accumulator->hash_with_origin_tagging(*accumulation_recursive_transcript);
405 }
406
407 HypernovaFoldingRecursiveVerifier folding_verifier(accumulation_recursive_transcript);
408
409 while (!stdlib_verification_queue.empty()) {
410 const StdlibVerifierInputs& verifier_input = stdlib_verification_queue.front();
411
412 auto [pairing_points, updated_ecc_hash] = recursive_verification_and_consistency_checks(
413 verifier_input, folding_verifier, prev_stdlib_accum_hash, running_ecc_op_hash);
414 points_accumulator.push_back(pairing_points);
415 running_ecc_op_hash = updated_ecc_hash;
416
417 stdlib_verification_queue.pop_front();
418 }
419
421 running_ecc_op_hash.has_value(), true, "Running ECC op hash should be set for public input propagation");
422
423 // Step 3: Reduce the group's claims to a single accumulator. For a single-claim init kernel the batching proof is
424 // empty and finalize returns the lone sumcheck claim directly.
425 StdlibProof stdlib_multilinear_batch_proof(circuit, multilinear_batch_proof);
426 auto [batch_verified, output_accumulator] =
427 folding_verifier.finalize(stdlib_multilinear_batch_proof, std::move(prev_stdlib_verifier_accumulator));
428 vinfo("Per-kernel folding verified: ", batch_verified ? "true" : "false");
429
430 // Output differs based on kernel type: HidingKernelIO (no accum hash) vs KernelIO (with accum hash)
431 if (is_hiding) {
432 // Perform decider verification
433 BB_ASSERT_EQ(num_claims, 2U, "In the hiding kernel the number of claims should always be equal to 2");
434 RecursiveDeciderVerifier decider_verifier(accumulation_recursive_transcript);
435 StdlibProof stdlib_decider_proof(circuit, decider_proof);
436 points_accumulator.emplace_back(decider_verifier.verify_proof(output_accumulator, stdlib_decider_proof));
437
438 // Perform batch merge verification
439 auto [batch_pairing_points, batch_merged_table_commitments] =
440 goblin.recursively_verify_batch_merge(circuit, running_ecc_op_hash.value());
441
442 // Append batch merge pairing points to the list of pairing points
443 points_accumulator.emplace_back(batch_pairing_points);
444
445 // Compute aggregated pairing points for output
446 PairingPoints pairing_points_aggregator = PairingPoints::aggregate_multiple(points_accumulator);
447
448 // Add randomness at the end of the hiding kernel (whose ecc ops fall right at the end of the op queue table) to
449 // ensure the Chonk proof doesn't leak information about the actual content of the op queue
451
452 HidingKernelIO hiding_output{ pairing_points_aggregator,
454 std::move(batch_merged_table_commitments) };
455 hiding_output.set_public();
456 } else {
457 // Compute aggregated pairing points for output
458 PairingPoints pairing_points_aggregator = PairingPoints::aggregate_multiple(points_accumulator);
459
460 // Extract native verifier accumulator from the stdlib accum to use it in the next round
461 recursive_verifier_native_accum = output_accumulator.get_value<VerifierAccumulator>();
462
463 auto kernel_return_data_commitment = bus_depot.get_kernel_return_data_commitment(circuit);
464 KernelIO::AppReturnDataCommitments app_return_data_commitments;
465 for (size_t idx = 0; idx < MAX_APPS_PER_KERNEL; ++idx) {
466 app_return_data_commitments[idx] = bus_depot.get_app_return_data_commitment(circuit, idx);
467 }
468
469 // Compute hash of output accumulator
470 RecursiveTranscript hash_transcript;
471 StdlibFF current_verifier_accum_hash = output_accumulator.hash_with_origin_tagging(hash_transcript);
472 info("Kernel output accumulator hash: ", current_verifier_accum_hash);
473
474 // Propagate public inputs
475 KernelIO kernel_output{ pairing_points_aggregator,
476 kernel_return_data_commitment,
477 app_return_data_commitments,
478 running_ecc_op_hash.value(),
479 current_verifier_accum_hash };
480 kernel_output.set_public();
481 }
482}
483
488 const std::shared_ptr<MegaZKVerificationKey>& precomputed_vk)
489{
490 BB_BENCH_NAME("Chonk::accumulate_hiding_kernel");
492 num_circuits_accumulated, num_circuits, "Chonk: Attempting to accumulate more circuits than expected.");
493 // throw, not BB_ASSERT: reachable from external step ordering, and a wrong position would feed
494 // the wrong variant alternative into std::get below (std::bad_variant_access / mis-folding).
495 if (!is_hiding_kernel()) {
496 throw_or_abort("Chonk::accumulate_hiding_kernel must be the final circuit in the IVC stack");
497 }
498
499 vinfo("Constructing hiding kernel instance (proving deferred to prove())");
501
502 // Free circuit block memory now that trace data has been copied to prover polynomials
503 for (auto& block : circuit.blocks.get()) {
504 block.free_data();
505 }
506
507 if (precomputed_vk) {
508#ifndef NDEBUG
509 auto computed_vk = std::make_shared<MegaZKVerificationKey>(hiding_prover_inst->get_precomputed());
510 BB_ASSERT(*precomputed_vk == *computed_vk,
511 "Chonk::accumulate_hiding_kernel - precomputed MegaZK VK does not match computed VK");
512#endif
513 hiding_vk = precomputed_vk;
514 } else {
516 }
518}
519
520// Templated body of accumulate_and_fold. Dispatched on InstanceFlavor (MegaAppFlavor for apps,
521// MegaKernelFlavor for kernels). The Hypernova accumulator is flavor-agnostic so apps and kernels
522// fold into the same `prover_accumulator`.
523template <typename InstanceFlavor>
526{
528 BB_ASSERT(vk != nullptr, "Chonk::accumulate_and_fold - VK expected for the provided circuit");
529
530 auto prover_instance = std::make_shared<PI>(circuit);
531#ifndef NDEBUG
532 debug_incoming_circuit<InstanceFlavor>(circuit, prover_instance, vk);
533#endif
534 // Free circuit block memory (wires and selectors) now that they've been copied to prover polynomials.
535 for (auto& block : circuit.blocks.get()) {
536 block.free_data();
537 }
538
539 // Run sumcheck on the incoming instance; the folding prover caches the resulting claim. The claims of the whole
540 // group are batched together once, when the group's last circuit is accumulated (see prove_multilinear_batching).
541 vinfo("Accumulating circuit number ", num_circuits_accumulated + 1);
542 return folding_prover->template accumulate_instance<InstanceFlavor>(prover_instance, vk);
543}
544
546{
547 BB_BENCH_NAME("Chonk::accumulate_and_fold");
548
549 const CircuitKind kind = current_kind();
550 const CircuitKind following_kind = next_kind();
551
552 const bool state_says_kernel = verification_queue.empty() && num_circuits_accumulated > 0;
553 BB_ASSERT_EQ(state_says_kernel,
554 kind == CircuitKind::Kernel,
555 "Chonk::accumulate_and_fold: CircuitKind disagrees with the IVC state machine");
556
557 const bool is_init_group = num_circuits_accumulated == 0;
558 if (kind == CircuitKind::Kernel || is_init_group) {
559 BB_ASSERT_EQ(folding_prover, nullptr, "Folding prover must be null at the beginning of a group");
560
561 // A kernel/init group begins a new folding group with a fresh transcript and folding prover. The previous
562 // accumulator (from the previous group) is supplied at finalize time (see prove_multilinear_batching).
565#ifndef NDEBUG
566 BB_ASSERT_EQ(native_folding_verifier, nullptr, "Folding verifier must be null at the beginning of a group");
570#endif
571 }
572
573 HonkProof proof;
574 VerifierInputs queue_entry;
575 queue_entry.kind = kind;
576 if (kind == CircuitKind::Kernel) {
578 proof = instance_to_accumulator<KernelFlavor>(circuit, kernel_vk);
579 queue_entry.kernel_honk_vk = std::move(kernel_vk);
580 } else {
582 proof = instance_to_accumulator<AppFlavor>(circuit, app_vk);
583 queue_entry.app_honk_vk = std::move(app_vk);
584 }
585 queue_entry.proof = std::move(proof);
586
590 }
591
592 verification_queue.push_back(queue_entry);
593
594#ifndef NDEBUG
596#endif
597
598 // If a kernel follows, the circuit just folded was the last of that kernel's group: produce the batching
599 // proof the kernel will recursively verify.
600 if (following_kind == CircuitKind::Kernel || following_kind == CircuitKind::HidingKernel) {
602 }
603
604 // Merge the ecc ops from this round of accumulation
605 goblin.op_queue->merge();
606
608}
609
611{
612 BB_ASSERT_LT(num_circuits_accumulated, num_circuits, "Chonk: every circuit has already been accumulated.");
614}
615
617{
618 const size_t next_idx = num_circuits_accumulated + 1;
619 return next_idx < num_circuits ? circuit_kinds[next_idx] : CircuitKind::None;
620}
621
623{
625 "is_init_kernel: stdlib verification queue must hold the current kernel's group");
626 return stdlib_verification_queue.front().kind == CircuitKind::App;
627}
628
636{
637 BB_BENCH_NAME("Chonk::accumulate");
639 num_circuits_accumulated, num_circuits, "Chonk: Attempting to accumulate more circuits than expected.");
640 const CircuitKind kind = current_kind();
641
642 switch (kind) {
644 // The constructor guarantees the HidingKernel kind only at the final position; std::get below throws
645 // bad_variant_access if the caller supplies a non-MegaZK VK.
646 accumulate_hiding_kernel(circuit, std::get<std::shared_ptr<MegaZKVerificationKey>>(vk));
647 break;
648 }
649 case CircuitKind::App:
650 case CircuitKind::Kernel: {
651 // Capture before folding: accumulate_and_fold advances num_circuits_accumulated.
652 const CircuitKind following_kind = next_kind();
653
654 accumulate_and_fold(circuit, vk);
655
656 // If the hiding kernel follows, the IVC is complete: prove the batch merge and run the decider on the
657 // final accumulator (the output of the hiding kernel's batching). Both proofs are recursively verified
658 // in the hiding kernel.
659 if (following_kind == CircuitKind::HidingKernel) {
662#ifndef NDEBUG
664#endif
666 }
667 break;
668 }
670 throw_or_abort("Chonk::accumulate: CircuitKind is None (unset)");
671 }
672}
673
681{
682 BB_ASSERT(!verification_queue.empty(), "Chonk: cannot batch an empty group");
683
684 // The init kernel's group begins with the first app's proof and carries no accumulator; every later
685 // group begins with the previous kernel's proof. So the group is the init group iff its first
686 // entry is an app.
687 const bool is_init_group = verification_queue.front().kind == CircuitKind::App;
688 const size_t num_claims = group_claim_count(/*has_previous_accumulator=*/!is_init_group, verification_queue.size());
689 BB_ASSERT_LTE(num_claims, CHONK_MAX_CLAIMS_PER_KERNEL, "Per-kernel batch width exceeds the supported maximum");
690
691 // Fold the group: the previous accumulator (absent for the init group, otherwise from the previous group) followed
692 // by the cached per-instance claims, all batched on the group's accumulation transcript so the batching challenge
693 // is bound by the instance sumchecks already absorbed there. A single-claim group needs no batching (empty proof).
694 std::optional<ProverAccumulator> previous_accumulator =
696 auto [proof, accumulator] = folding_prover->finalize(std::move(previous_accumulator));
697 BB_ASSERT_EQ(proof.empty(), num_claims == 1, "A single-claim group must produce no batching proof");
699 prover_accumulator = std::move(accumulator);
700
701#ifndef NDEBUG
703#endif
704
705 folding_prover.reset();
706}
707
718
733{
734 BB_BENCH_NAME("Chonk::prove");
735
736 // Share transcript between all provers.
738
739 // Phase 1: MegaZK Oink on the shared transcript.
741 auto hiding_oink_proof = batched_prover.prove_mega_zk_oink();
742
743 // Phase 2: Merge proof on the shared transcript (fixed append — hiding kernel's subtable).
744 auto merge_proof = goblin.prove_merge(transcript);
745 info("Goblin: num ultra ops = ", goblin.op_queue->get_ultra_ops_count());
746
747 // Phase 3: ECCVM proof on the shared transcript.
748 vinfo("prove eccvm...");
750 vinfo("finished eccvm proving.");
751
752 // Phase 4: Build translator proving key from ECCVM-derived challenges.
753 TranslatorCircuitBuilder translator_builder(
755 auto translator_key = std::make_shared<TranslatorProvingKey>(translator_builder);
756
757 // Phase 5: Translator Oink + Joint Sumcheck + Joint PCS on the shared transcript.
758 vinfo("prove translator and joint...");
759 auto joint_proof = batched_prover.prove(translator_key);
760 vinfo("finished translator and joint proving.");
761
762 // Release the hiding kernel instance now that proving is complete.
763 hiding_prover_inst.reset();
764
765 return ChonkProof{ std::move(hiding_oink_proof),
766 std::move(merge_proof),
769 std::move(joint_proof) };
770}
771
773{
774 BB_ASSERT(hiding_vk != nullptr, "Hiding kernel VK has not been computed yet");
776}
777
778} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:143
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
static FF ecc_op_hash_step(const std::vector< Commitment > &col_commitments, const std::optional< FF > &prev_hash=std::nullopt)
Compute one step of the ECC op running hash.
Prover for the batched MegaZK circuit + translator sumcheck and PCS.
HonkProof prove(std::shared_ptr< TranslatorProvingKey > translator_proving_key)
PublicInputsResult process_app_public_inputs(std::vector< StdlibFF > &public_inputs, AppWitnessCommitments &witness_commitments)
Definition chonk.cpp:271
ProverAccumulator prover_accumulator
Definition chonk.hpp:164
std::shared_ptr< FoldingProver > folding_prover
Definition chonk.hpp:165
void verify_decider_natively()
Definition chonk.cpp:107
std::shared_ptr< MegaZKFlavor::VKAndHash > get_hiding_kernel_vk_and_hash() const
Get the hiding kernel verification key and hash for Chonk verification.
Definition chonk.cpp:772
void complete_kernel_circuit_logic(ClientCircuit &circuit)
Append logic to complete a kernel circuit.
Definition chonk.cpp:355
void run_native_instance_sumcheck(const std::shared_ptr< typename NativeFlavor::VerificationKey > &honk_vk, const VerifierInputs &queue_entry)
Templated native verification of the instance to accumulator sumcheck.
Definition chonk.cpp:28
CircuitKind current_kind() const
Kind of the circuit currently being accumulated (or, between accumulate calls, the next one expected)...
Definition chonk.cpp:610
VerifierAccumulator native_verifier_accum
Definition chonk.hpp:173
void prove_multilinear_batching()
Generate multilinear batching proof for the current group of accumulators.
Definition chonk.cpp:680
void accumulate(ClientCircuit &circuit, const CircuitVerificationKey &vk)
Accumulate a circuit into the running IVC.
Definition chonk.cpp:635
static void hide_op_queue_content_in_hiding(ClientCircuit &circuit)
Adds two random non-ops to the hiding kernel for zero-knowledge.
Definition chonk.cpp:713
void accumulate_hiding_kernel(ClientCircuit &circuit, const std::shared_ptr< MegaZKVerificationKey > &precomputed_vk)
Build the hiding kernel's ZK proving key and verification key (proving is deferred to prove()).
Definition chonk.cpp:487
Chonk(std::vector< CircuitKind > circuit_kinds)
Definition chonk.cpp:121
KernelRecursiveFlavor::FF StdlibFF
Definition chonk.hpp:66
DataBusDepot bus_depot
Definition chonk.hpp:186
std::shared_ptr< Transcript > transcript
Definition chonk.hpp:154
size_t num_circuits_accumulated
Definition chonk.hpp:162
std::pair< PairingPoints, EccOpRunningHash > recursive_verification_and_consistency_checks(const StdlibVerifierInputs &verifier_inputs, HypernovaFoldingRecursiveVerifier &folding_verifier, const std::optional< StdlibFF > &prev_stdlib_acc_hash, const std::optional< EccOpRunningHash > &running_ecc_op_hash)
Run sumcheck on a single proof in the group and perform its databus/accumulator-hash consistency chec...
Definition chonk.cpp:293
HonkProof decider_proof
Definition chonk.hpp:169
std::vector< CircuitKind > circuit_kinds
Definition chonk.hpp:159
void update_native_verifier_accumulator(bool is_init_group)
Natively verify the multilinear batching proof and update the native verifier accumulator....
Definition chonk.cpp:83
bb::CircuitVerificationKey CircuitVerificationKey
Definition chonk.hpp:101
ChonkProof prove()
Construct Chonk proof using the batched MegaZK + Translator protocol.
Definition chonk.cpp:732
std::shared_ptr< HypernovaFoldingNativeVerifier > native_folding_verifier
Definition chonk.hpp:174
void instantiate_stdlib_verification_queue(ClientCircuit &circuit, const std::vector< StdlibCircuitVKAndHash > &input_keys={})
Instantiate a stdlib verification queue for use in the kernel completion logic.
Definition chonk.cpp:160
VerifierAccumulator recursive_verifier_native_accum
Definition chonk.hpp:171
PublicInputsResult process_kernel_public_inputs(std::vector< StdlibFF > &public_inputs, KernelWitnessCommitments &witness_commitments, const std::optional< StdlibFF > &prev_accum_hash)
Process public inputs from a verified circuit and perform databus consistency checks.
Definition chonk.cpp:207
std::shared_ptr< HidingKernelProverInstance > hiding_prover_inst
Definition chonk.hpp:191
CircuitKind next_kind() const
Kind of the circuit that follows the one currently being accumulated, or CircuitKind::None if the cur...
Definition chonk.cpp:616
std::shared_ptr< Transcript > native_verifier_accumulation_transcript
Definition chonk.hpp:175
bool is_hiding_kernel() const
Whether the circuit currently being accumulated/completed is the hiding kernel.
Definition chonk.hpp:268
void accumulate_and_fold(ClientCircuit &circuit, const CircuitVerificationKey &vk)
Turn the incoming instance into an accumulator. If a kernel follows, also produce a multilinear batch...
Definition chonk.cpp:545
size_t num_circuits
Definition chonk.hpp:160
void debug_incoming_circuit(ClientCircuit &circuit, const std::shared_ptr< ProverInstance_< InstanceFlavor > > &prover_instance, const std::shared_ptr< typename InstanceFlavor::VerificationKey > &precomputed_vk)
Definition chonk.cpp:48
VerificationQueue verification_queue
Definition chonk.hpp:182
static constexpr size_t group_claim_count(bool has_previous_accumulator, size_t group_size)
Number of claims a kernel batches: the previous accumulator (absent for the init kernel) plus one sum...
Definition chonk.hpp:198
Goblin goblin
Definition chonk.hpp:188
HonkProof multilinear_batch_proof
Definition chonk.hpp:167
std::shared_ptr< MegaZKVerificationKey > hiding_vk
Definition chonk.hpp:192
bool is_init_kernel() const
Whether the kernel currently being completed is the init kernel (the first kernel,...
Definition chonk.cpp:622
std::shared_ptr< Transcript > prover_accumulation_transcript
Definition chonk.hpp:157
HonkProof instance_to_accumulator(ClientCircuit &circuit, const std::shared_ptr< typename InstanceFlavor::VerificationKey > &vk)
Definition chonk.cpp:524
void verify_native_instance_sumcheck(const VerifierInputs &queue_entry)
Natively verify the instance-to-accumulator sumcheck of the circuit just accumulated....
Definition chonk.cpp:70
StdlibVerificationQueue stdlib_verification_queue
Definition chonk.hpp:183
const std::string & err() const
fq evaluation_challenge_x
Definition goblin.hpp:64
GoblinProof goblin_proof
Definition goblin.hpp:61
MergeProof prove_merge(const std::shared_ptr< Transcript > &transcript=std::make_shared< Transcript >()) const
Construct a single-step merge proof for the most recently merged subtable.
Definition goblin.cpp:28
void prove_eccvm()
Construct an ECCVM proof and TripleIPA opening proof.
Definition goblin.cpp:35
fq translation_batching_challenge_v
Definition goblin.hpp:63
void prove_batch_merge()
Construct a batched merge proof for all subtables accumulated during the IVC.
Definition goblin.cpp:89
std::shared_ptr< OpQueue > op_queue
Definition goblin.hpp:59
std::shared_ptr< Transcript > transcript
Definition goblin.hpp:65
std::pair< PairingPoints, BatchRecursiveTableCommitments > recursively_verify_batch_merge(MegaBuilder &builder, const BatchMergeRecursiveVerifier::FF &hash) const
Recursively verify the batched merge proof inside the hiding kernel.
Definition goblin.cpp:106
HyperNova decider prover. Produces final opening proof for the accumulated claim.
HonkProof construct_proof(Accumulator &accumulator)
HyperNova decider verifier (native + recursive). Verifies final opening proof.
PairingPoints verify_proof(Accumulator &accumulator, const Proof &proof)
Stateful HyperNova folding verifier (native + recursive). Verifies a series of instances against a st...
std::pair< bool, Accumulator > finalize(const Proof &batching_proof, std::optional< Accumulator > previous_accumulator=std::nullopt)
Batch the previous accumulator (if any) and the cached claims into a single accumulator.
bool accumulate_instance(const std::shared_ptr< VerifierInstance< InstanceFlavor > > &instance, const Proof &proof)
Verify the instance-to-accumulator sumcheck of one incoming proof and cache the resulting claim.
Recursive counterpart to MegaAppFlavor.
void queue_ecc_random_op()
Mechanism for populating two rows with randomness. This "operation" doesn't return a tuple representi...
ecc_op_tuple queue_ecc_eq(bool in_finalize=true)
Add point equality operation to the op queue based on the value of the internal accumulator and add c...
Recursive counterpart to MegaKernelFlavor.
An object storing two EC points that represent the inputs to a pairing check.
bool check() const
Verify the pairing equation e(P0, [1]₂) · e(P1, [x]₂) = 1.
Contains all the information required by a Honk prover to create a proof, constructed from a finalize...
TranslatorCircuitBuilder creates a circuit that evaluates the correctness of the evaluation of EccOpQ...
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
Commitment get_kernel_return_data_commitment(Builder &builder)
Get the previously set kernel return data commitment if it exists, else a default one.
Definition databus.hpp:171
bool app_return_data_slots_are_empty() const
Whether all app return-data slots are currently empty.
Definition databus.hpp:126
Commitment get_app_return_data_commitment(Builder &builder, const size_t idx)
Get the previously set app return data commitment if it exists, else a default one.
Definition databus.hpp:184
void set_app_return_data_commitment(const Commitment &commitment)
Record an app return-data commitment in the next available slot.
Definition databus.hpp:143
void set_kernel_return_data_commitment(const Commitment &commitment)
Definition databus.hpp:114
Manages the data that is propagated on the public inputs of an application/function circuit.
void reconstruct_from_public(const std::vector< FF > &public_inputs)
Reconstructs the IO components from a public inputs array.
Manages the data that is propagated on the public inputs of a hiding kernel circuit.
Manages the data that is propagated on the public inputs of a kernel circuit.
void reconstruct_from_public(const std::vector< FF > &public_inputs)
Reconstructs the IO components from a public inputs array.
#define info(...)
Definition log.hpp:93
#define vinfo(...)
Definition log.hpp:94
bool use_memory_profile
MemoryProfile GLOBAL_MEMORY_PROFILE
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
std::vector< fr > HonkProof
Definition proof.hpp:15
VerifierCommitmentKey< Curve > vk
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
PairingPoints pairing_points
Definition chonk.hpp:96
std::optional< StdlibFF > ecc_op_hash
Definition chonk.hpp:97
std::shared_ptr< AppRecursiveVKAndHash > app_honk_vk_and_hash
Definition chonk.hpp:126
std::shared_ptr< KernelRecursiveVKAndHash > kernel_honk_vk_and_hash
Definition chonk.hpp:127
std::shared_ptr< KernelVerificationKey > kernel_honk_vk
Definition chonk.hpp:106
bool is_kernel() const
Definition chonk.hpp:109
std::shared_ptr< AppVerificationKey > app_honk_vk
Definition chonk.hpp:105
std::vector< FF > proof
Definition chonk.hpp:104
HonkProof eccvm_proof
Definition types.hpp:22
HonkProof ipa_proof
Definition types.hpp:23
bool compare_with_verifier_claim(const MultilinearBatchingVerifierClaim< curve::BN254 > &verifier_claim) const
Debug helper to compare prover claim against verifier claim.
void add_checkpoint(const std::string &stage)
static PairingPoints aggregate_multiple(std::vector< PairingPoints > &pairing_points, bool handle_edge_cases=true)
Aggregate multiple PairingPoints using random linear combination.
void throw_or_abort(std::string const &err)
BB_VF_LOAD_LIMBS * this