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_is_in_field(std::string const& msg = "bigfield::assert_is_in_field") const;
576 void assert_less_than(const uint256_t& upper_limit, std::string const& msg = "bigfield::assert_less_than") const;
577 void reduce_mod_target_modulus() const;
578 void assert_equal(const bigfield& other, std::string const& msg = "bigfield::assert_equal") const;
579 void assert_is_not_equal(const bigfield& other,
580 std::string const& msg = "bigfield: prime limb diff is zero, but expected non-zero") const;
581
591 void self_reduce() const;
592
600 bool is_constant() const
601 {
602 bool is_limb_0_constant = binary_basis_limbs[0].element.is_constant();
603 bool is_limb_1_constant = binary_basis_limbs[1].element.is_constant();
604 bool is_limb_2_constant = binary_basis_limbs[2].element.is_constant();
605 bool is_limb_3_constant = binary_basis_limbs[3].element.is_constant();
606 bool is_prime_limb_constant = prime_basis_limb.is_constant();
607 BB_ASSERT_EQ(is_limb_0_constant, is_limb_1_constant);
608 BB_ASSERT_EQ(is_limb_1_constant, is_limb_2_constant);
609 BB_ASSERT_EQ(is_limb_2_constant, is_limb_3_constant);
610 BB_ASSERT_EQ(is_limb_3_constant, is_prime_limb_constant);
611 return is_prime_limb_constant;
612 }
613
619 bigfield invert() const { return (bigfield(1) / bigfield(*this)); }
620
624 static bigfield one()
625 {
626 bigfield result(nullptr, uint256_t(1));
627 return result;
628 }
629
633 static bigfield zero()
634 {
635 bigfield result(nullptr, uint256_t(0));
636 return result;
637 }
638
645 static constexpr bigfield unreduced_zero()
646 {
647 uint512_t multiple_of_modulus = ((get_maximum_unreduced_value() / modulus_u512) + 1) * modulus_u512;
648 auto msb = multiple_of_modulus.get_msb();
649
650 bigfield result(nullptr, uint256_t(0));
651 result.binary_basis_limbs[0] = Limb(bb::fr(multiple_of_modulus.slice(0, NUM_LIMB_BITS).lo));
652 result.binary_basis_limbs[1] = Limb(bb::fr(multiple_of_modulus.slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS).lo));
653 result.binary_basis_limbs[2] = Limb(bb::fr(multiple_of_modulus.slice(2 * NUM_LIMB_BITS, 3 * NUM_LIMB_BITS).lo));
654 result.binary_basis_limbs[3] = Limb(bb::fr(multiple_of_modulus.slice(3 * NUM_LIMB_BITS, msb + 1).lo));
655 result.prime_basis_limb = field_t<Builder>((multiple_of_modulus % uint512_t(field_t<Builder>::modulus)).lo);
656 return result;
657 }
658
663 {
665 for (auto& limb : binary_basis_limbs) {
666 limb.element.convert_constant_to_fixed_witness(context);
667 }
669 }
670
675 {
676 // Origin tags should be updated within
677 for (auto& limb : binary_basis_limbs) {
678 limb.element.fix_witness();
679 }
681
682 // This is now effectively a constant
684 }
685
686 Builder* get_context() const { return context; }
687
689 {
690 for (size_t i = 0; i < NUM_LIMBS; i++) {
691 binary_basis_limbs[i].element.set_origin_tag(tag);
692 }
694 }
696 {
697 for (size_t i = 0; i < NUM_LIMBS; i++) {
698 binary_basis_limbs[i].element.clear_round_provenance();
699 }
701 }
702
704 {
706 binary_basis_limbs[1].element.tag,
707 binary_basis_limbs[2].element.tag,
708 binary_basis_limbs[3].element.tag,
710 }
711
716 {
717 for (auto& limb : binary_basis_limbs) {
718 limb.element.set_free_witness_tag();
719 }
721 }
722
727 {
728 for (auto& limb : binary_basis_limbs) {
729 limb.element.unset_free_witness_tag();
730 }
732 }
740 uint32_t set_public() const
741 {
742 // Reduce bigfield to canonical form before combining into 2-limb format.
743 self_reduce();
744
745 Builder* ctx = get_context();
746 const uint32_t start_index = static_cast<uint32_t>(ctx->num_public_inputs());
747
748 // Combine limbs into 2-limb Codec format
749 constexpr uint256_t shift = uint256_t(1) << NUM_LIMB_BITS;
750 field_t<Builder> lo = binary_basis_limbs[0].element + binary_basis_limbs[1].element * shift;
751 field_t<Builder> hi = binary_basis_limbs[2].element + binary_basis_limbs[3].element * shift;
752
753 // Mark as used witnesses (these are intentionally in one gate for public input encoding)
756
757 ctx->set_public_input(lo.get_witness_index());
758 ctx->set_public_input(hi.get_witness_index());
759
760 return start_index;
761 }
762
764 {
765 // This = `T * n = 2^272 * |BN(Fr)|` So this equals n*2^t
766 uint1024_t maximum_product = get_maximum_crt_product();
767
768 // In multiplying two bigfield elements a and b, we must check that:
769 //
770 // a * b = q * p + r
771 //
772 // where q is the quotient, r is the remainder, and p is the size of the non-native field.
773 // The CRT requires that we check that the equation:
774 // (a) holds modulo the size of the native field n,
775 // (b) holds modulo the size of the bigger ring 2^t,
776 // (c) both sides of the equation are less than the max product M = 2^t * n.
777 // Thus, the max value of an unreduced bigfield element is √M. In this case, we use
778 // an even stricter bound. Let n = 2^m + l (where 1 < l < 2^m). Thus, we have:
779 //
780 // M = 2^t * n = 2^t * (2^m + l) = 2^(t + m) + (2^t * l)
781 // => M > 2^(t + m)
782 // => √M > 2^((t + m) / 2)
783 //
784 // We set the maximum unreduced value of a bigfield element to be: 2^((t + m) / 2) < √M.
785 //
786 // Note: We use a further safer bound of 2^((t + m - 1) / 2). We use -1 to stay safer,
787 // because it provides additional space to avoid the overflow, but get_msb() by itself should be enough.
788 uint64_t maximum_product_bits = maximum_product.get_msb() - 1;
789 return (uint512_t(1) << (maximum_product_bits >> 1)) - uint512_t(1);
790 }
791
792 // If we encounter this maximum value of a bigfield we stop execution
794 {
795 uint1024_t maximum_product = get_maximum_crt_product();
796 uint64_t maximum_product_bits = maximum_product.get_msb() - 1;
797 const size_t arbitrary_secure_margin = 20;
798 return (uint512_t(1) << ((maximum_product_bits >> 1) + arbitrary_secure_margin)) - uint512_t(1);
799 }
800
811 {
813 return maximum_product;
814 }
815
826 static size_t get_quotient_max_bits(const std::vector<uint1024_t>& remainders_max)
827 {
828 // find q_max * p + ...remainders_max < nT
830 for (const auto& r : remainders_max) {
831 base -= r;
832 }
833 base /= modulus_u512;
834 return static_cast<size_t>(base.get_msb() - 1);
835 }
836
847 const uint1024_t& b_max,
848 const std::vector<bigfield>& to_add)
849 {
850 uint1024_t product = a_max * b_max;
851 uint1024_t add_term = 0;
852 for (const auto& add : to_add) {
853 add_term += add.get_maximum_value();
854 }
855 constexpr uint1024_t maximum_default_bigint = uint1024_t(1) << (NUM_LIMB_BITS * 6 + NUM_LAST_LIMB_BITS * 2);
856
857 // check that the add terms alone cannot overflow the crt modulus. v. unlikely so just forbid circuits that
858 // trigger this case
859 BB_ASSERT_LT(add_term + maximum_default_bigint, get_maximum_crt_product());
860 return ((product + add_term) >= get_maximum_crt_product());
861 }
862
873 const std::vector<uint512_t>& bs_max,
874 const std::vector<bigfield>& to_add)
875 {
877 BB_ASSERT_EQ(as_max.size(), bs_max.size());
878 // Computing individual products
879 uint1024_t product_sum = 0;
880 uint1024_t add_term = 0;
881 for (size_t i = 0; i < as_max.size(); i++) {
882 product_sum += uint1024_t(as_max[i]) * uint1024_t(bs_max[i]);
883 }
884 for (const auto& add : to_add) {
885 add_term += add.get_maximum_value();
886 }
887 static const uint1024_t maximum_default_bigint = uint1024_t(1) << (NUM_LIMB_BITS * 6 + NUM_LAST_LIMB_BITS * 2);
888
889 // check that the add terms alone cannot overflow the crt modulus. v. unlikely so just forbid circuits that
890 // trigger this case
891 BB_ASSERT_LT(add_term + maximum_default_bigint, get_maximum_crt_product());
892 return ((product_sum + add_term) >= get_maximum_crt_product());
893 }
894
895 // a (currently generous) upper bound on the log of number of fr additions in any of the class operations
896 static constexpr uint64_t MAX_ADDITION_LOG = 10;
897
898 // The rationale of the expression is we should not overflow Fr when applying any bigfield operation (e.g. *) and
899 // starting with this max limb size
900 //
901 // In multiplication of bigfield elements a * b, we encounter sum of limbs multiplications of form:
902 // c0 := a0 * b0
903 // c1 := a1 * b0 + a0 * b1
904 // c2 := a2 * b0 + a1 * b1 + a0 * b2
905 // c3 := a3 * b0 + a2 * b1 + a1 * b2 + a0 * b3
906 // output:
907 // lo := c0 + c1 * 2^L,
908 // hi := c2 + c3 * 2^L.
909 // Since hi term contains upto 4 limb-products, we must ensure that the hi term does not overflow the native field
910 // 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
911 // doesn't overflow the native field modulus. Hence:
912 // max(∑ hi) = max(∑ c2 + c3 * 2^L)
913 // = max(∑ c2) + max(∑ c3 * 2^L)
914 // = 2^k * (3 * 2^2Q) + 2^k * 2^L * (4 * 2^2Q)
915 // < 2^k * (2^L + 1) * (4 * 2^2Q)
916 // < n
917 // ==> 2^k * 2^L * 2^(2Q + 3) < n
918 // ==> 2Q + 3 < (log(n) - k - L)
919 // ==> Q < ((log(n) - k - L) - 3) / 2
920 //
921 static constexpr uint64_t MAXIMUM_LIMB_SIZE_THAT_WOULDNT_OVERFLOW =
923
924 // If the logarithm of the maximum value of a limb is more than this, we need to reduce.
925 // We allow an element to be added to itself 10 times, so we allow the limb to grow by 10 bits.
926 // Number 10 is arbitrary, there's no actual usecase for adding 1024 elements together.
928
929 // If we reach this size of a limb, we stop execution (as safety measure). This should never reach during addition
930 // as we would reduce the limbs before they reach this size.
931 static constexpr uint64_t PROHIBITED_LIMB_BITS = MAX_UNREDUCED_LIMB_BITS + 5;
932
933 // If we encounter this maximum value of a bigfield we need to reduce it.
935 {
936 return ((uint256_t(1) << MAX_UNREDUCED_LIMB_BITS) - uint256_t(1));
937 }
938
939 // If we encounter this maximum value of a limb we stop execution
941
943
944 // For testing purposes only
946
947 private:
954 void unsafe_assert_less_than(const uint256_t& upper_limit,
955 std::string const& msg = "bigfield::unsafe_assert_less_than") const;
956
963 {
964 std::array<uint32_t, NUM_LIMBS> limb_witness_indices;
965 for (size_t i = 0; i < NUM_LIMBS; i++) {
966 limb_witness_indices[i] = binary_basis_limbs[i].element.get_witness_index();
967 }
968 return limb_witness_indices;
969 }
970
982 static std::array<uint32_t, 2> decompose_non_native_field_double_width_limb(
983 Builder* ctx, const uint32_t limb_idx, const size_t num_limb_bits = (2 * NUM_LIMB_BITS));
984
994 const bigfield& b,
995 const std::vector<bigfield>& to_add);
1005 const std::vector<uint512_t>& bs,
1006 const std::vector<uint512_t>& to_add);
1007
1019 const std::vector<uint512_t>& bs_max,
1020 const std::vector<bigfield>& to_add,
1021 const std::vector<uint1024_t>& remainders_max = {
1023
1043 static void unsafe_evaluate_multiply_add(const bigfield& input_left,
1044 const bigfield& input_to_mul,
1045 const std::vector<bigfield>& to_add,
1046 const bigfield& input_quotient,
1047 const std::vector<bigfield>& input_remainders);
1048
1069 const std::vector<bigfield>& input_right,
1070 const std::vector<bigfield>& to_add,
1071 const bigfield& input_quotient,
1072 const std::vector<bigfield>& input_remainders);
1073
1088 static void unsafe_evaluate_square_add(const bigfield& left,
1089 const std::vector<bigfield>& to_add,
1090 const bigfield& quotient,
1091 const bigfield& remainder);
1092
1113 void reduction_check() const;
1114
1121 void sanity_check() const;
1122
1129 {
1131 for (size_t i = 0; i < NUM_LIMBS; i++) {
1132 limb_maximums[i] = binary_basis_limbs[i].maximum_value;
1133 }
1134 return limb_maximums;
1135 }
1136
1151
1152}; // namespace stdlib
1153
1154// NOTE: For testing private functions in bigfield
1156 public:
1157 template <typename bigfield>
1158 static void unsafe_assert_less_than(const bigfield& input, const uint256_t& upper_limit)
1159 {
1160 input.unsafe_assert_less_than(upper_limit);
1161 }
1162
1163 template <typename bigfield>
1164 static void unsafe_evaluate_multiply_add(const bigfield& input_left,
1165 const bigfield& input_to_mul,
1166 const std::vector<bigfield>& to_add,
1167 const bigfield& input_quotient,
1168 const std::vector<bigfield>& input_remainders)
1169 {
1170 bigfield::unsafe_evaluate_multiply_add(input_left, input_to_mul, to_add, input_quotient, input_remainders);
1171 }
1172
1173 template <typename bigfield>
1175 const std::vector<bigfield>& input_right,
1176 const std::vector<bigfield>& to_add,
1177 const bigfield& input_quotient,
1178 const std::vector<bigfield>& input_remainders)
1179 {
1181 input_left, input_right, to_add, input_quotient, input_remainders);
1182 }
1183};
1184
1185template <typename C, typename T> inline std::ostream& operator<<(std::ostream& os, bigfield<T, C> const& v)
1186{
1187 return os << v.get_value();
1188}
1189
1190} // 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:82
constexpr uint64_t get_msb() const
Definition uintx.hpp:69
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:633
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:826
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:763
static constexpr uint256_t get_prohibited_limb_value()
Definition bigfield.hpp:940
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:896
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:927
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:846
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:695
Builder * get_context() const
Definition bigfield.hpp:686
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:810
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:921
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:688
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:931
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:934
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:715
static constexpr uint512_t get_prohibited_value()
Definition bigfield.hpp:793
bigfield & operator=(const bigfield &other)
void convert_constant_to_fixed_witness(Builder *builder)
Definition bigfield.hpp:662
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:624
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:962
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:703
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.
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
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:600
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:645
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:740
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:726
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:619
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:872
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:254
uintx< uint256_t > uint512_t
Definition uintx.hpp:307
uintx< uint512_t > uint1024_t
Definition uintx.hpp:309
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...
Definition biggroup.hpp:978
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:174
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