Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bigfield.test.cpp
Go to the documentation of this file.
3
6
7#include "../bool/bool.hpp"
8#include "../byte_array/byte_array.hpp"
9#include "../field/field.hpp"
10#include "./bigfield.hpp"
18#include <gtest/gtest.h>
19#include <memory>
20#include <utility>
21
22using namespace bb;
23
24namespace {
26}
27
28enum struct InputType {
29 WITNESS,
31};
32
37
38// Helper to extract Builder and Params from bigfield<Builder, Params>
39template <typename T> struct extract_builder;
40template <typename T> struct extract_fq_params;
41
42template <template <typename, typename> class BigField, typename Builder, typename Params>
43struct extract_builder<BigField<Builder, Params>> {
44 using type = Builder;
45};
46
47template <template <typename, typename> class BigField, typename Builder, typename Params>
48struct extract_fq_params<BigField<Builder, Params>> {
49 using type = Params;
50};
51
52template <typename BigField> using builder_t = typename extract_builder<BigField>::type;
53template <typename BigField> using params_t = typename extract_fq_params<BigField>::type;
54
56template <typename BigField> class stdlib_bigfield : public testing::Test {
57
58 using Builder = builder_t<BigField>; // extract builder from BigField
59 using fr_ct = typename bb::stdlib::bn254<Builder>::ScalarField; // native circuit field
60 using fq_native = bb::field<params_t<BigField>>; // native bigfield type
61 using fq_ct = BigField; // non-native field (circuit type)
62 using witness_ct = stdlib::witness_t<Builder>; // circuit witness type
63 using bool_ct = stdlib::bool_t<Builder>; // circuit boolean type
64 using byte_array_ct = stdlib::byte_array<Builder>; // circuit byte array type
65
66 public:
68 {
69 auto builder = Builder();
70 fq_ct constant = fq_ct(1);
71 fq_ct var = fq_ct::create_from_u512_as_witness(&builder, 1);
72 fr_ct small_var = witness_ct(&builder, fr(1));
73 fq_ct mixed = fq_ct(1).add_to_lower_limb(small_var, 1);
74 fq_ct r;
75
76 r = mixed + mixed;
77 r = mixed - mixed;
78 r = mixed + var;
79 r = mixed + constant;
80 r = mixed - var;
81 r = mixed - constant;
82 r = var - mixed;
83
84 r = var * constant;
85 r = constant / var;
86 r = constant * constant;
87 r = constant / constant;
88
89 r = mixed * var;
90 r = mixed / var;
91 r = mixed * mixed;
92 r = mixed * constant;
93 bool result = CircuitChecker::check(builder);
94 EXPECT_EQ(result, true);
95 }
96
97 // The bug happens when we are applying the CRT formula to a*b < r, which can happen when using the division
98 // operator
100 {
101 auto builder = Builder();
102 uint256_t value(2);
103 fq_ct tval = fq_ct::create_from_u512_as_witness(&builder, value);
104 fq_ct tval1 = tval - tval;
105 fq_ct tval2 = tval1 / tval;
106 (void)tval2;
107 bool result = CircuitChecker::check(builder);
108 EXPECT_EQ(result, true);
109 }
110
111 static void test_bad_mul()
112 {
113 auto builder = Builder();
114 uint256_t value(2);
115 fq_ct tval = fq_ct::create_from_u512_as_witness(&builder, value);
116 fq_ct tval1 = tval - tval;
117 fq_ct tval2 = tval1 / tval;
118 (void)tval2;
119 bool result = CircuitChecker::check(builder);
120 EXPECT_EQ(result, true);
121 }
122
123 // Gets a random bigfield element that is a circuit-witness
125 {
127 if (reduce_input) {
128 elt_native = elt_native.reduce_once().reduce_once();
129 }
130 fr elt_native_lo = fr(uint256_t(elt_native).slice(0, fq_ct::NUM_LIMB_BITS * 2));
131 fr elt_native_hi = fr(uint256_t(elt_native).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4));
132 fq_ct elt_ct(witness_ct(builder, elt_native_lo), witness_ct(builder, elt_native_hi));
133 // UNset free witness tag so we don't have to unset it in every test
134 elt_ct.unset_free_witness_tag();
135 return std::make_pair(elt_native, elt_ct);
136 }
137
138 // Gets a random bigfield element that is a circuit-constant
140 {
142 if (reduce_input) {
143 elt_native = elt_native.reduce_once().reduce_once();
144 }
145 fq_ct elt_ct(builder, uint256_t(elt_native));
146 return std::make_pair(elt_native, elt_ct);
147 }
148
149 // Gets a random bigfield element that may be either circuit-witness or cirucit-constant
151 {
152 return (engine.get_random_uint8() & 1) == 1 ? get_random_witness(builder, reduce_input)
153 : get_random_constant(builder, reduce_input);
154 }
155
157 {
158 if (type == InputType::WITNESS) {
159 return get_random_witness(builder, reduce_input);
160 }
161 return get_random_constant(builder, reduce_input);
162 }
163
165 size_t num,
166 bool reduce_input = false)
167 {
168 std::vector<fq_native> elts(num);
169 std::vector<fq_ct> big_elts(num);
170 for (size_t i = 0; i < num; ++i) {
171 auto [elt, big_elt] = get_random_witness(builder, reduce_input);
172 elts[i] = elt;
173 big_elts[i] = big_elt;
174 }
175 return std::make_pair(elts, big_elts);
176 }
177
179 size_t num,
180 bool reduce_input = false)
181 {
182 std::vector<fq_native> elts(num);
183 std::vector<fq_ct> big_elts(num);
184 for (size_t i = 0; i < num; ++i) {
185 auto [elt, big_elt] = get_random_constant(builder, reduce_input);
186 elts[i] = elt;
187 big_elts[i] = big_elt;
188 }
189 return std::make_pair(elts, big_elts);
190 }
191
194 size_t num,
195 bool reduce_input = false)
196 {
197 std::vector<fq_native> elts(num);
198 std::vector<fq_ct> big_elts(num);
199 for (size_t i = 0; i < num; ++i) {
200 auto [elt, big_elt] = get_random_element(builder, type, reduce_input);
201 elts[i] = elt;
202 big_elts[i] = big_elt;
203 }
204 return std::make_pair(elts, big_elts);
205 }
206
208 {
209 auto builder = Builder();
210 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
211
212 a_ct.binary_basis_limbs[0].element.set_origin_tag(submitted_value_origin_tag);
213 a_ct.binary_basis_limbs[1].element.set_origin_tag(challenge_origin_tag);
214 a_ct.prime_basis_limb.set_origin_tag(next_challenge_tag);
215
216 EXPECT_EQ(a_ct.get_origin_tag(), first_second_third_merged_tag);
217
218 a_ct.set_origin_tag(clear_tag);
219 EXPECT_EQ(a_ct.binary_basis_limbs[0].element.get_origin_tag(), clear_tag);
220 EXPECT_EQ(a_ct.binary_basis_limbs[1].element.get_origin_tag(), clear_tag);
221 EXPECT_EQ(a_ct.binary_basis_limbs[2].element.get_origin_tag(), clear_tag);
222 EXPECT_EQ(a_ct.binary_basis_limbs[3].element.get_origin_tag(), clear_tag);
223 EXPECT_EQ(a_ct.prime_basis_limb.get_origin_tag(), clear_tag);
224
225#ifndef NDEBUG
226 a_ct.set_origin_tag(instant_death_tag);
227 EXPECT_THROW(a_ct + a_ct, std::runtime_error);
228#endif
229 }
230
232 {
233 auto builder = Builder();
234 {
235 fr elt_native_lo = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS * 2)); // 136 bits
236 fr elt_native_hi = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS * 2)); // 136 bits
237 fq_ct elt_witness_ct =
238 fq_ct(witness_ct(&builder, elt_native_lo), witness_ct(&builder, elt_native_hi), true);
239 fq_ct elt_constant_ct = fq_ct(fr_ct(&builder, elt_native_lo), fr_ct(&builder, elt_native_hi), true);
240 }
241 {
242 fr elt_native_lo = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS * 2)); // 136 bits
243 fr elt_native_hi = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS * 2 - 3)); // 133 bits
244 fq_ct elt_witness_ct = fq_ct(witness_ct(&builder, elt_native_lo),
245 witness_ct(&builder, elt_native_hi),
246 false, // can_overflow must be false as max_bitlength is provided
247 4 * fq_ct::NUM_LIMB_BITS - 3);
248 fq_ct elt_constant_ct = fq_ct(fr_ct(&builder, elt_native_lo),
249 fr_ct(&builder, elt_native_hi),
250 false, // can_overflow must be false as max_bitlength is provided
251 4 * fq_ct::NUM_LIMB_BITS - 3);
252 }
253 bool result = CircuitChecker::check(builder);
254 EXPECT_EQ(result, true);
255 }
256
258 {
259 auto builder = Builder();
260 fr limb_1_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS + 10)); // 78 bits
261 fr limb_2_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS + 10)); // 78 bits
262 fr limb_3_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS + 10)); // 78 bits
263 fr limb_4_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS + 12)); // 80 bits
264
265 fr_ct limb_1_ct = fr_ct(witness_ct(&builder, limb_1_native));
266 fr_ct limb_2_ct = fr_ct(witness_ct(&builder, limb_2_native));
267 fr_ct limb_3_ct = fr_ct(witness_ct(&builder, limb_3_native));
268 fr_ct limb_4_ct = fr_ct(witness_ct(&builder, limb_4_native));
269
270 // This does not add any range constraints on the limbs, so virtually any limb values are valid.
271 // It does however correctly compute the prime basis limb (from the supplied limbs).
272 fq_ct result = fq_ct::unsafe_construct_from_limbs(limb_1_ct, limb_2_ct, limb_3_ct, limb_4_ct);
273
274 fr expected_prime_limb = limb_1_native;
275 expected_prime_limb += (limb_2_native * fq_ct::shift_1);
276 expected_prime_limb += (limb_3_native * fq_ct::shift_2);
277 expected_prime_limb += (limb_4_native * fq_ct::shift_3);
278 EXPECT_EQ(expected_prime_limb, result.prime_basis_limb.get_value());
279
280 // The other constructor takes in the prime limb as well (without any checks).
281 fq_ct result_1 = fq_ct::unsafe_construct_from_limbs(
282 limb_1_ct, limb_2_ct, limb_3_ct, limb_4_ct, witness_ct(&builder, fr::random_element()));
283 EXPECT_EQ(result.binary_basis_limbs[0].element.get_value(), result_1.binary_basis_limbs[0].element.get_value());
284
285 bool result_check = CircuitChecker::check(builder);
286 EXPECT_EQ(result_check, true);
287 }
288
290 {
291 auto builder = Builder();
292 fr limb_1_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS)); // 68 bits
293 fr limb_2_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS)); // 68 bits
294 fr limb_3_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS)); // 68 bits
295 fr limb_4_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LAST_LIMB_BITS)); // |p|-3*68 bits
296
297 fr_ct limb_1_ct = fr_ct(witness_ct(&builder, limb_1_native));
298 fr_ct limb_2_ct = fr_ct(witness_ct(&builder, limb_2_native));
299 fr_ct limb_3_ct = fr_ct(witness_ct(&builder, limb_3_native));
300 fr_ct limb_4_ct = fr_ct(witness_ct(&builder, limb_4_native));
301
302 // This does add range constraints on the limbs, so the limbs must be in range.
303 // It also correctly computes the prime basis limb (from the supplied limbs).
304 fq_ct result = fq_ct::construct_from_limbs(limb_1_ct, limb_2_ct, limb_3_ct, limb_4_ct);
305
306 fr expected_prime_limb = limb_1_native;
307 expected_prime_limb += (limb_2_native * fq_ct::shift_1);
308 expected_prime_limb += (limb_3_native * fq_ct::shift_2);
309 expected_prime_limb += (limb_4_native * fq_ct::shift_3);
310 EXPECT_EQ(expected_prime_limb, result.prime_basis_limb.get_value());
311
312 // All four limbs as 68-bit range constrained (fourth limb is set equal to limb_3)
313 fq_ct result_1 = fq_ct::construct_from_limbs(limb_1_ct, limb_2_ct, limb_3_ct, limb_3_ct, /*can_overflow=*/true);
314 EXPECT_EQ(result.binary_basis_limbs[0].element.get_value(), result_1.binary_basis_limbs[0].element.get_value());
315
316 bool result_check = CircuitChecker::check(builder);
317 EXPECT_EQ(result_check, true);
318 }
319
321 {
322 auto builder = Builder();
323 fr limb_1_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS)); // 68 bits
324 fr limb_2_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS)); // 68 bits
325 fr limb_3_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LIMB_BITS)); // 68 bits
326 fr limb_4_native = fr(uint256_t(fr::random_element()).slice(0, fq_ct::NUM_LAST_LIMB_BITS)); // |p|-3*68 bits
327
328 // Make limb_1 out of range
329 limb_1_native = uint256_t(limb_1_native) + (uint256_t(1) << fq_ct::NUM_LIMB_BITS);
330
331 fr_ct limb_1_ct = fr_ct(witness_ct(&builder, limb_1_native));
332 fr_ct limb_2_ct = fr_ct(witness_ct(&builder, limb_2_native));
333 fr_ct limb_3_ct = fr_ct(witness_ct(&builder, limb_3_native));
334 fr_ct limb_4_ct = fr_ct(witness_ct(&builder, limb_4_native));
335
336 // This will fail because limb_1 is out of range
337 fq_ct result = fq_ct::construct_from_limbs(limb_1_ct, limb_2_ct, limb_3_ct, limb_4_ct);
338 fr expected_prime_limb = limb_1_native;
339 expected_prime_limb += (limb_2_native * fq_ct::shift_1);
340 expected_prime_limb += (limb_3_native * fq_ct::shift_2);
341 expected_prime_limb += (limb_4_native * fq_ct::shift_3);
342 EXPECT_EQ(expected_prime_limb, result.prime_basis_limb.get_value());
343
344 bool result_check = CircuitChecker::check(builder);
345 EXPECT_EQ(result_check, false);
346 EXPECT_EQ(builder.err(), "bigfield::construct_from_limbs: limb 0 or 1 too large: lo limb.");
347 }
348
349 static void test_add_two(InputType a_type, InputType b_type, InputType c_type)
350 {
351 auto builder = Builder();
352 size_t num_repetitions = 10;
353 for (size_t i = 0; i < num_repetitions; ++i) {
354 auto [a_native, a_ct] = get_random_element(&builder, a_type); // fq, fq_ct
355 auto [b_native, b_ct] = get_random_element(&builder, b_type); // fq, fq_ct
356 auto [c_native, c_ct] = get_random_element(&builder, c_type); // fq, fq_ct
357
358 a_ct.set_origin_tag(submitted_value_origin_tag);
359 b_ct.set_origin_tag(challenge_origin_tag);
360
361 fq_ct d_ct;
362 if (i == num_repetitions - 1) {
364 d_ct = a_ct.add_two(b_ct, c_ct);
365 BENCH_GATE_COUNT_END(builder, "ADD_TWO");
366 } else {
367 d_ct = a_ct.add_two(b_ct, c_ct);
368 }
369 d_ct.self_reduce();
370
371 // Addition merges tags
372 EXPECT_EQ(d_ct.get_origin_tag(), first_two_merged_tag);
373
374 fq_native expected = (a_native + b_native + c_native).reduce_once().reduce_once();
375 expected = expected.from_montgomery_form();
376 uint512_t result = d_ct.get_value();
377
378 EXPECT_EQ(result.lo.data[0], expected.data[0]);
379 EXPECT_EQ(result.lo.data[1], expected.data[1]);
380 EXPECT_EQ(result.lo.data[2], expected.data[2]);
381 EXPECT_EQ(result.lo.data[3], expected.data[3]);
382 EXPECT_EQ(result.hi.data[0], 0ULL);
383 EXPECT_EQ(result.hi.data[1], 0ULL);
384 EXPECT_EQ(result.hi.data[2], 0ULL);
385 EXPECT_EQ(result.hi.data[3], 0ULL);
386 }
387 bool result = CircuitChecker::check(builder);
388 EXPECT_EQ(result, true);
389 }
390
391 static void test_sum(InputType a_type, bool mixed_inputs = false)
392 {
393 auto builder = Builder();
394 std::vector<size_t> num_elements_to_sum = { 1, 2, 10, 20 };
395
396 for (size_t num_elements : num_elements_to_sum) {
397 auto [a_native, a_ct] = get_random_elements(&builder, a_type, num_elements); // fq, fq_ct
398 auto [b_native, b_ct] = get_random_elements(&builder, !a_type, num_elements); // fq, fq_ct
399
400 std::vector<fq_ct> to_sum;
401 for (size_t j = 0; j < num_elements; ++j) {
402 to_sum.push_back(a_ct[j]);
403 to_sum.back().set_origin_tag(submitted_value_origin_tag);
404
405 if (mixed_inputs) {
406 to_sum.push_back(b_ct[j]);
407 to_sum.back().set_origin_tag(challenge_origin_tag);
408 }
409 }
410
411 fq_ct c_ct;
412 if (num_elements == 20) {
414 c_ct = fq_ct::sum(to_sum);
416 } else {
417 c_ct = fq_ct::sum(to_sum);
418 }
419
420 // Need to self-reduce as we are summing potentially many elements
421 c_ct.self_reduce();
422
423 // Sum merges tags
424 const auto output_tag = (mixed_inputs) ? first_two_merged_tag : submitted_value_origin_tag;
425 EXPECT_EQ(c_ct.get_origin_tag(), output_tag);
426
427 fq_native expected = fq_native::zero();
428 for (size_t j = 0; j < num_elements; ++j) {
429 expected += a_native[j];
430
431 if (mixed_inputs) {
432 expected += b_native[j];
433 }
434 }
435 expected = expected.from_montgomery_form();
436 uint512_t result = c_ct.get_value();
437
438 EXPECT_EQ(result.lo.data[0], expected.data[0]);
439 EXPECT_EQ(result.lo.data[1], expected.data[1]);
440 EXPECT_EQ(result.lo.data[2], expected.data[2]);
441 EXPECT_EQ(result.lo.data[3], expected.data[3]);
442 EXPECT_EQ(result.hi.data[0], 0ULL);
443 EXPECT_EQ(result.hi.data[1], 0ULL);
444 EXPECT_EQ(result.hi.data[2], 0ULL);
445 EXPECT_EQ(result.hi.data[3], 0ULL);
446 }
447
448 bool result = CircuitChecker::check(builder);
449 EXPECT_EQ(result, true);
450 }
451
452 // Generic binary operator test function
453 template <typename CircuitOpFunc, typename NativeOpFunc>
455 InputType b_type,
456 CircuitOpFunc circuit_op,
457 NativeOpFunc native_op,
458 const char* op_name,
459 size_t num_repetitions = 10,
460 bool need_reduced_inputs = false,
461 bool need_reduction_after = false,
462 bool do_tags_merge = true)
463 {
464 auto builder = Builder();
465 for (size_t i = 0; i < num_repetitions; ++i) {
466 auto [a_native, a_ct] = get_random_element(&builder, a_type, need_reduced_inputs); // fq_native, fq_ct
467 auto [b_native, b_ct] = get_random_element(&builder, b_type, need_reduced_inputs); // fq_native, fq_ct
468 a_ct.set_origin_tag(submitted_value_origin_tag);
469 b_ct.set_origin_tag(challenge_origin_tag);
470
471 fq_ct c_ct;
472 if (i == num_repetitions - 1) {
473 std::string bench_name = std::string(op_name);
474 BENCH_GATE_COUNT_START(builder, bench_name.c_str());
475 c_ct = circuit_op(a_ct, b_ct);
476 BENCH_GATE_COUNT_END(builder, bench_name.c_str());
477 } else {
478 c_ct = circuit_op(a_ct, b_ct);
479 }
480
481 // Some operations (add, sub, div) may need a self-reduction to get back into the field range
482 if (need_reduction_after) {
483 c_ct.self_reduce();
484 }
485
486 if (do_tags_merge) {
487 // Binary operations merge tags
488 EXPECT_EQ(c_ct.get_origin_tag(), first_two_merged_tag);
489 }
490
491 fq_native expected = native_op(a_native, b_native);
492 if (need_reduction_after) {
493 expected = expected.reduce_once().reduce_once();
494 }
495 expected = expected.from_montgomery_form();
496 uint512_t result = c_ct.get_value();
497
498 EXPECT_EQ(result.lo.data[0], expected.data[0]);
499 EXPECT_EQ(result.lo.data[1], expected.data[1]);
500 EXPECT_EQ(result.lo.data[2], expected.data[2]);
501 EXPECT_EQ(result.lo.data[3], expected.data[3]);
502 EXPECT_EQ(result.hi.data[0], 0ULL);
503 EXPECT_EQ(result.hi.data[1], 0ULL);
504 EXPECT_EQ(result.hi.data[2], 0ULL);
505 EXPECT_EQ(result.hi.data[3], 0ULL);
506 }
507 bool result = CircuitChecker::check(builder);
508 EXPECT_EQ(result, true);
509 }
510
511#define BINARY_OP_TEST(op_name, bench_name, op_symbol, repetitions, reduced_inputs, reduction_after) \
512 static void test_##op_name(InputType a_type, InputType b_type) \
513 { \
514 test_binary_operator_generic( \
515 a_type, \
516 b_type, \
517 [](const fq_ct& a, const fq_ct& b) { return a op_symbol b; }, \
518 [](const fq_native& a, const fq_native& b) { return a op_symbol b; }, \
519 #bench_name, \
520 repetitions, \
521 reduced_inputs, \
522 reduction_after); \
523 }
524
525 BINARY_OP_TEST(mul, MUL, *, 10, false, false)
526 BINARY_OP_TEST(add, ADD, +, 10, false, true)
527 BINARY_OP_TEST(sub, SUB, -, 10, false, true)
528 BINARY_OP_TEST(div, DIV, /, 10, true, true)
529
530 static void test_negate(InputType a_type)
531 {
533 a_type,
534 InputType::CONSTANT, // b is unused
535 [](const fq_ct& a, const fq_ct&) { return -a; },
536 [](const fq_native& a, const fq_native&) { return -a; },
537 "NEGATE",
538 10,
539 false, // need_reduced_inputs
540 true, // need_reduction_after
541 false // check_output_tag
542 );
543 }
544
545 static void test_sqr(InputType a_type)
546 {
548 a_type,
549 InputType::CONSTANT, // b is unused
550 [](const fq_ct& a, const fq_ct&) { return a.sqr(); },
551 [](const fq_native& a, const fq_native&) { return a.sqr(); },
552 "SQR",
553 10,
554 false,
555 false,
556 false);
557 }
558
559 // Generic assignment operator test function
560 template <typename CircuitOpFunc, typename NativeOpFunc>
562 InputType b_type,
563 CircuitOpFunc circuit_op,
564 NativeOpFunc native_op,
565 const char* op_name,
566 size_t num_repetitions = 4,
567 bool need_reduced_inputs = false,
568 bool need_reduction_after = false)
569 {
570 auto builder = Builder();
571 for (size_t i = 0; i < num_repetitions; ++i) {
572 auto [a_native, a_ct] = get_random_element(&builder, a_type, need_reduced_inputs); // fq, fq_ct
573 auto [b_native, b_ct] = get_random_element(&builder, b_type, need_reduced_inputs); // fq, fq_ct
574 a_ct.set_origin_tag(submitted_value_origin_tag);
575 b_ct.set_origin_tag(challenge_origin_tag);
576
577 if (i == num_repetitions - 1) {
578 std::string bench_name = std::string(op_name);
579 BENCH_GATE_COUNT_START(builder, bench_name.c_str());
580 circuit_op(a_ct, b_ct);
581 BENCH_GATE_COUNT_END(builder, bench_name.c_str());
582 } else {
583 circuit_op(a_ct, b_ct);
584 }
585
586 // Need to self-reduce as assignment operators do not automatically reduce
587 a_ct.self_reduce();
588
589 // Assignment operations merge tags
590 EXPECT_EQ(a_ct.get_origin_tag(), first_two_merged_tag);
591
592 fq_native expected = native_op(a_native, b_native);
593 if (need_reduction_after) {
594 expected = expected.reduce_once().reduce_once();
595 }
596 expected = expected.from_montgomery_form();
597 uint512_t result = a_ct.get_value();
598
599 EXPECT_EQ(result.lo.data[0], expected.data[0]);
600 EXPECT_EQ(result.lo.data[1], expected.data[1]);
601 EXPECT_EQ(result.lo.data[2], expected.data[2]);
602 EXPECT_EQ(result.lo.data[3], expected.data[3]);
603 EXPECT_EQ(result.hi.data[0], 0ULL);
604 EXPECT_EQ(result.hi.data[1], 0ULL);
605 EXPECT_EQ(result.hi.data[2], 0ULL);
606 EXPECT_EQ(result.hi.data[3], 0ULL);
607 }
608 bool result = CircuitChecker::check(builder);
609 EXPECT_EQ(result, true);
610 }
611
612#define ASSIGNMENT_OP_TEST(op_name, bench_name, op_symbol, repetitions, reduced_inputs, reduction_after) \
613 static void test_##op_name(InputType a_type, InputType b_type) \
614 { \
615 test_assign_operator_generic( \
616 a_type, \
617 b_type, \
618 [](fq_ct& a, const fq_ct& b) { a op_symbol## = b; }, \
619 [](const fq_native& a, const fq_native& b) { return a op_symbol b; }, \
620 #bench_name, \
621 repetitions, \
622 reduced_inputs, \
623 reduction_after); \
624 }
625
626 // Generate assignment operator tests using the macro
627 ASSIGNMENT_OP_TEST(mul_assign, MUL_ASSIGN, *, 10, false, false)
628 ASSIGNMENT_OP_TEST(add_assign, ADD_ASSIGN, +, 10, false, true)
629 ASSIGNMENT_OP_TEST(sub_assign, SUB_ASSIGN, -, 10, false, true)
630 ASSIGNMENT_OP_TEST(div_assign, DIV_ASSIGN, /, 10, true, true)
631
632 static void test_madd(InputType a_type, InputType b_type, InputType c_type)
633 {
634 auto builder = Builder();
635 size_t num_repetitions = 4;
636 for (size_t i = 0; i < num_repetitions; ++i) {
637 auto [a_native, a_ct] = get_random_element(&builder, a_type); // fq_native, fq_ct
638 auto [b_native, b_ct] = get_random_element(&builder, b_type); // fq_native, fq_ct
639 auto [c_native, c_ct] = get_random_element(&builder, c_type); // fq_native, fq_ct
640 a_ct.set_origin_tag(challenge_origin_tag);
641 b_ct.set_origin_tag(submitted_value_origin_tag);
642 c_ct.set_origin_tag(next_challenge_tag);
643
644 fq_ct d_ct;
645 if (i == num_repetitions - 1) {
647 d_ct = a_ct.madd(b_ct, { c_ct });
649 } else {
650 d_ct = a_ct.madd(b_ct, { c_ct });
651 }
652
653 // Madd merges tags
654 EXPECT_EQ(d_ct.get_origin_tag(), first_second_third_merged_tag);
655
656 fq_native expected = (a_native * b_native) + c_native;
657 expected = expected.from_montgomery_form();
658 uint512_t result = d_ct.get_value();
659
660 EXPECT_EQ(result.lo.data[0], expected.data[0]);
661 EXPECT_EQ(result.lo.data[1], expected.data[1]);
662 EXPECT_EQ(result.lo.data[2], expected.data[2]);
663 EXPECT_EQ(result.lo.data[3], expected.data[3]);
664 EXPECT_EQ(result.hi.data[0], 0ULL);
665 EXPECT_EQ(result.hi.data[1], 0ULL);
666 EXPECT_EQ(result.hi.data[2], 0ULL);
667 EXPECT_EQ(result.hi.data[3], 0ULL);
668 }
669 bool result = CircuitChecker::check(builder);
670 EXPECT_EQ(result, true);
671 }
672
673 static void test_sqradd(InputType a_type, InputType b_type)
674 {
675 auto builder = Builder();
676 size_t num_repetitions = 4;
677 for (size_t i = 0; i < num_repetitions; ++i) {
678 auto [a_native, a_ct] = get_random_element(&builder, a_type); // fq_native, fq_ct
679 auto [b_native, b_ct] = get_random_element(&builder, b_type); // fq_native, fq_ct
680 a_ct.set_origin_tag(challenge_origin_tag);
681 b_ct.set_origin_tag(submitted_value_origin_tag);
682
683 fq_ct c_ct;
684 if (i == num_repetitions - 1) {
686 c_ct = a_ct.sqradd({ b_ct });
687 BENCH_GATE_COUNT_END(builder, "SQRADD");
688 } else {
689 c_ct = a_ct.sqradd({ b_ct });
690 }
691 c_ct.self_reduce();
692
693 fq_native expected = (a_native.sqr()) + b_native;
694 expected = expected.from_montgomery_form();
695 uint512_t result = c_ct.get_value();
696
697 EXPECT_EQ(result.lo.data[0], expected.data[0]);
698 EXPECT_EQ(result.lo.data[1], expected.data[1]);
699 EXPECT_EQ(result.lo.data[2], expected.data[2]);
700 EXPECT_EQ(result.lo.data[3], expected.data[3]);
701 EXPECT_EQ(result.hi.data[0], 0ULL);
702 EXPECT_EQ(result.hi.data[1], 0ULL);
703 EXPECT_EQ(result.hi.data[2], 0ULL);
704 EXPECT_EQ(result.hi.data[3], 0ULL);
705 }
706 bool result = CircuitChecker::check(builder);
707 EXPECT_EQ(result, true);
708 }
709
710 static void test_mult_madd(InputType left_type, InputType right_type, InputType to_add_type, bool edge_case = false)
711 {
712 auto builder = Builder();
713 size_t num_repetitions = 1;
714 const size_t number_of_madds = 16;
715 for (size_t i = 0; i < num_repetitions; ++i) {
716 // Get random witnesses for the multiplicands and the to_add values
717 auto [mul_left_native, mul_left_ct] =
718 get_random_elements(&builder, left_type, number_of_madds); // std::vector<fq_native>, std::vector<fq_ct>
719 auto [mul_right_native, mul_right_ct] = get_random_elements(
720 &builder, right_type, number_of_madds); // std::vector<fq_native>, std::vector<fq_ct>
721 auto [to_add_native, to_add_ct] = get_random_elements(
722 &builder, to_add_type, number_of_madds); // std::vector<fq_native>, std::vector<fq_ct>
723
724 if (edge_case) {
725 // Replace last element in the multiplicands and summand with element of the opposite type
726 // This is to test the edge case where we have a mix of witness and constant types
727 auto [extra_left_native, extra_left_ct] = get_random_element(&builder, !left_type); // fq, fq_ct
728 auto [extra_right_native, extra_right_ct] = get_random_element(&builder, !right_type); // fq, fq_ct
729 auto [extra_to_add_native, extra_to_add_ct] = get_random_element(&builder, !to_add_type); // fq, fq_ct
730 mul_right_native[number_of_madds - 1] = extra_right_native;
731 mul_left_native[number_of_madds - 1] = extra_left_native;
732 to_add_native[number_of_madds - 1] = extra_to_add_native;
733 mul_left_ct[number_of_madds - 1] = extra_left_ct;
734 mul_right_ct[number_of_madds - 1] = extra_right_ct;
735 to_add_ct[number_of_madds - 1] = extra_to_add_ct;
736 }
737
738 // Set the origin tags of the last multiplicands and summand
739 mul_left_ct[number_of_madds - 1].set_origin_tag(submitted_value_origin_tag);
740 mul_right_ct[number_of_madds - 1].set_origin_tag(challenge_origin_tag);
741 to_add_ct[number_of_madds - 1].set_origin_tag(next_challenge_tag);
742
743 fq_ct f_ct;
744 if (i == num_repetitions - 1) {
745 BENCH_GATE_COUNT_START(builder, "MULT_MADD");
746 f_ct = fq_ct::mult_madd(mul_left_ct, mul_right_ct, to_add_ct);
747 BENCH_GATE_COUNT_END(builder, "MULT_MADD");
748 } else {
749 f_ct = fq_ct::mult_madd(mul_left_ct, mul_right_ct, to_add_ct);
750 }
751
752 // mult_madd merges tags
753 EXPECT_EQ(f_ct.get_origin_tag(), first_second_third_merged_tag);
754
755 // Compute expected value
756 fq_native expected(0);
757 for (size_t j = 0; j < number_of_madds; j++) {
758 expected += mul_left_native[j] * mul_right_native[j];
759 expected += to_add_native[j];
760 }
761 expected = expected.from_montgomery_form();
762 uint512_t result = f_ct.get_value();
763
764 EXPECT_EQ(result.lo.data[0], expected.data[0]);
765 EXPECT_EQ(result.lo.data[1], expected.data[1]);
766 EXPECT_EQ(result.lo.data[2], expected.data[2]);
767 EXPECT_EQ(result.lo.data[3], expected.data[3]);
768 EXPECT_EQ(result.hi.data[0], 0ULL);
769 EXPECT_EQ(result.hi.data[1], 0ULL);
770 EXPECT_EQ(result.hi.data[2], 0ULL);
771 EXPECT_EQ(result.hi.data[3], 0ULL);
772 }
773 if (builder.failed()) {
774 info("Builder failed with error: ", builder.err());
775 };
776 bool result = CircuitChecker::check(builder);
777 EXPECT_EQ(result, true);
778 }
779
780 static void test_dual_madd()
781 {
782 auto builder = Builder();
783 size_t num_repetitions = 1;
784 for (size_t i = 0; i < num_repetitions; ++i) {
785 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
786 auto [b_native, b_ct] = get_random_witness(&builder); // fq_native, fq_ct
787 auto [c_native, c_ct] = get_random_witness(&builder); // fq_native, fq_ct
788 auto [d_native, d_ct] = get_random_witness(&builder); // fq_native, fq_ct
789 auto [e_native, e_ct] = get_random_witness(&builder); // fq_native, fq_ct
790
791 a_ct.set_origin_tag(submitted_value_origin_tag);
792 d_ct.set_origin_tag(challenge_origin_tag);
793 e_ct.set_origin_tag(next_challenge_tag);
794
795 fq_ct f_ct;
796 if (i == num_repetitions - 1) {
797 BENCH_GATE_COUNT_START(builder, "DUAL_MADD");
798 f_ct = fq_ct::dual_madd(a_ct, b_ct, c_ct, d_ct, { e_ct });
799 BENCH_GATE_COUNT_END(builder, "DUAL_MADD");
800 } else {
801 f_ct = fq_ct::dual_madd(a_ct, b_ct, c_ct, d_ct, { e_ct });
802 }
803
804 // dual_madd merges tags
805 EXPECT_EQ(f_ct.get_origin_tag(), first_second_third_merged_tag);
806
807 fq_native expected = (a_native * b_native) + (c_native * d_native) + e_native;
808 expected = expected.from_montgomery_form();
809 uint512_t result = f_ct.get_value();
810
811 EXPECT_EQ(result.lo.data[0], expected.data[0]);
812 EXPECT_EQ(result.lo.data[1], expected.data[1]);
813 EXPECT_EQ(result.lo.data[2], expected.data[2]);
814 EXPECT_EQ(result.lo.data[3], expected.data[3]);
815 EXPECT_EQ(result.hi.data[0], 0ULL);
816 EXPECT_EQ(result.hi.data[1], 0ULL);
817 EXPECT_EQ(result.hi.data[2], 0ULL);
818 EXPECT_EQ(result.hi.data[3], 0ULL);
819 }
820 if (builder.failed()) {
821 info("Builder failed with error: ", builder.err());
822 };
823 bool result = CircuitChecker::check(builder);
824 EXPECT_EQ(result, true);
825 }
826
828 {
829 auto builder = Builder();
830 size_t num_repetitions = 10;
831 for (size_t i = 0; i < num_repetitions; ++i) {
832 // We need reduced inputs for division.
833 auto [a_native, a_ct] = get_random_element(&builder, a_type, true); // reduced fq_native, fq_ct
834 auto [b_native, b_ct] = get_random_element(&builder, b_type, true); // reduced fq_native, fq_ct
835 a_ct.set_origin_tag(submitted_value_origin_tag);
836 b_ct.set_origin_tag(challenge_origin_tag);
837
838 fq_ct c_ct;
839 if (i == num_repetitions - 1) {
840 BENCH_GATE_COUNT_START(builder, "DIV_DENOM_NO_CHECK");
841 c_ct = a_ct.div_without_denominator_check(b_ct);
842 BENCH_GATE_COUNT_END(builder, "DIV_DENOM_NO_CHECK");
843 } else {
844 c_ct = a_ct.div_without_denominator_check(b_ct);
845 }
846
847 // Division without denominator check merges tags
848 EXPECT_EQ(c_ct.get_origin_tag(), first_two_merged_tag);
849
850 fq_native expected = (a_native / b_native);
851 expected = expected.reduce_once().reduce_once();
852 expected = expected.from_montgomery_form();
853 uint512_t result = c_ct.get_value();
854
855 EXPECT_EQ(result.lo.data[0], expected.data[0]);
856 EXPECT_EQ(result.lo.data[1], expected.data[1]);
857 EXPECT_EQ(result.lo.data[2], expected.data[2]);
858 EXPECT_EQ(result.lo.data[3], expected.data[3]);
859 EXPECT_EQ(result.hi.data[0], 0ULL);
860 EXPECT_EQ(result.hi.data[1], 0ULL);
861 EXPECT_EQ(result.hi.data[2], 0ULL);
862 EXPECT_EQ(result.hi.data[3], 0ULL);
863 }
864 bool result = CircuitChecker::check(builder);
865 EXPECT_EQ(result, true);
866 }
867
868 static void test_add_and_div()
869 {
870 auto builder = Builder();
871 size_t num_repetitions = 1;
872 for (size_t i = 0; i < num_repetitions; ++i) {
873
874 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
875 auto [b_native, b_ct] = get_random_witness(&builder); // fq_native, fq_ct
876 auto [c_native, c_ct] = get_random_witness(&builder); // fq_native, fq_ct
877 auto [d_native, d_ct] = get_random_witness(&builder); // fq_native, fq_ct
878 b_ct.set_origin_tag(submitted_value_origin_tag);
879 c_ct.set_origin_tag(challenge_origin_tag);
880 d_ct.set_origin_tag(next_challenge_tag);
881
882 fq_ct e = (a_ct + b_ct) / (c_ct + d_ct);
883 EXPECT_EQ(e.get_origin_tag(), first_second_third_merged_tag);
884
885 fq_native expected = (a_native + b_native) / (c_native + d_native);
886 expected = expected.reduce_once().reduce_once();
887 expected = expected.from_montgomery_form();
888 uint512_t result = e.get_value();
889
890 EXPECT_EQ(result.lo.data[0], expected.data[0]);
891 EXPECT_EQ(result.lo.data[1], expected.data[1]);
892 EXPECT_EQ(result.lo.data[2], expected.data[2]);
893 EXPECT_EQ(result.lo.data[3], expected.data[3]);
894 EXPECT_EQ(result.hi.data[0], 0ULL);
895 EXPECT_EQ(result.hi.data[1], 0ULL);
896 EXPECT_EQ(result.hi.data[2], 0ULL);
897 EXPECT_EQ(result.hi.data[3], 0ULL);
898 }
899 bool result = CircuitChecker::check(builder);
900 EXPECT_EQ(result, true);
901 }
902
903 static void test_add_and_mul(InputType summand_type)
904 {
905 auto builder = Builder();
906 size_t num_repetitions = 10;
907 for (size_t i = 0; i < num_repetitions; ++i) {
908
909 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
910 auto [b_native, b_ct] = get_random_element(&builder, summand_type); // fq_native, fq_ct
911 auto [c_native, c_ct] = get_random_witness(&builder); // fq_native, fq_ct
912 auto [d_native, d_ct] = get_random_element(&builder, summand_type); // fq_native, fq_ct
913 b_ct.set_origin_tag(submitted_value_origin_tag);
914 c_ct.set_origin_tag(challenge_origin_tag);
915 d_ct.set_origin_tag(next_challenge_tag);
916
917 fq_ct e = (a_ct + b_ct) * (c_ct + d_ct);
918
919 EXPECT_EQ(e.get_origin_tag(), first_second_third_merged_tag);
920 fq_native expected = (a_native + b_native) * (c_native + d_native);
921 expected = expected.from_montgomery_form();
922 uint512_t result = e.get_value();
923
924 EXPECT_EQ(result.lo.data[0], expected.data[0]);
925 EXPECT_EQ(result.lo.data[1], expected.data[1]);
926 EXPECT_EQ(result.lo.data[2], expected.data[2]);
927 EXPECT_EQ(result.lo.data[3], expected.data[3]);
928 EXPECT_EQ(result.hi.data[0], 0ULL);
929 EXPECT_EQ(result.hi.data[1], 0ULL);
930 EXPECT_EQ(result.hi.data[2], 0ULL);
931 EXPECT_EQ(result.hi.data[3], 0ULL);
932 }
933 bool result = CircuitChecker::check(builder);
934 EXPECT_EQ(result, true);
935 }
936
937 static void test_sub_and_mul(InputType subtrahend_type)
938 {
939 auto builder = Builder();
940 size_t num_repetitions = 10;
941 for (size_t i = 0; i < num_repetitions; ++i) {
942 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
943 auto [b_native, b_ct] = get_random_element(&builder, subtrahend_type); // fq_native, fq_ct
944 auto [c_native, c_ct] = get_random_witness(&builder); // fq_native, fq_ct
945 auto [d_native, d_ct] = get_random_element(&builder, subtrahend_type); // fq_native, fq_ct
946
947 b_ct.set_origin_tag(submitted_value_origin_tag);
948 c_ct.set_origin_tag(challenge_origin_tag);
949 d_ct.set_origin_tag(next_challenge_tag);
950
951 fq_ct e = (a_ct - b_ct) * (c_ct - d_ct);
952
953 EXPECT_EQ(e.get_origin_tag(), first_second_third_merged_tag);
954 fq_native expected = (a_native - b_native) * (c_native - d_native);
955
956 expected = expected.from_montgomery_form();
957 uint512_t result = e.get_value();
958
959 EXPECT_EQ(result.lo.data[0], expected.data[0]);
960 EXPECT_EQ(result.lo.data[1], expected.data[1]);
961 EXPECT_EQ(result.lo.data[2], expected.data[2]);
962 EXPECT_EQ(result.lo.data[3], expected.data[3]);
963 EXPECT_EQ(result.hi.data[0], 0ULL);
964 EXPECT_EQ(result.hi.data[1], 0ULL);
965 EXPECT_EQ(result.hi.data[2], 0ULL);
966 EXPECT_EQ(result.hi.data[3], 0ULL);
967 }
968 bool result = CircuitChecker::check(builder);
969 EXPECT_EQ(result, true);
970 }
971
972 static void test_msub_div(InputType multiplicand_type, InputType to_sub_type, InputType divisor_type)
973 {
974 size_t num_repetitions = 8;
975 for (size_t i = 0; i < num_repetitions; ++i) {
976 auto builder = Builder();
977 auto [mul_l, mul_l_ct] = get_random_element(&builder, multiplicand_type);
978 auto [mul_r1, mul_r1_ct] = get_random_element(&builder, multiplicand_type);
979 auto [mul_r2, mul_r2_ct] = get_random_element(&builder, multiplicand_type);
980 auto [divisor1, divisor1_ct] = get_random_element(&builder, divisor_type);
981 auto [divisor2, divisor2_ct] = get_random_element(&builder, divisor_type);
982 auto [to_sub1, to_sub1_ct] = get_random_element(&builder, to_sub_type);
983 auto [to_sub2, to_sub2_ct] = get_random_element(&builder, to_sub_type);
984
985 mul_l_ct.set_origin_tag(submitted_value_origin_tag);
986 mul_r1_ct.set_origin_tag(challenge_origin_tag);
987 divisor1_ct.set_origin_tag(next_submitted_value_origin_tag);
988 to_sub1_ct.set_origin_tag(next_challenge_tag);
989
990 fq_ct result_ct;
991 if (i == num_repetitions - 1) {
992 BENCH_GATE_COUNT_START(builder, "MSUB_DIV");
993 result_ct = fq_ct::msub_div(
994 { mul_l_ct }, { mul_r1_ct - mul_r2_ct }, divisor1_ct - divisor2_ct, { to_sub1_ct, to_sub2_ct });
995 BENCH_GATE_COUNT_END(builder, "MSUB_DIV");
996 } else {
997 result_ct = fq_ct::msub_div(
998 { mul_l_ct }, { mul_r1_ct - mul_r2_ct }, divisor1_ct - divisor2_ct, { to_sub1_ct, to_sub2_ct });
999 }
1000
1001 EXPECT_EQ(result_ct.get_origin_tag(), first_to_fourth_merged_tag);
1002 fq_native expected = (-(mul_l * (mul_r1 - mul_r2) + to_sub1 + to_sub2)) / (divisor1 - divisor2);
1003 EXPECT_EQ(result_ct.get_value().lo, uint256_t(expected));
1004 EXPECT_EQ(result_ct.get_value().hi, uint256_t(0));
1005
1006 bool result = CircuitChecker::check(builder);
1007 EXPECT_EQ(result, true);
1008 }
1009 }
1010
1011 static void test_conditional_assign(InputType a_type, InputType b_type, InputType predicate_type)
1012 {
1013 auto builder = Builder();
1014 size_t num_repetitions = 1;
1015 for (size_t i = 0; i < num_repetitions; ++i) {
1016
1017 auto [a_native, a_ct] = get_random_element(&builder, a_type); // fq_native, fq_ct
1018 auto [b_native, b_ct] = get_random_element(&builder, b_type); // fq_native, fq_ct
1019 a_ct.set_origin_tag(submitted_value_origin_tag);
1020 b_ct.set_origin_tag(challenge_origin_tag);
1021
1022 bool_ct predicate_a;
1023 if (predicate_type == InputType::WITNESS) {
1024 predicate_a = bool_ct(witness_ct(&builder, true));
1025 } else {
1026 predicate_a = bool_ct(&builder, true);
1027 }
1028 predicate_a.set_origin_tag(next_challenge_tag);
1029
1030 fq_ct c = fq_ct::conditional_assign(predicate_a, a_ct, b_ct);
1031 fq_ct d = fq_ct::conditional_assign(!predicate_a, a_ct, b_ct);
1032
1033 // Conditional assign merges tags (even if predicate is a constant)
1034 EXPECT_EQ(c.get_origin_tag(), first_second_third_merged_tag);
1035 EXPECT_EQ(d.get_origin_tag(), first_second_third_merged_tag);
1036
1037 fq_ct e = c + d;
1038 e.self_reduce();
1039 uint512_t c_out = c.get_value();
1040 uint512_t d_out = d.get_value();
1041 uint512_t e_out = e.get_value();
1042
1043 fq_native result_c(c_out.lo);
1044 fq_native result_d(d_out.lo);
1045 fq_native result_e(e_out.lo);
1046
1047 EXPECT_EQ(result_c, a_native);
1048 EXPECT_EQ(result_d, b_native);
1049 EXPECT_EQ(result_e, fq_native(a_native + b_native));
1050 }
1051 bool result = CircuitChecker::check(builder);
1052 EXPECT_EQ(result, true);
1053 }
1054
1055 static void test_conditional_select(InputType a_type, InputType b_type, InputType predicate_type)
1056 {
1057 auto builder = Builder();
1058 size_t num_repetitions = 1;
1059 for (size_t i = 0; i < num_repetitions; ++i) {
1060
1061 auto [a_native, a_ct] = get_random_element(&builder, a_type); // fq_native, fq_ct
1062 auto [b_native, b_ct] = get_random_element(&builder, b_type); // fq_native, fq_ct
1063 a_ct.set_origin_tag(submitted_value_origin_tag);
1064 b_ct.set_origin_tag(challenge_origin_tag);
1065
1066 bool_ct predicate_a;
1067 if (predicate_type == InputType::WITNESS) {
1068 predicate_a = bool_ct(witness_ct(&builder, true));
1069 } else {
1070 predicate_a = bool_ct(&builder, true);
1071 }
1072 predicate_a.set_origin_tag(next_challenge_tag);
1073
1074 fq_ct c = a_ct.conditional_select(b_ct, predicate_a);
1075 fq_ct d = a_ct.conditional_select(b_ct, !predicate_a);
1076
1077 // Conditional select merges tags (even if predicate is a constant)
1078 EXPECT_EQ(c.get_origin_tag(), first_second_third_merged_tag);
1079 EXPECT_EQ(d.get_origin_tag(), first_second_third_merged_tag);
1080
1081 fq_ct e = c + d;
1082 e.self_reduce();
1083 uint512_t c_out = c.get_value();
1084 uint512_t d_out = d.get_value();
1085 uint512_t e_out = e.get_value();
1086
1087 fq_native result_c(c_out.lo);
1088 fq_native result_d(d_out.lo);
1089 fq_native result_e(e_out.lo);
1090
1091 EXPECT_EQ(result_c, b_native);
1092 EXPECT_EQ(result_d, a_native);
1093 EXPECT_EQ(result_e, fq_native(a_native + b_native));
1094 }
1095 bool result = CircuitChecker::check(builder);
1096 EXPECT_EQ(result, true);
1097 }
1098
1099 static void test_conditional_negate(InputType a_type, InputType predicate_type)
1100 {
1101 auto builder = Builder();
1102 size_t num_repetitions = 1;
1103 for (size_t i = 0; i < num_repetitions; ++i) {
1104
1105 auto [a_native, a_ct] = get_random_element(&builder, a_type); // fq_native, fq_ct
1106 a_ct.set_origin_tag(submitted_value_origin_tag);
1107
1108 bool_ct predicate_a;
1109 if (predicate_type == InputType::WITNESS) {
1110 predicate_a = bool_ct(witness_ct(&builder, true));
1111 } else {
1112 predicate_a = bool_ct(&builder, true);
1113 }
1114 predicate_a.set_origin_tag(challenge_origin_tag);
1115
1116 fq_ct c = a_ct.conditional_negate(predicate_a);
1117 fq_ct d = a_ct.conditional_negate(!predicate_a);
1118
1119 // Conditional negate merges tags
1120 EXPECT_EQ(c.get_origin_tag(), first_two_merged_tag);
1121 EXPECT_EQ(d.get_origin_tag(), first_two_merged_tag);
1122
1123 fq_ct e = c + d;
1124 c.self_reduce();
1125 d.self_reduce();
1126 e.self_reduce();
1127 uint512_t c_out = c.get_value();
1128 uint512_t d_out = d.get_value();
1129 uint512_t e_out = e.get_value();
1130
1131 fq_native result_c(c_out.lo);
1132 fq_native result_d(d_out.lo);
1133 fq_native result_e(e_out.lo);
1134
1135 fq_native expected_c = (-a_native);
1136 fq_native expected_d = a_native;
1137
1138 EXPECT_EQ(result_c, expected_c);
1139 EXPECT_EQ(result_d, expected_d);
1140 EXPECT_EQ(result_e, fq_native(0));
1141 }
1142 bool result = CircuitChecker::check(builder);
1143 EXPECT_EQ(result, true);
1144 }
1145
1147 {
1148 auto builder = Builder();
1149 size_t num_repetitions = 1;
1150 for (size_t i = 0; i < num_repetitions; ++i) {
1151 // Note: we're using g1 = bn254 here. not tested for other curves.
1152 g1::affine_element P1(g1::element::random_element());
1153 g1::affine_element P2(g1::element::random_element());
1154
1155 fq_ct x1(
1156 witness_ct(&builder, fr(uint256_t(P1.x).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1157 witness_ct(&builder, fr(uint256_t(P1.x).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1158 fq_ct y1(
1159 witness_ct(&builder, fr(uint256_t(P1.y).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1160 witness_ct(&builder, fr(uint256_t(P1.y).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1161 fq_ct x2(
1162 witness_ct(&builder, fr(uint256_t(P2.x).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1163 witness_ct(&builder, fr(uint256_t(P2.x).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1164 fq_ct y2(
1165 witness_ct(&builder, fr(uint256_t(P2.y).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1166 witness_ct(&builder, fr(uint256_t(P2.y).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1167
1168 uint64_t before = builder.get_num_finalized_gates_inefficient();
1169 fq_ct lambda = (y2 - y1) / (x2 - x1);
1170 fq_ct x3 = lambda.sqr() - (x2 + x1);
1171 fq_ct y3 = (x1 - x3) * lambda - y1;
1172 uint64_t after = builder.get_num_finalized_gates_inefficient();
1173 std::cerr << "added gates = " << after - before << std::endl;
1174
1175 // Check the result against the native group addition
1177 fq expected_x = P3.x;
1178 fq expected_y = P3.y;
1179 expected_x = expected_x.from_montgomery_form();
1180 expected_y = expected_y.from_montgomery_form();
1181 uint512_t result_x = x3.get_value() % fq_ct::modulus_u512;
1182 uint512_t result_y = y3.get_value() % fq_ct::modulus_u512;
1183 EXPECT_EQ(result_x.lo.data[0], expected_x.data[0]);
1184 EXPECT_EQ(result_x.lo.data[1], expected_x.data[1]);
1185 EXPECT_EQ(result_x.lo.data[2], expected_x.data[2]);
1186 EXPECT_EQ(result_x.lo.data[3], expected_x.data[3]);
1187 EXPECT_EQ(result_y.lo.data[0], expected_y.data[0]);
1188 EXPECT_EQ(result_y.lo.data[1], expected_y.data[1]);
1189 EXPECT_EQ(result_y.lo.data[2], expected_y.data[2]);
1190 EXPECT_EQ(result_y.lo.data[3], expected_y.data[3]);
1191 }
1192 bool result = CircuitChecker::check(builder);
1193 EXPECT_EQ(result, true);
1194 }
1195
1196 static void test_reduce()
1197 {
1198 auto builder = Builder();
1199 size_t num_repetitions = 10;
1200 for (size_t i = 0; i < num_repetitions; ++i) {
1201 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
1202 auto [b_native, b_ct] = get_random_witness(&builder); // fq_native, fq_ct
1203
1204 fq_ct c_ct = a_ct;
1205 fq_native expected = a_native;
1206 for (size_t i = 0; i < 16; ++i) {
1207 c_ct = b_ct * b_ct + c_ct;
1208 expected = b_native * b_native + expected;
1209 }
1210
1211 c_ct.set_origin_tag(challenge_origin_tag);
1212 c_ct.self_reduce();
1213
1214 // self_reduce preserves tags
1215 EXPECT_EQ(c_ct.get_origin_tag(), challenge_origin_tag);
1216
1217 fq_native result = fq_native(c_ct.get_value().lo);
1218 EXPECT_EQ(result, expected);
1219 EXPECT_EQ(c_ct.get_value().get_msb() < (fq_ct::modulus.get_msb() + 1), true);
1220 }
1221 bool result = CircuitChecker::check(builder);
1222 EXPECT_EQ(result, true);
1223 }
1224
1225 static void test_equality_operator(InputType a_type, InputType b_type)
1226 {
1227 auto builder = Builder();
1228 size_t num_repetitions = 10;
1229 for (size_t i = 0; i < num_repetitions; ++i) {
1230
1231 auto [a_native, a_ct] = get_random_element(&builder, a_type); // fq_native, fq_ct
1232 auto [b_native, b_ct] = get_random_element(&builder, b_type); // fq_native, fq_ct
1233
1234 // Construct witness from a_native
1235 fq_ct another_a_ct = fq_ct::create_from_u512_as_witness(&builder, uint512_t(a_native), true);
1236 bool_ct equality_with_self = (a_ct == another_a_ct);
1237 EXPECT_EQ(equality_with_self.get_value(), true);
1238
1239 // Check against b
1240 bool expected = (a_native == b_native);
1241 bool_ct result = (a_ct == b_ct);
1242 EXPECT_EQ(result.get_value(), expected);
1243 }
1244 bool result = CircuitChecker::check(builder);
1245 EXPECT_EQ(result, true);
1246 }
1247
1249 {
1250 auto builder = Builder();
1251 size_t num_repetitions = 10;
1252 for (size_t i = 0; i < num_repetitions; ++i) {
1253
1254 // Get unreduced inputs
1255 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
1256 auto [b_native, b_ct] = get_random_witness(&builder); // fq_native, fq_ct
1257
1258 // Get a reduced input
1259 auto [d_native, d_ct] = get_random_witness(&builder, true); // fq_native, fq_ct
1260
1261 // c_ct will be unreduced while performing operations
1262 fq_ct c_ct = a_ct;
1263 fq_native expected = a_native;
1264 for (size_t i = 0; i < 16; ++i) {
1265 c_ct = b_ct * b_ct + c_ct;
1266 expected = b_native * b_native + expected;
1267 }
1268
1269 c_ct.set_origin_tag(challenge_origin_tag);
1270
1271 // We need to reduce before calling assert_is_in_field
1272 c_ct.self_reduce();
1273 c_ct.assert_is_in_field();
1274
1275 // We can directly call assert_is_in_field on a reduced element
1276 d_ct.set_origin_tag(challenge_origin_tag);
1277 d_ct.assert_is_in_field();
1278
1279 // assert_is_in_field preserves tags
1280 EXPECT_EQ(c_ct.get_origin_tag(), challenge_origin_tag);
1281 EXPECT_EQ(d_ct.get_origin_tag(), challenge_origin_tag);
1282
1283 uint256_t result = (c_ct.get_value().lo);
1284 EXPECT_EQ(result, uint256_t(expected));
1285 EXPECT_EQ(c_ct.get_value().get_msb() < (fq_ct::modulus.get_msb() + 1), true);
1286 }
1287 bool result = CircuitChecker::check(builder);
1288 EXPECT_EQ(result, true);
1289 }
1290
1292 {
1293 auto builder = Builder();
1294 size_t num_repetitions = 1000;
1295 fq_ct c_ct = fq_ct::zero();
1296 fq_native expected = fq_native::zero();
1297 for (size_t i = 0; i < num_repetitions; ++i) {
1298
1299 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
1300 auto [b_native, b_ct] = get_random_witness(&builder); // fq_native, fq_ct
1301
1302 for (size_t i = 0; i < 16; ++i) {
1303 c_ct += a_ct * b_ct;
1304 expected += a_native * b_native;
1305 }
1306
1307 // Break out of the loop if c has exceeded the modulus
1308 if (c_ct.get_value() >= fq_ct::modulus) {
1309 break;
1310 }
1311 }
1312
1313 // this will fail because mult and add have been performed without reduction
1314 c_ct.assert_is_in_field();
1315
1316 // results must match (reduction called after assert_is_in_field)
1317 c_ct.self_reduce();
1318 uint256_t result_val = c_ct.get_value().lo;
1319 EXPECT_EQ(result_val, uint256_t(expected));
1320
1321 bool result = CircuitChecker::check(builder);
1322 EXPECT_EQ(result, false);
1323 }
1324
1326 {
1327 auto builder = Builder();
1328 size_t num_repetitions = 10;
1329 constexpr size_t num_bits = 200;
1330 constexpr uint256_t bit_mask = (uint256_t(1) << num_bits) - 1;
1331 for (size_t i = 0; i < num_repetitions; ++i) {
1332
1333 uint256_t a_u256 = uint256_t(fq_native::random_element()) & bit_mask;
1334 uint256_t b_u256 = uint256_t(fq_native::random_element()) & bit_mask;
1335
1336 // Construct 200-bit bigfield elements
1337 fq_ct a_ct(witness_ct(&builder, fr(a_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1338 witness_ct(&builder, fr(a_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1339 fq_ct b_ct(witness_ct(&builder, fr(b_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1340 witness_ct(&builder, fr(b_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1341
1342 // Assert a, b < 2^200
1343 a_ct.assert_less_than(bit_mask + 1);
1344 b_ct.assert_less_than(bit_mask + 1);
1345 EXPECT_EQ(a_ct.get_value().get_msb() < num_bits, true);
1346 EXPECT_EQ(b_ct.get_value().get_msb() < num_bits, true);
1347 }
1348 bool result = CircuitChecker::check(builder);
1349 EXPECT_EQ(result, true);
1350 }
1351
1353 {
1354 auto builder = Builder();
1355 constexpr size_t num_bits = 200;
1356 constexpr uint256_t bit_mask = (uint256_t(1) << num_bits) - 1;
1357
1358 size_t num_repetitions = 1000;
1359 fq_ct c_ct = fq_ct::zero();
1360 fq_native expected = fq_native::zero();
1361 for (size_t i = 0; i < num_repetitions; ++i) {
1362
1363 uint256_t a_u256 = uint256_t(fq_native::random_element()) & bit_mask;
1364 uint256_t b_u256 = uint256_t(fq_native::random_element()) & bit_mask;
1365
1366 // Construct 200-bit bigfield elements
1367 fq_ct a_ct(witness_ct(&builder, fr(a_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1368 witness_ct(&builder, fr(a_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1369 fq_ct b_ct(witness_ct(&builder, fr(b_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1370 witness_ct(&builder, fr(b_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1371
1372 // Mul and add without reduction to exceed 200 bits
1373 for (size_t i = 0; i < 16; ++i) {
1374 c_ct += a_ct * b_ct;
1375 expected += fq_native(a_u256) * fq_native(b_u256);
1376 }
1377
1378 // Break out of the loop if c has exceeded 200 bits
1379 if (c_ct.get_value().get_msb() >= num_bits) {
1380 break;
1381 }
1382 }
1383
1384 // check that assert_less_than fails
1385 c_ct.assert_less_than(bit_mask + 1);
1386
1387 // results must match (reduction called after assert_is_in_field)
1388 c_ct.self_reduce();
1389 uint256_t result_val = c_ct.get_value().lo;
1390 EXPECT_EQ(result_val, uint256_t(expected));
1391
1392 bool result = CircuitChecker::check(builder);
1393 EXPECT_EQ(result, false);
1394 }
1395
1397 {
1398 auto builder = Builder();
1399 size_t num_repetitions = 10;
1400 for (size_t i = 0; i < num_repetitions; ++i) {
1401
1402 // Get unreduced inputs
1403 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
1404 auto [b_native, b_ct] = get_random_witness(&builder); // fq_native, fq_ct
1405
1406 // c_ct will be unreduced while performing operations
1407 fq_ct c_ct = a_ct;
1408 fq_native expected = a_native;
1409 for (size_t i = 0; i < 16; ++i) {
1410 c_ct = b_ct * b_ct + c_ct;
1411 expected = b_native * b_native + expected;
1412 }
1413
1414 c_ct.set_origin_tag(challenge_origin_tag);
1415
1416 // reduce c to [0, p)
1417 // count gates for the last iteration only
1418 if (i == num_repetitions - 1) {
1419 BENCH_GATE_COUNT_START(builder, "REDUCE_MOD_P");
1420 c_ct.reduce_mod_target_modulus();
1421 BENCH_GATE_COUNT_END(builder, "REDUCE_MOD_P");
1422 } else {
1423 c_ct.reduce_mod_target_modulus();
1424 }
1425
1426 // reduce_mod_target_modulus preserves tags
1427 EXPECT_EQ(c_ct.get_origin_tag(), challenge_origin_tag);
1428
1429 uint256_t result = (c_ct.get_value().lo);
1430 EXPECT_EQ(result, uint256_t(expected));
1431 EXPECT_EQ(c_ct.get_value() < fq_ct::modulus, true);
1432 }
1433 bool result = CircuitChecker::check(builder);
1434 EXPECT_EQ(result, true);
1435 }
1436
1438 {
1439 auto builder = Builder();
1440 size_t num_repetitions = 10;
1441 for (size_t i = 0; i < num_repetitions; ++i) {
1442
1445
1446 std::vector<uint8_t> input_a(sizeof(fq_native));
1447 fq_native::serialize_to_buffer(a_native, &input_a[0]);
1448 std::vector<uint8_t> input_b(sizeof(fq_native));
1449 fq_native::serialize_to_buffer(b_native, &input_b[0]);
1450
1451 stdlib::byte_array<Builder> input_arr_a(&builder, input_a);
1452 stdlib::byte_array<Builder> input_arr_b(&builder, input_b);
1453
1454 input_arr_a.set_origin_tag(submitted_value_origin_tag);
1455 input_arr_b.set_origin_tag(challenge_origin_tag);
1456
1457 fq_ct a_ct(input_arr_a);
1458 fq_ct b_ct(input_arr_b);
1459
1460 fq_ct c_ct = a_ct * b_ct;
1461
1462 EXPECT_EQ(c_ct.get_origin_tag(), first_two_merged_tag);
1463
1464 fq_native expected = a_native * b_native;
1465 uint256_t result = (c_ct.get_value().lo);
1466 EXPECT_EQ(result, uint256_t(expected));
1467 }
1468 bool result = CircuitChecker::check(builder);
1469 EXPECT_EQ(result, true);
1470 }
1471
1472 // This check tests if elements are reduced to fit quotient into range proof
1474 {
1475 auto builder = Builder();
1476 const uint256_t input =
1477 uint256_t(0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffffff);
1478
1479 fq_ct a(witness_ct(&builder, fr(uint256_t(input).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1480 witness_ct(&builder, fr(uint256_t(input).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))),
1481 false);
1482 auto a1 = a;
1483 auto a2 = a;
1484 auto a3 = a;
1485 auto a4 = a;
1486
1487 for (auto i = 0; i < 8; i++) {
1488 a = a + a;
1489 a1 = a1 + a1;
1490 a2 = a2 + a2;
1491 a3 = a3 + a3;
1492 a4 = a4 + a4;
1493 }
1494
1495 auto b = a * a;
1496 (void)b;
1497
1498 auto c = a1.sqr();
1499 (void)c;
1500
1501 auto d = a2.sqradd({});
1502 (void)d;
1503
1504 auto e = a3.madd(a3, {});
1505 (void)e;
1506
1507 auto f = fq_ct::mult_madd({ a4 }, { a4 }, {}, false);
1508 (void)f;
1509
1510 bool result = CircuitChecker::check(builder);
1511 EXPECT_EQ(result, true);
1512 }
1513
1515 {
1516 auto builder = Builder();
1517 fq_native a(0);
1518 fq_native b(1);
1519 fq_ct a_ct(&builder, a);
1520 fq_ct b_ct(&builder, b);
1521 fq_ct selected = a_ct.conditional_select(b_ct, bool_ct(&builder, true));
1522 EXPECT_EQ(fq_native((selected.get_value() % uint512_t(fq_native::modulus)).lo), b);
1523 }
1524
1526 {
1527 auto builder = Builder();
1528 fq_native a(1);
1529 fq_ct a_ct(&builder, a);
1530 fq_ct ret = fq_ct::div_check_denominator_nonzero({}, a_ct);
1531 EXPECT_NE(ret.get_context(), nullptr);
1532 }
1533
1534 static void test_inversion()
1535 {
1536 fq_ct a = fq_ct(-7);
1537 fq_ct a_inverse = a.invert();
1538 fq_ct a_inverse_division = fq_ct(1) / a;
1539
1540 fq_native a_native = fq_native(-7);
1541 fq_native a_native_inverse = a_native.invert();
1542 EXPECT_EQ(fq_native((a.get_value() % uint512_t(fq_native::modulus)).lo), a_native);
1543 EXPECT_EQ(fq_native((a_inverse.get_value() % uint512_t(fq_native::modulus)).lo), a_native_inverse);
1544 EXPECT_EQ(fq_native((a_inverse_division.get_value() % uint512_t(fq_native::modulus)).lo), a_native_inverse);
1545 }
1546
1548 {
1549 auto builder = Builder();
1550 size_t num_repetitions = 10;
1551 for (size_t i = 0; i < num_repetitions; ++i) {
1552 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
1553 auto [c_native, c_ct] = get_random_witness(&builder); // fq_native, fq_ct
1554 auto [d_native, d_ct] = get_random_witness(&builder); // fq_native, fq_ct
1555
1556 fq_ct two_ct = fq_ct::unsafe_construct_from_limbs(witness_ct(&builder, fr(2)),
1557 witness_ct(&builder, fr(0)),
1558 witness_ct(&builder, fr(0)),
1559 witness_ct(&builder, fr(0)));
1560 fq_ct t0 = a_ct + a_ct;
1561 fq_ct t1 = a_ct * two_ct;
1562
1563 t0.assert_equal(t1);
1564 t0.assert_is_not_equal(c_ct);
1565 t0.assert_is_not_equal(d_ct);
1566 stdlib::bool_t<Builder> is_equal_a = t0 == t1;
1567 stdlib::bool_t<Builder> is_equal_b = t0 == c_ct;
1568 EXPECT_TRUE(is_equal_a.get_value());
1569 EXPECT_FALSE(is_equal_b.get_value());
1570 }
1571 bool result = CircuitChecker::check(builder);
1572 EXPECT_EQ(result, true);
1573 }
1574
1575 static void test_pow()
1576 {
1578
1580 uint32_t exponent_val = engine.get_random_uint32();
1581 // Set the high bit
1582 exponent_val |= static_cast<uint32_t>(1) << 31;
1583 fq_ct base_constant(&builder, static_cast<uint256_t>(base_val));
1584 fq_ct base_witness_ct = fq_ct::from_witness(&builder, typename fq_ct::native(base_val));
1585 // This also tests for the case where the exponent is zero
1586 for (size_t i = 0; i <= 32; i += 4) {
1587 uint32_t current_exponent_val = exponent_val >> i;
1588 fq_native expected = base_val.pow(current_exponent_val);
1589
1590 // Check for constant bigfield element with constant exponent
1591 fq_ct result_constant_base = base_constant.pow(current_exponent_val);
1592 EXPECT_EQ(fq_native(result_constant_base.get_value()), expected);
1593
1594 // Check for witness base with constant exponent
1595 fq_ct result_witness_base = base_witness_ct.pow(current_exponent_val);
1596 EXPECT_EQ(fq_native(result_witness_base.get_value()), expected);
1597
1598 base_witness_ct.set_origin_tag(submitted_value_origin_tag);
1599 }
1600
1601 bool check_result = CircuitChecker::check(builder);
1602 EXPECT_EQ(check_result, true);
1603 }
1604
1605 static void test_pow_one()
1606 {
1608
1610
1611 uint32_t current_exponent_val = 1;
1612 fq_ct base_constant_ct(&builder, static_cast<uint256_t>(base_val));
1613 fq_ct base_witness_ct = fq_ct::from_witness(&builder, typename fq_ct::native(base_val));
1614 fq_native expected = base_val.pow(current_exponent_val);
1615
1616 // Check for constant bigfield element with constant exponent
1617 fq_ct result_constant_base = base_constant_ct.pow(current_exponent_val);
1618 EXPECT_EQ(fq_native(result_constant_base.get_value()), expected);
1619
1620 // Check for witness base with constant exponent
1621 fq_ct result_witness_base = base_witness_ct.pow(current_exponent_val);
1622 EXPECT_EQ(fq_native(result_witness_base.get_value()), expected);
1623
1624 bool check_result = CircuitChecker::check(builder);
1625 EXPECT_EQ(check_result, true);
1626 }
1627
1629 {
1630 auto builder = Builder();
1631 size_t num_repetitions = 10;
1632 constexpr size_t num_bits = 200;
1633 constexpr uint256_t bit_mask = (uint256_t(1) << num_bits) - 1;
1634 for (size_t i = 0; i < num_repetitions; ++i) {
1635
1636 uint256_t a_u256 = uint256_t(fq_native::random_element()) & bit_mask;
1637 uint256_t b_u256 = uint256_t(fq_native::random_element()) & bit_mask;
1638
1639 // Construct 200-bit bigfield elements
1640 fq_ct a_ct(witness_ct(&builder, fr(a_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1641 witness_ct(&builder, fr(a_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1642 fq_ct b_ct(witness_ct(&builder, fr(b_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1643 witness_ct(&builder, fr(b_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1644
1645 // Assert a, b < 2^200
1648 EXPECT_EQ(a_ct.get_value().get_msb() < num_bits, true);
1649 EXPECT_EQ(b_ct.get_value().get_msb() < num_bits, true);
1650 }
1651
1652 // Also test when: p < a < bound
1653 // define a = p + small_random_value
1654 uint256_t small_mask = (uint256_t(1) << 16) - 1;
1655 uint256_t a_u256 = uint256_t(fq_native::random_element()) & small_mask;
1656 a_u256 += uint256_t(fq_native::modulus);
1657
1658 // upper bound must be greater than p + 2^16: we set it to p + 2^30
1659 uint256_t upper_bound = (uint256_t(1) << 30) + uint256_t(fq_native::modulus);
1660
1661 // Construct bigfield element
1662 fq_ct a_ct(witness_ct(&builder, fr(a_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1663 witness_ct(&builder, fr(a_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))),
1664 /*can_overflow*/ true);
1665
1666 // Assert a < bound
1668 EXPECT_EQ(a_ct.get_value() > uint512_t(fq_native::modulus), true);
1669
1670 // Combined circuit should pass
1671 bool result = CircuitChecker::check(builder);
1672 EXPECT_EQ(result, true);
1673 }
1674
1676 {
1677 {
1678 // Test a case when the value is exactly equal to the limit
1679 auto builder = Builder();
1680 constexpr size_t num_bits = 200;
1681 constexpr uint256_t bit_mask = (uint256_t(1) << num_bits) - 1;
1682 fq_ct a_ct(witness_ct(&builder, fr(bit_mask.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1683 witness_ct(&builder, fr(bit_mask.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1684
1685 // check that unsafe_assert_less_than fails when we try to check a < a.
1687
1688 bool result = CircuitChecker::check(builder);
1689 EXPECT_EQ(result, false);
1690 }
1691 {
1692 // Test a case when the value is (B + 2) but the bound is B.
1693 auto builder = Builder();
1694 constexpr size_t num_bits = 200;
1695 constexpr uint256_t bit_mask = (uint256_t(1) << num_bits) - 1;
1696 const uint256_t upper_bound = uint256_t(fq_native::random_element()) & bit_mask;
1697 const uint256_t a_value = upper_bound + uint256_t(2);
1698 fq_ct a_ct(witness_ct(&builder, fr(a_value.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1699 witness_ct(&builder, fr(a_value.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1700
1701 // check that unsafe_assert_less_than fails when we try to check (B + 2) < B.
1703
1704 bool result = CircuitChecker::check(builder);
1705 EXPECT_EQ(result, false);
1706 }
1707 {
1708 // Test a case when p < bound < a
1709 auto builder = Builder();
1710 uint256_t small_mask = (uint256_t(1) << 32) - 1;
1711 uint256_t a_u256 = uint256_t(fq_native::random_element()) & small_mask;
1712 a_u256 += uint256_t(fq_native::modulus);
1713
1714 // upper bound must be greater than p but smaller than a
1715 uint256_t upper_bound = uint256_t(fq_native::modulus) + uint256_t(1);
1716
1717 // Construct bigfield element
1718 fq_ct a_ct(witness_ct(&builder, fr(a_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1719 witness_ct(&builder, fr(a_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))),
1720 /*can_overflow*/ true);
1721
1722 // check that unsafe_assert_less_than fails when we try to check a < bound.
1724
1725 bool result = CircuitChecker::check(builder);
1726 EXPECT_EQ(result, false);
1727 }
1728 }
1729
1731 {
1733
1734 // The circuit enforces:
1735 // a * b + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod 2^T
1736 // a * b + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod n
1737
1738 // Single addend and remainder
1739 auto [a_native, a_ct] = get_random_witness(&builder);
1740 auto [b_native, b_ct] = get_random_witness(&builder);
1741 auto [c_native, c_ct] = get_random_witness(&builder);
1742
1743 // Get quotient and remainder for (a * b + c) from native values
1744 uint1024_t native_sum = uint1024_t(a_native) * uint1024_t(b_native) + uint1024_t(c_native);
1745 auto [q_native_1024, r_native_1024] = native_sum.divmod(uint1024_t(fq_ct::modulus));
1746 const uint512_t q_native_512 = q_native_1024.lo;
1747 const uint512_t r_native_512 = r_native_1024.lo;
1748 fq_ct q_ct = fq_ct::create_from_u512_as_witness(&builder, q_native_512, true);
1749 fq_ct r_ct = fq_ct::create_from_u512_as_witness(&builder, r_native_512, true);
1750
1751 // Call unsafe_evaluate_multiply_add (via friendly class)
1752 stdlib::bigfield_test_access::unsafe_evaluate_multiply_add(a_ct, b_ct, { c_ct }, q_ct, { r_ct });
1753
1754 // The above function does not protect against CRT overflows, i.e., check if lhs and rhs are less than
1755 // M = (2^T * n). Verify that adding a multiple of M to both sides does not result in an unsatisfiable circuit.
1756 uint512_t big_M = uint512_t(fr::modulus) * fq_ct::binary_basis.modulus;
1757 uint512_t modified_c_native = uint512_t(c_native) + big_M;
1758 uint512_t modified_r_native = uint512_t(r_native_512) + big_M;
1759 fq_ct modified_c_ct = fq_ct::create_from_u512_as_witness(&builder, modified_c_native, true);
1760 fq_ct modified_r_ct = fq_ct::create_from_u512_as_witness(&builder, modified_r_native, true);
1761
1762 // Call unsafe_evaluate_multiply_add (via friendly class)
1764 a_ct, b_ct, { modified_c_ct }, q_ct, { modified_r_ct });
1765
1766 // Native verification mod p
1767 fq_native expected_lhs = a_native * b_native + c_native;
1768 fq_native expected_rhs = fq_native(q_native_512) * fq_ct::modulus + fq_native(r_native_512);
1769 EXPECT_EQ(expected_lhs, expected_rhs);
1770
1771 // Native verification mod 2^T
1772 uint1024_t lhs_1024 = uint512_t(a_native) * uint512_t(b_native) + uint512_t(c_native);
1773 uint1024_t rhs_1024 = q_native_512 * fq_ct::modulus + r_native_512;
1774 auto [quotient_lhs, remainder_lhs] = lhs_1024.divmod(fq_ct::binary_basis.modulus);
1775 auto [quotient_rhs, remainder_rhs] = rhs_1024.divmod(fq_ct::binary_basis.modulus);
1776 EXPECT_EQ(remainder_lhs, remainder_rhs);
1777
1778 // Native verification mod n
1779 fr expected_lhs_fr = fr(a_native) * fr(b_native) + fr(c_native);
1780 fr expected_rhs_fr = fr(q_native_512) * fr(fq_ct::modulus) + fr(r_native_512);
1781 EXPECT_EQ(expected_lhs_fr, expected_rhs_fr);
1782
1783 // Check circuit correctness
1784 bool result = CircuitChecker::check(builder);
1785 EXPECT_EQ(result, true);
1786 }
1787
1789 {
1790 auto builder = Builder();
1791
1792 // The circuit enforces:
1793 // a * b + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod 2^T
1794 // a * b + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod n
1795
1796 // Single addend and remainder
1797 auto [a_native, a_ct] = get_random_witness(&builder);
1798 auto [b_native, b_ct] = get_random_witness(&builder);
1799 auto [c_native, c_ct] = get_random_witness(&builder);
1800
1801 // Get quotient and remainder for (a * b + c) from native values
1802 uint512_t native_sum = uint512_t(a_native) * uint512_t(b_native) + uint512_t(c_native);
1803 auto [q_native_uint512_t, r_native_uint512_t] = native_sum.divmod(uint512_t(fq_ct::modulus));
1804 fq_ct q_ct = fq_ct::create_from_u512_as_witness(
1805 &builder, q_native_uint512_t + uint512_t(1), true); // Intentionally poisoned
1806 fq_ct r_ct = fq_ct::create_from_u512_as_witness(&builder, r_native_uint512_t, true);
1807
1808 // Call unsafe_evaluate_multiply_add (via friendly class)
1809 stdlib::bigfield_test_access::unsafe_evaluate_multiply_add(a_ct, b_ct, { c_ct }, q_ct, { r_ct });
1810
1811 // Check circuit correctness
1812 bool result = CircuitChecker::check(builder);
1813 EXPECT_EQ(result, false);
1814 EXPECT_EQ(builder.err(), "bigfield: prime limb identity failed");
1815 }
1816
1818 {
1820
1821 // The circuit enforces:
1822 // a1 * b1 + a2 * b2 + ... + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod 2^T
1823 // a1 * b1 + a2 * b2 + ... + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod n
1824 size_t num_terms = 3;
1825 std::vector<fq_native> a_natives;
1826 std::vector<fq_native> b_natives;
1827 std::vector<fq_ct> a_cts;
1828 std::vector<fq_ct> b_cts;
1829
1830 for (size_t i = 0; i < num_terms; ++i) {
1831 auto [a_native, a_ct] = get_random_witness(&builder);
1832 auto [b_native, b_ct] = get_random_witness(&builder);
1833 a_natives.push_back(a_native);
1834 b_natives.push_back(b_native);
1835 a_cts.push_back(a_ct);
1836 b_cts.push_back(b_ct);
1837 }
1838
1839 auto [c_native, c_ct] = get_random_witness(&builder);
1840
1841 // Get quotient and remainder for (sum of ai * bi + c) from native values
1842 uint1024_t native_sum = uint1024_t(c_native);
1843 for (size_t i = 0; i < num_terms; ++i) {
1844 native_sum += uint1024_t(a_natives[i]) * uint1024_t(b_natives[i]);
1845 }
1846 auto [q_native_1024, r_native_1024] = native_sum.divmod(uint512_t(fq_ct::modulus));
1847 const uint512_t q_native_512 = q_native_1024.lo;
1848 const uint512_t r_native_512 = r_native_1024.lo;
1849 fq_ct q_ct = fq_ct::create_from_u512_as_witness(&builder, q_native_512, true);
1850 fq_ct r_ct = fq_ct::create_from_u512_as_witness(&builder, r_native_512, true);
1851
1852 // Call unsafe_evaluate_multiply_add (via friendly class)
1853 stdlib::bigfield_test_access::unsafe_evaluate_multiple_multiply_add(a_cts, b_cts, { c_ct }, q_ct, { r_ct });
1854
1855 // Native verification mod p
1856 fq_native expected_lhs = fq_native(c_native);
1857 for (size_t i = 0; i < num_terms; ++i) {
1858 expected_lhs += fq_native(a_natives[i]) * fq_native(b_natives[i]);
1859 }
1860 fq_native expected_rhs = fq_native(q_native_512) * fq_ct::modulus + fq_native(r_native_512);
1861 EXPECT_EQ(expected_lhs, expected_rhs);
1862
1863 // Native verification mod 2^T
1864 uint1024_t lhs_1024 = uint1024_t(c_native);
1865 for (size_t i = 0; i < num_terms; ++i) {
1866 lhs_1024 += uint1024_t(a_natives[i]) * uint1024_t(b_natives[i]);
1867 }
1868 uint1024_t rhs_1024 = q_native_512 * fq_ct::modulus + r_native_512;
1869 auto [quotient_lhs, remainder_lhs] = lhs_1024.divmod(fq_ct::binary_basis.modulus);
1870 auto [quotient_rhs, remainder_rhs] = rhs_1024.divmod(fq_ct::binary_basis.modulus);
1871 EXPECT_EQ(remainder_lhs, remainder_rhs);
1872
1873 // Native verification mod n
1874 fr expected_lhs_fr = fr(c_native);
1875 for (size_t i = 0; i < num_terms; ++i) {
1876 expected_lhs_fr += fr(a_natives[i]) * fr(b_natives[i]);
1877 }
1878 fr expected_rhs_fr = fr(q_native_512) * fr(fq_ct::modulus) + fr(r_native_512);
1879 EXPECT_EQ(expected_lhs_fr, expected_rhs_fr);
1880
1881 // Check circuit correctness
1882 bool result = CircuitChecker::check(builder);
1883 EXPECT_EQ(result, true);
1884 }
1885
1887 {
1889
1890 // The circuit enforces:
1891 // a1 * b1 + a2 * b2 + ... + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod 2^T
1892 // a1 * b1 + a2 * b2 + ... + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod n
1893 size_t num_terms = 3;
1894 std::vector<fq_native> a_natives;
1895 std::vector<fq_native> b_natives;
1896 std::vector<fq_ct> a_cts;
1897 std::vector<fq_ct> b_cts;
1898
1899 for (size_t i = 0; i < num_terms; ++i) {
1900 auto [a_native, a_ct] = get_random_witness(&builder);
1901 auto [b_native, b_ct] = get_random_witness(&builder);
1902 a_natives.push_back(a_native);
1903 b_natives.push_back(b_native);
1904 a_cts.push_back(a_ct);
1905 b_cts.push_back(b_ct);
1906 }
1907
1908 auto [c_native, c_ct] = get_random_witness(&builder);
1909
1910 // Get quotient and remainder for (sum of ai * bi + c) from native values
1911 uint1024_t native_sum = uint1024_t(c_native);
1912 for (size_t i = 0; i < num_terms; ++i) {
1913 native_sum += uint1024_t(a_natives[i]) * uint1024_t(b_natives[i]);
1914 }
1915 auto [q_native_1024, r_native_1024] = native_sum.divmod(uint1024_t(fq_ct::modulus));
1916 fq_ct q_ct = fq_ct::create_from_u512_as_witness(
1917 &builder, q_native_1024.lo + uint512_t(1), true); // Intentionally poisoned
1918 fq_ct r_ct = fq_ct::create_from_u512_as_witness(&builder, r_native_1024.lo, true);
1919
1920 // Call unsafe_evaluate_multiply_add (via friendly class)
1921 stdlib::bigfield_test_access::unsafe_evaluate_multiple_multiply_add(a_cts, b_cts, { c_ct }, q_ct, { r_ct });
1922
1923 // Check circuit correctness
1924 bool result = CircuitChecker::check(builder);
1925 EXPECT_EQ(result, false);
1926 EXPECT_EQ(builder.err(), "bigfield: prime limb identity failed");
1927 }
1928
1930 {
1931 auto builder = Builder();
1933 uint256_t two_to_68 = uint256_t(1) << fq_ct::NUM_LIMB_BITS;
1934 // construct bigfield where the low limb has a non-trivial `additive_constant`
1935 fq_ct z(zero + two_to_68, zero);
1936 // assert invariant for every limb: actual value <= maximum value
1937 // Failed in the past for for StandardCircuitBuilder
1938 for (auto zi : z.binary_basis_limbs) {
1939 EXPECT_LE(uint256_t(zi.element.get_value()), zi.maximum_value);
1940 }
1941 }
1942
1944 {
1945 auto builder = Builder();
1946 fq_ct witness_one = fq_ct::create_from_u512_as_witness(&builder, uint256_t(1));
1947 fq_ct constant_one(1);
1948 fq_ct::msub_div({ witness_one }, { witness_one }, constant_one, { witness_one }, true);
1949 bool result = CircuitChecker::check(builder);
1950 EXPECT_EQ(result, true);
1951 }
1952
1954 {
1955 typedef stdlib::bool_t<Builder> bool_t;
1956 auto builder = Builder();
1957
1958 fq_ct w0 = fq_ct::from_witness(&builder, typename fq_ct::native(1));
1959 w0 = w0.conditional_negate(bool_t(&builder, true));
1960 w0 = w0.conditional_negate(bool_t(&builder, false));
1961 w0 = w0.conditional_negate(bool_t(&builder, true));
1962 w0 = w0.conditional_negate(bool_t(&builder, true));
1963 fq_ct w4 = w0.conditional_negate(bool_t(&builder, false));
1964 w4 = w4.conditional_negate(bool_t(&builder, true));
1965 w4 = w4.conditional_negate(bool_t(&builder, true));
1966 fq_ct w5 = w4 - w0;
1967 fq_ct w6 = w5 / 1;
1968 (void)(w6);
1969 EXPECT_TRUE(CircuitChecker::check(builder));
1970 }
1971
1973 {
1974 auto builder = Builder();
1975
1976 fq_ct numerator = fq_ct::create_from_u512_as_witness(&builder, uint256_t(1) << (68 + 67));
1977 numerator.binary_basis_limbs[0].maximum_value = 0;
1978 numerator.binary_basis_limbs[1].maximum_value = uint256_t(1) << 67;
1979 numerator.binary_basis_limbs[2].maximum_value = 0;
1980 numerator.binary_basis_limbs[3].maximum_value = 0;
1981
1982 for (size_t i = 0; i < 9; i++) {
1983 numerator = numerator + numerator;
1984 }
1985 fq_ct denominator = fq_ct::create_from_u512_as_witness(&builder, uint256_t(1));
1986 fq_ct result = numerator / denominator;
1987 (void)(result);
1988 EXPECT_TRUE(CircuitChecker::check(builder));
1989 }
1990
1992 {
1994 uint256_t dlimb0_value = uint256_t("0x00000000000000000000000000000000000000000000000bef7fa109038857fc");
1995 uint256_t dlimb0_max = uint256_t("0x00000000000000000000000000000000000000000000000fffffffffffffffff");
1996 uint256_t dlimb1_value = uint256_t("0x0000000000000000000000000000000000000000000000056f10535779f56339");
1997 uint256_t dlimb1_max = uint256_t("0x00000000000000000000000000000000000000000000000fffffffffffffffff");
1998 uint256_t dlimb2_value = uint256_t("0x00000000000000000000000000000000000000000000000c741f60a1ec4e114e");
1999 uint256_t dlimb2_max = uint256_t("0x00000000000000000000000000000000000000000000000fffffffffffffffff");
2000 uint256_t dlimb3_value = uint256_t("0x000000000000000000000000000000000000000000000000000286b3cd344d8b");
2001 uint256_t dlimb3_max = uint256_t("0x0000000000000000000000000000000000000000000000000003ffffffffffff");
2002 uint256_t dlimb_prime = uint256_t("0x286b3cd344d8bc741f60a1ec4e114e56f10535779f56339bef7fa109038857fc");
2003
2004 uint256_t nlimb0_value = uint256_t("0x00000000000000000000000000000000000000000000080a84d9bea2b012417c");
2005 uint256_t nlimb0_max = uint256_t("0x000000000000000000000000000000000000000000000ff7c7469df4081b61fc");
2006 uint256_t nlimb1_value = uint256_t("0x00000000000000000000000000000000000000000000080f50ee84526e8e5ba7");
2007 uint256_t nlimb1_max = uint256_t("0x000000000000000000000000000000000000000000000ffef965c67ba5d5893c");
2008 uint256_t nlimb2_value = uint256_t("0x00000000000000000000000000000000000000000000080aba136ca8eaf6dc1b");
2009 uint256_t nlimb2_max = uint256_t("0x000000000000000000000000000000000000000000000ff8171d22fd607249ea");
2010 uint256_t nlimb3_value = uint256_t("0x00000000000000000000000000000000000000000000000001f0042419843c29");
2011 uint256_t nlimb3_max = uint256_t("0x00000000000000000000000000000000000000000000000003e00636264659ff");
2012 uint256_t nlimb_prime = uint256_t("0x000000000000000000000000000000474da776b8ee19a56b08186bdcf01240d8");
2013
2014 fq_ct w0 = fq_ct::from_witness(&builder, fq_native(0));
2015 w0.binary_basis_limbs[0].element = witness_ct(&builder, dlimb0_value);
2016 w0.binary_basis_limbs[1].element = witness_ct(&builder, dlimb1_value);
2017 w0.binary_basis_limbs[2].element = witness_ct(&builder, dlimb2_value);
2018 w0.binary_basis_limbs[3].element = witness_ct(&builder, dlimb3_value);
2019 w0.binary_basis_limbs[0].maximum_value = dlimb0_max;
2020 w0.binary_basis_limbs[1].maximum_value = dlimb1_max;
2021 w0.binary_basis_limbs[2].maximum_value = dlimb2_max;
2022 w0.binary_basis_limbs[3].maximum_value = dlimb3_max;
2023 w0.prime_basis_limb = witness_ct(&builder, dlimb_prime);
2024
2025 fq_ct w1 = fq_ct::from_witness(&builder, fq_native(0));
2026 w1.binary_basis_limbs[0].element = witness_ct(&builder, nlimb0_value);
2027 w1.binary_basis_limbs[1].element = witness_ct(&builder, nlimb1_value);
2028 w1.binary_basis_limbs[2].element = witness_ct(&builder, nlimb2_value);
2029 w1.binary_basis_limbs[3].element = witness_ct(&builder, nlimb3_value);
2030 w1.binary_basis_limbs[0].maximum_value = nlimb0_max;
2031 w1.binary_basis_limbs[1].maximum_value = nlimb1_max;
2032 w1.binary_basis_limbs[2].maximum_value = nlimb2_max;
2033 w1.binary_basis_limbs[3].maximum_value = nlimb3_max;
2034 w1.prime_basis_limb = witness_ct(&builder, nlimb_prime);
2035
2036 fq_ct w2 = w1 / w0;
2037 (void)w2;
2038 EXPECT_TRUE(CircuitChecker::check(builder));
2039 }
2040
2042 {
2043 auto builder = Builder();
2044 fq_ct zero = fq_ct::create_from_u512_as_witness(&builder, uint256_t(0));
2045 fq_ct alsozero = fq_ct::create_from_u512_as_witness(&builder, fq_ct::modulus_u512);
2046 for (size_t i = 0; i < 4; i++) {
2047 zero.binary_basis_limbs[i].maximum_value = zero.binary_basis_limbs[i].element.get_value();
2048 alsozero.binary_basis_limbs[i].maximum_value = alsozero.binary_basis_limbs[i].element.get_value();
2049 }
2050 zero.assert_is_not_equal(alsozero);
2051 bool result = CircuitChecker::check(builder);
2052 EXPECT_EQ(result, false);
2053 }
2054};
2055
2056// Define types for which the above tests will be constructed.
2057using CircuitTypes = testing::Types<typename bb::stdlib::bn254<UltraCircuitBuilder>::BaseField,
2062// Define the suite of tests.
2064
2065TYPED_TEST(stdlib_bigfield, assert_not_equal_regression)
2066{
2067 TestFixture::test_assert_not_equal_regression();
2068}
2069
2070TYPED_TEST(stdlib_bigfield, add_to_lower_limb_regression)
2071{
2072 TestFixture::test_add_to_lower_limb_regression();
2073}
2075{
2076 TestFixture::test_bad_mul();
2077}
2078
2079TYPED_TEST(stdlib_bigfield, division_formula_regression)
2080{
2081 TestFixture::test_division_formula_bug();
2082}
2084{
2085 TestFixture::test_basic_tag_logic();
2086}
2087TYPED_TEST(stdlib_bigfield, test_constructor)
2088{
2089 TestFixture::test_constructor_from_two_elements();
2090}
2091TYPED_TEST(stdlib_bigfield, test_unsafe_construct_from_limbs)
2092{
2093 TestFixture::test_unsafe_construct_from_limbs();
2094}
2095TYPED_TEST(stdlib_bigfield, test_construct_from_limbs)
2096{
2097 TestFixture::test_construct_from_limbs();
2098}
2099TYPED_TEST(stdlib_bigfield, test_construct_from_limbs_fails)
2100{
2101 TestFixture::test_construct_from_limbs_fails();
2102}
2104{
2105 TestFixture::test_add_two(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS);
2106}
2107TYPED_TEST(stdlib_bigfield, add_two_with_constants)
2108{
2109 TestFixture::test_add_two(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT);
2110 TestFixture::test_add_two(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS);
2111 TestFixture::test_add_two(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT);
2112 TestFixture::test_add_two(InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS);
2113 TestFixture::test_add_two(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT);
2114 TestFixture::test_add_two(InputType::CONSTANT, InputType::CONSTANT, InputType::WITNESS);
2115 TestFixture::test_add_two(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT);
2116}
2118{
2119 TestFixture::test_sum(InputType::WITNESS);
2120}
2121TYPED_TEST(stdlib_bigfield, sum_with_mixed_inputs)
2122{
2123 TestFixture::test_sum(InputType::WITNESS, true);
2124}
2125TYPED_TEST(stdlib_bigfield, sum_with_constant)
2126{
2127 TestFixture::test_sum(InputType::CONSTANT);
2128}
2130{
2131 TestFixture::test_mul(InputType::WITNESS, InputType::WITNESS);
2132}
2133TYPED_TEST(stdlib_bigfield, mul_with_constant)
2134{
2135 TestFixture::test_mul(InputType::WITNESS, InputType::CONSTANT);
2136 TestFixture::test_mul(InputType::CONSTANT, InputType::WITNESS);
2137 TestFixture::test_mul(InputType::CONSTANT, InputType::CONSTANT);
2138}
2140{
2141 TestFixture::test_sub(InputType::WITNESS, InputType::WITNESS);
2142}
2143TYPED_TEST(stdlib_bigfield, sub_with_constant)
2144{
2145 TestFixture::test_sub(InputType::WITNESS, InputType::CONSTANT);
2146 TestFixture::test_sub(InputType::CONSTANT, InputType::WITNESS);
2147 TestFixture::test_sub(InputType::CONSTANT, InputType::CONSTANT);
2148}
2150{
2151 TestFixture::test_add(InputType::WITNESS, InputType::WITNESS);
2152}
2153TYPED_TEST(stdlib_bigfield, add_with_constant)
2154{
2155 TestFixture::test_add(InputType::WITNESS, InputType::CONSTANT);
2156 TestFixture::test_add(InputType::CONSTANT, InputType::WITNESS);
2157 TestFixture::test_add(InputType::CONSTANT, InputType::CONSTANT);
2158}
2160{
2161 TestFixture::test_div(InputType::WITNESS, InputType::WITNESS); // w / w
2162}
2163TYPED_TEST(stdlib_bigfield, div_with_constant)
2164{
2165 TestFixture::test_div(InputType::WITNESS, InputType::CONSTANT); // w / c
2166 TestFixture::test_div(InputType::CONSTANT, InputType::WITNESS); // c / w
2167 TestFixture::test_div(InputType::CONSTANT, InputType::CONSTANT); // c / c
2168}
2170{
2171 TestFixture::test_sqr(InputType::WITNESS);
2172}
2173TYPED_TEST(stdlib_bigfield, sqr_with_constant)
2174{
2175 TestFixture::test_sqr(InputType::CONSTANT);
2176}
2178{
2179 TestFixture::test_negate(InputType::WITNESS);
2180}
2182{
2183 TestFixture::test_mul_assign(InputType::WITNESS, InputType::WITNESS);
2184}
2185TYPED_TEST(stdlib_bigfield, mul_assignment_with_constant)
2186{
2187 TestFixture::test_mul_assign(InputType::WITNESS, InputType::CONSTANT);
2188 TestFixture::test_mul_assign(InputType::CONSTANT, InputType::WITNESS);
2189 TestFixture::test_mul_assign(InputType::CONSTANT, InputType::CONSTANT);
2190}
2192{
2193 TestFixture::test_add_assign(InputType::WITNESS, InputType::WITNESS);
2194}
2195TYPED_TEST(stdlib_bigfield, add_assignment_with_constant)
2196{
2197 TestFixture::test_add_assign(InputType::WITNESS, InputType::CONSTANT);
2198 TestFixture::test_add_assign(InputType::CONSTANT, InputType::WITNESS);
2199 TestFixture::test_add_assign(InputType::CONSTANT, InputType::CONSTANT);
2200}
2202{
2203 TestFixture::test_sub_assign(InputType::WITNESS, InputType::WITNESS);
2204}
2205TYPED_TEST(stdlib_bigfield, sub_assignment_with_constant)
2206{
2207 TestFixture::test_sub_assign(InputType::WITNESS, InputType::CONSTANT);
2208 TestFixture::test_sub_assign(InputType::CONSTANT, InputType::WITNESS);
2209 TestFixture::test_sub_assign(InputType::CONSTANT, InputType::CONSTANT);
2210}
2212{
2213 TestFixture::test_div_assign(InputType::WITNESS, InputType::WITNESS); // w / w
2214}
2215TYPED_TEST(stdlib_bigfield, div_assignment_with_constant)
2216{
2217 TestFixture::test_div_assign(InputType::WITNESS, InputType::CONSTANT); // w / c
2218 TestFixture::test_div_assign(InputType::CONSTANT, InputType::WITNESS); // c / w
2219 TestFixture::test_div_assign(InputType::CONSTANT, InputType::CONSTANT); // c / c
2220}
2222{
2223 TestFixture::test_madd(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w * w + w
2224}
2225TYPED_TEST(stdlib_bigfield, madd_with_constants)
2226{
2227 TestFixture::test_madd(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w * w + c
2228 TestFixture::test_madd(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // w * c + w
2229 TestFixture::test_madd(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // w * c + c
2230 TestFixture::test_madd(InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS); // c * w + w
2231 TestFixture::test_madd(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // c * w + c
2232 TestFixture::test_madd(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w * w + c
2233 TestFixture::test_madd(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // w * c + w
2234 TestFixture::test_madd(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // c * w + c
2235}
2237{
2238 TestFixture::test_sqradd(InputType::WITNESS, InputType::WITNESS); // w^2 + w
2239}
2240TYPED_TEST(stdlib_bigfield, sqradd_with_constant)
2241{
2242 TestFixture::test_sqradd(InputType::WITNESS, InputType::CONSTANT); // w^2 + c
2243 TestFixture::test_sqradd(InputType::CONSTANT, InputType::WITNESS); // c^2 + w
2244 TestFixture::test_sqradd(InputType::CONSTANT, InputType::CONSTANT); // c^2 + c
2245}
2247{
2248 TestFixture::test_mult_madd(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS); // ∑ (w * w + w)
2249}
2250TYPED_TEST(stdlib_bigfield, mult_madd_with_constants)
2251{
2252 TestFixture::test_mult_madd(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // ∑ (w * w + c)
2253 TestFixture::test_mult_madd(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // ∑ (w * c + w)
2254 TestFixture::test_mult_madd(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // ∑ (w * c + c)
2255 TestFixture::test_mult_madd(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT); // ∑ (c * c + c)
2256}
2257TYPED_TEST(stdlib_bigfield, mult_madd_edge_cases)
2258{
2259 // all witness except the last one
2260 TestFixture::test_mult_madd(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS, true);
2261 // all constant except the last one
2262 TestFixture::test_mult_madd(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT, true);
2263}
2265{
2266 TestFixture::test_dual_madd();
2267}
2268TYPED_TEST(stdlib_bigfield, div_without_denominator_check)
2269{
2270 TestFixture::test_div_without_denominator_check(InputType::WITNESS, InputType::WITNESS); // w / w
2271}
2272TYPED_TEST(stdlib_bigfield, div_without_denominator_check_with_constant)
2273{
2274 TestFixture::test_div_without_denominator_check(InputType::WITNESS, InputType::CONSTANT); // w / c
2275 TestFixture::test_div_without_denominator_check(InputType::CONSTANT, InputType::WITNESS); // c / w
2276 TestFixture::test_div_without_denominator_check(InputType::CONSTANT, InputType::CONSTANT); // c / c
2277}
2279{
2280 TestFixture::test_add_and_div();
2281}
2283{
2284 TestFixture::test_add_and_mul(InputType::WITNESS); // (w + w) * (w + w)
2285}
2286TYPED_TEST(stdlib_bigfield, add_and_mul_with_constants)
2287{
2288 TestFixture::test_add_and_mul(InputType::CONSTANT); // (w + c) * (w + c)
2289}
2291{
2292 TestFixture::test_sub_and_mul(InputType::WITNESS); // (w - w) * (w - w)
2293}
2294TYPED_TEST(stdlib_bigfield, sub_and_mul_with_constants)
2295{
2296 TestFixture::test_sub_and_mul(InputType::CONSTANT); // (w - c) * (w - c)
2297}
2299{
2300 TestFixture::test_msub_div(
2301 InputType::WITNESS, InputType::WITNESS, InputType::WITNESS); // (-w * w - w - w) / (w - w)
2302}
2303TYPED_TEST(stdlib_bigfield, msub_div_with_constants)
2304{
2305 TestFixture::test_msub_div(
2306 InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // (-w * w - w - c) / (w - w)
2307 TestFixture::test_msub_div(
2308 InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // (-w * c - w - w) / (w - w)
2309 TestFixture::test_msub_div(
2310 InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // (-w * c - w - c) / (w - w)
2311 TestFixture::test_msub_div(
2312 InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS); // (-c * w - c - w) / (w - w)
2313 TestFixture::test_msub_div(
2314 InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // (-c * w - c - c) / (w - w)
2315 TestFixture::test_msub_div(
2316 InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT); // (-c * c - c - c) / (w - w)
2317}
2318TYPED_TEST(stdlib_bigfield, conditional_assign)
2319{
2320 TestFixture::test_conditional_assign(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS); // w ? w : w
2321}
2322TYPED_TEST(stdlib_bigfield, conditional_assign_with_constants)
2323{
2324 TestFixture::test_conditional_assign(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w ? w : c
2325 TestFixture::test_conditional_assign(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // w ? c : w
2326 TestFixture::test_conditional_assign(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // w ? c : c
2327 TestFixture::test_conditional_assign(InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS); // c ? w : w
2328 TestFixture::test_conditional_assign(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // c ? w : c
2329 TestFixture::test_conditional_assign(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT); // c ? c : c
2330}
2331TYPED_TEST(stdlib_bigfield, conditional_select)
2332{
2333 TestFixture::test_conditional_select(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS); // w ? w : w
2334}
2335TYPED_TEST(stdlib_bigfield, conditional_select_with_constants)
2336{
2337 TestFixture::test_conditional_select(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w ? w : c
2338 TestFixture::test_conditional_select(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // w ? c : w
2339 TestFixture::test_conditional_select(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // w ? c : c
2340 TestFixture::test_conditional_select(InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS); // c ? w : w
2341 TestFixture::test_conditional_select(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // c ? w : c
2342 TestFixture::test_conditional_select(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT); // c ? c : c
2343}
2344TYPED_TEST(stdlib_bigfield, msb_div_ctx_crash_regression)
2345{
2346 TestFixture::test_msub_div_ctx_crash_regression();
2347}
2348TYPED_TEST(stdlib_bigfield, conditional_negate)
2349{
2350 TestFixture::test_conditional_negate(InputType::WITNESS, InputType::WITNESS); // w ? -w : w
2351}
2352TYPED_TEST(stdlib_bigfield, conditional_negate_with_constants)
2353{
2354 TestFixture::test_conditional_negate(InputType::WITNESS, InputType::CONSTANT); // w ? -c : w
2355 TestFixture::test_conditional_negate(InputType::CONSTANT, InputType::WITNESS); // c ? -w : w
2356 TestFixture::test_conditional_negate(InputType::CONSTANT, InputType::CONSTANT); // c ? -c : c
2357}
2358TYPED_TEST(stdlib_bigfield, group_operations)
2359{
2360 // skip this test if the field is not bn254 base field
2362 GTEST_SKIP() << "skipping group operations test for non-bn254 base field";
2363 }
2364 TestFixture::test_group_operations();
2365}
2367{
2368 TestFixture::test_reduce();
2369}
2371{
2372 TestFixture::test_equality_operator(InputType::WITNESS, InputType::WITNESS); // w == w
2373}
2374TYPED_TEST(stdlib_bigfield, equality_with_constants)
2375{
2376 TestFixture::test_equality_operator(InputType::WITNESS, InputType::CONSTANT); // w == c
2377 TestFixture::test_equality_operator(InputType::CONSTANT, InputType::WITNESS); // c == w
2378 TestFixture::test_equality_operator(InputType::CONSTANT, InputType::CONSTANT); // c == c
2379}
2380
2381TYPED_TEST(stdlib_bigfield, unsafe_assert_less_than)
2382{
2383 TestFixture::test_unsafe_assert_less_than();
2384}
2385TYPED_TEST(stdlib_bigfield, unsafe_assert_less_than_fails)
2386{
2387 TestFixture::test_unsafe_assert_less_than_fails();
2388}
2389TYPED_TEST(stdlib_bigfield, unsafe_evaluate_multiply_add)
2390{
2391 TestFixture::test_unsafe_evaluate_multiply_add();
2392}
2393TYPED_TEST(stdlib_bigfield, unsafe_evaluate_multiply_add_fails)
2394{
2395 TestFixture::test_unsafe_evaluate_multiply_add_fails();
2396}
2397TYPED_TEST(stdlib_bigfield, unsafe_evaluate_multiple_multiply_add)
2398{
2399 TestFixture::test_unsafe_multiple_multiply_add();
2400}
2401TYPED_TEST(stdlib_bigfield, unsafe_evaluate_multiple_multiply_add_fails)
2402{
2403 TestFixture::test_unsafe_multiple_multiply_add_fails();
2404}
2405
2406TYPED_TEST(stdlib_bigfield, assert_is_in_field_success)
2407{
2408 TestFixture::test_assert_is_in_field_success();
2409}
2410TYPED_TEST(stdlib_bigfield, assert_is_in_field_fails)
2411{
2412 TestFixture::test_assert_is_in_field_fails();
2413}
2414TYPED_TEST(stdlib_bigfield, assert_less_than_success)
2415{
2416 TestFixture::test_assert_less_than_success();
2417}
2418TYPED_TEST(stdlib_bigfield, assert_less_than_fails)
2419{
2420 TestFixture::test_assert_less_than_fails();
2421}
2422TYPED_TEST(stdlib_bigfield, reduce_mod_target_modulus)
2423{
2424 TestFixture::test_reduce_mod_target_modulus();
2425}
2426TYPED_TEST(stdlib_bigfield, byte_array_constructors)
2427{
2428 TestFixture::test_byte_array_constructors();
2429}
2430TYPED_TEST(stdlib_bigfield, quotient_completeness_regression)
2431{
2432 TestFixture::test_quotient_completeness();
2433}
2434
2435TYPED_TEST(stdlib_bigfield, conditional_select_regression)
2436{
2437 TestFixture::test_conditional_select_regression();
2438}
2439
2440TYPED_TEST(stdlib_bigfield, division_context)
2441{
2442 TestFixture::test_division_context();
2443}
2444
2446{
2447 TestFixture::test_inversion();
2448}
2449
2450TYPED_TEST(stdlib_bigfield, assert_equal_not_equal)
2451{
2452 TestFixture::test_assert_equal_not_equal();
2453}
2454
2456{
2457 TestFixture::test_pow();
2458}
2459
2461{
2462 TestFixture::test_pow_one();
2463}
2464TYPED_TEST(stdlib_bigfield, nonnormalized_field_bug_regression)
2465{
2466 TestFixture::test_nonnormalized_field_bug_regression();
2467}
2468
2469TYPED_TEST(stdlib_bigfield, internal_div_bug_regression)
2470{
2471 TestFixture::test_internal_div_regression();
2472 TestFixture::test_internal_div_regression2();
2473 TestFixture::test_internal_div_regression3();
2474}
#define BINARY_OP_TEST(op_name, bench_name, op_symbol, repetitions, reduced_inputs, reduction_after)
typename extract_builder< BigField >::type builder_t
typename extract_fq_params< BigField >::type params_t
InputType
constexpr InputType operator!(InputType type)
#define ASSIGNMENT_OP_TEST(op_name, bench_name, op_symbol, repetitions, reduced_inputs, reduction_after)
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:33
virtual uint8_t get_random_uint8()=0
virtual uint32_t get_random_uint32()=0
virtual uint256_t get_random_uint256()=0
constexpr uint256_t slice(uint64_t start, uint64_t end) const
std::pair< uintx, uintx > divmod(const uintx &b) const
static void unsafe_evaluate_multiple_multiply_add(const std::vector< bigfield > &input_left, const std::vector< bigfield > &input_right, const std::vector< bigfield > &to_add, const bigfield &input_quotient, const std::vector< bigfield > &input_remainders)
static void unsafe_evaluate_multiply_add(const bigfield &input_left, const bigfield &input_to_mul, const std::vector< bigfield > &to_add, const bigfield &input_quotient, const std::vector< bigfield > &input_remainders)
static void unsafe_assert_less_than(const bigfield &input, const uint256_t &upper_limit)
Implements boolean logic in-circuit.
Definition bool.hpp:59
bool get_value() const
Definition bool.hpp:124
void set_origin_tag(const OriginTag &new_tag) const
Definition bool.hpp:153
Represents a dynamic array of bytes in-circuit.
void set_origin_tag(bb::OriginTag tag)
static witness_t create_constant_witness(Builder *parent_context, const bb::fr &in)
Definition witness.hpp:45
typename bb::stdlib::bn254< Builder >::ScalarField fr_ct
static void test_nonnormalized_field_bug_regression()
static void test_internal_div_regression3()
static void test_conditional_assign(InputType a_type, InputType b_type, InputType predicate_type)
static void test_reduce_mod_target_modulus()
static void test_group_operations()
static void test_sum(InputType a_type, bool mixed_inputs=false)
static void test_assert_is_in_field_fails()
static void test_binary_operator_generic(InputType a_type, InputType b_type, CircuitOpFunc circuit_op, NativeOpFunc native_op, const char *op_name, size_t num_repetitions=10, bool need_reduced_inputs=false, bool need_reduction_after=false, bool do_tags_merge=true)
static void test_construct_from_limbs()
static void test_bad_mul()
static void test_add_to_lower_limb_regression()
static void test_assert_less_than_fails()
static void test_equality_operator(InputType a_type, InputType b_type)
static void test_conditional_select(InputType a_type, InputType b_type, InputType predicate_type)
static void test_pow()
static void test_add_and_mul(InputType summand_type)
static std::pair< std::vector< fq_native >, std::vector< fq_ct > > get_random_witnesses(Builder *builder, size_t num, bool reduce_input=false)
static void test_unsafe_multiple_multiply_add()
static void test_quotient_completeness()
static void test_unsafe_evaluate_multiply_add()
static void test_msub_div_ctx_crash_regression()
static void test_unsafe_multiple_multiply_add_fails()
static void test_constructor_from_two_elements()
static void test_reduce()
static void test_assert_less_than_success()
static std::pair< fq_native, fq_ct > get_random_constant(Builder *builder, bool reduce_input=false)
static void test_sqradd(InputType a_type, InputType b_type)
builder_t< BigField > Builder
static void test_assert_is_in_field_success()
static void test_add_two(InputType a_type, InputType b_type, InputType c_type)
static void test_inversion()
static void test_add_and_div()
static void test_byte_array_constructors()
static void test_negate(InputType a_type)
static void test_msub_div(InputType multiplicand_type, InputType to_sub_type, InputType divisor_type)
static std::pair< fq_native, fq_ct > get_random_element(Builder *builder, bool reduce_input=false)
static std::pair< fq_native, fq_ct > get_random_witness(Builder *builder, bool reduce_input=false)
static std::pair< std::vector< fq_native >, std::vector< fq_ct > > get_random_elements(Builder *builder, InputType type, size_t num, bool reduce_input=false)
static void test_sqr(InputType a_type)
static std::pair< fq_native, fq_ct > get_random_element(Builder *builder, InputType type, bool reduce_input=false)
static void test_div_without_denominator_check(InputType a_type, InputType b_type)
static void test_sub_and_mul(InputType subtrahend_type)
static void test_assert_not_equal_regression()
static void test_internal_div_regression2()
static void test_basic_tag_logic()
static void test_madd(InputType a_type, InputType b_type, InputType c_type)
static void test_conditional_negate(InputType a_type, InputType predicate_type)
static void test_unsafe_construct_from_limbs()
stdlib::bool_t< Builder > bool_ct
static std::pair< std::vector< fq_native >, std::vector< fq_ct > > get_random_constants(Builder *builder, size_t num, bool reduce_input=false)
static void test_assign_operator_generic(InputType a_type, InputType b_type, CircuitOpFunc circuit_op, NativeOpFunc native_op, const char *op_name, size_t num_repetitions=4, bool need_reduced_inputs=false, bool need_reduction_after=false)
static void test_internal_div_regression()
static void test_dual_madd()
static void test_mult_madd(InputType left_type, InputType right_type, InputType to_add_type, bool edge_case=false)
stdlib::witness_t< Builder > witness_ct
static void test_unsafe_assert_less_than_fails()
static void test_unsafe_assert_less_than()
static void test_construct_from_limbs_fails()
static void test_assert_equal_not_equal()
static void test_unsafe_evaluate_multiply_add_fails()
static void test_conditional_select_regression()
static void test_division_context()
static void test_division_formula_bug()
bb::field< params_t< BigField > > fq_native
static void test_pow_one()
#define BENCH_GATE_COUNT_END(builder, op_name)
Definition log.hpp:17
#define BENCH_GATE_COUNT_START(builder, op_name)
Definition log.hpp:14
void info(Args... args)
Definition log.hpp:75
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
ECCVMCircuitBuilder Builder
numeric::RNG & engine
crypto::Poseidon2Bn254ScalarFieldParams Params
uintx< uint256_t > uint512_t
Definition uintx.hpp:307
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
uintx< uint512_t > uint1024_t
Definition uintx.hpp:309
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
@ SUB
Subtract two field elements.
@ DIV
Divide two field elements.
@ MUL
Multiply two field elements.
@ ADD_ASSIGN
Add-assign operation.
@ DIV_ASSIGN
Divide-assign operation.
@ MUL_ASSIGN
Multiply-assign operation.
@ ADD
Add two field elements.
@ SUB_ASSIGN
Subtract-assign operation.
field< Bn254FrParams > fr
Definition fr.hpp:174
C slice(C const &container, size_t start)
Definition container.hpp:9
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
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
#define STANDARD_TESTING_TAGS
testing::Types< bb::MegaCircuitBuilder, bb::UltraCircuitBuilder > CircuitTypes
General class for prime fields see Prime field documentation["field documentation"] for general imple...
static constexpr uint256_t modulus
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
constexpr field invert() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field sqr() const noexcept
static void serialize_to_buffer(const field &value, uint8_t *buffer)
BB_INLINE constexpr field from_montgomery_form() const noexcept
BB_INLINE constexpr field reduce_once() const noexcept
static constexpr field zero()