19#include "gtest/gtest.h"
23static constexpr size_t SMALL_LOG_2_NUM_GATES = 5;
50 Commitment commitment = FrCodec::deserialize_from_fields<Commitment>(
51 std::span{ proof }.subspan(public_inputs_offset, FrCodec::template calc_num_fields<Commitment>()));
52 commitment = commitment + Commitment::one();
53 auto commitment_frs = FrCodec::serialize_to_fields<Commitment>(commitment);
54 for (
size_t idx = 0; idx < 4; ++idx) {
55 proof[public_inputs_offset + idx] = commitment_frs[idx];
60 size_t num_app_circuits,
TestSettings settings = {},
bool check_circuit_sizes =
false)
63 const size_t num_circuits = circuit_producer.total_num_circuits;
64 Chonk ivc{ num_circuits };
66 for (
size_t j = 0; j < num_circuits; ++j) {
67 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings, check_circuit_sizes);
69 return { ivc.
prove(), ivc.get_hiding_kernel_vk_and_hash() };
75 return verifier.
verify(proof);
97 const size_t NUM_APP_CIRCUITS = 2;
99 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
100 Chonk ivc{ NUM_CIRCUITS };
101 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
103 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
104 auto [circuit,
vk] = circuit_producer.create_next_circuit_and_vk(ivc, settings);
105 ivc.accumulate(circuit,
vk);
109 EXPECT_EQ(ivc.verification_queue.size(), 2);
111 auto& app_entry = ivc.verification_queue[1];
112 ASSERT_FALSE(app_entry.is_kernel) <<
"Expected second queue entry to be an app";
115 size_t num_public_inputs = app_entry.honk_vk->num_public_inputs;
116 AppIOSerde app_io = AppIOSerde::from_proof(app_entry.proof, num_public_inputs);
119 app_io.pairing_inputs.P0() = app_io.pairing_inputs.P0() + app_io.pairing_inputs.P0();
120 app_io.pairing_inputs.P1() = app_io.pairing_inputs.P1() + app_io.pairing_inputs.P1();
122 EXPECT_TRUE(app_io.pairing_inputs.check());
124 app_io.to_proof(app_entry.proof, num_public_inputs);
128 auto proof = ivc.prove();
129 EXPECT_FALSE(
verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
141 const size_t NUM_APP_CIRCUITS = 2;
143 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
144 Chonk ivc{ NUM_CIRCUITS };
145 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
147 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
148 auto [circuit,
vk] = circuit_producer.create_next_circuit_and_vk(ivc, settings);
149 ivc.accumulate(circuit,
vk);
153 EXPECT_EQ(ivc.verification_queue.size(), 2);
155 auto& kernel_entry = ivc.verification_queue[0];
156 ASSERT_TRUE(kernel_entry.is_kernel) <<
"Expected first queue entry to be a kernel";
159 size_t num_public_inputs = kernel_entry.honk_vk->num_public_inputs;
160 KernelIOSerde kernel_io = KernelIOSerde::from_proof(kernel_entry.proof, num_public_inputs);
163 switch (field_to_tamper) {
166 kernel_io.pairing_inputs.P0() = Commitment::infinity();
167 kernel_io.pairing_inputs.P1() = Commitment::infinity();
168 EXPECT_TRUE(kernel_io.pairing_inputs.check());
172 kernel_io.output_hn_accum_hash +=
FF(1);
175 kernel_io.kernel_return_data = kernel_io.kernel_return_data + Commitment::one();
178 kernel_io.app_return_data = kernel_io.app_return_data + Commitment::one();
181 kernel_io.ecc_op_tables[0] = kernel_io.ecc_op_tables[0] + Commitment::one();
185 kernel_io.to_proof(kernel_entry.proof, num_public_inputs);
189 auto proof = ivc.prove();
190 EXPECT_FALSE(
verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
207 const size_t NUM_APP_CIRCUITS = 2;
209 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
210 Chonk ivc{ NUM_CIRCUITS };
211 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
214 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
215 auto [circuit,
vk] = circuit_producer.create_next_circuit_and_vk(ivc, settings);
216 ivc.accumulate(circuit,
vk);
220 HidingKernelIOSerde tail_io;
221 for (
auto& it : std::ranges::reverse_view(ivc.verification_queue)) {
223 size_t num_public_inputs = it.honk_vk->num_public_inputs;
224 ASSERT_EQ(num_public_inputs, HidingKernelIOSerde::PUBLIC_INPUTS_SIZE)
225 <<
"Tail kernel should use HidingKernelIO format";
226 tail_io = HidingKernelIOSerde::from_proof(it.proof, num_public_inputs);
232 auto proof = ivc.prove();
233 auto vk_and_hash = ivc.get_hiding_kernel_vk_and_hash();
236 size_t hiding_kernel_pub_inputs = vk_and_hash->vk->num_public_inputs;
237 ASSERT_EQ(hiding_kernel_pub_inputs, HidingKernelIOSerde::PUBLIC_INPUTS_SIZE)
238 <<
"HidingKernel should use HidingKernelIO format";
239 HidingKernelIOSerde hiding_io = HidingKernelIOSerde::from_proof(proof.mega_proof, hiding_kernel_pub_inputs);
242 switch (field_to_test) {
244 EXPECT_EQ(tail_io.pairing_inputs.P0(), hiding_io.pairing_inputs.P0())
245 <<
"P0 mismatch: Tail has " << tail_io.pairing_inputs.P0() <<
" but HidingKernel has "
246 << hiding_io.pairing_inputs.P0();
247 EXPECT_EQ(tail_io.pairing_inputs.P1(), hiding_io.pairing_inputs.P1())
248 <<
"P1 mismatch: Tail has " << tail_io.pairing_inputs.P1() <<
" but HidingKernel has "
249 << hiding_io.pairing_inputs.P1();
252 EXPECT_EQ(tail_io.kernel_return_data, hiding_io.kernel_return_data)
253 <<
"kernel_return_data mismatch: Tail has " << tail_io.kernel_return_data <<
" but HidingKernel has "
254 << hiding_io.kernel_return_data;
257 for (
size_t i = 0; i < tail_io.ecc_op_tables.size(); ++i) {
258 EXPECT_EQ(tail_io.ecc_op_tables[i], hiding_io.ecc_op_tables[i])
259 <<
"M_tail[" << i <<
"] mismatch: Tail has " << tail_io.ecc_op_tables[i] <<
" but HidingKernel has "
260 << hiding_io.ecc_op_tables[i];
276 const size_t NUM_APP_CIRCUITS = 2;
280 auto [proof,
vk] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS, {},
true);
281 EXPECT_TRUE(verify_chonk(proof,
vk));
287 accumulate_and_prove_ivc(NUM_APP_CIRCUITS, { .log2_num_gates = SMALL_LOG_2_NUM_GATES },
true);
288 EXPECT_TRUE(verify_chonk(proof,
vk));
300 const size_t NUM_APP_CIRCUITS = 2;
301 auto [proof,
vk] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS);
303 EXPECT_TRUE(verify_chonk(proof,
vk));
317 const size_t NUM_APP_CIRCUITS = 2;
321 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
322 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
323 Chonk ivc{ NUM_CIRCUITS };
324 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
327 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
328 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings);
330 auto proof = ivc.prove();
331 EXPECT_TRUE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
336 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
337 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
338 Chonk ivc{ NUM_CIRCUITS };
340 size_t num_public_inputs = 0;
343 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
345 circuit_producer.create_next_circuit_and_vk(ivc, { .log2_num_gates = SMALL_LOG_2_NUM_GATES });
349 num_public_inputs = circuit.num_public_inputs();
353 EXPECT_EQ(ivc.verification_queue.size(), 2);
354 tamper_with_proof(ivc.verification_queue[0].proof,
358 auto proof = ivc.prove();
359 EXPECT_FALSE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
364 CircuitProducer circuit_producer(NUM_APP_CIRCUITS);
365 const size_t NUM_CIRCUITS = circuit_producer.total_num_circuits;
366 Chonk ivc{ NUM_CIRCUITS };
369 for (
size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
371 circuit_producer.create_next_circuit_and_vk(ivc, { .log2_num_gates = SMALL_LOG_2_NUM_GATES });
375 EXPECT_EQ(ivc.verification_queue.size(), 2);
376 tamper_with_proof(ivc.verification_queue[1].proof,
377 circuit.num_public_inputs());
380 auto proof = ivc.prove();
381 EXPECT_FALSE(verify_chonk(proof, ivc.get_hiding_kernel_vk_and_hash()));
391 const TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
393 auto [unused_1, vk_and_hash_1] = accumulate_and_prove_ivc(1, settings);
394 auto [unused_2, vk_and_hash_2] = accumulate_and_prove_ivc(3, settings);
397 EXPECT_EQ(*vk_and_hash_1->vk.get(), *vk_and_hash_2->vk.get());
407 const size_t NUM_APP_CIRCUITS = 1;
408 const size_t log2_num_gates_small = 5;
409 const size_t log2_num_gates_big = 18;
411 const TestSettings settings_1{ .log2_num_gates = log2_num_gates_small };
412 const TestSettings settings_2{ .log2_num_gates = log2_num_gates_big };
414 auto [unused_1, vk_and_hash_1] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS, settings_1);
415 auto [unused_2, vk_and_hash_2] = accumulate_and_prove_ivc(NUM_APP_CIRCUITS, settings_2);
418 EXPECT_EQ(*vk_and_hash_1->vk.get(), *vk_and_hash_2->vk.get());
429 const size_t NUM_APP_CIRCUITS = 17;
433 EXPECT_TRUE(verified);
443 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
444 auto [proof,
vk] = accumulate_and_prove_ivc(1, settings);
447 const std::string filename =
"proof.msgpack";
448 proof.to_file_msgpack(filename);
451 EXPECT_TRUE(verify_chonk(proof_deserialized,
vk));
455 uint8_t*
buffer = proof.to_msgpack_heap_buffer();
456 auto uint8_buffer = from_buffer<std::vector<uint8_t>>(
buffer);
457 uint8_t
const* uint8_ptr = uint8_buffer.data();
460 EXPECT_TRUE(verify_chonk(proof_deserialized,
vk));
464 msgpack::sbuffer
buffer = proof.to_msgpack_buffer();
466 EXPECT_TRUE(verify_chonk(proof_deserialized,
vk));
468 std::vector<uint8_t> random_bytes(
buffer.size());
469 std::generate(random_bytes.begin(), random_bytes.end(), []() { return static_cast<uint8_t>(rand() % 256); });
571 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
572 auto [proof, vk_and_hash] = accumulate_and_prove_ivc(1, settings);
574 auto original_flat = proof.to_field_elements();
575 info(
"Original proof size: ", original_flat.size(),
" Fr elements (", original_flat.size() * 32,
" bytes)");
578 double ratio =
static_cast<double>(original_flat.size() * 32) /
static_cast<double>(compressed.size());
579 info(
"Compressed proof size: ", compressed.size(),
" bytes");
580 info(
"Compression ratio: ", ratio,
"x");
583 EXPECT_GE(ratio, 1.5) <<
"Compression ratio " << ratio <<
"x is below the expected minimum of 1.5x";
590 ASSERT_EQ(decompressed_flat.size(), original_flat.size());
591 for (
size_t i = 0; i < original_flat.size(); i++) {
592 ASSERT_EQ(decompressed_flat[i], original_flat[i]) <<
"Mismatch at element " << i;
596 EXPECT_TRUE(verify_chonk(decompressed, vk_and_hash));
#define BB_DISABLE_ASSERTS()
TEST_F(ChonkTests, TestCircuitSizes)
Test sizes of the circuits generated by MockCircuitProducer.
PrivateFunctionExecutionMockCircuitProducer CircuitProducer
static void test_hiding_kernel_io_propagation(HidingKernelIOField field_to_test)
Helper function to test HidingKernelIO field propagation consistency.
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.
HidingKernelIOField
Enum for specifying which HidingKernelIO field to test for propagation consistency.
Flavor::Commitment Commitment
static void test_kernel_io_tampering(KernelIOField field_to_tamper)
Helper function to test tampering with KernelIO fields.
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, which, if verified, fully establishes the correctness of RCG.
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
ChonkVerifier< false > ChonkNativeVerifier
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
static ChonkProof_ from_msgpack_buffer(uint8_t const *&buffer)
static constexpr size_t HIDING_KERNEL_PROOF_LENGTH_WITHOUT_PUBLIC_INPUTS
std::vector< FF > to_field_elements() const
Serialize proof to field elements (native mode)
static ChonkProof_ from_file_msgpack(const std::string &filename)