Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
eccvm_recursive_verifier.test.cpp
Go to the documentation of this file.
11
12#include <gtest/gtest.h>
13
14namespace {
16}
17namespace bb {
18class ECCVMRecursiveTests : public ::testing::Test {
19 public:
30
33
35
42
49 static InnerBuilder generate_circuit(numeric::RNG* engine = nullptr, const size_t num_iterations = 1)
50 {
51 using Curve = curve::BN254;
52 using G1 = Curve::Element;
53 using Fr = Curve::ScalarField;
54
56 G1 a = G1::random_element(engine);
57 G1 b = G1::random_element(engine);
58 G1 c = G1::random_element(engine);
61 for (size_t idx = 0; idx < num_iterations; idx++) {
62 op_queue->add_accumulate(a);
63 op_queue->mul_accumulate(a, x);
64 op_queue->mul_accumulate(b, x);
65 op_queue->mul_accumulate(b, y);
66 op_queue->add_accumulate(a);
67 op_queue->mul_accumulate(b, x);
68 op_queue->eq_and_reset();
69 op_queue->add_accumulate(c);
70 op_queue->mul_accumulate(a, x);
71 op_queue->mul_accumulate(b, x);
72 op_queue->eq_and_reset();
73 op_queue->mul_accumulate(a, x);
74 op_queue->mul_accumulate(b, x);
75 op_queue->mul_accumulate(c, x);
76 op_queue->merge();
77 }
78 InnerBuilder builder{ op_queue };
79 return builder;
80 }
81
83 {
85 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
86 InnerProver prover(builder, prover_transcript);
87 ECCVMProof proof = prover.construct_proof();
88 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(prover.key);
89
90 info("ECCVM Recursive Verifier");
91 OuterBuilder outer_circuit;
93 RecursiveVerifier verifier{ &outer_circuit, verification_key, stdlib_verifier_transcript };
94 verifier.transcript->enable_manifest();
95 auto [opening_claim, ipa_transcript] = verifier.verify_proof(proof);
97
98 info("Recursive Verifier: num gates = ", outer_circuit.get_estimated_num_finalized_gates());
99
100 // Check for a failure flag in the recursive verifier circuit
101 EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err();
102
103 bool result = CircuitChecker::check(outer_circuit);
104 EXPECT_TRUE(result);
105
106 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
107 InnerVerifier native_verifier(verifier_transcript);
108 native_verifier.transcript->enable_manifest();
109 bool native_result = native_verifier.verify_proof(proof);
110 EXPECT_TRUE(native_result);
111 auto recursive_manifest = verifier.transcript->get_manifest();
112 auto native_manifest = native_verifier.transcript->get_manifest();
113
114 ASSERT_GT(recursive_manifest.size(), 0);
115 for (size_t i = 0; i < recursive_manifest.size(); ++i) {
116 EXPECT_EQ(recursive_manifest[i], native_manifest[i])
117 << "Recursive Verifier/Verifier manifest discrepency in round " << i;
118 }
119
120 // Ensure verification key is the same
121 EXPECT_EQ(static_cast<uint64_t>(verifier.key->log_circuit_size.get_value()),
122 verification_key->log_circuit_size);
123 EXPECT_EQ(static_cast<uint64_t>(verifier.key->num_public_inputs.get_value()),
124 verification_key->num_public_inputs);
125 for (auto [vk_poly, native_vk_poly] : zip_view(verifier.key->get_all(), verification_key->get_all())) {
126 EXPECT_EQ(vk_poly.get_value(), native_vk_poly);
127 }
128
129 // Construct a full proof from the recursive verifier circuit
130 {
131 auto proving_key = std::make_shared<OuterDeciderProvingKey>(outer_circuit);
132 auto verification_key = std::make_shared<OuterFlavor::VerificationKey>(proving_key->get_precomputed());
133 OuterProver prover(proving_key, verification_key);
134 OuterVerifier verifier(verification_key);
135 auto proof = prover.construct_proof();
136 bool verified = verifier.template verify_proof<DefaultIO>(proof).result;
137
138 ASSERT_TRUE(verified);
139 }
140 }
141
143 {
145 builder.op_queue->add_erroneous_equality_op_for_testing();
146 builder.op_queue->merge();
147 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
148 InnerProver prover(builder, prover_transcript);
149 ECCVMProof proof = prover.construct_proof();
150 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(prover.key);
151
152 OuterBuilder outer_circuit;
153
155 RecursiveVerifier verifier{ &outer_circuit, verification_key, stdlib_verifier_transcript };
156 [[maybe_unused]] auto output = verifier.verify_proof(proof);
158 info("Recursive Verifier: estimated num finalized gates = ", outer_circuit.get_estimated_num_finalized_gates());
159
160 // Check for a failure flag in the recursive verifier circuit
161 EXPECT_FALSE(CircuitChecker::check(outer_circuit));
162 }
163
165 {
166 for (size_t idx = 0; idx < 2; idx++) {
168 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
169 InnerProver prover(builder, prover_transcript);
170 ECCVMProof proof = prover.construct_proof();
171
172 // Tamper with the proof to be verified
173 tamper_with_proof<InnerProver, InnerFlavor>(proof.pre_ipa_proof, static_cast<bool>(idx));
174
175 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(prover.key);
176
177 OuterBuilder outer_circuit;
179 RecursiveVerifier verifier{ &outer_circuit, verification_key, stdlib_verifier_transcript };
180 auto [opening_claim, ipa_proof] = verifier.verify_proof(proof);
182
183 if (idx == 0) {
184 // In this case, we changed the first non-zero value in the proof. It leads to a circuit check failure.
185 EXPECT_FALSE(CircuitChecker::check(outer_circuit));
186 } else {
187 // Changing the last commitment in the `pre_ipa_proof` would not result in a circuit check failure at
188 // this stage.
189 EXPECT_TRUE(CircuitChecker::check(outer_circuit));
190
191 // However, IPA recursive verifier must fail, as one of the commitments is incorrect.
192 VerifierCommitmentKey<InnerFlavor::Curve> native_pcs_vk(1UL << CONST_ECCVM_LOG_N);
194 &outer_circuit, 1UL << CONST_ECCVM_LOG_N, native_pcs_vk);
195
196 // Construct ipa_transcript from proof
198 ipa_transcript->load_proof(ipa_proof);
199 EXPECT_FALSE(
200 IPA<RecursiveFlavor::Curve>::full_verify_recursive(stdlib_pcs_vkey, opening_claim, ipa_transcript));
201 }
202 }
203 }
204
206 {
207
208 // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit
209 auto get_blocks = [](size_t inner_size)
211 auto inner_circuit = generate_circuit(&engine, inner_size);
212 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
213 InnerProver inner_prover(inner_circuit, prover_transcript);
214
215 ECCVMProof inner_proof = inner_prover.construct_proof();
216 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(inner_prover.key);
217
218 // Create a recursive verification circuit for the proof of the inner circuit
219 OuterBuilder outer_circuit;
220
222 RecursiveVerifier verifier{ &outer_circuit, verification_key, stdlib_verifier_transcript };
223
224 auto [opening_claim, ipa_transcript] = verifier.verify_proof(inner_proof);
226
227 auto outer_proving_key = std::make_shared<OuterDeciderProvingKey>(outer_circuit);
228 auto outer_verification_key =
229 std::make_shared<OuterFlavor::VerificationKey>(outer_proving_key->get_precomputed());
230
231 return { outer_circuit.blocks, outer_verification_key };
232 };
233
234 auto [blocks_20, verification_key_20] = get_blocks(20);
235 auto [blocks_40, verification_key_40] = get_blocks(40);
236
237 compare_ultra_blocks_and_verification_keys<OuterFlavor>({ blocks_20, blocks_40 },
238 { verification_key_20, verification_key_40 });
239 };
240};
241
246
247TEST_F(ECCVMRecursiveTests, SingleRecursiveVerificationFailure)
248{
250};
251
252TEST_F(ECCVMRecursiveTests, SingleRecursiveVerificationFailureTamperedProof)
253{
255};
256
261} // namespace bb
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
const std::string & err() const
A DeciderProvingKey is normally constructed from a finalized circuit and it contains all the informat...
The proving key is responsible for storing the polynomials used by the prover.
The verification key is responsible for storing the commitments to the precomputed (non-witnessk) pol...
typename Curve::ScalarField FF
ECCVMCircuitBuilder CircuitBuilder
typename G1::affine_element Commitment
typename Curve::BaseField BF
NativeTranscript Transcript
ECCVMProof construct_proof()
std::shared_ptr< ProvingKey > key
bb::BaseTranscript< bb::stdlib::recursion::honk::StdlibTranscriptParams< CircuitBuilder > > Transcript
static InnerBuilder generate_circuit(numeric::RNG *engine=nullptr, const size_t num_iterations=1)
Adds operations in BN254 to the op_queue and then constructs and ECCVM circuit from the op_queue.
static void test_recursive_verification_failure_tampered_proof()
std::conditional_t< IsMegaBuilder< OuterBuilder >, MegaFlavor, UltraFlavor > OuterFlavor
bool verify_proof(const ECCVMProof &proof)
This function verifies an ECCVM Honk proof for given program settings.
std::shared_ptr< Transcript > transcript
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:95
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
size_t get_estimated_num_finalized_gates() const override
Get the final number of gates in a circuit, which consists of the sum of: 1) Current number number of...
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::element Element
Definition grumpkin.hpp:55
void info(Args... args)
Definition log.hpp:70
AluTraceBuilder builder
Definition alu.test.cpp:123
FF a
FF b
numeric::RNG & engine
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
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:123
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::AffineElement G1
HonkProof pre_ipa_proof
Definition proof.hpp:24
static field random_element(numeric::RNG *engine=nullptr) noexcept
static void add_default_to_public_inputs(Builder &builder)
Adds default public inputs to the builder.