Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
hypernova_decider_verifier.test.cpp
Go to the documentation of this file.
11#include "gtest/gtest.h"
12
13#include <optional>
14#include <vector>
15
16using namespace bb;
17
18// Folds a "previous accumulator + one instance" group (a 2-claim fold), then runs the HyperNova decider on the
19// resulting accumulator both natively and recursively. The folding-specific failure modes (instance tampering) are
20// covered in hypernova_verifier.test.cpp; here we cover the decider's binding to the folded accumulator and pin the
21// decider transcript manifest.
22class HypernovaDeciderVerifierTests : public ::testing::Test {
23 protected:
25
26 public:
31
36
47
48 static constexpr size_t LOG_NUM_GATES = 4;
49
50 enum class TamperingMode : uint8_t { None, FoldedAccumulator };
51
64 {
65 TranscriptManifest manifest;
66 constexpr size_t frs_per_G = FrCodec::calc_num_fields<curve::BN254::AffineElement>();
67 constexpr size_t NUM_GEMINI_FOLDS = NativeFlavor::VIRTUAL_LOG_N - 1;
68 constexpr size_t NUM_GEMINI_EVALS = NativeFlavor::VIRTUAL_LOG_N;
69 constexpr size_t LAST_FOLDING_ROUND = (2 * NativeFlavor::VIRTUAL_LOG_N) + 4;
70
71 // rho challenge (same round as the folding's final challenge)
72 manifest.add_challenge(LAST_FOLDING_ROUND, "rho");
73
74 // Gemini FOLD commitments -> Gemini:r
75 for (size_t i = 1; i <= NUM_GEMINI_FOLDS; ++i) {
76 manifest.add_entry(LAST_FOLDING_ROUND + 1, "Gemini:FOLD_" + std::to_string(i), frs_per_G);
77 }
78 manifest.add_challenge(LAST_FOLDING_ROUND + 1, "Gemini:r");
79
80 // Gemini evaluations -> Shplonk:nu
81 for (size_t i = 1; i <= NUM_GEMINI_EVALS; ++i) {
82 manifest.add_entry(LAST_FOLDING_ROUND + 2, "Gemini:a_" + std::to_string(i), 1);
83 }
84 manifest.add_challenge(LAST_FOLDING_ROUND + 2, "Shplonk:nu");
85
86 // Shplonk:Q -> Shplonk:z
87 manifest.add_entry(LAST_FOLDING_ROUND + 3, "Shplonk:Q", frs_per_G);
88 manifest.add_challenge(LAST_FOLDING_ROUND + 3, "Shplonk:z");
89
90 // KZG:W
91 manifest.add_entry(LAST_FOLDING_ROUND + 4, "KZG:W", frs_per_G);
92
93 return manifest;
94 }
95
104
107 {
108 using FF = RecursiveFlavor::FF;
109 using Commitment = RecursiveFlavor::Commitment;
111 using VKAndHash = RecursiveFlavor::VKAndHash;
112
113 auto recursive_vk =
115 FF::from_witness(builder, native_instance->get_vk()->hash()));
116 auto recursive_instance = std::make_shared<RecursiveVerifierInstance>(recursive_vk);
117
118 recursive_instance->alpha = FF::from_witness(builder, native_instance->alpha);
119 auto native_comms = native_instance->witness_commitments.get_all();
120 for (auto [native_comm, recursive_comm] :
121 zip_view(native_comms, recursive_instance->witness_commitments.get_all())) {
122 recursive_comm = Commitment::from_witness(builder, native_comm);
123 }
124 recursive_instance->gate_challenges = std::vector<FF>(native_instance->gate_challenges.size());
125 for (auto [native_challenge, recursive_challenge] :
126 zip_view(native_instance->gate_challenges, recursive_instance->gate_challenges)) {
127 recursive_challenge = FF::from_witness(builder, native_challenge);
128 }
129 recursive_instance->relation_parameters.eta =
130 FF::from_witness(builder, native_instance->relation_parameters.eta);
131 recursive_instance->relation_parameters.eta_two =
132 FF::from_witness(builder, native_instance->relation_parameters.eta_two);
133 recursive_instance->relation_parameters.eta_three =
134 FF::from_witness(builder, native_instance->relation_parameters.eta_three);
135 recursive_instance->relation_parameters.beta =
136 FF::from_witness(builder, native_instance->relation_parameters.beta);
137 recursive_instance->relation_parameters.gamma =
138 FF::from_witness(builder, native_instance->relation_parameters.gamma);
139 recursive_instance->relation_parameters.public_input_delta =
140 FF::from_witness(builder, native_instance->relation_parameters.public_input_delta);
141 if constexpr (NativeFlavor::HasZK) {
142 recursive_instance->gemini_masking_commitment =
143 Commitment::from_witness(builder, native_instance->gemini_masking_commitment);
144 }
145 return recursive_instance;
146 }
147
152 {
153 auto transcript = std::make_shared<NativeTranscript>();
154 FoldingProver prover(transcript);
156 auto [_proof, accumulator] = prover.finalize();
157 return accumulator;
158 }
159
161 {
162 // Previous accumulator (claim 0) folded with one incoming instance (claim 1): a 2-claim fold.
163 ProverAccumulator previous_prover_accumulator = make_previous_accumulator();
164 NativeVerifierAccumulator previous_native_accumulator =
165 previous_prover_accumulator.to_verifier_claim_for_testing();
166
167 auto incoming_instance = generate_new_instance(5);
168 auto incoming_vk = std::make_shared<NativeVerificationKey>(incoming_instance->get_precomputed());
169
170 // ---- Prover: fold, then construct the decider proof on the folded accumulator ----
171 auto prover_transcript = std::make_shared<NativeTranscript>();
172 FoldingProver prover(prover_transcript);
173 HonkProof instance_proof = prover.accumulate_instance<NativeFlavor>(incoming_instance, incoming_vk);
174 auto [batch_proof, prover_accumulator] = prover.finalize(previous_prover_accumulator);
175
176 // Tamper the folded accumulator's polynomial after folding but before the decider: the decider proof then
177 // opens to a value inconsistent with the (honest) committed accumulator the verifier reconstructs.
179 prover_accumulator.non_shifted_polynomial.at(0) = NativeFF::random_element();
180 }
181 DeciderProver decider_prover(prover_transcript);
182 auto decider_proof = decider_prover.construct_proof(prover_accumulator);
183
184 // ---- Native: fold, then verify the decider proof ----
185 auto incoming_native_verifier_instance =
187 auto native_transcript = std::make_shared<NativeTranscript>();
188 NativeVerifier native_verifier(native_transcript);
189 native_verifier.accumulate_instance<NativeFlavor>(incoming_native_verifier_instance, instance_proof);
190 auto [native_folded, native_accumulator] = native_verifier.finalize(batch_proof, previous_native_accumulator);
191
192 // Pin the decider transcript manifest (only meaningful in the untampered case): enable tracking after
193 // folding so only the decider rounds are recorded.
194 if (mode == TamperingMode::None) {
195 native_transcript->enable_manifest();
196 }
197 NativeDeciderVerifier native_decider_verifier(native_transcript);
198 bool native_decider_verified = native_decider_verifier.verify_proof(native_accumulator, decider_proof).check();
199
200 // ---- Recursive: fold, then verify the decider proof ----
202 auto incoming_recursive_instance =
203 create_recursive_verifier_instance(&builder, incoming_native_verifier_instance);
204 auto previous_recursive_accumulator =
205 create_recursive_verifier_accumulator(&builder, previous_native_accumulator);
206 auto recursive_transcript = std::make_shared<RecursiveTranscript>();
207 RecursiveVerifier recursive_verifier(recursive_transcript);
208 stdlib::Proof<Builder> stdlib_instance_proof(builder, instance_proof);
209 recursive_verifier.accumulate_instance<RecursiveFlavor>(incoming_recursive_instance, stdlib_instance_proof);
210 stdlib::Proof<Builder> stdlib_batch_proof(builder, batch_proof);
211 auto [recursive_folded, recursive_accumulator] =
212 recursive_verifier.finalize(stdlib_batch_proof, previous_recursive_accumulator);
213 stdlib::Proof<Builder> stdlib_decider_proof(builder, decider_proof);
214 RecursiveDeciderVerifier recursive_decider_verifier(recursive_transcript);
215 bool recursive_decider_verified =
216 recursive_decider_verifier.verify_proof(recursive_accumulator, stdlib_decider_proof).check();
217
218 const bool tampered = (mode == TamperingMode::FoldedAccumulator);
219 // Folding succeeds in both modes (the tampering is applied after folding); the circuit is satisfiable.
220 EXPECT_TRUE(native_folded);
221 EXPECT_TRUE(recursive_folded);
223 // The decider pairing check passes iff the folded accumulator was not tampered.
224 EXPECT_EQ(native_decider_verified, !tampered);
225 EXPECT_EQ(recursive_decider_verified, native_decider_verified);
226
227 if (mode == TamperingMode::None) {
228 auto expected_manifest = build_expected_decider_manifest();
229 auto verifier_manifest = native_transcript->get_manifest();
230 EXPECT_EQ(verifier_manifest, expected_manifest);
231 }
232 }
233};
234
236{
237 test_decider(TamperingMode::None);
238}
239
240TEST_F(HypernovaDeciderVerifierTests, TamperWithFoldedAccumulator)
241{
242 test_decider(TamperingMode::FoldedAccumulator);
243}
static std::shared_ptr< RecursiveVerifierInstance > create_recursive_verifier_instance(Builder *builder, const std::shared_ptr< NativeVerifierInstance > &native_instance)
static ProverAccumulator make_previous_accumulator()
Build a valid previous accumulator (a single-instance fold) on a separate, discarded transcript.
static std::shared_ptr< ProverInstance > generate_new_instance(size_t log_num_gates=LOG_NUM_GATES)
RecursiveVerifier::Transcript RecursiveTranscript
static void test_decider(TamperingMode mode)
static TranscriptManifest build_expected_decider_manifest()
Build the expected transcript manifest for the HyperNova decider.
HyperNova decider prover. Produces final opening proof for the accumulated claim.
HonkProof construct_proof(Accumulator &accumulator)
HyperNova decider verifier (native + recursive). Verifies final opening proof.
PairingPoints verify_proof(Accumulator &accumulator, const Proof &proof)
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.
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 kernel circuits.
static constexpr bool HasZK
static constexpr size_t VIRTUAL_LOG_N
NativeVerificationKey_< PrecomputedEntities< Commitment >, Codec, HashFunction, CommitmentKey > VerificationKey
Recursive counterpart to MegaKernelFlavor.
VKAndHash_< FF, VerificationKey > VKAndHash
StdlibVerificationKey_< CircuitBuilder, NativeFlavor::PrecomputedEntities< Commitment >, NativeFlavor::VerificationKey > VerificationKey
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.
Base Native verification key class.
Definition flavor.hpp:138
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.
Definition proof.hpp:20
AluTraceBuilder builder
Definition alu.test.cpp:124
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
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:160
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
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
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