Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
hypernova_recursion_constraint.test.cpp
Go to the documentation of this file.
2#include "acir_format.hpp"
14
15#include <gtest/gtest.h>
16#include <vector>
17
18using namespace acir_format;
19using namespace bb;
20
21class HypernovaRecursionConstraintTest : public ::testing::Test {
22
23 public:
25 using FF = Chonk::FF;
28
41
43 {
45 builder.op_queue = std::make_shared<ECCOpQueue>(*builder.op_queue);
46 return dispatch_kind(kind, [&]<CircuitKind K>() {
47 using FlavorT = flavor_for<K>;
48 using VK = typename FlavorT::VerificationKey;
50 ProverInstance_<FlavorT>(builder).get_precomputed()) };
51 });
52 }
53
55 {
56
57 // Reset-tail kernel: verifies a single previous-kernel proof
58 EXPECT_EQ(ivc->verification_queue.size(), 1);
59 EXPECT_EQ(ivc->verification_queue[0].kind, CircuitKind::Kernel);
61
62 // Hiding kernel: verifies the tail kernel's proof
63 EXPECT_EQ(ivc->verification_queue.size(), 1);
64 EXPECT_EQ(ivc->verification_queue[0].kind, CircuitKind::Kernel);
66 }
67
68 static UltraCircuitBuilder create_inner_circuit(size_t log_num_gates = 10)
69 {
71
72 // Create 2^log_n many add gates based on input log num gates
73 const size_t num_gates = (1 << log_num_gates);
74 for (size_t i = 0; i < num_gates; ++i) {
76 uint32_t a_idx = builder.add_variable(a);
77
80 fr d = a + b + c;
81 uint32_t b_idx = builder.add_variable(b);
82 uint32_t c_idx = builder.add_variable(c);
83 uint32_t d_idx = builder.add_variable(d);
84
85 builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) });
86 }
87
89 return builder;
90 }
91
97 {
98 AcirProgram program;
99 std::vector<RecursionConstraint> recursion_constraints;
100
101 Builder circuit{ ivc->goblin.op_queue };
104
105 {
106 using RecursiveFlavor = UltraRecursiveFlavor_<Builder>;
108 using StdlibProof = bb::stdlib::Proof<Builder>;
110
111 // Create an arbitrary inner circuit
112 auto inner_circuit = create_inner_circuit();
113
114 // Compute native verification key
115 auto prover_instance = std::make_shared<ProverInstance_<UltraFlavor>>(inner_circuit);
116 auto honk_vk = std::make_shared<UltraFlavor::VerificationKey>(prover_instance->get_precomputed());
117 UltraProver prover(prover_instance, honk_vk); // A prerequisite for computing VK
118 auto inner_proof = prover.construct_proof();
119
120 if (tamper_vk) {
121 honk_vk->q_l() = g1::one;
122 auto honk_vk_and_hash = std::make_shared<UltraFlavor::VKAndHash>(honk_vk);
123 UltraVerifier_<UltraFlavor, DefaultIO> verifier(honk_vk_and_hash);
124 EXPECT_FALSE(verifier.verify_proof(inner_proof).result);
125 }
126 // Instantiate the recursive verifier using the native verification key
127 auto stdlib_vk_and_hash = std::make_shared<RecursiveFlavor::VKAndHash>(circuit, honk_vk);
128 bb::UltraVerifier_<RecursiveFlavor, StdlibIO> verifier(stdlib_vk_and_hash);
129
130 StdlibProof stdlib_inner_proof(circuit, inner_proof);
131 VerifierOutput output = verifier.verify_proof(stdlib_inner_proof);
132
133 // IO
134 StdlibIO inputs;
135 inputs.pairing_inputs = output.points_accumulator;
136 inputs.set_public(); // propagate resulting pairing points on the public inputs
137 }
138
139 return circuit;
140 }
141
151 PROOF_TYPE proof_type,
152 std::vector<FF>& witness)
153 {
154 auto fields = input.vk_to_field_elements();
155 auto hash = input.vk_hash();
156 RecursionConstraint constraint =
158 input.proof, // proof contains the public inputs at this stage
159 fields,
160 hash,
161 bb::fr::zero(),
162 /*num_public_inputs_to_extract=*/0,
163 proof_type);
164
165 constraint.proof = {}; // the proof witness indices are not needed in an ivc recursion constraint
166
167 return constraint;
168 }
169
177 {
179 constraints.reserve(proof_types.size());
180 for (PROOF_TYPE proof_type : proof_types) {
181 RecursionConstraint constraint;
182 constraint.proof_type = proof_type;
183 constraints.push_back(constraint);
184 }
185 return constraints;
186 }
187
202 {
203 AcirProgram program;
204
205 // Derive the ACIR proof_type for each queued proof the same way the verifier-side cross-check expects:
206 // the init kernel's first app is OINK, the hiding kernel verifies the tail via HN_FINAL, every other
207 // proof is HN. is_init is read from the (still-native) queue front; is_hiding from the IVC's circuit kinds.
208 const auto& verification_queue = ivc->verification_queue;
209 const bool is_init = !verification_queue.empty() && verification_queue.front().kind == CircuitKind::App;
210 const bool is_hiding = ivc->is_hiding_kernel();
211
212 // Construct recursion constraints based on the ivc verification queue; populate the witness along the way
213 std::vector<RecursionConstraint> hn_recursion_constraints;
214 hn_recursion_constraints.reserve(verification_queue.size());
215 for (size_t idx = 0; idx < verification_queue.size(); ++idx) {
216 PROOF_TYPE proof_type;
217 if (is_hiding) {
219 verification_queue.size(), 1U, "The hiding kernel should recursively verify only one proof.");
220 proof_type = PROOF_TYPE::HN_FINAL;
221 } else if (is_init && idx == 0) {
222 proof_type = PROOF_TYPE::OINK;
223 } else {
224 proof_type = PROOF_TYPE::HN;
225 }
226 hn_recursion_constraints.push_back(
227 create_recursion_constraint(verification_queue[idx], proof_type, program.witness));
228 }
229
230 // Construct a constraint system containing the business logic and ivc recursion constraints
231 program.constraints.max_witness_index = static_cast<uint32_t>(program.witness.size() - 1);
232 program.constraints.num_acir_opcodes = static_cast<uint32_t>(hn_recursion_constraints.size());
233 program.constraints.hn_recursion_constraints = hn_recursion_constraints;
234 for (size_t idx = 0; idx < hn_recursion_constraints.size(); ++idx) {
235 program.constraints.original_opcode_indices.hn_recursion_constraints.push_back(static_cast<uint32_t>(idx));
236 }
237
238 return program;
239 }
240
242 {
243 BB_ASSERT_NEQ(ivc->current_kind(), CircuitKind::App);
244 // construct a mock kernel program (acir) from the ivc verification queue
245 const ProgramMetadata metadata{ ivc };
246 AcirProgram mock_kernel_program = construct_mock_kernel_program(ivc);
247 auto kernel = acir_format::create_circuit<Builder>(mock_kernel_program, metadata);
248 // Build the VK in the flavor matching the current kind (Kernel / HidingKernel) from the kernel circuit.
249 Chonk::CircuitVerificationKey vk = dispatch_kind(ivc->current_kind(), [&]<CircuitKind K>() {
250 using FlavorT = flavor_for<K>;
251 using VK = typename FlavorT::VerificationKey;
252 return Chonk::CircuitVerificationKey{ std::make_shared<VK>(
253 ProverInstance_<FlavorT>(kernel).get_precomputed()) };
254 });
255 ivc->accumulate(kernel, vk);
256 }
257
259 {
260 BB_ASSERT_EQ(ivc->current_kind(), CircuitKind::App);
261 auto app_circuit = construct_mock_app_circuit(ivc);
262 ivc->accumulate(app_circuit, make_circuit_vk(app_circuit, ivc->current_kind()));
263 }
264
270 {
271 auto kernel = acir_format::create_circuit<Builder>(program);
273 ProverInstance_<Chonk::KernelFlavor>(kernel).get_precomputed());
274 }
275
276 // ---------------------------------------------------------------------------------------------
277 // Per-kernel-type scenario helpers
278 //
279 // Each kernel type is exercised two ways and the results compared:
280 // - real_*_vk: run the actual IVC over mock app/kernel circuits up to the target kernel and read its VK.
281 // - mock_*_vk: build the target kernel's VK through the production write-VK path, i.e. from the recursion
282 // constraints' proof types via create_mock_chonk_from_constraints.
283 // ---------------------------------------------------------------------------------------------
284
285 // Proof types Noir emits for an init kernel verifying `num_apps` leading apps: the first via OINK, the rest HN.
287 {
288 std::vector<PROOF_TYPE> proof_types(num_apps, PROOF_TYPE::HN);
289 proof_types.front() = PROOF_TYPE::OINK;
290 return proof_types;
291 }
292
293 // Proof types Noir emits for an inner kernel verifying the previous kernel (HN) followed by `num_apps` apps (HN).
295 {
296 return std::vector<PROOF_TYPE>(num_apps + 1, PROOF_TYPE::HN);
297 }
298
299 // Build a kernel VK from recursion constraints via the production write-VK path.
301 {
302 auto ivc = create_mock_chonk_from_constraints(make_hn_recursion_constraints(proof_types));
303 AcirProgram program = construct_mock_kernel_program(ivc);
304 program.witness = {}; // remove the witness to mimic the VK construction context
305 return construct_kernel_vk_from_acir_program(program);
306 }
307
308 // Build the hiding kernel's (MegaZK) VK from recursion constraints via the production write-VK path.
310 {
311 auto ivc = create_mock_chonk_from_constraints(make_hn_recursion_constraints({ PROOF_TYPE::HN_FINAL }));
312 AcirProgram program = construct_mock_kernel_program(ivc);
313 program.witness = {};
314 auto kernel = acir_format::create_circuit<Builder>(program);
316 Chonk::HidingKernelProverInstance(kernel).get_precomputed());
317 }
318
321 size_t gate_count; // total kernel-completion gates (attributed to the first recursion opcode)
322 size_t ecc_rows;
323 size_t ultra_ops;
324 };
325
326 // Build a kernel via the production write-VK path with gate counting enabled and report its gate/ECC/op counts.
328 {
329 auto ivc = create_mock_chonk_from_constraints(make_hn_recursion_constraints(proof_types));
330 AcirProgram program = construct_mock_kernel_program(ivc);
331 ProgramMetadata metadata{ .ivc = ivc, .collect_gates_per_opcode = true };
332 auto kernel = acir_format::create_circuit<Builder>(program, metadata);
333 return { program.constraints.gates_per_opcode.size(),
334 program.constraints.gates_per_opcode.empty() ? 0 : program.constraints.gates_per_opcode[0],
335 kernel.op_queue->get_num_rows(),
336 kernel.op_queue->get_current_subtable_size() };
337 }
338
339 // Real-IVC VK for an init kernel verifying `num_apps` leading apps.
341 {
342 std::vector<CircuitKind> kinds(num_apps, CircuitKind::App);
343 kinds.push_back(CircuitKind::Kernel); // init kernel (target)
344 kinds.push_back(CircuitKind::Kernel); // tail kernel
345 kinds.push_back(CircuitKind::HidingKernel); // hiding kernel
346 auto ivc = std::make_shared<Chonk>(kinds);
347 for (size_t i = 0; i < num_apps; ++i) {
348 construct_and_accumulate_mock_app(ivc);
349 }
350 construct_and_accumulate_mock_kernel(ivc); // init kernel verifying the leading apps
351 return ivc->verification_queue.back().kernel_honk_vk;
352 }
353
354 // Real-IVC VK for an inner kernel verifying the previous kernel plus `num_apps` apps.
356 {
357 std::vector<CircuitKind> kinds = { CircuitKind::App, CircuitKind::Kernel }; // App0 + init kernel
358 kinds.insert(kinds.end(), num_apps, CircuitKind::App); // the inner kernel's apps
359 kinds.push_back(CircuitKind::Kernel); // inner kernel (target)
360 kinds.push_back(CircuitKind::Kernel); // tail kernel
361 kinds.push_back(CircuitKind::HidingKernel); // hiding kernel
362 auto ivc = std::make_shared<Chonk>(kinds);
363 construct_and_accumulate_mock_app(ivc); // App0
364 construct_and_accumulate_mock_kernel(ivc); // init kernel (verifies App0)
365 for (size_t i = 0; i < num_apps; ++i) {
366 construct_and_accumulate_mock_app(ivc);
367 }
368 construct_and_accumulate_mock_kernel(ivc); // inner kernel verifying the previous kernel + apps
369 return ivc->verification_queue.back().kernel_honk_vk;
370 }
371
372 // Real-IVC VK for a reset/tail kernel verifying only the previous kernel.
374 {
375 auto ivc = std::make_shared<Chonk>(std::vector<CircuitKind>{ CircuitKind::App,
376 CircuitKind::Kernel,
377 CircuitKind::Kernel,
378 CircuitKind::Kernel,
379 CircuitKind::HidingKernel });
380 construct_and_accumulate_mock_app(ivc); // App0
381 construct_and_accumulate_mock_kernel(ivc); // init kernel (verifies App0)
382 construct_and_accumulate_mock_kernel(ivc); // reset/tail kernel (verifies only the previous kernel)
383 return ivc->verification_queue.back().kernel_honk_vk;
384 }
385
386 // Real-IVC (MegaZK) VK for the hiding kernel.
388 {
389 auto ivc = std::make_shared<Chonk>(std::vector<CircuitKind>{
390 CircuitKind::App, CircuitKind::Kernel, CircuitKind::Kernel, CircuitKind::HidingKernel });
391 construct_and_accumulate_mock_app(ivc);
392 construct_and_accumulate_mock_kernel(ivc); // init kernel
393 construct_and_accumulate_trailing_kernels(ivc); // reset-tail + hiding kernels
394 return ivc->hiding_vk;
395 }
396
397 protected:
399};
400
405{
407 EXPECT_EQ(merge_proof.size(), MERGE_PROOF_SIZE);
408}
409
415{
416 auto ivc = std::make_shared<Chonk>(std::vector<CircuitKind>{
417 CircuitKind::App, CircuitKind::Kernel, CircuitKind::Kernel, CircuitKind::HidingKernel });
418
419 // construct a mock app_circuit
420 construct_and_accumulate_mock_app(ivc);
421
422 // Construct kernel consisting only of the kernel completion logic
423 construct_and_accumulate_mock_kernel(ivc);
424
425 // add the trailing kernels
426 construct_and_accumulate_trailing_kernels(ivc);
427
428 auto proof = ivc->prove();
429 {
430 auto vk_and_hash = ivc->get_hiding_kernel_vk_and_hash();
431 ChonkNativeVerifier verifier(vk_and_hash);
432 EXPECT_TRUE(verifier.verify(proof));
433 }
434}
435
441{
442 // app, kernel, app, kernel, then the trailing reset, tail and hiding kernels
443 auto ivc = std::make_shared<Chonk>(std::vector<CircuitKind>{ CircuitKind::App,
444 CircuitKind::Kernel,
445 CircuitKind::App,
446 CircuitKind::Kernel,
447 CircuitKind::Kernel,
448 CircuitKind::HidingKernel });
449
450 // construct a mock app_circuit
451 construct_and_accumulate_mock_app(ivc);
452
453 const ProgramMetadata metadata{ ivc };
454
455 // Construct kernel_0; consists of a single oink recursive verification for app (plus databus/merge logic)
456 construct_and_accumulate_mock_kernel(ivc);
457
458 // construct a mock app_circuit
459 construct_and_accumulate_mock_app(ivc);
460
461 // Construct and accumulate another Kernel circuit
462 construct_and_accumulate_mock_kernel(ivc);
463
464 // Accumulate the trailing kernels
465 construct_and_accumulate_trailing_kernels(ivc);
466
467 auto proof = ivc->prove();
468 {
469 ChonkNativeVerifier verifier(ivc->get_hiding_kernel_vk_and_hash());
470 EXPECT_TRUE(verifier.verify(proof));
471 }
472}
473
474// VK pinning: the kernel VK built from the recursion constraints (production write-VK path) must match the VK
475// from a real IVC run, for an init kernel verifying 1..MAX_APPS_PER_KERNEL leading apps.
476TEST_F(HypernovaRecursionConstraintTest, GenerateInitKernelVKFromConstraints)
477{
479 for (size_t num_apps = 1; num_apps <= MAX_APPS_PER_KERNEL; ++num_apps) {
480 auto expected_kernel_vk = real_init_kernel_vk(num_apps);
481 auto kernel_vk = mock_kernel_vk(init_kernel_proof_types(num_apps));
482 EXPECT_EQ(*kernel_vk, *expected_kernel_vk) << "init kernel VK mismatch for " << num_apps << " app(s)";
483 }
484}
485
486// VK pinning for an inner kernel verifying the previous kernel plus 1..MAX_APPS_PER_KERNEL apps.
487TEST_F(HypernovaRecursionConstraintTest, GenerateInnerKernelVKFromConstraints)
488{
490 for (size_t num_apps = 1; num_apps <= MAX_APPS_PER_KERNEL; ++num_apps) {
491 auto expected_kernel_vk = real_inner_kernel_vk(num_apps);
492 auto kernel_vk = mock_kernel_vk(inner_kernel_proof_types(num_apps));
493 EXPECT_EQ(*kernel_vk, *expected_kernel_vk) << "inner kernel VK mismatch for " << num_apps << " app(s)";
494 }
495}
496
497// VK pinning for a reset or tail kernel: verifies a single previous-kernel HN proof.
498TEST_F(HypernovaRecursionConstraintTest, GenerateResetTailKernelVKFromConstraints)
499{
501 auto expected_kernel_vk = real_reset_tail_kernel_vk();
502 auto kernel_vk = mock_kernel_vk({ PROOF_TYPE::HN });
503 EXPECT_EQ(*kernel_vk, *expected_kernel_vk);
504}
505
506// VK pinning for the hiding kernel (MegaZK), which verifies the tail kernel's HN_FINAL proof.
507TEST_F(HypernovaRecursionConstraintTest, GenerateHidingKernelVKFromConstraints)
508{
510 auto expected_hiding_kernel_vk = real_hiding_kernel_vk();
511 auto kernel_vk = mock_hiding_kernel_vk();
512 EXPECT_EQ(*kernel_vk, *expected_hiding_kernel_vk);
513}
514
518TEST_F(HypernovaRecursionConstraintTest, RecursiveVerifierAppCircuit)
519{
520 auto ivc = std::make_shared<Chonk>(std::vector<CircuitKind>{
521 CircuitKind::App, CircuitKind::Kernel, CircuitKind::Kernel, CircuitKind::HidingKernel });
522
523 // construct a mock app_circuit with an UH recursion call
524 Builder app_circuit = construct_mock_UH_recursion_app_circuit(ivc, /*tamper_vk=*/false);
525
526 // Complete instance and generate an oink proof
527 {
528 ivc->accumulate(app_circuit, make_circuit_vk(app_circuit, ivc->current_kind()));
529 }
530
531 // Construct kernel consisting only of the kernel completion logic
532 construct_and_accumulate_mock_kernel(ivc);
533
534 construct_and_accumulate_trailing_kernels(ivc);
535
536 auto proof = ivc->prove();
537 {
538 ChonkNativeVerifier verifier(ivc->get_hiding_kernel_vk_and_hash());
539 EXPECT_TRUE(verifier.verify(proof));
540 }
541}
542
547TEST_F(HypernovaRecursionConstraintTest, RecursiveVerifierAppCircuitFailure)
548{
549 BB_DISABLE_ASSERTS(); // Disable assert in HN prover
550
551 auto ivc = std::make_shared<Chonk>(std::vector<CircuitKind>{
552 CircuitKind::App, CircuitKind::Kernel, CircuitKind::Kernel, CircuitKind::HidingKernel });
553
554 // construct and accumulate mock app_circuit that has bad pairing point object
555 Builder app_circuit = construct_mock_UH_recursion_app_circuit(ivc, /*tamper_vk=*/true);
556 {
557 ivc->accumulate(app_circuit, make_circuit_vk(app_circuit, ivc->current_kind()));
558 }
559
560 // Construct kernel consisting only of the kernel completion logic
561 construct_and_accumulate_mock_kernel(ivc);
562
563 // add the trailing kernels
564 construct_and_accumulate_trailing_kernels(ivc);
565
566 // We expect the Chonk proof to fail due to the app with a failed UH recursive verification
567 auto proof = ivc->prove();
568 {
569 ChonkNativeVerifier verifier(ivc->get_hiding_kernel_vk_and_hash());
570 EXPECT_FALSE(verifier.verify(proof));
571 }
572}
573
578{
580 for (size_t num_apps = 1; num_apps <= MAX_APPS_PER_KERNEL; ++num_apps) {
581 auto counts = mock_kernel_gate_counts(init_kernel_proof_types(num_apps));
582 EXPECT_EQ(counts.num_opcodes, num_apps) << "init kernel, " << num_apps << " app(s)";
583 EXPECT_EQ(counts.gate_count, INIT_KERNEL_GATE_COUNT[num_apps - 1]) << "init kernel, " << num_apps << " app(s)";
584 EXPECT_EQ(counts.ecc_rows, INIT_KERNEL_ECC_ROWS[num_apps - 1] + MSM_ROWS_OFFSET)
585 << "init kernel, " << num_apps << " app(s)";
586 EXPECT_EQ(counts.ultra_ops, INIT_KERNEL_ULTRA_OPS[num_apps - 1]) << "init kernel, " << num_apps << " app(s)";
587 }
588}
589
595{
597 for (size_t num_apps = 1; num_apps <= MAX_APPS_PER_KERNEL; ++num_apps) {
598 auto counts = mock_kernel_gate_counts(inner_kernel_proof_types(num_apps));
599 EXPECT_EQ(counts.num_opcodes, num_apps + 1) << "inner kernel, " << num_apps << " app(s)";
600 EXPECT_EQ(counts.gate_count, INNER_KERNEL_GATE_COUNT[num_apps - 1])
601 << "inner kernel, " << num_apps << " app(s)";
602 EXPECT_EQ(counts.ecc_rows, INNER_KERNEL_ECC_ROWS[num_apps - 1] + MSM_ROWS_OFFSET)
603 << "inner kernel, " << num_apps << " app(s)";
604 EXPECT_EQ(counts.ultra_ops, INNER_KERNEL_ULTRA_OPS[num_apps - 1]) << "inner kernel, " << num_apps << " app(s)";
605 }
606}
607
611TEST_F(HypernovaRecursionConstraintTest, ResetTailKernelGateCount)
612{
614 auto counts = mock_kernel_gate_counts({ PROOF_TYPE::HN });
615 EXPECT_EQ(counts.num_opcodes, 1U);
616 EXPECT_EQ(counts.gate_count, RESET_TAIL_KERNEL_GATE_COUNT);
617 EXPECT_EQ(counts.ecc_rows, RESET_TAIL_KERNEL_ECC_ROWS + MSM_ROWS_OFFSET);
618 EXPECT_EQ(counts.ultra_ops, RESET_TAIL_KERNEL_ULTRA_OPS);
619}
620
626{
628 auto counts = mock_kernel_gate_counts({ PROOF_TYPE::HN_FINAL });
629 EXPECT_EQ(counts.num_opcodes, 1U);
630 EXPECT_EQ(counts.gate_count, HIDING_KERNEL_GATE_COUNT);
631 EXPECT_EQ(counts.ecc_rows, HIDING_KERNEL_ECC_ROWS + MSM_ROWS_OFFSET);
632 EXPECT_EQ(counts.ultra_ops, bb::HIDING_KERNEL_ULTRA_OPS);
633}
634
635// =====================================================================================
636// Boundary check failure tests - verify that invalid inputs are rejected
637// =====================================================================================
638
642TEST_F(HypernovaRecursionConstraintTest, FailsOnConstraintIndicesSizeMismatch)
643{
644 auto ivc = create_mock_chonk_from_constraints(make_hn_recursion_constraints({ PROOF_TYPE::OINK }));
645
646 AcirProgram program = construct_mock_kernel_program(ivc);
647
648 // Corrupt the opcode indices to have wrong size
650
651 ProgramMetadata metadata{ .ivc = ivc };
652
653 EXPECT_THROW_WITH_MESSAGE(acir_format::create_circuit<Builder>(program, metadata),
654 "hn_recursion_data constraints/indices size mismatch");
655}
656
660TEST_F(HypernovaRecursionConstraintTest, FailsOnAcirQueueSizeMismatch)
661{
662 auto ivc = create_mock_chonk_from_constraints(make_hn_recursion_constraints({ PROOF_TYPE::OINK }));
663
664 AcirProgram program = construct_mock_kernel_program(ivc);
665
666 // Add an extra constraint that doesn't exist in the IVC queue
669
670 ProgramMetadata metadata{ .ivc = ivc };
671
672 EXPECT_THROW_WITH_MESSAGE(acir_format::create_circuit<Builder>(program, metadata),
673 "mismatch in number of recursive verifications");
674}
675
679TEST_F(HypernovaRecursionConstraintTest, FailsOnNonEmptyPublicInputs)
680{
681 auto ivc = create_mock_chonk_from_constraints(make_hn_recursion_constraints({ PROOF_TYPE::OINK }));
682
683 AcirProgram program = construct_mock_kernel_program(ivc);
684
685 // Add public inputs to the constraint (which should be empty for HN)
686 program.constraints.hn_recursion_constraints[0].public_inputs = { 0, 1, 2 };
687
688 ProgramMetadata metadata{ .ivc = ivc };
689
690 EXPECT_THROW_WITH_MESSAGE(acir_format::create_circuit<Builder>(program, metadata),
691 "unexpected non-empty public_inputs in HN constraint");
692}
693
697TEST_F(HypernovaRecursionConstraintTest, FailsOnProofTypeMismatch)
698{
699 auto ivc = create_mock_chonk_from_constraints(make_hn_recursion_constraints({ PROOF_TYPE::OINK }));
700
701 AcirProgram program = construct_mock_kernel_program(ivc);
702
703 // Change the proof type to something that doesn't match the IVC state: the init kernel's first app is
704 // verified via an OINK proof, so an HN proof_type must be rejected by the circuit-kinds-derived cross-check.
705 program.constraints.hn_recursion_constraints[0].proof_type = PROOF_TYPE::HN;
706
707 ProgramMetadata metadata{ .ivc = ivc };
708
709 EXPECT_THROW_WITH_MESSAGE(acir_format::create_circuit<Builder>(program, metadata),
710 "ACIR proof_type disagrees with circuit-kinds-derived state");
711}
#define BB_ASSERT_NEQ(actual, expected,...)
Definition assert.hpp:98
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:224
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
Shared type definitions for the Barretenberg RPC API.
static std::shared_ptr< Chonk::MegaZKVerificationKey > real_hiding_kernel_vk()
static void construct_and_accumulate_mock_app(std::shared_ptr< Chonk > ivc)
static std::shared_ptr< Chonk::KernelVerificationKey > real_inner_kernel_vk(size_t num_apps)
static std::shared_ptr< Chonk::KernelVerificationKey > construct_kernel_vk_from_acir_program(AcirProgram &program)
Construct a kernel circuit VK from an acir program with IVC recursion constraints....
static std::shared_ptr< Chonk::KernelVerificationKey > real_reset_tail_kernel_vk()
static void construct_and_accumulate_mock_kernel(std::shared_ptr< Chonk > ivc)
static std::vector< RecursionConstraint > make_hn_recursion_constraints(const std::vector< PROOF_TYPE > &proof_types)
Build a set of bare HN recursion constraints carrying only the given proof types.
static UltraCircuitBuilder create_inner_circuit(size_t log_num_gates=10)
static std::vector< PROOF_TYPE > init_kernel_proof_types(size_t num_apps)
static void construct_and_accumulate_trailing_kernels(const std::shared_ptr< Chonk > &ivc)
static KernelGateCounts mock_kernel_gate_counts(const std::vector< PROOF_TYPE > &proof_types)
static std::shared_ptr< Chonk::MegaZKVerificationKey > mock_hiding_kernel_vk()
static Chonk::CircuitVerificationKey make_circuit_vk(Builder &builder_in, CircuitKind kind)
static std::shared_ptr< Chonk::KernelVerificationKey > mock_kernel_vk(const std::vector< PROOF_TYPE > &proof_types)
static RecursionConstraint create_recursion_constraint(const VerifierInputs &input, PROOF_TYPE proof_type, std::vector< FF > &witness)
Create an ACIR RecursionConstraint given the corresponding verifier inputs.
static std::shared_ptr< Chonk::KernelVerificationKey > real_init_kernel_vk(size_t num_apps)
static Builder construct_mock_app_circuit(const std::shared_ptr< Chonk > &ivc)
Constuct a simple arbitrary circuit to represent a mock app circuit.
static AcirProgram construct_mock_kernel_program(const std::shared_ptr< Chonk > &ivc)
Generate an acir program {constraints, witness} for a mock kernel.
static Builder construct_mock_UH_recursion_app_circuit(const std::shared_ptr< Chonk > &ivc, const bool tamper_vk)
Constuct a mock app circuit with a UH recursive verifier.
static std::vector< PROOF_TYPE > inner_kernel_proof_types(size_t num_apps)
bb::CircuitVerificationKey CircuitVerificationKey
Definition chonk.hpp:101
bb::fr FF
Definition chonk.hpp:55
stdlib::recursion::PairingPoints< stdlib::bn254< ClientCircuit > > PairingPoints
Definition chonk.hpp:74
Verifier for Chonk IVC proofs (both native and recursive).
Output verify(const Proof &proof)
Verify a Chonk proof.
MergeProver::MergeProof MergeProof
Definition goblin.hpp:42
static void add_some_ecc_op_gates(MegaBuilder &builder)
Generate a simple test circuit with some ECC op gates and conventional arithmetic gates.
std::shared_ptr< ECCOpQueue > op_queue
static void add_arithmetic_gates(Builder &builder, const size_t num_gates=4)
Add a specified number of arithmetic gates to the provided circuit.
Contains all the information required by a Honk prover to create a proof, constructed from a finalize...
The recursive counterpart to the "native" Ultra flavor.
Output verify_proof(const Proof &proof)
Perform ultra verification.
static constexpr element one
Definition group.hpp:48
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:20
Manages the data that is propagated on the public inputs of an application/function circuit.
static void add_default(Builder &builder)
Add default public inputs when they are not present.
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
AvmProvingInputs inputs
constexpr std::array< size_t, KERNEL_APP_COUNTS > INNER_KERNEL_ECC_ROWS
constexpr size_t RESET_TAIL_KERNEL_GATE_COUNT
constexpr size_t MSM_ROWS_OFFSET
constexpr std::array< size_t, KERNEL_APP_COUNTS > INNER_KERNEL_ULTRA_OPS
Goblin::MergeProof create_mock_merge_proof()
Create a mock merge proof which has the correct structure but is not necessarily valid.
constexpr std::array< size_t, KERNEL_APP_COUNTS > INIT_KERNEL_ULTRA_OPS
RecursionConstraint recursion_data_to_recursion_constraint(std::vector< bb::fr > &witness, const std::vector< bb::fr > &proof, const std::vector< bb::fr > &key, const bb::fr &key_hash, const bb::fr &predicate, const size_t num_public_inputs_to_extract, const uint32_t proof_type)
========== TESTING UTILITIES ========== ///
Definition utils.cpp:53
constexpr size_t HIDING_KERNEL_ECC_ROWS
std::shared_ptr< Chonk > create_mock_chonk_from_constraints(const std::vector< RecursionConstraint > &constraints)
Create a Chonk instance with mocked state corresponding to a set of IVC recursion constraints.
constexpr std::array< size_t, KERNEL_APP_COUNTS > INIT_KERNEL_ECC_ROWS
constexpr size_t RESET_TAIL_KERNEL_ULTRA_OPS
constexpr std::array< size_t, KERNEL_APP_COUNTS > INNER_KERNEL_GATE_COUNT
constexpr size_t HIDING_KERNEL_GATE_COUNT
constexpr std::array< size_t, KERNEL_APP_COUNTS > INIT_KERNEL_GATE_COUNT
constexpr size_t RESET_TAIL_KERNEL_ECC_ROWS
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic)
Construct and check a goblin recursive verification circuit.
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
field< Bn254FrParams > fr
Definition fr.hpp:155
typename flavor_for_impl< K >::type flavor_for
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder
constexpr decltype(auto) dispatch_kind(CircuitKind kind, F &&f)
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
AcirFormatOriginalOpcodeIndices original_opcode_indices
std::vector< RecursionConstraint > hn_recursion_constraints
std::vector< size_t > gates_per_opcode
Struct containing both the constraints to be added to the circuit and the witness vector.
Metadata required to create a circuit.
std::shared_ptr< bb::Chonk > ivc
RecursionConstraint struct contains information required to recursively verify a proof.
std::vector< FF > vk_to_field_elements() const
Definition chonk.hpp:116
std::vector< FF > proof
Definition chonk.hpp:104
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr field zero()
Output type for recursive ultra verification.