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.
7#include "gtest/gtest.h"
8
9using namespace bb;
10
11// TODO(https://github.com/AztecProtocol/barretenberg/issues/1553): improve testing
12class HypernovaDeciderVerifierTests : public ::testing::Test {
13 protected:
15
16 public:
17 // Recursive decider verifier
21 using Builder = RecursiveFlavor::CircuitBuilder;
24
25 // Native decider verifier
28 using CommitmentKey = NativeFlavor::CommitmentKey;
29 using NativeFF = NativeFlavor::FF;
31 using NativeVerificationKey = NativeFlavor::VerificationKey;
33
34 // Provers
39
40 // Recursive Verifier
43
44 // Native Verifier
47
49
50 static std::shared_ptr<ProverInstance> generate_new_instance(size_t log_num_gates = 4)
51 {
53
57
59
60 return instance;
61 }
62
65 {
66 for (size_t idx = 0; auto [challenge_lhs, challenge_rhs] : zip_view(lhs.challenge, rhs.challenge)) {
67 if (challenge_lhs != challenge_rhs) {
68 info("Mismatch in the challenges at index ", idx);
69 return false;
70 }
71 }
73 info("Mismatch in the unshifted commitments");
74 return false;
75 }
77 info("Mismatch in the shifted commitments");
78 return false;
79 }
81 info("Mismatch in the unshifted evaluations");
82 return false;
83 }
85 info("Mismatch in the shifted evaluations");
86 return false;
87 }
88 return true;
89 }
90
91 static void tamper_with_accumulator(NativeProverAccumulator& accumulator, const TamperingMode& mode)
92 {
93 switch (mode) {
96 break;
98 // Tamper with the accumulator by changing the challenge, this should invalidate the decider proof but not
99 // the folding
100 accumulator.challenge[0] = NativeFF::random_element();
101 break;
103 // Tamper the folded accumulator by changing one commitment, this should invalidate the PCS but not the
104 // folding.
105 accumulator.non_shifted_commitment =
106 accumulator.non_shifted_commitment + NativeFlavor::Curve::AffineElement::one();
107 break;
108 }
109 };
110
111 static void tamper_with_instance(std::shared_ptr<ProverInstance>& instance, const TamperingMode& mode)
112 {
113 switch (mode) {
117 break;
119 // Tamper with the instance by changing w_l. This should invalidate the first sumcheck
120 instance->polynomials.w_l.at(1) = NativeFF::random_element();
121 break;
122 }
123 };
124
125 static void test_decider(const TamperingMode& mode)
126 {
127 // Generate accumulator
128 auto instance = generate_new_instance();
129 auto transcript = std::make_shared<NativeTranscript>();
130
131 HypernovaFoldingProver prover(transcript);
132 auto accumulator = prover.instance_to_accumulator(instance);
133 tamper_with_accumulator(accumulator, mode);
134
135 // Folding
136 auto incoming_instance = generate_new_instance(5);
137 tamper_with_instance(incoming_instance, mode);
138
139 auto incoming_vk = std::make_shared<NativeVerificationKey>(incoming_instance->get_precomputed());
140 auto incoming_verifier_instance = std::make_shared<NativeVerifierInstance>(incoming_vk);
141
142 auto prover_transcript = std::make_shared<NativeTranscript>();
143 HypernovaFoldingProver folding_prover(prover_transcript);
144 auto [folding_proof, folded_accumulator] = folding_prover.fold(accumulator, incoming_instance);
145 tamper_with_accumulator(folded_accumulator, mode);
146
147 // Construct Decider proof
148 auto ck = CommitmentKey(folded_accumulator.dyadic_size);
149 HypernovaDeciderProver decider_prover(prover_transcript);
150 auto decider_proof = decider_prover.construct_proof(ck, folded_accumulator);
151
152 // Natively verify the folding
153 auto native_transcript = std::make_shared<NativeTranscript>();
154 NativeHypernovaVerifier native_verifier(native_transcript);
155 auto [first_sumcheck_native, second_sumcheck_native, folded_verifier_accumulator_native] =
156 native_verifier.verify_folding_proof(incoming_verifier_instance, folding_proof);
157
158 // Natively verify the decider proof
159 NativeHypernovaDeciderVerifier decider_verifier(native_transcript);
160 auto native_pairing_points = decider_verifier.verify_proof(folded_verifier_accumulator_native, decider_proof);
161 bool native_verified = native_pairing_points.check();
162
163 // Recursively verify the folding
165
166 auto stdlib_incoming_instance =
167 std::make_shared<RecursiveVerifierInstance>(&builder, incoming_verifier_instance);
168 auto recursive_verifier_transcript = std::make_shared<RecursiveTranscript>();
169 RecursiveHypernovaVerifier recursive_verifier(recursive_verifier_transcript);
170 RecursiveProof proof(builder, folding_proof);
171 auto [first_sumcheck_recursive, second_sumcheck_recursive, folded_verifier_accumulator] =
172 recursive_verifier.verify_folding_proof(stdlib_incoming_instance, proof);
173
174 // Recursively verify the Decider proof
175 RecursiveProof stdlib_proof(builder, decider_proof);
176 RecursiveHypernovaDeciderVerifier recursive_decider_verifier(recursive_verifier_transcript);
177 auto recursive_pairing_points =
178 recursive_decider_verifier.verify_proof(folded_verifier_accumulator, stdlib_proof);
179
180 // Natively verify pairing points
181 auto P0 = recursive_pairing_points.P0.get_value();
182 auto P1 = recursive_pairing_points.P1.get_value();
184 auto recursive_verified = pp.check();
185
186 // The circuit is valid if and only if we have not tampered or we have tampered the folded accumulator
189 // Pairing point verification should pass as long as we have not tampered the folded accumulator or the
190 // accumulator
191 EXPECT_EQ(recursive_verified, mode != TamperingMode::FoldedAccumulator && mode != TamperingMode::Accumulator);
192 EXPECT_EQ(recursive_verified, native_verified);
193 // First sumcheck fails if the instance has been tampered with
194 EXPECT_EQ(first_sumcheck_recursive, mode != TamperingMode::Instance);
195 EXPECT_EQ(first_sumcheck_recursive, first_sumcheck_native);
196 // Second sumcheck fails if the accumulator has been tampered with
197 EXPECT_EQ(second_sumcheck_recursive, mode != TamperingMode::Accumulator);
198 EXPECT_EQ(second_sumcheck_recursive, second_sumcheck_native);
199 }
200};
201
203{
204 test_decider(TamperingMode::None);
205}
206
208{
210 test_decider(TamperingMode::Accumulator);
211}
212
214{
216 test_decider(TamperingMode::Instance);
217}
218
219TEST_F(HypernovaDeciderVerifierTests, TamperWithFoldedAccumulator)
220{
221 test_decider(TamperingMode::FoldedAccumulator);
222}
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:32
NativeHypernovaDeciderVerifier::Flavor NativeFlavor
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 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...
HonkProof construct_proof(const CommitmentKey &ck, Accumulator &accumulator)
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
MultilinearBatchingProverClaim Accumulator
std::pair< HonkProof, Accumulator > fold(const Accumulator &accumulator, const std::shared_ptr< ProverInstance > &instance)
Fold an instance into an accumulator. Folding happens in place.
ProverInstance_< Flavor > ProverInstance
Accumulator instance_to_accumulator(const std::shared_ptr< ProverInstance > &instance)
Turn an instance into an accumulator by running Sumcheck.
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.
A ProverInstance is normally constructed from a finalized circuit and it contains all the information...
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
void info(Args... args)
Definition log.hpp:74
AluTraceBuilder builder
Definition alu.test.cpp:123
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:188
CommitmentKey< Curve > ck
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13