Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
goblin_recursive_verifier.test.cpp
Go to the documentation of this file.
11
13class GoblinRecursiveVerifierTests : public testing::Test {
14 public:
18
23
31
32 // Compute the size of a Translator commitment (in bb::fr's)
33 static constexpr size_t comm_frs = FrCodec::calc_num_fields<Commitment>(); // 4
34 static constexpr size_t eval_frs = FrCodec::calc_num_fields<FF>(); // 1
35
36 // The `op` wire commitment is currently the second element of the proof, following the
37 // `accumulated_result` which is a BN254 BaseField element.
38 static constexpr size_t offset = FrCodec::calc_num_fields<BF>();
39
46 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1298):
47 // Better recursion testing - create more flexible proof tampering tests.
48 // Modify the `op` commitment which a part of the Merge protocol.
49 static void tamper_with_op_commitment(HonkProof& translator_proof)
50 {
51
52 // Extract `op` fields and convert them to a Commitment object
53 auto element_frs = std::span{ translator_proof }.subspan(offset, comm_frs);
54 auto op_commitment = NativeTranscript::template deserialize<Commitment>(element_frs);
55 // Modify the commitment
56 op_commitment = op_commitment * FF(2);
57 // Serialize the tampered commitment into the proof (overwriting the valid one).
58 auto op_commitment_reserialized = NativeTranscript::serialize(op_commitment);
59 std::copy(op_commitment_reserialized.begin(),
60 op_commitment_reserialized.end(),
61 translator_proof.begin() + static_cast<std::ptrdiff_t>(offset));
62 };
63
64 // Translator proof ends with [..., Libra:quotient_eval, Shplonk:Q, KZG:W]. We invalidate the proof by multiplying
65 // the eval by 2 (it leads to a Libra consistency check failure).
66 static void tamper_with_libra_eval(HonkProof& translator_proof)
67 {
68 // Proof tail size
69 static constexpr size_t tail_size = 2 * comm_frs + eval_frs; // 2*4 + 1 = 9
70
71 // Index of the target field (one fr) from the beginning
72 const size_t idx = translator_proof.size() - tail_size;
73
74 // Tamper: multiply by 2 (or tweak however you like)
75 translator_proof[idx] = translator_proof[idx] + translator_proof[idx];
76 };
82 static ProverOutput create_goblin_prover_output(Builder* outer_builder = nullptr, const size_t num_circuits = 5)
83 {
84
85 Goblin goblin;
87
88 // Merge the ecc ops from the newly constructed circuit
89 auto goblin_proof = goblin.prove(MergeSettings::APPEND);
90 // Subtable values and commitments - needed for (Recursive)MergeVerifier
91 MergeCommitments merge_commitments;
92 auto t_current = goblin.op_queue->construct_current_ultra_ops_subtable_columns();
93 auto T_prev = goblin.op_queue->construct_previous_ultra_ops_table_columns();
94 CommitmentKey<curve::BN254> pcs_commitment_key(goblin.op_queue->get_ultra_ops_table_num_rows());
95 for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
96 merge_commitments.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]);
97 merge_commitments.T_prev_commitments[idx] = pcs_commitment_key.commit(T_prev[idx]);
98 }
99
100 RecursiveMergeCommitments recursive_merge_commitments;
101 if (outer_builder != nullptr) {
102 for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
103 recursive_merge_commitments.t_commitments[idx] =
104 RecursiveCommitment::from_witness(outer_builder, merge_commitments.t_commitments[idx]);
105 recursive_merge_commitments.T_prev_commitments[idx] =
106 RecursiveCommitment::from_witness(outer_builder, merge_commitments.T_prev_commitments[idx]);
107 // Removing the free witness tag, since the merge commitments in the full scheme are supposed to
108 // be fiat-shamirred earlier
109 recursive_merge_commitments.t_commitments[idx].unset_free_witness_tag();
110 recursive_merge_commitments.T_prev_commitments[idx].unset_free_witness_tag();
111 }
112 }
113
114 // Output is a goblin proof plus ECCVM/Translator verification keys
115 return { goblin_proof,
117 merge_commitments,
118 recursive_merge_commitments };
119 }
120};
121
127{
128 auto [proof, verifier_input, merge_commitments, _] = create_goblin_prover_output();
129
131
132 EXPECT_TRUE(Goblin::verify(proof, merge_commitments, verifier_transcript, MergeSettings::APPEND));
133}
134
140{
142
143 auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] =
144 create_goblin_prover_output(&builder);
145
146 GoblinRecursiveVerifier verifier{ &builder, verifier_input };
147 GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_commitments, MergeSettings::APPEND);
149
150 info("Recursive Verifier: num gates = ", builder.num_gates);
151
152 EXPECT_EQ(builder.failed(), false) << builder.err();
153
154 EXPECT_TRUE(CircuitChecker::check(builder));
155
156 // Construct and verify a proof for the Goblin Recursive Verifier circuit
157 {
158 auto prover_instance = std::make_shared<OuterProverInstance>(builder);
159 auto verification_key =
160 std::make_shared<typename OuterFlavor::VerificationKey>(prover_instance->get_precomputed());
161 OuterProver prover(prover_instance, verification_key);
162 OuterVerifier verifier(verification_key);
163 auto proof = prover.construct_proof();
164 bool verified = verifier.template verify_proof<bb::DefaultIO>(proof).result;
165
166 ASSERT_TRUE(verified);
167 }
168}
169
170// Check that the GoblinRecursiveVerifier circuit does not depend on the inputs.
172{
173 // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit
174 auto get_blocks = [](size_t inner_size)
177
178 auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] =
179 create_goblin_prover_output(&builder, inner_size);
180
181 GoblinRecursiveVerifier verifier{ &builder, verifier_input };
183 verifier.verify(proof, recursive_merge_commitments, MergeSettings::APPEND);
185
186 info("Recursive Verifier: num gates = ", builder.num_gates);
187
188 // Construct and verify a proof for the Goblin Recursive Verifier circuit
189 auto prover_instance = std::make_shared<OuterProverInstance>(builder);
190 auto outer_verification_key =
191 std::make_shared<typename OuterFlavor::VerificationKey>(prover_instance->get_precomputed());
192 OuterProver prover(prover_instance, outer_verification_key);
193 OuterVerifier outer_verifier(outer_verification_key);
194 return { builder.blocks, outer_verification_key };
195 };
196
197 auto [blocks_5, verification_key_5] = get_blocks(5);
198 auto [blocks_6, verification_key_6] = get_blocks(6);
199
200 compare_ultra_blocks_and_verification_keys<OuterFlavor>({ blocks_5, blocks_6 },
201 { verification_key_5, verification_key_6 });
202}
203
209{
210 BB_DISABLE_ASSERTS(); // Avoid on_curve assertion failure in cycle_group etc
212
213 auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] =
214 create_goblin_prover_output(&builder);
215
216 // Tamper with the ECCVM proof
217 for (auto& val : proof.eccvm_proof.pre_ipa_proof) {
218 if (val > 0) { // tamper by finding the first non-zero value and incrementing it by 1
219 val += 1;
220 break;
221 }
222 }
223
224 GoblinRecursiveVerifier verifier{ &builder, verifier_input };
225 GoblinRecursiveVerifierOutput goblin_rec_verifier_output = verifier.verify(proof, recursive_merge_commitments);
226 EXPECT_FALSE(CircuitChecker::check(builder));
227
229 auto crs_factory = srs::get_grumpkin_crs_factory();
230 VerifierCommitmentKey<curve::Grumpkin> grumpkin_verifier_commitment_key(1 << CONST_ECCVM_LOG_N, crs_factory);
231 OpeningClaim<curve::Grumpkin> native_claim = goblin_rec_verifier_output.opening_claim.get_native_opening_claim();
232 auto native_ipa_transcript = std::make_shared<NativeTranscript>();
233 auto native_ipa_proof = goblin_rec_verifier_output.ipa_proof.get_value();
234 native_ipa_transcript->load_proof(native_ipa_proof);
235
236 bool native_result =
237 IPA<curve::Grumpkin>::reduce_verify(grumpkin_verifier_commitment_key, native_claim, native_ipa_transcript);
238 EXPECT_FALSE(native_result);
239}
240
246{
247 auto [proof, verifier_input, merge_commitments, _] = create_goblin_prover_output();
248
249 // Tamper with the Translator proof preamble
250 {
251 GoblinProof tampered_proof = proof;
252 tamper_with_op_commitment(tampered_proof.translator_proof);
254
255 RecursiveMergeCommitments recursive_merge_commitments;
256 for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
257 recursive_merge_commitments.t_commitments[idx] =
258 RecursiveCommitment::from_witness(&builder, merge_commitments.t_commitments[idx]);
259 recursive_merge_commitments.T_prev_commitments[idx] =
260 RecursiveCommitment::from_witness(&builder, merge_commitments.T_prev_commitments[idx]);
261 recursive_merge_commitments.t_commitments[idx].fix_witness();
262 recursive_merge_commitments.T_prev_commitments[idx].fix_witness();
263 }
264
265 GoblinRecursiveVerifier verifier{ &builder, verifier_input };
266 [[maybe_unused]] auto goblin_rec_verifier_output =
267 verifier.verify(tampered_proof, recursive_merge_commitments, MergeSettings::APPEND);
268 EXPECT_FALSE(CircuitChecker::check(builder));
269 }
270 // Tamper with the Translator proof non - preamble values
271 {
272 auto tampered_proof = proof;
273 tamper_with_libra_eval(tampered_proof.translator_proof);
274
276
277 RecursiveMergeCommitments recursive_merge_commitments;
278 for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
279 recursive_merge_commitments.t_commitments[idx] =
280 RecursiveCommitment::from_witness(&builder, merge_commitments.t_commitments[idx]);
281 recursive_merge_commitments.T_prev_commitments[idx] =
282 RecursiveCommitment::from_witness(&builder, merge_commitments.T_prev_commitments[idx]);
283 recursive_merge_commitments.t_commitments[idx].fix_witness();
284 recursive_merge_commitments.T_prev_commitments[idx].fix_witness();
285 }
286
287 GoblinRecursiveVerifier verifier{ &builder, verifier_input };
288 [[maybe_unused]] auto goblin_rec_verifier_output =
289 verifier.verify(tampered_proof, recursive_merge_commitments, MergeSettings::APPEND);
290 EXPECT_FALSE(CircuitChecker::check(builder));
291 }
292}
293
298TEST_F(GoblinRecursiveVerifierTests, TranslationEvaluationsFailure)
299{
301
302 auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] =
303 create_goblin_prover_output(&builder);
304
305 // Tamper with the evaluation of `op` witness. The index is computed manually.
306 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1298):
307 // Better recursion testing - create more flexible proof tampering tests.
308 const size_t op_limb_index = 593;
309 proof.eccvm_proof.pre_ipa_proof[op_limb_index] += 1;
310
311 GoblinRecursiveVerifier verifier{ &builder, verifier_input };
312 [[maybe_unused]] auto goblin_rec_verifier_output =
313 verifier.verify(proof, recursive_merge_commitments, MergeSettings::APPEND);
314
315 EXPECT_FALSE(CircuitChecker::check(builder));
316}
317
322TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure)
323{
324
325 {
326
328
329 auto [proof, verifier_input, merge_commitments, recursive_merge_commitments] =
330 create_goblin_prover_output(&builder);
331
333
334 // Check natively that the proof is correct.
335 EXPECT_TRUE(Goblin::verify(proof, merge_commitments, verifier_transcript, MergeSettings::APPEND));
336
337 tamper_with_op_commitment(proof.translator_proof);
338 // Construct and check the Goblin Recursive Verifier circuit
339
340 GoblinRecursiveVerifier verifier{ &builder, verifier_input };
341 [[maybe_unused]] auto goblin_rec_verifier_output =
342 verifier.verify(proof, recursive_merge_commitments, MergeSettings::APPEND);
343
344 EXPECT_FALSE(CircuitChecker::check(builder));
345 }
346
347 // TODO(https://github.com/AztecProtocol/barretenberg/issues/787)
348}
349} // namespace bb::stdlib::recursion::honk
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:32
static std::vector< DataType > serialize(const T &element)
Serialize a size_t to a vector of field elements.
CommitmentKey object over a pairing group 𝔾₁.
Commitment commit(PolynomialSpan< const Fr > polynomial) const
Uses the ProverSRS to create a commitment to p(X)
The verification key is responsible for storing the commitments to the precomputed (non-witnessk) pol...
static bool verify(const GoblinProof &proof, const MergeCommitments &merge_commitments, const std::shared_ptr< Transcript > &transcript, const MergeSettings merge_settings=MergeSettings::PREPEND)
Verify a full Goblin proof (ECCVM, Translator, merge)
Definition goblin.cpp:93
TranslatorFlavor::VerificationKey TranslatorVerificationKey
Definition goblin.hpp:38
std::shared_ptr< OpQueue > op_queue
Definition goblin.hpp:48
GoblinProof prove(const MergeSettings merge_settings=MergeSettings::PREPEND)
Constuct a full Goblin proof (ECCVM, Translator, merge)
Definition goblin.cpp:52
ECCVMFlavor::VerificationKey ECCVMVerificationKey
Definition goblin.hpp:37
static void construct_and_merge_mock_circuits(Goblin &goblin, const size_t num_circuits=3)
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:93
static constexpr size_t NUM_WIRES
typename Curve::AffineElement Commitment
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition claim.hpp:53
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.
The verification key is responsible for storing the commitments to the precomputed (non-witnessk) pol...
Curve::ScalarField FF
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
GoblinRecursiveVerifierOutput verify(const GoblinProof &, const MergeCommitments &merge_commitments, const MergeSettings merge_settings=MergeSettings::PREPEND)
Creates a circuit that executes the ECCVM, Translator and Merge verifiers.
GoblinRecursiveVerifier::MergeVerifier::Commitment RecursiveCommitment
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.
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)
std::shared_ptr< factories::CrsFactory< curve::Grumpkin > > get_grumpkin_crs_factory()
TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic)
Construct and check a goblin recursive verification circuit.
std::vector< fr > HonkProof
Definition proof.hpp:15
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
HonkProof translator_proof
Definition types.hpp:23
uint32_t set_public()
Set the witness indices for the limbs of the pairing points to public.