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 prover_instance = std::make_shared<OuterProverInstance>(outer_circuit);
132 auto verification_key = std::make_shared<OuterFlavor::VerificationKey>(prover_instance->get_precomputed());
133 OuterProver prover(prover_instance, 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 // Check that the size of the recursive verifier is consistent with historical expectation
142 uint32_t NUM_GATES_EXPECTED = 216315;
143 ASSERT_EQ(static_cast<uint32_t>(outer_circuit.get_num_finalized_gates()), NUM_GATES_EXPECTED)
144 << "Ultra-arithmetized ECCVM Recursive verifier gate count changed! Update this value if you are sure this "
145 "is expected.";
146 }
147
149 {
151 builder.op_queue->add_erroneous_equality_op_for_testing();
152 builder.op_queue->merge();
153 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
154 InnerProver prover(builder, prover_transcript);
155 ECCVMProof proof = prover.construct_proof();
156 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(prover.key);
157
158 OuterBuilder outer_circuit;
159
161 RecursiveVerifier verifier{ &outer_circuit, verification_key, stdlib_verifier_transcript };
162 [[maybe_unused]] auto output = verifier.verify_proof(proof);
164 info("Recursive Verifier: estimated num finalized gates = ", outer_circuit.get_estimated_num_finalized_gates());
165
166 // Check for a failure flag in the recursive verifier circuit
167 EXPECT_FALSE(CircuitChecker::check(outer_circuit));
168 }
169
171 {
172 for (size_t idx = 0; idx < 2; idx++) {
174 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
175 InnerProver prover(builder, prover_transcript);
176 ECCVMProof proof = prover.construct_proof();
177
178 // Tamper with the proof to be verified
179 tamper_with_proof<InnerProver, InnerFlavor>(proof.pre_ipa_proof, static_cast<bool>(idx));
180
181 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(prover.key);
182
183 OuterBuilder outer_circuit;
185 RecursiveVerifier verifier{ &outer_circuit, verification_key, stdlib_verifier_transcript };
186 auto [opening_claim, ipa_proof] = verifier.verify_proof(proof);
188
189 if (idx == 0) {
190 // In this case, we changed the first non-zero value in the proof. It leads to a circuit check failure.
191 EXPECT_FALSE(CircuitChecker::check(outer_circuit));
192 } else {
193 // Changing the last commitment in the `pre_ipa_proof` would not result in a circuit check failure at
194 // this stage.
195 EXPECT_TRUE(CircuitChecker::check(outer_circuit));
196
197 // However, IPA recursive verifier must fail, as one of the commitments is incorrect.
198 VerifierCommitmentKey<InnerFlavor::Curve> native_pcs_vk(1UL << CONST_ECCVM_LOG_N);
200 &outer_circuit, 1UL << CONST_ECCVM_LOG_N, native_pcs_vk);
201
202 // Construct ipa_transcript from proof
204 ipa_transcript->load_proof(ipa_proof);
205 EXPECT_FALSE(
206 IPA<RecursiveFlavor::Curve>::full_verify_recursive(stdlib_pcs_vkey, opening_claim, ipa_transcript));
207 }
208 }
209 }
210
212 {
213
214 // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit
215 auto get_blocks = [](size_t inner_size)
217 auto inner_circuit = generate_circuit(&engine, inner_size);
218 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
219 InnerProver inner_prover(inner_circuit, prover_transcript);
220
221 ECCVMProof inner_proof = inner_prover.construct_proof();
222 auto verification_key = std::make_shared<InnerFlavor::VerificationKey>(inner_prover.key);
223
224 // Create a recursive verification circuit for the proof of the inner circuit
225 OuterBuilder outer_circuit;
226
228 RecursiveVerifier verifier{ &outer_circuit, verification_key, stdlib_verifier_transcript };
229
230 auto [opening_claim, ipa_transcript] = verifier.verify_proof(inner_proof);
232
233 auto outer_proving_key = std::make_shared<OuterProverInstance>(outer_circuit);
234 auto outer_verification_key =
235 std::make_shared<OuterFlavor::VerificationKey>(outer_proving_key->get_precomputed());
236
237 return { outer_circuit.blocks, outer_verification_key };
238 };
239
240 auto [blocks_20, verification_key_20] = get_blocks(20);
241 auto [blocks_40, verification_key_40] = get_blocks(40);
242
243 compare_ultra_blocks_and_verification_keys<OuterFlavor>({ blocks_20, blocks_40 },
244 { verification_key_20, verification_key_40 });
245 };
246};
247
252
253TEST_F(ECCVMRecursiveTests, SingleRecursiveVerificationFailure)
254{
256};
257
258TEST_F(ECCVMRecursiveTests, SingleRecursiveVerificationFailureTamperedProof)
259{
260 BB_DISABLE_ASSERTS(); // Avoid on_curve assertion failure in cycle_group constructor
262};
263
268} // 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
ECCVMProof 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
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: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_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:74
AluTraceBuilder builder
Definition alu.test.cpp:123
FF a
FF b
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:188
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.