Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
client_ivc.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
15
16namespace bb {
17
18// Constructor
19ClientIVC::ClientIVC(size_t num_circuits, TraceSettings trace_settings)
20 : trace_usage_tracker(trace_settings)
21 , num_circuits(num_circuits)
22 , trace_settings(trace_settings)
23 , goblin(bn254_commitment_key)
24{
25 BB_ASSERT_GT(num_circuits, 0UL, "Number of circuits must be specified and greater than 0.");
26 // Allocate BN254 commitment key based on the max dyadic Mega structured trace size and translator circuit size.
27 // https://github.com/AztecProtocol/barretenberg/issues/1319): Account for Translator only when it's necessary
28 size_t commitment_key_size =
30 info("BN254 commitment key size: ", commitment_key_size);
32}
33
45 ClientCircuit& circuit, const std::vector<std::shared_ptr<RecursiveVKAndHash>>& input_keys)
46{
47 bool vkeys_provided = !input_keys.empty();
48 if (vkeys_provided) {
50 input_keys.size(),
51 "Incorrect number of verification keys provided in "
52 "stdlib verification queue instantiation.");
53 }
54
55 size_t key_idx = 0;
56 while (!verification_queue.empty()) {
57 const VerifierInputs& entry = verification_queue.front();
58
59 // Construct stdlib proof directly from the internal native queue data
60 StdlibProof stdlib_proof(circuit, entry.proof);
61
62 // Use the provided stdlib vkey if present, otherwise construct one from the internal native queue
63 std::shared_ptr<RecursiveVKAndHash> stdlib_vk_and_hash;
64 if (vkeys_provided) {
65 stdlib_vk_and_hash = input_keys[key_idx++];
66 } else {
67 stdlib_vk_and_hash = std::make_shared<RecursiveVKAndHash>(circuit, entry.honk_vk);
68 }
69
70 stdlib_verification_queue.emplace_back(stdlib_proof, stdlib_vk_and_hash, entry.type, entry.is_kernel);
71
72 verification_queue.pop_front(); // the native data is not needed beyond this point
73 }
74}
75
77 ClientCircuit& circuit,
78 const std::shared_ptr<RecursiveVerifierInstance>& verifier_instance,
80 const StdlibProof& proof)
81{
82 transcript->load_proof(proof);
83 OinkRecursiveVerifier verifier{ verifier_instance, transcript };
84 verifier.verify();
85
86 verifier_instance->target_sum = StdlibFF::from_witness_index(&circuit, circuit.zero_idx());
87 // Get the gate challenges for sumcheck/combiner computation
88 verifier_instance->gate_challenges =
89 transcript->template get_powers_of_challenge<StdlibFF>("gate_challenge", CONST_PG_LOG_N);
90
91 return verifier_instance;
92}
93
95 ClientCircuit& circuit,
96 const std::shared_ptr<RecursiveVerifierInstance>& verifier_accumulator,
97 const std::shared_ptr<RecursiveVerifierInstance>& verifier_instance,
99 const StdlibProof& proof,
100 std::optional<StdlibFF>& prev_accum_hash,
101 bool is_kernel)
102{
103 BB_ASSERT_NEQ(verifier_accumulator, nullptr, "verifier_accumulator cannot be null in PG recursive verification");
104
105 // Fiat-Shamir the accumulator. (Only needs to be performed on the first in a series of recursive PG verifications
106 // within a given kernel and by convention the kernel proof is always verified first).
107 if (is_kernel) {
108 prev_accum_hash = verifier_accumulator->hash_through_transcript("", *transcript);
109 transcript->add_to_hash_buffer("accum_hash", *prev_accum_hash);
110 info("Previous accumulator hash in PG rec verifier: ", *prev_accum_hash);
111 }
112 // Perform folding recursive verification to update the verifier accumulator
113 FoldingRecursiveVerifier verifier{ &circuit, verifier_accumulator, verifier_instance, transcript };
114 auto updated_verifier_accumulator = verifier.verify_folding_proof(proof);
115
116 return updated_verifier_accumulator;
117}
118
139 ClientCircuit& circuit,
140 const StdlibVerifierInputs& verifier_inputs,
141 const std::shared_ptr<ClientIVC::RecursiveVerifierInstance>& input_verifier_accumulator,
142 const TableCommitments& T_prev_commitments,
143 const std::shared_ptr<RecursiveTranscript>& accumulation_recursive_transcript)
144{
146
147 // The pairing points produced by the verification of the decider proof
148 PairingPoints decider_pairing_points;
149
150 // Input commitments to be passed to the merge recursive verification
151 MergeCommitments merge_commitments{ .T_prev_commitments = T_prev_commitments };
152
153 auto verifier_instance = std::make_shared<RecursiveVerifierInstance>(&circuit, verifier_inputs.honk_vk_and_hash);
154
156 std::optional<StdlibFF> prev_accum_hash = std::nullopt;
157 // The decider proof exists if the tail kernel has been accumulated
158 bool is_hiding_kernel = !decider_proof.empty();
159
160 switch (verifier_inputs.type) {
161 case QUEUE_TYPE::OINK: {
162 BB_ASSERT_EQ(input_verifier_accumulator, nullptr);
163
164 output_verifier_accumulator = perform_oink_recursive_verification(
165 circuit, verifier_instance, accumulation_recursive_transcript, verifier_inputs.proof);
166
167 // T_prev = 0 in the first recursive verification
168 merge_commitments.T_prev_commitments = stdlib::recursion::honk::empty_ecc_op_tables(circuit);
169 break;
170 }
171 case QUEUE_TYPE::PG:
172 case QUEUE_TYPE::PG_TAIL: {
173 output_verifier_accumulator = perform_pg_recursive_verification(circuit,
174 input_verifier_accumulator,
175 verifier_instance,
176 accumulation_recursive_transcript,
177 verifier_inputs.proof,
178 prev_accum_hash,
179 verifier_inputs.is_kernel);
180 break;
181 }
183 BB_ASSERT_EQ(stdlib_verification_queue.size(), size_t(1));
184
186
187 auto final_verifier_accumulator = perform_pg_recursive_verification(circuit,
188 input_verifier_accumulator,
189 verifier_instance,
190 accumulation_recursive_transcript,
191 verifier_inputs.proof,
192 prev_accum_hash,
193 verifier_inputs.is_kernel);
194 // Perform recursive decider verification
195 DeciderRecursiveVerifier decider{ &circuit, final_verifier_accumulator, accumulation_recursive_transcript };
196 decider_pairing_points = decider.verify_proof(decider_proof);
197
198 BB_ASSERT_EQ(output_verifier_accumulator, nullptr);
199 break;
200 }
201 default: {
202 throw_or_abort("Invalid queue type! Only OINK, PG, PG_TAIL and PG_FINAL are supported");
203 }
204 }
205
206 // Extract the witness commitments and public inputs from the incoming verifier instance
207 WitnessCommitments witness_commitments = std::move(verifier_instance->witness_commitments);
208 std::vector<StdlibFF> public_inputs = std::move(verifier_instance->public_inputs);
209
210 PairingPoints nested_pairing_points; // to be extracted from public inputs of app or kernel proof just verified
211
212 if (verifier_inputs.is_kernel) {
213 // Reconstruct the input from the previous kernel from its public inputs
214 KernelIO kernel_input; // pairing points, databus return data commitments
215 kernel_input.reconstruct_from_public(public_inputs);
216 nested_pairing_points = kernel_input.pairing_inputs;
217 // Perform databus consistency checks
218 kernel_input.kernel_return_data.incomplete_assert_equal(witness_commitments.calldata);
219 kernel_input.app_return_data.incomplete_assert_equal(witness_commitments.secondary_calldata);
220
221 // T_prev is read by the public input of the previous kernel K_{i-1} at the beginning of the recursive
222 // verification of of the folding of K_{i-1} (kernel), A_{i,1} (app), .., A_{i, n} (app). This verification
223 // happens in K_{i}
224 merge_commitments.T_prev_commitments = std::move(kernel_input.ecc_op_tables);
225
226 BB_ASSERT_EQ(verifier_inputs.type == QUEUE_TYPE::PG || verifier_inputs.type == QUEUE_TYPE::PG_TAIL ||
227 verifier_inputs.type == QUEUE_TYPE::PG_FINAL,
228 true,
229 "Kernel circuits should be folded.");
230 // Get the previous accum hash
231 info("PG accum hash from IO: ", kernel_input.output_pg_accum_hash);
232 ASSERT(prev_accum_hash.has_value());
233 kernel_input.output_pg_accum_hash.assert_equal(*prev_accum_hash);
234
235 if (!is_hiding_kernel) {
236 // The hiding kernel has no return data; it uses the traditional public-inputs mechanism
237 bus_depot.set_kernel_return_data_commitment(witness_commitments.return_data);
238 }
239 } else {
240 // Reconstruct the input from the previous app from its public inputs
241 AppIO app_input; // pairing points
242 app_input.reconstruct_from_public(public_inputs);
243 nested_pairing_points = app_input.pairing_inputs;
244
245 // Set the app return data commitment to be propagated via the public inputs
246 bus_depot.set_app_return_data_commitment(witness_commitments.return_data);
247 }
248
249 // Extract the commitments to the subtable corresponding to the incoming circuit
250 merge_commitments.t_commitments = witness_commitments.get_ecc_op_wires().get_copy();
251
252 // Recursively verify the corresponding merge proof
253 auto [pairing_points, merged_table_commitments] =
254 goblin.recursively_verify_merge(circuit, merge_commitments, accumulation_recursive_transcript);
255
256 pairing_points.aggregate(nested_pairing_points);
257 if (is_hiding_kernel) {
258 pairing_points.aggregate(decider_pairing_points);
259 // Add randomness at the end of the hiding kernel (whose ecc ops fall right at the end of the op queue table) to
260 // ensure the CIVC proof doesn't leak information about the actual content of the op queue
262 }
263
264 return { output_verifier_accumulator, pairing_points, merged_table_commitments };
265}
266
276{
277
278 // Transcript to be shared shared across recursive verification of the folding of K_{i-1} (kernel), A_{i,1} (app),
279 // .., A_{i, n} (app) (all circuits accumulated between the previous kernel and current one)
280 auto accumulation_recursive_transcript = std::make_shared<RecursiveTranscript>();
281
282 // Commitment to the previous state of the op_queue in the recursive verification
283 TableCommitments T_prev_commitments;
284
285 // Instantiate stdlib verifier inputs from their native counterparts
286 if (stdlib_verification_queue.empty()) {
288 }
289
290 bool is_init_kernel =
292
293 bool is_tail_kernel =
295
296 bool is_hiding_kernel =
298
299 // The ECC-op subtable for a kernel begins with an eq-and-reset to ensure that the preceeding circuit's subtable
300 // cannot affect the ECC-op accumulator for the kernel. For the tail kernel, we additionally add a preceeding no-op
301 // to ensure the op queue wires in translator are shiftable, i.e. their 0th coefficient is 0. (The tail kernel
302 // subtable is at the top of the final aggregate table since it is the last to be prepended).
303 if (is_tail_kernel) {
304 BB_ASSERT_EQ(circuit.op_queue->get_current_subtable_size(),
305 0U,
306 "tail kernel ecc ops table should be empty at this point");
307 circuit.queue_ecc_no_op();
308 // Add randomness at the begining of the tail kernel (whose ecc ops fall at the beginning of the op queue table)
309 // to ensure the CIVC proof doesn't leak information about the actual content of the op queue
311 }
312 circuit.queue_ecc_eq();
313
314 // Perform Oink/PG and Merge recursive verification + databus consistency checks for each entry in the queue
315 PairingPoints points_accumulator;
316 std::shared_ptr<RecursiveVerifierInstance> current_stdlib_verifier_accumulator = nullptr;
317 if (!is_init_kernel) {
318 current_stdlib_verifier_accumulator =
320 }
321 while (!stdlib_verification_queue.empty()) {
322 const StdlibVerifierInputs& verifier_input = stdlib_verification_queue.front();
323
324 auto [output_stdlib_verifier_accumulator, pairing_points, merged_table_commitments] =
326 verifier_input,
327 current_stdlib_verifier_accumulator,
328 T_prev_commitments,
329 accumulation_recursive_transcript);
330 points_accumulator.aggregate(pairing_points);
331 // Update commitment to the status of the op_queue
332 T_prev_commitments = merged_table_commitments;
333 // Update the output verifier accumulator
334 current_stdlib_verifier_accumulator = output_stdlib_verifier_accumulator;
335
336 stdlib_verification_queue.pop_front();
337 }
338 // Set the kernel output data to be propagated via the public inputs
339 if (is_hiding_kernel) {
340 BB_ASSERT_EQ(current_stdlib_verifier_accumulator, nullptr);
341 HidingKernelIO hiding_output{ points_accumulator, T_prev_commitments };
342 hiding_output.set_public();
343 } else {
344 BB_ASSERT_NEQ(current_stdlib_verifier_accumulator, nullptr);
345 // Extract native verifier accumulator from the stdlib accum for use on the next round
347 std::make_shared<VerifierInstance>(current_stdlib_verifier_accumulator->get_value());
348
349 KernelIO kernel_output;
350 kernel_output.pairing_inputs = points_accumulator;
353 kernel_output.ecc_op_tables = T_prev_commitments;
354 RecursiveTranscript hash_transcript;
355 kernel_output.output_pg_accum_hash =
356 current_stdlib_verifier_accumulator->hash_through_transcript("", hash_transcript);
357 info("kernel output pg hash: ", kernel_output.output_pg_accum_hash);
358 kernel_output.set_public();
359 }
360}
361
362HonkProof ClientIVC::construct_oink_proof(const std::shared_ptr<ProverInstance>& prover_instance,
364 const std::shared_ptr<Transcript>& transcript)
365{
366 vinfo("computing oink proof...");
367 MegaOinkProver oink_prover{ prover_instance, honk_vk, transcript };
368 oink_prover.prove();
369
370 prover_instance->target_sum = 0;
371 // Get the gate challenges for sumcheck/combiner computation
372 prover_instance->gate_challenges =
373 prover_accumulation_transcript->template get_powers_of_challenge<FF>("gate_challenge", CONST_PG_LOG_N);
374
375 prover_accumulator = prover_instance; // initialize the prover accum with the completed key
376
377 HonkProof oink_proof = oink_prover.export_proof();
378 vinfo("oink proof constructed");
379 return oink_proof;
380}
381
382HonkProof ClientIVC::construct_pg_proof(const std::shared_ptr<ProverInstance>& prover_instance,
384 const std::shared_ptr<Transcript>& transcript,
385 bool is_kernel)
386{
387 vinfo("computing pg proof...");
388 // Only fiat shamir if this is a kernel with the assumption that kernels are always the first being recursively
389 // verified.
390 if (is_kernel) {
391 // Fiat-Shamir the verifier accumulator
392 FF accum_hash = native_verifier_accum->hash_through_transcript("", *prover_accumulation_transcript);
393 prover_accumulation_transcript->add_to_hash_buffer("accum_hash", accum_hash);
394 info("Accumulator hash in PG prover: ", accum_hash);
395 }
396 auto verifier_instance = std::make_shared<VerifierInstance_<Flavor>>(honk_vk);
397 FoldingProver folding_prover({ prover_accumulator, prover_instance },
398 { native_verifier_accum, verifier_instance },
401 auto output = folding_prover.prove();
402 prover_accumulator = output.accumulator; // update the prover accumulator
403 vinfo("pg proof constructed");
404 return output.proof;
405}
406
411{
412 // first app
413 if (num_circuits_accumulated == 0) {
414 return QUEUE_TYPE::OINK;
415 }
416 // app (excluding first) or kernel (inner or reset)
418 return QUEUE_TYPE::PG;
419 }
420 // last kernel prior to tail kernel
422 return QUEUE_TYPE::PG_TAIL;
423 }
424 // tail kernel
427 }
428 // hiding kernel
430 return QUEUE_TYPE::MEGA;
431 }
432 return QUEUE_TYPE{};
433}
434
446{
448 num_circuits_accumulated, num_circuits, "ClientIVC: Attempting to accumulate more circuits than expected.");
449
450 ASSERT(precomputed_vk != nullptr, "ClientIVC::accumulate - VK expected for the provided circuit");
451
452 // Construct the prover instance for circuit
453 std::shared_ptr<ProverInstance> prover_instance = std::make_shared<ProverInstance>(circuit, trace_settings);
454
455 // If the current circuit overflows past the current size of the commitment key, reinitialize accordingly.
456 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1319)
457 if (prover_instance->dyadic_size() > bn254_commitment_key.dyadic_size) {
458 bn254_commitment_key = CommitmentKey<curve::BN254>(prover_instance->dyadic_size());
460 }
461 prover_instance->commitment_key = bn254_commitment_key;
463
464 // We're accumulating a kernel if the verification queue is empty (because the kernel circuit contains recursive
465 // verifiers for all the entries previously present in the verification queue) and if it's not the first accumulate
466 // call (which will always be for an app circuit).
467 bool is_kernel = verification_queue.empty() && num_circuits_accumulated > 0;
468
469 // Transcript to be shared across folding of K_{i} (kernel) (the current kernel), A_{i+1,1} (app), .., A_{i+1,
470 // n} (app)
471 if (is_kernel) {
473 }
474
475 // make a copy of the prover_accumulation_transcript for the verifier to use
476 auto verifier_transcript =
478
479 QUEUE_TYPE queue_type = get_queue_type();
480 HonkProof proof;
481 switch (queue_type) {
482 case QUEUE_TYPE::OINK:
483 vinfo("Accumulating first app circuit with OINK");
484 BB_ASSERT_EQ(is_kernel, false, "First circuit accumulated must always be an app");
485 proof = construct_oink_proof(prover_instance, precomputed_vk, prover_accumulation_transcript);
486 break;
487 case QUEUE_TYPE::PG:
489 proof = construct_pg_proof(prover_instance, precomputed_vk, prover_accumulation_transcript, is_kernel);
490 break;
492 proof = construct_pg_proof(prover_instance, precomputed_vk, prover_accumulation_transcript, is_kernel);
494 break;
495 case QUEUE_TYPE::MEGA:
496 proof = construct_honk_proof_for_hiding_kernel(circuit, precomputed_vk);
497 break;
498 }
499
500 VerifierInputs queue_entry{ std::move(proof), precomputed_vk, queue_type, is_kernel };
501 verification_queue.push_back(queue_entry);
502
503 // Update native verifier accumulator and construct merge proof (excluded for hiding kernel since PG terminates with
504 // tail kernel and hiding merge proof is constructed as part of goblin proving)
505 if (queue_entry.type != QUEUE_TYPE::MEGA) {
506 update_native_verifier_accumulator(queue_entry, verifier_transcript);
508 }
509
511}
512
526{
527 Point random_point = Point::random_element();
528 FF random_scalar = FF::random_element();
529 circuit.queue_ecc_mul_accum(random_point, random_scalar);
530 circuit.queue_ecc_eq();
531}
532
583
597
603 ClientCircuit& circuit, const std::shared_ptr<MegaVerificationKey>& verification_key)
604{
605 // Note: a structured trace is not used for the hiding kernel
606 auto hiding_prover_inst = std::make_shared<DeciderZKProvingKey>(circuit, TraceSettings(), bn254_commitment_key);
607
608 // Hiding circuit is proven by a MegaZKProver
609 MegaZKProver prover(hiding_prover_inst, verification_key, transcript);
610 HonkProof proof = prover.construct_proof();
611
612 return proof;
613}
614
621{
622 // deallocate the protogalaxy accumulator
623 prover_accumulator = nullptr;
624 auto mega_proof = verification_queue.front().proof;
625
626 // A transcript is shared between the Hiding circuit prover and the Goblin prover
628
629 // Returns a proof for the hiding circuit and the Goblin proof. The latter consists of Translator and ECCVM proof
630 // for the whole ecc op table and the merge proof for appending the subtable coming from the hiding circuit. The
631 // final merging is done via appending to facilitate creating a zero-knowledge merge proof. This enables us to add
632 // randomness to the beginning of the tail kernel and the end of the hiding kernel, hiding the commitments and
633 // evaluations of both the previous table and the incoming subtable.
634 // https://github.com/AztecProtocol/barretenberg/issues/1360
635 return { mega_proof, goblin.prove(MergeSettings::APPEND) };
636};
637
638bool ClientIVC::verify(const Proof& proof, const VerificationKey& vk)
639{
641 // Create a transcript to be shared by MegaZK-, Merge-, ECCVM-, and Translator- Verifiers.
643 // Verify the hiding circuit proof
644 MegaZKVerifier verifier{ vk.mega, /*ipa_verification_key=*/{}, civc_verifier_transcript };
645 auto [mega_verified, T_prev_commitments] = verifier.template verify_proof<bb::HidingKernelIO>(proof.mega_proof);
646 vinfo("Mega verified: ", mega_verified);
647 // Extract the commitments to the subtable corresponding to the incoming circuit
648 TableCommitments t_commitments = verifier.verifier_instance->witness_commitments.get_ecc_op_wires().get_copy();
649
650 // Goblin verification (final merge, eccvm, translator)
651 bool goblin_verified = Goblin::verify(
652 proof.goblin_proof, { t_commitments, T_prev_commitments }, civc_verifier_transcript, MergeSettings::APPEND);
653 vinfo("Goblin verified: ", goblin_verified);
654
655 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1396): State tracking in CIVC verifiers.
656 return goblin_verified && mega_verified;
657}
658
664HonkProof ClientIVC::construct_decider_proof(const std::shared_ptr<Transcript>& transcript)
665{
666 vinfo("prove decider...");
669 decider_prover.construct_proof();
670 return decider_prover.export_proof();
671}
672
673// Proof methods
675{
676 return mega_proof.size() + goblin_proof.size();
677}
678
680{
681 HonkProof proof;
682
683 proof.insert(proof.end(), mega_proof.begin(), mega_proof.end());
684 proof.insert(proof.end(), goblin_proof.merge_proof.begin(), goblin_proof.merge_proof.end());
685 proof.insert(
686 proof.end(), goblin_proof.eccvm_proof.pre_ipa_proof.begin(), goblin_proof.eccvm_proof.pre_ipa_proof.end());
687 proof.insert(proof.end(), goblin_proof.eccvm_proof.ipa_proof.begin(), goblin_proof.eccvm_proof.ipa_proof.end());
688 proof.insert(proof.end(), goblin_proof.translator_proof.begin(), goblin_proof.translator_proof.end());
689 return proof;
690};
691
693{
694 HonkProof mega_proof;
695 GoblinProof goblin_proof;
696
697 size_t custom_public_inputs_size = fields.size() - ClientIVC::Proof::PROOF_LENGTH();
698
699 // Mega proof
700 auto start_idx = fields.begin();
701 auto end_idx = start_idx + static_cast<std::ptrdiff_t>(
703 bb::HidingKernelIO::PUBLIC_INPUTS_SIZE + custom_public_inputs_size);
704 mega_proof.insert(mega_proof.end(), start_idx, end_idx);
705
706 // Merge proof
707 start_idx = end_idx;
708 end_idx += static_cast<std::ptrdiff_t>(MERGE_PROOF_SIZE);
709 goblin_proof.merge_proof.insert(goblin_proof.merge_proof.end(), start_idx, end_idx);
710
711 // ECCVM pre-ipa proof
712 start_idx = end_idx;
713 end_idx += static_cast<std::ptrdiff_t>(ECCVMFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS - IPA_PROOF_LENGTH);
714 goblin_proof.eccvm_proof.pre_ipa_proof.insert(goblin_proof.eccvm_proof.pre_ipa_proof.end(), start_idx, end_idx);
715
716 // ECCVM ipa proof
717 start_idx = end_idx;
718 end_idx += static_cast<std::ptrdiff_t>(IPA_PROOF_LENGTH);
719 goblin_proof.eccvm_proof.ipa_proof.insert(goblin_proof.eccvm_proof.ipa_proof.end(), start_idx, end_idx);
720
721 // Translator proof
722 start_idx = end_idx;
724 goblin_proof.translator_proof.insert(goblin_proof.translator_proof.end(), start_idx, end_idx);
725
726 return { mega_proof, goblin_proof };
727};
728
730{
731 msgpack::sbuffer buffer;
732 msgpack::pack(buffer, *this);
733 return buffer;
734}
735
737{
738 msgpack::sbuffer buffer = to_msgpack_buffer();
739
740 std::vector<uint8_t> buf(buffer.data(), buffer.data() + buffer.size());
741 return to_heap_buffer(buf);
742}
743
745{
746 auto uint8_buffer = from_buffer<std::vector<uint8_t>>(buffer);
747
748 msgpack::sbuffer sbuf;
749 sbuf.write(reinterpret_cast<char*>(uint8_buffer.data()), uint8_buffer.size());
750
751 return from_msgpack_buffer(sbuf);
752}
753
755{
756 msgpack::object_handle oh = msgpack::unpack(buffer.data(), buffer.size());
757 msgpack::object obj = oh.get();
758 Proof proof;
759 obj.convert(proof);
760 return proof;
761}
762
763void ClientIVC::Proof::to_file_msgpack(const std::string& filename) const
764{
765 msgpack::sbuffer buffer = to_msgpack_buffer();
766 std::ofstream ofs(filename, std::ios::binary);
767 if (!ofs.is_open()) {
768 throw_or_abort("Failed to open file for writing.");
769 }
770 ofs.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
771 ofs.close();
772}
773
775{
776 std::ifstream ifs(filename, std::ios::binary);
777 if (!ifs.is_open()) {
778 throw_or_abort("Failed to open file for reading.");
779 }
780
781 ifs.seekg(0, std::ios::end);
782 size_t file_size = static_cast<size_t>(ifs.tellg());
783 ifs.seekg(0, std::ios::beg);
784
785 std::vector<char> buffer(file_size);
786 ifs.read(buffer.data(), static_cast<std::streamsize>(file_size));
787 ifs.close();
788 msgpack::sbuffer msgpack_buffer;
789 msgpack_buffer.write(buffer.data(), file_size);
790
791 return Proof::from_msgpack_buffer(msgpack_buffer);
792}
793
794// VerificationKey construction
796{
797 BB_ASSERT_EQ(verification_queue.size(), 1UL);
798 BB_ASSERT_EQ(verification_queue.front().type == QUEUE_TYPE::MEGA, true);
799 auto verification_key = verification_queue.front().honk_vk;
800 return { verification_key,
803}
804
806 const std::shared_ptr<Transcript>& verifier_transcript)
807{
808 auto verifier_inst = std::make_shared<VerifierInstance>(queue_entry.honk_vk);
809 if (queue_entry.type == QUEUE_TYPE::OINK) {
810 verifier_transcript->load_proof(queue_entry.proof);
811 OinkVerifier<Flavor> oink_verifier{ verifier_inst, verifier_transcript };
812 oink_verifier.verify();
813 native_verifier_accum = verifier_inst;
814 native_verifier_accum->target_sum = 0;
815 // Get the gate challenges for sumcheck/combiner computation
816 native_verifier_accum->gate_challenges =
817 verifier_transcript->template get_powers_of_challenge<FF>("gate_challenge", CONST_PG_LOG_N);
818 } else {
819 if (queue_entry.is_kernel) {
820 // Fiat-Shamir the verifier accumulator
821 FF accum_hash = native_verifier_accum->hash_through_transcript("", *verifier_transcript);
822 verifier_transcript->add_to_hash_buffer("accum_hash", accum_hash);
823 info("Accumulator hash in PG verifier: ", accum_hash);
824 }
825 FoldingVerifier folding_verifier({ native_verifier_accum, verifier_inst }, verifier_transcript);
826 native_verifier_accum = folding_verifier.verify_folding_proof(queue_entry.proof);
827 }
828}
829
830} // namespace bb
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:118
#define BB_ASSERT_NEQ(actual, expected,...)
Definition assert.hpp:103
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:88
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:148
#define ASSERT(expression,...)
Definition assert.hpp:77
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
static std::shared_ptr< BaseTranscript > convert_prover_transcript_to_verifier_transcript(const std::shared_ptr< BaseTranscript > &prover_transcript)
Convert a prover transcript to a verifier transcript.
Proof prove()
Construct a proof for the IVC, which, if verified, fully establishes its correctness.
static void hide_op_queue_accumulation_result(ClientCircuit &circuit)
Add a valid operation with random data to the op queue to prevent information leakage in Translator p...
static void hide_op_queue_content_in_tail(ClientCircuit &circuit)
Adds three random ops to the tail kernel.
MegaFlavor::CommitmentKey bn254_commitment_key
TraceSettings trace_settings
std::shared_ptr< Transcript > prover_accumulation_transcript
ExecutionTraceUsageTracker trace_usage_tracker
HonkProof construct_honk_proof_for_hiding_kernel(ClientCircuit &circuit, const std::shared_ptr< MegaVerificationKey > &verification_key)
Construct a zero-knowledge proof for the hiding circuit, which recursively verifies the last folding,...
std::shared_ptr< VerifierInstance > recursive_verifier_native_accum
HonkProof construct_decider_proof(const std::shared_ptr< Transcript > &transcript)
Internal method for constructing a decider proof.
std::shared_ptr< ProverInstance > prover_accumulator
QUEUE_TYPE get_queue_type() const
Get queue type for the proof of a circuit about to be accumulated based on num circuits accumulated s...
VerificationKey get_vk() const
std::tuple< std::shared_ptr< RecursiveVerifierInstance >, PairingPoints, TableCommitments > perform_recursive_verification_and_databus_consistency_checks(ClientCircuit &circuit, const StdlibVerifierInputs &verifier_inputs, const std::shared_ptr< RecursiveVerifierInstance > &input_verifier_accumulator, const TableCommitments &T_prev_commitments, const std::shared_ptr< RecursiveTranscript > &accumulation_recursive_transcript)
Populate the provided circuit with constraints for (1) recursive verification of the provided accumul...
static void hide_op_queue_content_in_hiding(ClientCircuit &circuit)
Adds two random ops to the hiding kernel.
static std::shared_ptr< RecursiveVerifierInstance > perform_oink_recursive_verification(ClientCircuit &circuit, const std::shared_ptr< RecursiveVerifierInstance > &verifier_instance, const std::shared_ptr< RecursiveTranscript > &transcript, const StdlibProof &proof)
size_t num_circuits
void complete_kernel_circuit_logic(ClientCircuit &circuit)
Append logic to complete a kernel circuit.
Flavor::Curve::AffineElement Point
void accumulate(ClientCircuit &circuit, const std::shared_ptr< MegaVerificationKey > &precomputed_vk) override
Perform prover work for accumulation (e.g. PG folding, merge proving)
HonkProof construct_pg_proof(const std::shared_ptr< ProverInstance > &prover_instance, const std::shared_ptr< MegaVerificationKey > &honk_vk, const std::shared_ptr< Transcript > &transcript, bool is_kernel)
size_t num_circuits_accumulated
void update_native_verifier_accumulator(const VerifierInputs &queue_entry, const std::shared_ptr< Transcript > &verifier_transcript)
Runs either Oink or PG native verifier to update the native verifier accumulator.
ClientIVC(size_t num_circuits, TraceSettings trace_settings={})
VerificationQueue verification_queue
HonkProof construct_oink_proof(const std::shared_ptr< ProverInstance > &prover_instance, const std::shared_ptr< MegaVerificationKey > &honk_vk, const std::shared_ptr< Transcript > &transcript)
std::shared_ptr< VerifierInstance > native_verifier_accum
StdlibVerificationQueue stdlib_verification_queue
HonkProof decider_proof
std::array< RecursiveFlavor::Commitment, ClientCircuit::NUM_WIRES > TableCommitments
std::shared_ptr< Transcript > transcript
static bool verify(const Proof &proof, const VerificationKey &vk)
void instantiate_stdlib_verification_queue(ClientCircuit &circuit, const std::vector< std::shared_ptr< RecursiveVKAndHash > > &input_keys={})
Instantiate a stdlib verification queue for use in the kernel completion logic.
DataBusDepot bus_depot
stdlib::recursion::PairingPoints< ClientCircuit > PairingPoints
static std::shared_ptr< RecursiveVerifierInstance > perform_pg_recursive_verification(ClientCircuit &circuit, const std::shared_ptr< RecursiveVerifierInstance > &verifier_accumulator, const std::shared_ptr< RecursiveVerifierInstance > &verifier_instance, const std::shared_ptr< RecursiveTranscript > &transcript, const StdlibProof &proof, std::optional< StdlibFF > &prev_accum_hash, bool is_kernel)
CommitmentKey object over a pairing group 𝔾₁.
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS
static bool verify(const GoblinProof &proof, const MergeCommitments &merge_commitments, const std::shared_ptr< Transcript > &transcript, const MergeSettings merge_settings=MergeSettings::PREPEND)
Verify a full Goblin proof (ECCVM, Translator, merge)
Definition goblin.cpp:93
std::pair< PairingPoints, RecursiveTableCommitments > recursively_verify_merge(MegaBuilder &builder, const RecursiveMergeCommitments &merge_commitments, const std::shared_ptr< RecursiveTranscript > &transcript, const MergeSettings merge_settings=MergeSettings::PREPEND)
Recursively verify the next merge proof in the merge verification queue.
Definition goblin.cpp:73
MergeVerifier::TableCommitments TableCommitments
Definition goblin.hpp:41
void prove_merge(const std::shared_ptr< Transcript > &transcript=std::make_shared< Transcript >(), const MergeSettings merge_settings=MergeSettings::PREPEND)
Construct a merge proof for the goblin ECC ops in the provided circuit; append the proof to the merge...
Definition goblin.cpp:25
GoblinProof prove(const MergeSettings merge_settings=MergeSettings::PREPEND)
Constuct a full Goblin proof (ECCVM, Translator, merge)
Definition goblin.cpp:52
CommitmentKey< curve::BN254 > commitment_key
Definition goblin.hpp:49
std::shared_ptr< Transcript > transcript
Definition goblin.hpp:55
static constexpr size_t PUBLIC_INPUTS_SIZE
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_mul_accum(const g1::affine_element &point, const FF &scalar, bool in_finalize=false)
Add point mul-then-accumulate operation to the op queue and add corresponding gates.
std::shared_ptr< ECCOpQueue > op_queue
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...
ecc_op_tuple queue_ecc_no_op()
Logic for a no-op operation.
Container for all witness polynomials used/constructed by the prover.
static constexpr size_t VIRTUAL_LOG_N
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS(size_t virtual_log_n=MegaFlavor::VIRTUAL_LOG_N)
Class for all the oink rounds, which are shared between the folding prover and ultra prover.
void prove()
Oink Prover function that runs all the rounds of the verifier.
Verifier class for all the presumcheck rounds, which are shared between the folding verifier and ultr...
void verify()
Oink Verifier function that runs all the rounds of the verifier.
BB_PROFILE FoldingResult< Flavor > prove()
Execute the folding prover.
std::shared_ptr< VerifierInstance > verify_folding_proof(const std::vector< FF > &)
Run the folding protocol on the verifier side to establish whether the public data ϕ of the new accum...
static constexpr size_t CONST_TRANSLATOR_LOG_N
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS
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:128
Commitment get_app_return_data_commitment(Builder &builder)
Get the previously set app return data commitment if it exists, else a default one.
Definition databus.hpp:141
void set_app_return_data_commitment(const Commitment &commitment)
Definition databus.hpp:105
void set_kernel_return_data_commitment(const Commitment &commitment)
Definition databus.hpp:99
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.
void set_public()
Set each IO component to be a public input of the underlying circuit.
#define vinfo(...)
Definition log.hpp:79
void info(Args... args)
Definition log.hpp:74
uint8_t const * buf
Definition data_store.hpp:9
uint8_t buffer[RANDOM_BUFFER_SIZE]
Definition engine.cpp:34
std::array< typename bn254< Builder >::Group, Builder::NUM_WIRES > empty_ecc_op_tables(Builder &builder)
Construct commitments to empty subtables.
Entry point for Barretenberg command-line interface.
std::vector< fr > HonkProof
Definition proof.hpp:15
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
uint8_t * to_heap_buffer(T const &value)
A full proof for the IVC scheme containing a Mega proof showing correctness of the hiding circuit (wh...
void to_file_msgpack(const std::string &filename) const
static Proof from_msgpack_buffer(uint8_t const *&buffer)
std::vector< FF > to_field_elements() const
Serialize proof to field elements.
uint8_t * to_msgpack_heap_buffer() const
Very quirky method to convert a msgpack buffer to a "heap" buffer.
static constexpr size_t PROOF_LENGTH(size_t virtual_log_n=MegaZKFlavor::VIRTUAL_LOG_N)
The size of a ClientIVC proof with backend-added public inputs: HidingKernelIO.
size_t size() const
static Proof from_file_msgpack(const std::string &filename)
msgpack::sbuffer to_msgpack_buffer() const
static Proof from_field_elements(const std::vector< ClientIVC::FF > &fields)
GoblinProof goblin_proof
std::shared_ptr< RecursiveVKAndHash > honk_vk_and_hash
std::shared_ptr< MegaVerificationKey > honk_vk
HonkProof pre_ipa_proof
Definition proof.hpp:24
HonkProof ipa_proof
Definition proof.hpp:25
ECCVMProof eccvm_proof
Definition types.hpp:22
HonkProof merge_proof
Definition types.hpp:21
size_t size() const
Definition types.hpp:25
HonkProof translator_proof
Definition types.hpp:23
static field random_element(numeric::RNG *engine=nullptr) noexcept
An object storing two EC points that represent the inputs to a pairing check.
void aggregate(PairingPoints const &other)
Compute a linear combination of the present pairing points with an input set of pairing points.
uint32_t set_public()
Set the witness indices for the limbs of the pairing points to public.
void throw_or_abort(std::string const &err)