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 template <typename C>
344 // has size() and operator[].
345 requires requires(C& c) {
346 { c.size() } -> std::convertible_to<size_t>;
347 { c[0] };
348 }
349 static void batch_invert(C& coeffs) noexcept;
350 static void batch_invert(field* coeffs, size_t n) noexcept;
351 static void batch_invert(std::span<field> coeffs) noexcept;
357 constexpr std::pair<bool, field> sqrt() const noexcept
358 requires((Params_::modulus_0 & 0x3UL) == 0x3UL);
359 constexpr std::pair<bool, field> sqrt() const noexcept
360 requires((Params_::modulus_0 & 0x3UL) != 0x3UL);
361 BB_INLINE constexpr void self_neg() & noexcept;
362
363 BB_INLINE constexpr void self_to_montgomery_form() & noexcept;
364 BB_INLINE constexpr void self_from_montgomery_form() & noexcept;
365 // Reduced versions guarantee output is in canonical form [0, p)
366 BB_INLINE constexpr void self_to_montgomery_form_reduced() & noexcept;
367 BB_INLINE constexpr void self_from_montgomery_form_reduced() & noexcept;
368
369 BB_INLINE constexpr void self_conditional_negate(uint64_t predicate) & noexcept;
370
371 BB_INLINE constexpr field reduce_once() const noexcept;
372 BB_INLINE constexpr void self_reduce_once() & noexcept;
373
374 BB_INLINE constexpr void self_set_msb() & noexcept;
375 [[nodiscard]] BB_INLINE constexpr bool is_msb_set() const noexcept;
376 [[nodiscard]] BB_INLINE constexpr uint64_t is_msb_set_word() const noexcept;
377
378 [[nodiscard]] BB_INLINE constexpr bool is_zero() const noexcept;
379
380 static constexpr field get_root_of_unity(size_t subgroup_size) noexcept;
381
382 static void serialize_to_buffer(const field& value, uint8_t* buffer) { write(buffer, value); }
383
384 static field serialize_from_buffer(const uint8_t* buffer) { return from_buffer<field>(buffer); }
385
386 template <class V> static field reconstruct_from_public(const std::span<const field<V>, PUBLIC_INPUTS_SIZE>& limbs);
387
388 [[nodiscard]] BB_INLINE std::vector<uint8_t> to_buffer() const { return ::to_buffer(*this); }
389
390 struct wide_array {
391 uint64_t data[8]; // NOLINT
392 };
393 BB_INLINE constexpr wide_array mul_512(const field& other) const noexcept;
394
432 {
433 // force into strict form.
434 field input = k.reduce_once();
435
436 constexpr field endo_g1 = { Params::endo_g1_lo, Params::endo_g1_mid, Params::endo_g1_hi, 0 };
437 constexpr field endo_g2 = { Params::endo_g2_lo, Params::endo_g2_mid, 0, 0 };
438 constexpr field endo_minus_b1 = { Params::endo_minus_b1_lo, Params::endo_minus_b1_mid, 0, 0 };
439 constexpr field endo_b2 = { Params::endo_b2_lo, Params::endo_b2_mid, 0, 0 };
440
441 // c1 = (g2 * k) >> 256, c2 = (g1 * k) >> 256
442 wide_array c1 = endo_g2.mul_512(input);
443 wide_array c2 = endo_g1.mul_512(input);
444
445 // extract high halves
446 field c1_hi{ c1.data[4], c1.data[5], c1.data[6], c1.data[7] };
447 field c2_hi{ c2.data[4], c2.data[5], c2.data[6], c2.data[7] };
448
449 // q1 = c1 * (-b1), q2 = c2 * b2
450 wide_array q1 = c1_hi.mul_512(endo_minus_b1);
451 wide_array q2 = c2_hi.mul_512(endo_b2);
452
453 field q1_lo{ q1.data[0], q1.data[1], q1.data[2], q1.data[3] };
454 field q2_lo{ q2.data[0], q2.data[1], q2.data[2], q2.data[3] };
455
456 return (q2_lo - q1_lo).reduce_once();
457 }
458
472 static void split_into_endomorphism_scalars(const field& k, field& k1, field& k2)
473 {
474 if constexpr (Params::modulus_3 < MODULUS_TOP_LIMB_LARGE_THRESHOLD) {
475 // BN254 base or scalar field: use path that corresponds to 128-bit outputs.
477 k1 = { ret.first[0], ret.first[1], 0, 0 };
478 k2 = { ret.second[0], ret.second[1], 0, 0 };
479 } else {
480 // Large modulus (secp256k1): full-width path.
482 k2 = t1;
483 k1 = ((t1 * cube_root_of_unity()) + k).reduce_once();
484 }
485 }
486
502 {
503 static_assert(Params::modulus_3 < MODULUS_TOP_LIMB_LARGE_THRESHOLD);
505
506 // k2 (= t1) can be slightly negative for ~2^{-64} of inputs.
507 // When negative, t1 = k2 + r is 254 bits (upper limbs nonzero).
508 // Fix: decrement c1 by 1, equivalent to adding |b1| to k2.
509 // This shifts k2 by +|b1| (~127 bits, now positive) and k1 by -a1 (~64 bits),
510 // keeping both within 128 bits. See endomorphism_scalars.py for more details.
511 if (t1.data[2] != 0 || t1.data[3] != 0) {
512 constexpr field endo_minus_b1 = { Params::endo_minus_b1_lo, Params::endo_minus_b1_mid, 0, 0 };
513 t1 = (t1 + endo_minus_b1).reduce_once();
514 }
515
516 field t2 = ((t1 * cube_root_of_unity()) + k).reduce_once();
517 return {
518 { t2.data[0], t2.data[1] },
519 { t1.data[0], t1.data[1] },
520 };
521 }
522
523 friend std::ostream& operator<<(std::ostream& os, const field& a)
524 {
526 std::ios_base::fmtflags f(os.flags());
527 os << std::hex << "0x" << std::setfill('0') << std::setw(16) << out.data[3] << std::setw(16) << out.data[2]
528 << std::setw(16) << out.data[1] << std::setw(16) << out.data[0];
529 os.flags(f);
530 return os;
531 }
532
533 BB_INLINE static void __copy(const field& a, field& r) noexcept { r = a; } // NOLINT
534 static field random_element(numeric::RNG* engine = nullptr) noexcept;
535
536 // For serialization
537 void msgpack_pack(auto& packer) const;
538 void msgpack_unpack(auto o);
539 void msgpack_schema(auto& packer) const { packer.pack_alias(Params::schema_name, "bin32"); }
540
542 static constexpr uint256_t not_modulus = -modulus;
544
545#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
546 BB_INLINE static constexpr void wasm_madd(uint64_t& left_limb,
547 const std::array<uint64_t, WASM_NUM_LIMBS>& right_limbs,
548 uint64_t& result_0,
549 uint64_t& result_1,
550 uint64_t& result_2,
551 uint64_t& result_3,
552 uint64_t& result_4,
553 uint64_t& result_5,
554 uint64_t& result_6,
555 uint64_t& result_7,
556 uint64_t& result_8);
557 BB_INLINE static constexpr void wasm_reduce(uint64_t& result_0,
558 uint64_t& result_1,
559 uint64_t& result_2,
560 uint64_t& result_3,
561 uint64_t& result_4,
562 uint64_t& result_5,
563 uint64_t& result_6,
564 uint64_t& result_7,
565 uint64_t& result_8);
566 BB_INLINE static constexpr void wasm_reduce_yuval(uint64_t& result_0,
567 uint64_t& result_1,
568 uint64_t& result_2,
569 uint64_t& result_3,
570 uint64_t& result_4,
571 uint64_t& result_5,
572 uint64_t& result_6,
573 uint64_t& result_7,
574 uint64_t& result_8,
575 uint64_t& result_9);
576 BB_INLINE static constexpr std::array<uint64_t, WASM_NUM_LIMBS> wasm_convert(const uint64_t* data);
577#endif
578 BB_INLINE static constexpr std::pair<uint64_t, uint64_t> mul_wide(uint64_t a, uint64_t b) noexcept;
579
580 BB_INLINE static constexpr uint64_t mac(
581 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& carry_out) noexcept;
582
583 BB_INLINE static constexpr void mac(
584 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& out, uint64_t& carry_out) noexcept;
585
586 BB_INLINE static constexpr uint64_t mac_mini(uint64_t a, uint64_t b, uint64_t c, uint64_t& out) noexcept;
587
588 BB_INLINE static constexpr void mac_mini(
589 uint64_t a, uint64_t b, uint64_t c, uint64_t& out, uint64_t& carry_out) noexcept;
590
591 BB_INLINE static constexpr uint64_t mac_discard_lo(uint64_t a, uint64_t b, uint64_t c) noexcept;
592
593 BB_INLINE static constexpr uint64_t addc(uint64_t a, uint64_t b, uint64_t carry_in, uint64_t& carry_out) noexcept;
594
595 BB_INLINE static constexpr uint64_t sbb(uint64_t a, uint64_t b, uint64_t borrow_in, uint64_t& borrow_out) noexcept;
596
597 BB_INLINE static constexpr uint64_t square_accumulate(uint64_t a,
598 uint64_t b,
599 uint64_t c,
600 uint64_t carry_in_lo,
601 uint64_t carry_in_hi,
602 uint64_t& carry_lo,
603 uint64_t& carry_hi) noexcept;
604 BB_INLINE constexpr field reduce() const noexcept;
605 BB_INLINE constexpr field add(const field& other) const noexcept;
606 BB_INLINE constexpr field subtract(const field& other) const noexcept;
607
608 // Debug-only assertion: checks that the field element is in the strict coarse form [0, 2p).
609 // Only meaningful for "small" moduli (<=254 bits) which use the coarse representation.
610 // Not constexpr in debug builds (BB_ASSERT_DEBUG uses std::ostringstream).
611 // Callers must guard with `if (!std::is_constant_evaluated())` in constexpr functions.
612#ifdef NDEBUG
613 constexpr void assert_coarse_form() const noexcept {}
614#else
615 void assert_coarse_form() const noexcept
616 {
617 if constexpr (modulus.data[3] < MODULUS_TOP_LIMB_LARGE_THRESHOLD) {
618 uint256_t val{ data[0], data[1], data[2], data[3] };
619 BB_ASSERT_DEBUG(val < twice_modulus, "field element exceeds coarse form [0, 2p)");
620 }
621 }
622#endif
623 BB_INLINE constexpr field montgomery_mul(const field& other) const noexcept;
624 BB_INLINE constexpr field montgomery_mul_big(const field& other) const noexcept;
625 BB_INLINE constexpr field montgomery_square() const noexcept;
626
627#if (BBERG_NO_ASM == 0)
628 BB_INLINE static field asm_mul_with_coarse_reduction(const field& a, const field& b) noexcept;
629 BB_INLINE static field asm_sqr_with_coarse_reduction(const field& a) noexcept;
630 BB_INLINE static field asm_add_with_coarse_reduction(const field& a, const field& b) noexcept;
631 BB_INLINE static field asm_sub_with_coarse_reduction(const field& a, const field& b) noexcept;
632 BB_INLINE static void asm_self_mul_with_coarse_reduction(field& a, const field& b) noexcept;
633 BB_INLINE static void asm_self_sqr_with_coarse_reduction(field& a) noexcept;
634 BB_INLINE static void asm_self_add_with_coarse_reduction(field& a, const field& b) noexcept;
635 BB_INLINE static void asm_self_sub_with_coarse_reduction(field& a, const field& b) noexcept;
636
637 BB_INLINE static void asm_conditional_negate(field& r, uint64_t predicate) noexcept;
638 BB_INLINE static field asm_reduce_once(const field& a) noexcept;
639 BB_INLINE static void asm_self_reduce_once(field& a) noexcept;
640 static constexpr uint64_t zero_reference = 0x00ULL;
641#endif
642 constexpr field tonelli_shanks_sqrt() const noexcept;
643 static constexpr size_t primitive_root_log_size() noexcept;
644
645#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
646 static constexpr uint128_t lo_mask = 0xffffffffffffffffUL;
647#endif
648};
649
650template <typename B, typename Params> void read(B& it, field<Params>& value)
651{
652 using serialize::read;
653 field<Params> result{ 0, 0, 0, 0 };
654 read(it, result.data[3]);
655 read(it, result.data[2]);
656 read(it, result.data[1]);
657 read(it, result.data[0]);
658 value = result.to_montgomery_form();
659}
660template <typename B, typename Params> void write(B& buf, field<Params> const& value)
661{
662 using serialize::write;
664 write(buf, input.data[3]);
665 write(buf, input.data[2]);
666 write(buf, input.data[1]);
667 write(buf, input.data[0]);
668}
669
670} // namespace bb
671
672// Define hash function for field elements, e.g., so that it can be used in maps.
673// See https://en.cppreference.com/w/cpp/utility/hash .
674template <typename Params> struct std::hash<bb::field<Params>> {
675 std::size_t operator()(const bb::field<Params>& ff) const noexcept
676 {
677 // Just like in equality, we need to reduce the field element before hashing.
678 auto reduced = ff.reduce_once();
679 return bb::utils::hash_as_tuple(reduced.data[0], reduced.data[1], reduced.data[2], reduced.data[3]);
680 }
681};
#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()
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