36 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
37 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
39 return montgomery_mul(other);
42 return montgomery_mul(other);
44 return asm_mul_with_coarse_reduction(*
this, other);
50 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
51 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
58 asm_self_mul_with_coarse_reduction(*
this, other);
71 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
72 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
73 return montgomery_square();
76 return montgomery_square();
78 return asm_sqr_with_coarse_reduction(*
this);
84 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
85 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
86 *
this = montgomery_square();
89 *
this = montgomery_square();
91 asm_self_sqr_with_coarse_reduction(*
this);
103 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
104 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
110 return asm_add_with_coarse_reduction(*
this, other);
116 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
117 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
123 asm_self_add_with_coarse_reduction(*
this, other);
137 field<T> value_before_incrementing = *
this;
139 return value_before_incrementing;
149 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
150 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
151 return subtract_coarse(other);
154 return subtract_coarse(other);
156 return asm_sub_with_coarse_reduction(*
this, other);
162 if constexpr ((T::modulus_3 >= 0x4000000000000000ULL) ||
163 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
164 constexpr field p{ modulus.
data[0], modulus.data[1], modulus.data[2], modulus.data[3] };
184 constexpr field p{ twice_modulus.
data[0], twice_modulus.data[1], twice_modulus.data[2], twice_modulus.data[3] };
185 return (p - *
this).reduce_once();
190 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
191 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
192 *
this = subtract_coarse(other);
195 *
this = subtract_coarse(other);
197 asm_self_sub_with_coarse_reduction(*
this, other);
205 if constexpr ((T::modulus_3 >= 0x4000000000000000ULL) ||
206 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
207 constexpr field p{ modulus.
data[0], modulus.data[1], modulus.data[2], modulus.data[3] };
210 constexpr field p{ twice_modulus.
data[0], twice_modulus.data[1], twice_modulus.data[2], twice_modulus.data[3] };
211 *
this = (p - *
this).reduce_once();
217 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
218 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
219 *
this = predicate ? -(*this) : *
this;
222 *
this = predicate ? -(*this) : *
this;
224 asm_conditional_negate(*
this, predicate);
242 const field left = reduce_once();
244 const bool t0 = left.
data[3] > right.
data[3];
245 const bool t1 = (left.
data[3] == right.
data[3]) && (left.
data[2] > right.
data[2]);
248 const bool t3 = (left.
data[3] == right.
data[3]) && (left.
data[2] == right.
data[2]) &&
250 return (t0 || t1 || t2 || t3);
266 return (other > *
this);
271 const field left = reduce_once();
279 return (!
operator==(other));
284 constexpr field r_squared =
285 field{ r_squared_uint.
data[0], r_squared_uint.data[1], r_squared_uint.data[2], r_squared_uint.data[3] };
287 field result = *
this;
297 return (result * r_squared).reduce_once();
302 constexpr field one_raw{ 1, 0, 0, 0 };
309 field{ r_squared_uint.
data[0], r_squared_uint.data[1], r_squared_uint.data[2], r_squared_uint.data[3] };
320 constexpr field one_raw{ 1, 0, 0, 0 };
327 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
328 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
334 return asm_reduce_once(*
this);
340 if constexpr (
BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
341 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
347 asm_self_reduce_once(*
this);
356 const uint64_t maximum_set_bit = exponent.get_msb();
358 for (
int i =
static_cast<int>(maximum_set_bit) - 1; i >= 0; --i) {
360 if (exponent.get_bit(
static_cast<uint64_t
>(i))) {
361 accumulator *= to_mul;
366 }
else if (*
this == zero()) {
367 accumulator = zero();
374 return pow({ exponent, 0, 0, 0 });
379 if (*
this == zero()) {
382 return pow(modulus_minus_two);
388 batch_invert(std::span{ coeffs, n });
393 batch_invert<decltype(coeffs)>(coeffs);
398 requires requires(
C& c) {
404 const size_t n = coeffs.size();
407 std::vector<bool> skipped;
408 temporaries.reserve(n);
411 field accumulator = one();
412 for (
size_t i = 0; i < n; ++i) {
413 temporaries[i] = accumulator;
414 if (coeffs[i].is_zero()) {
418 accumulator *= coeffs[i];
438 accumulator = accumulator.
invert();
441 for (
size_t i = n - 1; i < n; --i) {
443 T0 = accumulator * temporaries[i];
444 accumulator *= coeffs[i];
473 constexpr uint256_t Q = (modulus - 1) >>
static_cast<uint64_t
>(primitive_root_log_size());
474 constexpr uint256_t Q_minus_one_over_two = (Q - 1) >> 1;
475 field v = pow(Q_minus_one_over_two);
483 for (
size_t i = 0; i < primitive_root_log_size() - 1; ++i) {
490 constexpr field g = coset_generator<0>().pow(Q);
491 constexpr field g_inv = coset_generator<0>().
pow(modulus - 1 - Q);
492 constexpr size_t root_bits = primitive_root_log_size();
493 constexpr size_t table_bits = 6;
494 constexpr size_t num_tables = root_bits / table_bits + (root_bits % table_bits != 0 ? 1 : 0);
495 constexpr size_t num_offset_tables = num_tables - 1;
496 constexpr size_t table_size =
static_cast<size_t>(1UL) << table_bits;
499 constexpr auto get_g_table = [&](
const field& h) {
502 for (
size_t i = 1; i < table_size; ++i) {
503 result[i] = result[i - 1] * h;
508 field working_base = g_inv;
510 for (
size_t i = 0; i < num_tables; ++i) {
511 result[i] = get_g_table(working_base);
512 for (
size_t j = 0; j < table_bits; ++j) {
519 field working_base = g_inv;
520 for (
size_t i = 0; i < root_bits % table_bits; ++i) {
524 for (
size_t i = 0; i < num_offset_tables; ++i) {
525 result[i] = get_g_table(working_base);
526 for (
size_t j = 0; j < table_bits; ++j) {
533 constexpr GTable root_table_a = get_g_table(g.pow(1UL << ((num_tables - 1) * table_bits)));
534 constexpr GTable root_table_b = get_g_table(g.pow(1UL << (root_bits - table_bits)));
538 for (
size_t i = 0; i < num_tables - 1; ++i) {
539 uvv_powers[i] = base;
540 for (
size_t j = 0; j < table_bits; ++j) {
544 uvv_powers[num_tables - 1] = base;
546 for (
size_t i = 0; i < num_tables; ++i) {
547 size_t table_index = num_tables - 1 - i;
548 field target = uvv_powers[table_index];
549 for (
size_t j = 0; j < i; ++j) {
550 size_t e_idx = num_tables - 1 - (i - 1) + j;
551 size_t g_idx = num_tables - 2 - j;
555 g_lookup = offset_g_tables[g_idx - 1][e_slices[e_idx]];
557 g_lookup = g_tables[g_idx][e_slices[e_idx]];
564 for (
auto& x : root_table_a) {
571 for (
auto& x : root_table_b) {
580 e_slices[table_index] = count;
584 for (
size_t i = 0; i < num_tables; ++i) {
585 auto& e_slice = e_slices[num_tables - 1 - i];
589 if ((e_slice & 1UL) == 1UL) {
590 size_t borrow_value = (i == 1) ? 1UL << ((root_bits % table_bits) - 1) : (1UL << (table_bits - 1));
591 e_slices[num_tables - i] += borrow_value;
596 field g_pow_minus_e_over_2 = 1;
597 for (
size_t i = 0; i < num_tables; ++i) {
599 g_pow_minus_e_over_2 *= g_tables[i][e_slices[num_tables - 1 - i]];
601 g_pow_minus_e_over_2 *= offset_g_tables[i - 1][e_slices[num_tables - 1 - i]];
604 return uv * g_pow_minus_e_over_2;
609 requires((T::modulus_0 & 0x3UL) == 0x3UL)
612 field root = pow(sqrt_exponent);
613 if ((root * root) == (*
this)) {
621 requires((T::modulus_0 & 0x3UL) != 0x3UL)
623 field root = tonelli_shanks_sqrt();
624 if ((root * root) == (*
this)) {
637 *
this = operator/(other);
643 data[3] = 0ULL | (1ULL << 63ULL);
648 return (
data[3] >> 63ULL) == 1ULL;
653 return (
data[3] >> 63ULL);
659 (
data[0] == T::modulus_0 &&
data[1] == T::modulus_1 &&
data[2] == T::modulus_2 &&
data[3] == T::modulus_3);
664#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
665 field r{ T::primitive_root_0, T::primitive_root_1, T::primitive_root_2, T::primitive_root_3 };
667 field r{ T::primitive_root_wasm_0, T::primitive_root_wasm_1, T::primitive_root_wasm_2, T::primitive_root_wasm_3 };
669 for (
size_t i = primitive_root_log_size(); i > subgroup_size; --i) {
685 return lo + (pow_2_256 * hi);
692 while (!target.
get_bit(result)) {
701 constexpr size_t n = COSET_GENERATOR_SIZE;
702 constexpr uint64_t subgroup_size = 1 << 30;
704 std::array<field, COSET_GENERATOR_SIZE> result{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
706 result[0] = (multiplicative_generator());
708 field work_variable = multiplicative_generator() +
field(1);
716 for (
size_t j = 0; j < count; ++j) {
717 field subgroup_check = (work_inverse * result[j]).pow(subgroup_size);
718 if (subgroup_check ==
field(1)) {
724 result[count] = (work_variable);
727 work_variable += field(1);
735 uint256_t p_minus_one_over_two = (modulus - 1) >> 1;
739 found = (target.
pow(p_minus_one_over_two) == -
field(1));
750 auto adjusted = from_montgomery_form();
755 uint64_t bin_data[4] = {
756 htonll(adjusted.data[3]), htonll(adjusted.data[2]), htonll(adjusted.data[1]), htonll(adjusted.data[0])
760 packer.pack_bin(
sizeof(bin_data));
761 packer.pack_bin_body((
const char*)bin_data,
sizeof(bin_data));
770 std::array<uint8_t,
sizeof(
data)> raw_data = o;
774 uint64_t* cast_data = (uint64_t*)&raw_data[0];
775 uint64_t reversed[] = { ntohll(cast_data[3]), ntohll(cast_data[2]), ntohll(cast_data[1]), ntohll(cast_data[0]) };
778 for (
int i = 0; i < 4; i++) {
779 data[i] = reversed[i];
783 *
this = to_montgomery_form();
#define BB_ASSERT(expression,...)
virtual uint256_t get_random_uint256()=0
constexpr bool get_bit(uint64_t bit_index) const
const std::vector< MemoryValue > data
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 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(C &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