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
80 const Limb& get_limb(size_t i) const { return binary_basis_limbs[i]; }
81
86
94 void set_limb_max(size_t i, const uint256_t& m)
95 {
96#ifndef NDEBUG
98 m,
99 "bigfield::set_limb_max: new max is below current witness value");
100#endif
101 binary_basis_limbs[i].maximum_value = m;
102 }
103
113 bigfield(const field_t<Builder>& low_bits,
114 const field_t<Builder>& high_bits,
115 const bool can_overflow = false,
116 const size_t maximum_bitlength = 0);
117
124 bigfield(Builder* parent_context = nullptr);
125
132 bigfield(Builder* parent_context, const uint256_t& value);
133
134 explicit bigfield(const uint256_t& value)
135 : bigfield(nullptr, uint256_t(value))
136 {}
137
143 bigfield(const int value)
144 : bigfield(nullptr, uint256_t(native(value)))
145 {}
146
147 // NOLINTNEXTLINE(google-runtime-int) intended behavior
148 bigfield(const unsigned long value)
149 : bigfield(nullptr, value)
150 {}
151
152 // NOLINTNEXTLINE(google-runtime-int) intended behavior
153 bigfield(const unsigned long long value)
154 : bigfield(nullptr, value)
155 {}
156
164 : bigfield(nullptr, uint256_t(value))
165 {}
166
175 const field_t<Builder>& b,
176 const field_t<Builder>& c,
177 const field_t<Builder>& d,
178 const bool can_overflow = false)
179 {
180 BB_ASSERT_EQ(a.is_constant(), b.is_constant());
181 BB_ASSERT_EQ(b.is_constant(), c.is_constant());
184 result.context = a.context;
185 result.binary_basis_limbs[0] = Limb(field_t(a));
186 result.binary_basis_limbs[1] = Limb(field_t(b));
187 result.binary_basis_limbs[2] = Limb(field_t(c));
188 result.binary_basis_limbs[3] =
190 result.prime_basis_limb = (result.binary_basis_limbs[3].element * shift_3)
191 .add_two(result.binary_basis_limbs[2].element * shift_2,
192 result.binary_basis_limbs[1].element * shift_1);
193 result.prime_basis_limb += (result.binary_basis_limbs[0].element);
194 return result;
195 };
196
203 const field_t<Builder>& b,
204 const field_t<Builder>& c,
205 const field_t<Builder>& d,
206 const bool can_overflow = false)
207 {
208 BB_ASSERT_EQ(a.is_constant(), b.is_constant());
209 BB_ASSERT_EQ(b.is_constant(), c.is_constant());
212 auto ctx = a.context;
213 result.context = a.context;
214 result.binary_basis_limbs[0] = Limb(field_t(a));
215 result.binary_basis_limbs[1] = Limb(field_t(b));
216 result.binary_basis_limbs[2] = Limb(field_t(c));
217 result.binary_basis_limbs[3] =
219 result.prime_basis_limb = (result.binary_basis_limbs[3].element * shift_3)
220 .add_two(result.binary_basis_limbs[2].element * shift_2,
221 result.binary_basis_limbs[1].element * shift_1);
222 result.prime_basis_limb += (result.binary_basis_limbs[0].element);
223
224 // Range contrain the first two limbs each to NUM_LIMB_BITS
225 ctx->range_constrain_two_limbs(result.binary_basis_limbs[0].element.get_witness_index(),
226 result.binary_basis_limbs[1].element.get_witness_index(),
227 static_cast<size_t>(NUM_LIMB_BITS),
228 static_cast<size_t>(NUM_LIMB_BITS),
229 "bigfield::construct_from_limbs: limb 0 or 1 too large");
230
231 // Range constrain the last two limbs to NUM_LIMB_BITS and NUM_LAST_LIMB_BITS
232 const size_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
233 ctx->range_constrain_two_limbs(result.binary_basis_limbs[2].element.get_witness_index(),
234 result.binary_basis_limbs[3].element.get_witness_index(),
235 static_cast<size_t>(NUM_LIMB_BITS),
236 static_cast<size_t>(num_last_limb_bits),
237 "bigfield::construct_from_limbs: limb 2 or 3 too large");
238
239 return result;
240 };
241
250 const field_t<Builder>& b,
251 const field_t<Builder>& c,
252 const field_t<Builder>& d,
253 const field_t<Builder>& prime_limb,
254 const bool can_overflow = false)
255 {
256 BB_ASSERT_EQ(a.is_constant(), b.is_constant());
257 BB_ASSERT_EQ(b.is_constant(), c.is_constant());
259 BB_ASSERT_EQ(d.is_constant(), prime_limb.is_constant());
261 result.context = a.context;
262 result.binary_basis_limbs[0] = Limb(field_t(a));
263 result.binary_basis_limbs[1] = Limb(field_t(b));
264 result.binary_basis_limbs[2] = Limb(field_t(c));
265 result.binary_basis_limbs[3] =
267 result.prime_basis_limb = prime_limb;
268
269#ifndef NDEBUG
270 std::array<bb::fr, NUM_LIMBS> limbs = { a.get_value(), b.get_value(), c.get_value(), d.get_value() };
272 bb::fr reconstructed_value =
273 limbs[0] + (limbs[1] * shift) + (limbs[2] * shift * shift) + (limbs[3] * shift * shift * shift);
274 bb::fr prime_limb_native = prime_limb.get_value();
275 BB_ASSERT_EQ(reconstructed_value, prime_limb_native);
276#endif
277 return result;
278 };
279
293 bigfield(const byte_array<Builder>& bytes);
294
295 // Copy constructor
296 bigfield(const bigfield& other);
297
298 // Move constructor
299 bigfield(bigfield&& other) noexcept;
300
301 // Destructor
302 ~bigfield() = default;
303
318 const uint512_t& value,
319 const bool can_overflow = false,
320 const size_t maximum_bitlength = 0);
321
322 static bigfield from_witness(Builder* ctx, const bb::field<T>& input)
323 {
324 uint256_t input_u256(input);
325 field_t<Builder> low(witness_t<Builder>(ctx, bb::fr(input_u256.slice(0, NUM_LIMB_BITS * 2))));
327 auto result = bigfield(low, hi);
328 result.set_free_witness_tag();
329 return result;
330 }
331
332 // Disallow from_witness for non-bb::fr types to prevent implicit conversions (specifically, using indices rather
333 // than values)
334 template <typename OT> static bigfield from_witness(Builder* ctx, const OT& input) = delete;
335
336 bigfield& operator=(const bigfield& other);
337 bigfield& operator=(bigfield&& other) noexcept;
338
339 // Code assumes modulus is at most 256 bits so good to define it via a uint256_t
340 static constexpr uint256_t modulus = (uint256_t(T::modulus_0, T::modulus_1, T::modulus_2, T::modulus_3));
341 static constexpr uint512_t modulus_u512 = static_cast<uint512_t>(modulus);
342 static constexpr uint64_t NUM_LIMB_BITS = NUM_LIMB_BITS_IN_FIELD_SIMULATION;
343 static constexpr uint64_t NUM_LAST_LIMB_BITS = modulus_u512.get_msb() + 1 - (NUM_LIMB_BITS * 3);
344
345 // The quotient reduction checks currently only support >=250 bit moduli and moduli >256 have never been tested
346 // (Check zkSecurity audit report issue #12 for explanation)
347 static_assert(modulus_u512.get_msb() + 1 >= 250 && modulus_u512.get_msb() + 1 <= 256);
348
354 static constexpr uint64_t LOG2_BINARY_MODULUS = NUM_LIMB_BITS * NUM_LIMBS;
355 static constexpr bool is_composite = true; // false only when fr is native
356
357 // This limits the size of all vectors that are being used to 16 (we don't really need more)
358 static constexpr size_t MAXIMUM_SUMMAND_COUNT_LOG = 4;
359 static constexpr size_t MAXIMUM_SUMMAND_COUNT = 1 << MAXIMUM_SUMMAND_COUNT_LOG;
360
363 static constexpr Basis target_basis{ modulus_u512, static_cast<size_t>(modulus_u512.get_msb() + 1) };
364 static constexpr bb::fr shift_1 = bb::fr(uint256_t(1) << NUM_LIMB_BITS);
365 static constexpr bb::fr shift_2 = bb::fr(uint256_t(1) << (NUM_LIMB_BITS * 2));
366 static constexpr bb::fr shift_3 = bb::fr(uint256_t(1) << (NUM_LIMB_BITS * 3));
381
382 // Gets the integer (uint512_t) value of the bigfield element by combining the binary basis limbs.
383 uint512_t get_value() const;
384
385 // Gets the maximum value of the bigfield element by combining the maximum values of the binary basis limbs.
387
404 bigfield add_to_lower_limb(const field_t<Builder>& other, const uint256_t& other_maximum_value) const;
405
420 bigfield operator+(const bigfield& other) const;
421
433 bigfield add_two(const bigfield& add_a, const bigfield& add_b) const;
434
448 bigfield operator-(const bigfield& other) const;
449
463 bigfield operator*(const bigfield& other) const;
464
475 bigfield operator/(const bigfield& other) const;
476
482 bigfield operator-() const { return bigfield(get_context(), uint256_t(0)) - *this; }
483
485 {
486 *this = operator+(other);
487 return *this;
488 }
490 {
491 *this = operator-(other);
492 return *this;
493 }
495 {
496 *this = operator*(other);
497 return *this;
498 }
500 {
501 *this = operator/(other);
502 return *this;
503 }
504
513 bigfield sqr() const;
514
524 bigfield sqradd(const std::vector<bigfield>& to_add) const;
525
537 bigfield pow(const uint32_t exponent) const;
538
547 bigfield madd(const bigfield& to_mul, const std::vector<bigfield>& to_add) const;
548
550 std::vector<bigfield>& mul_right,
551 const std::vector<bigfield>& to_add);
552
553 static bigfield mult_madd(const std::vector<bigfield>& mul_left,
554 const std::vector<bigfield>& mul_right,
555 const std::vector<bigfield>& to_add,
556 bool fix_remainder_to_zero = false);
557
558 static bigfield dual_madd(const bigfield& left_a,
559 const bigfield& right_a,
560 const bigfield& left_b,
561 const bigfield& right_b,
562 const std::vector<bigfield>& to_add);
563
564 // compute -(mul_left * mul_right + ...to_sub) / (divisor)
565 // We can evaluate this relationship with only one set of quotient/remainder range checks
566 static bigfield msub_div(const std::vector<bigfield>& mul_left,
567 const std::vector<bigfield>& mul_right,
568 const bigfield& divisor,
569 const std::vector<bigfield>& to_sub,
570 bool enable_divisor_nz_check = true);
571
572 static bigfield sum(const std::vector<bigfield>& terms);
573 static bigfield internal_div(const std::vector<bigfield>& numerators,
574 const bigfield& denominator,
575 bool check_for_zero);
576
577 static bigfield div_without_denominator_check(const std::vector<bigfield>& numerators, const bigfield& denominator);
579 static bigfield div_check_denominator_nonzero(const std::vector<bigfield>& numerators, const bigfield& denominator);
580
581 bigfield conditional_negate(const bool_t<Builder>& predicate) const;
582
592 bigfield conditional_select(const bigfield& other, const bool_t<Builder>& predicate) const;
593 static bigfield conditional_assign(const bool_t<Builder>& predicate, const bigfield& lhs, const bigfield& rhs)
594 {
595 return rhs.conditional_select(lhs, predicate);
596 }
597
598 bool_t<Builder> operator==(const bigfield& other) const;
599
600 void assert_zero_if(const bool_t<Builder>& predicate,
601 std::string const& msg = "bigfield::assert_zero_if failed") const;
602 void assert_is_in_field(std::string const& msg = "bigfield::assert_is_in_field") const;
603 void assert_less_than(const uint256_t& upper_limit, std::string const& msg = "bigfield::assert_less_than") const;
604 void reduce_mod_target_modulus() const;
605 void assert_equal(const bigfield& other, std::string const& msg = "bigfield::assert_equal") const;
606 void assert_is_not_equal(const bigfield& other,
607 std::string const& msg = "bigfield: prime limb diff is zero, but expected non-zero") const;
608 bool_t<Builder> is_less_than(const uint256_t& upper_limit, std::string const& msg = "bigfield::is_less_than") const;
609
619 void self_reduce() const;
620
628 bool is_constant() const
629 {
630 bool is_limb_0_constant = binary_basis_limbs[0].element.is_constant();
631 bool is_limb_1_constant = binary_basis_limbs[1].element.is_constant();
632 bool is_limb_2_constant = binary_basis_limbs[2].element.is_constant();
633 bool is_limb_3_constant = binary_basis_limbs[3].element.is_constant();
634 bool is_prime_limb_constant = prime_basis_limb.is_constant();
635 BB_ASSERT_EQ(is_limb_0_constant, is_limb_1_constant);
636 BB_ASSERT_EQ(is_limb_1_constant, is_limb_2_constant);
637 BB_ASSERT_EQ(is_limb_2_constant, is_limb_3_constant);
638 BB_ASSERT_EQ(is_limb_3_constant, is_prime_limb_constant);
639 return is_prime_limb_constant;
640 }
641
647 bigfield invert() const { return (bigfield(1) / bigfield(*this)); }
648
652 static bigfield one()
653 {
654 bigfield result(nullptr, uint256_t(1));
655 return result;
656 }
657
661 static bigfield zero()
662 {
663 bigfield result(nullptr, uint256_t(0));
664 return result;
665 }
666
673 static constexpr bigfield unreduced_zero()
674 {
675 uint512_t multiple_of_modulus = ((get_maximum_unreduced_value() / modulus_u512) + 1) * modulus_u512;
676 auto msb = multiple_of_modulus.get_msb();
677
678 bigfield result(nullptr, uint256_t(0));
679 result.binary_basis_limbs[0] = Limb(bb::fr(multiple_of_modulus.slice(0, NUM_LIMB_BITS).lo));
680 result.binary_basis_limbs[1] = Limb(bb::fr(multiple_of_modulus.slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS).lo));
681 result.binary_basis_limbs[2] = Limb(bb::fr(multiple_of_modulus.slice(2 * NUM_LIMB_BITS, 3 * NUM_LIMB_BITS).lo));
682 result.binary_basis_limbs[3] = Limb(bb::fr(multiple_of_modulus.slice(3 * NUM_LIMB_BITS, msb + 1).lo));
683 result.prime_basis_limb = field_t<Builder>((multiple_of_modulus % uint512_t(field_t<Builder>::modulus)).lo);
684 return result;
685 }
686
691 {
693 for (auto& limb : binary_basis_limbs) {
694 limb.element.convert_constant_to_fixed_witness(context);
695 }
697 }
698
703 {
704 // Origin tags should be updated within
705 for (auto& limb : binary_basis_limbs) {
706 limb.element.fix_witness();
707 }
709
710 // This is now effectively a constant
712 }
713
714 Builder* get_context() const { return context; }
715
717 {
718 for (size_t i = 0; i < NUM_LIMBS; i++) {
719 binary_basis_limbs[i].element.set_origin_tag(tag);
720 }
722 }
724 {
725 for (size_t i = 0; i < NUM_LIMBS; i++) {
726 binary_basis_limbs[i].element.clear_round_provenance();
727 }
729 }
730
732 {
734 binary_basis_limbs[1].element.tag,
735 binary_basis_limbs[2].element.tag,
736 binary_basis_limbs[3].element.tag,
738 }
739
744 {
745 for (auto& limb : binary_basis_limbs) {
746 limb.element.set_free_witness_tag();
747 }
749 }
750
755 {
756 for (auto& limb : binary_basis_limbs) {
757 limb.element.unset_free_witness_tag();
758 }
760 }
768 uint32_t set_public() const
769 {
770 // Reduce bigfield to canonical form before combining into 2-limb format.
771 self_reduce();
772
773 Builder* ctx = get_context();
774 const uint32_t start_index = static_cast<uint32_t>(ctx->num_public_inputs());
775
776 // Combine limbs into 2-limb Codec format
777 constexpr uint256_t shift = uint256_t(1) << NUM_LIMB_BITS;
778 field_t<Builder> lo = binary_basis_limbs[0].element + binary_basis_limbs[1].element * shift;
779 field_t<Builder> hi = binary_basis_limbs[2].element + binary_basis_limbs[3].element * shift;
780
781 // Mark as used witnesses (these are intentionally in one gate for public input encoding)
784
785 ctx->set_public_input(lo.get_witness_index());
786 ctx->set_public_input(hi.get_witness_index());
787
788 return start_index;
789 }
790
792 {
793 // This = `T * n = 2^272 * |BN(Fr)|` So this equals n*2^t
794 uint1024_t maximum_product = get_maximum_crt_product();
795
796 // In multiplying two bigfield elements a and b, we must check that:
797 //
798 // a * b = q * p + r
799 //
800 // where q is the quotient, r is the remainder, and p is the size of the non-native field.
801 // The CRT requires that we check that the equation:
802 // (a) holds modulo the size of the native field n,
803 // (b) holds modulo the size of the bigger ring 2^t,
804 // (c) both sides of the equation are less than the max product M = 2^t * n.
805 // Thus, the max value of an unreduced bigfield element is √M. In this case, we use
806 // an even stricter bound. Let n = 2^m + l (where 1 < l < 2^m). Thus, we have:
807 //
808 // M = 2^t * n = 2^t * (2^m + l) = 2^(t + m) + (2^t * l)
809 // => M > 2^(t + m)
810 // => √M > 2^((t + m) / 2)
811 //
812 // We set the maximum unreduced value of a bigfield element to be: 2^((t + m) / 2) < √M.
813 //
814 // Note: We use a further safer bound of 2^((t + m - 1) / 2). We use -1 to stay safer,
815 // because it provides additional space to avoid the overflow, but get_msb() by itself should be enough.
816 uint64_t maximum_product_bits = maximum_product.get_msb() - 1;
817 return (uint512_t(1) << (maximum_product_bits >> 1)) - uint512_t(1);
818 }
819
820 // If we encounter this maximum value of a bigfield we stop execution
822 {
823 uint1024_t maximum_product = get_maximum_crt_product();
824 uint64_t maximum_product_bits = maximum_product.get_msb() - 1;
825 const size_t arbitrary_secure_margin = 20;
826 return (uint512_t(1) << ((maximum_product_bits >> 1) + arbitrary_secure_margin)) - uint512_t(1);
827 }
828
839 {
841 return maximum_product;
842 }
843
854 static size_t get_quotient_max_bits(const std::vector<uint1024_t>& remainders_max)
855 {
856 // find q_max * p + ...remainders_max < nT
858 for (const auto& r : remainders_max) {
859 base -= r;
860 }
861 base /= modulus_u512;
862 return static_cast<size_t>(base.get_msb() - 1);
863 }
864
875 const uint1024_t& b_max,
876 const std::vector<bigfield>& to_add)
877 {
878 uint1024_t product = a_max * b_max;
879 uint1024_t add_term = 0;
880 for (const auto& add : to_add) {
881 add_term += add.get_maximum_value();
882 }
883 constexpr uint1024_t maximum_default_bigint = uint1024_t(1) << (NUM_LIMB_BITS * 6 + NUM_LAST_LIMB_BITS * 2);
884
885 // check that the add terms alone cannot overflow the crt modulus. v. unlikely so just forbid circuits that
886 // trigger this case
887 BB_ASSERT_LT(add_term + maximum_default_bigint, get_maximum_crt_product());
888 return ((product + add_term) >= get_maximum_crt_product());
889 }
890
901 const std::vector<uint512_t>& bs_max,
902 const std::vector<bigfield>& to_add)
903 {
905 BB_ASSERT_EQ(as_max.size(), bs_max.size());
906 // Computing individual products
907 uint1024_t product_sum = 0;
908 uint1024_t add_term = 0;
909 for (size_t i = 0; i < as_max.size(); i++) {
910 product_sum += uint1024_t(as_max[i]) * uint1024_t(bs_max[i]);
911 }
912 for (const auto& add : to_add) {
913 add_term += add.get_maximum_value();
914 }
915 static const uint1024_t maximum_default_bigint = uint1024_t(1) << (NUM_LIMB_BITS * 6 + NUM_LAST_LIMB_BITS * 2);
916
917 // check that the add terms alone cannot overflow the crt modulus. v. unlikely so just forbid circuits that
918 // trigger this case
919 BB_ASSERT_LT(add_term + maximum_default_bigint, get_maximum_crt_product());
920 return ((product_sum + add_term) >= get_maximum_crt_product());
921 }
922
923 // a (currently generous) upper bound on the log of number of fr additions in any of the class operations
924 static constexpr uint64_t MAX_ADDITION_LOG = 10;
925
926 // The rationale of the expression is we should not overflow Fr when applying any bigfield operation (e.g. *) and
927 // starting with this max limb size
928 //
929 // In multiplication of bigfield elements a * b, we encounter sum of limbs multiplications of form:
930 // c0 := a0 * b0
931 // c1 := a1 * b0 + a0 * b1
932 // c2 := a2 * b0 + a1 * b1 + a0 * b2
933 // c3 := a3 * b0 + a2 * b1 + a1 * b2 + a0 * b3
934 // output:
935 // lo := c0 + c1 * 2^L,
936 // hi := c2 + c3 * 2^L.
937 // Since hi term contains upto 4 limb-products, we must ensure that the hi term does not overflow the native field
938 // 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
939 // doesn't overflow the native field modulus. Hence:
940 // max(∑ hi) = max(∑ c2 + c3 * 2^L)
941 // = max(∑ c2) + max(∑ c3 * 2^L)
942 // = 2^k * (3 * 2^2Q) + 2^k * 2^L * (4 * 2^2Q)
943 // < 2^k * (2^L + 1) * (4 * 2^2Q)
944 // < n
945 // ==> 2^k * 2^L * 2^(2Q + 3) < n
946 // ==> 2Q + 3 < (log(n) - k - L)
947 // ==> Q < ((log(n) - k - L) - 3) / 2
948 //
949 static constexpr uint64_t MAXIMUM_LIMB_SIZE_THAT_WOULDNT_OVERFLOW =
951
952 // If the logarithm of the maximum value of a limb is more than this, we need to reduce.
953 // We allow an element to be added to itself 10 times, so we allow the limb to grow by 10 bits.
954 // Number 10 is arbitrary, there's no actual usecase for adding 1024 elements together.
956
957 // If we reach this size of a limb, we stop execution (as safety measure). This should never reach during addition
958 // as we would reduce the limbs before they reach this size.
959 static constexpr uint64_t PROHIBITED_LIMB_BITS = MAX_UNREDUCED_LIMB_BITS + 5;
960
961 // If we encounter this maximum value of a bigfield we need to reduce it.
963 {
964 return ((uint256_t(1) << MAX_UNREDUCED_LIMB_BITS) - uint256_t(1));
965 }
966
967 // If we encounter this maximum value of a limb we stop execution
969
971
972 // For testing purposes only
974
975 private:
984
993
1000 void unsafe_assert_less_than(const uint256_t& upper_limit,
1001 std::string const& msg = "bigfield::unsafe_assert_less_than") const;
1002
1009 {
1010 std::array<uint32_t, NUM_LIMBS> limb_witness_indices;
1011 for (size_t i = 0; i < NUM_LIMBS; i++) {
1012 limb_witness_indices[i] = binary_basis_limbs[i].element.get_witness_index();
1013 }
1014 return limb_witness_indices;
1015 }
1016
1028 static std::array<uint32_t, 2> decompose_non_native_field_double_width_limb(
1029 Builder* ctx, const uint32_t limb_idx, const size_t num_limb_bits = (2 * NUM_LIMB_BITS));
1030
1040 const bigfield& b,
1041 const std::vector<bigfield>& to_add);
1051 const std::vector<uint512_t>& bs,
1052 const std::vector<uint512_t>& to_add);
1053
1065 const std::vector<uint512_t>& bs_max,
1066 const std::vector<bigfield>& to_add,
1067 const std::vector<uint1024_t>& remainders_max = {
1069
1089 static void unsafe_evaluate_multiply_add(const bigfield& input_left,
1090 const bigfield& input_to_mul,
1091 const std::vector<bigfield>& to_add,
1092 const bigfield& input_quotient,
1093 const std::vector<bigfield>& input_remainders);
1094
1115 const std::vector<bigfield>& input_right,
1116 const std::vector<bigfield>& to_add,
1117 const bigfield& input_quotient,
1118 const std::vector<bigfield>& input_remainders);
1119
1134 static void unsafe_evaluate_square_add(const bigfield& left,
1135 const std::vector<bigfield>& to_add,
1136 const bigfield& quotient,
1137 const bigfield& remainder);
1138
1159 void reduction_check() const;
1160
1167 void sanity_check() const;
1168
1175 {
1177 for (size_t i = 0; i < NUM_LIMBS; i++) {
1178 limb_maximums[i] = binary_basis_limbs[i].maximum_value;
1179 }
1180 return limb_maximums;
1181 }
1182
1197
1198}; // namespace stdlib
1199
1200// NOTE: For testing private functions in bigfield
1202 public:
1203 template <typename bigfield>
1204 static void unsafe_assert_less_than(const bigfield& input, const uint256_t& upper_limit)
1205 {
1206 input.unsafe_assert_less_than(upper_limit);
1207 }
1208
1209 template <typename bigfield>
1210 static void unsafe_evaluate_multiply_add(const bigfield& input_left,
1211 const bigfield& input_to_mul,
1212 const std::vector<bigfield>& to_add,
1213 const bigfield& input_quotient,
1214 const std::vector<bigfield>& input_remainders)
1215 {
1216 bigfield::unsafe_evaluate_multiply_add(input_left, input_to_mul, to_add, input_quotient, input_remainders);
1217 }
1218
1219 template <typename bigfield>
1221 const std::vector<bigfield>& input_right,
1222 const std::vector<bigfield>& to_add,
1223 const bigfield& input_quotient,
1224 const std::vector<bigfield>& input_remainders)
1225 {
1227 input_left, input_right, to_add, input_quotient, input_remainders);
1228 }
1229
1230 template <typename bigfield>
1231 static void set_limb_element(bigfield& bf, size_t i, const typename bigfield::field_ct& v)
1232 {
1233 bf.binary_basis_limbs[i].element = v;
1234 }
1235
1236 template <typename bigfield> static void set_prime_basis_limb(bigfield& bf, const typename bigfield::field_ct& v)
1237 {
1238 bf.prime_basis_limb = v;
1239 }
1240
1241 template <typename bigfield> static void fix_witness_in_place(const bigfield& bf)
1242 {
1243 for (size_t i = 0; i < bigfield::NUM_LIMBS; ++i) {
1244 bf.binary_basis_limbs[i].element.fix_witness();
1245 }
1247 }
1248};
1249
1250template <typename C, typename T> inline std::ostream& operator<<(std::ostream& os, bigfield<T, C> const& v)
1251{
1252 return os << v.get_value();
1253}
1254
1255} // 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 set_prime_basis_limb(bigfield &bf, const typename bigfield::field_ct &v)
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 fix_witness_in_place(const bigfield &bf)
static void unsafe_assert_less_than(const bigfield &input, const uint256_t &upper_limit)
static void set_limb_element(bigfield &bf, size_t i, const typename bigfield::field_ct &v)
static bigfield zero()
Definition bigfield.hpp:661
static constexpr uint256_t DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB
Definition bigfield.hpp:352
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:854
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:249
static constexpr uint512_t get_maximum_unreduced_value()
Definition bigfield.hpp:791
static constexpr uint256_t get_prohibited_limb_value()
Definition bigfield.hpp:968
static constexpr uint64_t NUM_LIMB_BITS
Definition bigfield.hpp:342
static constexpr Basis binary_basis
Definition bigfield.hpp:362
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:924
static bigfield conditional_assign(const bool_t< Builder > &predicate, const bigfield &lhs, const bigfield &rhs)
Definition bigfield.hpp:593
static constexpr uint64_t MAX_UNREDUCED_LIMB_BITS
Definition bigfield.hpp:955
static constexpr size_t MAXIMUM_SUMMAND_COUNT_LOG
Definition bigfield.hpp:358
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:874
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:723
Builder * get_context() const
Definition bigfield.hpp:714
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:838
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:949
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:202
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:716
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:375
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:363
static constexpr uint64_t PROHIBITED_LIMB_BITS
Definition bigfield.hpp:959
static constexpr Basis prime_basis
Definition bigfield.hpp:361
static const uint1024_t DEFAULT_MAXIMUM_REMAINDER
Definition bigfield.hpp:349
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:163
const field_t< Builder > & get_prime_basis_limb() const
Read-only access to the prime basis limb.
Definition bigfield.hpp:85
static constexpr uint256_t get_maximum_unreduced_limb_value()
Definition bigfield.hpp:962
static constexpr uint64_t NUM_LAST_LIMB_BITS
Definition bigfield.hpp:343
void set_free_witness_tag()
Set the free witness flag for the bigfield.
Definition bigfield.hpp:743
static constexpr uint512_t get_prohibited_value()
Definition bigfield.hpp:821
bigfield & operator=(const bigfield &other)
void convert_constant_to_fixed_witness(Builder *builder)
Definition bigfield.hpp:690
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:494
static constexpr uint512_t negative_prime_modulus_mod_binary_basis
Definition bigfield.hpp:368
static bigfield one()
Definition bigfield.hpp:652
static constexpr uint256_t DEFAULT_MAXIMUM_LIMB
Definition bigfield.hpp:351
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.
bigfield(const unsigned long long value)
Definition bigfield.hpp:153
static constexpr size_t MAXIMUM_SUMMAND_COUNT
Definition bigfield.hpp:359
bb::OriginTag get_origin_tag() const
Definition bigfield.hpp:731
bigfield operator-=(const bigfield &other)
Definition bigfield.hpp:489
static bigfield from_witness(Builder *ctx, const bb::field< T > &input)
Definition bigfield.hpp:322
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:367
static constexpr uint256_t modulus
Definition bigfield.hpp:340
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:365
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:143
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:366
bool is_constant() const
Check if the bigfield is constant, i.e. its prime limb is constant.
Definition bigfield.hpp:628
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:354
const Limb & get_limb(size_t i) const
Read-only access to a binary basis limb (element + maximum_value).
Definition bigfield.hpp:80
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:174
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:673
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:992
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:983
uint32_t set_public() const
Set the witness indices for the limbs of the bigfield to public.
Definition bigfield.hpp:768
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:499
void set_limb_max(size_t i, const uint256_t &m)
Set the maximum_value of a binary basis limb.
Definition bigfield.hpp:94
bigfield operator-() const
Negation operator, works by subtracting this from zero.
Definition bigfield.hpp:482
static constexpr bool is_composite
Definition bigfield.hpp:355
bigfield operator+=(const bigfield &other)
Definition bigfield.hpp:484
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:364
void unset_free_witness_tag()
Unset the free witness flag for the bigfield.
Definition bigfield.hpp:754
bigfield(const unsigned long value)
Definition bigfield.hpp:148
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:647
bigfield(const uint256_t &value)
Definition bigfield.hpp:134
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:900
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:369
static constexpr uint512_t modulus_u512
Definition bigfield.hpp:341
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:384
void unset_free_witness_tag() const
Unset the free witness flag for the field element's tag.
Definition field.hpp:382
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:838
void convert_constant_to_fixed_witness(Builder *ctx)
Definition field.hpp:470
bool is_constant() const
Definition field.hpp:455
void set_free_witness_tag()
Set the free witness flag for the field element's tag.
Definition field.hpp:377
void set_origin_tag(const OriginTag &new_tag) const
Definition field.hpp:358
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:532
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
uintx< uint256_t > uint512_t
Definition uintx.hpp:309
uintx< uint512_t > uint1024_t
Definition uintx.hpp:311
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).
std::ostream & operator<<(std::ostream &os, CircuitKind kind)
field< Bn254FrParams > fr
Definition fr.hpp:155
constexpr ScalarIndex shift(ScalarIndex ctx, size_t d)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
bb::VectorAffineElementPushSpan< BaseParams > lhs
bb::VectorAffineElementPushSpan< BaseParams > rhs
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
VectorField result