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.
8#include "gtest/gtest.h"
9
10using namespace bb;
11
12// TODO(https://github.com/AztecProtocol/barretenberg/issues/1553): improve testing
13class HypernovaDeciderVerifierTests : public ::testing::Test {
14 protected:
16
17 public:
18 // Recursive decider verifier
22 using Builder = RecursiveFlavor::CircuitBuilder;
25
26 // Native decider verifier
29 using CommitmentKey = NativeFlavor::CommitmentKey;
30 using NativeFF = NativeFlavor::FF;
32 using NativeVerificationKey = NativeFlavor::VerificationKey;
34
35 // Provers
40
41 // Recursive Verifier
44
45 // Native Verifier
48
50
62 {
63 TranscriptManifest manifest;
64 constexpr size_t frs_per_G = FrCodec::calc_num_fields<curve::BN254::AffineElement>();
65 constexpr size_t NUM_GEMINI_FOLDS = NativeFlavor::VIRTUAL_LOG_N - 1; // 20
66 constexpr size_t NUM_GEMINI_EVALS = NativeFlavor::VIRTUAL_LOG_N; // 21
67 constexpr size_t FOLDING_ROUNDS = 50; // Rounds used by folding verifier
68
69 // Round 50: rho challenge
70 manifest.add_challenge(FOLDING_ROUNDS, "rho");
71
72 // Round 51: Gemini FOLD commitments -> Gemini:r
73 for (size_t i = 1; i <= NUM_GEMINI_FOLDS; ++i) {
74 manifest.add_entry(FOLDING_ROUNDS + 1, "Gemini:FOLD_" + std::to_string(i), frs_per_G);
75 }
76 manifest.add_challenge(FOLDING_ROUNDS + 1, "Gemini:r");
77
78 // Round 52: Gemini evaluations -> Shplonk:nu
79 for (size_t i = 1; i <= NUM_GEMINI_EVALS; ++i) {
80 manifest.add_entry(FOLDING_ROUNDS + 2, "Gemini:a_" + std::to_string(i), 1);
81 }
82 manifest.add_challenge(FOLDING_ROUNDS + 2, "Shplonk:nu");
83
84 // Round 53: Shplonk:Q -> Shplonk:z
85 manifest.add_entry(FOLDING_ROUNDS + 3, "Shplonk:Q", frs_per_G);
86 manifest.add_challenge(FOLDING_ROUNDS + 3, "Shplonk:z");
87
88 // Round 54: KZG:W -> KZG:masking_challenge
89 manifest.add_entry(FOLDING_ROUNDS + 4, "KZG:W", frs_per_G);
90 manifest.add_challenge(FOLDING_ROUNDS + 4, "KZG:masking_challenge");
91
92 return manifest;
93 }
94
107
109 const NativeVerifierAccumulator& rhs)
110 {
111 for (size_t idx = 0; auto [challenge_lhs, challenge_rhs] : zip_view(lhs.challenge, rhs.challenge)) {
112 if (challenge_lhs != challenge_rhs) {
113 info("Mismatch in the challenges at index ", idx);
114 return false;
115 }
116 }
118 info("Mismatch in the unshifted commitments");
119 return false;
120 }
121 if (lhs.shifted_commitment != rhs.shifted_commitment) {
122 info("Mismatch in the shifted commitments");
123 return false;
124 }
126 info("Mismatch in the unshifted evaluations");
127 return false;
128 }
129 if (lhs.shifted_evaluation != rhs.shifted_evaluation) {
130 info("Mismatch in the shifted evaluations");
131 return false;
132 }
133 return true;
134 }
135
142 {
143 using FF = RecursiveFlavor::FF;
144 using Commitment = RecursiveFlavor::Commitment;
145 using VerificationKey = RecursiveFlavor::VerificationKey;
146 using VKAndHash = RecursiveFlavor::VKAndHash;
147
148 // Create recursive VK from native VK
149 auto recursive_vk =
151 FF::from_witness(builder, native_instance->get_vk()->hash()));
152
153 // Create recursive instance with the recursive VK
154 auto recursive_instance = std::make_shared<RecursiveVerifierInstance>(recursive_vk);
155
156 // Convert alpha
157 recursive_instance->alpha = FF::from_witness(builder, native_instance->alpha);
158
159 // Convert witness commitments
160 auto native_comms = native_instance->witness_commitments.get_all();
161 for (auto [native_comm, recursive_comm] :
162 zip_view(native_comms, recursive_instance->witness_commitments.get_all())) {
163 recursive_comm = Commitment::from_witness(builder, native_comm);
164 }
165
166 // Convert gate challenges
167 recursive_instance->gate_challenges = std::vector<FF>(native_instance->gate_challenges.size());
168 for (auto [native_challenge, recursive_challenge] :
169 zip_view(native_instance->gate_challenges, recursive_instance->gate_challenges)) {
170 recursive_challenge = FF::from_witness(builder, native_challenge);
171 }
172
173 // Convert relation parameters
174 recursive_instance->relation_parameters.eta =
175 FF::from_witness(builder, native_instance->relation_parameters.eta);
176 recursive_instance->relation_parameters.eta_two =
177 FF::from_witness(builder, native_instance->relation_parameters.eta_two);
178 recursive_instance->relation_parameters.eta_three =
179 FF::from_witness(builder, native_instance->relation_parameters.eta_three);
180 recursive_instance->relation_parameters.beta =
181 FF::from_witness(builder, native_instance->relation_parameters.beta);
182 recursive_instance->relation_parameters.gamma =
183 FF::from_witness(builder, native_instance->relation_parameters.gamma);
184 recursive_instance->relation_parameters.public_input_delta =
185 FF::from_witness(builder, native_instance->relation_parameters.public_input_delta);
186
187 // For ZK flavors: convert gemini_masking_commitment
188 if constexpr (NativeFlavor::HasZK) {
189 recursive_instance->gemini_masking_commitment =
190 Commitment::from_witness(builder, native_instance->gemini_masking_commitment);
191 }
192
193 return recursive_instance;
194 }
195
197 {
198 switch (mode) {
201 break;
203 // Tamper with the accumulator by changing the challenge, this should invalidate the decider proof but not
204 // the folding
205 accumulator.challenge[0] = NativeFF::random_element();
206 break;
208 // Tamper the folded accumulator by changing one commitment, this should invalidate the PCS but not the
209 // folding.
210 accumulator.non_shifted_commitment =
211 accumulator.non_shifted_commitment + NativeFlavor::Curve::AffineElement::one();
212 break;
213 }
214 };
215
217 {
218 switch (mode) {
222 break;
224 // Tamper with the instance by changing w_l. This should invalidate the first sumcheck
225 instance->polynomials.w_l.at(1) = NativeFF::random_element();
226 break;
227 }
228 };
229
230 static void test_decider(const TamperingMode& mode)
231 {
232 // Generate accumulator
234 auto transcript = std::make_shared<NativeTranscript>();
235
236 HypernovaFoldingProver prover(transcript);
237 auto accumulator = prover.instance_to_accumulator(instance);
238 tamper_with_accumulator(accumulator, mode);
239
240 // Folding
241 auto incoming_instance = generate_new_instance(5);
242 tamper_with_instance(incoming_instance, mode);
243
244 auto incoming_vk = std::make_shared<NativeVerificationKey>(incoming_instance->get_precomputed());
245 auto incoming_verifier_instance =
247
248 auto prover_transcript = std::make_shared<NativeTranscript>();
249 HypernovaFoldingProver folding_prover(prover_transcript);
250 auto [folding_proof, folded_accumulator] = folding_prover.fold(accumulator, incoming_instance);
251 tamper_with_accumulator(folded_accumulator, mode);
252
253 // Construct Decider proof
254 auto ck = CommitmentKey(folded_accumulator.dyadic_size);
255 HypernovaDeciderProver decider_prover(prover_transcript);
256 auto decider_proof = decider_prover.construct_proof(ck, folded_accumulator);
257
258 // Natively verify the folding
259 auto native_transcript = std::make_shared<NativeTranscript>();
260 NativeHypernovaVerifier native_verifier(native_transcript);
261 auto [first_sumcheck_native, second_sumcheck_native, folded_verifier_accumulator_native] =
262 native_verifier.verify_folding_proof(incoming_verifier_instance, folding_proof);
263
264 // Enable manifest tracking before decider verification
265 native_transcript->enable_manifest();
266
267 // Natively verify the decider proof
268 NativeHypernovaDeciderVerifier decider_verifier(native_transcript);
269 auto native_pairing_points = decider_verifier.verify_proof(folded_verifier_accumulator_native, decider_proof);
270 bool native_verified = native_pairing_points.check();
271
272 // Recursively verify the folding
274
275 auto stdlib_incoming_instance = create_recursive_verifier_instance(&builder, incoming_verifier_instance);
276 auto recursive_verifier_transcript = std::make_shared<RecursiveTranscript>();
277 RecursiveHypernovaVerifier recursive_verifier(recursive_verifier_transcript);
278 RecursiveProof proof(builder, folding_proof);
279 auto [first_sumcheck_recursive, second_sumcheck_recursive, folded_verifier_accumulator] =
280 recursive_verifier.verify_folding_proof(stdlib_incoming_instance, proof);
281
282 // Recursively verify the Decider proof
283 RecursiveProof stdlib_proof(builder, decider_proof);
284 RecursiveHypernovaDeciderVerifier recursive_decider_verifier(recursive_verifier_transcript);
285 auto recursive_pairing_points =
286 recursive_decider_verifier.verify_proof(folded_verifier_accumulator, stdlib_proof);
287
288 // Natively verify pairing points
289 auto P0 = recursive_pairing_points.P0.get_value();
290 auto P1 = recursive_pairing_points.P1.get_value();
292 auto recursive_verified = pp.check();
293
294 // The circuit is valid if and only if we have not tampered or we have tampered the folded accumulator
297 // Pairing point verification should pass as long as we have not tampered the folded accumulator or the
298 // accumulator
299 EXPECT_EQ(recursive_verified, mode != TamperingMode::FoldedAccumulator && mode != TamperingMode::Accumulator);
300 EXPECT_EQ(recursive_verified, native_verified);
301 // First sumcheck fails if the instance has been tampered with
302 EXPECT_EQ(first_sumcheck_recursive, mode != TamperingMode::Instance);
303 EXPECT_EQ(first_sumcheck_recursive, first_sumcheck_native);
304 // Second sumcheck fails if the accumulator has been tampered with
305 EXPECT_EQ(second_sumcheck_recursive, mode != TamperingMode::Accumulator);
306 EXPECT_EQ(second_sumcheck_recursive, second_sumcheck_native);
307
308 // Pin the decider transcript manifest (only check when not tampering)
309 if (mode == TamperingMode::None) {
310 auto expected_manifest = build_expected_decider_manifest();
311 auto verifier_manifest = native_transcript->get_manifest();
312 EXPECT_EQ(verifier_manifest, expected_manifest);
313 }
314 }
315};
316
318{
319 test_decider(TamperingMode::None);
320}
321
323{
325 test_decider(TamperingMode::Accumulator);
326}
327
329{
331 test_decider(TamperingMode::Instance);
332}
333
334TEST_F(HypernovaDeciderVerifierTests, TamperWithFoldedAccumulator)
335{
336 test_decider(TamperingMode::FoldedAccumulator);
337}
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
std::shared_ptr< Napi::ThreadSafeFunction > instance
NativeHypernovaDeciderVerifier::Flavor NativeFlavor
static std::shared_ptr< RecursiveVerifierInstance > create_recursive_verifier_instance(Builder *builder, const std::shared_ptr< NativeVerifierInstance > &native_instance)
Test helper to create a recursive verifier instance from a native one.
static std::shared_ptr< ProverInstance > generate_new_instance(size_t log_num_gates=4)
RecursiveHypernovaDeciderVerifier::Proof RecursiveProof
NativeFlavor::VerificationKey NativeVerificationKey
NativeHypernovaVerifier::VerifierInstance NativeVerifierInstance
static void tamper_with_accumulator(NativeProverAccumulator &accumulator, const TamperingMode &mode)
RecursiveHypernovaVerifier::VerifierInstance RecursiveVerifierInstance
static bool compare_prover_verifier_accumulators(const NativeProverAccumulator &lhs, const NativeVerifierAccumulator &rhs)
static void test_decider(const TamperingMode &mode)
RecursiveHypernovaDeciderVerifier::Flavor RecursiveFlavor
static TranscriptManifest build_expected_decider_manifest()
Build the expected transcript manifest for HyperNova decider.
static void tamper_with_instance(std::shared_ptr< ProverInstance > &instance, const TamperingMode &mode)
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
HyperNova decider prover. Produces final opening proof for the accumulated claim.
HonkProof construct_proof(const CommitmentKey &ck, Accumulator &accumulator)
HyperNova decider verifier (native + recursive). Verifies final opening proof.
HypernovaFoldingVerifier< Flavor >::Accumulator Accumulator
PairingPoints verify_proof(Accumulator &accumulator, const Proof &proof)
std::conditional_t< IsRecursiveFlavor< Flavor >, typename HypernovaRecursiveTypes::Proof, typename HypernovaNativeTypes::Proof > Proof
std::conditional_t< IsRecursiveFlavor< Flavor >, typename HypernovaRecursiveTypes::PairingPoints, typename HypernovaNativeTypes::PairingPoints > PairingPoints
HyperNova folding prover. Folds circuit instances into accumulators, deferring PCS verification.
MultilinearBatchingProverClaim Accumulator
ProverInstance_< Flavor > ProverInstance
std::pair< HonkProof, Accumulator > fold(const Accumulator &accumulator, const std::shared_ptr< ProverInstance > &instance, const std::shared_ptr< VerificationKey > &honk_vk=nullptr)
Fold an instance into an accumulator. Folding happens in place.
Accumulator instance_to_accumulator(const std::shared_ptr< ProverInstance > &instance, const std::shared_ptr< VerificationKey > &honk_vk=nullptr)
Turn an instance into an accumulator by running Sumcheck.
HyperNova folding verifier (native + recursive). Verifies folding proofs and maintains accumulators.
std::tuple< bool, bool, Accumulator > verify_folding_proof(const std::shared_ptr< typename HypernovaFoldingVerifier::VerifierInstance > &instance, const Proof &proof)
Verify folding proof. Return the new accumulator and the results of the two sumchecks.
std::conditional_t< IsRecursiveFlavor< Flavor >, typename HypernovaRecursiveTypes::VerifierInstance, typename HypernovaNativeTypes::VerifierInstance > VerifierInstance
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:141
A ProverInstance is normally constructed from a finalized circuit and it contains all the information...
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.
void info(Args... args)
Definition log.hpp:89
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
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:185
CommitmentKey< Curve > ck
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)