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
193 InputType type,
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_estimated_num_finalized_gates();
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_estimated_num_finalized_gates();
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
1473 {
1474 auto builder = Builder();
1475 size_t num_repetitions = 10;
1476 for (size_t i = 0; i < num_repetitions; ++i) {
1477 auto [a_native, a_ct] = get_random_witness(&builder, true); // fq_native, fq_ct
1478 byte_array_ct a_bytes_ct = a_ct.to_byte_array();
1479
1480 std::vector<fr_ct> actual_bytes = a_bytes_ct.bytes();
1481 EXPECT_EQ(actual_bytes.size(), 32);
1482
1483 for (size_t j = 0; j < actual_bytes.size(); ++j) {
1484 const uint256_t expected = (uint256_t(a_native) >> (8 * j)).slice(0, 8);
1485 EXPECT_EQ(actual_bytes[32 - 1 - j].get_value(), expected);
1486 }
1487 }
1488 bool result = CircuitChecker::check(builder);
1489 EXPECT_EQ(result, true);
1490 }
1491
1492 // This check tests if elements are reduced to fit quotient into range proof
1494 {
1495 auto builder = Builder();
1496 const uint256_t input =
1497 uint256_t(0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffffff);
1498
1499 fq_ct a(witness_ct(&builder, fr(uint256_t(input).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1500 witness_ct(&builder, fr(uint256_t(input).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))),
1501 false);
1502 auto a1 = a;
1503 auto a2 = a;
1504 auto a3 = a;
1505 auto a4 = a;
1506
1507 for (auto i = 0; i < 8; i++) {
1508 a = a + a;
1509 a1 = a1 + a1;
1510 a2 = a2 + a2;
1511 a3 = a3 + a3;
1512 a4 = a4 + a4;
1513 }
1514
1515 auto b = a * a;
1516 (void)b;
1517
1518 auto c = a1.sqr();
1519 (void)c;
1520
1521 auto d = a2.sqradd({});
1522 (void)d;
1523
1524 auto e = a3.madd(a3, {});
1525 (void)e;
1526
1527 auto f = fq_ct::mult_madd({ a4 }, { a4 }, {}, false);
1528 (void)f;
1529
1530 bool result = CircuitChecker::check(builder);
1531 EXPECT_EQ(result, true);
1532 }
1533
1535 {
1536 auto builder = Builder();
1537 fq_native a(0);
1538 fq_native b(1);
1539 fq_ct a_ct(&builder, a);
1540 fq_ct b_ct(&builder, b);
1541 fq_ct selected = a_ct.conditional_select(b_ct, bool_ct(&builder, true));
1542 EXPECT_EQ(fq_native((selected.get_value() % uint512_t(fq_native::modulus)).lo), b);
1543 }
1544
1546 {
1547 auto builder = Builder();
1548 fq_native a(1);
1549 fq_ct a_ct(&builder, a);
1550 fq_ct ret = fq_ct::div_check_denominator_nonzero({}, a_ct);
1551 EXPECT_NE(ret.get_context(), nullptr);
1552 }
1553
1554 static void test_inversion()
1555 {
1556 fq_ct a = fq_ct(-7);
1557 fq_ct a_inverse = a.invert();
1558 fq_ct a_inverse_division = fq_ct(1) / a;
1559
1560 fq_native a_native = fq_native(-7);
1561 fq_native a_native_inverse = a_native.invert();
1562 EXPECT_EQ(fq_native((a.get_value() % uint512_t(fq_native::modulus)).lo), a_native);
1563 EXPECT_EQ(fq_native((a_inverse.get_value() % uint512_t(fq_native::modulus)).lo), a_native_inverse);
1564 EXPECT_EQ(fq_native((a_inverse_division.get_value() % uint512_t(fq_native::modulus)).lo), a_native_inverse);
1565 }
1566
1568 {
1569 auto builder = Builder();
1570 size_t num_repetitions = 10;
1571 for (size_t i = 0; i < num_repetitions; ++i) {
1572 auto [a_native, a_ct] = get_random_witness(&builder); // fq_native, fq_ct
1573 auto [c_native, c_ct] = get_random_witness(&builder); // fq_native, fq_ct
1574 auto [d_native, d_ct] = get_random_witness(&builder); // fq_native, fq_ct
1575
1576 fq_ct two_ct = fq_ct::unsafe_construct_from_limbs(witness_ct(&builder, fr(2)),
1577 witness_ct(&builder, fr(0)),
1578 witness_ct(&builder, fr(0)),
1579 witness_ct(&builder, fr(0)));
1580 fq_ct t0 = a_ct + a_ct;
1581 fq_ct t1 = a_ct * two_ct;
1582
1583 t0.assert_equal(t1);
1584 t0.assert_is_not_equal(c_ct);
1585 t0.assert_is_not_equal(d_ct);
1586 stdlib::bool_t<Builder> is_equal_a = t0 == t1;
1587 stdlib::bool_t<Builder> is_equal_b = t0 == c_ct;
1588 EXPECT_TRUE(is_equal_a.get_value());
1589 EXPECT_FALSE(is_equal_b.get_value());
1590 }
1591 bool result = CircuitChecker::check(builder);
1592 EXPECT_EQ(result, true);
1593 }
1594
1595 static void test_pow()
1596 {
1598
1599 fq_native base_val(engine.get_random_uint256());
1600 uint32_t exponent_val = engine.get_random_uint32();
1601 // Set the high bit
1602 exponent_val |= static_cast<uint32_t>(1) << 31;
1603 fq_ct base_constant(&builder, static_cast<uint256_t>(base_val));
1604 fq_ct base_witness_ct = fq_ct::from_witness(&builder, static_cast<uint256_t>(base_val));
1605 // This also tests for the case where the exponent is zero
1606 for (size_t i = 0; i <= 32; i += 4) {
1607 uint32_t current_exponent_val = exponent_val >> i;
1608 fq_native expected = base_val.pow(current_exponent_val);
1609
1610 // Check for constant bigfield element with constant exponent
1611 fq_ct result_constant_base = base_constant.pow(current_exponent_val);
1612 EXPECT_EQ(fq_native(result_constant_base.get_value()), expected);
1613
1614 // Check for witness base with constant exponent
1615 fq_ct result_witness_base = base_witness_ct.pow(current_exponent_val);
1616 EXPECT_EQ(fq_native(result_witness_base.get_value()), expected);
1617
1618 base_witness_ct.set_origin_tag(submitted_value_origin_tag);
1619 }
1620
1621 bool check_result = CircuitChecker::check(builder);
1622 EXPECT_EQ(check_result, true);
1623 }
1624
1625 static void test_pow_one()
1626 {
1628
1629 fq_native base_val(engine.get_random_uint256());
1630
1631 uint32_t current_exponent_val = 1;
1632 fq_ct base_constant_ct(&builder, static_cast<uint256_t>(base_val));
1633 fq_ct base_witness_ct = fq_ct::from_witness(&builder, static_cast<uint256_t>(base_val));
1634 fq_native expected = base_val.pow(current_exponent_val);
1635
1636 // Check for constant bigfield element with constant exponent
1637 fq_ct result_constant_base = base_constant_ct.pow(current_exponent_val);
1638 EXPECT_EQ(fq_native(result_constant_base.get_value()), expected);
1639
1640 // Check for witness base with constant exponent
1641 fq_ct result_witness_base = base_witness_ct.pow(current_exponent_val);
1642 EXPECT_EQ(fq_native(result_witness_base.get_value()), expected);
1643
1644 bool check_result = CircuitChecker::check(builder);
1645 EXPECT_EQ(check_result, true);
1646 }
1647
1649 {
1650 auto builder = Builder();
1651 size_t num_repetitions = 10;
1652 constexpr size_t num_bits = 200;
1653 constexpr uint256_t bit_mask = (uint256_t(1) << num_bits) - 1;
1654 for (size_t i = 0; i < num_repetitions; ++i) {
1655
1656 uint256_t a_u256 = uint256_t(fq_native::random_element()) & bit_mask;
1657 uint256_t b_u256 = uint256_t(fq_native::random_element()) & bit_mask;
1658
1659 // Construct 200-bit bigfield elements
1660 fq_ct a_ct(witness_ct(&builder, fr(a_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1661 witness_ct(&builder, fr(a_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1662 fq_ct b_ct(witness_ct(&builder, fr(b_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1663 witness_ct(&builder, fr(b_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1664
1665 // Assert a, b < 2^200
1668 EXPECT_EQ(a_ct.get_value().get_msb() < num_bits, true);
1669 EXPECT_EQ(b_ct.get_value().get_msb() < num_bits, true);
1670 }
1671
1672 // Also test when: p < a < bound
1673 // define a = p + small_random_value
1674 uint256_t small_mask = (uint256_t(1) << 16) - 1;
1675 uint256_t a_u256 = uint256_t(fq_native::random_element()) & small_mask;
1676 a_u256 += uint256_t(fq_native::modulus);
1677
1678 // upper bound must be greater than p + 2^16: we set it to p + 2^30
1679 uint256_t upper_bound = (uint256_t(1) << 30) + uint256_t(fq_native::modulus);
1680
1681 // Construct bigfield element
1682 fq_ct a_ct(witness_ct(&builder, fr(a_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1683 witness_ct(&builder, fr(a_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))),
1684 /*can_overflow*/ true);
1685
1686 // Assert a < bound
1688 EXPECT_EQ(a_ct.get_value() > uint512_t(fq_native::modulus), true);
1689
1690 // Combined circuit should pass
1691 bool result = CircuitChecker::check(builder);
1692 EXPECT_EQ(result, true);
1693 }
1694
1696 {
1697 {
1698 // Test a case when the value is exactly equal to the limit
1699 auto builder = Builder();
1700 constexpr size_t num_bits = 200;
1701 constexpr uint256_t bit_mask = (uint256_t(1) << num_bits) - 1;
1702 fq_ct a_ct(witness_ct(&builder, fr(bit_mask.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1703 witness_ct(&builder, fr(bit_mask.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1704
1705 // check that unsafe_assert_less_than fails when we try to check a < a.
1707
1708 bool result = CircuitChecker::check(builder);
1709 EXPECT_EQ(result, false);
1710 }
1711 {
1712 // Test a case when the value is (B + 2) but the bound is B.
1713 auto builder = Builder();
1714 constexpr size_t num_bits = 200;
1715 constexpr uint256_t bit_mask = (uint256_t(1) << num_bits) - 1;
1716 const uint256_t upper_bound = uint256_t(fq_native::random_element()) & bit_mask;
1717 const uint256_t a_value = upper_bound + uint256_t(2);
1718 fq_ct a_ct(witness_ct(&builder, fr(a_value.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1719 witness_ct(&builder, fr(a_value.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
1720
1721 // check that unsafe_assert_less_than fails when we try to check (B + 2) < B.
1723
1724 bool result = CircuitChecker::check(builder);
1725 EXPECT_EQ(result, false);
1726 }
1727 {
1728 // Test a case when p < bound < a
1729 auto builder = Builder();
1730 uint256_t small_mask = (uint256_t(1) << 32) - 1;
1731 uint256_t a_u256 = uint256_t(fq_native::random_element()) & small_mask;
1732 a_u256 += uint256_t(fq_native::modulus);
1733
1734 // upper bound must be greater than p but smaller than a
1735 uint256_t upper_bound = uint256_t(fq_native::modulus) + uint256_t(1);
1736
1737 // Construct bigfield element
1738 fq_ct a_ct(witness_ct(&builder, fr(a_u256.slice(0, fq_ct::NUM_LIMB_BITS * 2))),
1739 witness_ct(&builder, fr(a_u256.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))),
1740 /*can_overflow*/ true);
1741
1742 // check that unsafe_assert_less_than fails when we try to check a < bound.
1744
1745 bool result = CircuitChecker::check(builder);
1746 EXPECT_EQ(result, false);
1747 }
1748 }
1749
1751 {
1753
1754 // The circuit enforces:
1755 // a * b + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod 2^T
1756 // a * b + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod n
1757
1758 // Single addend and remainder
1759 auto [a_native, a_ct] = get_random_witness(&builder);
1760 auto [b_native, b_ct] = get_random_witness(&builder);
1761 auto [c_native, c_ct] = get_random_witness(&builder);
1762
1763 // Get quotient and remainder for (a * b + c) from native values
1764 uint1024_t native_sum = uint1024_t(a_native) * uint1024_t(b_native) + uint1024_t(c_native);
1765 auto [q_native_1024, r_native_1024] = native_sum.divmod(uint1024_t(fq_ct::modulus));
1766 const uint512_t q_native_512 = q_native_1024.lo;
1767 const uint512_t r_native_512 = r_native_1024.lo;
1768 fq_ct q_ct = fq_ct::create_from_u512_as_witness(&builder, q_native_512, true);
1769 fq_ct r_ct = fq_ct::create_from_u512_as_witness(&builder, r_native_512, true);
1770
1771 // Call unsafe_evaluate_multiply_add (via friendly class)
1772 stdlib::bigfield_test_access::unsafe_evaluate_multiply_add(a_ct, b_ct, { c_ct }, q_ct, { r_ct });
1773
1774 // The above function does not protect against CRT overflows, i.e., check if lhs and rhs are less than
1775 // M = (2^T * n). Verify that adding a multiple of M to both sides does not result in an unsatisfiable circuit.
1776 uint512_t big_M = uint512_t(fr::modulus) * fq_ct::binary_basis.modulus;
1777 uint512_t modified_c_native = uint512_t(c_native) + big_M;
1778 uint512_t modified_r_native = uint512_t(r_native_512) + big_M;
1779 fq_ct modified_c_ct = fq_ct::create_from_u512_as_witness(&builder, modified_c_native, true);
1780 fq_ct modified_r_ct = fq_ct::create_from_u512_as_witness(&builder, modified_r_native, true);
1781
1782 // Call unsafe_evaluate_multiply_add (via friendly class)
1784 a_ct, b_ct, { modified_c_ct }, q_ct, { modified_r_ct });
1785
1786 // Native verification mod p
1787 fq_native expected_lhs = a_native * b_native + c_native;
1788 fq_native expected_rhs = fq_native(q_native_512) * fq_ct::modulus + fq_native(r_native_512);
1789 EXPECT_EQ(expected_lhs, expected_rhs);
1790
1791 // Native verification mod 2^T
1792 uint1024_t lhs_1024 = uint512_t(a_native) * uint512_t(b_native) + uint512_t(c_native);
1793 uint1024_t rhs_1024 = q_native_512 * fq_ct::modulus + r_native_512;
1794 auto [quotient_lhs, remainder_lhs] = lhs_1024.divmod(fq_ct::binary_basis.modulus);
1795 auto [quotient_rhs, remainder_rhs] = rhs_1024.divmod(fq_ct::binary_basis.modulus);
1796 EXPECT_EQ(remainder_lhs, remainder_rhs);
1797
1798 // Native verification mod n
1799 fr expected_lhs_fr = fr(a_native) * fr(b_native) + fr(c_native);
1800 fr expected_rhs_fr = fr(q_native_512) * fr(fq_ct::modulus) + fr(r_native_512);
1801 EXPECT_EQ(expected_lhs_fr, expected_rhs_fr);
1802
1803 // Check circuit correctness
1804 bool result = CircuitChecker::check(builder);
1805 EXPECT_EQ(result, true);
1806 }
1807
1809 {
1810 auto builder = Builder();
1811
1812 // The circuit enforces:
1813 // a * b + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod 2^T
1814 // a * b + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod n
1815
1816 // Single addend and remainder
1817 auto [a_native, a_ct] = get_random_witness(&builder);
1818 auto [b_native, b_ct] = get_random_witness(&builder);
1819 auto [c_native, c_ct] = get_random_witness(&builder);
1820
1821 // Get quotient and remainder for (a * b + c) from native values
1822 uint512_t native_sum = uint512_t(a_native) * uint512_t(b_native) + uint512_t(c_native);
1823 auto [q_native_uint512_t, r_native_uint512_t] = native_sum.divmod(uint512_t(fq_ct::modulus));
1824 fq_ct q_ct = fq_ct::create_from_u512_as_witness(
1825 &builder, q_native_uint512_t + uint512_t(1), true); // Intentionally poisoned
1826 fq_ct r_ct = fq_ct::create_from_u512_as_witness(&builder, r_native_uint512_t, true);
1827
1828 // Call unsafe_evaluate_multiply_add (via friendly class)
1829 stdlib::bigfield_test_access::unsafe_evaluate_multiply_add(a_ct, b_ct, { c_ct }, q_ct, { r_ct });
1830
1831 // Check circuit correctness
1832 bool result = CircuitChecker::check(builder);
1833 EXPECT_EQ(result, false);
1834 EXPECT_EQ(builder.err(), "bigfield: prime limb identity failed");
1835 }
1836
1838 {
1840
1841 // The circuit enforces:
1842 // a1 * b1 + a2 * b2 + ... + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod 2^T
1843 // a1 * b1 + a2 * b2 + ... + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod n
1844 size_t num_terms = 3;
1845 std::vector<fq_native> a_natives;
1846 std::vector<fq_native> b_natives;
1847 std::vector<fq_ct> a_cts;
1848 std::vector<fq_ct> b_cts;
1849
1850 for (size_t i = 0; i < num_terms; ++i) {
1851 auto [a_native, a_ct] = get_random_witness(&builder);
1852 auto [b_native, b_ct] = get_random_witness(&builder);
1853 a_natives.push_back(a_native);
1854 b_natives.push_back(b_native);
1855 a_cts.push_back(a_ct);
1856 b_cts.push_back(b_ct);
1857 }
1858
1859 auto [c_native, c_ct] = get_random_witness(&builder);
1860
1861 // Get quotient and remainder for (sum of ai * bi + c) from native values
1862 uint1024_t native_sum = uint1024_t(c_native);
1863 for (size_t i = 0; i < num_terms; ++i) {
1864 native_sum += uint1024_t(a_natives[i]) * uint1024_t(b_natives[i]);
1865 }
1866 auto [q_native_1024, r_native_1024] = native_sum.divmod(uint512_t(fq_ct::modulus));
1867 const uint512_t q_native_512 = q_native_1024.lo;
1868 const uint512_t r_native_512 = r_native_1024.lo;
1869 fq_ct q_ct = fq_ct::create_from_u512_as_witness(&builder, q_native_512, true);
1870 fq_ct r_ct = fq_ct::create_from_u512_as_witness(&builder, r_native_512, true);
1871
1872 // Call unsafe_evaluate_multiply_add (via friendly class)
1873 stdlib::bigfield_test_access::unsafe_evaluate_multiple_multiply_add(a_cts, b_cts, { c_ct }, q_ct, { r_ct });
1874
1875 // Native verification mod p
1876 fq_native expected_lhs = fq_native(c_native);
1877 for (size_t i = 0; i < num_terms; ++i) {
1878 expected_lhs += fq_native(a_natives[i]) * fq_native(b_natives[i]);
1879 }
1880 fq_native expected_rhs = fq_native(q_native_512) * fq_ct::modulus + fq_native(r_native_512);
1881 EXPECT_EQ(expected_lhs, expected_rhs);
1882
1883 // Native verification mod 2^T
1884 uint1024_t lhs_1024 = uint1024_t(c_native);
1885 for (size_t i = 0; i < num_terms; ++i) {
1886 lhs_1024 += uint1024_t(a_natives[i]) * uint1024_t(b_natives[i]);
1887 }
1888 uint1024_t rhs_1024 = q_native_512 * fq_ct::modulus + r_native_512;
1889 auto [quotient_lhs, remainder_lhs] = lhs_1024.divmod(fq_ct::binary_basis.modulus);
1890 auto [quotient_rhs, remainder_rhs] = rhs_1024.divmod(fq_ct::binary_basis.modulus);
1891 EXPECT_EQ(remainder_lhs, remainder_rhs);
1892
1893 // Native verification mod n
1894 fr expected_lhs_fr = fr(c_native);
1895 for (size_t i = 0; i < num_terms; ++i) {
1896 expected_lhs_fr += fr(a_natives[i]) * fr(b_natives[i]);
1897 }
1898 fr expected_rhs_fr = fr(q_native_512) * fr(fq_ct::modulus) + fr(r_native_512);
1899 EXPECT_EQ(expected_lhs_fr, expected_rhs_fr);
1900
1901 // Check circuit correctness
1902 bool result = CircuitChecker::check(builder);
1903 EXPECT_EQ(result, true);
1904 }
1905
1907 {
1909
1910 // The circuit enforces:
1911 // a1 * b1 + a2 * b2 + ... + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod 2^T
1912 // a1 * b1 + a2 * b2 + ... + (c0 + c1 + ...) = q * p + (r0 + r1 + ...) mod n
1913 size_t num_terms = 3;
1914 std::vector<fq_native> a_natives;
1915 std::vector<fq_native> b_natives;
1916 std::vector<fq_ct> a_cts;
1917 std::vector<fq_ct> b_cts;
1918
1919 for (size_t i = 0; i < num_terms; ++i) {
1920 auto [a_native, a_ct] = get_random_witness(&builder);
1921 auto [b_native, b_ct] = get_random_witness(&builder);
1922 a_natives.push_back(a_native);
1923 b_natives.push_back(b_native);
1924 a_cts.push_back(a_ct);
1925 b_cts.push_back(b_ct);
1926 }
1927
1928 auto [c_native, c_ct] = get_random_witness(&builder);
1929
1930 // Get quotient and remainder for (sum of ai * bi + c) from native values
1931 uint1024_t native_sum = uint1024_t(c_native);
1932 for (size_t i = 0; i < num_terms; ++i) {
1933 native_sum += uint1024_t(a_natives[i]) * uint1024_t(b_natives[i]);
1934 }
1935 auto [q_native_1024, r_native_1024] = native_sum.divmod(uint1024_t(fq_ct::modulus));
1936 fq_ct q_ct = fq_ct::create_from_u512_as_witness(
1937 &builder, q_native_1024.lo + uint512_t(1), true); // Intentionally poisoned
1938 fq_ct r_ct = fq_ct::create_from_u512_as_witness(&builder, r_native_1024.lo, true);
1939
1940 // Call unsafe_evaluate_multiply_add (via friendly class)
1941 stdlib::bigfield_test_access::unsafe_evaluate_multiple_multiply_add(a_cts, b_cts, { c_ct }, q_ct, { r_ct });
1942
1943 // Check circuit correctness
1944 bool result = CircuitChecker::check(builder);
1945 EXPECT_EQ(result, false);
1946 EXPECT_EQ(builder.err(), "bigfield: prime limb identity failed");
1947 }
1948
1950 {
1951 auto builder = Builder();
1953 uint256_t two_to_68 = uint256_t(1) << fq_ct::NUM_LIMB_BITS;
1954 // construct bigfield where the low limb has a non-trivial `additive_constant`
1955 fq_ct z(zero + two_to_68, zero);
1956 // assert invariant for every limb: actual value <= maximum value
1957 // Failed in the past for for StandardCircuitBuilder
1958 for (auto zi : z.binary_basis_limbs) {
1959 EXPECT_LE(uint256_t(zi.element.get_value()), zi.maximum_value);
1960 }
1961 }
1962
1964 {
1965 auto builder = Builder();
1966 fq_ct witness_one = fq_ct::create_from_u512_as_witness(&builder, uint256_t(1));
1967 fq_ct constant_one(1);
1968 fq_ct::msub_div({ witness_one }, { witness_one }, constant_one, { witness_one }, true);
1969 bool result = CircuitChecker::check(builder);
1970 EXPECT_EQ(result, true);
1971 }
1972
1974 {
1975 typedef stdlib::bool_t<Builder> bool_t;
1976 auto builder = Builder();
1977
1978 fq_ct w0 = fq_ct::from_witness(&builder, 1);
1979 w0 = w0.conditional_negate(bool_t(&builder, true));
1980 w0 = w0.conditional_negate(bool_t(&builder, false));
1981 w0 = w0.conditional_negate(bool_t(&builder, true));
1982 w0 = w0.conditional_negate(bool_t(&builder, true));
1983 fq_ct w4 = w0.conditional_negate(bool_t(&builder, false));
1984 w4 = w4.conditional_negate(bool_t(&builder, true));
1985 w4 = w4.conditional_negate(bool_t(&builder, true));
1986 fq_ct w5 = w4 - w0;
1987 fq_ct w6 = w5 / 1;
1988 (void)(w6);
1989 EXPECT_TRUE(CircuitChecker::check(builder));
1990 }
1991
1993 {
1994 auto builder = Builder();
1995
1996 fq_ct numerator = fq_ct::create_from_u512_as_witness(&builder, uint256_t(1) << (68 + 67));
1997 numerator.binary_basis_limbs[0].maximum_value = 0;
1998 numerator.binary_basis_limbs[1].maximum_value = uint256_t(1) << 67;
1999 numerator.binary_basis_limbs[2].maximum_value = 0;
2000 numerator.binary_basis_limbs[3].maximum_value = 0;
2001
2002 for (size_t i = 0; i < 9; i++) {
2003 numerator = numerator + numerator;
2004 }
2005 fq_ct denominator = fq_ct::create_from_u512_as_witness(&builder, uint256_t(1));
2006 fq_ct result = numerator / denominator;
2007 (void)(result);
2008 EXPECT_TRUE(CircuitChecker::check(builder));
2009 }
2010
2012 {
2014 uint256_t dlimb0_value = uint256_t("0x00000000000000000000000000000000000000000000000bef7fa109038857fc");
2015 uint256_t dlimb0_max = uint256_t("0x00000000000000000000000000000000000000000000000fffffffffffffffff");
2016 uint256_t dlimb1_value = uint256_t("0x0000000000000000000000000000000000000000000000056f10535779f56339");
2017 uint256_t dlimb1_max = uint256_t("0x00000000000000000000000000000000000000000000000fffffffffffffffff");
2018 uint256_t dlimb2_value = uint256_t("0x00000000000000000000000000000000000000000000000c741f60a1ec4e114e");
2019 uint256_t dlimb2_max = uint256_t("0x00000000000000000000000000000000000000000000000fffffffffffffffff");
2020 uint256_t dlimb3_value = uint256_t("0x000000000000000000000000000000000000000000000000000286b3cd344d8b");
2021 uint256_t dlimb3_max = uint256_t("0x0000000000000000000000000000000000000000000000000003ffffffffffff");
2022 uint256_t dlimb_prime = uint256_t("0x286b3cd344d8bc741f60a1ec4e114e56f10535779f56339bef7fa109038857fc");
2023
2024 uint256_t nlimb0_value = uint256_t("0x00000000000000000000000000000000000000000000080a84d9bea2b012417c");
2025 uint256_t nlimb0_max = uint256_t("0x000000000000000000000000000000000000000000000ff7c7469df4081b61fc");
2026 uint256_t nlimb1_value = uint256_t("0x00000000000000000000000000000000000000000000080f50ee84526e8e5ba7");
2027 uint256_t nlimb1_max = uint256_t("0x000000000000000000000000000000000000000000000ffef965c67ba5d5893c");
2028 uint256_t nlimb2_value = uint256_t("0x00000000000000000000000000000000000000000000080aba136ca8eaf6dc1b");
2029 uint256_t nlimb2_max = uint256_t("0x000000000000000000000000000000000000000000000ff8171d22fd607249ea");
2030 uint256_t nlimb3_value = uint256_t("0x00000000000000000000000000000000000000000000000001f0042419843c29");
2031 uint256_t nlimb3_max = uint256_t("0x00000000000000000000000000000000000000000000000003e00636264659ff");
2032 uint256_t nlimb_prime = uint256_t("0x000000000000000000000000000000474da776b8ee19a56b08186bdcf01240d8");
2033
2034 fq_ct w0 = fq_ct::from_witness(&builder, fq_native(0));
2035 w0.binary_basis_limbs[0].element = witness_ct(&builder, dlimb0_value);
2036 w0.binary_basis_limbs[1].element = witness_ct(&builder, dlimb1_value);
2037 w0.binary_basis_limbs[2].element = witness_ct(&builder, dlimb2_value);
2038 w0.binary_basis_limbs[3].element = witness_ct(&builder, dlimb3_value);
2039 w0.binary_basis_limbs[0].maximum_value = dlimb0_max;
2040 w0.binary_basis_limbs[1].maximum_value = dlimb1_max;
2041 w0.binary_basis_limbs[2].maximum_value = dlimb2_max;
2042 w0.binary_basis_limbs[3].maximum_value = dlimb3_max;
2043 w0.prime_basis_limb = witness_ct(&builder, dlimb_prime);
2044
2045 fq_ct w1 = fq_ct::from_witness(&builder, fq_native(0));
2046 w1.binary_basis_limbs[0].element = witness_ct(&builder, nlimb0_value);
2047 w1.binary_basis_limbs[1].element = witness_ct(&builder, nlimb1_value);
2048 w1.binary_basis_limbs[2].element = witness_ct(&builder, nlimb2_value);
2049 w1.binary_basis_limbs[3].element = witness_ct(&builder, nlimb3_value);
2050 w1.binary_basis_limbs[0].maximum_value = nlimb0_max;
2051 w1.binary_basis_limbs[1].maximum_value = nlimb1_max;
2052 w1.binary_basis_limbs[2].maximum_value = nlimb2_max;
2053 w1.binary_basis_limbs[3].maximum_value = nlimb3_max;
2054 w1.prime_basis_limb = witness_ct(&builder, nlimb_prime);
2055
2056 fq_ct w2 = w1 / w0;
2057 (void)w2;
2058 EXPECT_TRUE(CircuitChecker::check(builder));
2059 }
2060
2062 {
2063 auto builder = Builder();
2064 fq_ct zero = fq_ct::create_from_u512_as_witness(&builder, uint256_t(0));
2065 fq_ct alsozero = fq_ct::create_from_u512_as_witness(&builder, fq_ct::modulus_u512);
2066 for (size_t i = 0; i < 4; i++) {
2067 zero.binary_basis_limbs[i].maximum_value = zero.binary_basis_limbs[i].element.get_value();
2068 alsozero.binary_basis_limbs[i].maximum_value = alsozero.binary_basis_limbs[i].element.get_value();
2069 }
2070 zero.assert_is_not_equal(alsozero);
2071 bool result = CircuitChecker::check(builder);
2072 EXPECT_EQ(result, false);
2073 }
2074};
2075
2076// Define types for which the above tests will be constructed.
2077using CircuitTypes = testing::Types<typename bb::stdlib::bn254<UltraCircuitBuilder>::BaseField,
2082// Define the suite of tests.
2084
2085TYPED_TEST(stdlib_bigfield, assert_not_equal_regression)
2086{
2087 TestFixture::test_assert_not_equal_regression();
2088}
2089
2090TYPED_TEST(stdlib_bigfield, add_to_lower_limb_regression)
2091{
2092 TestFixture::test_add_to_lower_limb_regression();
2093}
2095{
2096 TestFixture::test_bad_mul();
2097}
2098
2099TYPED_TEST(stdlib_bigfield, division_formula_regression)
2100{
2101 TestFixture::test_division_formula_bug();
2102}
2104{
2105 TestFixture::test_basic_tag_logic();
2106}
2107TYPED_TEST(stdlib_bigfield, test_constructor)
2108{
2109 TestFixture::test_constructor_from_two_elements();
2110}
2111TYPED_TEST(stdlib_bigfield, test_unsafe_construct_from_limbs)
2112{
2113 TestFixture::test_unsafe_construct_from_limbs();
2114}
2115TYPED_TEST(stdlib_bigfield, test_construct_from_limbs)
2116{
2117 TestFixture::test_construct_from_limbs();
2118}
2119TYPED_TEST(stdlib_bigfield, test_construct_from_limbs_fails)
2120{
2121 TestFixture::test_construct_from_limbs_fails();
2122}
2124{
2125 TestFixture::test_add_two(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS);
2126}
2127TYPED_TEST(stdlib_bigfield, add_two_with_constants)
2128{
2129 TestFixture::test_add_two(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT);
2130 TestFixture::test_add_two(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS);
2131 TestFixture::test_add_two(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT);
2132 TestFixture::test_add_two(InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS);
2133 TestFixture::test_add_two(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT);
2134 TestFixture::test_add_two(InputType::CONSTANT, InputType::CONSTANT, InputType::WITNESS);
2135 TestFixture::test_add_two(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT);
2136}
2138{
2139 TestFixture::test_sum(InputType::WITNESS);
2140}
2141TYPED_TEST(stdlib_bigfield, sum_with_mixed_inputs)
2142{
2143 TestFixture::test_sum(InputType::WITNESS, true);
2144}
2145TYPED_TEST(stdlib_bigfield, sum_with_constant)
2146{
2147 TestFixture::test_sum(InputType::CONSTANT);
2148}
2150{
2151 TestFixture::test_mul(InputType::WITNESS, InputType::WITNESS);
2152}
2153TYPED_TEST(stdlib_bigfield, mul_with_constant)
2154{
2155 TestFixture::test_mul(InputType::WITNESS, InputType::CONSTANT);
2156 TestFixture::test_mul(InputType::CONSTANT, InputType::WITNESS);
2157 TestFixture::test_mul(InputType::CONSTANT, InputType::CONSTANT);
2158}
2160{
2161 TestFixture::test_sub(InputType::WITNESS, InputType::WITNESS);
2162}
2163TYPED_TEST(stdlib_bigfield, sub_with_constant)
2164{
2165 TestFixture::test_sub(InputType::WITNESS, InputType::CONSTANT);
2166 TestFixture::test_sub(InputType::CONSTANT, InputType::WITNESS);
2167 TestFixture::test_sub(InputType::CONSTANT, InputType::CONSTANT);
2168}
2170{
2171 TestFixture::test_add(InputType::WITNESS, InputType::WITNESS);
2172}
2173TYPED_TEST(stdlib_bigfield, add_with_constant)
2174{
2175 TestFixture::test_add(InputType::WITNESS, InputType::CONSTANT);
2176 TestFixture::test_add(InputType::CONSTANT, InputType::WITNESS);
2177 TestFixture::test_add(InputType::CONSTANT, InputType::CONSTANT);
2178}
2180{
2181 TestFixture::test_div(InputType::WITNESS, InputType::WITNESS); // w / w
2182}
2183TYPED_TEST(stdlib_bigfield, div_with_constant)
2184{
2185 TestFixture::test_div(InputType::WITNESS, InputType::CONSTANT); // w / c
2186 TestFixture::test_div(InputType::CONSTANT, InputType::WITNESS); // c / w
2187 TestFixture::test_div(InputType::CONSTANT, InputType::CONSTANT); // c / c
2188}
2190{
2191 TestFixture::test_sqr(InputType::WITNESS);
2192}
2193TYPED_TEST(stdlib_bigfield, sqr_with_constant)
2194{
2195 TestFixture::test_sqr(InputType::CONSTANT);
2196}
2198{
2199 TestFixture::test_negate(InputType::WITNESS);
2200}
2202{
2203 TestFixture::test_mul_assign(InputType::WITNESS, InputType::WITNESS);
2204}
2205TYPED_TEST(stdlib_bigfield, mul_assignment_with_constant)
2206{
2207 TestFixture::test_mul_assign(InputType::WITNESS, InputType::CONSTANT);
2208 TestFixture::test_mul_assign(InputType::CONSTANT, InputType::WITNESS);
2209 TestFixture::test_mul_assign(InputType::CONSTANT, InputType::CONSTANT);
2210}
2212{
2213 TestFixture::test_add_assign(InputType::WITNESS, InputType::WITNESS);
2214}
2215TYPED_TEST(stdlib_bigfield, add_assignment_with_constant)
2216{
2217 TestFixture::test_add_assign(InputType::WITNESS, InputType::CONSTANT);
2218 TestFixture::test_add_assign(InputType::CONSTANT, InputType::WITNESS);
2219 TestFixture::test_add_assign(InputType::CONSTANT, InputType::CONSTANT);
2220}
2222{
2223 TestFixture::test_sub_assign(InputType::WITNESS, InputType::WITNESS);
2224}
2225TYPED_TEST(stdlib_bigfield, sub_assignment_with_constant)
2226{
2227 TestFixture::test_sub_assign(InputType::WITNESS, InputType::CONSTANT);
2228 TestFixture::test_sub_assign(InputType::CONSTANT, InputType::WITNESS);
2229 TestFixture::test_sub_assign(InputType::CONSTANT, InputType::CONSTANT);
2230}
2232{
2233 TestFixture::test_div_assign(InputType::WITNESS, InputType::WITNESS); // w / w
2234}
2235TYPED_TEST(stdlib_bigfield, div_assignment_with_constant)
2236{
2237 TestFixture::test_div_assign(InputType::WITNESS, InputType::CONSTANT); // w / c
2238 TestFixture::test_div_assign(InputType::CONSTANT, InputType::WITNESS); // c / w
2239 TestFixture::test_div_assign(InputType::CONSTANT, InputType::CONSTANT); // c / c
2240}
2242{
2243 TestFixture::test_madd(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w * w + w
2244}
2245TYPED_TEST(stdlib_bigfield, madd_with_constants)
2246{
2247 TestFixture::test_madd(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w * w + c
2248 TestFixture::test_madd(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // w * c + w
2249 TestFixture::test_madd(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // w * c + c
2250 TestFixture::test_madd(InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS); // c * w + w
2251 TestFixture::test_madd(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // c * w + c
2252 TestFixture::test_madd(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w * w + c
2253 TestFixture::test_madd(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // w * c + w
2254 TestFixture::test_madd(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // c * w + c
2255}
2257{
2258 TestFixture::test_sqradd(InputType::WITNESS, InputType::WITNESS); // w^2 + w
2259}
2260TYPED_TEST(stdlib_bigfield, sqradd_with_constant)
2261{
2262 TestFixture::test_sqradd(InputType::WITNESS, InputType::CONSTANT); // w^2 + c
2263 TestFixture::test_sqradd(InputType::CONSTANT, InputType::WITNESS); // c^2 + w
2264 TestFixture::test_sqradd(InputType::CONSTANT, InputType::CONSTANT); // c^2 + c
2265}
2267{
2268 TestFixture::test_mult_madd(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS); // ∑ (w * w + w)
2269}
2270TYPED_TEST(stdlib_bigfield, mult_madd_with_constants)
2271{
2272 TestFixture::test_mult_madd(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // ∑ (w * w + c)
2273 TestFixture::test_mult_madd(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // ∑ (w * c + w)
2274 TestFixture::test_mult_madd(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // ∑ (w * c + c)
2275 TestFixture::test_mult_madd(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT); // ∑ (c * c + c)
2276}
2277TYPED_TEST(stdlib_bigfield, mult_madd_edge_cases)
2278{
2279 // all witness except the last one
2280 TestFixture::test_mult_madd(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS, true);
2281 // all constant except the last one
2282 TestFixture::test_mult_madd(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT, true);
2283}
2285{
2286 TestFixture::test_dual_madd();
2287}
2288TYPED_TEST(stdlib_bigfield, div_without_denominator_check)
2289{
2290 TestFixture::test_div_without_denominator_check(InputType::WITNESS, InputType::WITNESS); // w / w
2291}
2292TYPED_TEST(stdlib_bigfield, div_without_denominator_check_with_constant)
2293{
2294 TestFixture::test_div_without_denominator_check(InputType::WITNESS, InputType::CONSTANT); // w / c
2295 TestFixture::test_div_without_denominator_check(InputType::CONSTANT, InputType::WITNESS); // c / w
2296 TestFixture::test_div_without_denominator_check(InputType::CONSTANT, InputType::CONSTANT); // c / c
2297}
2299{
2300 TestFixture::test_add_and_div();
2301}
2303{
2304 TestFixture::test_add_and_mul(InputType::WITNESS); // (w + w) * (w + w)
2305}
2306TYPED_TEST(stdlib_bigfield, add_and_mul_with_constants)
2307{
2308 TestFixture::test_add_and_mul(InputType::CONSTANT); // (w + c) * (w + c)
2309}
2311{
2312 TestFixture::test_sub_and_mul(InputType::WITNESS); // (w - w) * (w - w)
2313}
2314TYPED_TEST(stdlib_bigfield, sub_and_mul_with_constants)
2315{
2316 TestFixture::test_sub_and_mul(InputType::CONSTANT); // (w - c) * (w - c)
2317}
2319{
2320 TestFixture::test_msub_div(
2321 InputType::WITNESS, InputType::WITNESS, InputType::WITNESS); // (-w * w - w - w) / (w - w)
2322}
2323TYPED_TEST(stdlib_bigfield, msub_div_with_constants)
2324{
2325 TestFixture::test_msub_div(
2326 InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // (-w * w - w - c) / (w - w)
2327 TestFixture::test_msub_div(
2328 InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // (-w * c - w - w) / (w - w)
2329 TestFixture::test_msub_div(
2330 InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // (-w * c - w - c) / (w - w)
2331 TestFixture::test_msub_div(
2332 InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS); // (-c * w - c - w) / (w - w)
2333 TestFixture::test_msub_div(
2334 InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // (-c * w - c - c) / (w - w)
2335 TestFixture::test_msub_div(
2336 InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT); // (-c * c - c - c) / (w - w)
2337}
2338TYPED_TEST(stdlib_bigfield, conditional_assign)
2339{
2340 TestFixture::test_conditional_assign(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS); // w ? w : w
2341}
2342TYPED_TEST(stdlib_bigfield, conditional_assign_with_constants)
2343{
2344 TestFixture::test_conditional_assign(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w ? w : c
2345 TestFixture::test_conditional_assign(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // w ? c : w
2346 TestFixture::test_conditional_assign(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // w ? c : c
2347 TestFixture::test_conditional_assign(InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS); // c ? w : w
2348 TestFixture::test_conditional_assign(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // c ? w : c
2349 TestFixture::test_conditional_assign(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT); // c ? c : c
2350}
2351TYPED_TEST(stdlib_bigfield, conditional_select)
2352{
2353 TestFixture::test_conditional_select(InputType::WITNESS, InputType::WITNESS, InputType::WITNESS); // w ? w : w
2354}
2355TYPED_TEST(stdlib_bigfield, conditional_select_with_constants)
2356{
2357 TestFixture::test_conditional_select(InputType::WITNESS, InputType::WITNESS, InputType::CONSTANT); // w ? w : c
2358 TestFixture::test_conditional_select(InputType::WITNESS, InputType::CONSTANT, InputType::WITNESS); // w ? c : w
2359 TestFixture::test_conditional_select(InputType::WITNESS, InputType::CONSTANT, InputType::CONSTANT); // w ? c : c
2360 TestFixture::test_conditional_select(InputType::CONSTANT, InputType::WITNESS, InputType::WITNESS); // c ? w : w
2361 TestFixture::test_conditional_select(InputType::CONSTANT, InputType::WITNESS, InputType::CONSTANT); // c ? w : c
2362 TestFixture::test_conditional_select(InputType::CONSTANT, InputType::CONSTANT, InputType::CONSTANT); // c ? c : c
2363}
2364TYPED_TEST(stdlib_bigfield, msb_div_ctx_crash_regression)
2365{
2366 TestFixture::test_msub_div_ctx_crash_regression();
2367}
2368TYPED_TEST(stdlib_bigfield, conditional_negate)
2369{
2370 TestFixture::test_conditional_negate(InputType::WITNESS, InputType::WITNESS); // w ? -w : w
2371}
2372TYPED_TEST(stdlib_bigfield, conditional_negate_with_constants)
2373{
2374 TestFixture::test_conditional_negate(InputType::WITNESS, InputType::CONSTANT); // w ? -c : w
2375 TestFixture::test_conditional_negate(InputType::CONSTANT, InputType::WITNESS); // c ? -w : w
2376 TestFixture::test_conditional_negate(InputType::CONSTANT, InputType::CONSTANT); // c ? -c : c
2377}
2378TYPED_TEST(stdlib_bigfield, group_operations)
2379{
2380 // skip this test if the field is not bn254 base field
2382 GTEST_SKIP() << "skipping group operations test for non-bn254 base field";
2383 }
2384 TestFixture::test_group_operations();
2385}
2387{
2388 TestFixture::test_reduce();
2389}
2391{
2392 TestFixture::test_equality_operator(InputType::WITNESS, InputType::WITNESS); // w == w
2393}
2394TYPED_TEST(stdlib_bigfield, equality_with_constants)
2395{
2396 TestFixture::test_equality_operator(InputType::WITNESS, InputType::CONSTANT); // w == c
2397 TestFixture::test_equality_operator(InputType::CONSTANT, InputType::WITNESS); // c == w
2398 TestFixture::test_equality_operator(InputType::CONSTANT, InputType::CONSTANT); // c == c
2399}
2400
2401TYPED_TEST(stdlib_bigfield, unsafe_assert_less_than)
2402{
2403 TestFixture::test_unsafe_assert_less_than();
2404}
2405TYPED_TEST(stdlib_bigfield, unsafe_assert_less_than_fails)
2406{
2407 TestFixture::test_unsafe_assert_less_than_fails();
2408}
2409TYPED_TEST(stdlib_bigfield, unsafe_evaluate_multiply_add)
2410{
2411 TestFixture::test_unsafe_evaluate_multiply_add();
2412}
2413TYPED_TEST(stdlib_bigfield, unsafe_evaluate_multiply_add_fails)
2414{
2415 TestFixture::test_unsafe_evaluate_multiply_add_fails();
2416}
2417TYPED_TEST(stdlib_bigfield, unsafe_evaluate_multiple_multiply_add)
2418{
2419 TestFixture::test_unsafe_multiple_multiply_add();
2420}
2421TYPED_TEST(stdlib_bigfield, unsafe_evaluate_multiple_multiply_add_fails)
2422{
2423 TestFixture::test_unsafe_multiple_multiply_add_fails();
2424}
2425
2426TYPED_TEST(stdlib_bigfield, assert_is_in_field_success)
2427{
2428 TestFixture::test_assert_is_in_field_success();
2429}
2430TYPED_TEST(stdlib_bigfield, assert_is_in_field_fails)
2431{
2432 TestFixture::test_assert_is_in_field_fails();
2433}
2434TYPED_TEST(stdlib_bigfield, assert_less_than_success)
2435{
2436 TestFixture::test_assert_less_than_success();
2437}
2438TYPED_TEST(stdlib_bigfield, assert_less_than_fails)
2439{
2440 TestFixture::test_assert_less_than_fails();
2441}
2442TYPED_TEST(stdlib_bigfield, reduce_mod_target_modulus)
2443{
2444 TestFixture::test_reduce_mod_target_modulus();
2445}
2446TYPED_TEST(stdlib_bigfield, byte_array_constructors)
2447{
2448 TestFixture::test_byte_array_constructors();
2449}
2451{
2452 TestFixture::test_to_byte_array();
2453}
2454TYPED_TEST(stdlib_bigfield, quotient_completeness_regression)
2455{
2456 TestFixture::test_quotient_completeness();
2457}
2458
2459TYPED_TEST(stdlib_bigfield, conditional_select_regression)
2460{
2461 TestFixture::test_conditional_select_regression();
2462}
2463
2464TYPED_TEST(stdlib_bigfield, division_context)
2465{
2466 TestFixture::test_division_context();
2467}
2468
2470{
2471 TestFixture::test_inversion();
2472}
2473
2474TYPED_TEST(stdlib_bigfield, assert_equal_not_equal)
2475{
2476 TestFixture::test_assert_equal_not_equal();
2477}
2478
2480{
2481 TestFixture::test_pow();
2482}
2483
2485{
2486 TestFixture::test_pow_one();
2487}
2488TYPED_TEST(stdlib_bigfield, nonnormalized_field_bug_regression)
2489{
2490 TestFixture::test_nonnormalized_field_bug_regression();
2491}
2492
2493TYPED_TEST(stdlib_bigfield, internal_div_bug_regression)
2494{
2495 TestFixture::test_internal_div_regression();
2496 TestFixture::test_internal_div_regression2();
2497 TestFixture::test_internal_div_regression3();
2498}
#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
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:111
void set_origin_tag(const OriginTag &new_tag) const
Definition bool.hpp:128
Represents a dynamic array of bytes in-circuit.
void set_origin_tag(bb::OriginTag tag)
bytes_t const & bytes() const
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_to_byte_array()
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:16
#define BENCH_GATE_COUNT_START(builder, op_name)
Definition log.hpp:14
void info(Args... args)
Definition log.hpp:74
AluTraceBuilder builder
Definition alu.test.cpp:123
FF a
FF b
ECCVMCircuitBuilder Builder
testing::Types< bb::UltraCircuitBuilder, bb::MegaCircuitBuilder > CircuitTypes
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.
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
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
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()