37 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
38 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
40 return montgomery_mul(other);
43 return montgomery_mul(other);
45 return asm_mul_with_coarse_reduction(*
this, other);
51 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
52 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
59 asm_self_mul_with_coarse_reduction(*
this, other);
72 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
73 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
74 return montgomery_square();
77 return montgomery_square();
79 return asm_sqr_with_coarse_reduction(*
this);
85 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
86 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
87 *
this = montgomery_square();
90 *
this = montgomery_square();
92 asm_self_sqr_with_coarse_reduction(*
this);
104 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
105 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
111 return asm_add_with_coarse_reduction(*
this, other);
117 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
118 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
124 asm_self_add_with_coarse_reduction(*
this, other);
138 field<T> value_before_incrementing = *
this;
140 return value_before_incrementing;
150 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
151 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
152 return subtract_coarse(other);
155 return subtract_coarse(other);
157 return asm_sub_with_coarse_reduction(*
this, other);
163 if constexpr ((T::modulus_3 >= 0x4000000000000000ULL) ||
164 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
165 constexpr field p{ modulus.
data[0], modulus.data[1], modulus.data[2], modulus.data[3] };
185 constexpr field p{ twice_modulus.
data[0], twice_modulus.data[1], twice_modulus.data[2], twice_modulus.data[3] };
186 return (p - *
this).reduce_once();
191 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
192 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
193 *
this = subtract_coarse(other);
196 *
this = subtract_coarse(other);
198 asm_self_sub_with_coarse_reduction(*
this, other);
206 if constexpr ((T::modulus_3 >= 0x4000000000000000ULL) ||
207 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
208 constexpr field p{ modulus.
data[0], modulus.data[1], modulus.data[2], modulus.data[3] };
211 constexpr field p{ twice_modulus.
data[0], twice_modulus.data[1], twice_modulus.data[2], twice_modulus.data[3] };
212 *
this = (p - *
this).reduce_once();
218 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
219 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
220 *
this = predicate ? -(*this) : *
this;
223 *
this = predicate ? -(*this) : *
this;
225 asm_conditional_negate(*
this, predicate);
243 const field left = reduce_once();
245 const bool t0 = left.
data[3] > right.
data[3];
246 const bool t1 = (left.
data[3] == right.
data[3]) && (left.
data[2] > right.
data[2]);
249 const bool t3 = (left.
data[3] == right.
data[3]) && (left.
data[2] == right.
data[2]) &&
251 return (t0 || t1 || t2 || t3);
267 return (other > *
this);
272 const field left = reduce_once();
280 return (!
operator==(other));
285 constexpr field r_squared =
286 field{ r_squared_uint.
data[0], r_squared_uint.data[1], r_squared_uint.data[2], r_squared_uint.data[3] };
288 field result = *
this;
298 return (result * r_squared).reduce_once();
303 constexpr field one_raw{ 1, 0, 0, 0 };
310 field{ r_squared_uint.
data[0], r_squared_uint.data[1], r_squared_uint.data[2], r_squared_uint.data[3] };
321 constexpr field one_raw{ 1, 0, 0, 0 };
328 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
329 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
335 return asm_reduce_once(*
this);
341 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
342 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
348 asm_self_reduce_once(*
this);
357 const uint64_t maximum_set_bit = exponent.get_msb();
359 for (
int i =
static_cast<int>(maximum_set_bit) - 1; i >= 0; --i) {
361 if (exponent.get_bit(
static_cast<uint64_t
>(i))) {
362 accumulator *= to_mul;
367 }
else if (*
this == zero()) {
368 accumulator = zero();
375 return pow({ exponent, 0, 0, 0 });
380 if (*
this == zero()) {
383 return pow(modulus_minus_two);
388 batch_invert(std::span{ coeffs, n });
394 const size_t n = coeffs.size();
398 auto temporaries = temporaries_ptr.get();
399 auto* skipped = skipped_ptr.get();
401 field accumulator = one();
402 for (
size_t i = 0; i < n; ++i) {
403 temporaries[i] = accumulator;
404 if (coeffs[i].is_zero()) {
408 accumulator *= coeffs[i];
428 accumulator = accumulator.
invert();
431 for (
size_t i = n - 1; i < n; --i) {
433 T0 = accumulator * temporaries[i];
434 accumulator *= coeffs[i];
463 constexpr uint256_t Q = (modulus - 1) >>
static_cast<uint64_t
>(primitive_root_log_size());
464 constexpr uint256_t Q_minus_one_over_two = (Q - 1) >> 1;
465 field v = pow(Q_minus_one_over_two);
473 for (
size_t i = 0; i < primitive_root_log_size() - 1; ++i) {
480 constexpr field g = coset_generator<0>().pow(Q);
481 constexpr field g_inv = coset_generator<0>().
pow(modulus - 1 - Q);
482 constexpr size_t root_bits = primitive_root_log_size();
483 constexpr size_t table_bits = 6;
484 constexpr size_t num_tables = root_bits / table_bits + (root_bits % table_bits != 0 ? 1 : 0);
485 constexpr size_t num_offset_tables = num_tables - 1;
486 constexpr size_t table_size =
static_cast<size_t>(1UL) << table_bits;
489 constexpr auto get_g_table = [&](
const field& h) {
492 for (
size_t i = 1; i < table_size; ++i) {
493 result[i] = result[i - 1] * h;
498 field working_base = g_inv;
500 for (
size_t i = 0; i < num_tables; ++i) {
501 result[i] = get_g_table(working_base);
502 for (
size_t j = 0; j < table_bits; ++j) {
509 field working_base = g_inv;
510 for (
size_t i = 0; i < root_bits % table_bits; ++i) {
514 for (
size_t i = 0; i < num_offset_tables; ++i) {
515 result[i] = get_g_table(working_base);
516 for (
size_t j = 0; j < table_bits; ++j) {
523 constexpr GTable root_table_a = get_g_table(g.pow(1UL << ((num_tables - 1) * table_bits)));
524 constexpr GTable root_table_b = get_g_table(g.pow(1UL << (root_bits - table_bits)));
528 for (
size_t i = 0; i < num_tables - 1; ++i) {
529 uvv_powers[i] = base;
530 for (
size_t j = 0; j < table_bits; ++j) {
534 uvv_powers[num_tables - 1] = base;
536 for (
size_t i = 0; i < num_tables; ++i) {
537 size_t table_index = num_tables - 1 - i;
538 field target = uvv_powers[table_index];
539 for (
size_t j = 0; j < i; ++j) {
540 size_t e_idx = num_tables - 1 - (i - 1) + j;
541 size_t g_idx = num_tables - 2 - j;
545 g_lookup = offset_g_tables[g_idx - 1][e_slices[e_idx]];
547 g_lookup = g_tables[g_idx][e_slices[e_idx]];
554 for (
auto& x : root_table_a) {
561 for (
auto& x : root_table_b) {
570 e_slices[table_index] = count;
574 for (
size_t i = 0; i < num_tables; ++i) {
575 auto& e_slice = e_slices[num_tables - 1 - i];
579 if ((e_slice & 1UL) == 1UL) {
580 size_t borrow_value = (i == 1) ? 1UL << ((root_bits % table_bits) - 1) : (1UL << (table_bits - 1));
581 e_slices[num_tables - i] += borrow_value;
586 field g_pow_minus_e_over_2 = 1;
587 for (
size_t i = 0; i < num_tables; ++i) {
589 g_pow_minus_e_over_2 *= g_tables[i][e_slices[num_tables - 1 - i]];
591 g_pow_minus_e_over_2 *= offset_g_tables[i - 1][e_slices[num_tables - 1 - i]];
594 return uv * g_pow_minus_e_over_2;
599 requires((T::modulus_0 & 0x3UL) == 0x3UL)
602 field root = pow(sqrt_exponent);
603 if ((root * root) == (*
this)) {
611 requires((T::modulus_0 & 0x3UL) != 0x3UL)
613 field root = tonelli_shanks_sqrt();
614 if ((root * root) == (*
this)) {
627 *
this = operator/(other);
633 data[3] = 0ULL | (1ULL << 63ULL);
638 return (
data[3] >> 63ULL) == 1ULL;
643 return (
data[3] >> 63ULL);
649 (
data[0] == T::modulus_0 &&
data[1] == T::modulus_1 &&
data[2] == T::modulus_2 &&
data[3] == T::modulus_3);
654#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
655 field r{ T::primitive_root_0, T::primitive_root_1, T::primitive_root_2, T::primitive_root_3 };
657 field r{ T::primitive_root_wasm_0, T::primitive_root_wasm_1, T::primitive_root_wasm_2, T::primitive_root_wasm_3 };
659 for (
size_t i = primitive_root_log_size(); i > subgroup_size; --i) {
675 return lo + (pow_2_256 * hi);
682 while (!target.
get_bit(result)) {
691 constexpr size_t n = COSET_GENERATOR_SIZE;
692 constexpr uint64_t subgroup_size = 1 << 30;
694 std::array<field, COSET_GENERATOR_SIZE> result{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
696 result[0] = (multiplicative_generator());
698 field work_variable = multiplicative_generator() +
field(1);
706 for (
size_t j = 0; j < count; ++j) {
707 field subgroup_check = (work_inverse * result[j]).pow(subgroup_size);
708 if (subgroup_check ==
field(1)) {
714 result[count] = (work_variable);
717 work_variable +=
field(1);
725 uint256_t p_minus_one_over_two = (modulus - 1) >> 1;
729 found = (target.
pow(p_minus_one_over_two) == -
field(1));
740 auto adjusted = from_montgomery_form();
745 uint64_t bin_data[4] = {
746 htonll(adjusted.data[3]), htonll(adjusted.data[2]), htonll(adjusted.data[1]), htonll(adjusted.data[0])
750 packer.pack_bin(
sizeof(bin_data));
751 packer.pack_bin_body((
const char*)bin_data,
sizeof(bin_data));
760 std::array<uint8_t,
sizeof(
data)> raw_data = o;
764 uint64_t* cast_data = (uint64_t*)&raw_data[0];
765 uint64_t reversed[] = { ntohll(cast_data[3]), ntohll(cast_data[2]), ntohll(cast_data[1]), ntohll(cast_data[0]) };
768 for (
int i = 0; i < 4; i++) {
769 data[i] = reversed[i];
773 *
this = to_montgomery_form();
#define ASSERT_IN_CONSTEXPR(expression,...)
virtual uint256_t get_random_uint256()=0
constexpr bool get_bit(uint64_t bit_index) const
const std::vector< FF > data
Entry point for Barretenberg command-line interface.
Univariate< Fr, domain_end, domain_start, skip_count > operator+(const Fr &ff, const Univariate< Fr, domain_end, domain_start, skip_count > &uv)
Univariate< Fr, domain_end, domain_start, skip_count > operator*(const Fr &ff, const Univariate< Fr, domain_end, domain_start, skip_count > &uv)
std::shared_ptr< void > get_mem_slab(size_t size)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
General class for prime fields see Prime field documentation["field documentation"] for general imple...
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_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 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
static constexpr std::array< field, COSET_GENERATOR_SIZE > compute_coset_generators() 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 & 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
static constexpr field multiplicative_generator() noexcept
BB_INLINE constexpr field & operator*=(const field &other) &noexcept
BB_INLINE constexpr bool is_zero() const noexcept
static void batch_invert(std::span< field > coeffs) noexcept
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()
BB_INLINE constexpr uint64_t is_msb_set_word() const noexcept
void throw_or_abort(std::string const &err)