Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
field_declarations.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Completed, auditors: [Raju], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
14#include <array>
15#include <cstdint>
16#include <iostream>
17#include <random>
18#include <span>
19
20#ifndef DISABLE_ASM
21#ifdef __BMI2__
22#define BBERG_NO_ASM 0
23#else
24#define BBERG_NO_ASM 1
25#endif
26#else
27#define BBERG_NO_ASM 1
28#endif
29
30namespace bb {
31
32// Threshold for "large" moduli (>= 2^254). When the top limb of the modulus is >= 2^62,
33// intermediate arithmetic results can overflow 256 bits, requiring different reduction strategies (enacted via
34// constexpr branching).
35//
36// There is a further difference: internally, when limb[3] <MODULUS_TOP_LIMB_LARGE_THRESHOLD, we allow for coarse
37// representation of the elements; this means that we assume the underlying unsigned integer to be in the range [0, 2p).
38//
39// On the other hand, for moduli with limb[3] > MODULUS_TOP_LIMB_LARGE_THRESHOLD, the uint256_t element
40// derived from the limbs is arbitrary (and is in particular NOT guaranteed to be in the range [0, p)). In particular
41// one sees this in the `add` functionality.
42
43// To speed up multiplication, we internally represent all elements in MONTGOMERY form. This means that the underlying 4
44// limbs represent a * R modulo p. (See the documentation in \ref field_docs["field documentation"]).
45//
46// In Barretenberg, the main workhorse fields are the base and scalar fields of BN-254, which are "small" moduli: they
47// are each 254 bits. The field algorithms for them are constant-time.
48//
49// NOTE: For the 254-bit fields in Barretenberg, namely BN254 base and scalar fields, we also
50// use this constexpr branching to capture another (conceptually unrelated) property: that
51// the short basis of the lattice from the endomorphism is shorter than expected. See endomorphism_scalars.py for more
52// information.
53static constexpr uint64_t MODULUS_TOP_LIMB_LARGE_THRESHOLD = 0x4000000000000000ULL; // 2^62
54
60template <class Params_> struct alignas(32) field {
61 public:
62 using View = field;
64 using Params = Params_;
65 using in_buf = const uint8_t*;
66 using vec_in_buf = const uint8_t*;
67 using out_buf = uint8_t*;
68 using vec_out_buf = uint8_t**;
69
70 // The number of element required to represent field<Params_> in the public inputs of a circuit
71 static constexpr size_t PUBLIC_INPUTS_SIZE = Params::PUBLIC_INPUTS_SIZE;
72
73#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
74#define WASM_NUM_LIMBS 9
75#define WASM_LIMB_BITS 29
76#endif
77
78 // We don't initialize data in the default constructor since we'd lose a lot of time on huge array initializations.
79 // Other alternatives have been noted, such as casting to get around constructors where they matter,
80 // however it is felt that sanitizer tools (e.g. MSAN) can detect garbage well, whereas doing
81 // hacky casts where needed would require rework to critical algos like MSM, FFT, Sumcheck.
82 // Instead, the recommended solution is use an explicit {} where initialization is important:
83 // field f; // not initialized
84 // field f{}; // zero-initialized
85 // std::array<field, N> arr; // not initialized, good for huge N
86 // std::array<field, N> arr {}; // zero-initialized, preferable for moderate N
87 field() = default;
88
89 constexpr field(const numeric::uint256_t& input) noexcept
90 : data{ input.data[0], input.data[1], input.data[2], input.data[3] }
91 {
93 }
94
95 constexpr field(const uint128_t& input) noexcept
96 : field(static_cast<uint256_t>(input))
97 {}
98
99 // NOLINTNEXTLINE (unsigned long is platform dependent, which we want in this case)
100 constexpr field(const unsigned long input) noexcept
101 : data{ input, 0, 0, 0 }
102 {
104 }
105
106 constexpr field(const unsigned int input) noexcept
107 : data{ input, 0, 0, 0 }
108 {
110 }
111
112 // NOLINTNEXTLINE (unsigned long long is platform dependent, which we want in this case)
113 constexpr field(const unsigned long long input) noexcept
114 : data{ input, 0, 0, 0 }
115 {
117 }
118
119 constexpr field(const int input) noexcept
120 : data{ 0, 0, 0, 0 }
121 {
122 if (input < 0) {
123 data[0] = static_cast<uint64_t>(-input);
124 data[1] = 0;
125 data[2] = 0;
126 data[3] = 0;
128 self_neg();
130 } else {
131 data[0] = static_cast<uint64_t>(input);
132 data[1] = 0;
133 data[2] = 0;
134 data[3] = 0;
136 }
137 }
145 constexpr field(const uint64_t a, const uint64_t b, const uint64_t c, const uint64_t d) noexcept
146 : data{ a, b, c, d } {};
147
154 constexpr explicit field(const uint512_t& input) noexcept
155 {
156 uint256_t value = (input % modulus).lo;
157 data[0] = value.data[0];
158 data[1] = value.data[1];
159 data[2] = value.data[2];
160 data[3] = value.data[3];
162 }
163
164 constexpr explicit field(std::string input) noexcept
165 {
166 uint256_t value(input);
167 *this = field(value);
168 }
169
170 // Conversion operators to primitive types.
171 // Note: from_montgomery_form() may return values bigger than p (in the range of [0, 2p) for 254-bit fields,
172 // arbitrary 256-bit number for 256-bit fields.)
173 // We call reduce_once() to ensure canonical [0, p) representation.
174
175 constexpr explicit operator bool() const
176 {
178 if ((out.data[0] != 0 && out.data[0] != 1) || out.data[1] != 0 || out.data[2] != 0 || out.data[3] != 0) {
179 bb::assert_failure("Cannot convert field element to bool unless it is 0 or 1");
180 }
181 return static_cast<bool>(out.data[0]);
182 }
183
184 constexpr explicit operator uint8_t() const
185 {
187 return static_cast<uint8_t>(out.data[0]);
188 }
189
190 constexpr explicit operator uint16_t() const
191 {
193 return static_cast<uint16_t>(out.data[0]);
194 }
195
196 constexpr explicit operator uint32_t() const
197 {
199 return static_cast<uint32_t>(out.data[0]);
200 }
201
202 constexpr explicit operator uint64_t() const
203 {
205 return out.data[0];
206 }
207
208 constexpr explicit operator uint128_t() const
209 {
211 uint128_t lo = out.data[0];
212 uint128_t hi = out.data[1];
213 return (hi << 64) | lo;
214 }
215
216 constexpr operator uint256_t() const noexcept
217 {
219 return uint256_t(out.data[0], out.data[1], out.data[2], out.data[3]);
220 }
221
222 [[nodiscard]] constexpr uint256_t uint256_t_no_montgomery_conversion() const noexcept
223 {
224 return { data[0], data[1], data[2], data[3] };
225 }
226
227 constexpr field(const field& other) noexcept = default;
228 constexpr field(field&& other) noexcept = default;
229 constexpr field& operator=(const field& other) & noexcept = default;
230 constexpr field& operator=(field&& other) & noexcept = default;
231 constexpr ~field() noexcept = default;
232 alignas(32) uint64_t data[4]; // NOLINT
233
234 static constexpr uint256_t modulus =
235 uint256_t{ Params::modulus_0, Params::modulus_1, Params::modulus_2, Params::modulus_3 };
236#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
237 static constexpr uint256_t r_squared_uint{
238 Params_::r_squared_0, Params_::r_squared_1, Params_::r_squared_2, Params_::r_squared_3
239 };
240#else
241 static constexpr uint256_t r_squared_uint{
242 Params_::r_squared_wasm_0, Params_::r_squared_wasm_1, Params_::r_squared_wasm_2, Params_::r_squared_wasm_3
243 };
244 static constexpr std::array<uint64_t, 9> wasm_modulus = { Params::modulus_wasm_0, Params::modulus_wasm_1,
245 Params::modulus_wasm_2, Params::modulus_wasm_3,
246 Params::modulus_wasm_4, Params::modulus_wasm_5,
247 Params::modulus_wasm_6, Params::modulus_wasm_7,
248 Params::modulus_wasm_8 };
249 static constexpr std::array<uint64_t, 9> wasm_r_inv = {
250 Params::r_inv_wasm_0, Params::r_inv_wasm_1, Params::r_inv_wasm_2, Params::r_inv_wasm_3, Params::r_inv_wasm_4,
251 Params::r_inv_wasm_5, Params::r_inv_wasm_6, Params::r_inv_wasm_7, Params::r_inv_wasm_8
252 };
253
254#endif
255 static constexpr field cube_root_of_unity()
256 {
257 // endomorphism i.e. lambda * [P] = (beta * x, y)
258 if constexpr (Params::cube_root_0 != 0) {
259#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
260 constexpr field result{
261 Params::cube_root_0, Params::cube_root_1, Params::cube_root_2, Params::cube_root_3
262 };
263#else
264 constexpr field result{
265 Params::cube_root_wasm_0, Params::cube_root_wasm_1, Params::cube_root_wasm_2, Params::cube_root_wasm_3
266 };
267#endif
268 return result;
269 } else {
270 constexpr field two_inv = field(2).invert();
271 constexpr field numerator = (-field(3)).sqrt() - field(1);
272 constexpr field result = two_inv * numerator;
273 return result;
274 }
275 }
276
277 static constexpr field zero() { return field(0, 0, 0, 0); }
278 static constexpr field neg_one() { return -field(1); }
279 static constexpr field one() { return field(1); }
280
281 static constexpr field coset_generator()
282 {
283#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
284 const field result{
285 Params::coset_generator_0,
286 Params::coset_generator_1,
287 Params::coset_generator_2,
288 Params::coset_generator_3,
289 };
290#else
291 const field result{
292 Params::coset_generator_0,
293 Params::coset_generator_1,
294 Params::coset_generator_2,
295 Params::coset_generator_3,
296 };
297#endif
298
299 return result;
300 }
301
302 BB_INLINE constexpr field operator*(const field& other) const noexcept;
303 BB_INLINE constexpr field operator+(const field& other) const noexcept;
304 BB_INLINE constexpr field operator-(const field& other) const noexcept;
305 BB_INLINE constexpr field operator-() const noexcept;
306 constexpr field operator/(const field& other) const noexcept;
307
308 // prefix increment (++x)
309 BB_INLINE constexpr field operator++() noexcept;
310 // postfix increment (x++)
311 // NOLINTNEXTLINE
312 BB_INLINE constexpr field operator++(int) noexcept;
313
314 BB_INLINE constexpr field& operator*=(const field& other) & noexcept;
315 BB_INLINE constexpr field& operator+=(const field& other) & noexcept;
316 BB_INLINE constexpr field& operator-=(const field& other) & noexcept;
317 constexpr field& operator/=(const field& other) & noexcept;
318
319 // NOTE: comparison operators exist so that `field` is comparible with stl methods that require them.
320 // (e.g. std::sort)
321 // Finite fields do not have an explicit ordering, these should *NEVER* be used in algebraic algorithms.
322 BB_INLINE constexpr bool operator>(const field& other) const noexcept;
323 BB_INLINE constexpr bool operator<(const field& other) const noexcept;
324 BB_INLINE constexpr bool operator==(const field& other) const noexcept;
325 BB_INLINE constexpr bool operator!=(const field& other) const noexcept;
326
327 BB_INLINE constexpr field to_montgomery_form() const noexcept;
328 BB_INLINE constexpr field from_montgomery_form() const noexcept;
329 // Reduced versions guarantee output is in canonical form [0, p)
330 BB_INLINE constexpr field to_montgomery_form_reduced() const noexcept;
331 BB_INLINE constexpr field from_montgomery_form_reduced() const noexcept;
332
333 BB_INLINE constexpr field sqr() const noexcept;
334 BB_INLINE constexpr void self_sqr() & noexcept;
335
336 BB_INLINE constexpr field pow(const uint256_t& exponent) const noexcept;
337 BB_INLINE constexpr field pow(uint64_t exponent) const noexcept;
338 // STARKNET: next line was commented as stark252 violates the assertion
339 // static_assert(Params::modulus_0 != 1);
340 static constexpr uint256_t modulus_minus_two =
341 uint256_t(Params::modulus_0 - 2ULL, Params::modulus_1, Params::modulus_2, Params::modulus_3);
342 constexpr field invert() const noexcept;
343 constexpr field invert_const_time() const noexcept;
344 template <typename C>
345 // has size() and operator[].
346 requires requires(C& c) {
347 { c.size() } -> std::convertible_to<size_t>;
348 { c[0] };
349 }
350 static void batch_invert(C& coeffs) noexcept;
351 static void batch_invert(field* coeffs, size_t n) noexcept;
352 static void batch_invert(std::span<field> coeffs) noexcept;
358 constexpr std::pair<bool, field> sqrt() const noexcept
359 requires((Params_::modulus_0 & 0x3UL) == 0x3UL);
360 constexpr std::pair<bool, field> sqrt() const noexcept
361 requires((Params_::modulus_0 & 0x3UL) != 0x3UL);
362 BB_INLINE constexpr void self_neg() & noexcept;
363
364 BB_INLINE constexpr void self_to_montgomery_form() & noexcept;
365 BB_INLINE constexpr void self_from_montgomery_form() & noexcept;
366 // Reduced versions guarantee output is in canonical form [0, p)
367 BB_INLINE constexpr void self_to_montgomery_form_reduced() & noexcept;
368 BB_INLINE constexpr void self_from_montgomery_form_reduced() & noexcept;
369
370 BB_INLINE constexpr void self_conditional_negate(uint64_t predicate) & noexcept;
371
372 BB_INLINE constexpr field reduce_once() const noexcept;
373 BB_INLINE constexpr void self_reduce_once() & noexcept;
374
375 BB_INLINE constexpr void self_set_msb() & noexcept;
376 [[nodiscard]] BB_INLINE constexpr bool is_msb_set() const noexcept;
377 [[nodiscard]] BB_INLINE constexpr uint64_t is_msb_set_word() const noexcept;
378
379 [[nodiscard]] BB_INLINE constexpr bool is_zero() const noexcept;
380
381 static constexpr field get_root_of_unity(size_t subgroup_size) noexcept;
382
383 static void serialize_to_buffer(const field& value, uint8_t* buffer) { write(buffer, value); }
384
385 static field serialize_from_buffer(const uint8_t* buffer) { return from_buffer<field>(buffer); }
386
387 template <class V> static field reconstruct_from_public(const std::span<const field<V>, PUBLIC_INPUTS_SIZE>& limbs);
388
389 [[nodiscard]] BB_INLINE std::vector<uint8_t> to_buffer() const { return ::to_buffer(*this); }
390
391 struct wide_array {
392 uint64_t data[8]; // NOLINT
393 };
394 BB_INLINE constexpr wide_array mul_512(const field& other) const noexcept;
395
433 {
434 // force into strict form.
435 field input = k.reduce_once();
436
437 constexpr field endo_g1 = { Params::endo_g1_lo, Params::endo_g1_mid, Params::endo_g1_hi, 0 };
438 constexpr field endo_g2 = { Params::endo_g2_lo, Params::endo_g2_mid, 0, 0 };
439 constexpr field endo_minus_b1 = { Params::endo_minus_b1_lo, Params::endo_minus_b1_mid, 0, 0 };
440 constexpr field endo_b2 = { Params::endo_b2_lo, Params::endo_b2_mid, 0, 0 };
441
442 // c1 = (g2 * k) >> 256, c2 = (g1 * k) >> 256
443 wide_array c1 = endo_g2.mul_512(input);
444 wide_array c2 = endo_g1.mul_512(input);
445
446 // extract high halves
447 field c1_hi{ c1.data[4], c1.data[5], c1.data[6], c1.data[7] };
448 field c2_hi{ c2.data[4], c2.data[5], c2.data[6], c2.data[7] };
449
450 // q1 = c1 * (-b1), q2 = c2 * b2
451 wide_array q1 = c1_hi.mul_512(endo_minus_b1);
452 wide_array q2 = c2_hi.mul_512(endo_b2);
453
454 field q1_lo{ q1.data[0], q1.data[1], q1.data[2], q1.data[3] };
455 field q2_lo{ q2.data[0], q2.data[1], q2.data[2], q2.data[3] };
456
457 return (q2_lo - q1_lo).reduce_once();
458 }
459
473 static void split_into_endomorphism_scalars(const field& k, field& k1, field& k2)
474 {
475 if constexpr (Params::modulus_3 < MODULUS_TOP_LIMB_LARGE_THRESHOLD) {
476 // BN254 base or scalar field: use path that corresponds to 128-bit outputs.
478 k1 = { ret.first[0], ret.first[1], 0, 0 };
479 k2 = { ret.second[0], ret.second[1], 0, 0 };
480 } else {
481 // Large modulus (secp256k1): full-width path.
483 k2 = t1;
484 k1 = ((t1 * cube_root_of_unity()) + k).reduce_once();
485 }
486 }
487
503 {
504 static_assert(Params::modulus_3 < MODULUS_TOP_LIMB_LARGE_THRESHOLD);
505
506 // short-circuit the split if k is already small
507 if (k.data[2] == 0 && k.data[3] == 0 && (k.data[1] >> 63) == 0) {
508 return {
509 { k.data[0], k.data[1] },
510 { 0, 0 },
511 };
512 }
513
515
516 // k2 (= t1) can be slightly negative for ~2^{-64} of inputs.
517 // When negative, t1 = k2 + r is 254 bits (upper limbs nonzero).
518 // Fix: decrement c1 by 1, equivalent to adding |b1| to k2.
519 // This shifts k2 by +|b1| (~127 bits, now positive) and k1 by -a1 (~64 bits),
520 // keeping both within 128 bits. See endomorphism_scalars.py for more details.
521 if (t1.data[2] != 0 || t1.data[3] != 0) {
522 constexpr field endo_minus_b1 = { Params::endo_minus_b1_lo, Params::endo_minus_b1_mid, 0, 0 };
523 t1 = (t1 + endo_minus_b1).reduce_once();
524 }
525
526 field t2 = ((t1 * cube_root_of_unity()) + k).reduce_once();
527 return {
528 { t2.data[0], t2.data[1] },
529 { t1.data[0], t1.data[1] },
530 };
531 }
532
533 friend std::ostream& operator<<(std::ostream& os, const field& a)
534 {
536 std::ios_base::fmtflags f(os.flags());
537 os << std::hex << "0x" << std::setfill('0') << std::setw(16) << out.data[3] << std::setw(16) << out.data[2]
538 << std::setw(16) << out.data[1] << std::setw(16) << out.data[0];
539 os.flags(f);
540 return os;
541 }
542
543 BB_INLINE static void __copy(const field& a, field& r) noexcept { r = a; } // NOLINT
544 static field random_element(numeric::RNG* engine = nullptr) noexcept;
545
546 // For serialization
547 void msgpack_pack(auto& packer) const;
548 void msgpack_unpack(auto o);
549 void msgpack_schema(auto& packer) const { packer.pack_alias(Params::schema_name, "bin32"); }
550
552 static constexpr uint256_t not_modulus = -modulus;
554
555#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
556 BB_INLINE static constexpr void wasm_madd(uint64_t& left_limb,
557 const std::array<uint64_t, WASM_NUM_LIMBS>& right_limbs,
558 uint64_t& result_0,
559 uint64_t& result_1,
560 uint64_t& result_2,
561 uint64_t& result_3,
562 uint64_t& result_4,
563 uint64_t& result_5,
564 uint64_t& result_6,
565 uint64_t& result_7,
566 uint64_t& result_8);
567 BB_INLINE static constexpr void wasm_reduce(uint64_t& result_0,
568 uint64_t& result_1,
569 uint64_t& result_2,
570 uint64_t& result_3,
571 uint64_t& result_4,
572 uint64_t& result_5,
573 uint64_t& result_6,
574 uint64_t& result_7,
575 uint64_t& result_8);
576 BB_INLINE static constexpr void wasm_reduce_yuval(uint64_t& result_0,
577 uint64_t& result_1,
578 uint64_t& result_2,
579 uint64_t& result_3,
580 uint64_t& result_4,
581 uint64_t& result_5,
582 uint64_t& result_6,
583 uint64_t& result_7,
584 uint64_t& result_8,
585 uint64_t& result_9);
586 BB_INLINE static constexpr std::array<uint64_t, WASM_NUM_LIMBS> wasm_convert(const uint64_t* data);
587#endif
588 BB_INLINE static constexpr std::pair<uint64_t, uint64_t> mul_wide(uint64_t a, uint64_t b) noexcept;
589
590 BB_INLINE static constexpr uint64_t mac(
591 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& carry_out) noexcept;
592
593 BB_INLINE static constexpr void mac(
594 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& out, uint64_t& carry_out) noexcept;
595
596 BB_INLINE static constexpr uint64_t mac_mini(uint64_t a, uint64_t b, uint64_t c, uint64_t& out) noexcept;
597
598 BB_INLINE static constexpr void mac_mini(
599 uint64_t a, uint64_t b, uint64_t c, uint64_t& out, uint64_t& carry_out) noexcept;
600
601 BB_INLINE static constexpr uint64_t mac_discard_lo(uint64_t a, uint64_t b, uint64_t c) noexcept;
602
603 BB_INLINE static constexpr uint64_t addc(uint64_t a, uint64_t b, uint64_t carry_in, uint64_t& carry_out) noexcept;
604
605 BB_INLINE static constexpr uint64_t sbb(uint64_t a, uint64_t b, uint64_t borrow_in, uint64_t& borrow_out) noexcept;
606
607 BB_INLINE static constexpr uint64_t square_accumulate(uint64_t a,
608 uint64_t b,
609 uint64_t c,
610 uint64_t carry_in_lo,
611 uint64_t carry_in_hi,
612 uint64_t& carry_lo,
613 uint64_t& carry_hi) noexcept;
614 BB_INLINE constexpr field reduce() const noexcept;
615 BB_INLINE constexpr field add(const field& other) const noexcept;
616 BB_INLINE constexpr field subtract(const field& other) const noexcept;
617
618 // Debug-only assertion: checks that the field element is in the strict coarse form [0, 2p).
619 // Only meaningful for "small" moduli (<=254 bits) which use the coarse representation.
620 // Not constexpr in debug builds (BB_ASSERT_DEBUG uses std::ostringstream).
621 // Callers must guard with `if (!std::is_constant_evaluated())` in constexpr functions.
622#ifdef NDEBUG
623 constexpr void assert_coarse_form() const noexcept {}
624#else
625 void assert_coarse_form() const noexcept
626 {
627 if constexpr (modulus.data[3] < MODULUS_TOP_LIMB_LARGE_THRESHOLD) {
628 uint256_t val{ data[0], data[1], data[2], data[3] };
629 BB_ASSERT_DEBUG(val < twice_modulus, "field element exceeds coarse form [0, 2p)");
630 }
631 }
632#endif
633 BB_INLINE constexpr field montgomery_mul(const field& other) const noexcept;
634 BB_INLINE constexpr field montgomery_mul_big(const field& other) const noexcept;
635 BB_INLINE constexpr field montgomery_square() const noexcept;
636
637#if (BBERG_NO_ASM == 0)
638 BB_INLINE static field asm_mul_with_coarse_reduction(const field& a, const field& b) noexcept;
639 BB_INLINE static field asm_sqr_with_coarse_reduction(const field& a) noexcept;
640 BB_INLINE static field asm_add_with_coarse_reduction(const field& a, const field& b) noexcept;
641 BB_INLINE static field asm_sub_with_coarse_reduction(const field& a, const field& b) noexcept;
642 BB_INLINE static void asm_self_mul_with_coarse_reduction(field& a, const field& b) noexcept;
643 BB_INLINE static void asm_self_sqr_with_coarse_reduction(field& a) noexcept;
644 BB_INLINE static void asm_self_add_with_coarse_reduction(field& a, const field& b) noexcept;
645 BB_INLINE static void asm_self_sub_with_coarse_reduction(field& a, const field& b) noexcept;
646
647 BB_INLINE static void asm_conditional_negate(field& r, uint64_t predicate) noexcept;
648 BB_INLINE static field asm_reduce_once(const field& a) noexcept;
649 BB_INLINE static void asm_self_reduce_once(field& a) noexcept;
650 static constexpr uint64_t zero_reference = 0x00ULL;
651#endif
652 constexpr field tonelli_shanks_sqrt() const noexcept;
653 static constexpr size_t primitive_root_log_size() noexcept;
654
655#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
656 static constexpr uint128_t lo_mask = 0xffffffffffffffffUL;
657#endif
658};
659
660template <typename B, typename Params> void read(B& it, field<Params>& value)
661{
662 using serialize::read;
663 field<Params> result{ 0, 0, 0, 0 };
664 read(it, result.data[3]);
665 read(it, result.data[2]);
666 read(it, result.data[1]);
667 read(it, result.data[0]);
668 value = result.to_montgomery_form();
669}
670template <typename B, typename Params> void write(B& buf, field<Params> const& value)
671{
672 using serialize::write;
674 write(buf, input.data[3]);
675 write(buf, input.data[2]);
676 write(buf, input.data[1]);
677 write(buf, input.data[0]);
678}
679
680} // namespace bb
681
682// Define hash function for field elements, e.g., so that it can be used in maps.
683// See https://en.cppreference.com/w/cpp/utility/hash .
684template <typename Params> struct std::hash<bb::field<Params>> {
685 std::size_t operator()(const bb::field<Params>& ff) const noexcept
686 {
687 // Just like in equality, we need to reduce the field element before hashing.
688 auto reduced = ff.reduce_once();
689 return bb::utils::hash_as_tuple(reduced.data[0], reduced.data[1], reduced.data[2], reduced.data[3]);
690 }
691};
#define BB_ASSERT_DEBUG(expression,...)
Definition assert.hpp:55
#define BB_INLINE
FF a
FF b
numeric::RNG & engine
std::unique_ptr< uint8_t[]> buffer
Definition engine.cpp:60
size_t hash_as_tuple(const Ts &... ts)
Definition utils.hpp:22
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void read(B &it, field2< base_field, Params > &value)
void write(B &buf, field2< base_field, Params > const &value)
void assert_failure(std::string const &err)
Definition assert.cpp:11
void read(auto &it, msgpack_concepts::HasMsgPack auto &obj)
Automatically derived read for any object that defines .msgpack() (implicitly defined by SERIALIZATIO...
void write(auto &buf, const msgpack_concepts::HasMsgPack auto &obj)
Automatically derived write for any object that defines .msgpack() (implicitly defined by SERIALIZATI...
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
unsigned __int128 uint128_t
Definition serialize.hpp:45
General class for prime fields see Prime field documentation["field documentation"] for general imple...
static constexpr field cube_root_of_unity()
void assert_coarse_form() const noexcept
constexpr field(const int input) noexcept
field()=default
constexpr ~field() noexcept=default
BB_INLINE constexpr field from_montgomery_form_reduced() const noexcept
static constexpr std::array< uint64_t, 9 > wasm_modulus
static constexpr field get_root_of_unity(size_t subgroup_size) noexcept
BB_INLINE constexpr void self_to_montgomery_form_reduced() &noexcept
static constexpr field neg_one()
static constexpr field one()
static constexpr uint256_t modulus
BB_INLINE constexpr void self_reduce_once() &noexcept
static BB_INLINE constexpr std::array< uint64_t, WASM_NUM_LIMBS > wasm_convert(const uint64_t *data)
Convert 4 64-bit limbs into 9 29-bit limbs.
constexpr field(const unsigned long long input) 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....
constexpr field & operator=(const field &other) &noexcept=default
static constexpr field coset_generator()
BB_INLINE constexpr void self_from_montgomery_form_reduced() &noexcept
static BB_INLINE constexpr std::pair< uint64_t, uint64_t > mul_wide(uint64_t a, uint64_t b) noexcept
static constexpr uint256_t twice_not_modulus
BB_INLINE constexpr field to_montgomery_form() const noexcept
BB_INLINE constexpr wide_array mul_512(const field &other) const noexcept
static BB_INLINE constexpr uint64_t mac_discard_lo(uint64_t a, uint64_t b, uint64_t c) noexcept
static BB_INLINE constexpr uint64_t sbb(uint64_t a, uint64_t b, uint64_t borrow_in, uint64_t &borrow_out) noexcept
unsigned 64-bit subtract-with-borrow that takes in borrow_in value in the size-2 set {0,...
BB_INLINE constexpr field subtract(const field &other) const noexcept
BB_INLINE constexpr void self_conditional_negate(uint64_t predicate) &noexcept
void msgpack_schema(auto &packer) const
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
static BB_INLINE constexpr uint64_t mac(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t &carry_out) noexcept
Compute uint128_t(a * b + c + carry_in), where the inputs are all uint64_t. Return the top 64 bits.
static void split_into_endomorphism_scalars(const field &k, field &k1, field &k2)
Full-width endomorphism decomposition: k ≡ k1 - k2·λ (mod r). Modifies the field elements k1 and k2.
friend std::ostream & operator<<(std::ostream &os, const field &a)
static BB_INLINE constexpr uint64_t addc(uint64_t a, uint64_t b, uint64_t carry_in, uint64_t &carry_out) noexcept
unsigned 64-bit add-with-carry that takes in a carry_in and a carry_out bit and rewrites the latter.
static constexpr uint256_t r_squared_uint
static BB_INLINE constexpr void wasm_reduce(uint64_t &result_0, uint64_t &result_1, uint64_t &result_2, uint64_t &result_3, uint64_t &result_4, uint64_t &result_5, uint64_t &result_6, uint64_t &result_7, uint64_t &result_8)
Perform 29-bit Montgomery reduction on 1 limb (result_0 should be zero modulo 2^29 after calling this...
BB_INLINE constexpr field montgomery_mul_big(const field &other) const noexcept
Mongtomery multiplication for moduli > 2²⁵⁴
static constexpr size_t PUBLIC_INPUTS_SIZE
constexpr field & operator=(field &&other) &noexcept=default
constexpr field(const uint64_t a, const uint64_t b, const uint64_t c, const uint64_t d) noexcept
cast four uint64_t as a field
uint8_t ** vec_out_buf
constexpr field(const uint128_t &input) noexcept
BB_INLINE constexpr void self_sqr() &noexcept
constexpr field(const uint512_t &input) noexcept
Convert a 512-bit big integer into a field element.
constexpr field invert() const noexcept
constexpr field(field &&other) noexcept=default
BB_INLINE constexpr void self_neg() &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
static BB_INLINE constexpr void wasm_madd(uint64_t &left_limb, const std::array< uint64_t, WASM_NUM_LIMBS > &right_limbs, uint64_t &result_0, uint64_t &result_1, uint64_t &result_2, uint64_t &result_3, uint64_t &result_4, uint64_t &result_5, uint64_t &result_6, uint64_t &result_7, uint64_t &result_8)
Multiply left limb by a sequence of 9 limbs and accumulate into result variables.
static BB_INLINE constexpr uint64_t square_accumulate(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in_lo, uint64_t carry_in_hi, uint64_t &carry_lo, uint64_t &carry_hi) noexcept
Computes a + 2 * b * c + carry_in_lo + 2^64 * carry_in_hi, in the form of returning a uint64_t and mo...
BB_INLINE constexpr field to_montgomery_form_reduced() const noexcept
constexpr uint256_t uint256_t_no_montgomery_conversion() const noexcept
static BB_INLINE constexpr void wasm_reduce_yuval(uint64_t &result_0, uint64_t &result_1, uint64_t &result_2, uint64_t &result_3, uint64_t &result_4, uint64_t &result_5, uint64_t &result_6, uint64_t &result_7, uint64_t &result_8, uint64_t &result_9)
Perform 29-bit Montgomery reduction on 1 limb using Yuval's method.
static field serialize_from_buffer(const uint8_t *buffer)
static constexpr uint256_t modulus_minus_two
static void serialize_to_buffer(const field &value, uint8_t *buffer)
void msgpack_pack(auto &packer) const
constexpr std::pair< bool, field > sqrt() const noexcept
Compute square root of the field element.
static BB_INLINE void __copy(const field &a, field &r) noexcept
const uint8_t * vec_in_buf
constexpr field(const field &other) noexcept=default
BB_INLINE constexpr void self_from_montgomery_form() &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.
static constexpr uint256_t not_modulus
BB_INLINE constexpr void self_to_montgomery_form() &noexcept
static constexpr std::array< uint64_t, 9 > wasm_r_inv
BB_INLINE constexpr field from_montgomery_form() const noexcept
BB_INLINE constexpr field operator-() const noexcept
constexpr field(const numeric::uint256_t &input) noexcept
BB_INLINE constexpr void self_set_msb() &noexcept
const uint8_t * in_buf
void msgpack_unpack(auto o)
BB_INLINE constexpr field add(const field &other) const noexcept
BB_INLINE std::vector< uint8_t > to_buffer() const
constexpr field(const unsigned int input) noexcept
static constexpr size_t primitive_root_log_size() noexcept
static field compute_endomorphism_k2(const field &k)
Shared core of the endomorphism scalar decomposition.
static field reconstruct_from_public(const std::span< const field< V >, PUBLIC_INPUTS_SIZE > &limbs)
BB_INLINE constexpr field montgomery_square() const noexcept
Squaring via a variant of the Montgomery algorithm, where we roughly take advantage of the repeated t...
BB_INLINE constexpr field reduce_once() const noexcept
BB_INLINE constexpr field montgomery_mul(const field &other) const noexcept
static std::pair< std::array< uint64_t, 2 >, std::array< uint64_t, 2 > > split_into_endomorphism_scalars(const field &k)
128-bit endomorphism decomposition: k ≡ k1 - k2·λ (mod r).
BB_INLINE constexpr field reduce() const noexcept
reduce once, i.e., if the value is bigger than the modulus, subtract off the modulus once.
constexpr field(const unsigned long input) noexcept
static constexpr field zero()
constexpr field invert_const_time() const noexcept
static BB_INLINE constexpr uint64_t mac_mini(uint64_t a, uint64_t b, uint64_t c, uint64_t &out) noexcept
BB_INLINE constexpr uint64_t is_msb_set_word() const noexcept
static constexpr uint256_t twice_modulus
constexpr field(std::string input) noexcept
std::size_t operator()(const bb::field< Params > &ff) const noexcept