Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bigfield.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Suyash], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
8
9#include "../byte_array/byte_array.hpp"
10#include "../circuit_builders/circuit_builders_fwd.hpp"
11#include "../field/field.hpp"
12#include "../field/field_utils.hpp"
19
20namespace bb::stdlib {
21
22template <typename Builder, typename T> class bigfield {
23
24 public:
25 using View = bigfield;
27 using TParams = T;
30
31 // Number of bb::fr field elements used to represent a bigfield element in the public inputs
32 static constexpr size_t PUBLIC_INPUTS_SIZE = BIGFIELD_PUBLIC_INPUTS_SIZE;
33
34 struct Basis {
36 size_t num_bits;
37 };
38
45 struct Limb {
46 Limb() = default;
48 : element(input)
49 {
50 if (input.is_constant()) {
53 } else {
54 maximum_value = max;
55 }
56 }
57 friend std::ostream& operator<<(std::ostream& os, const Limb& a)
58 {
59 os << "{ " << a.element << " <= " << a.maximum_value << " }";
60 return os;
61 }
62 Limb(const Limb& other) = default;
63 Limb(Limb&& other) noexcept = default;
64 Limb& operator=(const Limb& other) = default;
65 Limb& operator=(Limb&& other) noexcept = default;
66 ~Limb() = default;
67
70 };
71
72 // Number of limbs used to represent a bigfield element in the binary basis
73 static constexpr size_t NUM_LIMBS = 4;
74
76
82
87
97 bigfield(const field_t<Builder>& low_bits,
98 const field_t<Builder>& high_bits,
99 const bool can_overflow = false,
100 const size_t maximum_bitlength = 0);
101
108 bigfield(Builder* parent_context = nullptr);
109
116 bigfield(Builder* parent_context, const uint256_t& value);
117
118 explicit bigfield(const uint256_t& value)
119 : bigfield(nullptr, uint256_t(value))
120 {}
121
127 bigfield(const int value)
128 : bigfield(nullptr, uint256_t(native(value)))
129 {}
130
131 // NOLINTNEXTLINE(google-runtime-int) intended behavior
132 bigfield(const unsigned long value)
133 : bigfield(nullptr, value)
134 {}
135
136 // NOLINTNEXTLINE(google-runtime-int) intended behavior
137 bigfield(const unsigned long long value)
138 : bigfield(nullptr, value)
139 {}
140
148 : bigfield(nullptr, uint256_t(value))
149 {}
150
159 const field_t<Builder>& b,
160 const field_t<Builder>& c,
161 const field_t<Builder>& d,
162 const bool can_overflow = false)
163 {
164 BB_ASSERT_EQ(a.is_constant(), b.is_constant());
165 BB_ASSERT_EQ(b.is_constant(), c.is_constant());
167 bigfield result;
168 result.context = a.context;
169 result.binary_basis_limbs[0] = Limb(field_t(a));
170 result.binary_basis_limbs[1] = Limb(field_t(b));
171 result.binary_basis_limbs[2] = Limb(field_t(c));
172 result.binary_basis_limbs[3] =
174 result.prime_basis_limb = (result.binary_basis_limbs[3].element * shift_3)
175 .add_two(result.binary_basis_limbs[2].element * shift_2,
176 result.binary_basis_limbs[1].element * shift_1);
177 result.prime_basis_limb += (result.binary_basis_limbs[0].element);
178 return result;
179 };
180
187 const field_t<Builder>& b,
188 const field_t<Builder>& c,
189 const field_t<Builder>& d,
190 const bool can_overflow = false)
191 {
192 BB_ASSERT_EQ(a.is_constant(), b.is_constant());
193 BB_ASSERT_EQ(b.is_constant(), c.is_constant());
195 bigfield result;
196 auto ctx = a.context;
197 result.context = a.context;
198 result.binary_basis_limbs[0] = Limb(field_t(a));
199 result.binary_basis_limbs[1] = Limb(field_t(b));
200 result.binary_basis_limbs[2] = Limb(field_t(c));
201 result.binary_basis_limbs[3] =
203 result.prime_basis_limb = (result.binary_basis_limbs[3].element * shift_3)
204 .add_two(result.binary_basis_limbs[2].element * shift_2,
205 result.binary_basis_limbs[1].element * shift_1);
206 result.prime_basis_limb += (result.binary_basis_limbs[0].element);
207
208 // Range contrain the first two limbs each to NUM_LIMB_BITS
209 ctx->range_constrain_two_limbs(result.binary_basis_limbs[0].element.get_witness_index(),
210 result.binary_basis_limbs[1].element.get_witness_index(),
211 static_cast<size_t>(NUM_LIMB_BITS),
212 static_cast<size_t>(NUM_LIMB_BITS),
213 "bigfield::construct_from_limbs: limb 0 or 1 too large");
214
215 // Range constrain the last two limbs to NUM_LIMB_BITS and NUM_LAST_LIMB_BITS
216 const size_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
217 ctx->range_constrain_two_limbs(result.binary_basis_limbs[2].element.get_witness_index(),
218 result.binary_basis_limbs[3].element.get_witness_index(),
219 static_cast<size_t>(NUM_LIMB_BITS),
220 static_cast<size_t>(num_last_limb_bits),
221 "bigfield::construct_from_limbs: limb 2 or 3 too large");
222
223 return result;
224 };
225
234 const field_t<Builder>& b,
235 const field_t<Builder>& c,
236 const field_t<Builder>& d,
237 const field_t<Builder>& prime_limb,
238 const bool can_overflow = false)
239 {
240 BB_ASSERT_EQ(a.is_constant(), b.is_constant());
241 BB_ASSERT_EQ(b.is_constant(), c.is_constant());
243 BB_ASSERT_EQ(d.is_constant(), prime_limb.is_constant());
244 bigfield result;
245 result.context = a.context;
246 result.binary_basis_limbs[0] = Limb(field_t(a));
247 result.binary_basis_limbs[1] = Limb(field_t(b));
248 result.binary_basis_limbs[2] = Limb(field_t(c));
249 result.binary_basis_limbs[3] =
251 result.prime_basis_limb = prime_limb;
252 return result;
253 };
254
268 bigfield(const byte_array<Builder>& bytes);
269
270 // Copy constructor
271 bigfield(const bigfield& other);
272
273 // Move constructor
274 bigfield(bigfield&& other) noexcept;
275
276 // Destructor
277 ~bigfield() = default;
278
293 const uint512_t& value,
294 const bool can_overflow = false,
295 const size_t maximum_bitlength = 0);
296
297 static bigfield from_witness(Builder* ctx, const bb::field<T>& input)
298 {
299 uint256_t input_u256(input);
300 field_t<Builder> low(witness_t<Builder>(ctx, bb::fr(input_u256.slice(0, NUM_LIMB_BITS * 2))));
302 auto result = bigfield(low, hi);
303 result.set_free_witness_tag();
304 return result;
305 }
306
307 // Disallow from_witness for non-bb::fr types to prevent implicit conversions (specifically, using indices rather
308 // than values)
309 template <typename OT> static bigfield from_witness(Builder* ctx, const OT& input) = delete;
310
311 bigfield& operator=(const bigfield& other);
312 bigfield& operator=(bigfield&& other) noexcept;
313
314 // Code assumes modulus is at most 256 bits so good to define it via a uint256_t
315 static constexpr uint256_t modulus = (uint256_t(T::modulus_0, T::modulus_1, T::modulus_2, T::modulus_3));
316 static constexpr uint512_t modulus_u512 = static_cast<uint512_t>(modulus);
317 static constexpr uint64_t NUM_LIMB_BITS = NUM_LIMB_BITS_IN_FIELD_SIMULATION;
318 static constexpr uint64_t NUM_LAST_LIMB_BITS = modulus_u512.get_msb() + 1 - (NUM_LIMB_BITS * 3);
319
320 // The quotient reduction checks currently only support >=250 bit moduli and moduli >256 have never been tested
321 // (Check zkSecurity audit report issue #12 for explanation)
322 static_assert(modulus_u512.get_msb() + 1 >= 250 && modulus_u512.get_msb() + 1 <= 256);
323
329 static constexpr uint64_t LOG2_BINARY_MODULUS = NUM_LIMB_BITS * NUM_LIMBS;
330 static constexpr bool is_composite = true; // false only when fr is native
331
332 // This limits the size of all vectors that are being used to 16 (we don't really need more)
333 static constexpr size_t MAXIMUM_SUMMAND_COUNT_LOG = 4;
334 static constexpr size_t MAXIMUM_SUMMAND_COUNT = 1 << MAXIMUM_SUMMAND_COUNT_LOG;
335
338 static constexpr Basis target_basis{ modulus_u512, static_cast<size_t>(modulus_u512.get_msb() + 1) };
339 static constexpr bb::fr shift_1 = bb::fr(uint256_t(1) << NUM_LIMB_BITS);
340 static constexpr bb::fr shift_2 = bb::fr(uint256_t(1) << (NUM_LIMB_BITS * 2));
341 static constexpr bb::fr shift_3 = bb::fr(uint256_t(1) << (NUM_LIMB_BITS * 3));
356
357 // Gets the integer (uint512_t) value of the bigfield element by combining the binary basis limbs.
358 uint512_t get_value() const;
359
360 // Gets the maximum value of the bigfield element by combining the maximum values of the binary basis limbs.
362
379 bigfield add_to_lower_limb(const field_t<Builder>& other, const uint256_t& other_maximum_value) const;
380
395 bigfield operator+(const bigfield& other) const;
396
408 bigfield add_two(const bigfield& add_a, const bigfield& add_b) const;
409
423 bigfield operator-(const bigfield& other) const;
424
438 bigfield operator*(const bigfield& other) const;
439
450 bigfield operator/(const bigfield& other) const;
451
457 bigfield operator-() const { return bigfield(get_context(), uint256_t(0)) - *this; }
458
460 {
461 *this = operator+(other);
462 return *this;
463 }
465 {
466 *this = operator-(other);
467 return *this;
468 }
470 {
471 *this = operator*(other);
472 return *this;
473 }
475 {
476 *this = operator/(other);
477 return *this;
478 }
479
488 bigfield sqr() const;
489
499 bigfield sqradd(const std::vector<bigfield>& to_add) const;
500
512 bigfield pow(const uint32_t exponent) const;
513
522 bigfield madd(const bigfield& to_mul, const std::vector<bigfield>& to_add) const;
523
525 std::vector<bigfield>& mul_right,
526 const std::vector<bigfield>& to_add);
527
528 static bigfield mult_madd(const std::vector<bigfield>& mul_left,
529 const std::vector<bigfield>& mul_right,
530 const std::vector<bigfield>& to_add,
531 bool fix_remainder_to_zero = false);
532
533 static bigfield dual_madd(const bigfield& left_a,
534 const bigfield& right_a,
535 const bigfield& left_b,
536 const bigfield& right_b,
537 const std::vector<bigfield>& to_add);
538
539 // compute -(mul_left * mul_right + ...to_sub) / (divisor)
540 // We can evaluate this relationship with only one set of quotient/remainder range checks
541 static bigfield msub_div(const std::vector<bigfield>& mul_left,
542 const std::vector<bigfield>& mul_right,
543 const bigfield& divisor,
544 const std::vector<bigfield>& to_sub,
545 bool enable_divisor_nz_check = true);
546
547 static bigfield sum(const std::vector<bigfield>& terms);
548 static bigfield internal_div(const std::vector<bigfield>& numerators,
549 const bigfield& denominator,
550 bool check_for_zero);
551
552 static bigfield div_without_denominator_check(const std::vector<bigfield>& numerators, const bigfield& denominator);
554 static bigfield div_check_denominator_nonzero(const std::vector<bigfield>& numerators, const bigfield& denominator);
555
556 bigfield conditional_negate(const bool_t<Builder>& predicate) const;
557
567 bigfield conditional_select(const bigfield& other, const bool_t<Builder>& predicate) const;
568 static bigfield conditional_assign(const bool_t<Builder>& predicate, const bigfield& lhs, const bigfield& rhs)
569 {
570 return rhs.conditional_select(lhs, predicate);
571 }
572
573 bool_t<Builder> operator==(const bigfield& other) const;
574
575 void assert_zero_if(const bool_t<Builder>& predicate,
576 std::string const& msg = "bigfield::assert_zero_if failed") const;
577 void assert_is_in_field(std::string const& msg = "bigfield::assert_is_in_field") const;
578 void assert_less_than(const uint256_t& upper_limit, std::string const& msg = "bigfield::assert_less_than") const;
579 void reduce_mod_target_modulus() const;
580 void assert_equal(const bigfield& other, std::string const& msg = "bigfield::assert_equal") const;
581 void assert_is_not_equal(const bigfield& other,
582 std::string const& msg = "bigfield: prime limb diff is zero, but expected non-zero") const;
583 bool_t<Builder> is_less_than(const uint256_t& upper_limit, std::string const& msg = "bigfield::is_less_than") const;
584
594 void self_reduce() const;
595
603 bool is_constant() const
604 {
605 bool is_limb_0_constant = binary_basis_limbs[0].element.is_constant();
606 bool is_limb_1_constant = binary_basis_limbs[1].element.is_constant();
607 bool is_limb_2_constant = binary_basis_limbs[2].element.is_constant();
608 bool is_limb_3_constant = binary_basis_limbs[3].element.is_constant();
609 bool is_prime_limb_constant = prime_basis_limb.is_constant();
610 BB_ASSERT_EQ(is_limb_0_constant, is_limb_1_constant);
611 BB_ASSERT_EQ(is_limb_1_constant, is_limb_2_constant);
612 BB_ASSERT_EQ(is_limb_2_constant, is_limb_3_constant);
613 BB_ASSERT_EQ(is_limb_3_constant, is_prime_limb_constant);
614 return is_prime_limb_constant;
615 }
616
622 bigfield invert() const { return (bigfield(1) / bigfield(*this)); }
623
627 static bigfield one()
628 {
629 bigfield result(nullptr, uint256_t(1));
630 return result;
631 }
632
636 static bigfield zero()
637 {
638 bigfield result(nullptr, uint256_t(0));
639 return result;
640 }
641
648 static constexpr bigfield unreduced_zero()
649 {
650 uint512_t multiple_of_modulus = ((get_maximum_unreduced_value() / modulus_u512) + 1) * modulus_u512;
651 auto msb = multiple_of_modulus.get_msb();
652
653 bigfield result(nullptr, uint256_t(0));
654 result.binary_basis_limbs[0] = Limb(bb::fr(multiple_of_modulus.slice(0, NUM_LIMB_BITS).lo));
655 result.binary_basis_limbs[1] = Limb(bb::fr(multiple_of_modulus.slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS).lo));
656 result.binary_basis_limbs[2] = Limb(bb::fr(multiple_of_modulus.slice(2 * NUM_LIMB_BITS, 3 * NUM_LIMB_BITS).lo));
657 result.binary_basis_limbs[3] = Limb(bb::fr(multiple_of_modulus.slice(3 * NUM_LIMB_BITS, msb + 1).lo));
658 result.prime_basis_limb = field_t<Builder>((multiple_of_modulus % uint512_t(field_t<Builder>::modulus)).lo);
659 return result;
660 }
661
666 {
668 for (auto& limb : binary_basis_limbs) {
669 limb.element.convert_constant_to_fixed_witness(context);
670 }
672 }
673
678 {
679 // Origin tags should be updated within
680 for (auto& limb : binary_basis_limbs) {
681 limb.element.fix_witness();
682 }
684
685 // This is now effectively a constant
687 }
688
689 Builder* get_context() const { return context; }
690
692 {
693 for (size_t i = 0; i < NUM_LIMBS; i++) {
694 binary_basis_limbs[i].element.set_origin_tag(tag);
695 }
697 }
699 {
700 for (size_t i = 0; i < NUM_LIMBS; i++) {
701 binary_basis_limbs[i].element.clear_round_provenance();
702 }
704 }
705
707 {
709 binary_basis_limbs[1].element.tag,
710 binary_basis_limbs[2].element.tag,
711 binary_basis_limbs[3].element.tag,
713 }
714
719 {
720 for (auto& limb : binary_basis_limbs) {
721 limb.element.set_free_witness_tag();
722 }
724 }
725
730 {
731 for (auto& limb : binary_basis_limbs) {
732 limb.element.unset_free_witness_tag();
733 }
735 }
743 uint32_t set_public() const
744 {
745 // Reduce bigfield to canonical form before combining into 2-limb format.
746 self_reduce();
747
748 Builder* ctx = get_context();
749 const uint32_t start_index = static_cast<uint32_t>(ctx->num_public_inputs());
750
751 // Combine limbs into 2-limb Codec format
752 constexpr uint256_t shift = uint256_t(1) << NUM_LIMB_BITS;
753 field_t<Builder> lo = binary_basis_limbs[0].element + binary_basis_limbs[1].element * shift;
754 field_t<Builder> hi = binary_basis_limbs[2].element + binary_basis_limbs[3].element * shift;
755
756 // Mark as used witnesses (these are intentionally in one gate for public input encoding)
759
760 ctx->set_public_input(lo.get_witness_index());
761 ctx->set_public_input(hi.get_witness_index());
762
763 return start_index;
764 }
765
767 {
768 // This = `T * n = 2^272 * |BN(Fr)|` So this equals n*2^t
769 uint1024_t maximum_product = get_maximum_crt_product();
770
771 // In multiplying two bigfield elements a and b, we must check that:
772 //
773 // a * b = q * p + r
774 //
775 // where q is the quotient, r is the remainder, and p is the size of the non-native field.
776 // The CRT requires that we check that the equation:
777 // (a) holds modulo the size of the native field n,
778 // (b) holds modulo the size of the bigger ring 2^t,
779 // (c) both sides of the equation are less than the max product M = 2^t * n.
780 // Thus, the max value of an unreduced bigfield element is √M. In this case, we use
781 // an even stricter bound. Let n = 2^m + l (where 1 < l < 2^m). Thus, we have:
782 //
783 // M = 2^t * n = 2^t * (2^m + l) = 2^(t + m) + (2^t * l)
784 // => M > 2^(t + m)
785 // => √M > 2^((t + m) / 2)
786 //
787 // We set the maximum unreduced value of a bigfield element to be: 2^((t + m) / 2) < √M.
788 //
789 // Note: We use a further safer bound of 2^((t + m - 1) / 2). We use -1 to stay safer,
790 // because it provides additional space to avoid the overflow, but get_msb() by itself should be enough.
791 uint64_t maximum_product_bits = maximum_product.get_msb() - 1;
792 return (uint512_t(1) << (maximum_product_bits >> 1)) - uint512_t(1);
793 }
794
795 // If we encounter this maximum value of a bigfield we stop execution
797 {
798 uint1024_t maximum_product = get_maximum_crt_product();
799 uint64_t maximum_product_bits = maximum_product.get_msb() - 1;
800 const size_t arbitrary_secure_margin = 20;
801 return (uint512_t(1) << ((maximum_product_bits >> 1) + arbitrary_secure_margin)) - uint512_t(1);
802 }
803
814 {
816 return maximum_product;
817 }
818
829 static size_t get_quotient_max_bits(const std::vector<uint1024_t>& remainders_max)
830 {
831 // find q_max * p + ...remainders_max < nT
833 for (const auto& r : remainders_max) {
834 base -= r;
835 }
836 base /= modulus_u512;
837 return static_cast<size_t>(base.get_msb() - 1);
838 }
839
850 const uint1024_t& b_max,
851 const std::vector<bigfield>& to_add)
852 {
853 uint1024_t product = a_max * b_max;
854 uint1024_t add_term = 0;
855 for (const auto& add : to_add) {
856 add_term += add.get_maximum_value();
857 }
858 constexpr uint1024_t maximum_default_bigint = uint1024_t(1) << (NUM_LIMB_BITS * 6 + NUM_LAST_LIMB_BITS * 2);
859
860 // check that the add terms alone cannot overflow the crt modulus. v. unlikely so just forbid circuits that
861 // trigger this case
862 BB_ASSERT_LT(add_term + maximum_default_bigint, get_maximum_crt_product());
863 return ((product + add_term) >= get_maximum_crt_product());
864 }
865
876 const std::vector<uint512_t>& bs_max,
877 const std::vector<bigfield>& to_add)
878 {
880 BB_ASSERT_EQ(as_max.size(), bs_max.size());
881 // Computing individual products
882 uint1024_t product_sum = 0;
883 uint1024_t add_term = 0;
884 for (size_t i = 0; i < as_max.size(); i++) {
885 product_sum += uint1024_t(as_max[i]) * uint1024_t(bs_max[i]);
886 }
887 for (const auto& add : to_add) {
888 add_term += add.get_maximum_value();
889 }
890 static const uint1024_t maximum_default_bigint = uint1024_t(1) << (NUM_LIMB_BITS * 6 + NUM_LAST_LIMB_BITS * 2);
891
892 // check that the add terms alone cannot overflow the crt modulus. v. unlikely so just forbid circuits that
893 // trigger this case
894 BB_ASSERT_LT(add_term + maximum_default_bigint, get_maximum_crt_product());
895 return ((product_sum + add_term) >= get_maximum_crt_product());
896 }
897
898 // a (currently generous) upper bound on the log of number of fr additions in any of the class operations
899 static constexpr uint64_t MAX_ADDITION_LOG = 10;
900
901 // The rationale of the expression is we should not overflow Fr when applying any bigfield operation (e.g. *) and
902 // starting with this max limb size
903 //
904 // In multiplication of bigfield elements a * b, we encounter sum of limbs multiplications of form:
905 // c0 := a0 * b0
906 // c1 := a1 * b0 + a0 * b1
907 // c2 := a2 * b0 + a1 * b1 + a0 * b2
908 // c3 := a3 * b0 + a2 * b1 + a1 * b2 + a0 * b3
909 // output:
910 // lo := c0 + c1 * 2^L,
911 // hi := c2 + c3 * 2^L.
912 // Since hi term contains upto 4 limb-products, we must ensure that the hi term does not overflow the native field
913 // modulus. Suppose we are adding 2^k such terms. Let Q be the max bitsize of a limb. We want to ensure that the sum
914 // doesn't overflow the native field modulus. Hence:
915 // max(∑ hi) = max(∑ c2 + c3 * 2^L)
916 // = max(∑ c2) + max(∑ c3 * 2^L)
917 // = 2^k * (3 * 2^2Q) + 2^k * 2^L * (4 * 2^2Q)
918 // < 2^k * (2^L + 1) * (4 * 2^2Q)
919 // < n
920 // ==> 2^k * 2^L * 2^(2Q + 3) < n
921 // ==> 2Q + 3 < (log(n) - k - L)
922 // ==> Q < ((log(n) - k - L) - 3) / 2
923 //
924 static constexpr uint64_t MAXIMUM_LIMB_SIZE_THAT_WOULDNT_OVERFLOW =
926
927 // If the logarithm of the maximum value of a limb is more than this, we need to reduce.
928 // We allow an element to be added to itself 10 times, so we allow the limb to grow by 10 bits.
929 // Number 10 is arbitrary, there's no actual usecase for adding 1024 elements together.
931
932 // If we reach this size of a limb, we stop execution (as safety measure). This should never reach during addition
933 // as we would reduce the limbs before they reach this size.
934 static constexpr uint64_t PROHIBITED_LIMB_BITS = MAX_UNREDUCED_LIMB_BITS + 5;
935
936 // If we encounter this maximum value of a bigfield we need to reduce it.
938 {
939 return ((uint256_t(1) << MAX_UNREDUCED_LIMB_BITS) - uint256_t(1));
940 }
941
942 // If we encounter this maximum value of a limb we stop execution
944
946
947 // For testing purposes only
949
950 private:
957 void unsafe_assert_less_than(const uint256_t& upper_limit,
958 std::string const& msg = "bigfield::unsafe_assert_less_than") const;
959
966 {
967 std::array<uint32_t, NUM_LIMBS> limb_witness_indices;
968 for (size_t i = 0; i < NUM_LIMBS; i++) {
969 limb_witness_indices[i] = binary_basis_limbs[i].element.get_witness_index();
970 }
971 return limb_witness_indices;
972 }
973
985 static std::array<uint32_t, 2> decompose_non_native_field_double_width_limb(
986 Builder* ctx, const uint32_t limb_idx, const size_t num_limb_bits = (2 * NUM_LIMB_BITS));
987
997 const bigfield& b,
998 const std::vector<bigfield>& to_add);
1008 const std::vector<uint512_t>& bs,
1009 const std::vector<uint512_t>& to_add);
1010
1022 const std::vector<uint512_t>& bs_max,
1023 const std::vector<bigfield>& to_add,
1024 const std::vector<uint1024_t>& remainders_max = {
1026
1046 static void unsafe_evaluate_multiply_add(const bigfield& input_left,
1047 const bigfield& input_to_mul,
1048 const std::vector<bigfield>& to_add,
1049 const bigfield& input_quotient,
1050 const std::vector<bigfield>& input_remainders);
1051
1072 const std::vector<bigfield>& input_right,
1073 const std::vector<bigfield>& to_add,
1074 const bigfield& input_quotient,
1075 const std::vector<bigfield>& input_remainders);
1076
1091 static void unsafe_evaluate_square_add(const bigfield& left,
1092 const std::vector<bigfield>& to_add,
1093 const bigfield& quotient,
1094 const bigfield& remainder);
1095
1116 void reduction_check() const;
1117
1124 void sanity_check() const;
1125
1132 {
1134 for (size_t i = 0; i < NUM_LIMBS; i++) {
1135 limb_maximums[i] = binary_basis_limbs[i].maximum_value;
1136 }
1137 return limb_maximums;
1138 }
1139
1154
1155}; // namespace stdlib
1156
1157// NOTE: For testing private functions in bigfield
1159 public:
1160 template <typename bigfield>
1161 static void unsafe_assert_less_than(const bigfield& input, const uint256_t& upper_limit)
1162 {
1163 input.unsafe_assert_less_than(upper_limit);
1164 }
1165
1166 template <typename bigfield>
1167 static void unsafe_evaluate_multiply_add(const bigfield& input_left,
1168 const bigfield& input_to_mul,
1169 const std::vector<bigfield>& to_add,
1170 const bigfield& input_quotient,
1171 const std::vector<bigfield>& input_remainders)
1172 {
1173 bigfield::unsafe_evaluate_multiply_add(input_left, input_to_mul, to_add, input_quotient, input_remainders);
1174 }
1175
1176 template <typename bigfield>
1178 const std::vector<bigfield>& input_right,
1179 const std::vector<bigfield>& to_add,
1180 const bigfield& input_quotient,
1181 const std::vector<bigfield>& input_remainders)
1182 {
1184 input_left, input_right, to_add, input_quotient, input_remainders);
1185 }
1186};
1187
1188template <typename C, typename T> inline std::ostream& operator<<(std::ostream& os, bigfield<T, C> const& v)
1189{
1190 return os << v.get_value();
1191}
1192
1193} // namespace bb::stdlib
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:143
constexpr uint256_t slice(uint64_t start, uint64_t end) const
constexpr uint64_t get_msb() const
constexpr uintx slice(const uint64_t start, const uint64_t end) const
Definition uintx.hpp:81
constexpr uint64_t get_msb() const
Definition uintx.hpp:68
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)
static bigfield zero()
Definition bigfield.hpp:636
static constexpr uint256_t DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB
Definition bigfield.hpp:327
static size_t get_quotient_max_bits(const std::vector< uint1024_t > &remainders_max)
Compute the maximum number of bits for quotient range proof to protect against CRT underflow.
Definition bigfield.hpp:829
static bigfield unsafe_construct_from_limbs(const field_t< Builder > &a, const field_t< Builder > &b, const field_t< Builder > &c, const field_t< Builder > &d, const field_t< Builder > &prime_limb, const bool can_overflow=false)
Construct a bigfield element from binary limbs and a prime basis limb that are already reduced.
Definition bigfield.hpp:233
static constexpr uint512_t get_maximum_unreduced_value()
Definition bigfield.hpp:766
static constexpr uint256_t get_prohibited_limb_value()
Definition bigfield.hpp:943
static constexpr uint64_t NUM_LIMB_BITS
Definition bigfield.hpp:317
static constexpr Basis binary_basis
Definition bigfield.hpp:337
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)
Evaluate a relation involving multiple multiplications and additions.
static constexpr uint64_t MAX_ADDITION_LOG
Definition bigfield.hpp:899
static bigfield conditional_assign(const bool_t< Builder > &predicate, const bigfield &lhs, const bigfield &rhs)
Definition bigfield.hpp:568
static constexpr uint64_t MAX_UNREDUCED_LIMB_BITS
Definition bigfield.hpp:930
static constexpr size_t MAXIMUM_SUMMAND_COUNT_LOG
Definition bigfield.hpp:333
static bool mul_product_overflows_crt_modulus(const uint1024_t &a_max, const uint1024_t &b_max, const std::vector< bigfield > &to_add)
Definition bigfield.hpp:849
static bigfield msub_div(const std::vector< bigfield > &mul_left, const std::vector< bigfield > &mul_right, const bigfield &divisor, const std::vector< bigfield > &to_sub, bool enable_divisor_nz_check=true)
void clear_round_provenance() const
Definition bigfield.hpp:698
Builder * get_context() const
Definition bigfield.hpp:689
static constexpr uint1024_t get_maximum_crt_product()
Compute the maximum product of two bigfield elements in CRT: M = 2^t * n.
Definition bigfield.hpp:813
bigfield operator*(const bigfield &other) const
Evaluate a non-native field multiplication: (a * b = c mod p) where p == target_basis....
bigfield conditional_select(const bigfield &other, const bool_t< Builder > &predicate) const
Create an element which is equal to either this or other based on the predicate.
static bigfield div_check_denominator_nonzero(const std::vector< bigfield > &numerators, const bigfield &denominator)
static bigfield sum(const std::vector< bigfield > &terms)
Create constraints for summing these terms.
static void unsafe_evaluate_square_add(const bigfield &left, const std::vector< bigfield > &to_add, const bigfield &quotient, const bigfield &remainder)
Evaluate a square with several additions.
static constexpr uint64_t MAXIMUM_LIMB_SIZE_THAT_WOULDNT_OVERFLOW
Definition bigfield.hpp:924
static bigfield construct_from_limbs(const field_t< Builder > &a, const field_t< Builder > &b, const field_t< Builder > &c, const field_t< Builder > &d, const bool can_overflow=false)
Construct a bigfield element from binary limbs that are already reduced and ensure they are range con...
Definition bigfield.hpp:186
bigfield madd(const bigfield &to_mul, const std::vector< bigfield > &to_add) const
Compute a * b + ...to_add = c mod p.
bigfield conditional_negate(const bool_t< Builder > &predicate) const
static bigfield mult_madd(const std::vector< bigfield > &mul_left, const std::vector< bigfield > &mul_right, const std::vector< bigfield > &to_add, bool fix_remainder_to_zero=false)
void set_origin_tag(const bb::OriginTag &tag) const
Definition bigfield.hpp:691
uint512_t get_value() const
void assert_is_in_field(std::string const &msg="bigfield::assert_is_in_field") const
static bigfield internal_div(const std::vector< bigfield > &numerators, const bigfield &denominator, bool check_for_zero)
static constexpr std::array< bb::fr, NUM_LIMBS > neg_modulus_mod_binary_basis_limbs
Definition bigfield.hpp:350
void assert_less_than(const uint256_t &upper_limit, std::string const &msg="bigfield::assert_less_than") const
static constexpr size_t PUBLIC_INPUTS_SIZE
Definition bigfield.hpp:32
static constexpr Basis target_basis
Definition bigfield.hpp:338
static constexpr uint64_t PROHIBITED_LIMB_BITS
Definition bigfield.hpp:934
static constexpr Basis prime_basis
Definition bigfield.hpp:336
static const uint1024_t DEFAULT_MAXIMUM_REMAINDER
Definition bigfield.hpp:324
bigfield add_to_lower_limb(const field_t< Builder > &other, const uint256_t &other_maximum_value) const
Add a field element to the lower limb. CAUTION (the element has to be constrained before using this f...
bigfield(const native value)
Construct a new bigfield object from bb::fq. We first convert to uint256_t as field elements are in M...
Definition bigfield.hpp:147
static constexpr uint256_t get_maximum_unreduced_limb_value()
Definition bigfield.hpp:937
static constexpr uint64_t NUM_LAST_LIMB_BITS
Definition bigfield.hpp:318
void set_free_witness_tag()
Set the free witness flag for the bigfield.
Definition bigfield.hpp:718
static constexpr uint512_t get_prohibited_value()
Definition bigfield.hpp:796
bigfield & operator=(const bigfield &other)
void convert_constant_to_fixed_witness(Builder *builder)
Definition bigfield.hpp:665
uint512_t get_maximum_value() const
std::array< uint256_t, NUM_LIMBS > get_binary_basis_limb_maximums()
Get the maximum values of the binary basis limbs.
static uint512_t compute_maximum_quotient_value(const std::vector< uint512_t > &as, const std::vector< uint512_t > &bs, const std::vector< uint512_t > &to_add)
Compute the maximum possible value of quotient of a*b+\sum(to_add)
bigfield sqradd(const std::vector< bigfield > &to_add) const
Square and add operator, computes a * a + ...to_add = c mod p.
static constexpr size_t NUM_LIMBS
Definition bigfield.hpp:73
bigfield operator*=(const bigfield &other)
Definition bigfield.hpp:469
static constexpr uint512_t negative_prime_modulus_mod_binary_basis
Definition bigfield.hpp:343
static bigfield one()
Definition bigfield.hpp:627
static constexpr uint256_t DEFAULT_MAXIMUM_LIMB
Definition bigfield.hpp:326
bigfield add_two(const bigfield &add_a, const bigfield &add_b) const
Create constraints for summing three bigfield elements efficiently.
std::array< uint32_t, NUM_LIMBS > get_binary_basis_limb_witness_indices() const
Get the witness indices of the (normalized) binary basis limbs.
Definition bigfield.hpp:965
bigfield(const unsigned long long value)
Definition bigfield.hpp:137
static constexpr size_t MAXIMUM_SUMMAND_COUNT
Definition bigfield.hpp:334
bb::OriginTag get_origin_tag() const
Definition bigfield.hpp:706
bigfield operator-=(const bigfield &other)
Definition bigfield.hpp:464
static bigfield from_witness(Builder *ctx, const bb::field< T > &input)
Definition bigfield.hpp:297
void reduction_check() const
Check if the bigfield element needs to be reduced.
void assert_zero_if(const bool_t< Builder > &predicate, std::string const &msg="bigfield::assert_zero_if failed") const
static constexpr bb::fr negative_prime_modulus_mod_native_basis
Definition bigfield.hpp:342
static constexpr uint256_t modulus
Definition bigfield.hpp:315
static bigfield from_witness(Builder *ctx, const OT &input)=delete
bool_t< Builder > is_less_than(const uint256_t &upper_limit, std::string const &msg="bigfield::is_less_than") const
static constexpr bb::fr shift_2
Definition bigfield.hpp:340
bigfield(const int value)
Constructs a new bigfield object from an int value. We first need to to construct a field element fro...
Definition bigfield.hpp:127
static bigfield dual_madd(const bigfield &left_a, const bigfield &right_a, const bigfield &left_b, const bigfield &right_b, const std::vector< bigfield > &to_add)
bigfield sqr() const
Square operator, computes a * a = c mod p.
static void perform_reductions_for_mult_madd(std::vector< bigfield > &mul_left, std::vector< bigfield > &mul_right, const std::vector< bigfield > &to_add)
Performs individual reductions on the supplied elements as well as more complex reductions to prevent...
static constexpr bb::fr shift_3
Definition bigfield.hpp:341
bool is_constant() const
Check if the bigfield is constant, i.e. its prime limb is constant.
Definition bigfield.hpp:603
static std::array< uint32_t, 2 > decompose_non_native_field_double_width_limb(Builder *ctx, const uint32_t limb_idx, const size_t num_limb_bits=(2 *NUM_LIMB_BITS))
Decompose a single witness into two limbs, range constrained to NUM_LIMB_BITS (68) and num_limb_bits ...
void reduce_mod_target_modulus() const
static std::pair< uint512_t, uint512_t > compute_quotient_remainder_values(const bigfield &a, const bigfield &b, const std::vector< bigfield > &to_add)
Compute the quotient and remainder values for dividing (a * b + (to_add[0] + ... + to_add[-1])) with ...
void unsafe_assert_less_than(const uint256_t &upper_limit, std::string const &msg="bigfield::unsafe_assert_less_than") const
Assert that the current bigfield is less than the given upper limit.
bigfield operator+(const bigfield &other) const
Adds two bigfield elements. Inputs are reduced to the modulus if necessary. Requires 4 gates if both ...
void assert_equal(const bigfield &other, std::string const &msg="bigfield::assert_equal") const
static constexpr uint64_t LOG2_BINARY_MODULUS
Definition bigfield.hpp:329
static bigfield create_from_u512_as_witness(Builder *ctx, const uint512_t &value, const bool can_overflow=false, const size_t maximum_bitlength=0)
Creates a bigfield element from a uint512_t. Bigfield element is constructed as a witness and not a c...
bigfield pow(const uint32_t exponent) const
Raise the bigfield element to the power of (out-of-circuit) exponent.
static std::pair< bool, size_t > get_quotient_reduction_info(const std::vector< uint512_t > &as_max, const std::vector< uint512_t > &bs_max, const std::vector< bigfield > &to_add, const std::vector< uint1024_t > &remainders_max={ DEFAULT_MAXIMUM_REMAINDER })
Check for 2 conditions (CRT modulus is overflown or the maximum quotient doesn't fit into range proof...
static bigfield unsafe_construct_from_limbs(const field_t< Builder > &a, const field_t< Builder > &b, const field_t< Builder > &c, const field_t< Builder > &d, const bool can_overflow=false)
Construct a bigfield element from binary limbs that are already reduced.
Definition bigfield.hpp:158
static constexpr bigfield unreduced_zero()
Create an unreduced 0 ~ p*k, where p*k is the minimal multiple of modulus that should be reduced.
Definition bigfield.hpp:648
void sanity_check() const
Perform a sanity check on a value that is about to interact with another value.
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)
Evaluate a multiply add identity with several added elements and several remainders.
field_t< Builder > prime_basis_limb
Represents a bigfield element in the prime basis: (a mod n) where n is the native modulus.
Definition bigfield.hpp:86
static bigfield div_without_denominator_check(const std::vector< bigfield > &numerators, const bigfield &denominator)
std::array< Limb, NUM_LIMBS > binary_basis_limbs
Represents a bigfield element in the binary basis. A bigfield element is represented as a combination...
Definition bigfield.hpp:81
uint32_t set_public() const
Set the witness indices for the limbs of the bigfield to public.
Definition bigfield.hpp:743
bool_t< Builder > operator==(const bigfield &other) const
Validate whether two bigfield elements are equal to each other.
bigfield operator/=(const bigfield &other)
Definition bigfield.hpp:474
bigfield operator-() const
Negation operator, works by subtracting this from zero.
Definition bigfield.hpp:457
static constexpr bool is_composite
Definition bigfield.hpp:330
bigfield operator+=(const bigfield &other)
Definition bigfield.hpp:459
static std::pair< uint512_t, uint512_t > compute_partial_schoolbook_multiplication(const std::array< uint256_t, NUM_LIMBS > &a_limbs, const std::array< uint256_t, NUM_LIMBS > &b_limbs)
Compute the partial multiplication of two uint256_t arrays using schoolbook multiplication.
static constexpr bb::fr shift_1
Definition bigfield.hpp:339
void unset_free_witness_tag()
Unset the free witness flag for the bigfield.
Definition bigfield.hpp:729
bigfield(const unsigned long value)
Definition bigfield.hpp:132
void self_reduce() const
Reduce the bigfield element modulo the target modulus.
bigfield invert() const
Inverting function with the assumption that the bigfield element we are calling invert on is not zero...
Definition bigfield.hpp:622
bigfield(const uint256_t &value)
Definition bigfield.hpp:118
static bool mul_product_overflows_crt_modulus(const std::vector< uint512_t > &as_max, const std::vector< uint512_t > &bs_max, const std::vector< bigfield > &to_add)
Definition bigfield.hpp:875
void assert_is_not_equal(const bigfield &other, std::string const &msg="bigfield: prime limb diff is zero, but expected non-zero") const
static constexpr std::array< uint256_t, NUM_LIMBS > neg_modulus_mod_binary_basis_limbs_u256
Definition bigfield.hpp:344
static constexpr uint512_t modulus_u512
Definition bigfield.hpp:316
bigfield operator/(const bigfield &other) const
Implements boolean logic in-circuit.
Definition bool.hpp:60
Represents a dynamic array of bytes in-circuit.
bb::fr additive_constant
Definition field.hpp:94
void clear_round_provenance() const
Definition field.hpp:370
void unset_free_witness_tag() const
Unset the free witness flag for the field element's tag.
Definition field.hpp:368
void convert_constant_to_fixed_witness(Builder *ctx)
Definition field.hpp:456
bool is_constant() const
Definition field.hpp:441
void set_free_witness_tag()
Set the free witness flag for the field element's tag.
Definition field.hpp:363
void set_origin_tag(const OriginTag &new_tag) const
Definition field.hpp:357
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:518
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
std::ostream & operator<<(std::ostream &os, uint256_t const &a)
Definition uint256.hpp:258
uintx< uint256_t > uint512_t
Definition uintx.hpp:306
uintx< uint512_t > uint1024_t
Definition uintx.hpp:308
std::conditional_t< IsGoblinBigGroup< C, Fq, Fr, G >, element_goblin::goblin_element< C, goblin_field< C >, Fr, G >, element_default::element< C, Fq, Fr, G > > element
element wraps either element_default::element or element_goblin::goblin_element depending on parametr...
void mark_witness_as_used(const field_t< Builder > &field)
Mark a field_t witness as used (for UltraBuilder only).
field< Bn254FrParams > fr
Definition fr.hpp:155
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
General class for prime fields see Prime field documentation["field documentation"] for general imple...
static constexpr uint256_t modulus
Represents a single limb of a bigfield element, with its value and maximum value.
Definition bigfield.hpp:45
Limb & operator=(Limb &&other) noexcept=default
Limb(Limb &&other) noexcept=default
Limb(const field_t< Builder > &input, const uint256_t &max=DEFAULT_MAXIMUM_LIMB)
Definition bigfield.hpp:47
Limb & operator=(const Limb &other)=default
field_t< Builder > element
Definition bigfield.hpp:68
friend std::ostream & operator<<(std::ostream &os, const Limb &a)
Definition bigfield.hpp:57
Limb(const Limb &other)=default