2#include "barretenberg/common/assert.hpp"
3#include "barretenberg/common/compiler_hints.hpp"
4#include "barretenberg/numeric/random/engine.hpp"
5#include "barretenberg/numeric/uint128/uint128.hpp"
6#include "barretenberg/numeric/uint256/uint256.hpp"
13#ifndef DISABLE_SHENANIGANS
24template <
class Params_>
struct alignas(32)
field {
27 using Params = Params_;
28 using in_buf =
const uint8_t*;
29 using vec_in_buf =
const uint8_t*;
30 using out_buf = uint8_t*;
31 using vec_out_buf = uint8_t**;
45 : data{ input.data[0], input.data[1], input.data[2], input.data[3] }
47 self_to_montgomery_form();
51 constexpr field(
const unsigned long input) noexcept
52 : data{ input, 0, 0, 0 }
54 self_to_montgomery_form();
57 constexpr field(
const unsigned int input) noexcept
58 : data{ input, 0, 0, 0 }
60 self_to_montgomery_form();
64 constexpr field(
const unsigned long long input) noexcept
65 : data{ input, 0, 0, 0 }
67 self_to_montgomery_form();
70 constexpr field(
const int input) noexcept
74 data[0] =
static_cast<uint64_t
>(-input);
78 self_to_montgomery_form();
82 data[0] =
static_cast<uint64_t
>(input);
86 self_to_montgomery_form();
90 constexpr field(
const uint64_t a,
const uint64_t b,
const uint64_t c,
const uint64_t d) noexcept
91 : data{ a, b, c, d } {};
99 constexpr explicit field(
const uint512_t& input)
noexcept
102 data[0] = value.data[0];
103 data[1] = value.data[1];
104 data[2] = value.data[2];
105 data[3] = value.data[3];
106 self_to_montgomery_form();
109 constexpr explicit field(std::string input)
noexcept
112 *
this =
field(value);
115 constexpr explicit operator uint32_t()
const
117 field out = from_montgomery_form();
118 return static_cast<uint32_t
>(out.data[0]);
121 constexpr explicit operator uint64_t()
const
123 field out = from_montgomery_form();
127 constexpr explicit operator uint128_t()
const
129 field out = from_montgomery_form();
130 uint128_t lo = out.data[0];
131 uint128_t hi = out.data[1];
132 return (hi << 64) | lo;
135 constexpr operator uint256_t() const noexcept
137 field out = from_montgomery_form();
138 return uint256_t(out.data[0], out.data[1], out.data[2], out.data[3]);
141 [[nodiscard]]
constexpr uint256_t uint256_t_no_montgomery_conversion() const noexcept
143 return { data[0], data[1], data[2], data[3] };
146 constexpr field(
const field& other)
noexcept =
default;
147 constexpr field(field&& other)
noexcept =
default;
148 constexpr field& operator=(
const field& other)
noexcept =
default;
149 constexpr field& operator=(field&& other)
noexcept =
default;
150 constexpr ~field() noexcept = default;
151 alignas(32) uint64_t data[4];
154 uint256_t{ Params::modulus_0, Params::modulus_1, Params::modulus_2, Params::modulus_3 };
156 static constexpr field cube_root_of_unity()
159 if constexpr (Params::cube_root_0 != 0) {
160 constexpr field result{
161 Params::cube_root_0, Params::cube_root_1, Params::cube_root_2, Params::cube_root_3
165 constexpr field two_inv = field(2).invert();
166 constexpr field numerator = (-field(3)).
sqrt() - field(1);
167 constexpr field result = two_inv * numerator;
172 static constexpr field zero() {
return field(0, 0, 0, 0); }
173 static constexpr field neg_one() {
return -field(1); }
174 static constexpr field one() {
return field(1); }
176 static constexpr field external_coset_generator()
179 Params::coset_generators_0[7],
180 Params::coset_generators_1[7],
181 Params::coset_generators_2[7],
182 Params::coset_generators_3[7],
187 static constexpr field tag_coset_generator()
190 Params::coset_generators_0[6],
191 Params::coset_generators_1[6],
192 Params::coset_generators_2[6],
193 Params::coset_generators_3[6],
198 static constexpr field coset_generator(
const size_t idx)
202 Params::coset_generators_0[idx],
203 Params::coset_generators_1[idx],
204 Params::coset_generators_2[idx],
205 Params::coset_generators_3[idx],
210 BBERG_INLINE
constexpr field
operator*(
const field& other)
const noexcept;
211 BBERG_INLINE
constexpr field
operator+(
const field& other)
const noexcept;
212 BBERG_INLINE
constexpr field
operator-(
const field& other)
const noexcept;
213 BBERG_INLINE
constexpr field
operator-() const noexcept;
214 constexpr field operator/(const field& other) const noexcept;
217 BBERG_INLINE constexpr field operator++() noexcept;
220 BBERG_INLINE constexpr field operator++(
int) noexcept;
222 BBERG_INLINE constexpr field& operator*=(const field& other) noexcept;
223 BBERG_INLINE constexpr field& operator+=(const field& other) noexcept;
224 BBERG_INLINE constexpr field& operator-=(const field& other) noexcept;
225 constexpr field& operator/=(const field& other) noexcept;
230 BBERG_INLINE constexpr
bool operator>(const field& other) const noexcept;
231 BBERG_INLINE constexpr
bool operator<(const field& other) const noexcept;
232 BBERG_INLINE constexpr
bool operator==(const field& other) const noexcept;
233 BBERG_INLINE constexpr
bool operator!=(const field& other) const noexcept;
235 BBERG_INLINE constexpr field to_montgomery_form() const noexcept;
236 BBERG_INLINE constexpr field from_montgomery_form() const noexcept;
238 BBERG_INLINE constexpr field
sqr() const noexcept;
239 BBERG_INLINE constexpr
void self_sqr() noexcept;
241 BBERG_INLINE constexpr field pow(const
uint256_t& exponent) const noexcept;
242 BBERG_INLINE constexpr field pow(uint64_t exponent) const noexcept;
243 static constexpr
uint256_t modulus_minus_two =
244 uint256_t(Params::modulus_0 - 2ULL, Params::modulus_1, Params::modulus_2, Params::modulus_3);
245 constexpr field invert() const noexcept;
246 static
void batch_invert(std::span<field> coeffs) noexcept;
247 static
void batch_invert(field* coeffs,
size_t n) noexcept;
253 constexpr std::pair<
bool, field>
sqrt() const noexcept;
255 BBERG_INLINE constexpr
void self_neg() noexcept;
257 BBERG_INLINE constexpr
void self_to_montgomery_form() noexcept;
258 BBERG_INLINE constexpr
void self_from_montgomery_form() noexcept;
260 BBERG_INLINE constexpr
void self_conditional_negate(uint64_t predicate) noexcept;
262 BBERG_INLINE constexpr field reduce_once() const noexcept;
263 BBERG_INLINE constexpr
void self_reduce_once() noexcept;
265 BBERG_INLINE constexpr
void self_set_msb() noexcept;
266 [[nodiscard]] BBERG_INLINE constexpr
bool is_msb_set() const noexcept;
267 [[nodiscard]] BBERG_INLINE constexpr uint64_t is_msb_set_word() const noexcept;
269 [[nodiscard]] BBERG_INLINE constexpr
bool is_zero() const noexcept;
271 static constexpr field get_root_of_unity(
size_t subgroup_size) noexcept;
273 static
void serialize_to_buffer(const field& value, uint8_t* buffer) { write(buffer, value); }
275 static field serialize_from_buffer(
const uint8_t* buffer) {
return from_buffer<field>(buffer); }
277 [[nodiscard]] BBERG_INLINE std::vector<uint8_t> to_buffer()
const { return ::to_buffer(*
this); }
282 BBERG_INLINE
constexpr wide_array mul_512(
const field& other)
const noexcept;
283 BBERG_INLINE
constexpr wide_array sqr_512() const noexcept;
285 BBERG_INLINE constexpr
field conditionally_subtract_from_double_modulus(const uint64_t predicate) const noexcept
287 if (predicate != 0) {
289 twice_modulus.data[0], twice_modulus.data[1], twice_modulus.data[2], twice_modulus.data[3]
323 if constexpr (Params::modulus_3 >= 0x4000000000000000ULL) {
324 split_into_endomorphism_scalars_384(k, k1, k2);
327 field input = k.reduce_once();
329 constexpr field endo_g1 = { Params::endo_g1_lo, Params::endo_g1_mid, Params::endo_g1_hi, 0 };
331 constexpr field endo_g2 = { Params::endo_g2_lo, Params::endo_g2_mid, 0, 0 };
333 constexpr field endo_minus_b1 = { Params::endo_minus_b1_lo, Params::endo_minus_b1_mid, 0, 0 };
335 constexpr field endo_b2 = { Params::endo_b2_lo, Params::endo_b2_mid, 0, 0 };
345 c1.data[4], c1.data[5], c1.data[6], c1.data[7]
348 c2.data[4], c2.data[5], c2.data[6], c2.data[7]
359 field q1_lo{ q1.data[0], q1.data[1], q1.data[2], q1.data[3] };
360 field q2_lo{ q2.data[0], q2.data[1], q2.data[2], q2.data[3] };
362 field t1 = (q2_lo - q1_lo).reduce_once();
363 field beta = cube_root_of_unity();
364 field t2 = (t1 * beta + input).reduce_once();
365 k2.data[0] = t1.data[0];
366 k2.data[1] = t1.data[1];
367 k1.data[0] = t2.data[0];
368 k1.data[1] = t2.data[1];
371 static void split_into_endomorphism_scalars_384(
const field& input,
field& k1_out,
field& k2_out)
374 constexpr field minus_b1f{
375 Params::endo_minus_b1_lo,
376 Params::endo_minus_b1_mid,
390 Params::endo_g1_hihi,
396 Params::endo_g2_hihi,
399 field kf = input.reduce_once();
400 uint256_t k{ kf.data[0], kf.data[1], kf.data[2], kf.data[3] };
402 uint512_t c1 = (uint512_t(k) *
static_cast<uint512_t
>(g1)) >> 384;
403 uint512_t c2 = (uint512_t(k) *
static_cast<uint512_t
>(g2)) >> 384;
405 field c1f{ c1.lo.data[0], c1.lo.data[1], c1.lo.data[2], c1.lo.data[3] };
406 field c2f{ c2.lo.data[0], c2.lo.data[1], c2.lo.data[2], c2.lo.data[3] };
408 c1f.self_to_montgomery_form();
409 c2f.self_to_montgomery_form();
410 c1f = c1f * minus_b1f;
412 field r2f = c1f - c2f;
413 field beta = cube_root_of_unity();
414 field r1f = input.reduce_once() - r2f * beta;
422 friend std::ostream& operator<<(std::ostream& os,
const field& a)
424 field out = a.from_montgomery_form();
425 std::ios_base::fmtflags f(os.flags());
426 os << std::hex <<
"0x" << std::setfill(
'0') << std::setw(16) << out.data[3] << std::setw(16) << out.data[2]
427 << std::setw(16) << out.data[1] << std::setw(16) << out.data[0];
432 BBERG_INLINE
static void __copy(
const field& a, field& r)
noexcept { r = a; }
433 BBERG_INLINE
static void __swap(field& src, field& dest)
noexcept
442 static constexpr field multiplicative_generator() noexcept;
445 void msgpack_pack(auto& packer) const;
446 void msgpack_unpack(auto o);
447 void msgpack_schema(auto& packer)
const { packer.pack_alias(Params::schema_name,
"bin32"); }
450 static constexpr uint256_t twice_modulus = modulus + modulus;
451 static constexpr uint256_t not_modulus = -modulus;
452 static constexpr uint256_t twice_not_modulus = -twice_modulus;
457 constexpr wnaf_table(
const uint256_t& target)
459 static_cast<uint8_t>(target.data[0] & 15), static_cast<uint8_t>((target.data[0] >> 4) & 15),
460 static_cast<uint8_t>((target.data[0] >> 8) & 15), static_cast<uint8_t>((target.data[0] >> 12) & 15),
461 static_cast<uint8_t>((target.data[0] >> 16) & 15), static_cast<uint8_t>((target.data[0] >> 20) & 15),
462 static_cast<uint8_t>((target.data[0] >> 24) & 15), static_cast<uint8_t>((target.data[0] >> 28) & 15),
463 static_cast<uint8_t>((target.data[0] >> 32) & 15), static_cast<uint8_t>((target.data[0] >> 36) & 15),
464 static_cast<uint8_t>((target.data[0] >> 40) & 15), static_cast<uint8_t>((target.data[0] >> 44) & 15),
465 static_cast<uint8_t>((target.data[0] >> 48) & 15), static_cast<uint8_t>((target.data[0] >> 52) & 15),
466 static_cast<uint8_t>((target.data[0] >> 56) & 15), static_cast<uint8_t>((target.data[0] >> 60) & 15),
467 static_cast<uint8_t>(target.data[1] & 15), static_cast<uint8_t>((target.data[1] >> 4) & 15),
468 static_cast<uint8_t>((target.data[1] >> 8) & 15), static_cast<uint8_t>((target.data[1] >> 12) & 15),
469 static_cast<uint8_t>((target.data[1] >> 16) & 15), static_cast<uint8_t>((target.data[1] >> 20) & 15),
470 static_cast<uint8_t>((target.data[1] >> 24) & 15), static_cast<uint8_t>((target.data[1] >> 28) & 15),
471 static_cast<uint8_t>((target.data[1] >> 32) & 15), static_cast<uint8_t>((target.data[1] >> 36) & 15),
472 static_cast<uint8_t>((target.data[1] >> 40) & 15), static_cast<uint8_t>((target.data[1] >> 44) & 15),
473 static_cast<uint8_t>((target.data[1] >> 48) & 15), static_cast<uint8_t>((target.data[1] >> 52) & 15),
474 static_cast<uint8_t>((target.data[1] >> 56) & 15), static_cast<uint8_t>((target.data[1] >> 60) & 15),
475 static_cast<uint8_t>(target.data[2] & 15), static_cast<uint8_t>((target.data[2] >> 4) & 15),
476 static_cast<uint8_t>((target.data[2] >> 8) & 15), static_cast<uint8_t>((target.data[2] >> 12) & 15),
477 static_cast<uint8_t>((target.data[2] >> 16) & 15), static_cast<uint8_t>((target.data[2] >> 20) & 15),
478 static_cast<uint8_t>((target.data[2] >> 24) & 15), static_cast<uint8_t>((target.data[2] >> 28) & 15),
479 static_cast<uint8_t>((target.data[2] >> 32) & 15), static_cast<uint8_t>((target.data[2] >> 36) & 15),
480 static_cast<uint8_t>((target.data[2] >> 40) & 15), static_cast<uint8_t>((target.data[2] >> 44) & 15),
481 static_cast<uint8_t>((target.data[2] >> 48) & 15), static_cast<uint8_t>((target.data[2] >> 52) & 15),
482 static_cast<uint8_t>((target.data[2] >> 56) & 15), static_cast<uint8_t>((target.data[2] >> 60) & 15),
483 static_cast<uint8_t>(target.data[3] & 15), static_cast<uint8_t>((target.data[3] >> 4) & 15),
484 static_cast<uint8_t>((target.data[3] >> 8) & 15), static_cast<uint8_t>((target.data[3] >> 12) & 15),
485 static_cast<uint8_t>((target.data[3] >> 16) & 15), static_cast<uint8_t>((target.data[3] >> 20) & 15),
486 static_cast<uint8_t>((target.data[3] >> 24) & 15), static_cast<uint8_t>((target.data[3] >> 28) & 15),
487 static_cast<uint8_t>((target.data[3] >> 32) & 15), static_cast<uint8_t>((target.data[3] >> 36) & 15),
488 static_cast<uint8_t>((target.data[3] >> 40) & 15), static_cast<uint8_t>((target.data[3] >> 44) & 15),
489 static_cast<uint8_t>((target.data[3] >> 48) & 15), static_cast<uint8_t>((target.data[3] >> 52) & 15),
490 static_cast<uint8_t>((target.data[3] >> 56) & 15), static_cast<uint8_t>((target.data[3] >> 60) & 15)
495 BBERG_INLINE
static constexpr std::pair<uint64_t, uint64_t> mul_wide(uint64_t a, uint64_t b)
noexcept;
497 BBERG_INLINE
static constexpr uint64_t mac(
498 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& carry_out)
noexcept;
500 BBERG_INLINE
static constexpr void mac(
501 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& out, uint64_t& carry_out)
noexcept;
503 BBERG_INLINE
static constexpr uint64_t mac_mini(uint64_t a, uint64_t b, uint64_t c, uint64_t& out)
noexcept;
505 BBERG_INLINE
static constexpr void mac_mini(
506 uint64_t a, uint64_t b, uint64_t c, uint64_t& out, uint64_t& carry_out)
noexcept;
508 BBERG_INLINE
static constexpr uint64_t mac_discard_lo(uint64_t a, uint64_t b, uint64_t c)
noexcept;
510 BBERG_INLINE
static constexpr uint64_t addc(uint64_t a,
513 uint64_t& carry_out)
noexcept;
515 BBERG_INLINE
static constexpr uint64_t sbb(uint64_t a,
518 uint64_t& borrow_out)
noexcept;
520 BBERG_INLINE
static constexpr uint64_t square_accumulate(uint64_t a,
523 uint64_t carry_in_lo,
524 uint64_t carry_in_hi,
526 uint64_t& carry_hi)
noexcept;
527 BBERG_INLINE
constexpr field reduce() const noexcept;
528 BBERG_INLINE constexpr field add(const field& other) const noexcept;
529 BBERG_INLINE constexpr field subtract(const field& other) const noexcept;
530 BBERG_INLINE constexpr field subtract_coarse(const field& other) const noexcept;
531 BBERG_INLINE constexpr field montgomery_mul(const field& other) const noexcept;
532 BBERG_INLINE constexpr field montgomery_mul_big(const field& other) const noexcept;
533 BBERG_INLINE constexpr field montgomery_square() const noexcept;
535#if (BBERG_NO_ASM == 0)
536 BBERG_INLINE
static field asm_mul(
const field& a,
const field& b)
noexcept;
537 BBERG_INLINE
static field asm_sqr(
const field& a)
noexcept;
538 BBERG_INLINE
static field asm_add(
const field& a,
const field& b)
noexcept;
539 BBERG_INLINE
static field asm_sub(
const field& a,
const field& b)
noexcept;
540 BBERG_INLINE
static field asm_mul_with_coarse_reduction(
const field& a,
const field& b)
noexcept;
541 BBERG_INLINE
static field asm_sqr_with_coarse_reduction(
const field& a)
noexcept;
542 BBERG_INLINE
static field asm_add_with_coarse_reduction(
const field& a,
const field& b)
noexcept;
543 BBERG_INLINE
static field asm_sub_with_coarse_reduction(
const field& a,
const field& b)
noexcept;
544 BBERG_INLINE
static field asm_add_without_reduction(
const field& a,
const field& b)
noexcept;
545 BBERG_INLINE
static void asm_self_sqr(
const field& a)
noexcept;
546 BBERG_INLINE
static void asm_self_add(
const field& a,
const field& b)
noexcept;
547 BBERG_INLINE
static void asm_self_sub(
const field& a,
const field& b)
noexcept;
548 BBERG_INLINE
static void asm_self_mul_with_coarse_reduction(
const field& a,
const field& b)
noexcept;
549 BBERG_INLINE
static void asm_self_sqr_with_coarse_reduction(
const field& a)
noexcept;
550 BBERG_INLINE
static void asm_self_add_with_coarse_reduction(
const field& a,
const field& b)
noexcept;
551 BBERG_INLINE
static void asm_self_sub_with_coarse_reduction(
const field& a,
const field& b)
noexcept;
552 BBERG_INLINE
static void asm_self_add_without_reduction(
const field& a,
const field& b)
noexcept;
554 BBERG_INLINE
static void asm_conditional_negate(field& r, uint64_t predicate)
noexcept;
555 BBERG_INLINE
static field asm_reduce_once(
const field& a)
noexcept;
556 BBERG_INLINE
static void asm_self_reduce_once(
const field& a)
noexcept;
557 static constexpr uint64_t zero_reference = 0x00ULL;
559 static constexpr size_t COSET_GENERATOR_SIZE = 15;
560 constexpr field tonelli_shanks_sqrt() const noexcept;
561 static constexpr
size_t primitive_root_log_size() noexcept;
562 static constexpr std::array<field, COSET_GENERATOR_SIZE> compute_coset_generators() noexcept;
564#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
565 static constexpr uint128_t lo_mask = 0xffffffffffffffffUL;
569template <
typename B,
typename Params>
void read(B& it, field<Params>& value)
571 using serialize::read;
572 field<Params> result{ 0, 0, 0, 0 };
573 read(it, result.data[3]);
574 read(it, result.data[2]);
575 read(it, result.data[1]);
576 read(it, result.data[0]);
577 value = result.to_montgomery_form();
579template <
typename B,
typename Params>
void write(B& buf, field<Params>
const& value)
581 using serialize::write;
582 const field input = value.from_montgomery_form();
583 write(buf, input.data[3]);
584 write(buf, input.data[2]);
585 write(buf, input.data[1]);
586 write(buf, input.data[0]);
Definition: engine.hpp:10
Definition: uint256.hpp:25
constexpr_utils defines some helper methods that perform some stl-equivalent operations but in a cons...
Definition: constexpr_utils.hpp:16
Definition: field_declarations.hpp:279
Definition: field_declarations.hpp:24
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
constexpr field(const uint512_t &input) noexcept
Convert a 512-bit big integer into a field element.
Definition: field_declarations.hpp:99
static void split_into_endomorphism_scalars(const field &k, field &k1, field &k2)
Definition: field_declarations.hpp:320
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
BBERG_INLINE constexpr field operator-(const field &other) const noexcept
Definition: field_impl.hpp:139