2#include "barretenberg/common/slab_allocator.hpp"
3#include "barretenberg/common/throw_or_abort.hpp"
4#include "barretenberg/numeric/bitop/get_msb.hpp"
5#include "barretenberg/numeric/random/engine.hpp"
11#include "./field_declarations.hpp"
28 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
29 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
31 return montgomery_mul(other);
33 if (std::is_constant_evaluated()) {
34 return montgomery_mul(other);
36 return asm_mul_with_coarse_reduction(*
this, other);
42 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
43 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
45 *
this = operator*(other);
47 if (std::is_constant_evaluated()) {
48 *
this = operator*(other);
50 asm_self_mul_with_coarse_reduction(*
this, other);
63 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
64 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
65 return montgomery_square();
67 if (std::is_constant_evaluated()) {
68 return montgomery_square();
70 return asm_sqr_with_coarse_reduction(*
this);
76 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
77 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
78 *
this = montgomery_square();
80 if (std::is_constant_evaluated()) {
81 *
this = montgomery_square();
83 asm_self_sqr_with_coarse_reduction(*
this);
95 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
96 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
99 if (std::is_constant_evaluated()) {
102 return asm_add_with_coarse_reduction(*
this, other);
108 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
109 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
110 (*this) = operator+(other);
112 if (std::is_constant_evaluated()) {
113 (*this) = operator+(other);
115 asm_self_add_with_coarse_reduction(*
this, other);
121template <
class T>
constexpr field<T> field<T>::operator++() noexcept
127template <
class T>
constexpr field<T> field<T>::operator++(
int)
noexcept
129 field<T> value_before_incrementing = *
this;
131 return value_before_incrementing;
141 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
142 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
143 return subtract_coarse(other);
145 if (std::is_constant_evaluated()) {
146 return subtract_coarse(other);
148 return asm_sub_with_coarse_reduction(*
this, other);
154 if constexpr ((T::modulus_3 >= 0x4000000000000000ULL) ||
155 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
156 constexpr field p{ modulus.data[0], modulus.data[1], modulus.data[2], modulus.data[3] };
176 constexpr field p{ twice_modulus.data[0], twice_modulus.data[1], twice_modulus.data[2], twice_modulus.data[3] };
177 return (p - *
this).reduce_once();
180template <
class T>
constexpr field<T>& field<T>::operator-=(
const field& other)
noexcept
182 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
183 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
184 *
this = subtract_coarse(other);
186 if (std::is_constant_evaluated()) {
187 *
this = subtract_coarse(other);
189 asm_self_sub_with_coarse_reduction(*
this, other);
195template <
class T>
constexpr void field<T>::self_neg() noexcept
197 if constexpr ((T::modulus_3 >= 0x4000000000000000ULL) ||
198 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
199 constexpr field p{ modulus.data[0], modulus.data[1], modulus.data[2], modulus.data[3] };
202 constexpr field p{ twice_modulus.data[0], twice_modulus.data[1], twice_modulus.data[2], twice_modulus.data[3] };
203 *
this = (p - *
this).reduce_once();
207template <
class T>
constexpr void field<T>::self_conditional_negate(
const uint64_t predicate)
noexcept
209 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
210 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
211 *
this = predicate ? -(*this) : *
this;
213 if (std::is_constant_evaluated()) {
214 *
this = predicate ? -(*this) : *
this;
216 asm_conditional_negate(*
this, predicate);
234 const field left = reduce_once();
235 const field right = other.reduce_once();
236 const bool t0 = left.data[3] > right.data[3];
237 const bool t1 = (left.data[3] == right.data[3]) && (left.data[2] > right.data[2]);
239 (left.data[3] == right.data[3]) && (left.data[2] == right.data[2]) && (left.data[1] > right.data[1]);
240 const bool t3 = (left.data[3] == right.data[3]) && (left.data[2] == right.data[2]) &&
241 (left.data[1] == right.data[1]) && (left.data[0] > right.data[0]);
242 return (t0 || t1 || t2 || t3);
258 return (other > *
this);
263 const field left = reduce_once();
264 const field right = other.reduce_once();
265 return (left.data[0] == right.data[0]) && (left.data[1] == right.data[1]) && (left.data[2] == right.data[2]) &&
266 (left.data[3] == right.data[3]);
269template <
class T>
constexpr bool field<T>::operator!=(
const field& other)
const noexcept
271 return (!
operator==(other));
274template <
class T>
constexpr field<T> field<T>::to_montgomery_form() const noexcept
276 constexpr field r_squared{ T::r_squared_0, T::r_squared_1, T::r_squared_2, T::r_squared_3 };
278 field result = *
this;
285 result.self_reduce_once();
286 result.self_reduce_once();
287 result.self_reduce_once();
288 return (result * r_squared).reduce_once();
291template <
class T>
constexpr field<T> field<T>::from_montgomery_form() const noexcept
293 constexpr field one_raw{ 1, 0, 0, 0 };
294 return operator*(one_raw).reduce_once();
297template <
class T>
constexpr void field<T>::self_to_montgomery_form() noexcept
299 constexpr field r_squared{ T::r_squared_0, T::r_squared_1, T::r_squared_2, T::r_squared_3 };
307template <
class T>
constexpr void field<T>::self_from_montgomery_form() noexcept
309 constexpr field one_raw{ 1, 0, 0, 0 };
314template <
class T>
constexpr field<T> field<T>::reduce_once() const noexcept
316 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
317 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
320 if (std::is_constant_evaluated()) {
323 return asm_reduce_once(*
this);
327template <
class T>
constexpr void field<T>::self_reduce_once() noexcept
329 if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) ||
330 (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) {
333 if (std::is_constant_evaluated()) {
336 asm_self_reduce_once(*
this);
341template <
class T>
constexpr field<T> field<T>::pow(
const uint256_t& exponent)
const noexcept
344 field accumulator{ data[0], data[1], data[2], data[3] };
345 field to_mul{ data[0], data[1], data[2], data[3] };
346 const uint64_t maximum_set_bit = exponent.get_msb();
348 for (
int i =
static_cast<int>(maximum_set_bit) - 1; i >= 0; --i) {
349 accumulator.self_sqr();
350 if (exponent.get_bit(
static_cast<uint64_t
>(i))) {
351 accumulator *= to_mul;
356 }
else if (*
this == zero()) {
357 accumulator = zero();
362template <
class T>
constexpr field<T> field<T>::pow(
const uint64_t exponent)
const noexcept
364 return pow({ exponent, 0, 0, 0 });
367template <
class T>
constexpr field<T> field<T>::invert() const noexcept
369 if (*
this == zero()) {
370 throw_or_abort(
"Trying to invert zero in the field");
372 return pow(modulus_minus_two);
375template <
class T>
void field<T>::batch_invert(field* coeffs,
const size_t n)
noexcept
377 batch_invert(std::span{ coeffs, n });
380template <
class T>
void field<T>::batch_invert(std::span<field> coeffs)
noexcept
382 const size_t n = coeffs.size();
384 auto temporaries_ptr = std::static_pointer_cast<field[]>(
get_mem_slab(n *
sizeof(field)));
385 auto skipped_ptr = std::static_pointer_cast<bool[]>(
get_mem_slab(n));
386 auto temporaries = temporaries_ptr.get();
387 auto* skipped = skipped_ptr.get();
389 field accumulator = one();
390 for (
size_t i = 0; i < n; ++i) {
391 temporaries[i] = accumulator;
392 if (coeffs[i].is_zero()) {
396 accumulator *= coeffs[i];
416 accumulator = accumulator.invert();
419 for (
size_t i = n - 1; i < n; --i) {
421 T0 = accumulator * temporaries[i];
422 accumulator *= coeffs[i];
428template <
class T>
constexpr field<T> field<T>::tonelli_shanks_sqrt() const noexcept
458 constexpr uint256_t Q = (modulus - 1) >>
static_cast<uint64_t
>(primitive_root_log_size() - 1);
459 constexpr uint256_t Q_minus_one_over_two = (Q - 1) >> 2;
462 field z = coset_generator(0);
463 field b = pow(Q_minus_one_over_two);
464 field r = operator*(b);
470 for (
size_t i = 0; i < primitive_root_log_size() - 1; ++i) {
473 if (check != one()) {
476 field t1 = z.
pow(Q_minus_one_over_two);
480 size_t m = primitive_root_log_size();
487 while (t2m != one()) {
492 size_t j = m - i - 1;
507template <
class T>
constexpr std::pair<bool, field<T>>
field<T>::sqrt() const noexcept
510 if constexpr ((T::modulus_0 & 0x3UL) == 0x3UL) {
512 root = pow(sqrt_exponent);
514 root = tonelli_shanks_sqrt();
516 if ((root * root) == (*
this)) {
517 return std::pair<bool, field>(
true, root);
519 return std::pair<bool, field>(
false, field::zero());
525 return operator*(other.invert());
528template <
class T>
constexpr field<T>& field<T>::operator/=(
const field& other)
noexcept
530 *
this = operator/(other);
534template <
class T>
constexpr void field<T>::self_set_msb() noexcept
536 data[3] = 0ULL | (1ULL << 63ULL);
539template <
class T>
constexpr bool field<T>::is_msb_set() const noexcept
541 return (data[3] >> 63ULL) == 1ULL;
544template <
class T>
constexpr uint64_t field<T>::is_msb_set_word() const noexcept
546 return (data[3] >> 63ULL);
549template <
class T>
constexpr bool field<T>::is_zero() const noexcept
551 return ((data[0] | data[1] | data[2] | data[3]) == 0) ||
552 (data[0] == T::modulus_0 && data[1] == T::modulus_1 && data[2] == T::modulus_2 && data[3] == T::modulus_3);
555template <
class T>
constexpr field<T> field<T>::get_root_of_unity(
size_t subgroup_size)
noexcept
557 field r{ T::primitive_root_0, T::primitive_root_1, T::primitive_root_2, T::primitive_root_3 };
558 for (
size_t i = primitive_root_log_size(); i > subgroup_size; --i) {
566 if (engine ==
nullptr) {
567 engine = &numeric::random::get_engine();
570 uint512_t source = engine->get_random_uint512();
571 uint512_t q(modulus);
572 uint512_t reduced = source % q;
573 return field(reduced.lo);
576template <
class T>
constexpr size_t field<T>::primitive_root_log_size() noexcept
580 while (!target.get_bit(result)) {
587constexpr std::array<field<T>, field<T>::COSET_GENERATOR_SIZE> field<T>::compute_coset_generators() noexcept
589 constexpr size_t n = COSET_GENERATOR_SIZE;
590 constexpr uint64_t subgroup_size = 1 << 30;
592 std::array<field, COSET_GENERATOR_SIZE> result{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
594 result[0] = (multiplicative_generator());
596 field work_variable = multiplicative_generator() + field(1);
602 field work_inverse = work_variable.invert();
604 for (
size_t j = 0; j < count; ++j) {
605 field subgroup_check = (work_inverse * result[j]).pow(subgroup_size);
606 if (subgroup_check == field(1)) {
612 result[count] = (work_variable);
615 work_variable += field(1);
620template <
class T>
constexpr field<T> field<T>::multiplicative_generator() noexcept
623 uint256_t p_minus_one_over_two = (modulus - 1) >> 1;
627 found = (target.pow(p_minus_one_over_two) == -field(1));
635template <
class Params>
void field<Params>::msgpack_pack(
auto& packer)
const
638 auto adjusted = from_montgomery_form();
642 uint64_t bin_data[4] = {
643 htonll(adjusted.data[3]), htonll(adjusted.data[2]), htonll(adjusted.data[1]), htonll(adjusted.data[0])
647 packer.pack_bin(
sizeof(bin_data));
648 packer.pack_bin_body((
const char*)bin_data,
sizeof(bin_data));
654template <
class Params>
void field<Params>::msgpack_unpack(
auto o)
657 std::array<uint8_t,
sizeof(data)> raw_data = o;
661 uint64_t* cast_data = (uint64_t*)&raw_data[0];
662 uint64_t reversed[] = { ntohll(cast_data[3]), ntohll(cast_data[2]), ntohll(cast_data[1]), ntohll(cast_data[0]) };
665 for (
int i = 0; i < 4; i++) {
666 data[i] = reversed[i];
670 *
this = to_montgomery_form();
Definition: engine.hpp:10
Definition: uint256.hpp:25
field_t pow(const field_t &exponent) const
raise a field_t to a power of an exponent (field_t). Note that the exponent must not exceed 32 bits a...
Definition: field.cpp:346
constexpr_utils defines some helper methods that perform some stl-equivalent operations but in a cons...
Definition: constexpr_utils.hpp:16
std::shared_ptr< void > get_mem_slab(size_t size)
Definition: slab_allocator.cpp:214
Definition: field_declarations.hpp:24
BBERG_INLINE constexpr bool operator<(const field &other) const noexcept
Less-than operator.
Definition: field_impl.hpp:256
BBERG_INLINE constexpr field sqr() const noexcept
Definition: field_impl.hpp:61
constexpr std::pair< bool, field > sqrt() const noexcept
Compute square root of the field element.
Definition: field_impl.hpp:507
BBERG_INLINE constexpr bool operator>(const field &other) const noexcept
Greater-than operator.
Definition: field_impl.hpp:232
BBERG_INLINE constexpr field operator+(const field &other) const noexcept
Definition: field_impl.hpp:93
BBERG_INLINE constexpr field operator*(const field &other) const noexcept
Definition: field_impl.hpp:26