2#include <sys/resource.h>
21#include "gtest/gtest.h"
25static constexpr size_t SMALL_LOG_2_NUM_GATES = 5;
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];
62 size_t num_app_circuits,
TestSettings settings = {},
bool check_circuit_sizes =
false)
65 const size_t num_circuits = circuit_producer.total_num_circuits;
66 Chonk ivc{ num_circuits };
68 for (
size_t j = 0; j < num_circuits; ++j) {
69 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings, check_circuit_sizes);
71 return { ivc.
prove(), ivc.get_hiding_kernel_vk_and_hash() };
77 return verifier.
verify(proof);
94 const size_t NUM_APP_CIRCUITS = 2;
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 };
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);
106 EXPECT_EQ(ivc.verification_queue.size(), 2);
108 auto& app_entry = ivc.verification_queue[1];
109 ASSERT_FALSE(app_entry.is_kernel) <<
"Expected second queue entry to be an app";
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);
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();
119 EXPECT_TRUE(app_io.pairing_inputs.check());
121 app_io.to_proof(app_entry.proof, num_public_inputs);
125 auto proof = ivc.prove();
126 EXPECT_FALSE(
verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
138 const size_t NUM_APP_CIRCUITS = 2;
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 };
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);
150 EXPECT_EQ(ivc.verification_queue.size(), 2);
152 auto& kernel_entry = ivc.verification_queue[0];
153 ASSERT_TRUE(kernel_entry.is_kernel) <<
"Expected first queue entry to be a kernel";
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);
160 switch (field_to_tamper) {
164 kernel_io.pairing_inputs.P0() = kernel_io.pairing_inputs.P0() + Commitment::one();
168 kernel_io.output_hn_accum_hash +=
FF(1);
171 kernel_io.kernel_return_data = kernel_io.kernel_return_data + Commitment::one();
174 kernel_io.app_return_data = kernel_io.app_return_data + Commitment::one();
177 kernel_io.ecc_op_hash +=
FF(1);
181 kernel_io.to_proof(kernel_entry.proof, num_public_inputs);
185 auto proof = ivc.prove();
186 EXPECT_FALSE(
verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
204 const size_t NUM_APP_CIRCUITS = 2;
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 };
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)) {
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);
226 auto [circuit,
vk] = circuit_producer.create_next_circuit_and_vk(ivc, settings);
227 ivc.accumulate(circuit,
vk);
230 auto proof = ivc.prove();
231 auto vk_and_hash = ivc.get_hiding_kernel_vk_and_hash();
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);
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;
254 const size_t NUM_APP_CIRCUITS = 2;
258 auto [proof,
vk] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS, {},
true);
259 EXPECT_TRUE(verify_chonk(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));
278 const size_t NUM_APP_CIRCUITS = 2;
279 auto [proof,
vk] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS);
281 EXPECT_TRUE(verify_chonk(proof,
vk));
295 const size_t NUM_APP_CIRCUITS = 2;
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 };
305 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
306 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings);
308 auto proof = ivc.prove();
309 EXPECT_TRUE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
314 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
315 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
316 Chonk ivc{ NUM_CIRCUITS };
318 size_t num_public_inputs = 0;
321 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
323 circuit_producer.create_next_circuit_and_vk(ivc, { .log2_num_gates = SMALL_LOG_2_NUM_GATES });
327 num_public_inputs = circuit.num_public_inputs();
331 EXPECT_EQ(ivc.verification_queue.size(), 2);
332 tamper_with_proof(ivc.verification_queue[0].proof,
336 auto proof = ivc.prove();
337 EXPECT_FALSE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
342 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
343 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
344 Chonk ivc{ NUM_CIRCUITS };
347 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
349 circuit_producer.create_next_circuit_and_vk(ivc, { .log2_num_gates = SMALL_LOG_2_NUM_GATES });
353 EXPECT_EQ(ivc.verification_queue.size(), 2);
354 tamper_with_proof(ivc.verification_queue[1].proof,
355 circuit.num_public_inputs());
358 auto proof = ivc.prove();
359 EXPECT_FALSE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
369 const TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
371 auto [unused_1, vk_and_hash_1] = accumulate_and_prove_ivc(1, settings);
372 auto [unused_2, vk_and_hash_2] = accumulate_and_prove_ivc(3, settings);
375 EXPECT_EQ(*vk_and_hash_1->vk.get(), *vk_and_hash_2->vk.get());
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;
389 const TestSettings settings_1{ .log2_num_gates = log2_num_gates_small };
390 const TestSettings settings_2{ .log2_num_gates = log2_num_gates_big };
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);
396 EXPECT_EQ(*vk_and_hash_1->vk.get(), *vk_and_hash_2->vk.get());
404HEAVY_TEST(ChonkKernelCapacity, MaxCapacityPassing)
408 const size_t NUM_APP_CIRCUITS = (CHONK_MAX_NUM_CIRCUITS - 3) / 2;
412 EXPECT_TRUE(verified);
423 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
424 auto [proof,
vk] = accumulate_and_prove_ivc(1, settings);
427 const std::string filename =
"proof.msgpack";
428 proof.to_file_msgpack(filename);
431 EXPECT_TRUE(verify_chonk(proof_deserialized,
vk));
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();
440 EXPECT_TRUE(verify_chonk(proof_deserialized,
vk));
444 msgpack::sbuffer
buffer = proof.to_msgpack_buffer();
446 EXPECT_TRUE(verify_chonk(proof_deserialized,
vk));
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); });
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;
541 constexpr size_t LOG2_NUM_GATES = 10;
542 const size_t NUM_APP_CIRCUITS = 1;
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 };
549 for (
size_t j = 0; j < num_circuits; ++j) {
550 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings);
553 info(
"Peak RSS before prove: ", get_peak_rss_mib(),
" MiB");
557 info(
"Peak RSS after prove: ", get_peak_rss_mib(),
" MiB");
560 EXPECT_TRUE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
565 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
566 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(1, settings);
568 auto original_flat = proof.to_field_elements();
569 info(
"Original proof size: ", original_flat.size(),
" Fr elements (", original_flat.size() * 32,
" bytes)");
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");
577 EXPECT_GE(ratio, 1.5) <<
"Compression ratio " << ratio <<
"x is below the expected minimum of 1.5x";
579 size_t mega_num_pub_inputs =
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;
591 EXPECT_TRUE(verify_chonk(decompressed, vk_and_hash));
597static std::vector<uint8_t> compress_and_corrupt(
const ChonkProof& proof,
size_t element_idx,
const uint256_t&
value)
600 size_t byte_offset = element_idx * 32;
601 EXPECT_LT(byte_offset + 32, compressed.size());
603 std::vector<uint8_t> buf;
605 std::copy(buf.begin(), buf.end(), compressed.begin() +
static_cast<ptrdiff_t
>(byte_offset));
612 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
613 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(1, settings);
614 size_t mega_num_pub_inputs =
616 ASSERT_GT(mega_num_pub_inputs, 0);
621 auto corrupted = compress_and_corrupt(proof, 0,
Fr::modulus);
630 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
631 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(1, settings);
632 size_t mega_num_pub_inputs =
637 auto corrupted = compress_and_corrupt(proof, mega_num_pub_inputs,
Fq::modulus + 1);
646 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
647 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(1, settings);
648 size_t mega_num_pub_inputs =
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();
657 auto corrupted = compress_and_corrupt(proof, mega_num_pub_inputs,
uint256_t(x_not_on_curve));
664 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
665 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(1, settings);
666 size_t mega_num_pub_inputs =
671 compressed.resize(compressed.size() - 32);
#define EXPECT_THROW_OR_ABORT(statement, matcher)
#define BB_DISABLE_ASSERTS()
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()
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.
HypernovaDeciderProver DeciderProver
ChonkProof prove()
Construct Chonk proof using the batched MegaZK + Translator protocol.
ProverInstance_< Flavor > ProverInstance
VerifierInstance_< Flavor > VerifierInstance
void accumulate(ClientCircuit &circuit, const std::shared_ptr< MegaVerificationKey > &precomputed_vk) override
Perform prover work for accumulation (e.g. HN folding, merge proving)
MegaCircuitBuilder ClientCircuit
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::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.
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...
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
std::unique_ptr< uint8_t[]> buffer
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
std::vector< fr > HonkProof
::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
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