Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
goblin_verifier.test.cpp
Go to the documentation of this file.
11
13class GoblinRecursiveVerifierTests : public testing::Test {
14 public:
18
23
25 using RecursiveCommitment = bb::GoblinRecursiveVerifier::MergeVerifier::Commitment;
27 using RecursiveMergeCommitments = bb::GoblinRecursiveVerifier::MergeVerifier::InputCommitments;
31
37 static void tamper_with_op_commitment(MergeCommitments& merge_commitments)
38 {
39 // The first commitment in merged table is the `op` wire commitment
40 merge_commitments.t_commitments[0] = merge_commitments.t_commitments[0] * FF(2);
41 };
42
43 // ECCVM pre-IPA proof ends with evaluations including `op`. We tamper with the `op` evaluation.
44 // The structure is: [..., op_eval, x_lo_y_hi_eval, x_hi_z_1_eval, y_lo_z_2_eval, IPA_proof...]
45 // So op_eval is 3 fields before the IPA proof starts.
46 static void tamper_with_eccvm_op_eval(HonkProof& eccvm_proof)
47 {
48 // The `op` evaluation is located 3 evaluations before the end of pre-IPA proof
49 // (followed by x_lo_y_hi, x_hi_z_1, y_lo_z_2 evaluations)
50 static constexpr size_t evals_after_op = 3; // x_lo_y_hi, x_hi_z_1, y_lo_z_2
51 const size_t op_eval_idx = eccvm_proof.size() - evals_after_op;
52
53 // Tamper with the op evaluation
54 eccvm_proof[op_eval_idx] += FF(1);
55 };
56
62 static ProverOutput create_goblin_prover_output(Builder* outer_builder = nullptr, const size_t num_circuits = 5)
63 {
64
65 Goblin goblin;
67 goblin.op_queue->construct_zk_columns();
68
69 // Merge the ecc ops from the newly constructed circuit
70 auto goblin_proof = goblin.prove();
71 // Subtable values and commitments - needed for (Recursive)MergeVerifier
72 MergeCommitments merge_commitments;
73 auto t_current = goblin.op_queue->construct_current_ultra_ops_subtable_columns();
74 auto T_prev = goblin.op_queue->construct_table_columns_up_to_tail();
75 CommitmentKey<curve::BN254> pcs_commitment_key(goblin.op_queue->get_ultra_ops_table_num_rows() +
77 for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
78 merge_commitments.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]);
79 merge_commitments.T_prev_commitments[idx] = pcs_commitment_key.commit(T_prev[idx]);
80 }
81
82 RecursiveMergeCommitments recursive_merge_commitments;
83 if (outer_builder != nullptr) {
84 for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
85 recursive_merge_commitments.t_commitments[idx] =
86 RecursiveCommitment::from_witness(outer_builder, merge_commitments.t_commitments[idx]);
87 recursive_merge_commitments.T_prev_commitments[idx] =
88 RecursiveCommitment::from_witness(outer_builder, merge_commitments.T_prev_commitments[idx]);
89 // Removing the free witness tag, since the merge commitments in the full scheme are supposed to
90 // be fiat-shamirred earlier
91 recursive_merge_commitments.t_commitments[idx].unset_free_witness_tag();
92 recursive_merge_commitments.T_prev_commitments[idx].unset_free_witness_tag();
93 }
94 }
95
96 // Output is a goblin proof plus merge commitments
97 return { goblin_proof, merge_commitments, recursive_merge_commitments };
98 }
99};
100
106{
107 auto [proof, merge_commitments, _] = create_goblin_prover_output();
108
109 auto transcript = std::make_shared<NativeTranscript>();
110 bb::GoblinVerifier verifier(transcript, proof, merge_commitments);
112
113 result.translator_pairing_points.aggregate(result.merge_pairing_points);
115 auto accumulator = result.triple_ipa_opening.reduce_to_accumulator();
116 bool ipa_verified = bb::ECCVMVerifier::TripleIPA::verify_accumulator(ipa_vk, accumulator);
117
118 EXPECT_TRUE(result.all_checks_passed);
119 EXPECT_TRUE(result.translator_pairing_points.check());
120 EXPECT_TRUE(ipa_verified);
121}
122
123TEST_F(GoblinRecursiveVerifierTests, NativeVerificationRejectsTamperedTripleIPAProof)
124{
125 auto [proof, merge_commitments, _] = create_goblin_prover_output();
126 ASSERT_FALSE(proof.ipa_proof.empty());
127 proof.ipa_proof[0] += bb::fr(1);
128
129 auto transcript = std::make_shared<NativeTranscript>();
130 bb::GoblinVerifier verifier(transcript, proof, merge_commitments);
132
133 result.translator_pairing_points.aggregate(result.merge_pairing_points);
135 auto accumulator = result.triple_ipa_opening.reduce_to_accumulator();
136 bool ipa_verified = bb::ECCVMVerifier::TripleIPA::verify_accumulator(ipa_vk, accumulator);
137
138 EXPECT_TRUE(result.all_checks_passed);
139 EXPECT_TRUE(result.translator_pairing_points.check());
140 EXPECT_FALSE(ipa_verified);
141}
142
148{
150
151 auto [proof, merge_commitments, recursive_merge_commitments] = create_goblin_prover_output(&builder);
152
153 auto transcript = std::make_shared<Transcript>();
154 GoblinStdlibProof stdlib_proof(builder, proof);
155 bb::GoblinRecursiveVerifier verifier{ transcript, stdlib_proof, recursive_merge_commitments };
156 auto output = verifier.reduce_to_pairing_check_and_triple_ipa_opening();
157
158 // Aggregate merge + translator pairing points
159 output.translator_pairing_points.aggregate(output.merge_pairing_points);
160
161 // This test exercises the Goblin recursive verifier circuit, not TripleIPA propagation. Use a random valid ordinary
162 // IPA (claim, proof) pair to satisfy the UltraRollupHonk IO shape.
163 auto [ipa_claim, ipa_proof] =
164 IPA<stdlib::grumpkin<UltraCircuitBuilder>>::create_random_valid_ipa_claim_and_proof(builder);
165
167 inputs.pairing_inputs = output.translator_pairing_points;
168 inputs.ipa_claim = ipa_claim;
169 inputs.set_public();
170
171 builder.ipa_proof = ipa_proof;
172
173 info("Recursive Verifier: num gates = ", builder.num_gates());
174
175 EXPECT_EQ(builder.failed(), false) << builder.err();
176
177 EXPECT_TRUE(CircuitChecker::check(builder));
178
179 // Construct and verify a proof for the Goblin Recursive Verifier circuit
180 {
181 auto prover_instance = std::make_shared<OuterProverInstance>(builder);
182 auto verification_key =
183 std::make_shared<typename OuterFlavor::VerificationKey>(prover_instance->get_precomputed());
184 auto vk_and_hash = std::make_shared<typename OuterFlavor::VKAndHash>(verification_key);
185 OuterProver prover(prover_instance, verification_key);
186 OuterVerifier verifier(vk_and_hash);
187 auto proof = prover.construct_proof();
188 bool verified = verifier.verify_proof(proof).result;
189
190 ASSERT_TRUE(verified);
191 }
192}
193
194// Check that the GoblinRecursiveVerifier circuit does not depend on the inputs.
196{
197 // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit
198 auto get_blocks = [](size_t inner_size)
199 -> std::tuple<typename Builder::ExecutionTrace, std::shared_ptr<OuterFlavor::VerificationKey>> {
201
202 auto [proof, merge_commitments, recursive_merge_commitments] =
203 create_goblin_prover_output(&builder, inner_size);
204
205 auto transcript = std::make_shared<Transcript>();
206 GoblinStdlibProof stdlib_proof(builder, proof);
207 bb::GoblinRecursiveVerifier verifier{ transcript, stdlib_proof, recursive_merge_commitments };
208 auto output = verifier.reduce_to_pairing_check_and_triple_ipa_opening();
209
210 // Aggregate merge + translator pairing points
211 output.translator_pairing_points.aggregate(output.merge_pairing_points);
212
213 // VK-shape comparison only; not testing TripleIPA propagation. Use a random valid ordinary IPA (claim, proof)
214 // pair to satisfy the UltraRollupHonk IO shape.
215 auto [ipa_claim, ipa_proof] =
216 IPA<stdlib::grumpkin<UltraCircuitBuilder>>::create_random_valid_ipa_claim_and_proof(builder);
217
219 inputs.pairing_inputs = output.translator_pairing_points;
220 inputs.ipa_claim = ipa_claim;
221 inputs.set_public();
222
223 builder.ipa_proof = ipa_proof;
224
225 info("Recursive Verifier: num gates = ", builder.num_gates());
226
227 // Construct and verify a proof for the Goblin Recursive Verifier circuit
228 auto prover_instance = std::make_shared<OuterProverInstance>(builder);
229 auto outer_verification_key =
230 std::make_shared<typename OuterFlavor::VerificationKey>(prover_instance->get_precomputed());
231 auto vk_and_hash = std::make_shared<typename OuterFlavor::VKAndHash>(outer_verification_key);
232 OuterProver prover(prover_instance, outer_verification_key);
233 OuterVerifier outer_verifier(vk_and_hash);
234 return { builder.blocks, outer_verification_key };
235 };
236
237 auto [blocks_5, verification_key_5] = get_blocks(5);
238 auto [blocks_6, verification_key_6] = get_blocks(6);
239
240 compare_ultra_blocks_and_verification_keys<OuterFlavor>({ blocks_5, blocks_6 },
241 { verification_key_5, verification_key_6 });
242}
243
249TEST_F(GoblinRecursiveVerifierTests, MergeToTranslatorBindingFailure)
250{
251 auto [proof, merge_commitments, _] = create_goblin_prover_output();
252
253 // Tamper with the op commitment in merge commitments (used by Translator verifier)
254 MergeCommitments tampered_merge_commitments = merge_commitments;
255 tamper_with_op_commitment(tampered_merge_commitments);
257
258 RecursiveMergeCommitments recursive_merge_commitments;
259 for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
260 recursive_merge_commitments.t_commitments[idx] =
261 RecursiveCommitment::from_witness(&builder, tampered_merge_commitments.t_commitments[idx]);
262 recursive_merge_commitments.T_prev_commitments[idx] =
263 RecursiveCommitment::from_witness(&builder, tampered_merge_commitments.T_prev_commitments[idx]);
264 recursive_merge_commitments.t_commitments[idx].fix_witness();
265 recursive_merge_commitments.T_prev_commitments[idx].fix_witness();
266 }
267
268 auto transcript = std::make_shared<Transcript>();
269 GoblinStdlibProof stdlib_proof(builder, proof);
270 bb::GoblinRecursiveVerifier verifier{ transcript, stdlib_proof, recursive_merge_commitments };
271 auto goblin_rec_verifier_output = verifier.reduce_to_pairing_check_and_triple_ipa_opening();
272
273 // Aggregate merge + translator pairing points
274 goblin_rec_verifier_output.translator_pairing_points.aggregate(goblin_rec_verifier_output.merge_pairing_points);
275
276 // Circuit is correct but pairing check should fail
277 EXPECT_TRUE(CircuitChecker::check(builder));
278
279 // Check that the pairing fails natively
280 bb::PairingPoints<curve::BN254> native_pairing_points(
281 goblin_rec_verifier_output.translator_pairing_points.P0().get_value(),
282 goblin_rec_verifier_output.translator_pairing_points.P1().get_value());
283 bool pairing_result = native_pairing_points.check();
284 EXPECT_FALSE(pairing_result);
285}
286
293TEST_F(GoblinRecursiveVerifierTests, ECCVMToTranslatorBindingFailure)
294{
296
297 auto [proof, merge_commitments, recursive_merge_commitments] = create_goblin_prover_output(&builder);
298
299 // Tamper with the `op` evaluation in the ECCVM proof
300 tamper_with_eccvm_op_eval(proof.eccvm_proof);
301
302 auto transcript = std::make_shared<Transcript>();
303 GoblinStdlibProof stdlib_proof(builder, proof);
304 bb::GoblinRecursiveVerifier verifier{ transcript, stdlib_proof, recursive_merge_commitments };
305 [[maybe_unused]] auto goblin_rec_verifier_output = verifier.reduce_to_pairing_check_and_triple_ipa_opening();
306
307 EXPECT_FALSE(CircuitChecker::check(builder));
308}
309} // namespace bb::stdlib::recursion::honk
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
CommitmentKey object over a pairing group ๐”พโ‚.
Commitment commit(PolynomialSpan< const Fr > polynomial, bool has_duplicates_hint=false) const
Uses the ProverSRS to create a commitment to p(X)
static constexpr size_t ECCVM_FIXED_SIZE
static bool verify_accumulator(const TripleIpaAccumulator &accumulator)
Simple verification key class for fixed-size circuits (ECCVM, Translator, AVM).
Definition flavor.hpp:104
TranslatorFlavor::VerificationKey TranslatorVerificationKey
Definition goblin.hpp:45
GoblinProof prove()
Constuct a full Goblin proof (ECCVM, Translator, merge)
Definition goblin.cpp:60
std::shared_ptr< OpQueue > op_queue
Definition goblin.hpp:59
ECCVMFlavor::VerificationKey ECCVMVerificationKey
Definition goblin.hpp:44
static void construct_and_merge_mock_circuits(Goblin &goblin, const size_t num_circuits=3)
Unified Goblin verifier for both native and recursive verification.
ReductionResult reduce_to_pairing_check_and_triple_ipa_opening()
Reduce Goblin proof to pairing checks and a TripleIPA claim.
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:87
static constexpr size_t NUM_WIRES
typename Curve::AffineElement Commitment
An object storing two EC points that represent the inputs to a pairing check.
bool check() const
Verify the pairing equation e(P0, [1]โ‚‚) ยท e(P1, [x]โ‚‚) = 1.
Contains all the information required by a Honk prover to create a proof, constructed from a finalize...
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
Curve::ScalarField FF
static constexpr size_t ZK_ULTRA_OPS
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
static ProverOutput create_goblin_prover_output(Builder *outer_builder=nullptr, const size_t num_circuits=5)
Create a goblin proof and the VM verification keys needed by the goblin recursive verifier.
bb::GoblinRecursiveVerifier::MergeVerifier::InputCommitments RecursiveMergeCommitments
bb::GoblinRecursiveVerifier::MergeVerifier::Commitment RecursiveCommitment
static void tamper_with_op_commitment(MergeCommitments &merge_commitments)
The data that is propagated on the public inputs of a rollup circuit.
#define info(...)
Definition log.hpp:93
AluTraceBuilder builder
Definition alu.test.cpp:124
AvmProvingInputs inputs
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic)
Construct and check a goblin recursive verification circuit.
std::vector< fr > HonkProof
Definition proof.hpp:15
UltraVerifier_< UltraFlavor, RollupIO > UltraRollupVerifier
field< Bn254FrParams > fr
Definition fr.hpp:155
BaseTranscript< stdlib::StdlibCodec< stdlib::field_t< UltraCircuitBuilder > >, stdlib::poseidon2< UltraCircuitBuilder > > UltraStdlibTranscript
UltraCircuitBuilder_< UltraExecutionTraceBlocks > UltraCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
VectorField result