Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
chonk.test.cpp
Go to the documentation of this file.
1#include <ranges>
2#include <sys/resource.h>
3
21#include "gtest/gtest.h"
22
23using namespace bb;
24
25static constexpr size_t SMALL_LOG_2_NUM_GATES = 5;
26
27class ChonkTests : public ::testing::Test {
28 protected:
30
32 using FF = typename Flavor::FF;
39 using CircuitProducer = PrivateFunctionExecutionMockCircuitProducer;
41
42 public:
49 static void tamper_with_proof(HonkProof& proof, size_t public_inputs_offset)
50 {
51 // Tamper with the commitment in the proof
52 Commitment commitment = FrCodec::deserialize_from_fields<Commitment>(
53 std::span{ proof }.subspan(public_inputs_offset, FrCodec::template calc_num_fields<Commitment>()));
54 commitment = commitment + Commitment::one();
55 auto commitment_frs = FrCodec::serialize_to_fields<Commitment>(commitment);
56 for (size_t idx = 0; idx < 4; ++idx) {
57 proof[public_inputs_offset + idx] = commitment_frs[idx];
58 }
59 }
60
62 size_t num_app_circuits, TestSettings settings = {}, bool check_circuit_sizes = false)
63 {
64 CircuitProducer circuit_producer(num_app_circuits);
65 const size_t num_circuits = circuit_producer.total_num_circuits;
66 Chonk ivc{ num_circuits };
67
68 for (size_t j = 0; j < num_circuits; ++j) {
69 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings, check_circuit_sizes);
70 }
71 return { ivc.prove(), ivc.get_hiding_kernel_vk_and_hash() };
72 };
73
74 static bool verify_chonk(const ChonkProof& proof, const std::shared_ptr<MegaZKFlavor::VKAndHash>& vk_and_hash)
75 {
76 ChonkVerifier verifier(vk_and_hash);
77 return verifier.verify(proof);
78 }
79
84
91 {
93
94 const size_t NUM_APP_CIRCUITS = 2;
95 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
96 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
97 Chonk ivc{ NUM_CIRCUITS };
98 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
99
100 for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
101 auto [circuit, vk] = circuit_producer.create_next_circuit_and_vk(ivc, settings);
102 ivc.accumulate(circuit, vk);
103
104 // After accumulating 3 circuits (app, kernel, app), we have 2 proofs in the queue
105 if (idx == 2) {
106 EXPECT_EQ(ivc.verification_queue.size(), 2);
107
108 auto& app_entry = ivc.verification_queue[1];
109 ASSERT_FALSE(app_entry.is_kernel) << "Expected second queue entry to be an app";
110
112 size_t num_public_inputs = app_entry.honk_vk->num_public_inputs;
113 AppIOSerde app_io = AppIOSerde::from_proof(app_entry.proof, num_public_inputs);
114
115 // Set P0 to [x]₁ (the first SRS point after [1]) and P1 to [1]₁
116 app_io.pairing_inputs.P0() = srs::get_crs_factory<curve::BN254>()->get_crs(2)->get_monomial_points()[1];
117 app_io.pairing_inputs.P1() = -Commitment::one();
118
119 EXPECT_TRUE(app_io.pairing_inputs.check());
120
121 app_io.to_proof(app_entry.proof, num_public_inputs);
122 }
123 }
124
125 auto proof = ivc.prove();
126 EXPECT_FALSE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
127 }
128
134 static void test_kernel_io_tampering(KernelIOField field_to_tamper)
135 {
137
138 const size_t NUM_APP_CIRCUITS = 2;
139 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
140 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
141 Chonk ivc{ NUM_CIRCUITS };
142 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
143
144 for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
145 auto [circuit, vk] = circuit_producer.create_next_circuit_and_vk(ivc, settings);
146 ivc.accumulate(circuit, vk);
147
148 // After accumulating 3 circuits (app, kernel, app), we have 2 proofs in the queue
149 if (idx == 2) {
150 EXPECT_EQ(ivc.verification_queue.size(), 2);
151
152 auto& kernel_entry = ivc.verification_queue[0];
153 ASSERT_TRUE(kernel_entry.is_kernel) << "Expected first queue entry to be a kernel";
154
155 using KernelIOSerde = bb::stdlib::recursion::honk::KernelIOSerde;
156 size_t num_public_inputs = kernel_entry.honk_vk->num_public_inputs;
157 KernelIOSerde kernel_io = KernelIOSerde::from_proof(kernel_entry.proof, num_public_inputs);
158
159 // Tamper with the specified field
160 switch (field_to_tamper) {
162 // Replace with a different valid pairing: P0 = G1, P1 = -G1 satisfies e(G1,[1])·e(-G1,[x]) != 1
163 // so instead use P0 + random offset to break binding without breaking the pairing trivially
164 kernel_io.pairing_inputs.P0() = kernel_io.pairing_inputs.P0() + Commitment::one();
165 break;
166 }
168 kernel_io.output_hn_accum_hash += FF(1);
169 break;
171 kernel_io.kernel_return_data = kernel_io.kernel_return_data + Commitment::one();
172 break;
174 kernel_io.app_return_data = kernel_io.app_return_data + Commitment::one();
175 break;
177 kernel_io.ecc_op_hash += FF(1);
178 break;
179 }
180
181 kernel_io.to_proof(kernel_entry.proof, num_public_inputs);
182 }
183 }
184
185 auto proof = ivc.prove();
186 EXPECT_FALSE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
187 }
188
200 {
201 using HidingKernelIOSerde = bb::stdlib::recursion::honk::HidingKernelIOSerde;
202 using KernelIOSerde = bb::stdlib::recursion::honk::KernelIOSerde;
203
204 const size_t NUM_APP_CIRCUITS = 2;
205 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
206 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
207 Chonk ivc{ NUM_CIRCUITS };
208 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
209
210 // Extract tail kernel IO before the last accumulation consumes the verification queue.
211 // The tail kernel (HN_FINAL) uses KernelIO format; the hiding kernel uses HidingKernelIO.
212 KernelIOSerde tail_io;
213 for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
214 if (idx == NUM_CIRCUITS - 1) {
215 for (auto& it : std::ranges::reverse_view(ivc.verification_queue)) {
216 if (it.is_kernel) {
217 size_t num_public_inputs = it.honk_vk->num_public_inputs;
218 ASSERT_EQ(num_public_inputs, KernelIOSerde::PUBLIC_INPUTS_SIZE)
219 << "Tail kernel should use KernelIO format";
220 ASSERT_GT(it.proof.size(), num_public_inputs) << "Tail kernel proof too small";
221 tail_io = KernelIOSerde::from_proof(it.proof, num_public_inputs);
222 break;
223 }
224 }
225 }
226 auto [circuit, vk] = circuit_producer.create_next_circuit_and_vk(ivc, settings);
227 ivc.accumulate(circuit, vk);
228 }
229
230 auto proof = ivc.prove();
231 auto vk_and_hash = ivc.get_hiding_kernel_vk_and_hash();
232
233 size_t hiding_kernel_pub_inputs = vk_and_hash->vk->num_public_inputs;
234 ASSERT_EQ(hiding_kernel_pub_inputs, HidingKernelIOSerde::PUBLIC_INPUTS_SIZE)
235 << "HidingKernel should use HidingKernelIO format";
236 HidingKernelIOSerde hiding_io =
237 HidingKernelIOSerde::from_proof(proof.hiding_oink_proof, hiding_kernel_pub_inputs);
238
239 EXPECT_EQ(tail_io.kernel_return_data, hiding_io.kernel_return_data)
240 << "kernel_return_data mismatch: Tail has " << tail_io.kernel_return_data << " but HidingKernel has "
241 << hiding_io.kernel_return_data;
242 }
243};
244
252TEST_F(ChonkTests, TestCircuitSizes)
253{
254 const size_t NUM_APP_CIRCUITS = 2;
255
256 // Check circuit sizes when no settings are passed
257 {
258 auto [proof, vk] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS, {}, true);
259 EXPECT_TRUE(verify_chonk(proof, vk));
260 }
261
262 // Check circuit sizes when no settings are passed
263 {
264 auto [proof, vk] =
265 accumulate_and_prove_ivc(NUM_APP_CIRCUITS, { .log2_num_gates = SMALL_LOG_2_NUM_GATES }, true);
266 EXPECT_TRUE(verify_chonk(proof, vk));
267 }
268};
269
277{
278 const size_t NUM_APP_CIRCUITS = 2;
279 auto [proof, vk] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS);
280
281 EXPECT_TRUE(verify_chonk(proof, vk));
282};
283
291TEST_F(ChonkTests, BadProofFailure)
292{
293 BB_DISABLE_ASSERTS(); // Disable assert in HN prover
294
295 const size_t NUM_APP_CIRCUITS = 2;
296 // Confirm that the IVC verifies if nothing is tampered with
297 {
298
299 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
300 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
301 Chonk ivc{ NUM_CIRCUITS };
302 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
303
304 // Construct and accumulate a set of mocked private function execution circuits
305 for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
306 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings);
307 }
308 auto proof = ivc.prove();
309 EXPECT_TRUE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
310 }
311
312 // The IVC throws an exception if the FIRST fold proof is tampered with
313 {
314 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
315 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
316 Chonk ivc{ NUM_CIRCUITS };
317
318 size_t num_public_inputs = 0;
319
320 // Construct and accumulate a set of mocked private function execution circuits
321 for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
322 auto [circuit, vk] =
323 circuit_producer.create_next_circuit_and_vk(ivc, { .log2_num_gates = SMALL_LOG_2_NUM_GATES });
324 ivc.accumulate(circuit, vk);
325
326 if (idx == 1) {
327 num_public_inputs = circuit.num_public_inputs();
328 }
329
330 if (idx == 2) {
331 EXPECT_EQ(ivc.verification_queue.size(), 2); // two proofs after 3 calls to accumulation
332 tamper_with_proof(ivc.verification_queue[0].proof,
333 num_public_inputs); // tamper with first proof
334 }
335 }
336 auto proof = ivc.prove();
337 EXPECT_FALSE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
338 }
339
340 // The IVC fails if the SECOND fold proof is tampered with
341 {
342 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
343 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
344 Chonk ivc{ NUM_CIRCUITS };
345
346 // Construct and accumulate a set of mocked private function execution circuits
347 for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
348 auto [circuit, vk] =
349 circuit_producer.create_next_circuit_and_vk(ivc, { .log2_num_gates = SMALL_LOG_2_NUM_GATES });
350 ivc.accumulate(circuit, vk);
351
352 if (idx == 2) {
353 EXPECT_EQ(ivc.verification_queue.size(), 2); // two proofs after 3 calls to accumulation
354 tamper_with_proof(ivc.verification_queue[1].proof,
355 circuit.num_public_inputs()); // tamper with second proof
356 }
357 }
358 auto proof = ivc.prove();
359 EXPECT_FALSE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
360 }
361};
362
367TEST_F(ChonkTests, VKIndependenceFromNumberOfCircuits)
368{
369 const TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
370
371 auto [unused_1, vk_and_hash_1] = accumulate_and_prove_ivc(/*num_app_circuits=*/1, settings);
372 auto [unused_2, vk_and_hash_2] = accumulate_and_prove_ivc(/*num_app_circuits=*/3, settings);
373
374 // Check the equality of the hiding kernel VKeys
375 EXPECT_EQ(*vk_and_hash_1->vk.get(), *vk_and_hash_2->vk.get());
376};
377
382TEST_F(ChonkTests, VKIndependenceFromCircuitSize)
383{
384 // Run IVC for two sets of circuits
385 const size_t NUM_APP_CIRCUITS = 1;
386 const size_t log2_num_gates_small = 5;
387 const size_t log2_num_gates_big = 18;
388
389 const TestSettings settings_1{ .log2_num_gates = log2_num_gates_small };
390 const TestSettings settings_2{ .log2_num_gates = log2_num_gates_big };
391
392 auto [unused_1, vk_and_hash_1] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS, settings_1);
393 auto [unused_2, vk_and_hash_2] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS, settings_2);
394
395 // Check the equality of the hiding kernel VKeys
396 EXPECT_EQ(*vk_and_hash_1->vk.get(), *vk_and_hash_2->vk.get());
397};
398
403#ifdef NDEBUG
404HEAVY_TEST(ChonkKernelCapacity, MaxCapacityPassing)
405{
407
408 const size_t NUM_APP_CIRCUITS = (CHONK_MAX_NUM_CIRCUITS - /*trailing kernels*/ 3) / 2;
409 auto [proof, vk] = ChonkTests::accumulate_and_prove_ivc(NUM_APP_CIRCUITS);
410
411 bool verified = ChonkTests::verify_chonk(proof, vk);
412 EXPECT_TRUE(verified);
413};
414#endif
415
420TEST_F(ChonkTests, MsgpackProofFromFileOrBuffer)
421{
422 // Generate an arbitrary valid CICV proof
423 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
424 auto [proof, vk] = accumulate_and_prove_ivc(/*num_app_circuits=*/1, settings);
425
426 { // Serialize/deserialize the proof to/from a file, check that it verifies
427 const std::string filename = "proof.msgpack";
428 proof.to_file_msgpack(filename);
429 auto proof_deserialized = ChonkProof::from_file_msgpack(filename);
430
431 EXPECT_TRUE(verify_chonk(proof_deserialized, vk));
432 }
433
434 { // Serialize/deserialize proof to/from a heap buffer, check that it verifies
435 uint8_t* buffer = proof.to_msgpack_heap_buffer();
436 auto uint8_buffer = from_buffer<std::vector<uint8_t>>(buffer);
437 uint8_t const* uint8_ptr = uint8_buffer.data();
438 auto proof_deserialized = ChonkProof::from_msgpack_buffer(uint8_ptr);
439
440 EXPECT_TRUE(verify_chonk(proof_deserialized, vk));
441 }
442
443 { // Check that attempting to deserialize a proof from a buffer with random bytes fails gracefully
444 msgpack::sbuffer buffer = proof.to_msgpack_buffer();
445 auto proof_deserialized = ChonkProof::from_msgpack_buffer(buffer);
446 EXPECT_TRUE(verify_chonk(proof_deserialized, vk));
447
448 std::vector<uint8_t> random_bytes(buffer.size());
449 std::generate(random_bytes.begin(), random_bytes.end(), []() { return static_cast<uint8_t>(rand() % 256); });
450 std::copy(random_bytes.begin(), random_bytes.end(), buffer.data());
451
452 // Expect deserialization to fail (either msgpack parse error, type mismatch, trailing data,
453 // or non-canonical field encoding)
454 EXPECT_ANY_THROW(ChonkProof::from_msgpack_buffer(buffer));
455 }
456};
457
463TEST_F(ChonkTests, KernelPairingInputsTamperingFailure)
464{
465 ChonkTests::test_kernel_io_tampering(KernelIOField::PAIRING_INPUTS);
466}
467
473TEST_F(ChonkTests, AppPairingInputsTamperingFailure)
474{
476}
477
484TEST_F(ChonkTests, AccumulatorHashTamperingFailure)
485{
486 ChonkTests::test_kernel_io_tampering(KernelIOField::ACCUMULATOR_HASH);
487}
488
494TEST_F(ChonkTests, KernelReturnDataTamperingFailure)
495{
496 ChonkTests::test_kernel_io_tampering(KernelIOField::KERNEL_RETURN_DATA);
497}
498
504TEST_F(ChonkTests, AppReturnDataTamperingFailure)
505{
506 ChonkTests::test_kernel_io_tampering(KernelIOField::APP_RETURN_DATA);
507}
508
513TEST_F(ChonkTests, EccOpHashTamperingFailure)
514{
515 ChonkTests::test_kernel_io_tampering(KernelIOField::ECC_OP_HASH);
516}
517
523TEST_F(ChonkTests, KernelReturnDataPropagationConsistency)
524{
526}
527
533TEST_F(ChonkTests, SmallAppProvingMemory)
534{
535 auto get_peak_rss_mib = []() -> size_t {
536 struct rusage usage{};
537 getrusage(RUSAGE_SELF, &usage);
538 return static_cast<size_t>(usage.ru_maxrss) / 1024; // Linux: ru_maxrss is in KB
539 };
540
541 constexpr size_t LOG2_NUM_GATES = 10;
542 const size_t NUM_APP_CIRCUITS = 1;
543
544 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
545 const size_t num_circuits = circuit_producer.total_num_circuits;
546 Chonk ivc{ num_circuits };
547 TestSettings settings{ .log2_num_gates = LOG2_NUM_GATES };
548
549 for (size_t j = 0; j < num_circuits; ++j) {
550 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings);
551 }
552
553 info("Peak RSS before prove: ", get_peak_rss_mib(), " MiB");
554
555 ChonkProof proof = ivc.prove();
556
557 info("Peak RSS after prove: ", get_peak_rss_mib(), " MiB");
558
559 // Verify the proof is valid
560 EXPECT_TRUE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
561}
562
563TEST_F(ChonkTests, ProofCompressionRoundtrip)
564{
565 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
566 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(/*num_app_circuits=*/1, settings);
567
568 auto original_flat = proof.to_field_elements();
569 info("Original proof size: ", original_flat.size(), " Fr elements (", original_flat.size() * 32, " bytes)");
570
571 auto compressed = ProofCompressor::compress_chonk_proof(proof);
572 double ratio = static_cast<double>(original_flat.size() * 32) / static_cast<double>(compressed.size());
573 info("Compressed proof size: ", compressed.size(), " bytes");
574 info("Compression ratio: ", ratio, "x");
575
576 // Compression should achieve at least 1.5x (commitments 4 Fr → 32 bytes, scalars 1:1)
577 EXPECT_GE(ratio, 1.5) << "Compression ratio " << ratio << "x is below the expected minimum of 1.5x";
578
579 size_t mega_num_pub_inputs =
580 proof.hiding_oink_proof.size() - ProofLength::Oink<MegaZKFlavor>::LENGTH_WITHOUT_PUB_INPUTS;
581 ChonkProof decompressed = ProofCompressor::decompress_chonk_proof(compressed, mega_num_pub_inputs);
582
583 // Verify element-by-element roundtrip
584 auto decompressed_flat = decompressed.to_field_elements();
585 ASSERT_EQ(decompressed_flat.size(), original_flat.size());
586 for (size_t i = 0; i < original_flat.size(); i++) {
587 ASSERT_EQ(decompressed_flat[i], original_flat[i]) << "Mismatch at element " << i;
588 }
589
590 // Verify the decompressed proof
591 EXPECT_TRUE(verify_chonk(decompressed, vk_and_hash));
592}
593
597static std::vector<uint8_t> compress_and_corrupt(const ChonkProof& proof, size_t element_idx, const uint256_t& value)
598{
599 auto compressed = ProofCompressor::compress_chonk_proof(proof);
600 size_t byte_offset = element_idx * 32;
601 EXPECT_LT(byte_offset + 32, compressed.size());
602 // Overwrite the element with the given value (big-endian)
603 std::vector<uint8_t> buf;
604 write(buf, value);
605 std::copy(buf.begin(), buf.end(), compressed.begin() + static_cast<ptrdiff_t>(byte_offset));
606 return compressed;
607}
608
609// Rejects a BN scalar value >= Fr::modulus
610TEST_F(ChonkTests, DecompressionRejectsNonCanonicalBN254Scalar)
611{
612 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
613 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(/*num_app_circuits=*/1, settings);
614 size_t mega_num_pub_inputs =
615 proof.hiding_oink_proof.size() - ProofLength::Oink<MegaZKFlavor>::LENGTH_WITHOUT_PUB_INPUTS;
616 ASSERT_GT(mega_num_pub_inputs, 0); // Need at least one public input (BN254 scalar)
617
618 // Element 0 is the first public input (a BN254 scalar). Set it to Fr::modulus (non-canonical).
620
621 auto corrupted = compress_and_corrupt(proof, 0, Fr::modulus);
622 EXPECT_THROW_OR_ABORT(ProofCompressor::decompress_chonk_proof(corrupted, mega_num_pub_inputs), "");
623}
624
625// Rejects a BN commitment x-coordinate >= Fq::modulus
626TEST_F(ChonkTests, DecompressionRejectsNonCanonicalBN254CommitmentX)
627{
629
630 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
631 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(/*num_app_circuits=*/1, settings);
632 size_t mega_num_pub_inputs =
633 proof.hiding_oink_proof.size() - ProofLength::Oink<MegaZKFlavor>::LENGTH_WITHOUT_PUB_INPUTS;
634
635 // First BN254 commitment is at element index mega_num_pub_inputs.
636 // Set x-coordinate to Fq::modulus + 1 (non-canonical, with no sign bit).
637 auto corrupted = compress_and_corrupt(proof, mega_num_pub_inputs, Fq::modulus + 1);
638 EXPECT_THROW_OR_ABORT(ProofCompressor::decompress_chonk_proof(corrupted, mega_num_pub_inputs), "");
639}
640
641// Rejects a canonical x-coordinate that is not on the BN254 curve
642TEST_F(ChonkTests, DecompressionRejectsInvalidBN254CurvePoint)
643{
645
646 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
647 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(/*num_app_circuits=*/1, settings);
648 size_t mega_num_pub_inputs =
649 proof.hiding_oink_proof.size() - ProofLength::Oink<MegaZKFlavor>::LENGTH_WITHOUT_PUB_INPUTS;
650
651 // x=4 is not on BN254
652 Fq x_not_on_curve(4);
653 Fq rhs = x_not_on_curve * x_not_on_curve * x_not_on_curve + Fq(3);
654 auto [is_sq, _] = rhs.sqrt();
655 ASSERT_FALSE(is_sq);
656
657 auto corrupted = compress_and_corrupt(proof, mega_num_pub_inputs, uint256_t(x_not_on_curve));
658 EXPECT_THROW_OR_ABORT(ProofCompressor::decompress_chonk_proof(corrupted, mega_num_pub_inputs), "");
659}
660
661// Rejects a compressed proof that is too short (read_u256 bounds check)
662TEST_F(ChonkTests, DecompressionRejectsTruncatedProof)
663{
664 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
665 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(/*num_app_circuits=*/1, settings);
666 size_t mega_num_pub_inputs =
667 proof.hiding_oink_proof.size() - ProofLength::Oink<MegaZKFlavor>::LENGTH_WITHOUT_PUB_INPUTS;
668
669 auto compressed = ProofCompressor::compress_chonk_proof(proof);
670 // Truncate by removing the last 32-byte element
671 compressed.resize(compressed.size() - 32);
672 EXPECT_THROW_OR_ABORT(ProofCompressor::decompress_chonk_proof(compressed, mega_num_pub_inputs), "");
673}
#define EXPECT_THROW_OR_ABORT(statement, matcher)
Definition assert.hpp:192
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
TEST_F(ChonkTests, TestCircuitSizes)
Test sizes of the circuits generated by MockCircuitProducer.
PrivateFunctionExecutionMockCircuitProducer CircuitProducer
static bool verify_chonk(const ChonkProof &proof, const std::shared_ptr< MegaZKFlavor::VKAndHash > &vk_and_hash)
static void tamper_with_proof(HonkProof &proof, size_t public_inputs_offset)
Tamper with a proof.
Flavor::Commitment Commitment
static void test_kernel_io_tampering(KernelIOField field_to_tamper)
Helper function to test tampering with KernelIO fields.
static void test_kernel_return_data_propagation()
Helper function to test HidingKernelIO field propagation consistency.
static void SetUpTestSuite()
typename Flavor::FF FF
static std::pair< ChonkProof, std::shared_ptr< MegaZKFlavor::VKAndHash > > accumulate_and_prove_ivc(size_t num_app_circuits, TestSettings settings={}, bool check_circuit_sizes=false)
static void test_app_io_tampering()
Helper function to test tampering with AppIO pairing inputs.
KernelIOField
Enum for specifying which KernelIO field to tamper with in tests.
The IVC scheme used by the aztec client for private function execution.
Definition chonk.hpp:39
HypernovaDeciderProver DeciderProver
Definition chonk.hpp:78
ChonkProof prove()
Construct Chonk proof using the batched MegaZK + Translator protocol.
Definition chonk.cpp:617
ProverInstance_< Flavor > ProverInstance
Definition chonk.hpp:50
MegaFlavor Flavor
Definition chonk.hpp:43
VerifierInstance_< Flavor > VerifierInstance
Definition chonk.hpp:52
void accumulate(ClientCircuit &circuit, const std::shared_ptr< MegaVerificationKey > &precomputed_vk) override
Perform prover work for accumulation (e.g. HN folding, merge proving)
Definition chonk.cpp:564
MegaCircuitBuilder ClientCircuit
Definition chonk.hpp:53
Verifier for Chonk IVC proofs (both native and recursive).
Output verify(const Proof &proof)
Verify a Chonk proof.
HyperNova decider prover. Produces final opening proof for the accumulated claim.
Curve::ScalarField FF
Curve::AffineElement Commitment
NativeVerificationKey_< PrecomputedEntities< Commitment >, Codec, HashFunction, CommitmentKey > VerificationKey
The verification key stores commitments to the precomputed (non-witness) polynomials used by the veri...
Base Native verification key class.
Definition flavor.hpp:135
static std::vector< uint8_t > compress_chonk_proof(const ChonkProof &proof)
static ChonkProof decompress_chonk_proof(const std::vector< uint8_t > &compressed, size_t mega_num_public_inputs)
Contains all the information required by a Honk prover to create a proof, constructed from a finalize...
The VerifierInstance encapsulates all the necessary information for a Honk Verifier to verify a proof...
bb::fq BaseField
Definition bn254.hpp:19
bb::fr ScalarField
Definition bn254.hpp:18
Native representation and serde for AppIO public inputs.
Native representation and serde for HidingKernelIO public inputs.
For test purposes only: Native representation and serde for KernelIO public inputs
#define info(...)
Definition log.hpp:93
std::unique_ptr< uint8_t[]> buffer
Definition engine.cpp:60
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
std::vector< fr > HonkProof
Definition proof.hpp:15
::testing::Types< BN254Settings, GrumpkinSettings > TestSettings
void write(B &buf, field2< base_field, Params > const &value)
ChonkVerifier< false > ChonkNativeVerifier
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static ChonkProof_ from_msgpack_buffer(uint8_t const *&buffer)
std::vector< FF > to_field_elements() const
Serialize proof to field elements (native mode)
static ChonkProof_ from_file_msgpack(const std::string &filename)
Computes Oink proof length from flavor traits.
static constexpr uint256_t modulus
#define HEAVY_TEST(x, y)
Definition test.hpp:9