38 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
39 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
41 return montgomery_mul(other);
44 return montgomery_mul(other);
46 field result = asm_mul_with_coarse_reduction(*
this, other);
54 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
55 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
62 asm_self_mul_with_coarse_reduction(*
this, other);
76 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
77 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
78 return montgomery_square();
81 return montgomery_square();
83 field result = asm_sqr_with_coarse_reduction(*
this);
91 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
92 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
93 *
this = montgomery_square();
96 *
this = montgomery_square();
98 asm_self_sqr_with_coarse_reduction(*
this);
111 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
112 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
118 field result = asm_add_with_coarse_reduction(*
this, other);
126 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
127 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
133 asm_self_add_with_coarse_reduction(*
this, other);
134 assert_coarse_form();
148 field<T> value_before_incrementing = *
this;
150 return value_before_incrementing;
160 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
161 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
162 return subtract(other);
165 return subtract(other);
167 field result = asm_sub_with_coarse_reduction(*
this, other);
179 constexpr field p{ modulus.
data[0], modulus.data[1], modulus.data[2], modulus.data[3] };
185 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
186 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
187 *
this = subtract(other);
190 *
this = subtract(other);
192 asm_self_sub_with_coarse_reduction(*
this, other);
193 assert_coarse_form();
202 constexpr field p{ modulus.
data[0], modulus.data[1], modulus.data[2], modulus.data[3] };
208 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
209 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
210 *
this = predicate ? -(*this) : *
this;
213 *
this = predicate ? -(*this) : *
this;
215 asm_conditional_negate(*
this, predicate);
233 const field left = reduce_once();
235 const bool t0 = left.
data[3] > right.
data[3];
236 const bool t1 = (left.
data[3] == right.
data[3]) && (left.
data[2] > right.
data[2]);
239 const bool t3 = (left.
data[3] == right.
data[3]) && (left.
data[2] == right.
data[2]) &&
241 return (t0 || t1 || t2 || t3);
257 return (other > *
this);
265 const field left = reduce_once();
273 return (!
operator==(other));
289 constexpr field r_squared =
290 field{ r_squared_uint.
data[0], r_squared_uint.data[1], r_squared_uint.data[2], r_squared_uint.data[3] };
291 return *
this * r_squared;
296 constexpr field one_raw{ 1, 0, 0, 0 };
303 field{ r_squared_uint.
data[0], r_squared_uint.data[1], r_squared_uint.data[2], r_squared_uint.data[3] };
309 constexpr field one_raw{ 1, 0, 0, 0 };
326 self_to_montgomery_form();
332 self_from_montgomery_form();
338 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
339 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
345 return asm_reduce_once(*
this);
351 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) ||
352 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
358 asm_self_reduce_once(*
this);
367 const uint64_t maximum_set_bit = exponent.get_msb();
369 for (
int i =
static_cast<int>(maximum_set_bit) - 1; i >= 0; --i) {
370 accumulator.self_sqr();
371 if (exponent.get_bit(
static_cast<uint64_t
>(i))) {
372 accumulator *= to_mul;
377 }
else if (*
this == zero()) {
378 accumulator = zero();
385 return pow({ exponent, 0, 0, 0 });
390 if (*
this == zero()) {
395 return pow(modulus_minus_two);
397 if constexpr (bernstein_yang::supported_v<T>) {
400 field non_mont = from_montgomery_form_reduced();
404 result.self_to_montgomery_form();
407 return pow(modulus_minus_two);
413 if (*
this == zero()) {
416 return pow(modulus_minus_two);
421 batch_invert(std::span{ coeffs, n });
426 batch_invert<decltype(coeffs)>(coeffs);
439 requires requires(
C& c) {
445 const size_t n = coeffs.size();
448 std::vector<bool> skipped;
449 temporaries.resize(n);
452 field accumulator = one();
453 for (
size_t i = 0; i < n; ++i) {
454 temporaries[i] = accumulator;
455 if (coeffs[i].is_zero()) {
459 accumulator *= coeffs[i];
462 accumulator = accumulator.invert();
465 for (
size_t i = n - 1; i < n; --i) {
467 T0 = accumulator * temporaries[i];
468 accumulator *= coeffs[i];
510 constexpr uint256_t Q = (modulus - 1) >>
static_cast<uint64_t
>(primitive_root_log_size());
511 constexpr uint256_t Q_minus_one_over_two = (Q - 1) >> 1;
513 field v = pow(Q_minus_one_over_two);
526 for (
size_t i = 0; i < primitive_root_log_size() - 1; ++i) {
539 constexpr field g = coset_generator().pow(Q);
542 constexpr field g_inv = coset_generator().
pow(modulus - 1 - Q);
545 constexpr size_t root_bits = primitive_root_log_size();
550 constexpr size_t table_bits = 6;
554 constexpr size_t num_tables = root_bits / table_bits + (root_bits % table_bits != 0 ? 1 : 0);
555 constexpr size_t num_offset_tables = num_tables - 1;
558 constexpr size_t table_size =
static_cast<size_t>(1UL) << table_bits;
564 constexpr auto get_g_table = [&](
const field& h) {
567 for (
size_t i = 1; i < table_size; ++i) {
568 result[i] = result[i - 1] * h;
577 field working_base = g_inv;
579 for (
size_t i = 0; i < num_tables; ++i) {
580 result[i] = get_g_table(working_base);
582 for (
size_t j = 0; j < table_bits; ++j) {
593 field working_base = g_inv;
595 for (
size_t i = 0; i < root_bits % table_bits; ++i) {
599 for (
size_t i = 0; i < num_offset_tables; ++i) {
600 result[i] = get_g_table(working_base);
601 for (
size_t j = 0; j < table_bits; ++j) {
602 working_base.self_sqr();
611 constexpr GTable root_table_a = get_g_table(
g.pow(1UL << ((num_tables - 1) * table_bits)));
613 constexpr GTable root_table_b = get_g_table(
g.pow(1UL << (root_bits - table_bits)));
622 for (
size_t i = 0; i < num_tables - 1; ++i) {
623 uvv_powers[i] = base;
624 for (
size_t j = 0; j < table_bits; ++j) {
628 uvv_powers[num_tables - 1] = base;
636 for (
size_t i = 0; i < num_tables; ++i) {
638 size_t table_index = num_tables - 1 - i;
641 field target = uvv_powers[table_index];
645 for (
size_t j = 0; j < i; ++j) {
646 size_t e_idx = num_tables - 1 - (i - 1) + j;
647 size_t g_idx = num_tables - 2 - j;
651 g_lookup = offset_g_tables[g_idx - 1][e_slices[e_idx]];
653 g_lookup = g_tables[g_idx][e_slices[e_idx]];
664 for (
auto& x : root_table_a) {
672 for (
auto& x : root_table_b) {
680 if (count == table_size) {
684 e_slices[table_index] = count;
694 for (
size_t i = 0; i < num_tables; ++i) {
695 auto& e_slice = e_slices[num_tables - 1 - i];
699 if ((e_slice & 1UL) == 1UL) {
702 size_t borrow_value = (i == 1) ? 1UL << ((root_bits % table_bits) - 1) : (1UL << (table_bits - 1));
703 e_slices[num_tables - i] += borrow_value;
713 field g_pow_minus_e_over_2 = 1;
714 for (
size_t i = 0; i < num_tables; ++i) {
716 g_pow_minus_e_over_2 *= g_tables[i][e_slices[num_tables - 1 - i]];
718 g_pow_minus_e_over_2 *= offset_g_tables[i - 1][e_slices[num_tables - 1 - i]];
722 auto result = uv * g_pow_minus_e_over_2;
723 if (result * result != *
this) {
731 requires((T::modulus_0 & 0x3UL) == 0x3UL)
734 field root = pow(sqrt_exponent);
735 if ((root * root) == (*
this)) {
743 requires((T::modulus_0 & 0x3UL) != 0x3UL)
745 field root = tonelli_shanks_sqrt();
746 if ((root * root) == (*
this)) {
759 *
this = operator/(other);
765 data[3] = 0ULL | (1ULL << 63ULL);
770 return (
data[3] >> 63ULL) == 1ULL;
775 return (
data[3] >> 63ULL);
784 const uint64_t mod_zero =
785 (
data[0] ^ T::modulus_0) | (
data[1] ^ T::modulus_1) | (
data[2] ^ T::modulus_2) | (
data[3] ^ T::modulus_3);
786 return static_cast<bool>(
static_cast<uint64_t
>(raw_zero == 0) |
static_cast<uint64_t
>(mod_zero == 0));
791#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
792 field r{ T::primitive_root_0, T::primitive_root_1, T::primitive_root_2, T::primitive_root_3 };
794 field r{ T::primitive_root_wasm_0, T::primitive_root_wasm_1, T::primitive_root_wasm_2, T::primitive_root_wasm_3 };
796 for (
size_t i = primitive_root_log_size(); i > subgroup_size; --i) {
812 return lo + (pow_2_256 * hi);
819 while (!target.
get_bit(result)) {
831 auto adjusted = from_montgomery_form_reduced();
836 uint64_t bin_data[4] = {
837 htonll(adjusted.data[3]), htonll(adjusted.data[2]), htonll(adjusted.data[1]), htonll(adjusted.data[0])
841 packer.pack_bin(
sizeof(bin_data));
842 packer.pack_bin_body((
const char*)bin_data,
sizeof(bin_data));
851 std::array<uint8_t,
sizeof(
data)> raw_data = o;
855 uint64_t* cast_data = (uint64_t*)&raw_data[0];
856 uint64_t reversed[] = { ntohll(cast_data[3]), ntohll(cast_data[2]), ntohll(cast_data[1]), ntohll(cast_data[0]) };
859 for (
int i = 0; i < 4; i++) {
860 data[i] = reversed[i];
865 throw_or_abort(
"msgpack field deserialization: non-canonical encoding (value >= modulus)");
869 *
this = to_montgomery_form();
virtual uint256_t get_random_uint256()=0
constexpr bool get_bit(uint64_t bit_index) const
constexpr u64 p_inv_mod_2k_from_montgomery_r_inv(u64 r_inv) noexcept
uint256_t invert_vartime(const uint256_t &a, const uint256_t &p, u64 p_inv_mod_2k) noexcept
Variable-time safegcd inverse (Bernstein-Yang TCHES 2019, Pornin 2020 §4).
Entry point for Barretenberg command-line interface.
Univariate< Fr, domain_end > operator+(const Fr &ff, const Univariate< Fr, domain_end > &uv)
void assert_failure(std::string const &err)
Univariate< Fr, domain_end > operator*(const Fr &ff, const Univariate< Fr, domain_end > &uv)
constexpr void g(state_array &state, size_t a, size_t b, size_t c, size_t d, uint32_t x, uint32_t y)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
General class for prime fields see Prime field documentation["field documentation"] for general imple...
void assert_coarse_form() const noexcept
BB_INLINE constexpr field from_montgomery_form_reduced() const noexcept
static constexpr field get_root_of_unity(size_t subgroup_size) noexcept
BB_INLINE constexpr field & operator+=(const field &other) &noexcept
BB_INLINE constexpr void self_to_montgomery_form_reduced() &noexcept
static constexpr field one()
BB_INLINE constexpr void self_reduce_once() &noexcept
BB_INLINE constexpr bool operator!=(const field &other) const noexcept
BB_INLINE constexpr field operator*(const field &other) const noexcept
BB_INLINE constexpr field operator+(const field &other) const noexcept
constexpr field tonelli_shanks_sqrt() const noexcept
Implements an optimized variant of Tonelli-Shanks via lookup tables. Algorithm taken from https://cr....
BB_INLINE constexpr void self_from_montgomery_form_reduced() &noexcept
BB_INLINE constexpr field to_montgomery_form() const noexcept
BB_INLINE constexpr void self_conditional_negate(uint64_t predicate) &noexcept
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
BB_INLINE constexpr field operator++() noexcept
constexpr field operator/(const field &other) const noexcept
BB_INLINE constexpr void self_sqr() &noexcept
constexpr field invert() const noexcept
BB_INLINE constexpr void self_neg() &noexcept
BB_INLINE constexpr bool operator==(const field &other) const noexcept
BB_INLINE constexpr bool is_msb_set() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field sqr() const noexcept
BB_INLINE constexpr bool operator>(const field &other) const noexcept
Greater-than operator.
BB_INLINE constexpr field to_montgomery_form_reduced() const noexcept
BB_INLINE constexpr field & operator-=(const field &other) &noexcept
void msgpack_pack(auto &packer) const
constexpr std::pair< bool, field > sqrt() const noexcept
Compute square root of the field element.
BB_INLINE constexpr void self_from_montgomery_form() &noexcept
BB_INLINE constexpr field & operator*=(const field &other) &noexcept
BB_INLINE constexpr bool is_zero() const noexcept
static void batch_invert(C &coeffs) noexcept
Batch invert a collection of field elements using Montgomery's trick.
BB_INLINE constexpr void self_to_montgomery_form() &noexcept
BB_INLINE constexpr field from_montgomery_form() const noexcept
BB_INLINE constexpr field operator-() const noexcept
BB_INLINE constexpr bool operator<(const field &other) const noexcept
Less-than operator.
BB_INLINE constexpr void self_set_msb() &noexcept
void msgpack_unpack(auto o)
constexpr field & operator/=(const field &other) &noexcept
static constexpr size_t primitive_root_log_size() noexcept
BB_INLINE constexpr field reduce_once() const noexcept
static constexpr field zero()
constexpr field invert_const_time() const noexcept
BB_INLINE constexpr uint64_t is_msb_set_word() const noexcept
void throw_or_abort(std::string const &err)