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: Planned, 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 BB_INLINE constexpr wide_array sqr_512() const noexcept;
395
396 BB_INLINE constexpr field conditionally_subtract_from_double_modulus(const uint64_t predicate) const noexcept
397 {
398 if (predicate != 0) {
399 constexpr field p{
401 };
402 return p - *this;
403 }
404 return *this;
405 }
406
444 {
445 // force into strict form.
446 field input = k.reduce_once();
447
448 constexpr field endo_g1 = { Params::endo_g1_lo, Params::endo_g1_mid, Params::endo_g1_hi, 0 };
449 constexpr field endo_g2 = { Params::endo_g2_lo, Params::endo_g2_mid, 0, 0 };
450 constexpr field endo_minus_b1 = { Params::endo_minus_b1_lo, Params::endo_minus_b1_mid, 0, 0 };
451 constexpr field endo_b2 = { Params::endo_b2_lo, Params::endo_b2_mid, 0, 0 };
452
453 // c1 = (g2 * k) >> 256, c2 = (g1 * k) >> 256
454 wide_array c1 = endo_g2.mul_512(input);
455 wide_array c2 = endo_g1.mul_512(input);
456
457 // extract high halves
458 field c1_hi{ c1.data[4], c1.data[5], c1.data[6], c1.data[7] };
459 field c2_hi{ c2.data[4], c2.data[5], c2.data[6], c2.data[7] };
460
461 // q1 = c1 * (-b1), q2 = c2 * b2
462 wide_array q1 = c1_hi.mul_512(endo_minus_b1);
463 wide_array q2 = c2_hi.mul_512(endo_b2);
464
465 field q1_lo{ q1.data[0], q1.data[1], q1.data[2], q1.data[3] };
466 field q2_lo{ q2.data[0], q2.data[1], q2.data[2], q2.data[3] };
467
468 return (q2_lo - q1_lo).reduce_once();
469 }
470
484 static void split_into_endomorphism_scalars(const field& k, field& k1, field& k2)
485 {
486 if constexpr (Params::modulus_3 < MODULUS_TOP_LIMB_LARGE_THRESHOLD) {
487 // BN254 base or scalar field: use path that corresponds to 128-bit outputs.
489 k1 = { ret.first[0], ret.first[1], 0, 0 };
490 k2 = { ret.second[0], ret.second[1], 0, 0 };
491 } else {
492 // Large modulus (secp256k1): full-width path.
494 k2 = t1;
495 k1 = ((t1 * cube_root_of_unity()) + k).reduce_once();
496 }
497 }
498
514 {
515 static_assert(Params::modulus_3 < MODULUS_TOP_LIMB_LARGE_THRESHOLD);
517
518 // k2 (= t1) can be slightly negative for ~2^{-64} of inputs.
519 // When negative, t1 = k2 + r is 254 bits (upper limbs nonzero).
520 // Fix: decrement c1 by 1, equivalent to adding |b1| to k2.
521 // This shifts k2 by +|b1| (~127 bits, now positive) and k1 by -a1 (~64 bits),
522 // keeping both within 128 bits. See endomorphism_scalars.py for more details.
523 if (t1.data[2] != 0 || t1.data[3] != 0) {
524 constexpr field endo_minus_b1 = { Params::endo_minus_b1_lo, Params::endo_minus_b1_mid, 0, 0 };
525 t1 = (t1 + endo_minus_b1).reduce_once();
526 }
527
528 field t2 = ((t1 * cube_root_of_unity()) + k).reduce_once();
529 return {
530 { t2.data[0], t2.data[1] },
531 { t1.data[0], t1.data[1] },
532 };
533 }
534
535 friend std::ostream& operator<<(std::ostream& os, const field& a)
536 {
538 std::ios_base::fmtflags f(os.flags());
539 os << std::hex << "0x" << std::setfill('0') << std::setw(16) << out.data[3] << std::setw(16) << out.data[2]
540 << std::setw(16) << out.data[1] << std::setw(16) << out.data[0];
541 os.flags(f);
542 return os;
543 }
544
545 BB_INLINE static void __copy(const field& a, field& r) noexcept { r = a; } // NOLINT
546 BB_INLINE static void __swap(field& src, field& dest) noexcept // NOLINT
547 {
548 field T = dest;
549 dest = src;
550 src = T;
551 }
552
553 static field random_element(numeric::RNG* engine = nullptr) noexcept;
554
555 // For serialization
556 void msgpack_pack(auto& packer) const;
557 void msgpack_unpack(auto o);
558 void msgpack_schema(auto& packer) const { packer.pack_alias(Params::schema_name, "bin32"); }
559
561 static constexpr uint256_t not_modulus = -modulus;
563
564 struct wnaf_table {
565 uint8_t windows[64]; // NOLINT
566
567 constexpr wnaf_table(const uint256_t& target)
568 : windows{
569 static_cast<uint8_t>(target.data[0] & 15), static_cast<uint8_t>((target.data[0] >> 4) & 15),
570 static_cast<uint8_t>((target.data[0] >> 8) & 15), static_cast<uint8_t>((target.data[0] >> 12) & 15),
571 static_cast<uint8_t>((target.data[0] >> 16) & 15), static_cast<uint8_t>((target.data[0] >> 20) & 15),
572 static_cast<uint8_t>((target.data[0] >> 24) & 15), static_cast<uint8_t>((target.data[0] >> 28) & 15),
573 static_cast<uint8_t>((target.data[0] >> 32) & 15), static_cast<uint8_t>((target.data[0] >> 36) & 15),
574 static_cast<uint8_t>((target.data[0] >> 40) & 15), static_cast<uint8_t>((target.data[0] >> 44) & 15),
575 static_cast<uint8_t>((target.data[0] >> 48) & 15), static_cast<uint8_t>((target.data[0] >> 52) & 15),
576 static_cast<uint8_t>((target.data[0] >> 56) & 15), static_cast<uint8_t>((target.data[0] >> 60) & 15),
577 static_cast<uint8_t>(target.data[1] & 15), static_cast<uint8_t>((target.data[1] >> 4) & 15),
578 static_cast<uint8_t>((target.data[1] >> 8) & 15), static_cast<uint8_t>((target.data[1] >> 12) & 15),
579 static_cast<uint8_t>((target.data[1] >> 16) & 15), static_cast<uint8_t>((target.data[1] >> 20) & 15),
580 static_cast<uint8_t>((target.data[1] >> 24) & 15), static_cast<uint8_t>((target.data[1] >> 28) & 15),
581 static_cast<uint8_t>((target.data[1] >> 32) & 15), static_cast<uint8_t>((target.data[1] >> 36) & 15),
582 static_cast<uint8_t>((target.data[1] >> 40) & 15), static_cast<uint8_t>((target.data[1] >> 44) & 15),
583 static_cast<uint8_t>((target.data[1] >> 48) & 15), static_cast<uint8_t>((target.data[1] >> 52) & 15),
584 static_cast<uint8_t>((target.data[1] >> 56) & 15), static_cast<uint8_t>((target.data[1] >> 60) & 15),
585 static_cast<uint8_t>(target.data[2] & 15), static_cast<uint8_t>((target.data[2] >> 4) & 15),
586 static_cast<uint8_t>((target.data[2] >> 8) & 15), static_cast<uint8_t>((target.data[2] >> 12) & 15),
587 static_cast<uint8_t>((target.data[2] >> 16) & 15), static_cast<uint8_t>((target.data[2] >> 20) & 15),
588 static_cast<uint8_t>((target.data[2] >> 24) & 15), static_cast<uint8_t>((target.data[2] >> 28) & 15),
589 static_cast<uint8_t>((target.data[2] >> 32) & 15), static_cast<uint8_t>((target.data[2] >> 36) & 15),
590 static_cast<uint8_t>((target.data[2] >> 40) & 15), static_cast<uint8_t>((target.data[2] >> 44) & 15),
591 static_cast<uint8_t>((target.data[2] >> 48) & 15), static_cast<uint8_t>((target.data[2] >> 52) & 15),
592 static_cast<uint8_t>((target.data[2] >> 56) & 15), static_cast<uint8_t>((target.data[2] >> 60) & 15),
593 static_cast<uint8_t>(target.data[3] & 15), static_cast<uint8_t>((target.data[3] >> 4) & 15),
594 static_cast<uint8_t>((target.data[3] >> 8) & 15), static_cast<uint8_t>((target.data[3] >> 12) & 15),
595 static_cast<uint8_t>((target.data[3] >> 16) & 15), static_cast<uint8_t>((target.data[3] >> 20) & 15),
596 static_cast<uint8_t>((target.data[3] >> 24) & 15), static_cast<uint8_t>((target.data[3] >> 28) & 15),
597 static_cast<uint8_t>((target.data[3] >> 32) & 15), static_cast<uint8_t>((target.data[3] >> 36) & 15),
598 static_cast<uint8_t>((target.data[3] >> 40) & 15), static_cast<uint8_t>((target.data[3] >> 44) & 15),
599 static_cast<uint8_t>((target.data[3] >> 48) & 15), static_cast<uint8_t>((target.data[3] >> 52) & 15),
600 static_cast<uint8_t>((target.data[3] >> 56) & 15), static_cast<uint8_t>((target.data[3] >> 60) & 15)
601 }
602 {}
603 };
604
605#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
606 BB_INLINE static constexpr void wasm_madd(uint64_t& left_limb,
607 const std::array<uint64_t, WASM_NUM_LIMBS>& right_limbs,
608 uint64_t& result_0,
609 uint64_t& result_1,
610 uint64_t& result_2,
611 uint64_t& result_3,
612 uint64_t& result_4,
613 uint64_t& result_5,
614 uint64_t& result_6,
615 uint64_t& result_7,
616 uint64_t& result_8);
617 BB_INLINE static constexpr void wasm_reduce(uint64_t& result_0,
618 uint64_t& result_1,
619 uint64_t& result_2,
620 uint64_t& result_3,
621 uint64_t& result_4,
622 uint64_t& result_5,
623 uint64_t& result_6,
624 uint64_t& result_7,
625 uint64_t& result_8);
626 BB_INLINE static constexpr void wasm_reduce_yuval(uint64_t& result_0,
627 uint64_t& result_1,
628 uint64_t& result_2,
629 uint64_t& result_3,
630 uint64_t& result_4,
631 uint64_t& result_5,
632 uint64_t& result_6,
633 uint64_t& result_7,
634 uint64_t& result_8,
635 uint64_t& result_9);
636 BB_INLINE static constexpr std::array<uint64_t, WASM_NUM_LIMBS> wasm_convert(const uint64_t* data);
637#endif
638 BB_INLINE static constexpr std::pair<uint64_t, uint64_t> mul_wide(uint64_t a, uint64_t b) noexcept;
639
640 BB_INLINE static constexpr uint64_t mac(
641 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& carry_out) noexcept;
642
643 BB_INLINE static constexpr void mac(
644 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& out, uint64_t& carry_out) noexcept;
645
646 BB_INLINE static constexpr uint64_t mac_mini(uint64_t a, uint64_t b, uint64_t c, uint64_t& out) noexcept;
647
648 BB_INLINE static constexpr void mac_mini(
649 uint64_t a, uint64_t b, uint64_t c, uint64_t& out, uint64_t& carry_out) noexcept;
650
651 BB_INLINE static constexpr uint64_t mac_discard_lo(uint64_t a, uint64_t b, uint64_t c) noexcept;
652
653 BB_INLINE static constexpr uint64_t addc(uint64_t a, uint64_t b, uint64_t carry_in, uint64_t& carry_out) noexcept;
654
655 BB_INLINE static constexpr uint64_t sbb(uint64_t a, uint64_t b, uint64_t borrow_in, uint64_t& borrow_out) noexcept;
656
657 BB_INLINE static constexpr uint64_t square_accumulate(uint64_t a,
658 uint64_t b,
659 uint64_t c,
660 uint64_t carry_in_lo,
661 uint64_t carry_in_hi,
662 uint64_t& carry_lo,
663 uint64_t& carry_hi) noexcept;
664 BB_INLINE constexpr field reduce() const noexcept;
665 BB_INLINE constexpr field add(const field& other) const noexcept;
666 BB_INLINE constexpr field subtract(const field& other) const noexcept;
667 BB_INLINE constexpr field montgomery_mul(const field& other) const noexcept;
668 BB_INLINE constexpr field montgomery_mul_big(const field& other) const noexcept;
669 BB_INLINE constexpr field montgomery_square() const noexcept;
670
671#if (BBERG_NO_ASM == 0)
672 BB_INLINE static field asm_mul_with_coarse_reduction(const field& a, const field& b) noexcept;
673 BB_INLINE static field asm_sqr_with_coarse_reduction(const field& a) noexcept;
674 BB_INLINE static field asm_add_with_coarse_reduction(const field& a, const field& b) noexcept;
675 BB_INLINE static field asm_sub_with_coarse_reduction(const field& a, const field& b) noexcept;
676 BB_INLINE static void asm_self_mul_with_coarse_reduction(const field& a, const field& b) noexcept;
677 BB_INLINE static void asm_self_sqr_with_coarse_reduction(const field& a) noexcept;
678 BB_INLINE static void asm_self_add_with_coarse_reduction(const field& a, const field& b) noexcept;
679 BB_INLINE static void asm_self_sub_with_coarse_reduction(const field& a, const field& b) noexcept;
680
681 BB_INLINE static void asm_conditional_negate(field& r, uint64_t predicate) noexcept;
682 BB_INLINE static field asm_reduce_once(const field& a) noexcept;
683 BB_INLINE static void asm_self_reduce_once(const field& a) noexcept;
684 static constexpr uint64_t zero_reference = 0x00ULL;
685#endif
686 constexpr field tonelli_shanks_sqrt() const noexcept;
687 static constexpr size_t primitive_root_log_size() noexcept;
688
689#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
690 static constexpr uint128_t lo_mask = 0xffffffffffffffffUL;
691#endif
692};
693
694template <typename B, typename Params> void read(B& it, field<Params>& value)
695{
696 using serialize::read;
697 field<Params> result{ 0, 0, 0, 0 };
698 read(it, result.data[3]);
699 read(it, result.data[2]);
700 read(it, result.data[1]);
701 read(it, result.data[0]);
702 value = result.to_montgomery_form();
703}
704template <typename B, typename Params> void write(B& buf, field<Params> const& value)
705{
706 using serialize::write;
708 write(buf, input.data[3]);
709 write(buf, input.data[2]);
710 write(buf, input.data[1]);
711 write(buf, input.data[0]);
712}
713
714} // namespace bb
715
716// Define hash function for field elements, e.g., so that it can be used in maps.
717// See https://en.cppreference.com/w/cpp/utility/hash .
718template <typename Params> struct std::hash<bb::field<Params>> {
719 std::size_t operator()(const bb::field<Params>& ff) const noexcept
720 {
721 // Just like in equality, we need to reduce the field element before hashing.
722 auto reduced = ff.reduce_once();
723 return bb::utils::hash_as_tuple(reduced.data[0], reduced.data[1], reduced.data[2], reduced.data[3]);
724 }
725};
#define BB_INLINE
FF a
FF b
uint8_t const * buf
Definition data_store.hpp:9
numeric::RNG & engine
std::unique_ptr< uint8_t[]> buffer
Definition engine.cpp:50
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 MSGPACK_FIEL...
void write(auto &buf, const msgpack_concepts::HasMsgPack auto &obj)
Automatically derived write for any object that defines .msgpack() (implicitly defined by MSGPACK_FIE...
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
unsigned __int128 uint128_t
Definition serialize.hpp:45
constexpr wnaf_table(const uint256_t &target)
General class for prime fields see Prime field documentation["field documentation"] for general imple...
static constexpr field cube_root_of_unity()
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....
static BB_INLINE void __swap(field &src, field &dest) noexcept
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
BB_INLINE constexpr field conditionally_subtract_from_double_modulus(const uint64_t predicate) 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
BB_INLINE constexpr wide_array sqr_512() const 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