Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
cycle_group.test.cpp
Go to the documentation of this file.
12#include <gtest/gtest.h>
13
14#define STDLIB_TYPE_ALIASES \
15 using Builder = TypeParam; \
16 using cycle_group_ct = stdlib::cycle_group<Builder>; \
17 using Curve = typename stdlib::cycle_group<Builder>::Curve; \
18 using Element = typename Curve::Element; \
19 using AffineElement = typename Curve::AffineElement; \
20 using Group = typename Curve::Group; \
21 using bool_ct = stdlib::bool_t<Builder>; \
22 using witness_ct = stdlib::witness_t<Builder>; \
23 using cycle_scalar_ct = cycle_group_ct::cycle_scalar;
24
25using namespace bb;
26
27namespace {
29}
30#pragma GCC diagnostic push
31#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
32
33template <class Builder> class CycleGroupTest : public ::testing::Test {
34 public:
36 using Group = typename Curve::Group;
37
38 using Element = typename Curve::Element;
40
41 static constexpr size_t num_generators = 110;
42 static inline std::array<AffineElement, num_generators> generators{};
43
44 static void SetUpTestSuite()
45 {
46
47 for (size_t i = 0; i < num_generators; ++i) {
48 generators[i] = Group::one * Curve::ScalarField::random_element(&engine);
49 }
50 };
51};
52
53using CircuitTypes = ::testing::Types<bb::UltraCircuitBuilder>;
55
61TYPED_TEST(CycleGroupTest, TestBasicTagLogic)
62{
65
66 auto lhs = TestFixture::generators[0];
67 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
68 // Set the whole tag first
69 a.set_origin_tag(next_challenge_tag);
70 // Set tags of x an y
71 a.x.set_origin_tag(submitted_value_origin_tag);
72 a.y.set_origin_tag(challenge_origin_tag);
73
74 // The tag of the _is_point_at_infinity member should stay as next_challenge_tag, so the whole thing should be the
75 // union of all 3
76
77 EXPECT_EQ(a.get_origin_tag(), first_second_third_merged_tag);
78
79#ifndef NDEBUG
80 cycle_group_ct b = cycle_group_ct::from_witness(&builder, TestFixture::generators[1]);
81 b.x.set_origin_tag(instant_death_tag);
82 // Even requesting the tag of the whole structure can cause instant death
83 EXPECT_THROW(b.get_origin_tag(), std::runtime_error);
84#endif
85}
86
91TYPED_TEST(CycleGroupTest, TestInfConstantWintnessRegression)
92{
95
96 auto lhs = TestFixture::generators[0] * 0;
97 cycle_group_ct a = cycle_group_ct::from_constant_witness(&builder, lhs);
98 (void)a;
99 EXPECT_FALSE(builder.failed());
100 EXPECT_TRUE(CircuitChecker::check(builder));
101}
102
107TYPED_TEST(CycleGroupTest, TestInfWintnessRegression)
108{
111
112 auto lhs = TestFixture::generators[0] * 0;
113 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
114 (void)a;
115 EXPECT_FALSE(builder.failed());
116 EXPECT_TRUE(CircuitChecker::check(builder));
117}
118
123TYPED_TEST(CycleGroupTest, TestWitnessSumRegression)
124{
127
128 auto lhs = TestFixture::generators[0];
129 auto rhs = TestFixture::generators[1];
130 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
131 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
132 cycle_group_ct c = a + b;
133 EXPECT_FALSE(c.is_constant());
134 c = a - b;
135 EXPECT_FALSE(c.is_constant());
136}
137
142TYPED_TEST(CycleGroupTest, TestOperatorNegRegression)
143{
146
147 auto lhs = TestFixture::generators[0];
148 auto rhs = TestFixture::generators[1];
149 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
150 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
151 b = -b;
152 cycle_group_ct c = a.unconditional_add(b);
153 (void)c;
154 EXPECT_FALSE(builder.failed());
155 EXPECT_TRUE(CircuitChecker::check(builder));
156}
157
162TYPED_TEST(CycleGroupTest, TestConstantWitnessMixupRegression)
163{
166
167 auto c1 = cycle_group_ct(AffineElement::one());
168 auto cw8 = cycle_group_ct::from_constant_witness(&builder, AffineElement::one() * 0);
169 auto w11 = cycle_group_ct::from_witness(&builder, TestFixture::generators[0]);
170
171 auto w9 = cw8 + c1; // mixup happens here due to _is_infinity being a constant
172 auto w26 = w9 + w11; // and here the circuit checker crashes
173
174 auto w10 = cw8 - c1;
175 auto w27 = w10 - w11; // and here
176 (void)w26;
177 (void)w27;
178 EXPECT_NO_THROW(CircuitChecker::check(builder)); // It won't be a throw anyway
179}
180
185TYPED_TEST(CycleGroupTest, TestConditionalAssignRegression)
186{
189
190 auto c0 = cycle_group_ct(AffineElement::one() * 0);
191 auto c1 = cycle_group_ct::conditional_assign(bool_ct(witness_ct(&builder, false)), c0, c0);
192 auto w3 = c1.dbl();
193 (void)w3;
194 EXPECT_NO_THROW(CircuitChecker::check(builder)); // It won't be a throw anyway
195}
196
201TYPED_TEST(CycleGroupTest, TestConditionalAssignSuperMixupRegression)
202{
205
206 auto c0 = cycle_group_ct(TestFixture::generators[0]);
207 auto c1 = cycle_group_ct(-TestFixture::generators[0]);
208 auto w2 = cycle_group_ct::conditional_assign(bool_ct(witness_ct(&builder, true)), c0, c1);
209 EXPECT_FALSE(w2.x.is_constant());
210 EXPECT_FALSE(w2.y.is_constant());
211 EXPECT_TRUE(w2.is_point_at_infinity().is_constant());
212 auto w3 = w2.dbl();
213 (void)w3;
214 EXPECT_NO_THROW(CircuitChecker::check(builder)); // It won't be a throw anyway
215}
216
221TYPED_TEST(CycleGroupTest, TestValidateOnCurveSucceed)
222{
225
226 auto lhs = TestFixture::generators[0];
227 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
228 a.validate_is_on_curve();
229 EXPECT_FALSE(builder.failed());
230 EXPECT_TRUE(CircuitChecker::check(builder));
231}
232
238TYPED_TEST(CycleGroupTest, TestValidateOnCurveInfinitySucceed)
239{
242
245
246 cycle_group_ct a(x, y, /*_is_infinity=*/true); // marks this point as the point at infinity
247 a.validate_is_on_curve();
248 EXPECT_FALSE(builder.failed());
249 EXPECT_TRUE(CircuitChecker::check(builder));
250}
251
257TYPED_TEST(CycleGroupTest, TestValidateOnCurveFail)
258{
261
264
265 cycle_group_ct a(x, y, /*_is_infinity=*/false);
266 a.validate_is_on_curve();
267 EXPECT_TRUE(builder.failed());
268 EXPECT_FALSE(CircuitChecker::check(builder));
269}
270
276TYPED_TEST(CycleGroupTest, TestValidateOnCurveFail2)
277{
280
283
284 cycle_group_ct a(x, y, /*_is_infinity=*/bool_ct(witness_ct(&builder, false)));
285 a.validate_is_on_curve();
286 EXPECT_TRUE(builder.failed());
287 EXPECT_FALSE(CircuitChecker::check(builder));
288}
289
290TYPED_TEST(CycleGroupTest, TestStandardForm)
291{
293 auto builder = Builder();
294
295 cycle_group_ct input_a = cycle_group_ct::from_witness(&builder, Element::random_element());
296 cycle_group_ct input_b = cycle_group_ct::from_witness(&builder, Element::random_element());
297 cycle_group_ct input_c = cycle_group_ct(Element::random_element());
298 cycle_group_ct input_d = cycle_group_ct(Element::random_element());
299
300 input_b.set_point_at_infinity(true);
301 input_d.set_point_at_infinity(true);
302
305 cycle_group_ct input_e = cycle_group_ct(x, y, true);
306 cycle_group_ct input_f = cycle_group_ct(x, y, bool_ct(witness_ct(&builder, true)));
307
308 // Assign different tags to all inputs
309 input_a.set_origin_tag(submitted_value_origin_tag);
310 input_b.set_origin_tag(challenge_origin_tag);
311 input_c.set_origin_tag(next_challenge_tag);
312 input_d.set_origin_tag(first_two_merged_tag);
313
314 auto standard_a = input_a.get_standard_form();
315 auto standard_b = input_b.get_standard_form();
316 auto standard_c = input_c.get_standard_form();
317 auto standard_d = input_d.get_standard_form();
318 auto standard_e = input_e.get_standard_form();
319 auto standard_f = input_f.get_standard_form();
320
321 EXPECT_EQ(standard_a.is_point_at_infinity().get_value(), false);
322 EXPECT_EQ(standard_b.is_point_at_infinity().get_value(), true);
323 EXPECT_EQ(standard_c.is_point_at_infinity().get_value(), false);
324 EXPECT_EQ(standard_d.is_point_at_infinity().get_value(), true);
325 EXPECT_EQ(standard_e.is_point_at_infinity().get_value(), true);
326 EXPECT_EQ(standard_f.is_point_at_infinity().get_value(), true);
327
328 // Ensure that the tags in the standard form remain the same
329 EXPECT_EQ(standard_a.get_origin_tag(), submitted_value_origin_tag);
330 EXPECT_EQ(standard_b.get_origin_tag(), challenge_origin_tag);
331 EXPECT_EQ(standard_c.get_origin_tag(), next_challenge_tag);
332 EXPECT_EQ(standard_d.get_origin_tag(), first_two_merged_tag);
333
334 auto input_a_x = input_a.x.get_value();
335 auto input_a_y = input_a.y.get_value();
336 auto input_c_x = input_c.x.get_value();
337 auto input_c_y = input_c.y.get_value();
338
339 auto standard_a_x = standard_a.x.get_value();
340 auto standard_a_y = standard_a.y.get_value();
341
342 auto standard_b_x = standard_b.x.get_value();
343 auto standard_b_y = standard_b.y.get_value();
344
345 auto standard_c_x = standard_c.x.get_value();
346 auto standard_c_y = standard_c.y.get_value();
347
348 auto standard_d_x = standard_d.x.get_value();
349 auto standard_d_y = standard_d.y.get_value();
350
351 auto standard_e_x = standard_e.x.get_value();
352 auto standard_e_y = standard_e.y.get_value();
353
354 auto standard_f_x = standard_f.x.get_value();
355 auto standard_f_y = standard_f.y.get_value();
356
357 EXPECT_EQ(input_a_x, standard_a_x);
358 EXPECT_EQ(input_a_y, standard_a_y);
359 EXPECT_EQ(standard_b_x, 0);
360 EXPECT_EQ(standard_b_y, 0);
361 EXPECT_EQ(input_c_x, standard_c_x);
362 EXPECT_EQ(input_c_y, standard_c_y);
363 EXPECT_EQ(standard_d_x, 0);
364 EXPECT_EQ(standard_d_y, 0);
365 EXPECT_EQ(standard_e_x, 0);
366 EXPECT_EQ(standard_e_y, 0);
367 EXPECT_EQ(standard_f_x, 0);
368 EXPECT_EQ(standard_f_y, 0);
369
370 EXPECT_TRUE(CircuitChecker::check(builder));
371}
373{
375 auto builder = Builder();
376
377 auto lhs = TestFixture::generators[0];
378 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
379 cycle_group_ct b = cycle_group_ct(lhs);
380 // Assign two different tags
381 a.set_origin_tag(submitted_value_origin_tag);
382 b.set_origin_tag(challenge_origin_tag);
383 cycle_group_ct c;
384 cycle_group_ct d;
385 std::cout << "pre = " << builder.get_estimated_num_finalized_gates() << std::endl;
386 for (size_t i = 0; i < 3; ++i) {
387 c = a.dbl();
388 }
389 std::cout << "post = " << builder.get_estimated_num_finalized_gates() << std::endl;
390 d = b.dbl();
391 AffineElement expected(Element(lhs).dbl());
392 AffineElement result = c.get_value();
393 EXPECT_EQ(result, expected);
394 EXPECT_EQ(d.get_value(), expected);
395
396 bool proof_result = CircuitChecker::check(builder);
397 EXPECT_EQ(proof_result, true);
398
399 // Ensure the tags stay the same after doubling
400 EXPECT_EQ(c.get_origin_tag(), submitted_value_origin_tag);
401 EXPECT_EQ(d.get_origin_tag(), challenge_origin_tag);
402}
403
404TYPED_TEST(CycleGroupTest, TestUnconditionalAdd)
405{
407 auto builder = Builder();
408
409 auto add =
410 [&](const AffineElement& lhs, const AffineElement& rhs, const bool lhs_constant, const bool rhs_constant) {
411 cycle_group_ct a = lhs_constant ? cycle_group_ct(lhs) : cycle_group_ct::from_witness(&builder, lhs);
412 cycle_group_ct b = rhs_constant ? cycle_group_ct(rhs) : cycle_group_ct::from_witness(&builder, rhs);
413 // Assign two different tags
414 a.set_origin_tag(submitted_value_origin_tag);
415 b.set_origin_tag(challenge_origin_tag);
416 cycle_group_ct c = a.unconditional_add(b);
417 AffineElement expected(Element(lhs) + Element(rhs));
418 AffineElement result = c.get_value();
419 EXPECT_EQ(result, expected);
420 // Ensure the tags in the result are merged
421 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
422 };
423
424 add(TestFixture::generators[0], TestFixture::generators[1], false, false);
425 add(TestFixture::generators[0], TestFixture::generators[1], false, true);
426 add(TestFixture::generators[0], TestFixture::generators[1], true, false);
427 add(TestFixture::generators[0], TestFixture::generators[1], true, true);
428
429 bool proof_result = CircuitChecker::check(builder);
430 EXPECT_EQ(proof_result, true);
431}
432
433TYPED_TEST(CycleGroupTest, TestConstrainedUnconditionalAddSucceed)
434{
436 auto builder = Builder();
437
438 auto lhs = TestFixture::generators[0];
439 auto rhs = TestFixture::generators[1];
440
441 // case 1. valid unconditional add
442 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
443 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
444 cycle_group_ct c = a.checked_unconditional_add(b);
445 AffineElement expected(Element(lhs) + Element(rhs));
446 AffineElement result = c.get_value();
447 EXPECT_EQ(result, expected);
448
449 bool proof_result = CircuitChecker::check(builder);
450 EXPECT_EQ(proof_result, true);
451}
452
453TYPED_TEST(CycleGroupTest, TestConstrainedUnconditionalAddFail)
454{
456 auto builder = Builder();
457
458 auto lhs = TestFixture::generators[0];
459 auto rhs = -TestFixture::generators[0]; // ruh roh
460
461 // case 2. invalid unconditional add
462 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
463 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
464 a.checked_unconditional_add(b);
465
466 EXPECT_TRUE(builder.failed());
467
468 bool proof_result = CircuitChecker::check(builder);
469 EXPECT_EQ(proof_result, false);
470}
471
473{
475 auto builder = Builder();
476
477 auto lhs = TestFixture::generators[0];
478 auto rhs = -TestFixture::generators[1];
479
480 cycle_group_ct point_at_infinity = cycle_group_ct::from_witness(&builder, rhs);
481 point_at_infinity.set_point_at_infinity(bool_ct(witness_ct(&builder, true)));
482
483 // case 1. no edge-cases triggered
484 {
485 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
486 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
487 // Here and in the following cases we assign two different tags
488 a.set_origin_tag(submitted_value_origin_tag);
489 b.set_origin_tag(challenge_origin_tag);
490 cycle_group_ct c = a + b;
491 AffineElement expected(Element(lhs) + Element(rhs));
492 AffineElement result = c.get_value();
493 EXPECT_EQ(result, expected);
494 // We expect the tags to be merged in the result
495 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
496 }
497
498 // case 2. lhs is point at infinity
499 {
500 cycle_group_ct a = point_at_infinity;
501 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
502 a.set_origin_tag(submitted_value_origin_tag);
503 b.set_origin_tag(challenge_origin_tag);
504
505 cycle_group_ct c = a + b;
506 AffineElement result = c.get_value();
507 EXPECT_EQ(result, rhs);
508 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
509 }
510
511 // case 3. rhs is point at infinity
512 {
513 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
514 cycle_group_ct b = point_at_infinity;
515 a.set_origin_tag(submitted_value_origin_tag);
516 b.set_origin_tag(challenge_origin_tag);
517
518 cycle_group_ct c = a + b;
519 AffineElement result = c.get_value();
520 EXPECT_EQ(result, lhs);
521 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
522 }
523
524 // case 4. both points are at infinity
525 {
526 cycle_group_ct a = point_at_infinity;
527 cycle_group_ct b = point_at_infinity;
528 a.set_origin_tag(submitted_value_origin_tag);
529 b.set_origin_tag(challenge_origin_tag);
530
531 cycle_group_ct c = a + b;
532 EXPECT_TRUE(c.is_point_at_infinity().get_value());
533 EXPECT_TRUE(c.get_value().is_point_at_infinity());
534 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
535 }
536
537 // case 5. lhs = -rhs
538 {
539 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
540 cycle_group_ct b = cycle_group_ct::from_witness(&builder, -lhs);
541 a.set_origin_tag(submitted_value_origin_tag);
542 b.set_origin_tag(challenge_origin_tag);
543
544 cycle_group_ct c = a + b;
545 EXPECT_TRUE(c.is_point_at_infinity().get_value());
546 EXPECT_TRUE(c.get_value().is_point_at_infinity());
547 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
548 }
549
550 // case 6. lhs = rhs
551 {
552 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
553 cycle_group_ct b = cycle_group_ct::from_witness(&builder, lhs);
554 a.set_origin_tag(submitted_value_origin_tag);
555 b.set_origin_tag(challenge_origin_tag);
556
557 cycle_group_ct c = a + b;
558 AffineElement expected((Element(lhs)).dbl());
559 AffineElement result = c.get_value();
560 EXPECT_EQ(result, expected);
561 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
562 }
563
564 bool proof_result = CircuitChecker::check(builder);
565 EXPECT_EQ(proof_result, true);
566}
567
568TYPED_TEST(CycleGroupTest, TestUnconditionalSubtract)
569{
571 auto builder = Builder();
572
573 auto subtract =
574 [&](const AffineElement& lhs, const AffineElement& rhs, const bool lhs_constant, const bool rhs_constant) {
575 cycle_group_ct a = lhs_constant ? cycle_group_ct(lhs) : cycle_group_ct::from_witness(&builder, lhs);
576 cycle_group_ct b = rhs_constant ? cycle_group_ct(rhs) : cycle_group_ct::from_witness(&builder, rhs);
577 // Assign two different tags
578 a.set_origin_tag(submitted_value_origin_tag);
579 b.set_origin_tag(challenge_origin_tag);
580
581 cycle_group_ct c = a.unconditional_subtract(b);
582 AffineElement expected(Element(lhs) - Element(rhs));
583 AffineElement result = c.get_value();
584 EXPECT_EQ(result, expected);
585 // Expect tags to be merged in the result
586 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
587 };
588
589 subtract(TestFixture::generators[0], TestFixture::generators[1], false, false);
590 subtract(TestFixture::generators[0], TestFixture::generators[1], false, true);
591 subtract(TestFixture::generators[0], TestFixture::generators[1], true, false);
592 subtract(TestFixture::generators[0], TestFixture::generators[1], true, true);
593
594 bool proof_result = CircuitChecker::check(builder);
595 EXPECT_EQ(proof_result, true);
596}
597
598TYPED_TEST(CycleGroupTest, TestConstrainedUnconditionalSubtractSucceed)
599{
601 auto builder = Builder();
602
603 auto lhs = TestFixture::generators[0];
604 auto rhs = TestFixture::generators[1];
605
606 // case 1. valid unconditional add
607 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
608 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
609 cycle_group_ct c = a.checked_unconditional_subtract(b);
610 AffineElement expected(Element(lhs) - Element(rhs));
611 AffineElement result = c.get_value();
612 EXPECT_EQ(result, expected);
613
614 bool proof_result = CircuitChecker::check(builder);
615 EXPECT_EQ(proof_result, true);
616}
617
618TYPED_TEST(CycleGroupTest, TestConstrainedUnconditionalSubtractFail)
619{
621 auto builder = Builder();
622
623 auto lhs = TestFixture::generators[0];
624 auto rhs = -TestFixture::generators[0]; // ruh roh
625
626 // case 2. invalid unconditional add
627 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
628 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
629 a.checked_unconditional_subtract(b);
630
631 EXPECT_TRUE(builder.failed());
632
633 bool proof_result = CircuitChecker::check(builder);
634 EXPECT_EQ(proof_result, false);
635}
636
638{
642 auto builder = Builder();
643
644 auto lhs = TestFixture::generators[0];
645 auto rhs = -TestFixture::generators[1];
646
647 cycle_group_ct point_at_infinity = cycle_group_ct::from_witness(&builder, rhs);
648 point_at_infinity.set_point_at_infinity(bool_ct(witness_ct(&builder, true)));
649
650 // case 1. no edge-cases triggered
651 {
652 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
653 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
654 // Here and in the following cases we set 2 different tags to a and b
655 a.set_origin_tag(submitted_value_origin_tag);
656 b.set_origin_tag(challenge_origin_tag);
657
658 cycle_group_ct c = a - b;
659 AffineElement expected(Element(lhs) - Element(rhs));
660 AffineElement result = c.get_value();
661 EXPECT_EQ(result, expected);
662 // We expect the tag of the result to be the union of a and b tags
663 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
664 }
665
666 // case 2. lhs is point at infinity
667 {
668 cycle_group_ct a = point_at_infinity;
669 cycle_group_ct b = cycle_group_ct::from_witness(&builder, rhs);
670 a.set_origin_tag(submitted_value_origin_tag);
671 b.set_origin_tag(challenge_origin_tag);
672
673 cycle_group_ct c = a - b;
674 AffineElement result = c.get_value();
675 EXPECT_EQ(result, -rhs);
676 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
677 }
678
679 // case 3. rhs is point at infinity
680 {
681 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
682 cycle_group_ct b = point_at_infinity;
683 a.set_origin_tag(submitted_value_origin_tag);
684 b.set_origin_tag(challenge_origin_tag);
685
686 cycle_group_ct c = a - b;
687 AffineElement result = c.get_value();
688 EXPECT_EQ(result, lhs);
689 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
690 }
691
692 // case 4. both points are at infinity
693 {
694 cycle_group_ct a = point_at_infinity;
695 cycle_group_ct b = point_at_infinity;
696 a.set_origin_tag(submitted_value_origin_tag);
697 b.set_origin_tag(challenge_origin_tag);
698
699 cycle_group_ct c = a - b;
700 EXPECT_TRUE(c.is_point_at_infinity().get_value());
701 EXPECT_TRUE(c.get_value().is_point_at_infinity());
702 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
703 }
704
705 // case 5. lhs = -rhs
706 {
707 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
708 cycle_group_ct b = cycle_group_ct::from_witness(&builder, -lhs);
709 a.set_origin_tag(submitted_value_origin_tag);
710 b.set_origin_tag(challenge_origin_tag);
711
712 cycle_group_ct c = a - b;
713 AffineElement expected((Element(lhs)).dbl());
714 AffineElement result = c.get_value();
715 EXPECT_EQ(result, expected);
716 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
717 }
718
719 // case 6. lhs = rhs
720 {
721 cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs);
722 cycle_group_ct b = cycle_group_ct::from_witness(&builder, lhs);
723 a.set_origin_tag(submitted_value_origin_tag);
724 b.set_origin_tag(challenge_origin_tag);
725
726 cycle_group_ct c = a - b;
727 EXPECT_TRUE(c.is_point_at_infinity().get_value());
728 EXPECT_TRUE(c.get_value().is_point_at_infinity());
729 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
730 }
731
732 bool proof_result = CircuitChecker::check(builder);
733 EXPECT_EQ(proof_result, true);
734}
735
737{
739 auto builder = Builder();
740
741 const size_t num_muls = 1;
748 auto assign_and_merge_tags = [](auto& points, auto& scalars) {
749 OriginTag merged_tag;
750 for (size_t i = 0; i < points.size(); i++) {
751 const auto point_tag = OriginTag(/*parent_index=*/0, /*round_index=*/i, /*is_submitted=*/true);
752 const auto scalar_tag = OriginTag(/*parent_index=*/0, /*round_index=*/i, /*is_submitted=*/false);
753
754 merged_tag = OriginTag(merged_tag, OriginTag(point_tag, scalar_tag));
755 points[i].set_origin_tag(point_tag);
756 scalars[i].set_origin_tag(scalar_tag);
757 }
758 return merged_tag;
759 };
760 // case 1, general MSM with inputs that are combinations of constant and witnesses
761 {
764 Element expected = Group::point_at_infinity;
765
766 for (size_t i = 0; i < num_muls; ++i) {
767 auto element = TestFixture::generators[i];
768 typename Group::Fr scalar = Group::Fr::random_element(&engine);
769
770 // 1: add entry where point, scalar are witnesses
771 expected += (element * scalar);
772 points.emplace_back(cycle_group_ct::from_witness(&builder, element));
773 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
774
775 // 2: add entry where point is constant, scalar is witness
776 expected += (element * scalar);
777 points.emplace_back(cycle_group_ct(element));
778 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
779
780 // 3: add entry where point is witness, scalar is constant
781 expected += (element * scalar);
782 points.emplace_back(cycle_group_ct::from_witness(&builder, element));
783 scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar));
784
785 // 4: add entry where point is constant, scalar is constant
786 expected += (element * scalar);
787 points.emplace_back(cycle_group_ct(element));
788 scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar));
789 }
790
791 // Here and in the following cases assign different tags to points and scalars and get the union of them back
792 const auto expected_tag = assign_and_merge_tags(points, scalars);
793
794 auto result = cycle_group_ct::batch_mul(points, scalars);
795 EXPECT_EQ(result.get_value(), AffineElement(expected));
796 // The tag should the union of all tags
797 EXPECT_EQ(result.get_origin_tag(), expected_tag);
798 }
799
800 // case 2, MSM that produces point at infinity
801 {
804
805 auto element = TestFixture::generators[0];
806 typename Group::Fr scalar = Group::Fr::random_element(&engine);
807 points.emplace_back(cycle_group_ct::from_witness(&builder, element));
808 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
809
810 points.emplace_back(cycle_group_ct::from_witness(&builder, element));
811 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, -scalar));
812
813 const auto expected_tag = assign_and_merge_tags(points, scalars);
814
815 auto result = cycle_group_ct::batch_mul(points, scalars);
816 EXPECT_TRUE(result.is_point_at_infinity().get_value());
817
818 EXPECT_EQ(result.get_origin_tag(), expected_tag);
819 }
820
821 // case 3. Multiply by zero
822 {
825
826 auto element = TestFixture::generators[0];
827 typename Group::Fr scalar = 0;
828 points.emplace_back(cycle_group_ct::from_witness(&builder, element));
829 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
830
831 const auto expected_tag = assign_and_merge_tags(points, scalars);
832 auto result = cycle_group_ct::batch_mul(points, scalars);
833 EXPECT_TRUE(result.is_point_at_infinity().get_value());
834 EXPECT_EQ(result.get_origin_tag(), expected_tag);
835 }
836
837 // case 4. Inputs are points at infinity
838 {
841
842 auto element = TestFixture::generators[0];
843 typename Group::Fr scalar = Group::Fr::random_element(&engine);
844
845 // is_infinity = witness
846 {
847 cycle_group_ct point = cycle_group_ct::from_witness(&builder, element);
848 point.set_point_at_infinity(witness_ct(&builder, true));
849 points.emplace_back(point);
850 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
851 }
852 // is_infinity = constant
853 {
854 cycle_group_ct point = cycle_group_ct::from_witness(&builder, element);
855 point.set_point_at_infinity(true);
856 points.emplace_back(point);
857 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
858 }
859
860 const auto expected_tag = assign_and_merge_tags(points, scalars);
861 auto result = cycle_group_ct::batch_mul(points, scalars);
862 EXPECT_TRUE(result.is_point_at_infinity().get_value());
863 EXPECT_EQ(result.get_origin_tag(), expected_tag);
864 }
865
866 // case 5, fixed-base MSM with inputs that are combinations of constant and witnesses (group elements are in
867 // lookup table)
868 {
871 std::vector<typename Group::Fq> scalars_native;
872 Element expected = Group::point_at_infinity;
873 for (size_t i = 0; i < num_muls; ++i) {
875 typename Group::Fr scalar = Group::Fr::random_element(&engine);
876
877 // 1: add entry where point is constant, scalar is witness
878 expected += (element * scalar);
879 points.emplace_back(element);
880 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
881 scalars_native.emplace_back(uint256_t(scalar));
882
883 // 2: add entry where point is constant, scalar is constant
885 expected += (element * scalar);
886 points.emplace_back(element);
887 scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar));
888 scalars_native.emplace_back(uint256_t(scalar));
889 }
890 const auto expected_tag = assign_and_merge_tags(points, scalars);
891 auto result = cycle_group_ct::batch_mul(points, scalars);
892 EXPECT_EQ(result.get_value(), AffineElement(expected));
893 EXPECT_EQ(result.get_value(), crypto::pedersen_commitment::commit_native(scalars_native));
894 EXPECT_EQ(result.get_origin_tag(), expected_tag);
895 }
896
897 // case 6, fixed-base MSM with inputs that are combinations of constant and witnesses (some group elements are
898 // in lookup table)
899 {
902 std::vector<typename Group::Fr> scalars_native;
903 Element expected = Group::point_at_infinity;
904 for (size_t i = 0; i < num_muls; ++i) {
906 typename Group::Fr scalar = Group::Fr::random_element(&engine);
907
908 // 1: add entry where point is constant, scalar is witness
909 expected += (element * scalar);
910 points.emplace_back(element);
911 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
912 scalars_native.emplace_back(scalar);
913
914 // 2: add entry where point is constant, scalar is constant
916 expected += (element * scalar);
917 points.emplace_back(element);
918 scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar));
919 scalars_native.emplace_back(scalar);
920
921 // // 3: add entry where point is constant, scalar is witness
922 scalar = Group::Fr::random_element(&engine);
923 element = Group::one * Group::Fr::random_element(&engine);
924 expected += (element * scalar);
925 points.emplace_back(element);
926 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
927 scalars_native.emplace_back(scalar);
928 }
929 const auto expected_tag = assign_and_merge_tags(points, scalars);
930 auto result = cycle_group_ct::batch_mul(points, scalars);
931 EXPECT_EQ(result.get_value(), AffineElement(expected));
932 EXPECT_EQ(result.get_origin_tag(), expected_tag);
933 }
934
935 // case 7, Fixed-base MSM where input scalars are 0
936 {
939
940 for (size_t i = 0; i < num_muls; ++i) {
942 typename Group::Fr scalar = 0;
943
944 // 1: add entry where point is constant, scalar is witness
945 points.emplace_back((element));
946 scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
947
948 // // 2: add entry where point is constant, scalar is constant
949 points.emplace_back((element));
950 scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar));
951 }
952 const auto expected_tag = assign_and_merge_tags(points, scalars);
953 auto result = cycle_group_ct::batch_mul(points, scalars);
954 EXPECT_EQ(result.is_point_at_infinity().get_value(), true);
955 EXPECT_EQ(result.get_origin_tag(), expected_tag);
956 }
957
958 bool check_result = CircuitChecker::check(builder);
959 EXPECT_EQ(check_result, true);
960}
961
963{
965 auto builder = Builder();
966
967 const size_t num_muls = 5;
968
969 // case 1, general MSM with inputs that are combinations of constant and witnesses
970 {
971 cycle_group_ct point;
972 typename cycle_group_ct::cycle_scalar scalar;
973 cycle_group_ct result;
974 for (size_t i = 0; i < num_muls; ++i) {
975 auto element = TestFixture::generators[i];
976 typename Group::Fr native_scalar = Group::Fr::random_element(&engine);
977 auto expected_result = element * native_scalar;
978
979 // 1: add entry where point, scalar are witnesses
980 point = (cycle_group_ct::from_witness(&builder, element));
981 scalar = (cycle_group_ct::cycle_scalar::from_witness(&builder, native_scalar));
982 point.set_origin_tag(submitted_value_origin_tag);
983 scalar.set_origin_tag(challenge_origin_tag);
984 result = point * scalar;
985
986 EXPECT_EQ((result).get_value(), (expected_result));
987
988 // 2: add entry where point is constant, scalar is witness
989 point = (cycle_group_ct(element));
990 scalar = (cycle_group_ct::cycle_scalar::from_witness(&builder, native_scalar));
991
992 EXPECT_EQ((result).get_value(), (expected_result));
993
994 // 3: add entry where point is witness, scalar is constant
995 point = (cycle_group_ct::from_witness(&builder, element));
996 EXPECT_EQ((result).get_value(), (expected_result));
997
998 // 4: add entry where point is constant, scalar is constant
999 point = (cycle_group_ct(element));
1000 EXPECT_EQ((result).get_value(), (expected_result));
1001 }
1002 }
1003
1004 bool proof_result = CircuitChecker::check(builder);
1005 EXPECT_EQ(proof_result, true);
1006}
1007
1009{
1012 cycle_group_ct one = cycle_group_ct::one(&builder);
1013 auto expected_one_native = Group::one;
1014 auto one_native = one.get_value();
1015 EXPECT_EQ(one_native.x, expected_one_native.x);
1016 EXPECT_EQ(one_native.y, expected_one_native.y);
1017}
1018
1024TYPED_TEST(CycleGroupTest, TestConversionFromBigfield)
1025{
1027 using FF = typename Curve::ScalarField;
1029
1030 const auto run_test = [](bool construct_witnesses) {
1032 auto elt = FF::random_element(&engine);
1033 FF_ct big_elt;
1034 if (construct_witnesses) {
1035 big_elt = FF_ct::from_witness(&builder, elt);
1036 } else {
1037 big_elt = FF_ct(elt);
1038 }
1039 big_elt.set_origin_tag(submitted_value_origin_tag);
1040 cycle_scalar_ct scalar_from_big_elt(big_elt);
1041 EXPECT_EQ(elt, scalar_from_big_elt.get_value());
1042 EXPECT_EQ(scalar_from_big_elt.get_origin_tag(), big_elt.get_origin_tag());
1043 if (construct_witnesses) {
1044 EXPECT_FALSE(big_elt.is_constant());
1045 EXPECT_FALSE(scalar_from_big_elt.is_constant());
1046 EXPECT_TRUE(CircuitChecker::check(builder));
1047 }
1048 };
1049 run_test(/*construct_witnesses=*/true);
1050 run_test(/*construct_witnesses=*/false);
1051}
1052
1053TYPED_TEST(CycleGroupTest, TestBatchMulIsConsistent)
1054{
1056 using FF = typename Curve::ScalarField;
1058
1059 const auto run_test = [](bool construct_witnesses) {
1061 auto scalar1 = FF::random_element(&engine);
1062 auto scalar2 = FF::random_element(&engine);
1063
1064 FF_ct big_scalar1;
1065 FF_ct big_scalar2;
1066 if (construct_witnesses) {
1067 big_scalar1 = FF_ct::from_witness(&builder, scalar1);
1068 big_scalar2 = FF_ct::from_witness(&builder, scalar2);
1069 } else {
1070 big_scalar1 = FF_ct(scalar1);
1071 big_scalar2 = FF_ct(scalar2);
1072 }
1073 cycle_group_ct result1 = cycle_group_ct::batch_mul({ TestFixture::generators[0], TestFixture::generators[1] },
1074 { big_scalar1, big_scalar2 });
1075
1076 cycle_group_ct result2 =
1077 cycle_group_ct::batch_mul({ TestFixture::generators[0], TestFixture::generators[1] },
1078 { cycle_scalar_ct(big_scalar1), cycle_scalar_ct(big_scalar2) });
1079
1080 AffineElement result1_native = result1.get_value();
1081 AffineElement result2_native = result2.get_value();
1082 EXPECT_EQ(result1_native.x, result2_native.x);
1083 EXPECT_EQ(result1_native.y, result2_native.y);
1084 if (construct_witnesses) {
1085 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1020): Re-enable these.
1086 // EXPECT_FALSE(result1.is_constant());
1087 // EXPECT_FALSE(result2.is_constant());
1088 EXPECT_TRUE(CircuitChecker::check(builder));
1089 }
1090 };
1091 run_test(/*construct_witnesses=*/true);
1092 run_test(/*construct_witnesses=*/false);
1093}
1094#pragma GCC diagnostic pop
static void SetUpTestSuite()
static std::array< AffineElement, num_generators > generators
typename Curve::Element Element
typename stdlib::cycle_group< Builder >::Curve Curve
typename Curve::Group Group
static constexpr size_t num_generators
typename Curve::AffineElement AffineElement
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
static AffineElement commit_native(const std::vector< Fq > &inputs, GeneratorContext context={})
Given a vector of fields, generate a pedersen commitment using the indexed generators.
Definition pedersen.cpp:24
typename Group::element Element
Definition bn254.hpp:21
typename bb::g1 Group
Definition bn254.hpp:20
typename Group::affine_element AffineElement
Definition bn254.hpp:22
static constexpr affine_element rhs_generator_point()
static constexpr affine_element lhs_generator_point()
Implements boolean logic in-circuit.
Definition bool.hpp:59
typename Builder::EmbeddedCurve Curve
static field_t from_witness(Builder *ctx, const bb::fr &input)
Definition field.hpp:424
AluTraceBuilder builder
Definition alu.test.cpp:123
FF a
FF b
bool expected_result
#define STDLIB_TYPE_ALIASES
ECCVMCircuitBuilder Builder
numeric::RNG & engine
bn254::witness_ct witness_ct
stdlib::bool_t< Builder > bool_ct
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
Entry point for Barretenberg command-line interface.
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
typename Flavor::FF FF
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
#define STANDARD_TESTING_TAGS
Curve::Element Element
testing::Types< bb::UltraCircuitBuilder > CircuitTypes