Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
field.test.cpp
Go to the documentation of this file.
1#include "field.hpp"
2#include "../bool/bool.hpp"
3#include "array.hpp"
9#include <gtest/gtest.h>
10#include <utility>
11
12using namespace bb;
13
14namespace {
16}
17
18template <class T> void ignore_unused(T&) {} // use to ignore unused variables in lambdas
19
20using namespace bb;
21
22template <typename Builder> class stdlib_field : public testing::Test {
27
28 static uint64_t fidget(Builder& builder)
29 {
30 field_ct a(public_witness_ct(&builder, fr::one())); // a is a legit wire value in our circuit
32 (fr::one())); // b is just a constant, and should not turn up as a wire value in our circuit
33 const size_t num_gates = builder.get_estimated_num_finalized_gates();
34
35 // This shouldn't create a constraint - we just need to scale the addition/multiplication gates that `a` is
36 // involved in, `c` should have the same witness index as `a`, i.e. point to the same wire value
37 field_ct c = a + b;
38 EXPECT_TRUE(c.witness_index == a.witness_index);
39 EXPECT_TRUE(builder.get_estimated_num_finalized_gates() == num_gates);
40 field_ct d(&builder, fr::coset_generator<0>()); // like b, d is just a constant and not a wire value
41
42 // by this point, we shouldn't have added any constraints in our circuit
43 for (size_t i = 0; i < 17; ++i) {
44 c = c * d; // shouldn't create a constraint - just scales up c (which points to same wire value as a)
45 c = c - d; // shouldn't create a constraint - just adds a constant term into c's gates
46 c = c * a; // will create a constraint - both c and a are wires in our circuit (the same wire actually, so
47 // this is a square-ish gate)
48 }
49
50 // run the same computation using normal types so we can compare the output
51 uint64_t aa = 1;
52 uint64_t bb = 1;
53 uint64_t cc = aa + bb;
54 uint64_t dd = 5;
55 for (size_t i = 0; i < 17; ++i) {
56 cc = cc * dd;
57 cc = cc - dd;
58 cc = cc * aa;
59 }
60 return cc;
61 }
62
63 static void build_test_circuit(Builder& builder, size_t num_gates)
64 {
67
68 field_ct c(&builder);
69 for (size_t i = 0; i < (num_gates / 4) - 4; ++i) {
70 c = a + b;
71 c = a * c;
72 a = b * b;
73 b = c * c;
74 }
75 }
76
77 public:
79 {
82 field_ct elt(witness_ct(&builder, val));
83 // Ensure the value is correct
84 EXPECT_EQ(elt.get_value(), val);
85 // Ensure that the context is not missing
86 EXPECT_FALSE(elt.is_constant());
87 }
88 static void test_add()
89 {
91 // Case 1: both summands are witnesses
94 field_ct sum = a + b;
95 EXPECT_TRUE(sum.get_value() == a.get_value() + b.get_value());
96 EXPECT_FALSE(sum.is_constant());
97
98 // Case 2: second summand is a constant
100 field_ct sum_with_constant = sum + c;
101 EXPECT_TRUE(sum_with_constant.get_value() == sum.get_value() + c.get_value());
102 EXPECT_TRUE(sum.witness_index == sum_with_constant.witness_index);
103
104 // Case 3: first summand is a constant
105 sum_with_constant = c + sum;
106 EXPECT_TRUE(sum_with_constant.get_value() == sum.get_value() + c.get_value());
107 EXPECT_TRUE(sum.witness_index == sum_with_constant.witness_index);
108
109 // Case 4: both summands are witnesses with matching indices
110 field_ct sum_with_same_witness_index = sum_with_constant + sum;
111 EXPECT_TRUE(sum_with_same_witness_index.get_value() == sum.get_value() + sum_with_constant.get_value());
112 EXPECT_TRUE((sum_with_same_witness_index.witness_index == sum_with_constant.witness_index) &&
113 (sum_with_same_witness_index.witness_index == sum.witness_index));
114
115 // Case 5: both summands are constant
117 field_ct constant_sum = c + d;
118 EXPECT_TRUE(constant_sum.is_constant());
119 EXPECT_TRUE(constant_sum.get_value() == d.get_value() + c.get_value());
120 }
122 {
123 auto run_test = [&](fr elt, size_t num_bits, bool expect_verified) {
126 a.create_range_constraint(num_bits, "field_tests: range_constraint on a fails");
127
128 bool verified = CircuitChecker::check(builder);
129 EXPECT_EQ(verified, expect_verified);
130 if (verified != expect_verified) {
131 info("Range constraint malfunction on ", elt, " with num_bits ", num_bits);
132 }
133 };
134
135 run_test(2, 1, false);
136 run_test(2, 2, true);
137 run_test(3, 2, true);
138 // 130 = 0b10000010, 8 bits
139 for (size_t num_bits = 1; num_bits < 17; num_bits++) {
140 run_test(130, num_bits, num_bits >= 8);
141 }
142
143 // -1 has maximum bit length
144 run_test(-1, fr::modulus.get_msb(), false);
145 run_test(-1, 128, false);
146 run_test(-1, fr::modulus.get_msb() + 1, true);
147 }
148
150 {
151 // Test the conversion from field_t to bool_t.
152
153 std::array<bb::fr, 5> input_array{ 0, 1, 0, 1, bb::fr::random_element() };
154 // Cases 0,1: Constant 0, 1
155 // Cases 2,3: Witnesses 0, 1
156 for (size_t idx = 0; idx < 4; idx++) {
157 bool expected_to_be_constant = (idx < 2);
159 field_ct field_elt = (expected_to_be_constant) ? field_ct(input_array[idx])
160 : field_ct(witness_ct(&builder, input_array[idx]));
161 bool_ct converted(field_elt);
162 EXPECT_TRUE(converted.is_constant() == expected_to_be_constant);
163 EXPECT_TRUE(field_elt.get_value() == converted.get_value());
164
165 if (!expected_to_be_constant) {
166 EXPECT_TRUE(CircuitChecker::check(builder));
167 EXPECT_TRUE(converted.witness_index == field_elt.witness_index);
168 }
169 }
170 // Check that the conversion aborts in the case of random field elements.
171 bool_ct invalid_bool;
172 // Case 4: Invalid constant conversion
174 invalid_bool = bool_ct(field_ct(input_array.back())),
175 "Assertion failed: (additive_constant == bb::fr::one() || additive_constant == bb::fr::zero())");
176 // Case 5: Invalid witness conversion
178 EXPECT_THROW_OR_ABORT(invalid_bool = bool_ct(field_ct(witness_ct(&builder, input_array.back()))),
179 "Assertion failed: ((witness == bb::fr::zero()) || (witness == bb::fr::one()) == true)");
180 }
186 {
189 bool_ct b_false = bool_ct(one * field_ct(0));
190 EXPECT_FALSE(b_false.get_value());
191 }
193 {
195 // Populate test inputs
201
203 engine.get_random_uint256(), // lhs, rhs = const
204 witness_ct(&builder, engine.get_random_uint256()), // one side is a witness
205 witness_ct(&builder, engine.get_random_uint256()), // both witnesses
206 lhs_in[3], // equal constants
207 lhs_in[4] // equal witnesses
208 };
209
210 auto check_conditional_assign =
211 [](auto& builder, bool_ct& predicate, field_ct& lhs, field_ct& rhs, bool same_elt) {
212 size_t num_gates_before = builder.get_estimated_num_finalized_gates();
213 field_ct result = field_ct::conditional_assign(predicate, lhs, rhs);
214 EXPECT_TRUE(result.get_value() == (predicate.get_value() ? lhs.get_value() : rhs.get_value()));
215
216 size_t expected_num_gates = 0;
217 // If predicate is constant, no need to constrain the result of the operation
218 if (!predicate.is_constant()) {
219 // If the witness index and constants of lhs and lhs do coincide, no gates are added
220 if (!same_elt) {
221 int num_witnesses = static_cast<int>(!rhs.is_constant()) + static_cast<int>(!lhs.is_constant());
222 // If lhs or rhs is a constant field element, `lhs - rhs` does not create an extra gate
223 expected_num_gates += static_cast<size_t>(num_witnesses);
224 }
225 }
226
227 EXPECT_TRUE(builder.get_estimated_num_finalized_gates() - num_gates_before == expected_num_gates);
228 };
229 // Populate predicate array, ensure that both constant and witness predicates are present
230 std::array<bool_ct, 4> predicates{
231 bool_ct(true), bool_ct(false), bool_ct(witness_ct(&builder, true)), bool_ct(witness_ct(&builder, false))
232 };
233
234 for (auto& predicate : predicates) {
235 for (size_t i = 0; i < 4; i++) {
236 check_conditional_assign(builder, predicate, lhs_in[i], rhs_in[i], i > 2);
237 }
238 }
239 EXPECT_TRUE(CircuitChecker::check(builder));
240 }
246 {
247
248 auto check_that_conditional_assign_result_is_constant = [](bool_ct& predicate) {
249 field_ct x(2);
250 field_ct y(2);
251 field_ct z(1);
252 field_ct alpha = x.madd(y, -z);
253 field_ct beta(3);
254 field_ct zeta = field_ct::conditional_assign(predicate, alpha, beta);
255
256 EXPECT_TRUE(zeta.is_constant());
257 };
258
260 // Populate predicate array, ensure that both constant and witness predicates are present
261 std::array<bool_ct, 4> predicates{
262 bool_ct(true), bool_ct(false), bool_ct(witness_ct(&builder, true)), bool_ct(witness_ct(&builder, false))
263 };
264
265 for (auto& predicate : predicates) {
266 check_that_conditional_assign_result_is_constant(predicate);
267 }
268 }
269
276 {
278
279 field_ct a(1);
280 field_ct b(1);
281 EXPECT_TRUE(a.multiplicative_constant == bb::fr::one());
282 EXPECT_TRUE(b.multiplicative_constant == bb::fr::one());
283 auto c = a + b;
284 EXPECT_TRUE(c.multiplicative_constant == bb::fr::one());
285 c = a - b;
286 EXPECT_TRUE(c.multiplicative_constant == bb::fr::one());
287 c = -c;
288 EXPECT_TRUE(c.multiplicative_constant == bb::fr::one());
289 }
290
294 static void test_assert_equal()
295 {
296 auto run_test = [](bool constrain, bool true_when_y_val_zero = true) {
298 field_ct x = witness_ct(&builder, 1);
299 field_ct y = witness_ct(&builder, 0);
300
301 // With no constraints, the proof verification will pass even though
302 // we assert x and y are equal.
303 bool expected_result = true;
304
305 if (constrain) {
306 /* The fact that we have a passing test in both cases that follow tells us
307 * that the failure in the first case comes from the additive constraint,
308 * not from a copy constraint. That failure is because the assert_equal
309 * below says that 'the value of y was always x'--the value 1 is substituted
310 * for x when evaluating the gate identity.
311 */
312 if (true_when_y_val_zero) {
313 // constraint: 0*x + 1*y + 0*0 + 0 == 0
314
315 builder.create_add_gate({ .a = x.witness_index,
316 .b = y.witness_index,
317 .c = builder.zero_idx,
318 .a_scaling = 0,
319 .b_scaling = 1,
320 .c_scaling = 0,
321 .const_scaling = 0 });
322 expected_result = false;
323 } else {
324 // constraint: 0*x + 1*y + 0*0 - 1 == 0
325
326 builder.create_add_gate({ .a = x.witness_index,
327 .b = y.witness_index,
328 .c = builder.zero_idx,
329 .a_scaling = 0,
330 .b_scaling = 1,
331 .c_scaling = 0,
332 .const_scaling = -1 });
333 expected_result = true;
334 }
335 }
336
337 x.assert_equal(y);
338
339 // both field elements have real value 1 now
340 EXPECT_EQ(x.get_value(), 1);
341 EXPECT_EQ(y.get_value(), 1);
342
343 bool result = CircuitChecker::check(builder);
344
345 EXPECT_EQ(result, expected_result);
346 };
347
348 run_test(false);
349 run_test(true, true);
350 run_test(true, false);
351 }
352
354 {
356
357 // Constant == constant
358 {
359 field_ct a(&builder, 5);
360 field_ct b(&builder, 5);
361 EXPECT_NO_THROW(a.assert_equal(b));
362 }
363
364 // Constant != constant
365 {
366 field_ct a(&builder, 3);
367 field_ct b(&builder, 7);
368 EXPECT_THROW_OR_ABORT(a.assert_equal(b), "field_t::assert_equal: constants are not equal");
369 }
370
371 // Constant == witness
372 {
374 size_t num_gates_start = builder.get_estimated_num_finalized_gates();
375 field_ct a(&builder, 9);
377 a.assert_equal(b);
378 EXPECT_TRUE(CircuitChecker::check(builder));
379 // 1 gate is needed to fix the constant
380 EXPECT_EQ(builder.get_estimated_num_finalized_gates() - num_gates_start, 1);
381 }
382
383 // Witness == constant
384 {
386 size_t num_gates_start = builder.get_estimated_num_finalized_gates();
388 field_ct b(&builder, 42);
389 a.assert_equal(b);
390 EXPECT_TRUE(CircuitChecker::check(builder));
391 // 1 gate is needed to fix the constant
392 EXPECT_EQ(builder.get_estimated_num_finalized_gates() - num_gates_start, 1);
393 }
394
395 // Witness == witness (equal values)
396 {
398 size_t num_gates_start = builder.get_estimated_num_finalized_gates();
399
402 a.assert_equal(b);
403 EXPECT_TRUE(CircuitChecker::check(builder));
404 // Both witnesses are normalized, no gates are created, only a copy constraint
405 EXPECT_EQ(builder.get_estimated_num_finalized_gates() - num_gates_start, 0);
406 }
407
408 // Witness != witness (both are not normalized)
409 {
411 size_t num_gates_start = builder.get_estimated_num_finalized_gates();
413 a += 13;
415 b += 1;
416 a.assert_equal(b);
417 EXPECT_FALSE(CircuitChecker::check(builder));
418 // Both witnesses are not normalized, we use a single `add_gate` to ensure they are equal
419 EXPECT_EQ(builder.get_estimated_num_finalized_gates() - num_gates_start, 1);
420 EXPECT_EQ(builder.err(), "field_t::assert_equal");
421 }
422 }
423
425 {
427 auto gates_before = builder.get_estimated_num_finalized_gates();
428 uint64_t expected = fidget(builder);
429 auto gates_after = builder.get_estimated_num_finalized_gates();
430 auto& block = builder.blocks.arithmetic;
431 EXPECT_EQ(builder.get_variable(block.w_o()[block.size() - 1]), fr(expected));
432 info("Number of gates added", gates_after - gates_before);
433 bool result = CircuitChecker::check(builder);
434 EXPECT_EQ(result, true);
435 }
436
437 static void test_div()
438 {
440
444
448
449 // Case 0: Numerator = const, denominator != const
450 field_ct out = field_ct(&builder, b.get_value()) / a;
451 EXPECT_EQ(out.get_value(), b.get_value() / a.get_value());
452 EXPECT_FALSE(out.is_constant());
453 // Check that the result is normalized in this case
454 EXPECT_TRUE(out.multiplicative_constant == 1 && out.additive_constant == 0);
455
456 // Case 1: Numerator and denominator != const
457 out = b / a;
458 EXPECT_EQ(out.get_value(), b.get_value() / a.get_value());
459
460 // Case 2: Numerator != const, denominator = const,
461 out = a / b.get_value();
462 EXPECT_EQ(out.get_value(), a.get_value() / b.get_value());
463 EXPECT_EQ(out.witness_index, a.witness_index);
464
465 // Case 3: Numerator = const 0.
466 out = field_ct(0) / b;
467 EXPECT_EQ(out.get_value(), 0);
468 EXPECT_EQ(out.is_constant(), true);
469
470 bool result = CircuitChecker::check(builder);
471 EXPECT_EQ(result, true);
472 }
473
475 {
476 // Case 0. Numerator = const, denominator = const. Check the correctness of the value and that the result is
477 // constant.
480 field_ct q = a / b;
481 EXPECT_TRUE(q.is_constant());
482 EXPECT_EQ(a.get_value() / b.get_value(), q.get_value());
483
484 {
485 // Case 1. Numerator = const, denominator = const 0. Check that the division is aborted
486 b = 0;
487 EXPECT_THROW_OR_ABORT(a / b, ".*");
488 }
489 { // Case 2. Numerator != const, denominator = const 0. Check that the division is aborted
492 b = 0;
493 EXPECT_THROW_OR_ABORT(a / b, ".*");
494 }
495 {
496 // Case 3. Numerator != const, denominator = witness 0 . Check that the circuit fails.
500 q = a / b;
501 EXPECT_FALSE(CircuitChecker::check(builder));
502 }
503 {
504 // Case 4. Numerator = const, denominator = witness 0 . Check that the circuit fails.
508 q = a / b;
509 EXPECT_FALSE(CircuitChecker::check(builder));
510 }
511 }
512 static void test_invert()
513 {
514 // Test constant case
516 field_ct b = a.invert();
517 // Check that the result is constant and correct
518 EXPECT_TRUE(a.is_constant() && (b.get_value() * a.get_value() == 1));
519
520 // Test non-constant case
522 a = witness_ct(&builder, a.get_value());
523 b = a.invert();
524 // Check that the result is normalized
525 EXPECT_TRUE((b.multiplicative_constant == 1) && (b.additive_constant == 0));
526 // Check that the result is correct
527 EXPECT_TRUE(a.get_value() * b.get_value() == 1);
528 }
529
530 static void test_invert_zero()
531 {
533
535 {
536 a.invert();
537 // Check that the result is constant and correct
538 EXPECT_FALSE(CircuitChecker::check(builder));
539 EXPECT_EQ(builder.err(), "field_t::invert denominator is 0");
540 }
541
542 a = 0;
543 EXPECT_THROW_OR_ABORT(a.invert(), "field_t::invert denominator is constant 0");
544 }
546 {
548
550
551 field_ct b = a++;
552
553 EXPECT_EQ(b.get_value(), 10);
554 EXPECT_EQ(a.get_value(), 11);
555 EXPECT_TRUE(!b.is_constant());
556
557 EXPECT_TRUE(CircuitChecker::check(builder));
558 }
559
561 {
563
565
566 field_ct b = ++a;
567
568 EXPECT_EQ(b.get_value(), 11);
569 EXPECT_EQ(a.get_value(), 11);
570
571 bool result = CircuitChecker::check(builder);
572 EXPECT_EQ(result, true);
573 }
574
576 {
580
581 field_ct c = a + b;
582
583 for (size_t i = 0; i < 16; ++i) {
584 b = a;
585 a = c;
586 c = a + b;
587 }
588
589 EXPECT_EQ(c.get_value(), fr(4181));
590
591 bool result = CircuitChecker::check(builder);
592 EXPECT_EQ(result, true);
593 }
594
596 {
598
602
603 field_ct a_sqr = a * a;
604 field_ct b_sqr = b * b;
605 field_ct c_sqr = c * c;
606 c_sqr.set_public();
607 field_ct sum_sqrs = a_sqr + b_sqr;
608
609 // builder.assert_equal(sum_sqrs.witness_index, c_sqr.witness_index, "triple is not pythagorean");
610 c_sqr.assert_equal(sum_sqrs);
611
612 bool verified = CircuitChecker::check(builder);
613
614 ASSERT_TRUE(verified);
615 }
616
617 static void test_equality()
618 {
620 auto gates_before = builder.get_estimated_num_finalized_gates();
623 bool_ct r = a == b;
624
625 auto gates_after = builder.get_estimated_num_finalized_gates();
626 EXPECT_EQ(r.get_value(), true);
627
628 fr x = r.get_value();
629 EXPECT_EQ(x, fr(1));
630 // Using a == b, when both a and b are witnesses, adds 4 constraints:
631 // 1) compute a - b;
632 // 2) ensure r is bool;
633 // 3) (a - b) * I + r - 1 = 0;
634 // 4) -I * r + r = 0.
635 EXPECT_EQ(gates_after - gates_before, 4UL);
636
637 bool result = CircuitChecker::check(builder);
638 EXPECT_EQ(result, true);
639 }
640
642 {
644
645 auto gates_before = builder.get_estimated_num_finalized_gates();
648 bool_ct r = a == b;
649 auto gates_after = builder.get_estimated_num_finalized_gates();
650
651 EXPECT_FALSE(r.get_value());
652
653 // Using a == b, when both a and b are witnesses, adds 4 constraints:
654 // 1) compute a - b;
655 // 2) ensure r is bool;
656 // 3) (a - b) * I + r - 1 = 0;
657 // 4) -I * r + r = 0
658 EXPECT_EQ(gates_after - gates_before, 4UL);
659 EXPECT_TRUE(CircuitChecker::check(builder));
660 }
661
663 {
666
667 auto gates_before = builder.get_estimated_num_finalized_gates();
668 field_ct b = 3;
669 field_ct c = 7;
670 // Note that the lhs is constant, hence (rhs - lhs) can be computed without adding new gates, using == in
671 // this case requires 3 constraints 1) ensure r is bool; 2) (a - b) * I + r - 1 = 0; 3) -I * r + r = 0
672 bool_ct r = (a * c) == (b * c + c);
673 auto gates_after = builder.get_estimated_num_finalized_gates();
674 EXPECT_EQ(gates_after - gates_before, 3UL);
675 r = r && (b + 1 == a);
676 EXPECT_EQ(r.get_value(), true);
677 // The situation is as above, but we also applied && to bool_t witnesses, which adds an extra gate.
678 EXPECT_EQ(builder.get_estimated_num_finalized_gates() - gates_after, 4UL);
679 EXPECT_TRUE(CircuitChecker::check(builder));
680 }
681
683 {
684 size_t n = 16384;
686
688
689 bool result = CircuitChecker::check(builder);
690 EXPECT_EQ(result, true);
691 }
692
693 static void test_is_zero()
694 {
696 // Create constant elements
698 field_ct e(&builder, fr::one());
699 // Validate that `is_zero()` check does not add any gates in this case
700 const size_t old_n = builder.get_estimated_num_finalized_gates();
701 bool_ct d_zero = d.is_zero();
702 bool_ct e_zero = e.is_zero();
703 const size_t new_n = builder.get_estimated_num_finalized_gates();
704 EXPECT_EQ(old_n, new_n);
705
706 // Create witnesses
709 // Create constants
713 field_ct c_4 = c_1 + c_2;
714
715 // Ensure that `a` and `b` are not normalized
716 a = a * c_4 + c_4;
717 b = b * c_4 + c_4; // = -c_4 + c_4
718 b = (b - c_1 - c_2) / c_4; // = (-c_1 - c_2 )/c_4 = -1
719 b = b + c_3; // = -1 + 1 = 0
720 EXPECT_TRUE(a.additive_constant != 0 || a.multiplicative_constant != 1);
721 EXPECT_TRUE(b.additive_constant != 0 || b.multiplicative_constant != 1);
722
723 bool_ct a_zero = a.is_zero();
724 bool_ct b_zero = b.is_zero();
725
726 bool_ct a_normalized_zero = a.normalize().is_zero();
727 bool_ct b_normalized_zero = b.normalize().is_zero();
728
729 EXPECT_EQ(a_zero.get_value(), false);
730 EXPECT_EQ(b_zero.get_value(), true);
731 EXPECT_EQ(a_normalized_zero.get_value(), false);
732 EXPECT_EQ(b_normalized_zero.get_value(), true);
733 EXPECT_EQ(d_zero.get_value(), true);
734 EXPECT_EQ(e_zero.get_value(), false);
735
736 bool result = CircuitChecker::check(builder);
737 EXPECT_EQ(result, true);
738 }
739
741 {
743 size_t num_gates_before = builder.get_estimated_num_finalized_gates();
745 if (a.get_value() == 0) {
746 a += 1;
747 }
748 a.assert_is_not_zero();
749 // a is a constant, so no gates should be added
750 EXPECT_TRUE(builder.get_estimated_num_finalized_gates() - num_gates_before == 0);
751 a = witness_ct(&builder, 17);
752 a.assert_is_not_zero();
753 EXPECT_TRUE(builder.get_estimated_num_finalized_gates() - num_gates_before == 1);
754 // Ensure a is not normalized anymore
755 a *= 2;
756 a += 4;
757 a.assert_is_not_zero();
758 EXPECT_TRUE(CircuitChecker::check(builder));
759 { // a is a non-normalized witness with value 0
760 a -= field_ct(a.get_value());
761 a.assert_is_not_zero();
762 EXPECT_FALSE(CircuitChecker::check(builder));
763 }
764 { // a is a normalized witness with value 0
765 a = witness_ct(&builder, 0);
766 a.assert_is_not_zero();
767 EXPECT_FALSE(CircuitChecker::check(builder));
768 }
769 { // a is a const 0
770 a = field_ct(0);
771 EXPECT_THROW_OR_ABORT(a.assert_is_not_zero(), "assert_is_not_zero");
772 }
773 }
774
775 static void test_madd()
776 {
778
788
789 // test madd when all operands are witnesses
790 field_ct d = a * ma + ca;
791 field_ct e = b * mb + cb;
792 field_ct f = c * mc + cc;
793 field_ct g = d.madd(e, f);
794 field_ct h = d * e + f;
795 h = h.normalize();
796 g = g.normalize();
797 EXPECT_EQ(g.get_value(), h.get_value());
798
799 // test madd when to_add = constant
800 field_ct i = a.madd(b, ma);
801 field_ct j = a * b + ma;
802 i = i.normalize();
803 j = j.normalize();
804 EXPECT_EQ(i.get_value(), j.get_value());
805
806 // test madd when to_mul = constant
807 field_ct k = a.madd(mb, c);
808 field_ct l = a * mb + c;
809 k = k.normalize();
810 l = l.normalize();
811 EXPECT_EQ(k.get_value(), l.get_value());
812
813 // test madd when lhs is constant
814 field_ct m = ma.madd(b, c);
815 field_ct n = ma * b + c;
816 m = m.normalize();
817 n = n.normalize();
818 EXPECT_EQ(m.get_value(), n.get_value());
819
820 bool result = CircuitChecker::check(builder);
821 EXPECT_EQ(result, true);
822 }
824 {
825
826 auto make_constant = [](Builder& builder, int val) { return field_ct(&builder, bb::fr(val)); };
827 auto make_witness = [](Builder& builder, int val) { return field_ct(witness_ct(&builder, bb::fr(val))); };
828
829 struct Case {
830 bool a_const;
831 bool b_const;
832 bool c_const;
833 bool expect_gate;
834 };
835
836 std::vector<Case> cases = {
837 { true, true, true, false }, { true, true, false, false }, { true, false, true, false },
838 { false, true, true, false }, { true, false, false, true }, { false, true, false, true },
839 { false, false, true, true }, { false, false, false, true },
840 };
841
842 for (const auto& [a_const, b_const, c_const, expect_gate] : cases) {
844
845 auto a = a_const ? make_constant(builder, 1) : make_witness(builder, 1);
846 auto b = b_const ? make_constant(builder, 2) : make_witness(builder, 2);
847 auto c = c_const ? make_constant(builder, 3) : make_witness(builder, 3);
848
849 size_t before = builder.get_estimated_num_finalized_gates();
850 a.madd(b, c);
851 size_t after = builder.get_estimated_num_finalized_gates();
852 bool gate_added = (after - before == 1);
853 EXPECT_EQ(gate_added, expect_gate);
854
855 before = builder.get_estimated_num_finalized_gates();
856 a.add_two(b, c);
857 after = builder.get_estimated_num_finalized_gates();
858
859 gate_added = (after - before == 1);
860 EXPECT_EQ(gate_added, expect_gate);
861 }
862 }
864 {
866 std::array<bool_ct, 4> predicates{
867 bool_ct(true), bool_ct(false), bool_ct(witness_ct(&builder, true)), bool_ct(witness_ct(&builder, false))
868 };
869 field_ct constant_summand(bb::fr::random_element());
871 for (auto& predicate : predicates) {
872
873 const bool predicate_is_witness = !predicate.is_constant();
874
875 // Conditionally negate a constant
876 size_t num_gates_before = builder.get_estimated_num_finalized_gates();
877 auto result = constant_summand.conditional_negate(predicate);
878 auto expected_result = predicate.get_value() ? -constant_summand.get_value() : constant_summand.get_value();
879 EXPECT_TRUE(result.get_value() == expected_result);
880 // Check that `result` is constant if and only if both the predicate and (*this) are constant.
881 EXPECT_TRUE(result.is_constant() == predicate.is_constant());
882 // A gate is only added if the predicate is a witness
883 EXPECT_TRUE(builder.get_estimated_num_finalized_gates() - num_gates_before == 0);
884
885 // Conditionally negate a witness
886 num_gates_before = builder.get_estimated_num_finalized_gates();
887 result = witness_summand.conditional_negate(predicate);
888 expected_result = predicate.get_value() ? -witness_summand.get_value() : witness_summand.get_value();
889 EXPECT_TRUE(result.get_value() == expected_result);
890 // The result must be a witness
891 EXPECT_FALSE(result.is_constant());
892 // A gate is only added if the predicate is a witness
893 EXPECT_TRUE(builder.get_estimated_num_finalized_gates() - num_gates_before == predicate_is_witness);
894 }
895 }
896 static void test_two_bit_table()
897 {
903
905
906 bool_ct zero(witness_ct(&builder, false));
907 bool_ct one(witness_ct(&builder, true));
908
909 field_ct result_a = field_ct::select_from_two_bit_table(table, zero, zero).normalize();
910 field_ct result_b = field_ct::select_from_two_bit_table(table, zero, one).normalize();
911 field_ct result_c = field_ct::select_from_two_bit_table(table, one, zero).normalize();
912 field_ct result_d = field_ct::select_from_two_bit_table(table, one, one).normalize();
913
914 EXPECT_EQ(result_a.get_value(), a.get_value());
915 EXPECT_EQ(result_b.get_value(), b.get_value());
916 EXPECT_EQ(result_c.get_value(), c.get_value());
917 EXPECT_EQ(result_d.get_value(), d.get_value());
918
919 bool result = CircuitChecker::check(builder);
920 EXPECT_EQ(result, true);
921 }
922
923 static void test_split_at()
924 {
926
927 // Test different bit sizes
928 std::vector<size_t> test_bit_sizes = { 8, 16, 32, 100, 252 };
929
930 // Lambda to check split_at functionality
931 auto check_split_at = [&](const field_ct& a, size_t start, size_t num_bits) {
932 const uint256_t a_native = a.get_value();
933 auto split_data = a.split_at(start, num_bits);
934 EXPECT_EQ(split_data.first.get_value(), a_native & ((uint256_t(1) << start) - 1));
935 EXPECT_EQ(split_data.second.get_value(), (a_native >> start) & ((uint256_t(1) << num_bits) - 1));
936
937 if (a.is_constant()) {
938 EXPECT_TRUE(split_data.first.is_constant());
939 EXPECT_TRUE(split_data.second.is_constant());
940 }
941
942 if (start == 0) {
943 EXPECT_TRUE(split_data.first.is_constant());
944 EXPECT_TRUE(split_data.first.get_value() == 0);
945 EXPECT_EQ(split_data.second.get_value(), a.get_value());
946 }
947 };
948
949 for (size_t num_bits : test_bit_sizes) {
950 uint256_t a_native = engine.get_random_uint256() & ((uint256_t(1) << num_bits) - 1);
951
952 // check split_at for a constant
953 field_ct a_constant(a_native);
954 check_split_at(a_constant, 0, num_bits);
955 check_split_at(a_constant, num_bits / 4, num_bits);
956 check_split_at(a_constant, num_bits / 3, num_bits);
957 check_split_at(a_constant, num_bits / 2, num_bits);
958 check_split_at(a_constant, num_bits - 1, num_bits);
959
960 // check split_at for a witness
961 field_ct a_witness(witness_ct(&builder, a_native));
962 check_split_at(a_witness, 0, num_bits);
963 check_split_at(a_witness, num_bits / 4, num_bits);
964 check_split_at(a_witness, num_bits / 3, num_bits);
965 check_split_at(a_witness, num_bits / 2, num_bits);
966 check_split_at(a_witness, num_bits - 1, num_bits);
967 }
968
969 bool result = CircuitChecker::check(builder);
970 EXPECT_EQ(result, true);
971 }
972
974 {
984
986
987 bool_ct zero(witness_ct(&builder, false));
988 bool_ct one(witness_ct(&builder, true));
989
990 field_ct result_a = field_ct::select_from_three_bit_table(table, zero, zero, zero).normalize();
991 field_ct result_b = field_ct::select_from_three_bit_table(table, zero, zero, one).normalize();
992 field_ct result_c = field_ct::select_from_three_bit_table(table, zero, one, zero).normalize();
993 field_ct result_d = field_ct::select_from_three_bit_table(table, zero, one, one).normalize();
994 field_ct result_e = field_ct::select_from_three_bit_table(table, one, zero, zero).normalize();
995 field_ct result_f = field_ct::select_from_three_bit_table(table, one, zero, one).normalize();
996 field_ct result_g = field_ct::select_from_three_bit_table(table, one, one, zero).normalize();
997 field_ct result_h = field_ct::select_from_three_bit_table(table, one, one, one).normalize();
998
999 EXPECT_EQ(result_a.get_value(), a.get_value());
1000 EXPECT_EQ(result_b.get_value(), b.get_value());
1001 EXPECT_EQ(result_c.get_value(), c.get_value());
1002 EXPECT_EQ(result_d.get_value(), d.get_value());
1003 EXPECT_EQ(result_e.get_value(), e.get_value());
1004 EXPECT_EQ(result_f.get_value(), f.get_value());
1005 EXPECT_EQ(result_g.get_value(), g.get_value());
1006 EXPECT_EQ(result_h.get_value(), h.get_value());
1007
1008 bool result = CircuitChecker::check(builder);
1009 EXPECT_EQ(result, true);
1010 }
1011
1013 {
1015
1018 field_ct c(witness_ct(&builder, fr(3)));
1019 field_ct d(witness_ct(&builder, fr(4)));
1020 field_ct e(witness_ct(&builder, fr(5)));
1021 std::vector<field_ct> set = { a, b, c, d, e };
1022
1023 a.assert_is_in_set(set);
1024 info("num gates = ", builder.get_estimated_num_finalized_gates());
1025
1026 bool result = CircuitChecker::check(builder);
1027 EXPECT_EQ(result, true);
1028 }
1029
1031 {
1033
1036 field_ct c(witness_ct(&builder, fr(3)));
1037 field_ct d(witness_ct(&builder, fr(4)));
1038 field_ct e(witness_ct(&builder, fr(5)));
1039 std::vector<field_ct> set = { a, b, c, d, e };
1040
1041 field_ct f(witness_ct(&builder, fr(6)));
1042 f.assert_is_in_set(set);
1043
1044 info("num gates = ", builder.get_estimated_num_finalized_gates());
1045 bool result = CircuitChecker::check(builder);
1046 EXPECT_EQ(result, false);
1047 }
1048
1049 static void test_pow()
1050 {
1052
1053 std::array<uint32_t, 3> const_exponent_values{ 0, 1, engine.get_random_uint32() };
1054 std::array<field_ct, 3> witness_exponent_values{ witness_ct(&builder, 0),
1055 witness_ct(&builder, 1),
1057
1058 std::array<uint256_t, 3> base_values{ 0, 1, engine.get_random_uint256() };
1059 for (auto& base : base_values) {
1060 for (auto& exponent : const_exponent_values) {
1061 // Test constant base && integer exponent cases
1062 field_ct result = field_ct(base).pow(exponent);
1063 EXPECT_TRUE(result.is_constant());
1064 EXPECT_EQ(result.get_value(), bb::fr(base).pow(exponent));
1065 // Test witness base && integer exponent cases
1066 field_ct witness_base(witness_ct(&builder, base));
1067 result = witness_base.pow(exponent);
1068
1069 if (exponent != 0) {
1070 EXPECT_TRUE(!result.is_constant());
1071 } else {
1072 EXPECT_TRUE(result.is_constant());
1073 }
1074
1075 EXPECT_EQ(result.get_value(), bb::fr(base).pow(exponent));
1076
1077 EXPECT_TRUE(CircuitChecker::check(builder));
1078 }
1079 for (auto& exponent : witness_exponent_values) {
1080
1081 // Test constant base && witness exponent cases
1082 field_ct result = field_ct(base).pow(exponent);
1083 // Normalized witness == 1 leads to constant results in `conditional_assign(predicate, 1, 1)`
1084 EXPECT_EQ(result.is_constant(), base == 1);
1085
1086 EXPECT_EQ(result.get_value(), bb::fr(base).pow(exponent.get_value()));
1087 // Test witness base && witness exponent cases
1088 field_ct witness_base(witness_ct(&builder, base));
1089 result = witness_base.pow(exponent);
1090
1091 EXPECT_TRUE(!result.is_constant());
1092 EXPECT_EQ(result.get_value(), bb::fr(base).pow(exponent.get_value()));
1093
1094 EXPECT_TRUE(CircuitChecker::check(builder));
1095 }
1096 }
1097 }
1098
1100 {
1102
1103 fr base_val(engine.get_random_uint256());
1104 uint64_t exponent_val = engine.get_random_uint32();
1105 exponent_val += (uint64_t(1) << 32);
1106
1107 [[maybe_unused]] field_ct base = witness_ct(&builder, base_val);
1108 field_ct exponent = witness_ct(&builder, exponent_val);
1109 EXPECT_THROW_OR_ABORT(base.pow(exponent), "Assertion failed: \\(exponent_value.get_msb\\(\\) < 32\\)");
1110
1111 exponent = field_ct(exponent_val);
1112 EXPECT_THROW_OR_ABORT(base.pow(exponent), "Assertion failed: \\(exponent_value.get_msb\\(\\) < 32\\)");
1113 };
1114
1116 {
1118
1120 field_ct value_ct = witness_ct(&builder, value);
1121
1122 field_ct first_copy = witness_ct(&builder, value_ct.get_value());
1123 field_ct second_copy = field_ct::copy_as_new_witness(builder, value_ct);
1124
1125 EXPECT_EQ(value_ct.get_value(), value);
1126 EXPECT_EQ(first_copy.get_value(), value);
1127 EXPECT_EQ(second_copy.get_value(), value);
1128
1129 EXPECT_EQ(value_ct.get_witness_index() + 1, first_copy.get_witness_index());
1130 EXPECT_EQ(value_ct.get_witness_index() + 2, second_copy.get_witness_index());
1131 info("num gates = ", builder.get_estimated_num_finalized_gates());
1132
1133 bool result = CircuitChecker::check(builder);
1134 EXPECT_EQ(result, true);
1135 }
1136
1138 {
1139 // Create a constant 0, `assert_is_zero()` does nothing in-circuit in this case
1140 field_ct elt = bb::fr::zero();
1141 elt.assert_is_zero();
1142 // If we apply `assert_is_zero()` to a non-zero constant, we hit an ASSERT failure
1143 elt = bb::fr::random_element();
1144
1145 if (elt.get_value() != 0) {
1146 EXPECT_THROW_OR_ABORT(elt.assert_is_zero(), "field_t::assert_is_zero");
1147 }
1148 // Create a witness 0
1150 elt = witness_ct(&builder, bb::fr::zero());
1151 elt.assert_is_zero();
1152 // The circuit must be correct
1153 EXPECT_TRUE(CircuitChecker::check(builder));
1154
1155 // If we apply `assert_is_zero()` to a non-zero witness, an unsatisfiable `poly_gate` constraint is created
1157 if (non_zero_elt.get_value() != 0) {
1158 non_zero_elt.assert_is_zero();
1159 EXPECT_FALSE(CircuitChecker::check(builder));
1160 }
1161 }
1162
1163 static void test_accumulate()
1164 {
1165 for (size_t max_vector_length = 1; max_vector_length < 100; max_vector_length++) {
1167 std::vector<bb::fr> native_input(max_vector_length, 0);
1168 for (auto& entry : native_input) {
1169 entry = bb::fr::random_element();
1170 }
1171
1172 // Compute the native sum
1173 bb::fr native_sum = std::accumulate(native_input.begin(), native_input.end(), bb::fr::zero());
1174 std::vector<field_ct> input(max_vector_length);
1175 size_t idx = 0;
1176 // Convert native vector to a vector of field_t elements. Every 5th element is set to be constant.
1177 for (auto& native_entry : native_input) {
1178 field_ct entry = ((idx % 5) == 0) ? field_ct(native_entry) : witness_ct(&builder, native_entry);
1179 input.emplace_back(entry);
1180 idx++;
1181 }
1182 // Compute the accumulation result
1184 EXPECT_EQ(native_sum, sum.get_value());
1185
1186 // Check that the result is normalized
1187 if (!sum.is_constant()) {
1188 EXPECT_TRUE(sum.multiplicative_constant == 1 && sum.additive_constant == 0);
1189 }
1190
1191 EXPECT_TRUE(CircuitChecker::check(builder));
1192
1193 // Check that the number of gates is as expected
1194 size_t num_witnesses = max_vector_length - (max_vector_length + 4) / 5;
1195 size_t padding = (3 - (num_witnesses % 3)) % 3;
1196 size_t expected_num_gates = (num_witnesses + padding) / 3;
1197
1198 EXPECT_EQ(builder.get_estimated_num_finalized_gates() - 1, expected_num_gates);
1199
1200 // Check that the accumulation of constant entries does not create a witness
1201 std::vector<field_ct> constant_input;
1202 for (auto& entry : input) {
1203 if (entry.is_constant()) {
1204 constant_input.emplace_back(entry);
1205 }
1206 }
1207 field_ct constant_sum = field_ct::accumulate(constant_input);
1208 EXPECT_TRUE(constant_sum.is_constant());
1209 }
1210 // Test edge cases
1211 // 1. Accumulating an empty vector should lead to constant zero.
1212 std::vector<field_ct> empty_input;
1213 field_ct result(field_ct::accumulate(empty_input));
1214 EXPECT_TRUE(result.is_constant() && result.get_value() == bb::fr::zero());
1215 // 2. Check that the result of accumulating a single witness summand is correct and normalized.
1217 field_ct single_summand = witness_ct(&builder, bb::fr::random_element());
1218 single_summand += field_ct(bb::fr(3));
1219 single_summand *= field_ct(bb::fr(2));
1220 // `single_summand` isn't normalized anymore
1221 EXPECT_TRUE(single_summand.additive_constant != 0 && single_summand.multiplicative_constant != 1);
1222 std::vector<field_ct> single_element_input{ single_summand };
1223 // The accumulation result is expected to be normalized
1224 result = field_ct::accumulate(single_element_input);
1225 EXPECT_TRUE(result.get_value() == single_summand.get_value() && result.additive_constant == 0 &&
1226 result.multiplicative_constant == 1);
1227 }
1228
1229 static void test_fix_witness()
1230 {
1232
1234 witness.fix_witness();
1235 // Validate that the negated value of the witness is recorded in q_c.
1236 EXPECT_TRUE(builder.blocks.arithmetic.q_c().back() == -witness.get_value());
1237 }
1238
1240 {
1242
1243 for (size_t i = 0; i < 10; ++i) {
1244 int a_val = static_cast<int>(engine.get_random_uint8());
1245 int b_val = 0;
1246 switch (i) {
1247 case 0: {
1248 b_val = a_val;
1249 break;
1250 }
1251 case 1: {
1252 b_val = a_val + 1;
1253 break;
1254 }
1255 case 2: {
1256 b_val = a_val - 1;
1257 break;
1258 }
1259 default: {
1260 b_val = static_cast<int>(engine.get_random_uint8());
1261 break;
1262 }
1263 }
1264 if (b_val < 0) {
1265 b_val = 255;
1266 }
1267 if (b_val > 255) {
1268 b_val = 0;
1269 }
1270 field_ct a = witness_ct(&builder, static_cast<uint64_t>(a_val));
1271 field_ct b = witness_ct(&builder, static_cast<uint64_t>(b_val));
1272 a.create_range_constraint(8);
1273 b.create_range_constraint(8);
1274 bool_ct result = a.template ranged_less_than<8>(b);
1275 bool expected = a_val < b_val;
1276
1277 EXPECT_EQ(result.get_value(), expected);
1278 }
1279 bool check_result = CircuitChecker::check(builder);
1280 EXPECT_EQ(check_result, true);
1281 }
1282
1284 {
1286
1289
1290 constexpr uint256_t modulus = bb::fr::modulus;
1291 constexpr size_t max_valid_num_bits = modulus.get_msb() - 1;
1292
1293 // ---------- VALID CASE ----------
1294 {
1295 constexpr size_t num_bits = max_valid_num_bits;
1296 EXPECT_NO_THROW({
1297 auto result = a.template ranged_less_than<num_bits>(b);
1298 EXPECT_EQ(result.get_value(), true);
1299 });
1300 }
1301 }
1302
1303 static void test_add_two()
1304 {
1306 auto x_1 = bb::fr::random_element();
1307 auto x_2 = bb::fr::random_element();
1308 auto x_3 = bb::fr::random_element();
1309
1310 field_ct x_1_ct = witness_ct(&builder, x_1);
1311 field_ct x_2_ct = witness_ct(&builder, x_2);
1312 field_ct x_3_ct = witness_ct(&builder, x_3);
1313
1314 auto sum_ct = x_1_ct.add_two(x_2_ct, x_3_ct);
1315
1316 EXPECT_EQ(sum_ct.get_value(), x_1 + x_2 + x_3);
1317
1318 bool circuit_checks = CircuitChecker::check(builder);
1319 EXPECT_TRUE(circuit_checks);
1320 }
1322 {
1324 // Randomly generate a and b (a must ≤ 252 bits)
1325 uint256_t a_val =
1327 auto a = field_ct(witness_ct(&builder, a_val));
1329 EXPECT_TRUE(a.get_origin_tag().is_empty());
1330 EXPECT_TRUE(b.get_origin_tag().is_empty());
1331 const size_t parent_id = 0;
1332
1333 const auto submitted_value_origin_tag = OriginTag(parent_id, /*round_id=*/0, /*is_submitted=*/true);
1334 const auto challenge_origin_tag = OriginTag(parent_id, /*round_id=*/0, /*is_submitted=*/false);
1335 const auto next_challenge_tag = OriginTag(parent_id, /*round_id=*/1, /*submitted=*/false);
1336
1337 const auto first_two_merged_tag = OriginTag(submitted_value_origin_tag, challenge_origin_tag);
1338 const auto first_and_third_merged_tag = OriginTag(submitted_value_origin_tag, next_challenge_tag);
1339 const auto first_second_third_merged_tag = OriginTag(first_two_merged_tag, next_challenge_tag);
1340
1341 a.set_origin_tag(submitted_value_origin_tag);
1342 b.set_origin_tag(challenge_origin_tag);
1343
1344 EXPECT_EQ(a.get_origin_tag(), submitted_value_origin_tag);
1345 EXPECT_EQ(b.get_origin_tag(), challenge_origin_tag);
1346
1347 // Basic additon merges tags
1348 auto c = a + b;
1349 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
1350
1351 // Basic multiplication merges tags
1352 auto d = a * b;
1353 EXPECT_EQ(d.get_origin_tag(), first_two_merged_tag);
1354
1355 // Basic subtraction merges tags
1356 auto e = a - b;
1357 EXPECT_EQ(e.get_origin_tag(), first_two_merged_tag);
1358
1359 // Division merges tags
1360
1361 auto f = a / b;
1362 EXPECT_EQ(f.get_origin_tag(), first_two_merged_tag);
1363
1364 // Exponentiation merges tags
1365
1366 auto exponent = field_ct(witness_ct(&builder, 10));
1367 exponent.set_origin_tag(challenge_origin_tag);
1368 auto g = a.pow(exponent);
1369 EXPECT_EQ(g.get_origin_tag(), first_two_merged_tag);
1370
1371 // Madd merges tags
1373 h.set_origin_tag(next_challenge_tag);
1374 auto i = a.madd(b, h);
1375 EXPECT_EQ(i.get_origin_tag(), first_second_third_merged_tag);
1376
1377 // add_two merges tags
1378 auto j = a.add_two(b, h);
1379 EXPECT_EQ(j.get_origin_tag(), first_second_third_merged_tag);
1380
1381 // Normalize preserves tag
1382
1383 EXPECT_EQ(j.normalize().get_origin_tag(), j.get_origin_tag());
1384
1385 // is_zero preserves tag
1386
1387 EXPECT_EQ(a.is_zero().get_origin_tag(), a.get_origin_tag());
1388
1389 // equals/not equals operator merges tags
1390
1391 EXPECT_EQ((a == b).get_origin_tag(), first_two_merged_tag);
1392 EXPECT_EQ((a != b).get_origin_tag(), first_two_merged_tag);
1393
1394 // Conditionals merge tags
1395
1396 auto k = bool_ct(witness_ct(&builder, 1));
1397 k.set_origin_tag(next_challenge_tag);
1398 auto l = a.conditional_negate(k);
1399 EXPECT_EQ(l.get_origin_tag(), first_and_third_merged_tag);
1400
1401 auto m = field_ct::conditional_assign(k, a, b);
1402 EXPECT_EQ(m.get_origin_tag(), first_second_third_merged_tag);
1403
1404 // Accumulate merges tags
1405 const size_t MAX_ACCUMULATED_ELEMENTS = 16;
1406 std::vector<field_ct> elements;
1407 std::vector<OriginTag> accumulated_tags;
1408 for (size_t index = 0; index < MAX_ACCUMULATED_ELEMENTS; index++) {
1409 const auto current_tag = OriginTag(parent_id, index >> 1, !(index & 1));
1410 if (index == 0) {
1411 accumulated_tags.push_back(current_tag);
1412 } else {
1413 accumulated_tags.emplace_back(accumulated_tags[index - 1], current_tag);
1414 }
1416 element.set_origin_tag(current_tag);
1417 elements.emplace_back(element);
1418 }
1419
1420 for (size_t index = MAX_ACCUMULATED_ELEMENTS - 1; index > 0; index--) {
1421 EXPECT_EQ(field_ct::accumulate(elements).get_origin_tag(), accumulated_tags[index]);
1422 elements.pop_back();
1423 }
1424
1425 // Split preserves tags
1426 const size_t num_bits = uint256_t(a.get_value()).get_msb() + 1;
1427 auto split_data = a.split_at(num_bits / 2, num_bits);
1428 EXPECT_EQ(split_data.first.get_origin_tag(), submitted_value_origin_tag);
1429 EXPECT_EQ(split_data.second.get_origin_tag(), submitted_value_origin_tag);
1430
1431 // Conversions
1432
1433 auto o = field_ct(witness_ct(&builder, 1));
1434 o.set_origin_tag(submitted_value_origin_tag);
1435 auto p = bool_ct(o);
1436 EXPECT_EQ(p.get_origin_tag(), submitted_value_origin_tag);
1437
1438 o.set_origin_tag(challenge_origin_tag);
1439 o = field_ct(p);
1440
1441 EXPECT_EQ(o.get_origin_tag(), submitted_value_origin_tag);
1442
1444 auto poisoned_tag = challenge_origin_tag;
1445 poisoned_tag.poison();
1446 q.set_origin_tag(poisoned_tag);
1447#ifndef NDEBUG
1448 EXPECT_THROW(q + q, std::runtime_error);
1449#endif
1450 }
1451
1453 {
1455
1456 Builder builder1;
1457 Builder builder2;
1458
1459 auto null = static_cast<Builder*>(nullptr);
1460
1461 // Case 1: All nullptr
1462 {
1463 Builder* result = validate_context(null, null, null);
1464 EXPECT_EQ(result, nullptr);
1465 }
1466
1467 // Case 2: One non-nullptr
1468 {
1469 Builder* result = validate_context(&builder1);
1470 EXPECT_EQ(result, &builder1);
1471 }
1472
1473 // Case 3: Leading nullptrs
1474 {
1475 Builder* result = validate_context(null, null, &builder1);
1476 EXPECT_EQ(result, &builder1);
1477 }
1478
1479 // Case 4: One non-null followed by nullptrs
1480 {
1481 Builder* result = validate_context(&builder1, null, null);
1482 EXPECT_EQ(result, &builder1);
1483 }
1484
1485 // Case 5: All same non-nullptr
1486 {
1487 Builder* result = validate_context(&builder1, &builder1, &builder1);
1488 EXPECT_EQ(result, &builder1);
1489 }
1490
1491 // Case 6: Conflict between two different non-nullptrs
1492 {
1493 EXPECT_THROW_OR_ABORT(validate_context(&builder1, &builder2),
1494 "Pointers refer to different builder objects!");
1495 }
1496
1497 // Case 7: Conflict between first and last non-null
1498 {
1499 EXPECT_THROW_OR_ABORT(validate_context(&builder1, null, null, &builder2),
1500 "Pointers refer to different builder objects!");
1501 }
1502
1503 // Case 8: First null, two same non-null later
1504 {
1505 Builder* result = validate_context(null, &builder1, &builder1);
1506 EXPECT_EQ(result, &builder1);
1507 }
1508
1509 // Case 9: Interleaved nulls and same pointer
1510 {
1511 Builder* result = validate_context(&builder1, null, &builder1, null);
1512 EXPECT_EQ(result, &builder1);
1513 }
1514 }
1515
1517 {
1518 // Case 1: Empty container returns nullptr
1519 {
1521 Builder* ctx = validate_context<Builder>(empty);
1522 EXPECT_EQ(ctx, nullptr);
1523 }
1524
1525 // Case 2: Same context
1526 {
1528 std::vector<field_ct> fields = {
1529 field_ct(&builder, 1),
1530 field_ct(&builder, 2),
1531 field_ct(&builder, 3),
1532 };
1533 Builder* ctx = validate_context<Builder>(fields);
1534 EXPECT_EQ(ctx, &builder);
1535 }
1536
1537 // Case 3: Some nullptr contexts
1538 {
1540 field_ct null_field; // context is nullptr
1541 field_ct a(&builder, 1);
1542 field_ct b(&builder, 2);
1543 std::vector<field_ct> fields = { null_field, a, b };
1544 Builder* ctx = validate_context<Builder>(fields);
1545 EXPECT_EQ(ctx, &builder);
1546 }
1547
1548 // Case 4: Mismatched contexts should throw/abort
1549 {
1550 Builder builder1;
1551 Builder builder2;
1552 std::vector<field_ct> fields = {
1553 field_ct(&builder1, 1),
1554 field_ct(&builder1, 1),
1555 field_ct(1),
1556 field_ct(&builder2, 2),
1557 };
1558
1559 EXPECT_THROW_OR_ABORT(validate_context<Builder>(fields), "Pointers refer to different builder objects!");
1560 }
1561 }
1562};
1563using CircuitTypes = testing::Types<bb::UltraCircuitBuilder>;
1564
1566
1567TYPED_TEST(stdlib_field, test_accumulate)
1568{
1569 TestFixture::test_accumulate();
1570}
1572{
1573 TestFixture::test_add();
1574}
1575TYPED_TEST(stdlib_field, test_add_mul_with_constants)
1576{
1577 TestFixture::test_add_mul_with_constants();
1578}
1580{
1581 TestFixture::test_add_two();
1582}
1583TYPED_TEST(stdlib_field, test_assert_equal)
1584{
1585 TestFixture::test_assert_equal();
1586}
1587TYPED_TEST(stdlib_field, test_assert_equal_gate_count)
1588{
1589 TestFixture::test_assert_equal_with_gate_count();
1590}
1591TYPED_TEST(stdlib_field, test_assert_is_in_set)
1592{
1593 TestFixture::test_assert_is_in_set();
1594}
1595TYPED_TEST(stdlib_field, test_assert_is_in_set_fails)
1596{
1597 TestFixture::test_assert_is_in_set_fails();
1598}
1599TYPED_TEST(stdlib_field, test_assert_is_zero)
1600{
1601 TestFixture::test_assert_is_zero();
1602}
1603TYPED_TEST(stdlib_field, test_assert_is_not_zero)
1604{
1605 TestFixture::test_assert_is_not_zero();
1606}
1607TYPED_TEST(stdlib_field, test_bool_conversion)
1608{
1609 TestFixture::test_bool_conversion();
1610}
1611TYPED_TEST(stdlib_field, test_bool_conversion_regression)
1612{
1613 TestFixture::test_bool_conversion_regression();
1614}
1615TYPED_TEST(stdlib_field, test_conditional_assign)
1616{
1617 TestFixture::test_conditional_assign();
1618}
1619TYPED_TEST(stdlib_field, test_conditional_assign_regression)
1620{
1621 TestFixture::test_conditional_assign_regression();
1622}
1623TYPED_TEST(stdlib_field, test_conditional_negate)
1624{
1625 TestFixture::test_conditional_negate();
1626}
1627TYPED_TEST(stdlib_field, test_constructor_from_witness)
1628{
1629 TestFixture::test_constructor_from_witness();
1630}
1631TYPED_TEST(stdlib_field, test_copy_as_new_witness)
1632{
1633 TestFixture::test_copy_as_new_witness();
1634}
1635TYPED_TEST(stdlib_field, test_create_range_constraint)
1636{
1637 TestFixture::create_range_constraint();
1638}
1640{
1641 TestFixture::test_div();
1642}
1643TYPED_TEST(stdlib_field, test_div_edge_cases)
1644{
1645 TestFixture::test_div_edge_cases();
1646}
1648{
1649 TestFixture::test_equality();
1650}
1651TYPED_TEST(stdlib_field, test_equality_false)
1652{
1653 TestFixture::test_equality_false();
1654}
1655TYPED_TEST(stdlib_field, test_equality_with_constants)
1656{
1657 TestFixture::test_equality_with_constants();
1658}
1659TYPED_TEST(stdlib_field, test_field_fibbonaci)
1660{
1661 TestFixture::test_field_fibbonaci();
1662}
1663TYPED_TEST(stdlib_field, test_field_pythagorean)
1664{
1665 TestFixture::test_field_pythagorean();
1666}
1667TYPED_TEST(stdlib_field, test_fix_witness)
1668{
1669 TestFixture::test_fix_witness();
1670}
1672{
1673 TestFixture::test_invert();
1674}
1675TYPED_TEST(stdlib_field, test_invert_zero)
1676{
1677 TestFixture::test_invert_zero();
1678}
1680{
1681 TestFixture::test_is_zero();
1682}
1683TYPED_TEST(stdlib_field, test_larger_circuit)
1684{
1685 TestFixture::test_larger_circuit();
1686}
1688{
1689 TestFixture::test_madd();
1690}
1691TYPED_TEST(stdlib_field, test_madd_add_two_gate_count)
1692{
1693 TestFixture::test_madd_add_two_gate_count();
1694}
1695TYPED_TEST(stdlib_field, test_multiplicative_constant_regression)
1696{
1697 TestFixture::test_multiplicative_constant_regression();
1698}
1699TYPED_TEST(stdlib_field, test_origin_tag_consistency)
1700{
1701 TestFixture::test_origin_tag_consistency();
1702}
1703TYPED_TEST(stdlib_field, test_postfix_increment)
1704{
1705 TestFixture::test_postfix_increment();
1706}
1708{
1709 TestFixture::test_pow();
1710}
1711TYPED_TEST(stdlib_field, test_pow_exponent_out_of_range)
1712{
1713 TestFixture::test_pow_exponent_out_of_range();
1714}
1715TYPED_TEST(stdlib_field, test_prefix_increment)
1716{
1717 TestFixture::test_prefix_increment();
1718}
1719TYPED_TEST(stdlib_field, test_ranged_less_than)
1720{
1721 TestFixture::test_ranged_less_than();
1722}
1723TYPED_TEST(stdlib_field, test_ranged_less_than_max_num_bits)
1724{
1725 TestFixture::test_ranged_less_than_max_num_bits();
1726}
1728{
1729 TestFixture::test_split_at();
1730}
1731TYPED_TEST(stdlib_field, test_three_bit_table)
1732{
1733 TestFixture::test_three_bit_table();
1734}
1735TYPED_TEST(stdlib_field, test_two_bit_table)
1736{
1737 TestFixture::test_two_bit_table();
1738}
1739TYPED_TEST(stdlib_field, test_validate_context)
1740{
1741 TestFixture::test_validate_context();
1742}
1743TYPED_TEST(stdlib_field, test_validate_container_context)
1744{
1745 TestFixture::test_validate_container_context();
1746}
#define EXPECT_THROW_OR_ABORT(statement, matcher)
Definition assert.hpp:150
size_t get_estimated_num_finalized_gates() const
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
virtual uint8_t get_random_uint8()=0
virtual uint32_t get_random_uint32()=0
virtual uint256_t get_random_uint256()=0
constexpr uint64_t get_msb() const
Implements boolean logic in-circuit.
Definition bool.hpp:59
bool get_value() const
Definition bool.hpp:109
bool is_constant() const
Definition bool.hpp:111
bool_t normalize() const
A bool_t element is normalized if witness_inverted == false. For a given *this, output its normalized...
Definition bool.cpp:478
uint32_t witness_index
Definition bool.hpp:133
void assert_is_zero(std::string const &msg="field_t::assert_is_zero") const
Enforce a copy constraint between *this and 0 stored at zero_idx of the Builder.
Definition field.cpp:676
field_t conditional_negate(const bool_t< Builder > &predicate) const
If predicate's value == true, negate the value, else keep it unchanged.
Definition field.cpp:858
void assert_is_in_set(const std::vector< field_t > &set, std::string const &msg="field_t::assert_not_in_set") const
Constrain *this \in set by enforcing that P(X) = \prod_{s \in set} (X - s) is 0 at X = *this.
Definition field.cpp:974
uint32_t set_public() const
Definition field.hpp:404
void assert_equal(const field_t &rhs, std::string const &msg="field_t::assert_equal") const
Copy constraint: constrain that *this field is equal to rhs element.
Definition field.cpp:929
field_t madd(const field_t &to_mul, const field_t &to_add) const
Definition field.cpp:507
bb::fr additive_constant
Definition field.hpp:88
static field_t select_from_three_bit_table(const std::array< field_t, 8 > &table, const bool_t< Builder > &t2, const bool_t< Builder > &t1, const bool_t< Builder > &t0)
Given a multilinear polynomial in 3 variables, which is represented by a table of monomial coefficien...
Definition field.cpp:1058
static field_t accumulate(const std::vector< field_t > &input)
Efficiently compute the sum of vector entries. Using big_add_gate we reduce the number of gates neede...
Definition field.cpp:1147
field_t invert() const
Definition field.hpp:304
static field_t conditional_assign(const bool_t< Builder > &predicate, const field_t &lhs, const field_t &rhs)
If predicate == true then return lhs, else return rhs.
Definition field.cpp:884
static std::array< field_t, 8 > preprocess_three_bit_table(const field_t &T0, const field_t &T1, const field_t &T2, const field_t &T3, const field_t &T4, const field_t &T5, const field_t &T6, const field_t &T7)
Given a table T of size 8, outputs the monomial coefficients of the multilinear polynomial in t0,...
Definition field.cpp:1010
bb::fr multiplicative_constant
Definition field.hpp:89
static field_t copy_as_new_witness(Builder &context, field_t const &other)
Definition field.hpp:241
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:827
field_t normalize() const
Return a new element, where the in-circuit witness contains the actual represented value (multiplicat...
Definition field.cpp:635
static field_t select_from_two_bit_table(const std::array< field_t, 4 > &table, const bool_t< Builder > &t1, const bool_t< Builder > &t0)
Given a multilinear polynomial in 2 variables, which is represented by a table of monomial coefficien...
Definition field.cpp:1036
static field_t from_witness(Builder *ctx, const bb::fr &input)
Definition field.hpp:424
bool_t< Builder > is_zero() const
Validate whether a field_t element is zero.
Definition field.cpp:774
field_t pow(const uint32_t &exponent) const
Raise this field element to the power of the provided uint32_t exponent.
Definition field.cpp:419
bool is_constant() const
Definition field.hpp:399
static std::array< field_t, 4 > preprocess_two_bit_table(const field_t &T0, const field_t &T1, const field_t &T2, const field_t &T3)
Given a table T of size 4, outputs the monomial coefficients of the multilinear polynomial in t0,...
Definition field.cpp:992
uint32_t witness_index
Definition field.hpp:132
field_t add_two(const field_t &add_b, const field_t &add_c) const
Efficiently compute (this + a + b) using big_mul gate.
Definition field.cpp:572
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:461
static void test_bool_conversion()
static void test_conditional_assign_regression()
Test that conditional assign doesn't produce a new witness if lhs and rhs are constant.
void test_validate_container_context()
static void test_fix_witness()
static void test_div()
static void test_assert_is_zero()
static void test_conditional_assign()
static uint64_t fidget(Builder &builder)
static void test_div_edge_cases()
static void create_range_constraint()
static void test_prefix_increment()
static void test_equality()
static void test_invert()
stdlib::public_witness_t< Builder > public_witness_ct
static void test_split_at()
static void test_equality_false()
static void build_test_circuit(Builder &builder, size_t num_gates)
static void test_ranged_less_than_max_num_bits()
static void test_larger_circuit()
static void test_accumulate()
static void test_field_fibbonaci()
void test_validate_context()
static void test_copy_as_new_witness()
static void test_is_zero()
stdlib::witness_t< Builder > witness_ct
static void test_assert_equal()
Demonstrate current behavior of assert_equal.
stdlib::bool_t< Builder > bool_ct
static void test_invert_zero()
void test_assert_equal_with_gate_count()
static void test_constructor_from_witness()
static void test_assert_is_in_set()
static void test_pow()
static void test_conditional_negate()
static void test_origin_tag_consistency()
static void test_add()
static void test_add_two()
static void test_add_mul_with_constants()
static void test_multiplicative_constant_regression()
Test that multiplicative_constant of constants is no longer affected by any arithimetic operation.
static void test_assert_is_in_set_fails()
static void test_equality_with_constants()
static void test_three_bit_table()
static void test_madd()
static void test_two_bit_table()
static void test_field_pythagorean()
static void test_ranged_less_than()
static void test_postfix_increment()
static void test_assert_is_not_zero()
static void test_bool_conversion_regression()
Test that bool is converted correctly.
stdlib::field_t< Builder > field_ct
static void test_madd_add_two_gate_count()
static void test_pow_exponent_out_of_range()
void info(Args... args)
Definition log.hpp:70
AluTraceBuilder builder
Definition alu.test.cpp:123
FF a
FF b
bool expected_result
ECCVMCircuitBuilder Builder
numeric::RNG & engine
void ignore_unused(T &)
constexpr size_t MAX_NO_WRAP_INTEGER_BIT_LENGTH
Definition grumpkin.hpp:15
constexpr T get_msb(const T in)
Definition get_msb.hpp:47
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
T * validate_context(T *ptr)
Definition field.hpp:16
Entry point for Barretenberg command-line interface.
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
field< Bn254FrParams > fr
Definition fr.hpp:174
Inner sum(Cont< Inner, Args... > const &in)
Definition container.hpp:70
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
testing::Types< bb::UltraCircuitBuilder > CircuitTypes
static constexpr field neg_one()
static constexpr field one()
static constexpr uint256_t modulus
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr field zero()