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.
13
14#include <gtest/gtest.h>
15
16namespace {
18}
19namespace bb {
20class ECCVMRecursiveTests : public ::testing::Test {
21 public:
32
35
37
44
51 static InnerBuilder generate_circuit(numeric::RNG* engine = nullptr, const size_t num_iterations = 1)
52 {
53 using Curve = curve::BN254;
54 using G1 = Curve::Element;
55 using Fr = Curve::ScalarField;
57
59 G1 a = G1::random_element(engine);
60 G1 b = G1::random_element(engine);
61 G1 c = G1::random_element(engine);
64 for (size_t idx = 0; idx < num_iterations; idx++) {
65 op_queue->add_accumulate(a);
66 op_queue->mul_accumulate(a, x);
67 op_queue->mul_accumulate(b, x);
68 op_queue->mul_accumulate(b, y);
69 op_queue->add_accumulate(a);
70 op_queue->mul_accumulate(b, x);
71 op_queue->eq_and_reset();
72 op_queue->add_accumulate(c);
73 op_queue->mul_accumulate(a, x);
74 op_queue->mul_accumulate(b, x);
75 op_queue->eq_and_reset();
76 op_queue->mul_accumulate(a, x);
77 op_queue->mul_accumulate(b, x);
78 op_queue->mul_accumulate(c, x);
79 op_queue->merge();
80 }
81 // Set hiding op for ECCVM ZK (required before ECCVMCircuitBuilder construction)
82 op_queue->append_hiding_op(Fq::random_element(engine), Fq::random_element(engine));
83 InnerBuilder builder{ op_queue };
84 return builder;
85 }
86
88 {
90 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
91 InnerProver prover(builder, prover_transcript);
92 auto [proof, opening_claim] = prover.construct_proof();
93
94 // Compute IPA proof
95 auto ipa_transcript = std::make_shared<Transcript>();
96 ECCVMFlavor::PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
97 HonkProof ipa_proof = ipa_transcript->export_proof();
98
99 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(prover.key);
100
101 info("ECCVM Recursive Verifier");
102 OuterBuilder outer_circuit;
103 auto stdlib_proof = stdlib::Proof<OuterBuilder>(outer_circuit, proof);
105 RecursiveVerifier verifier{ stdlib_verifier_transcript, stdlib_proof };
106 verifier.transcript->enable_manifest();
107 [[maybe_unused]] auto recursive_opening_claim = verifier.verify_proof();
109
110 info("Recursive Verifier: num gates = ", outer_circuit.get_num_finalized_gates_inefficient());
111
112 // Check for a failure flag in the recursive verifier circuit
113 EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err();
114
115 bool result = CircuitChecker::check(outer_circuit);
116 EXPECT_TRUE(result);
117
118 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
119 InnerVerifier native_verifier(verifier_transcript, proof);
120 native_verifier.transcript->enable_manifest();
121 auto native_opening_claim = native_verifier.verify_proof();
122
123 // Verify IPA
124 auto ipa_verify_transcript = std::make_shared<Transcript>();
125 ipa_verify_transcript->load_proof(ipa_proof);
126 bool ipa_verified = ECCVMFlavor::PCS::reduce_verify(
127 native_verifier.key->pcs_verification_key, native_opening_claim, ipa_verify_transcript);
128 bool native_result = ipa_verified && native_verifier.sumcheck_verified && native_verifier.consistency_checked &&
130 EXPECT_TRUE(native_result);
131 auto recursive_manifest = verifier.transcript->get_manifest();
132 auto native_manifest = native_verifier.transcript->get_manifest();
133
134 ASSERT_GT(recursive_manifest.size(), 0);
135 for (size_t i = 0; i < recursive_manifest.size(); ++i) {
136 EXPECT_EQ(recursive_manifest[i], native_manifest[i])
137 << "Recursive Verifier/Verifier manifest discrepency in round " << i;
138 }
139
140 // Ensure verification key is the same
141 EXPECT_EQ(static_cast<uint64_t>(verifier.key->log_circuit_size.get_value()),
142 verification_key->log_circuit_size);
143 EXPECT_EQ(static_cast<uint64_t>(verifier.key->num_public_inputs.get_value()),
144 verification_key->num_public_inputs);
145 for (auto [vk_poly, native_vk_poly] : zip_view(verifier.key->get_all(), verification_key->get_all())) {
146 EXPECT_EQ(vk_poly.get_value(), native_vk_poly);
147 }
148
149 // Construct a full proof from the recursive verifier circuit
150 {
151 auto prover_instance = std::make_shared<OuterProverInstance>(outer_circuit);
152 auto verification_key = std::make_shared<OuterFlavor::VerificationKey>(prover_instance->get_precomputed());
153 OuterProver prover(prover_instance, verification_key);
154 OuterVerifier verifier(verification_key);
155 auto proof = prover.construct_proof();
156 bool verified = verifier.template verify_proof<DefaultIO>(proof).result;
157
158 ASSERT_TRUE(verified);
159 }
160
161 // Check that the size of the recursive verifier is consistent with historical expectation
162 uint32_t NUM_GATES_EXPECTED = 215193;
163 ASSERT_EQ(static_cast<uint32_t>(outer_circuit.get_num_finalized_gates()), NUM_GATES_EXPECTED)
164 << "Ultra-arithmetized ECCVM Recursive verifier gate count changed! Update this value if you are sure this "
165 "is expected.";
166 }
167
169 {
171 builder.op_queue->add_erroneous_equality_op_for_testing();
172 builder.op_queue->merge();
173 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
174 InnerProver prover(builder, prover_transcript);
175 auto [proof, opening_claim] = prover.construct_proof();
176
177 // Compute IPA proof
178 auto ipa_transcript = std::make_shared<Transcript>();
179 ECCVMFlavor::PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
180 HonkProof ipa_proof = ipa_transcript->export_proof();
181
182 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(prover.key);
183
184 OuterBuilder outer_circuit;
185 auto stdlib_proof = stdlib::Proof<OuterBuilder>(outer_circuit, proof);
186
188 RecursiveVerifier verifier{ stdlib_verifier_transcript, stdlib_proof };
189 [[maybe_unused]] auto output = verifier.verify_proof();
191 info("Recursive Verifier: estimated num finalized gates = ",
193
194 // Check for a failure flag in the recursive verifier circuit
195 EXPECT_FALSE(CircuitChecker::check(outer_circuit));
196 }
197
199 {
200 for (size_t idx = 0; idx < 2; idx++) {
202 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
203 InnerProver prover(builder, prover_transcript);
204 auto [proof, opening_claim] = prover.construct_proof();
205
206 // Compute IPA proof
207 auto ipa_transcript_prover = std::make_shared<Transcript>();
208 ECCVMFlavor::PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript_prover);
209 HonkProof ipa_proof_native = ipa_transcript_prover->export_proof();
210
211 // Tamper with the proof to be verified
212 tamper_with_proof<InnerProver, InnerFlavor>(proof, static_cast<bool>(idx));
213
214 OuterBuilder outer_circuit;
215 auto stdlib_proof = stdlib::Proof<OuterBuilder>(outer_circuit, proof);
217 RecursiveVerifier verifier{ stdlib_verifier_transcript, stdlib_proof };
218 auto recursive_opening_claim = verifier.verify_proof();
220
221 if (idx == 0) {
222 // In this case, we changed the first non-zero value in the proof. It leads to a circuit check failure.
223 EXPECT_FALSE(CircuitChecker::check(outer_circuit));
224 } else {
225 // Changing the last commitment in the `proof_data` would not result in a circuit check failure at
226 // this stage.
227 EXPECT_TRUE(CircuitChecker::check(outer_circuit));
228
229 // However, IPA recursive verifier must fail, as one of the commitments is incorrect.
230 VerifierCommitmentKey<InnerFlavor::Curve> native_pcs_vk(1UL << CONST_ECCVM_LOG_N);
232 &outer_circuit, 1UL << CONST_ECCVM_LOG_N, native_pcs_vk);
233
234 // Construct ipa_transcript from proof
235 auto stdlib_ipa_proof = stdlib::Proof<OuterBuilder>(outer_circuit, ipa_proof_native);
238 stdlib_pcs_vkey, recursive_opening_claim, ipa_transcript));
239 }
240 }
241 }
242
244 {
245
246 // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit
247 auto get_blocks = [](size_t inner_size)
249 auto inner_circuit = generate_circuit(&engine, inner_size);
250 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
251 InnerProver inner_prover(inner_circuit, prover_transcript);
252
253 auto [proof, opening_claim] = inner_prover.construct_proof();
254
255 // Compute IPA proof
256 auto ipa_transcript = std::make_shared<Transcript>();
257 ECCVMFlavor::PCS::compute_opening_proof(inner_prover.key->commitment_key, opening_claim, ipa_transcript);
258 HonkProof ipa_proof = ipa_transcript->export_proof();
259
260 // Create a recursive verification circuit for the proof of the inner circuit
261 OuterBuilder outer_circuit;
262 auto stdlib_proof = stdlib::Proof<OuterBuilder>(outer_circuit, proof);
263
265 RecursiveVerifier verifier{ stdlib_verifier_transcript, stdlib_proof };
266
267 [[maybe_unused]] auto recursive_opening_claim = verifier.verify_proof();
269
270 auto outer_proving_key = std::make_shared<OuterProverInstance>(outer_circuit);
271 auto outer_verification_key =
272 std::make_shared<OuterFlavor::VerificationKey>(outer_proving_key->get_precomputed());
273
274 return { outer_circuit.blocks, outer_verification_key };
275 };
276
277 auto [blocks_20, verification_key_20] = get_blocks(20);
278 auto [blocks_40, verification_key_40] = get_blocks(40);
279
280 compare_ultra_blocks_and_verification_keys<OuterFlavor>({ blocks_20, blocks_40 },
281 { verification_key_20, verification_key_40 });
282 };
283};
284
289
290TEST_F(ECCVMRecursiveTests, SingleRecursiveVerificationFailure)
291{
293};
294
295TEST_F(ECCVMRecursiveTests, SingleRecursiveVerificationFailureTamperedProof)
296{
297 BB_DISABLE_ASSERTS(); // Avoid on_curve assertion failure in cycle_group constructor
299};
300
305} // namespace bb
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:32
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
const std::string & err() const
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
std::pair< Proof, OpeningClaim > construct_proof()
std::shared_ptr< ProvingKey > key
StdlibTranscript< 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
Unified ECCVM verifier class for both native and recursive verification.
bool translation_masking_consistency_checked
std::shared_ptr< Transcript > transcript
std::shared_ptr< VerificationKey > key
OpeningClaim< Curve > verify_proof()
Verifies an ECCVM Honk proof for given program settings.
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:93
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.
size_t get_num_finalized_gates() const override
Get the number of gates in a finalized circuit.
size_t get_num_finalized_gates_inefficient(bool ensure_nonzero=true) const
Get the number of gates in the finalized version of the circuit.
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::element Element
Definition grumpkin.hpp:62
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:19
static void add_default(Builder &builder)
Add default public inputs when they are not present.
void info(Args... args)
Definition log.hpp:75
AluTraceBuilder builder
Definition alu.test.cpp:124
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.
Definition api.hpp:5
std::vector< fr > HonkProof
Definition proof.hpp:15
ECCVMVerifier_< ECCVMRecursiveFlavor > ECCVMRecursiveVerifier
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:185
ECCVMVerifier_< ECCVMFlavor > ECCVMVerifier
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::AffineElement G1
static field random_element(numeric::RNG *engine=nullptr) noexcept