16#include "../circuit_builders/circuit_builders.hpp"
19#include "../field/field.hpp"
24template <
typename Builder,
typename T>
34template <
typename Builder,
typename T>
48template <
typename Builder,
typename T>
51 const bool can_overflow,
52 const size_t maximum_bitlength)
55 BB_ASSERT((can_overflow ==
true && maximum_bitlength == 0) ||
56 (can_overflow ==
false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
69 const auto limb_witnesses =
83 uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
86 if (maximum_bitlength > 0) {
89 num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
92 const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
95 const auto limb_witnesses = decompose_non_native_field_double_width_limb(
105 binary_basis_limbs[0] =
Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
106 binary_basis_limbs[1] =
Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
107 binary_basis_limbs[2] =
Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
108 if (maximum_bitlength > 0) {
109 uint256_t max_limb_value = (
uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
110 binary_basis_limbs[3] =
Limb(limb_3, max_limb_value);
112 binary_basis_limbs[3] =
113 Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
115 prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
117 set_origin_tag(new_tag);
120template <
typename Builder,
typename T>
123 , binary_basis_limbs{ other.binary_basis_limbs[0],
124 other.binary_basis_limbs[1],
125 other.binary_basis_limbs[2],
126 other.binary_basis_limbs[3] }
127 , prime_basis_limb(other.prime_basis_limb)
130template <
typename Builder,
typename T>
133 , binary_basis_limbs{ other.binary_basis_limbs[0],
134 other.binary_basis_limbs[1],
135 other.binary_basis_limbs[2],
136 other.binary_basis_limbs[3] }
137 , prime_basis_limb(other.prime_basis_limb)
140template <
typename Builder,
typename T>
143 const bool can_overflow,
144 const size_t maximum_bitlength)
146 BB_ASSERT((can_overflow ==
true && maximum_bitlength == 0) ||
147 (can_overflow ==
false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
149 limbs[0] =
value.slice(0, NUM_LIMB_BITS).lo;
150 limbs[1] =
value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
151 limbs[2] =
value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
152 limbs[3] =
value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
179 ctx->create_unconstrained_gate(
180 ctx->blocks.arithmetic, ctx->zero_idx(), ctx->zero_idx(), ctx->zero_idx(), limb_0.
get_witness_index());
182 uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
185 result.binary_basis_limbs[0] =
Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
186 result.binary_basis_limbs[1] =
Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
187 result.binary_basis_limbs[2] =
Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
188 result.binary_basis_limbs[3] =
189 Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
192 if (maximum_bitlength > 0) {
194 num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
196 result.binary_basis_limbs[3].maximum_value = max_limb_value;
198 result.prime_basis_limb = prime_limb;
201 static_cast<size_t>(NUM_LIMB_BITS),
202 static_cast<size_t>(NUM_LIMB_BITS),
203 "bigfield::create_from_u512_as_witness: limb 0 or 1 too large");
206 static_cast<size_t>(NUM_LIMB_BITS),
207 static_cast<size_t>(num_last_limb_bits),
208 "bigfield::create_from_u512_as_witness: limb 2 or 3 too large");
211 result.set_free_witness_tag();
220 const uint64_t byte_val =
uint256_t(split_byte.get_value()).
data[0];
221 const uint64_t lo_nibble_val = byte_val & 15ULL;
222 const uint64_t hi_nibble_val = byte_val >> 4;
237 const auto reconstruct_two_limbs = [&split_byte_into_nibbles](
Builder* ctx,
241 const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
268 const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
269 const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
273 const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
274 res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits) - 1;
281 if (
this == &other) {
296 binary_basis_limbs[0] = other.binary_basis_limbs[0];
297 binary_basis_limbs[1] = other.binary_basis_limbs[1];
298 binary_basis_limbs[2] = other.binary_basis_limbs[2];
299 binary_basis_limbs[3] = other.binary_basis_limbs[3];
300 prime_basis_limb = other.prime_basis_limb;
310 return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
319 return t0 + t1 + t2 + t3;
322template <
typename Builder,
typename T>
324 const uint256_t& other_maximum_value)
const
328 uint512_t(get_maximum_unreduced_limb_value()));
340 for (
size_t i = 1; i < NUM_LIMBS; i++) {
342 result.binary_basis_limbs[i] =
344 binary_basis_limbs[i].maximum_value);
346 result.binary_basis_limbs[i].element.fix_witness();
354 result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
356 result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
357 result.prime_basis_limb = prime_basis_limb + other;
362template <
typename Builder,
typename T>
376 result.binary_basis_limbs[0].maximum_value =
378 result.binary_basis_limbs[1].maximum_value =
380 result.binary_basis_limbs[2].maximum_value =
382 result.binary_basis_limbs[3].maximum_value =
397 bool both_witness = !is_constant() && !other.
is_constant();
398 bool both_prime_limb_multiplicative_constant_one =
400 if (both_prime_limb_multiplicative_constant_one && both_witness) {
401 bool limbconst = is_constant() || other.
is_constant() ||
409 for (
size_t i = 0; i < NUM_LIMBS; ++i) {
410 const auto& x_limb = binary_basis_limbs[i].element;
413 x_scaled[i] = { x_limb.witness_index, x_limb.multiplicative_constant };
414 y_scaled[i] = { y_limb.witness_index, y_limb.multiplicative_constant };
415 c_adds[i] =
bb::fr(x_limb.additive_constant + y_limb.additive_constant);
419 uint32_t x_prime(prime_basis_limb.witness_index);
423 const auto output_witnesses =
424 ctx->evaluate_non_native_field_addition({ x_scaled[0], y_scaled[0], c_adds[0] },
425 { x_scaled[1], y_scaled[1], c_adds[1] },
426 { x_scaled[2], y_scaled[2], c_adds[2] },
427 { x_scaled[3], y_scaled[3], c_adds[3] },
428 { x_prime, y_prime, c_prime });
453template <
typename Builder,
typename T>
469 result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value +
472 result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value +
475 result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value +
478 result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value +
482 result.binary_basis_limbs[0].element =
484 result.binary_basis_limbs[1].element =
486 result.binary_basis_limbs[2].element =
488 result.binary_basis_limbs[3].element =
495template <
typename Builder,
typename T>
503 uint512_t left = get_value() % modulus_u512;
505 uint512_t out = (left + modulus_u512 - right) % modulus_u512;
514 uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
550 uint64_t limb_0_borrow_shift =
std::max(limb_0_maximum_value.
get_msb() + 1, NUM_LIMB_BITS);
557 uint64_t limb_1_borrow_shift =
std::max(limb_1_maximum_value.
get_msb() + 1, NUM_LIMB_BITS);
560 uint64_t limb_2_borrow_shift =
std::max(limb_2_maximum_value.
get_msb() + 1, NUM_LIMB_BITS);
575 uint512_t constant_to_add = constant_to_add_factor.
lo * modulus_u512;
618 result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
619 result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
620 result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
621 result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
626 result.binary_basis_limbs[0].element = binary_basis_limbs[0].element +
bb::fr(to_add_0);
627 result.binary_basis_limbs[1].element = binary_basis_limbs[1].element +
bb::fr(to_add_1);
628 result.binary_basis_limbs[2].element = binary_basis_limbs[2].element +
bb::fr(to_add_2);
629 result.binary_basis_limbs[3].element = binary_basis_limbs[3].element +
bb::fr(to_add_3);
631 bool both_witness = !is_constant() && !other.
is_constant();
632 bool both_prime_limb_multiplicative_constant_one =
634 if (both_prime_limb_multiplicative_constant_one && both_witness) {
635 bool limbconst = is_constant() || other.
is_constant() ||
644 for (
size_t i = 0; i < NUM_LIMBS; ++i) {
645 const auto& x_limb =
result.binary_basis_limbs[i].element;
648 x_scaled[i] = { x_limb.witness_index, x_limb.multiplicative_constant };
649 y_scaled[i] = { y_limb.witness_index, y_limb.multiplicative_constant };
650 c_diffs[i] =
bb::fr(x_limb.additive_constant - y_limb.additive_constant);
654 uint32_t x_prime(prime_basis_limb.witness_index);
657 uint512_t constant_to_add_mod_native = (constant_to_add) % prime_basis.modulus;
658 c_prime +=
bb::fr(constant_to_add_mod_native.lo);
660 const auto output_witnesses =
661 ctx->evaluate_non_native_field_subtraction({ x_scaled[0], y_scaled[0], c_diffs[0] },
662 { x_scaled[1], y_scaled[1], c_diffs[1] },
663 { x_scaled[2], y_scaled[2], c_diffs[2] },
664 { x_scaled[3], y_scaled[3], c_diffs[3] },
665 { x_prime, y_prime, c_prime });
686 uint512_t constant_to_add_mod_native = (constant_to_add) % prime_basis.modulus;
687 field_t prime_basis_to_add(ctx,
bb::fr(constant_to_add_mod_native.lo));
688 result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
693template <
typename Builder,
typename T>
701 const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*
this, other, {});
716 auto [reduction_required, num_quotient_bits] =
717 get_quotient_reduction_info({ get_maximum_value() }, { other.
get_maximum_value() }, {});
718 if (reduction_required) {
724 return (*this).operator*(other);
726 quotient = create_from_u512_as_witness(ctx, quotient_value,
false, num_quotient_bits);
727 remainder = create_from_u512_as_witness(ctx, remainder_value);
731 unsafe_evaluate_multiply_add(*
this, other, {}, quotient, { remainder });
737template <
typename Builder,
typename T>
741 return internal_div({ *
this }, other,
true);
751template <
typename Builder,
typename T>
756 if (terms.size() == 1) {
761 for (
size_t i = 1; i < (terms.size() + 1) / 2; i++) {
762 acc = acc.
add_two(terms[2 * i - 1], terms[2 * i]);
764 if ((terms.size() & 1) == 0) {
765 acc += terms[terms.size() - 1];
779template <
typename Builder,
typename T>
785 if (numerators.empty()) {
786 if (check_for_zero) {
796 bool numerator_constant =
true;
798 for (
const auto& numerator_element : numerators) {
799 ctx = (ctx ==
nullptr) ? numerator_element.get_context() : ctx;
800 numerator_element.reduction_check();
801 numerator_values += numerator_element.get_value();
802 numerator_constant = numerator_constant && (numerator_element.is_constant());
810 const uint1024_t modulus(target_basis.modulus);
816 const uint256_t denominator_reduced = (right % modulus).lo.lo;
817 if (denominator_reduced != 0) {
819 const NativeField numerator_native(
uint256_t((left % modulus).lo.lo));
820 inverse_value =
uint512_t(
uint256_t(numerator_native * NativeField(denominator_reduced).invert()));
824 (
uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
829 if (numerator_constant && denominator.
is_constant()) {
830 if (check_for_zero) {
842 for (
const auto& n : numerators) {
843 numerator_max.push_back(n.get_maximum_value());
846 auto [reduction_required, num_quotient_bits] =
847 get_quotient_reduction_info({
static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
849 { unreduced_zero() },
851 if (reduction_required) {
854 return internal_div(numerators, denominator, check_for_zero);
857 if (check_for_zero) {
861 quotient = create_from_u512_as_witness(ctx, quotient_value,
false, num_quotient_bits);
862 inverse = create_from_u512_as_witness(ctx, inverse_value);
866 unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
876template <
typename Builder,
typename T>
880 return internal_div(numerators, denominator,
false);
883template <
typename Builder,
typename T>
886 return internal_div({ *
this }, denominator,
false);
894template <
typename Builder,
typename T>
898 return internal_div(numerators, denominator,
true);
906 const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*
this, *
this, {});
915 auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
916 { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
917 if (reduction_required) {
922 quotient = create_from_u512_as_witness(ctx, quotient_value,
false, num_quotient_bits);
923 remainder = create_from_u512_as_witness(ctx, remainder_value);
926 unsafe_evaluate_square_add(*
this, {}, quotient, remainder);
927 remainder.set_origin_tag(get_origin_tag());
931template <
typename Builder,
typename T>
940 bool add_constant =
true;
941 for (
const auto& add_element : to_add) {
942 add_element.reduction_check();
944 add_constant = add_constant && (add_element.is_constant());
950 const uint1024_t modulus(target_basis.modulus);
957 const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
968 const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
970 for (
auto& add_element : to_add) {
971 new_to_add.push_back(add_element);
974 new_to_add.push_back(
bigfield(ctx, remainder_1024.lo.lo));
975 return sum(new_to_add);
980 auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
981 { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
983 if (reduction_required) {
985 return sqradd(to_add);
987 const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
989 uint256_t remainder_value = remainder_1024.lo.lo;
991 quotient = create_from_u512_as_witness(ctx, quotient_value,
false, num_quotient_bits);
992 remainder = create_from_u512_as_witness(ctx, remainder_value);
999 unsafe_evaluate_square_add(*
this, to_add, quotient, remainder);
1006 if (exponent == 0) {
1011 if (is_constant()) {
1012 auto base_val = get_value();
1014 uint512_t base = base_val % modulus_u512;
1015 uint32_t shifted_exponent = exponent;
1018 while (shifted_exponent > 0) {
1019 if (shifted_exponent & 1) {
1023 shifted_exponent >>= 1;
1028 bool accumulator_initialized =
false;
1031 uint32_t shifted_exponent = exponent;
1034 while (shifted_exponent != 0) {
1035 if (shifted_exponent & 1) {
1036 if (!accumulator_initialized) {
1037 accumulator = running_power;
1038 accumulator_initialized =
true;
1040 accumulator *= running_power;
1043 shifted_exponent >>= 1;
1048 if (shifted_exponent != 0) {
1049 running_power = running_power.
sqr();
1055template <
typename Builder,
typename T>
1064 bool add_constant =
true;
1066 for (
const auto& add_element : to_add) {
1067 add_element.reduction_check();
1069 add_constant = add_constant && (add_element.is_constant());
1075 const uint1024_t modulus(target_basis.modulus);
1077 const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1079 const uint512_t quotient_value = quotient_1024.
lo;
1080 const uint512_t remainder_value = remainder_1024.
lo;
1084 if (is_constant() && to_mul.
is_constant() && add_constant) {
1087 }
else if (is_constant() && to_mul.
is_constant()) {
1088 const auto [_, mul_remainder_1024] = (left * mul_right).divmod(modulus);
1093 auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1094 { get_maximum_value() }, { to_mul.
get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1095 if (reduction_required) {
1101 return (*this).madd(to_mul, to_add);
1103 quotient = create_from_u512_as_witness(ctx, quotient_value,
false, num_quotient_bits);
1104 remainder = create_from_u512_as_witness(ctx, remainder_value);
1108 OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.
get_origin_tag());
1109 for (
auto&
element : to_add) {
1110 new_tag = OriginTag(new_tag,
element.get_origin_tag());
1114 unsafe_evaluate_multiply_add(*
this, to_mul, to_add, quotient, { remainder });
1130template <
typename Builder,
typename T>
1139 const size_t number_of_products = mul_left.size();
1144 max_values_left.reserve(number_of_products);
1145 max_values_right.reserve(number_of_products);
1147 for (
auto& left_element : mul_left) {
1148 left_element.reduction_check();
1149 max_values_left.emplace_back(left_element.get_maximum_value());
1152 for (
auto& right_element : mul_right) {
1153 right_element.reduction_check();
1154 max_values_right.emplace_back(right_element.get_maximum_value());
1164 get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1166 if (reduction_required) {
1179 size_t number_of_products) {
1180 maxval_updates.resize(0);
1181 maxval_updates.reserve(number_of_products * 2);
1183 for (
size_t i = 0; i < number_of_products; i++) {
1186 uint1024_t original_product = original_left * original_right;
1187 if (m_left[i].is_constant()) {
1191 uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1192 if (new_product > original_product) {
1195 maxval_updates.emplace_back(
1198 if (m_right[i].is_constant()) {
1202 uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1203 if (new_product > original_product) {
1206 maxval_updates.emplace_back(
1220 while (reduction_required) {
1222 compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1225 std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1228 auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1233 if (multiplicand_index == 0) {
1234 mul_left[largest_update_product_index].self_reduce();
1236 mul_right[largest_update_product_index].self_reduce();
1239 for (
size_t i = 0; i < number_of_products; i++) {
1240 max_values_left[i] = mul_left[i].get_maximum_value();
1241 max_values_right[i] = mul_right[i].get_maximum_value();
1244 get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1261template <
typename Builder,
typename T>
1265 bool fix_remainder_to_zero)
1274 const size_t number_of_products = mul_left.size();
1276 const uint1024_t modulus(target_basis.modulus);
1281 bool add_constant =
true;
1286 for (
auto [left_element, right_element] :
zip_view(mul_left, mul_right)) {
1287 new_tag =
OriginTag(new_tag,
OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1289 for (
auto&
element : to_add) {
1293 for (
const auto& add_element : to_add) {
1294 add_element.reduction_check();
1295 if (add_element.is_constant()) {
1296 add_right_constant_sum +=
uint1024_t(add_element.get_value());
1298 add_constant =
false;
1299 new_to_add.push_back(add_element);
1308 bool product_sum_constant =
true;
1309 for (
size_t i = 0; i < number_of_products; i++) {
1310 if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1312 sum_of_constant_products +=
1316 new_input_left.push_back(mutable_mul_left[i]);
1317 new_input_right.push_back(mutable_mul_right[i]);
1318 product_sum_constant =
false;
1324 for (
auto& el : mutable_mul_left) {
1332 for (
auto& el : mutable_mul_right) {
1339 if (product_sum_constant) {
1342 const auto [quotient_1024, remainder_1024] =
1343 (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1344 BB_ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1346 result.set_origin_tag(new_tag);
1349 const auto [quotient_1024, remainder_1024] =
1350 (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1361 if (fix_remainder_to_zero) {
1363 result.assert_equal(zero());
1365 result.set_origin_tag(new_tag);
1374 const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1375 const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1377 if (constant_part_remainder_256 !=
uint256_t(0)) {
1378 new_to_add.push_back(
bigfield(ctx, constant_part_remainder_256));
1383 for (
const auto& add_element : new_to_add) {
1385 add_element.reduction_check();
1386 add_right_final_sum +=
uint1024_t(add_element.get_value());
1388 add_right_maximum +=
uint1024_t(add_element.get_maximum_value());
1390 const size_t final_number_of_products = new_input_left.size();
1393 worst_case_product_sum =
uint1024_t(final_number_of_products) *
uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1397 BB_ASSERT_LT(worst_case_product_sum + add_right_maximum, get_maximum_crt_product());
1401 perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1403 for (
size_t i = 0; i < final_number_of_products; i++) {
1404 sum_of_products_final +=
uint1024_t(new_input_left[i].get_value()) *
uint1024_t(new_input_right[i].get_value());
1408 const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1411 const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1415 if (fix_remainder_to_zero) {
1419 const uint512_t quotient_value = quotient_1024.
lo;
1420 const uint512_t remainder_value = remainder_1024.
lo;
1425 quotient = create_from_u512_as_witness(ctx, quotient_value,
false, num_quotient_bits);
1427 if (fix_remainder_to_zero) {
1433 remainder = create_from_u512_as_witness(ctx, remainder_value);
1440 unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1450template <
typename Builder,
typename T>
1466 return mult_madd(mul_left, mul_right, to_add);
1487template <
typename Builder,
typename T>
1492 bool enable_divisor_nz_check)
1496 BB_ASSERT((divisor.
get_value() % modulus_u512) != 0,
"bigfield: Division by zero in msub_div");
1499 for (
auto [left_element, right_element] :
zip_view(mul_left, mul_right)) {
1500 new_tag =
OriginTag(new_tag,
OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1502 for (
auto&
element : to_sub) {
1508 for (
auto& el : mul_left) {
1509 if (el.context != NULL) {
1516 for (
auto& el : mul_right) {
1517 if (el.context != NULL) {
1524 for (
auto& el : to_sub) {
1525 if (el.context != NULL) {
1531 const size_t num_multiplications = mul_left.size();
1532 native product_native = 0;
1533 bool products_constant =
true;
1536 if (enable_divisor_nz_check) {
1541 for (
size_t i = 0; i < num_multiplications; ++i) {
1542 const native mul_left_native(
uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1543 const native mul_right_native(
uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1544 product_native += (mul_left_native * -mul_right_native);
1545 products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1550 bool sub_constant =
true;
1551 for (
const auto& sub : to_sub) {
1552 sub_native += (
uint512_t(sub.get_value() % modulus_u512).
lo);
1553 sub_constant = sub_constant && sub.is_constant();
1559 const native result_native = (product_native - sub_native) / divisor_native;
1564 if (sub_constant && products_constant && divisor.
is_constant()) {
1566 result.set_origin_tag(new_tag);
1575 result.set_origin_tag(new_tag);
1579 for (
const auto& in : mul_left) {
1580 eval_left.emplace_back(in);
1582 for (
const auto& in : mul_right) {
1583 eval_right.emplace_back(in);
1586 mult_madd(eval_left, eval_right, to_sub,
true);
1591template <
typename Builder,
typename T>
1600 uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1621template <
typename Builder,
typename T>
1635 const bool is_add_constant_same =
a.additive_constant ==
b.additive_constant;
1636 const bool is_mul_constant_same =
a.multiplicative_constant ==
b.multiplicative_constant;
1637 return is_witness_index_same && is_add_constant_same && is_mul_constant_same;
1644 bool is_prime_limb_same = is_limb_same(prime_basis_limb, other.
prime_basis_limb);
1645 if (is_limb_0_same && is_limb_1_same && is_limb_2_same && is_limb_3_same && is_prime_limb_same) {
1671 other.
binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1673 other.
binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1675 other.
binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1677 other.
binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1682 result.binary_basis_limbs[0] =
1684 result.binary_basis_limbs[1] =
1686 result.binary_basis_limbs[2] =
1688 result.binary_basis_limbs[3] =
1690 result.prime_basis_limb = prime_limb;
1718 auto lhs = get_value() % modulus_u512;
1720 bool is_equal_raw = (
lhs ==
rhs);
1722 return is_equal_raw;
1734 native inverse_native = is_equal_raw ? 0 : diff_native.
invert();
1743 bigfield product = diff * multiplicand;
1758 if (is_constant()) {
1759 uint256_t reduced_value = (get_value() % modulus_u512).lo;
1762 const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1763 binary_basis_limbs[1].
element.get_origin_tag(),
1764 binary_basis_limbs[2].element.get_origin_tag(),
1765 binary_basis_limbs[3].element.get_origin_tag(),
1766 prime_basis_limb.get_origin_tag() });
1777 binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1778 binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1779 binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1780 prime_basis_limb.set_origin_tag(origin_tags[4]);
1784 uint256_t maximum_unreduced_limb_value = get_maximum_unreduced_limb_value();
1785 bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_unreduced_limb_value;
1786 bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_unreduced_limb_value;
1787 bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_unreduced_limb_value;
1788 bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_unreduced_limb_value;
1789 if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1790 limb_overflow_test_2 || limb_overflow_test_3) {
1798 uint256_t prohibited_limb_value = get_prohibited_limb_value();
1799 bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > prohibited_limb_value;
1800 bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > prohibited_limb_value;
1801 bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > prohibited_limb_value;
1802 bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > prohibited_limb_value;
1805 BB_ASSERT(!(get_maximum_value() > get_prohibited_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1806 limb_overflow_test_2 || limb_overflow_test_3));
1809template <
typename Builder,
typename T>
1814 (binary_basis_limbs[0].element * predicate_field).assert_is_zero(msg +
": binary limb 0 not zero");
1815 (binary_basis_limbs[1].element * predicate_field).assert_is_zero(msg +
": binary limb 1 not zero");
1816 (binary_basis_limbs[2].element * predicate_field).assert_is_zero(msg +
": binary limb 2 not zero");
1817 (binary_basis_limbs[3].element * predicate_field).assert_is_zero(msg +
": binary limb 3 not zero");
1818 (prime_basis_limb * predicate_field).assert_is_zero(msg +
": prime limb not zero");
1830 assert_less_than(modulus, msg ==
"bigfield::assert_is_in_field" ?
"bigfield::assert_less_than" : msg);
1835template <
typename Builder,
typename T>
1839 if (is_constant()) {
1840 BB_ASSERT((get_value() % modulus_u512).lo < upper_limit, msg);
1844 bool is_default_msg = msg ==
"bigfield::assert_less_than";
1849 auto ctx = get_context();
1850 ctx->range_constrain_two_limbs(binary_basis_limbs[0].
element.get_witness_index(),
1851 binary_basis_limbs[1].element.get_witness_index(),
1852 static_cast<size_t>(NUM_LIMB_BITS),
1853 static_cast<size_t>(NUM_LIMB_BITS),
1854 is_default_msg ?
"bigfield::assert_less_than: limb 0 or 1 too large" : msg);
1857 ctx->range_constrain_two_limbs(binary_basis_limbs[2].
element.get_witness_index(),
1858 binary_basis_limbs[3].element.get_witness_index(),
1859 static_cast<size_t>(NUM_LIMB_BITS),
1860 static_cast<size_t>(NUM_LAST_LIMB_BITS),
1861 is_default_msg ?
"bigfield::assert_less_than: limb 2 or 3 too large" : msg);
1864 unsafe_assert_less_than(upper_limit, is_default_msg ?
"bigfield::unsafe_assert_less_than" : msg);
1868template <
typename Builder,
typename T>
1871 bool is_default_msg = msg ==
"bigfield::is_less_than";
1876 ctx->range_constrain_two_limbs(binary_basis_limbs[0].
element.get_witness_index(),
1877 binary_basis_limbs[1].element.get_witness_index(),
1878 static_cast<size_t>(NUM_LIMB_BITS),
1879 static_cast<size_t>(NUM_LIMB_BITS),
1880 is_default_msg ?
"bigfield::is_less_than: limb 0 or 1 too large" : msg);
1882 ctx->range_constrain_two_limbs(binary_basis_limbs[2].
element.get_witness_index(),
1883 binary_basis_limbs[3].element.get_witness_index(),
1884 static_cast<size_t>(NUM_LIMB_BITS),
1885 static_cast<size_t>(NUM_LAST_LIMB_BITS),
1886 is_default_msg ?
"bigfield::is_less_than: limb 2 or 3 too large" : msg);
1888 const uint256_t upper_limit_value_0 = upper_limit.
slice(0, NUM_LIMB_BITS);
1889 const uint256_t upper_limit_value_1 = upper_limit.
slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
1890 const uint256_t upper_limit_value_2 = upper_limit.
slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
1892 upper_limit.
slice(NUM_LIMB_BITS * 3, (NUM_LIMB_BITS * 3) + NUM_LAST_LIMB_BITS);
1894 bool_t<Builder> third_limb_is_smaller = binary_basis_limbs[3].element.template ranged_less_than<NUM_LAST_LIMB_BITS>(
1899 binary_basis_limbs[2].element.template ranged_less_than<NUM_LIMB_BITS>(
field_t<Builder>(upper_limit_value_2));
1903 binary_basis_limbs[1].element.template ranged_less_than<NUM_LIMB_BITS>(
field_t<Builder>(upper_limit_value_1));
1907 binary_basis_limbs[0].element.template ranged_less_than<NUM_LIMB_BITS>(
field_t<Builder>(upper_limit_value_0));
1911 third_limb_is_smaller || (third_limb_is_equal && second_limb_is_smaller) ||
1912 (third_limb_is_equal && second_limb_is_equal && first_limb_is_smaller) ||
1913 (third_limb_is_equal && second_limb_is_equal && first_limb_is_equal && zeroth_limb_is_smaller);
1927 unsafe_assert_less_than(modulus);
1932template <
typename Builder,
typename T>
1937 if (is_constant()) {
1948 const uint256_t upper_limit_value_0 = strict_upper_limit.
slice(0, NUM_LIMB_BITS);
1949 const uint256_t upper_limit_value_1 = strict_upper_limit.
slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
1950 const uint256_t upper_limit_value_2 = strict_upper_limit.
slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
1951 const uint256_t upper_limit_value_3 = strict_upper_limit.
slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
1954 const uint256_t val_1 =
value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
1955 const uint256_t val_2 =
value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
1957 bool borrow_0_value = val_0 > upper_limit_value_0;
1958 bool borrow_1_value = (val_1 +
uint256_t(borrow_0_value)) > (upper_limit_value_1);
1959 bool borrow_2_value = (val_2 +
uint256_t(borrow_1_value)) > (upper_limit_value_2);
1979 upper_limit_0 - binary_basis_limbs[0].element + (
static_cast<field_t<Builder>>(borrow_0) * shift_1);
1987 get_context()->range_constrain_two_limbs(
1990 static_cast<size_t>(NUM_LIMB_BITS),
1991 static_cast<size_t>(NUM_LIMB_BITS),
1992 msg ==
"bigfield::unsafe_assert_less_than" ?
"bigfield::unsafe_assert_less_than: r0 or r1 too large" : msg);
1993 get_context()->range_constrain_two_limbs(
1996 static_cast<size_t>(NUM_LIMB_BITS),
1997 static_cast<size_t>(NUM_LAST_LIMB_BITS),
1998 msg ==
"bigfield::unsafe_assert_less_than" ?
"bigfield::unsafe_assert_less_than: r2 or r3 too large" : msg);
2006template <
typename Builder,
typename T>
2011 std::cerr <<
"bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" <<
std::endl;
2012 BB_ASSERT_EQ(get_value(), other.
get_value(),
"We expect constants to be less than the target modulus");
2023 "bigfield::assert_equal: 'this' is not reduced (value >= p). Call self_reduce() before comparing "
2024 "against a constant.");
2037 }
else if (is_constant()) {
2042 uint512_t lhs_reduced_value = get_value() % modulus_u512;
2044 if ((lhs_reduced_value != rhs_reduced_value) && !get_context()->failed()) {
2045 get_context()->failure(msg);
2049 const auto original_tag = get_origin_tag();
2052 set_origin_tag(empty_tag);
2057 const uint512_t modulus(target_basis.modulus);
2059 const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2060 if (remainder_512 != 0) {
2065 const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2067 witness_t(ctx,
fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2070 unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2073 set_origin_tag(original_tag);
2088template <
typename Builder,
typename T>
2092 const auto get_overload_count = [target_modulus = modulus_u512](
const uint512_t& maximum_value) {
2094 size_t overload_count = 0;
2095 while (
target <= maximum_value) {
2097 target += target_modulus;
2099 return overload_count;
2101 const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2102 const size_t rhs_overload_count = get_overload_count(other.
get_maximum_value());
2110 auto diff = base_diff;
2115 for (
size_t i = 0; i < lhs_overload_count; ++i) {
2116 diff = diff * (base_diff - prime_basis_accumulator);
2117 prime_basis_accumulator += prime_basis;
2119 prime_basis_accumulator = prime_basis;
2120 for (
size_t i = 0; i < rhs_overload_count; ++i) {
2121 diff = diff * (base_diff + prime_basis_accumulator);
2122 prime_basis_accumulator += prime_basis;
2135 if (is_constant()) {
2139 const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2143 uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2144 uint64_t maximum_quotient_bits = maximum_quotient_size.
get_msb() + 1;
2145 if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2146 ++maximum_quotient_bits;
2150 uint32_t quotient_limb_index =
context->add_variable(
bb::fr(quotient_value.
lo));
2153 static_cast<size_t>(maximum_quotient_bits));
2156 get_maximum_crt_product());
2167 unsafe_evaluate_multiply_add(*
this, one(), {}, quotient, { remainder });
2168 binary_basis_limbs[0] =
2174 set_origin_tag(new_tag);
2177template <
typename Builder,
typename T>
2186 BB_ASSERT_LTE(input_remainders.size(), MAXIMUM_SUMMAND_COUNT);
2191 for (
auto& el : to_add) {
2194 for (
auto& el : input_remainders) {
2202 bigfield quotient = input_quotient;
2217 std::tie(max_q_neg_p_lo, max_q_neg_p_hi) = compute_partial_schoolbook_multiplication(
2223 for (
const auto& remainder : input_remainders) {
2244 (max_remainders_lo + ((
uint256_t(1) << (2 * NUM_LIMB_BITS)) - 1)) >> (2 * NUM_LIMB_BITS);
2249 for (
size_t i = 0; i < to_add.size(); ++i) {
2250 max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2251 (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2252 max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2253 (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2255 const uint512_t max_lo = max_ab_lo + max_q_neg_p_lo + max_remainders_lo + max_a0;
2256 const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2257 const uint512_t max_hi = max_ab_hi + max_q_neg_p_hi + max_a1 + max_lo_carry;
2259 uint64_t max_lo_bits = (max_lo.
get_msb() + 1);
2260 uint64_t max_hi_bits = max_hi.
get_msb() + 1;
2262 BB_ASSERT(max_lo_bits > (2 * NUM_LIMB_BITS));
2263 BB_ASSERT(max_hi_bits > (2 * NUM_LIMB_BITS));
2265 uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2266 uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2296 const auto convert_constant_to_fixed_witness = [ctx](
const bigfield& input) {
2299 auto original_tag = input.get_origin_tag();
2303 ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2305 ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2307 ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2309 ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2316 left = convert_constant_to_fixed_witness(left);
2319 to_mul = convert_constant_to_fixed_witness(to_mul);
2322 quotient = convert_constant_to_fixed_witness(quotient);
2324 if (remainders[0].is_constant()) {
2325 remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2331 for (
size_t i = 1; i < remainders.size(); ++i) {
2332 limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].
element);
2333 limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].
element * shift_1);
2334 limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].
element);
2335 limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].
element * shift_1);
2336 prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2338 for (
const auto& add : to_add) {
2339 limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2340 limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2341 limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2342 limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2343 prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2346 const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2347 const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2348 bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2349 needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2351 if (needs_normalize) {
2352 limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].
element * shift_1);
2353 limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].
element * shift_1);
2359 : remainders[0].binary_basis_limbs[1].element,
2362 : remainders[0].binary_basis_limbs[3].element,
2371 remainder_limbs[0].get_witness_index(),
2372 remainder_limbs[1].get_witness_index(),
2373 remainder_limbs[2].get_witness_index(),
2374 remainder_limbs[3].get_witness_index(),
2376 { neg_modulus_mod_binary_basis_limbs[0],
2377 neg_modulus_mod_binary_basis_limbs[1],
2378 neg_modulus_mod_binary_basis_limbs[2],
2379 neg_modulus_mod_binary_basis_limbs[3] },
2383 const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2388 -remainder_prime_limb,
2389 "bigfield: prime limb identity failed");
2396 if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2399 static_cast<size_t>(carry_hi_msb),
2400 static_cast<size_t>(carry_lo_msb),
2401 "bigfield::unsafe_evaluate_multiply_add: carries too large");
2408template <
typename Builder,
typename T>
2418 BB_ASSERT_LTE(input_remainders.size(), MAXIMUM_SUMMAND_COUNT);
2421 bool is_left_constant =
true;
2422 for (
auto& el : input_left) {
2424 is_left_constant &= el.is_constant();
2426 bool is_right_constant =
true;
2427 for (
auto& el : input_right) {
2429 is_right_constant &= el.is_constant();
2431 for (
auto& el : to_add) {
2435 for (
auto& el : input_remainders) {
2440 BB_ASSERT(!is_left_constant || !is_right_constant);
2445 bigfield quotient = input_quotient;
2446 const size_t num_multiplications = input_left.size();
2450 for (
const auto& el : input_left) {
2456 if (ctx ==
nullptr) {
2457 for (
const auto& el : input_right) {
2478 for (
const auto& remainder : input_remainders) {
2499 (max_remainders_lo + ((
uint256_t(1) << (2 * NUM_LIMB_BITS)) - 1)) >> (2 * NUM_LIMB_BITS);
2503 const auto [max_q_neg_p_lo, max_q_neg_p_hi] = compute_partial_schoolbook_multiplication(
2507 max_lo += max_q_neg_p_lo + max_remainders_lo;
2508 max_hi += max_q_neg_p_hi;
2513 for (
size_t i = 0; i < to_add.size(); ++i) {
2514 max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2515 (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2516 max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2517 (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2523 for (
size_t i = 0; i < num_multiplications; ++i) {
2524 const auto [product_lo, product_hi] = compute_partial_schoolbook_multiplication(
2525 left[i].get_binary_basis_limb_maximums(), right[i].get_binary_basis_limb_maximums());
2526 max_lo += product_lo;
2527 max_hi += product_hi;
2530 const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2531 max_hi += max_lo_carry;
2534 uint64_t max_lo_bits = (max_lo.
get_msb() + 1);
2535 uint64_t max_hi_bits = max_hi.
get_msb() + 1;
2565 const auto convert_constant_to_fixed_witness = [ctx](
const bigfield& input) {
2569 auto original_tag = input.get_origin_tag();
2573 ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2575 ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2577 ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2579 ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2600 for (
size_t i = 0; i < num_multiplications; ++i) {
2601 if (left[i].is_constant()) {
2602 left[i] = convert_constant_to_fixed_witness(left[i]);
2604 if (right[i].is_constant()) {
2605 right[i] = convert_constant_to_fixed_witness(right[i]);
2610 left[i].get_binary_basis_limb_witness_indices(),
2611 right[i].get_binary_basis_limb_witness_indices(),
2614 const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2624 limb_0_accumulator.emplace_back(-lo_2);
2625 limb_2_accumulator.emplace_back(-hi_2);
2626 prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2630 quotient = convert_constant_to_fixed_witness(quotient);
2633 bool no_remainders = remainders.empty();
2634 if (!no_remainders) {
2635 limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].
element);
2636 limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].
element);
2637 prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2639 for (
size_t i = 1; i < remainders.size(); ++i) {
2640 limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].
element);
2641 limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].
element * shift_1);
2642 limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].
element);
2643 limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].
element * shift_1);
2644 prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2646 for (
const auto& add : to_add) {
2647 limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2648 limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2649 limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2650 limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2651 prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2665 : remainders[0].binary_basis_limbs[1].element;
2670 : remainders[0].binary_basis_limbs[3].element;
2683 left[0].get_binary_basis_limb_witness_indices(),
2684 right[0].get_binary_basis_limb_witness_indices(),
2687 remainder_limbs[0].get_witness_index(),
2688 remainder_limbs[1].get_witness_index(),
2689 remainder_limbs[2].get_witness_index(),
2690 remainder_limbs[3].get_witness_index(),
2692 { neg_modulus_mod_binary_basis_limbs[0],
2693 neg_modulus_mod_binary_basis_limbs[1],
2694 neg_modulus_mod_binary_basis_limbs[2],
2695 neg_modulus_mod_binary_basis_limbs[3] },
2698 const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2701 right[0].prime_basis_limb,
2703 -remainder_prime_limb,
2704 "bigfield: prime limb identity failed");
2709 BB_ASSERT(max_lo_bits > (2 * NUM_LIMB_BITS));
2710 BB_ASSERT(max_hi_bits > (2 * NUM_LIMB_BITS));
2712 uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2713 uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2717 if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2720 static_cast<size_t>(carry_hi_msb),
2721 static_cast<size_t>(carry_lo_msb),
2722 "bigfield::unsafe_evaluate_multiply_add: carries too large");
2729template <
typename Builder,
typename T>
2750 unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
2753template <
typename Builder,
typename T>
2760 for (
const auto& add_element : to_add) {
2761 add_element.reduction_check();
2768 const uint1024_t modulus(target_basis.modulus);
2770 const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
2772 return { quotient_1024.lo, remainder_1024.lo };
2775template <
typename Builder,
typename T>
2784 for (
const auto& add_element : to_add) {
2788 for (
size_t i = 0; i < as.size(); i++) {
2792 const uint1024_t modulus(target_basis.modulus);
2794 const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
2796 return quotient_1024.lo;
2798template <
typename Builder,
typename T>
2808 BB_ASSERT_LTE(remainders_max.size(), MAXIMUM_SUMMAND_COUNT);
2811 if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
2814 const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
2816 for (
auto& added_element : to_add) {
2817 to_add_max.push_back(added_element.get_maximum_value());
2820 const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
2823 if (maximum_quotient >= (
uint512_t(1) << num_quotient_bits)) {
2829template <
typename Builder,
typename T>
2833 const uint512_t b0_inner = (a_limbs[1] * b_limbs[0]);
2834 const uint512_t b1_inner = (a_limbs[0] * b_limbs[1]);
2835 const uint512_t c0_inner = (a_limbs[1] * b_limbs[1]);
2836 const uint512_t c1_inner = (a_limbs[2] * b_limbs[0]);
2837 const uint512_t c2_inner = (a_limbs[0] * b_limbs[2]);
2838 const uint512_t d0_inner = (a_limbs[3] * b_limbs[0]);
2839 const uint512_t d1_inner = (a_limbs[2] * b_limbs[1]);
2840 const uint512_t d2_inner = (a_limbs[1] * b_limbs[2]);
2841 const uint512_t d3_inner = (a_limbs[0] * b_limbs[3]);
2843 const uint512_t r0_inner = (a_limbs[0] * b_limbs[0]);
2844 const uint512_t r1_inner = b0_inner + b1_inner;
2845 const uint512_t r2_inner = c0_inner + c1_inner + c2_inner;
2846 const uint512_t r3_inner = d0_inner + d1_inner + d2_inner + d3_inner;
2847 const uint512_t lo_val = r0_inner + (r1_inner << NUM_LIMB_BITS);
2848 const uint512_t hi_val = r2_inner + (r3_inner << NUM_LIMB_BITS);
2861template <
typename Builder,
typename T>
2863 const uint32_t limb_idx,
2864 const size_t num_limb_bits)
2873 const uint32_t low_idx = ctx->add_variable(
bb::fr(low));
2874 const uint32_t hi_idx = ctx->add_variable(
bb::fr(hi));
2877 const size_t lo_bits = NUM_LIMB_BITS;
2878 const size_t hi_bits = num_limb_bits - NUM_LIMB_BITS;
2879 ctx->range_constrain_two_limbs(
2880 low_idx, hi_idx, lo_bits, hi_bits,
"decompose_non_native_field_double_width_limb: limbs too large");
2888 return std::array<uint32_t, 2>{ low_idx, hi_idx };
#define BB_ASSERT(expression,...)
#define BB_ASSERT_GT(left, right,...)
#define BB_ASSERT_EQ(actual, expected,...)
#define BB_ASSERT_LTE(left, right,...)
#define BB_ASSERT_LT(left, right,...)
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
constexpr uint64_t get_msb() const
static void unsafe_evaluate_multiple_multiply_add(const std::vector< bigfield > &input_left, const std::vector< bigfield > &input_right, const std::vector< bigfield > &to_add, const bigfield &input_quotient, const std::vector< bigfield > &input_remainders)
Evaluate a relation involving multiple multiplications and additions.
static bigfield conditional_assign(const bool_t< Builder > &predicate, const bigfield &lhs, const bigfield &rhs)
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)
Builder * get_context() const
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.
bigfield(const field_t< Builder > &low_bits, const field_t< Builder > &high_bits, const bool can_overflow=false, const size_t maximum_bitlength=0)
Constructs a new bigfield object from two field elements representing the low and high bits.
static void unsafe_evaluate_square_add(const bigfield &left, const std::vector< bigfield > &to_add, const bigfield "ient, const bigfield &remainder)
Evaluate a square with several additions.
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
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)
void assert_less_than(const uint256_t &upper_limit, std::string const &msg="bigfield::assert_less_than") const
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 & operator=(const bigfield &other)
void convert_constant_to_fixed_witness(Builder *builder)
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.
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.
bb::OriginTag get_origin_tag() const
static bigfield from_witness(Builder *ctx, const bb::field< T > &input)
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 uint256_t modulus
bool_t< Builder > is_less_than(const uint256_t &upper_limit, std::string const &msg="bigfield::is_less_than") const
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...
bool is_constant() const
Check if the bigfield is constant, i.e. its prime limb is constant.
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 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.
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.
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...
bool_t< Builder > operator==(const bigfield &other) const
Validate whether two bigfield elements are equal to each other.
bigfield operator-() const
Negation operator, works by subtracting this from zero.
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.
void self_reduce() const
Reduce the bigfield element modulo the target modulus.
void assert_is_not_equal(const bigfield &other, std::string const &msg="bigfield: prime limb diff is zero, but expected non-zero") const
bigfield operator/(const bigfield &other) const
Implements boolean logic in-circuit.
void set_origin_tag(const OriginTag &new_tag) const
void unset_free_witness_tag()
OriginTag get_origin_tag() const
Represents a dynamic array of bytes in-circuit.
byte_array slice(size_t offset) const
Slice bytes from the byte array starting at offset. Does not add any constraints.
Builder * get_context() const
bb::OriginTag get_origin_tag() const
void assert_is_zero(std::string const &msg="field_t::assert_is_zero") const
Enforce a copy constraint between *this and 0 stored at zero_idx of the Builder.
void assert_equal(const field_t &rhs, std::string const &msg="field_t::assert_equal") const
Copy constraint: constrain that *this field is equal to rhs element.
field_t madd(const field_t &to_mul, const field_t &to_add) const
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
static void evaluate_polynomial_identity(const field_t &a, const field_t &b, const field_t &c, const field_t &d, const std::string &msg="field_t::evaluate_polynomial_identity")
Given a, b, c, d, constrain a * b + c + d = 0 by creating a big_mul_gate.
static field_t accumulate(const std::vector< field_t > &input)
Efficiently compute the sum of vector entries. Using big_add_gate we reduce the number of gates neede...
static bool witness_indices_match(const field_t &a, const field_t &b)
Check if two field elements have the same witness index (for identity checks).
void create_range_constraint(size_t num_bits, std::string const &msg="field_t::range_constraint") const
Let x = *this.normalize(), constrain x.v < 2^{num_bits}.
bb::fr multiplicative_constant
static field_t conditional_assign_internal(const bool_t< Builder > &predicate, const field_t &lhs, const field_t &rhs)
If predicate == true then return lhs, else return rhs.
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
static void evaluate_linear_identity(const field_t &a, const field_t &b, const field_t &c, const field_t &d, const std::string &msg="field_t::evaluate_linear_identity")
Constrain a + b + c + d to be equal to 0.
void set_origin_tag(const OriginTag &new_tag) const
void assert_is_not_zero(std::string const &msg="field_t::assert_is_not_zero") const
Constrain *this to be non-zero by establishing that it has an inverse.
uint32_t get_witness_index() const
Get the witness index of the current field element.
StrictMock< MockContext > context
stdlib::field_t< Builder > field_ct
void add_values(TreeType &tree, const std::vector< NullifierLeafValue > &values)
uintx< uint256_t > uint512_t
uintx< uint512_t > uint1024_t
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...
Entry point for Barretenberg command-line interface.
Univariate< Fr, domain_end > operator+(const Fr &ff, const Univariate< Fr, domain_end > &uv)
field< Bn254FrParams > fr
C slice(C const &container, size_t start)
Inner sum(Cont< Inner, Args... > const &in)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::vector< Instruction > target
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
bb::VectorAffineElementPushSpan< BaseParams > lhs
bb::VectorAffineElementPushSpan< BaseParams > out
bb::VectorAffineElementPushSpan< BaseParams > rhs
static OriginTag constant()
constexpr field invert() const noexcept
Represents a single limb of a bigfield element, with its value and maximum value.
void throw_or_abort(std::string const &err)