12#include "gtest/gtest.h"
30 "expected manifest only defined for MegaKernelFlavor / MegaAppFlavor");
36 "SECOND_APP_CALLDATA",
"THIRD_APP_CALLDATA",
37 "FOURTH_APP_CALLDATA",
"FIFTH_APP_CALLDATA",
39 std::vector<std::string> buses;
40 for (
size_t builder_idx : Flavor::BUILDER_BUS_INDICES) {
41 buses.emplace_back(ALL_BUSES[builder_idx]);
45 constexpr size_t frs_per_G = FrCodec::calc_num_fields<curve::BN254::AffineElement>();
46 constexpr size_t NUM_SUMCHECK_UNIVARIATES = Flavor::VIRTUAL_LOG_N;
51 manifest.
add_challenge(round, std::array{
"eta",
"rom_logup_gamma" });
53 for (
size_t i = 0; i < 4; ++i) {
56 for (
const auto& wire : {
"W_L",
"W_R",
"W_O" }) {
57 manifest.
add_entry(round, wire, frs_per_G);
59 for (
const auto& wire : {
"ECC_OP_WIRE_1",
"ECC_OP_WIRE_2",
"ECC_OP_WIRE_3",
"ECC_OP_WIRE_4" }) {
60 manifest.
add_entry(round, wire, frs_per_G);
62 for (
const auto& bus : buses) {
63 manifest.
add_entry(round, bus, frs_per_G);
64 manifest.
add_entry(round, bus +
"_READ_COUNTS", frs_per_G);
70 if constexpr (has_lookup) {
71 manifest.
add_entry(round,
"LOOKUP_READ_COUNTS", frs_per_G);
72 manifest.
add_entry(round,
"LOOKUP_READ_TAGS", frs_per_G);
74 manifest.
add_entry(round,
"W_4", frs_per_G);
79 manifest.
add_challenge(round,
"HypernovaFoldingProver:gate_challenge");
80 if constexpr (has_lookup) {
81 manifest.
add_entry(round,
"LOOKUP_INVERSES", frs_per_G);
83 for (
const auto& bus : buses) {
84 manifest.
add_entry(round, bus +
"_INVERSES", frs_per_G);
86 manifest.
add_entry(round,
"Z_PERM", frs_per_G);
90 for (
size_t i = 0; i < NUM_SUMCHECK_UNIVARIATES; ++i) {
98 for (
size_t i = 0; i < Flavor::NUM_UNSHIFTED_ENTITIES - 1; ++i) {
101 for (
size_t i = 0; i < Flavor::NUM_SHIFTED_ENTITIES - 1; ++i) {
110 for (
size_t i = 0; i < NUM_SUMCHECK_UNIVARIATES; ++i) {
152 template <
typename Flavor>
164 for (
size_t idx = 0;
auto [challenge_lhs, challenge_rhs] :
zip_view(
lhs.challenge,
rhs.challenge)) {
165 if (challenge_lhs != challenge_rhs) {
166 info(
"Mismatch in the challenges at index ", idx);
170 if (
lhs.non_shifted_commitment !=
rhs.non_shifted_commitment) {
171 info(
"Mismatch in the unshifted commitments");
174 if (
lhs.shifted_commitment !=
rhs.shifted_commitment) {
175 info(
"Mismatch in the shifted commitments");
178 if (
lhs.non_shifted_evaluation !=
rhs.non_shifted_evaluation) {
179 info(
"Mismatch in the unshifted evaluations");
182 if (
lhs.shifted_evaluation !=
rhs.shifted_evaluation) {
183 info(
"Mismatch in the shifted evaluations");
192 template <
typename NativeFlavor,
typename RecursiveFlavor>
196 using FF =
typename RecursiveFlavor::FF;
197 using Commitment =
typename RecursiveFlavor::Commitment;
199 using VKAndHash =
typename RecursiveFlavor::VKAndHash;
203 FF::from_witness(
builder, native_instance->get_vk()->hash()));
206 recursive_instance->alpha = FF::from_witness(
builder, native_instance->alpha);
208 auto native_comms = native_instance->witness_commitments.get_all();
209 for (
auto [native_comm, recursive_comm] :
210 zip_view(native_comms, recursive_instance->witness_commitments.get_all())) {
211 recursive_comm = Commitment::from_witness(
builder, native_comm);
214 recursive_instance->gate_challenges = std::vector<FF>(native_instance->gate_challenges.size());
215 for (
auto [native_challenge, recursive_challenge] :
216 zip_view(native_instance->gate_challenges, recursive_instance->gate_challenges)) {
217 recursive_challenge = FF::from_witness(
builder, native_challenge);
220 recursive_instance->relation_parameters.eta =
221 FF::from_witness(
builder, native_instance->relation_parameters.eta);
222 recursive_instance->relation_parameters.eta_two =
223 FF::from_witness(
builder, native_instance->relation_parameters.eta_two);
224 recursive_instance->relation_parameters.eta_three =
225 FF::from_witness(
builder, native_instance->relation_parameters.eta_three);
226 recursive_instance->relation_parameters.beta =
227 FF::from_witness(
builder, native_instance->relation_parameters.beta);
228 recursive_instance->relation_parameters.gamma =
229 FF::from_witness(
builder, native_instance->relation_parameters.gamma);
230 recursive_instance->relation_parameters.public_input_delta =
231 FF::from_witness(
builder, native_instance->relation_parameters.public_input_delta);
233 if constexpr (NativeFlavor::HasZK) {
234 recursive_instance->gemini_masking_commitment =
235 Commitment::from_witness(
builder, native_instance->gemini_masking_commitment);
238 return recursive_instance;
244 auto& q_arith = instance->polynomials.q_arith();
246 if (!q_arith[i].is_zero()) {
261 auto [_proof, accumulator] = prover.
finalize();
274 prover_instances.reserve(num_instances);
275 vks.reserve(num_instances);
276 for (
size_t i = 0; i < num_instances; ++i) {
277 prover_instances.push_back(generate_instance<KernelFlavor>(
LOG_NUM_GATES + i));
281 tamper_instance<KernelFlavor>(prover_instances.back());
286 if (use_previous_accumulator) {
288 previous_native_accumulator = previous_prover_accumulator->to_verifier_claim_for_testing();
295 proofs.reserve(num_instances);
296 for (
size_t i = 0; i < num_instances; ++i) {
299 auto [batch_proof, prover_accumulator] =
300 prover.
finalize(previous_prover_accumulator.has_value() ? previous_prover_accumulator :
std::nullopt);
304 native_verifier_instances.reserve(num_instances);
305 for (
size_t i = 0; i < num_instances; ++i) {
306 native_verifier_instances.push_back(
311 std::vector<bool> native_sumchecks;
312 native_sumchecks.reserve(num_instances);
313 for (
size_t i = 0; i < num_instances; ++i) {
314 native_sumchecks.push_back(
317 auto [native_verified, native_accumulator] = native_verifier.
finalize(
318 batch_proof, previous_native_accumulator.has_value() ? previous_native_accumulator :
std::nullopt);
323 recursiver_verifier_instances.reserve(num_instances);
324 for (
size_t i = 0; i < num_instances; ++i) {
325 recursiver_verifier_instances.push_back(
326 make_recursive_verifier_instance<KernelFlavor, KernelRecursiveFlavor>(&
builder,
327 native_verifier_instances[i]));
330 if (previous_native_accumulator.has_value()) {
331 previous_recursive_accumulator =
336 std::vector<bool> recursive_sumchecks;
337 recursive_sumchecks.reserve(num_instances);
338 for (
size_t i = 0; i < num_instances; ++i) {
341 recursiver_verifier_instances[i], stdlib_proof));
344 auto [recursive_verified, recursive_accumulator] = recursive_verifier.
finalize(
346 previous_recursive_accumulator.has_value() ? previous_recursive_accumulator :
std::nullopt);
350 for (
size_t i = 0; i < num_instances; ++i) {
351 const bool expected = !tampered || i != num_instances - 1;
352 EXPECT_EQ(native_sumchecks[i], expected) <<
"native instance " << i;
353 EXPECT_EQ(recursive_sumchecks[i], native_sumchecks[i]) <<
"recursive instance " << i;
356 EXPECT_TRUE(native_verified);
357 EXPECT_EQ(recursive_verified, native_verified);
360 prover_accumulator, recursive_accumulator.template get_value<NativeVerifierAccumulator>()));
377 auto [_proof, accumulator] = prover.
finalize();
383 auto incoming_instance = generate_instance<Flavor>(
LOG_NUM_GATES + 1);
388 auto [batch_proof, _folded] = folding_prover.
finalize(previous_prover_accumulator);
391 auto incoming_verifier_instance =
394 verifier_transcript->enable_manifest();
397 verifier.
finalize(batch_proof, previous_verifier_accumulator);
399 auto actual_manifest = verifier_transcript->get_manifest();
400 auto expected_manifest = build_expected_folding_manifest<Flavor>();
401 ASSERT_EQ(actual_manifest.size(), expected_manifest.size());
402 for (
size_t round = 0; round < actual_manifest.size(); ++round) {
403 EXPECT_EQ(actual_manifest[round], expected_manifest[round])
404 <<
"folding manifest discrepancy in round " << round;
412 for (
size_t num_instances = 1; num_instances <= CHONK_MAX_CLAIMS_PER_KERNEL; ++num_instances) {
413 test_folding(num_instances,
false, TamperingMode::None);
419 for (
size_t num_instances = 1; num_instances < CHONK_MAX_CLAIMS_PER_KERNEL; ++num_instances) {
420 test_folding(num_instances,
true, TamperingMode::None);
429 auto kernel_instance = generate_instance<KernelFlavor>();
430 auto app_instance_0 = generate_instance<AppFlavor>(LOG_NUM_GATES + 1);
431 auto app_instance_1 = generate_instance<AppFlavor>(LOG_NUM_GATES + 2);
438 FoldingProver prover(prover_transcript);
439 HonkProof kernel_proof = prover.accumulate_instance<KernelFlavor>(kernel_instance, kernel_vk);
440 HonkProof app_proof_0 = prover.accumulate_instance<AppFlavor>(app_instance_0, app_vk_0);
441 HonkProof app_proof_1 = prover.accumulate_instance<AppFlavor>(app_instance_1, app_vk_1);
442 auto [batch_proof, prover_accumulator] = prover.finalize();
445 auto kernel_verifier_instance =
447 auto app_verifier_instance_0 =
449 auto app_verifier_instance_1 =
452 NativeVerifier native_verifier(native_transcript);
453 EXPECT_TRUE(native_verifier.accumulate_instance<KernelFlavor>(kernel_verifier_instance, kernel_proof));
454 EXPECT_TRUE(native_verifier.accumulate_instance<AppFlavor>(app_verifier_instance_0, app_proof_0));
455 EXPECT_TRUE(native_verifier.accumulate_instance<AppFlavor>(app_verifier_instance_1, app_proof_1));
456 auto [native_verified, native_accumulator] = native_verifier.finalize(batch_proof);
460 auto kernel_recursive_instance =
461 make_recursive_verifier_instance<KernelFlavor, KernelRecursiveFlavor>(&
builder, kernel_verifier_instance);
462 auto app_recursive_instance_0 =
463 make_recursive_verifier_instance<AppFlavor, AppRecursiveFlavor>(&
builder, app_verifier_instance_0);
464 auto app_recursive_instance_1 =
465 make_recursive_verifier_instance<AppFlavor, AppRecursiveFlavor>(&
builder, app_verifier_instance_1);
467 RecursiveVerifier recursive_verifier(recursive_transcript);
469 recursive_verifier.accumulate_instance<KernelRecursiveFlavor>(kernel_recursive_instance, stdlib_kernel_proof);
471 recursive_verifier.accumulate_instance<AppRecursiveFlavor>(app_recursive_instance_0, stdlib_app_proof_0);
473 recursive_verifier.accumulate_instance<AppRecursiveFlavor>(app_recursive_instance_1, stdlib_app_proof_1);
475 auto [recursive_verified, recursive_accumulator] = recursive_verifier.finalize(stdlib_batch_proof);
478 EXPECT_TRUE(native_verified);
479 EXPECT_EQ(recursive_verified, native_verified);
480 EXPECT_TRUE(compare_prover_verifier_accumulators(prover_accumulator, native_accumulator));
481 EXPECT_TRUE(compare_prover_verifier_accumulators(
482 prover_accumulator, recursive_accumulator.template get_value<NativeVerifierAccumulator>()));
490 test_folding(3,
false, TamperingMode::Instance);
497 expect_folding_manifest<bb::MegaKernelFlavor>();
502 expect_folding_manifest<bb::MegaAppFlavor>();
#define BB_DISABLE_ASSERTS()
static void SetUpTestSuite()
void expect_folding_manifest()
Drive a "previous accumulator + one instance" folding session through the native verifier with manife...
static std::shared_ptr< ProverInstance_< Flavor > > generate_instance(size_t log_num_gates=LOG_NUM_GATES)
RecursiveVerifier::Transcript RecursiveTranscript
static ProverAccumulator make_previous_accumulator()
Build a valid previous accumulator (a single-instance fold) for the prover and verifiers.
NativeVerifier::Transcript NativeTranscript
static constexpr size_t LOG_NUM_GATES
static bool compare_prover_verifier_accumulators(const ProverAccumulator &lhs, const NativeVerifierAccumulator &rhs)
static void tamper_instance(const std::shared_ptr< ProverInstance_< Flavor > > &instance)
static void test_folding(size_t num_instances, bool use_previous_accumulator, TamperingMode mode)
Fold num_instances kernel instances with the prover, then verify the group natively and recursively.
static std::shared_ptr< VerifierInstance_< RecursiveFlavor > > make_recursive_verifier_instance(Builder *builder, const std::shared_ptr< VerifierInstance_< NativeFlavor > > &native_instance)
Build a recursive verifier instance from a native one (already populated by the native verifier).
static constexpr size_t NUM_ALL_ENTITIES
HyperNova folding prover. Folds circuit instances into accumulators, deferring PCS verification.
MultilinearBatchingProverClaim Accumulator
std::pair< HonkProof, Accumulator > finalize(std::optional< Accumulator > previous_accumulator=std::nullopt)
Batch the previous accumulator (if any) and the cached claims into a single accumulator.
HonkProof accumulate_instance(const std::shared_ptr< ProverInstance_< InstanceFlavor > > &instance, const std::shared_ptr< typename InstanceFlavor::VerificationKey > &honk_vk=nullptr)
Turn an instance into an accumulator and cache the resulting claim for the final batching.
MegaFlavor::Transcript Transcript
Stateful HyperNova folding verifier (native + recursive). Verifies a series of instances against a st...
std::pair< bool, Accumulator > finalize(const Proof &batching_proof, std::optional< Accumulator > previous_accumulator=std::nullopt)
Batch the previous accumulator (if any) and the cached claims into a single accumulator.
typename BaseFlavor::Transcript Transcript
bool accumulate_instance(const std::shared_ptr< VerifierInstance< InstanceFlavor > > &instance, const Proof &proof)
Verify the instance-to-accumulator sumcheck of one incoming proof and cache the resulting claim.
MultilinearBatchingVerifierClaim< Curve > Accumulator
Mega flavor specialized for Chonk app circuits.
Recursive counterpart to MegaAppFlavor.
Mega flavor specialized for Chonk kernel circuits.
Recursive counterpart to MegaKernelFlavor.
MegaCircuitBuilder CircuitBuilder
static void add_arithmetic_gates_with_public_inputs(Builder &builder, const size_t num_gates=4)
Add a specified number of arithmetic gates (with public inputs) to the provided circuit.
static void add_lookup_gates(Builder &builder, size_t num_iterations=1)
Add lookup gates using the uint32 XOR lookup table (table size 4096)
static void add_arithmetic_gates(Builder &builder, const size_t num_gates=4)
Add a specified number of arithmetic gates to the provided circuit.
Native flavor for multilinear batching sumcheck with NumClaims polynomials.
Base Native verification key class.
Contains all the information required by a Honk prover to create a proof, constructed from a finalize...
void add_entry(size_t round, const std::string &element_label, size_t element_size)
void add_challenge(size_t round, const std::string &label)
Add a single challenge label to the manifest for the given round.
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
The VerifierInstance encapsulates all the necessary information for a Honk Verifier to verify a proof...
A simple wrapper around a vector of stdlib field elements representing a proof.
TranscriptManifest build_expected_folding_manifest()
Build the expected HyperNova folding transcript manifest for a "previous accumulator + one instance" ...
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
TEST_F(IPATest, ChallengesAreZero)
MultilinearBatchingVerifierClaim< bb::MegaKernelRecursiveFlavor::Curve > create_recursive_verifier_accumulator(MegaCircuitBuilder *builder, const MultilinearBatchingVerifierClaim< bb::MegaKernelFlavor::Curve > &native_accumulator)
Test helper to create a recursive verifier accumulator from a native one.
HypernovaFoldingVerifier< true > HypernovaFoldingRecursiveVerifier
HypernovaFoldingVerifier< false > HypernovaFoldingNativeVerifier
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::string to_string(bb::avm2::ValueTag tag)
bb::VectorAffineElementPushSpan< BaseParams > lhs
bb::VectorAffineElementPushSpan< BaseParams > rhs
Prover's claim for multilinear batching - contains polynomials and their evaluation claims.
MultilinearBatchingVerifierClaim< curve::BN254 > to_verifier_claim_for_testing() const
Verifier's claim for multilinear batching - contains commitments and evaluation claims.
static field random_element(numeric::RNG *engine=nullptr) noexcept