Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
eccvm_circuit_builder.test.cpp
Go to the documentation of this file.
6#include <gtest/gtest.h>
7
8using namespace bb;
9using G1 = bb::g1;
10using Fr = typename G1::Fr;
12
13namespace {
15} // namespace
16
17TEST(ECCVMCircuitBuilderTests, BaseCase)
18{
19 auto generators = G1::derive_generators("test generators", 3);
20 typename G1::element a = generators[0];
21 typename G1::element b = generators[1];
22 typename G1::element c = generators[2];
23 typename G1::element point_at_infinity = G1::point_at_infinity;
26 Fr zero_scalar = 0;
27
29
30 op_queue->add_accumulate(a);
31 op_queue->mul_accumulate(a, x);
32 op_queue->mul_accumulate(b, x);
33 op_queue->mul_accumulate(b, y);
34 op_queue->add_accumulate(a);
35 op_queue->mul_accumulate(b, x);
36 op_queue->add_accumulate(b);
37 op_queue->eq_and_reset();
38 op_queue->add_accumulate(c);
39 op_queue->mul_accumulate(a, x);
40 op_queue->mul_accumulate(point_at_infinity, x);
41 op_queue->mul_accumulate(b, x);
42 op_queue->eq_and_reset();
43 op_queue->mul_accumulate(a, x);
44 op_queue->mul_accumulate(b, x);
45 op_queue->mul_accumulate(point_at_infinity, zero_scalar);
46 op_queue->mul_accumulate(c, x);
47 op_queue->eq_and_reset();
48 op_queue->mul_accumulate(point_at_infinity, zero_scalar);
49 op_queue->mul_accumulate(point_at_infinity, x);
50 op_queue->mul_accumulate(point_at_infinity, zero_scalar);
51 op_queue->add_accumulate(a);
52 op_queue->eq_and_reset();
53 op_queue->add_accumulate(a);
54 op_queue->add_accumulate(point_at_infinity);
55 op_queue->eq_and_reset();
56 op_queue->add_accumulate(point_at_infinity);
57 op_queue->eq_and_reset();
58 op_queue->mul_accumulate(point_at_infinity, x);
59 op_queue->mul_accumulate(point_at_infinity, -x);
60 op_queue->eq_and_reset();
61 op_queue->add_accumulate(a);
62 op_queue->mul_accumulate(point_at_infinity, x);
63 op_queue->mul_accumulate(point_at_infinity, -x);
64 op_queue->add_accumulate(a);
65 op_queue->add_accumulate(a);
66 op_queue->eq_and_reset();
67 op_queue->merge();
68 add_hiding_op_for_test(op_queue);
69 ECCVMCircuitBuilder circuit{ op_queue };
70 bool result = ECCVMTraceChecker::check(circuit);
71 EXPECT_EQ(result, true);
72}
73
74TEST(ECCVMCircuitBuilderTests, NoOp)
75{
77 add_hiding_op_for_test(op_queue);
78
79 ECCVMCircuitBuilder circuit{ op_queue };
80 bool result = ECCVMTraceChecker::check(circuit, &engine);
81 EXPECT_EQ(result, true);
82}
83
84TEST(ECCVMCircuitBuilderTests, Add)
85{
87
88 auto generators = G1::derive_generators("test generators", 3);
89 typename G1::element a = generators[0];
90
91 op_queue->add_accumulate(a);
92 op_queue->merge();
93 add_hiding_op_for_test(op_queue);
94
95 ECCVMCircuitBuilder circuit{ op_queue };
96 bool result = ECCVMTraceChecker::check(circuit, &engine);
97 EXPECT_EQ(result, true);
98}
99
100TEST(ECCVMCircuitBuilderTests, Mul)
101{
103
104 auto generators = G1::derive_generators("test generators", 3);
105 typename G1::element a = generators[0];
107
108 op_queue->mul_accumulate(a, x);
109 op_queue->merge();
110 add_hiding_op_for_test(op_queue);
111
112 ECCVMCircuitBuilder circuit{ op_queue };
113 bool result = ECCVMTraceChecker::check(circuit, &engine);
114 EXPECT_EQ(result, true);
115}
116
117TEST(ECCVMCircuitBuilderTests, MulInfinity)
118{
120
121 auto generators = G1::derive_generators("test generators", 3);
122 typename G1::element a = generators[0];
124 G1::element b = -a * x;
125
126 op_queue->add_accumulate(b);
127 op_queue->mul_accumulate(a, x);
128 op_queue->eq_and_reset();
129 op_queue->merge();
130 add_hiding_op_for_test(op_queue);
131
132 ECCVMCircuitBuilder circuit{ op_queue };
133 bool result = ECCVMTraceChecker::check(circuit);
134 EXPECT_EQ(result, true);
135}
136
137// Validate we do not trigger edge cases of addition formulae when we have identical mul inputs
138TEST(ECCVMCircuitBuilderTests, MulOverIdenticalInputs)
139{
141
142 auto generators = G1::derive_generators("test generators", 3);
143 typename G1::element a = generators[0];
145 op_queue->mul_accumulate(a, x);
146 op_queue->mul_accumulate(a, x);
147 op_queue->eq_and_reset();
148 op_queue->merge();
149 add_hiding_op_for_test(op_queue);
150
151 ECCVMCircuitBuilder circuit{ op_queue };
152 bool result = ECCVMTraceChecker::check(circuit);
153 EXPECT_EQ(result, true);
154}
155
156TEST(ECCVMCircuitBuilderTests, MSMProducesInfinity)
157{
159
160 auto generators = G1::derive_generators("test generators", 3);
161 typename G1::element a = generators[0];
163 op_queue->add_accumulate(a);
164 op_queue->mul_accumulate(a, x);
165 op_queue->mul_accumulate(a, -x);
166 op_queue->eq_and_reset();
167 op_queue->merge();
168 add_hiding_op_for_test(op_queue);
169
170 ECCVMCircuitBuilder circuit{ op_queue };
171 bool result = ECCVMTraceChecker::check(circuit);
172 EXPECT_EQ(result, true);
173}
174
175TEST(ECCVMCircuitBuilderTests, MSMOverPointAtInfinity)
176{
178
179 auto generators = G1::derive_generators("test generators", 3);
180 typename G1::element point_at_infinity = G1::point_at_infinity;
181 typename G1::element b = generators[0];
183 Fr zero_scalar = 0;
184
185 // validate including points at infinity in a multiscalar multiplication does not effect result
186 {
187 op_queue->mul_accumulate(b, x);
188 op_queue->mul_accumulate(point_at_infinity, x);
189 op_queue->eq_and_reset();
190 op_queue->merge();
191 add_hiding_op_for_test(op_queue);
192
193 ECCVMCircuitBuilder circuit{ op_queue };
194 bool result = ECCVMTraceChecker::check(circuit);
195 EXPECT_EQ(result, true);
196 }
197 // validate multiplying a point at infinity by nonzero scalar produces point at infinity
198 {
199 op_queue->mul_accumulate(point_at_infinity, x);
200 op_queue->eq_and_reset();
201 op_queue->merge();
202
203 ECCVMCircuitBuilder circuit{ op_queue };
204 bool result = ECCVMTraceChecker::check(circuit);
205 EXPECT_EQ(result, true);
206 }
207 // validate multiplying a point by zero produces point at infinity
208 {
209 op_queue->mul_accumulate(b, zero_scalar);
210 op_queue->eq_and_reset();
211 op_queue->merge();
212
213 ECCVMCircuitBuilder circuit{ op_queue };
214 bool result = ECCVMTraceChecker::check(circuit);
215 EXPECT_EQ(result, true);
216 }
217 // validate multiplying a point at infinity by zero produces a point at infinity
218 {
219 op_queue->mul_accumulate(point_at_infinity, zero_scalar);
220 op_queue->eq_and_reset();
221 op_queue->merge();
222
223 ECCVMCircuitBuilder circuit{ op_queue };
224 bool result = ECCVMTraceChecker::check(circuit);
225 EXPECT_EQ(result, true);
226 }
227 // validate an MSM made entirely of points at infinity / zero scalars produces a point at infinity
228 {
229 op_queue->mul_accumulate(point_at_infinity, x);
230 op_queue->mul_accumulate(b, zero_scalar);
231 op_queue->eq_and_reset();
232 op_queue->merge();
233
234 ECCVMCircuitBuilder circuit{ op_queue };
235 bool result = ECCVMTraceChecker::check(circuit);
236 EXPECT_EQ(result, true);
237 }
238}
239
240TEST(ECCVMCircuitBuilderTests, ShortMul)
241{
243
244 auto generators = G1::derive_generators("test generators", 3);
245
246 typename G1::element a = generators[0];
247 uint256_t small_x = 0;
248 // make sure scalar is less than 127 bits to fit in z1
249 small_x.data[0] = engine.get_random_uint64();
250 small_x.data[1] = engine.get_random_uint64() & 0xFFFFFFFFFFFFULL;
251 Fr x = small_x;
252
253 op_queue->mul_accumulate(a, x);
254 op_queue->eq_and_reset();
255 op_queue->merge();
256 add_hiding_op_for_test(op_queue);
257
258 ECCVMCircuitBuilder circuit{ op_queue };
259 bool result = ECCVMTraceChecker::check(circuit, &engine);
260 EXPECT_EQ(result, true);
261}
262
263TEST(ECCVMCircuitBuilderTests, EqFails)
264{
266
267 auto generators = G1::derive_generators("test generators", 3);
268 typename G1::element a = generators[0];
270
271 op_queue->mul_accumulate(a, x);
272 // Tamper with the eq op such that the expected value is incorect
273 op_queue->add_erroneous_equality_op_for_testing();
274 op_queue->merge();
275 add_hiding_op_for_test(op_queue);
276
277 ECCVMCircuitBuilder circuit{ op_queue };
278 bool result = ECCVMTraceChecker::check(circuit, &engine);
279 EXPECT_EQ(result, false);
280}
281
282TEST(ECCVMCircuitBuilderTests, EmptyRow)
283{
285
286 op_queue->empty_row_for_testing();
287 op_queue->merge();
288 add_hiding_op_for_test(op_queue);
289
290 ECCVMCircuitBuilder circuit{ op_queue };
291 bool result = ECCVMTraceChecker::check(circuit, &engine);
292 EXPECT_EQ(result, true);
293}
294
295TEST(ECCVMCircuitBuilderTests, EmptyRowBetweenOps)
296{
298
299 auto generators = G1::derive_generators("test generators", 3);
300 typename G1::element a = generators[0];
302
303 op_queue->mul_accumulate(a, x);
304 op_queue->empty_row_for_testing();
305 op_queue->eq_and_reset();
306 op_queue->merge();
307 add_hiding_op_for_test(op_queue);
308
309 ECCVMCircuitBuilder circuit{ op_queue };
310 bool result = ECCVMTraceChecker::check(circuit, &engine);
311 EXPECT_EQ(result, true);
312}
313
314TEST(ECCVMCircuitBuilderTests, EndWithEq)
315{
317
318 auto generators = G1::derive_generators("test generators", 3);
319 typename G1::element a = generators[0];
321
322 op_queue->mul_accumulate(a, x);
323 op_queue->eq_and_reset();
324 op_queue->merge();
325 add_hiding_op_for_test(op_queue);
326
327 ECCVMCircuitBuilder circuit{ op_queue };
328 bool result = ECCVMTraceChecker::check(circuit, &engine);
329 EXPECT_EQ(result, true);
330}
331
332TEST(ECCVMCircuitBuilderTests, EndWithAdd)
333{
335
336 auto generators = G1::derive_generators("test generators", 3);
337 typename G1::element a = generators[0];
339
340 op_queue->mul_accumulate(a, x);
341 op_queue->eq_and_reset();
342 op_queue->add_accumulate(a);
343 op_queue->merge();
344 add_hiding_op_for_test(op_queue);
345
346 ECCVMCircuitBuilder circuit{ op_queue };
347 bool result = ECCVMTraceChecker::check(circuit, &engine);
348 EXPECT_EQ(result, true);
349}
350
351TEST(ECCVMCircuitBuilderTests, EndWithMul)
352{
354
355 auto generators = G1::derive_generators("test generators", 3);
356 typename G1::element a = generators[0];
358
359 op_queue->add_accumulate(a);
360 op_queue->eq_and_reset();
361 op_queue->mul_accumulate(a, x);
362 op_queue->merge();
363 add_hiding_op_for_test(op_queue);
364
365 ECCVMCircuitBuilder circuit{ op_queue };
366 bool result = ECCVMTraceChecker::check(circuit, &engine);
367 EXPECT_EQ(result, true);
368}
369
370TEST(ECCVMCircuitBuilderTests, EndWithNoop)
371{
373
374 auto generators = G1::derive_generators("test generators", 3);
375 typename G1::element a = generators[0];
377
378 op_queue->add_accumulate(a);
379 op_queue->eq_and_reset();
380 op_queue->mul_accumulate(a, x);
381
382 op_queue->empty_row_for_testing();
383 op_queue->merge();
384 add_hiding_op_for_test(op_queue);
385
386 ECCVMCircuitBuilder circuit{ op_queue };
387 bool result = ECCVMTraceChecker::check(circuit, &engine);
388 EXPECT_EQ(result, true);
389}
390
391TEST(ECCVMCircuitBuilderTests, MSM)
392{
393 static constexpr size_t max_num_msms = 9;
394 auto generators = G1::derive_generators("test generators", max_num_msms);
395
396 const auto compute_msms = [&](const size_t num_msms, auto& op_queue) {
398 std::vector<Fr> scalars;
399 typename G1::element expected = G1::point_at_infinity;
400 for (size_t i = 0; i < num_msms; ++i) {
401 points.emplace_back(generators[i]);
402 scalars.emplace_back(Fr::random_element(&engine));
403 expected += (points[i] * scalars[i]);
404 op_queue->mul_accumulate(points[i], scalars[i]);
405 }
406 op_queue->eq_and_reset();
407 op_queue->merge();
408 };
409
410 // single msms
411 for (size_t j = 1; j < max_num_msms; ++j) {
413
414 compute_msms(j, op_queue);
415 add_hiding_op_for_test(op_queue);
416 ECCVMCircuitBuilder circuit{ op_queue };
417 bool result = ECCVMTraceChecker::check(circuit);
418 EXPECT_EQ(result, true);
419 }
420 // chain msms
422
423 for (size_t j = 1; j < 9; ++j) {
424 compute_msms(j, op_queue);
425 }
426 add_hiding_op_for_test(op_queue);
427 ECCVMCircuitBuilder circuit{ op_queue };
428 bool result = ECCVMTraceChecker::check(circuit, &engine);
429 EXPECT_EQ(result, true);
430}
431
432TEST(ECCVMCircuitBuilderTests, EqAgainstPointAtInfinity)
433{
435
436 auto generators = G1::derive_generators("test generators", 3);
437 typename G1::element a = generators[0];
438 a.self_set_infinity();
439
440 op_queue->add_accumulate(a);
441 op_queue->eq_and_reset();
442 op_queue->merge();
443 add_hiding_op_for_test(op_queue);
444
445 ECCVMCircuitBuilder circuit{ op_queue };
446 bool result = ECCVMTraceChecker::check(circuit);
447 EXPECT_EQ(result, true);
448}
449
450TEST(ECCVMCircuitBuilderTests, AddPointAtInfinity)
451{
453
454 auto generators = G1::derive_generators("test generators", 3);
455 typename G1::element a = generators[0];
456 typename G1::element b = generators[0];
457 b.self_set_infinity();
458
459 op_queue->add_accumulate(a);
460 op_queue->add_accumulate(b);
461 op_queue->eq_and_reset();
462 op_queue->merge();
463 add_hiding_op_for_test(op_queue);
464
465 ECCVMCircuitBuilder circuit{ op_queue };
466 bool result = ECCVMTraceChecker::check(circuit);
467 EXPECT_EQ(result, true);
468}
469
470TEST(ECCVMCircuitBuilderTests, AddProducesPointAtInfinity)
471{
473
474 auto generators = G1::derive_generators("test generators", 3);
475 typename G1::element a = generators[0];
476
477 op_queue->add_accumulate(a);
478 op_queue->add_accumulate(-a);
479 op_queue->eq_and_reset();
480 op_queue->merge();
481 add_hiding_op_for_test(op_queue);
482
483 ECCVMCircuitBuilder circuit{ op_queue };
484 bool result = ECCVMTraceChecker::check(circuit);
485 EXPECT_EQ(result, true);
486}
487
488TEST(ECCVMCircuitBuilderTests, AddProducesDouble)
489{
491
492 auto generators = G1::derive_generators("test generators", 3);
493 typename G1::element a = generators[0];
494
495 op_queue->add_accumulate(a);
496 op_queue->add_accumulate(a);
497 op_queue->eq_and_reset();
498 op_queue->merge();
499 add_hiding_op_for_test(op_queue);
500
501 ECCVMCircuitBuilder circuit{ op_queue };
502 bool result = ECCVMTraceChecker::check(circuit);
503 EXPECT_EQ(result, true);
504}
505
523TEST(ECCVMCircuitBuilderTests, InfinityFailure)
524{
525 using G1 = g1::affine_element;
526 using Fr = fr;
527
528 auto P1 = G1::infinity();
529
530 // Add the same operations to the ECC op queue; the native computation is performed under the hood.
532
533 for (size_t i = 0; i < 1; i++) {
534 op_queue->mul_accumulate(P1, Fr(0));
535 }
536 op_queue->merge();
537 add_hiding_op_for_test(op_queue);
538
539 auto eccvm_builder = ECCVMCircuitBuilder(op_queue);
540
541 // Note: With the hiding op at index 0, the mul op is at index 1, so we check row 2
542 auto transcript_rows = ECCVMTranscriptBuilder::compute_rows(op_queue->get_eccvm_ops(), 1);
543
544 // check that the corresponding op is mul (now at row 2 due to hiding op at row 1)
545 bool row_op_code_correct = transcript_rows[2].opcode == 4;
546 // row.base_x populate the transcript polynomial transcript_Px in ECCVM Flavor
547 bool failure = Fr(transcript_rows[2].base_x) == Fr(0);
548
549 bool circuit_checked = ECCVMTraceChecker::check(eccvm_builder);
550
551 EXPECT_TRUE(failure && row_op_code_correct && circuit_checked);
552}
558TEST(ECCVMCircuitBuilderTests, ScalarEdgeCase)
559{
561
562 auto generators = G1::derive_generators("test generators", 1);
563 typename G1::element a = generators[0];
564
565 // Test with scalar = 2^128 (edge case for scalar decomposition)
566 Fr two_to_the_128 = Fr(uint256_t(1) << 128);
567 op_queue->mul_accumulate(a, two_to_the_128);
568
569 op_queue->merge();
570 add_hiding_op_for_test(op_queue);
571
572 ECCVMCircuitBuilder circuit{ op_queue };
573 bool result = ECCVMTraceChecker::check(circuit, &engine);
574 EXPECT_EQ(result, true);
575}
static bool check(ECCVMCircuitBuilder &, numeric::RNG *engine_ptr=nullptr)
static std::vector< TranscriptRow > compute_rows(const std::vector< ECCVMOperation > &vm_operations, const uint32_t total_number_of_muls)
Computes the ECCVM transcript rows.
group_elements::affine_element< Fq, Fr, Params > affine_element
Definition group.hpp:42
static constexpr element point_at_infinity
Definition group.hpp:47
group_elements::element< Fq, Fr, Params > element
Definition group.hpp:41
Fr_ Fr
Definition group.hpp:40
static std::vector< affine_element > derive_generators(const std::vector< uint8_t > &domain_separator_bytes, const size_t num_generators, const size_t starting_index=0)
Derives generator points via hash-to-curve.
Definition group.hpp:87
virtual uint64_t get_random_uint64()=0
FF a
FF b
typename G1::Fr Fr
numeric::RNG & engine
void add_hiding_op_for_test(const std::shared_ptr< ECCOpQueue > &op_queue)
Set a hiding op on the op_queue for testing.
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
group< fq, fr, Bn254G1Params > g1
Definition g1.hpp:33
field< Bn254FrParams > fr
Definition fr.hpp:174
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
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