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: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
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 {
36template <class Params_> struct alignas(32) field {
37 public:
38 using View = field;
40 using Params = Params_;
41 using in_buf = const uint8_t*;
42 using vec_in_buf = const uint8_t*;
43 using out_buf = uint8_t*;
44 using vec_out_buf = uint8_t**;
45
46 // The number of element required to represent field<Params_> in the public inputs of a circuit
47 static constexpr size_t PUBLIC_INPUTS_SIZE = Params::PUBLIC_INPUTS_SIZE;
48
49#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
50#define WASM_NUM_LIMBS 9
51#define WASM_LIMB_BITS 29
52#endif
53
54 // We don't initialize data in the default constructor since we'd lose a lot of time on huge array initializations.
55 // Other alternatives have been noted, such as casting to get around constructors where they matter,
56 // however it is felt that sanitizer tools (e.g. MSAN) can detect garbage well, whereas doing
57 // hacky casts where needed would require rework to critical algos like MSM, FFT, Sumcheck.
58 // Instead, the recommended solution is use an explicit {} where initialization is important:
59 // field f; // not initialized
60 // field f{}; // zero-initialized
61 // std::array<field, N> arr; // not initialized, good for huge N
62 // std::array<field, N> arr {}; // zero-initialized, preferable for moderate N
63 field() = default;
64
65 constexpr field(const numeric::uint256_t& input) noexcept
66 : data{ input.data[0], input.data[1], input.data[2], input.data[3] }
67 {
69 }
70
71 constexpr field(const uint128_t& input) noexcept
73 {}
74
75 // NOLINTNEXTLINE (unsigned long is platform dependent, which we want in this case)
76 constexpr field(const unsigned long input) noexcept
77 : data{ input, 0, 0, 0 }
78 {
80 }
81
82 constexpr field(const unsigned int input) noexcept
83 : data{ input, 0, 0, 0 }
84 {
86 }
87
88 // NOLINTNEXTLINE (unsigned long long is platform dependent, which we want in this case)
89 constexpr field(const unsigned long long input) noexcept
90 : data{ input, 0, 0, 0 }
91 {
93 }
94
95 constexpr field(const int input) noexcept
96 : data{ 0, 0, 0, 0 }
97 {
98 if (input < 0) {
99 data[0] = static_cast<uint64_t>(-input);
100 data[1] = 0;
101 data[2] = 0;
102 data[3] = 0;
104 self_neg();
106 } else {
107 data[0] = static_cast<uint64_t>(input);
108 data[1] = 0;
109 data[2] = 0;
110 data[3] = 0;
112 }
113 }
114
115 constexpr field(const uint64_t a, const uint64_t b, const uint64_t c, const uint64_t d) noexcept
116 : data{ a, b, c, d } {};
117
124 constexpr explicit field(const uint512_t& input) noexcept
125 {
126 uint256_t value = (input % modulus).lo;
127 data[0] = value.data[0];
128 data[1] = value.data[1];
129 data[2] = value.data[2];
130 data[3] = value.data[3];
132 }
133
134 constexpr explicit field(std::string input) noexcept
135 {
136 uint256_t value(input);
137 *this = field(value);
138 }
139
140 constexpr explicit operator bool() const
141 {
143 ASSERT_IN_CONSTEXPR(out.data[0] == 0 || out.data[0] == 1);
144 return static_cast<bool>(out.data[0]);
145 }
146
147 constexpr explicit operator uint8_t() const
148 {
150 return static_cast<uint8_t>(out.data[0]);
151 }
152
153 constexpr explicit operator uint16_t() const
154 {
156 return static_cast<uint16_t>(out.data[0]);
157 }
158
159 constexpr explicit operator uint32_t() const
160 {
162 return static_cast<uint32_t>(out.data[0]);
163 }
164
165 constexpr explicit operator uint64_t() const
166 {
168 return out.data[0];
169 }
170
171 constexpr explicit operator uint128_t() const
172 {
174 uint128_t lo = out.data[0];
175 uint128_t hi = out.data[1];
176 return (hi << 64) | lo;
177 }
178
179 constexpr operator uint256_t() const noexcept
180 {
182 return uint256_t(out.data[0], out.data[1], out.data[2], out.data[3]);
183 }
184
185 [[nodiscard]] constexpr uint256_t uint256_t_no_montgomery_conversion() const noexcept
186 {
187 return { data[0], data[1], data[2], data[3] };
188 }
189
190 constexpr field(const field& other) noexcept = default;
191 constexpr field(field&& other) noexcept = default;
192 constexpr field& operator=(const field& other) & noexcept = default;
193 constexpr field& operator=(field&& other) & noexcept = default;
194 constexpr ~field() noexcept = default;
195 alignas(32) uint64_t data[4]; // NOLINT
196
197 static constexpr uint256_t modulus =
198 uint256_t{ Params::modulus_0, Params::modulus_1, Params::modulus_2, Params::modulus_3 };
199#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
200 static constexpr uint256_t r_squared_uint{
201 Params_::r_squared_0, Params_::r_squared_1, Params_::r_squared_2, Params_::r_squared_3
202 };
203#else
204 static constexpr uint256_t r_squared_uint{
205 Params_::r_squared_wasm_0, Params_::r_squared_wasm_1, Params_::r_squared_wasm_2, Params_::r_squared_wasm_3
206 };
207 static constexpr std::array<uint64_t, 9> wasm_modulus = { Params::modulus_wasm_0, Params::modulus_wasm_1,
208 Params::modulus_wasm_2, Params::modulus_wasm_3,
209 Params::modulus_wasm_4, Params::modulus_wasm_5,
210 Params::modulus_wasm_6, Params::modulus_wasm_7,
211 Params::modulus_wasm_8 };
212 static constexpr std::array<uint64_t, 9> wasm_r_inv = {
213 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,
214 Params::r_inv_wasm_5, Params::r_inv_wasm_6, Params::r_inv_wasm_7, Params::r_inv_wasm_8
215 };
216
217#endif
218 static constexpr field cube_root_of_unity()
219 {
220 // endomorphism i.e. lambda * [P] = (beta * x, y)
221 if constexpr (Params::cube_root_0 != 0) {
222#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
223 constexpr field result{
224 Params::cube_root_0, Params::cube_root_1, Params::cube_root_2, Params::cube_root_3
225 };
226#else
227 constexpr field result{
228 Params::cube_root_wasm_0, Params::cube_root_wasm_1, Params::cube_root_wasm_2, Params::cube_root_wasm_3
229 };
230#endif
231 return result;
232 } else {
233 constexpr field two_inv = field(2).invert();
234 constexpr field numerator = (-field(3)).sqrt() - field(1);
235 constexpr field result = two_inv * numerator;
236 return result;
237 }
238 }
239
240 static constexpr field zero() { return field(0, 0, 0, 0); }
241 static constexpr field neg_one() { return -field(1); }
242 static constexpr field one() { return field(1); }
243
245 {
246#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
247 const field result{
248 Params::coset_generators_0[7],
249 Params::coset_generators_1[7],
250 Params::coset_generators_2[7],
251 Params::coset_generators_3[7],
252 };
253#else
254 const field result{
255 Params::coset_generators_wasm_0[7],
256 Params::coset_generators_wasm_1[7],
257 Params::coset_generators_wasm_2[7],
258 Params::coset_generators_wasm_3[7],
259 };
260#endif
261
262 return result;
263 }
264
265 static constexpr field tag_coset_generator()
266 {
267#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
268 const field result{
269 Params::coset_generators_0[6],
270 Params::coset_generators_1[6],
271 Params::coset_generators_2[6],
272 Params::coset_generators_3[6],
273 };
274#else
275 const field result{
276 Params::coset_generators_wasm_0[6],
277 Params::coset_generators_wasm_1[6],
278 Params::coset_generators_wasm_2[6],
279 Params::coset_generators_wasm_3[6],
280 };
281#endif
282
283 return result;
284 }
285
286 template <size_t idx> static constexpr field coset_generator()
287 {
288 static_assert(idx < 7);
289#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
290 const field result{
291 Params::coset_generators_0[idx],
292 Params::coset_generators_1[idx],
293 Params::coset_generators_2[idx],
294 Params::coset_generators_3[idx],
295 };
296#else
297 const field result{
298 Params::coset_generators_wasm_0[idx],
299 Params::coset_generators_wasm_1[idx],
300 Params::coset_generators_wasm_2[idx],
301 Params::coset_generators_wasm_3[idx],
302 };
303#endif
304
305 return result;
306 }
307
308 BB_INLINE constexpr field operator*(const field& other) const noexcept;
309 BB_INLINE constexpr field operator+(const field& other) const noexcept;
310 BB_INLINE constexpr field operator-(const field& other) const noexcept;
311 BB_INLINE constexpr field operator-() const noexcept;
312 constexpr field operator/(const field& other) const noexcept;
313
314 // prefix increment (++x)
315 BB_INLINE constexpr field operator++() noexcept;
316 // postfix increment (x++)
317 // NOLINTNEXTLINE
318 BB_INLINE constexpr field operator++(int) noexcept;
319
320 BB_INLINE constexpr field& operator*=(const field& other) & noexcept;
321 BB_INLINE constexpr field& operator+=(const field& other) & noexcept;
322 BB_INLINE constexpr field& operator-=(const field& other) & noexcept;
323 constexpr field& operator/=(const field& other) & noexcept;
324
325 // NOTE: comparison operators exist so that `field` is comparible with stl methods that require them.
326 // (e.g. std::sort)
327 // Finite fields do not have an explicit ordering, these should *NEVER* be used in algebraic algorithms.
328 BB_INLINE constexpr bool operator>(const field& other) const noexcept;
329 BB_INLINE constexpr bool operator<(const field& other) const noexcept;
330 BB_INLINE constexpr bool operator==(const field& other) const noexcept;
331 BB_INLINE constexpr bool operator!=(const field& other) const noexcept;
332
333 BB_INLINE constexpr field to_montgomery_form() const noexcept;
334 BB_INLINE constexpr field from_montgomery_form() const noexcept;
335
336 BB_INLINE constexpr field sqr() const noexcept;
337 BB_INLINE constexpr void self_sqr() & noexcept;
338
339 BB_INLINE constexpr field pow(const uint256_t& exponent) const noexcept;
340 BB_INLINE constexpr field pow(uint64_t exponent) const noexcept;
341 // STARKNET: next line was commented as stark252 violates the assertion
342 // static_assert(Params::modulus_0 != 1);
343 static constexpr uint256_t modulus_minus_two =
344 uint256_t(Params::modulus_0 - 2ULL, Params::modulus_1, Params::modulus_2, Params::modulus_3);
345 constexpr field invert() const noexcept;
346 static void batch_invert(std::span<field> coeffs) noexcept;
347 static void batch_invert(field* coeffs, size_t n) noexcept;
353 constexpr std::pair<bool, field> sqrt() const noexcept
354 requires((Params_::modulus_0 & 0x3UL) == 0x3UL);
355 constexpr std::pair<bool, field> sqrt() const noexcept
356 requires((Params_::modulus_0 & 0x3UL) != 0x3UL);
357 BB_INLINE constexpr void self_neg() & noexcept;
358
359 BB_INLINE constexpr void self_to_montgomery_form() & noexcept;
360 BB_INLINE constexpr void self_from_montgomery_form() & noexcept;
361
362 BB_INLINE constexpr void self_conditional_negate(uint64_t predicate) & noexcept;
363
364 BB_INLINE constexpr field reduce_once() const noexcept;
365 BB_INLINE constexpr void self_reduce_once() & noexcept;
366
367 BB_INLINE constexpr void self_set_msb() & noexcept;
368 [[nodiscard]] BB_INLINE constexpr bool is_msb_set() const noexcept;
369 [[nodiscard]] BB_INLINE constexpr uint64_t is_msb_set_word() const noexcept;
370
371 [[nodiscard]] BB_INLINE constexpr bool is_zero() const noexcept;
372
373 static constexpr field get_root_of_unity(size_t subgroup_size) noexcept;
374
375 static void serialize_to_buffer(const field& value, uint8_t* buffer) { write(buffer, value); }
376
377 static field serialize_from_buffer(const uint8_t* buffer) { return from_buffer<field>(buffer); }
378
379 template <class V> static field reconstruct_from_public(const std::span<const field<V>, PUBLIC_INPUTS_SIZE>& limbs);
380
381 [[nodiscard]] BB_INLINE std::vector<uint8_t> to_buffer() const { return ::to_buffer(*this); }
382
383 struct wide_array {
384 uint64_t data[8]; // NOLINT
385 };
386 BB_INLINE constexpr wide_array mul_512(const field& other) const noexcept;
387 BB_INLINE constexpr wide_array sqr_512() const noexcept;
388
389 BB_INLINE constexpr field conditionally_subtract_from_double_modulus(const uint64_t predicate) const noexcept
390 {
391 if (predicate != 0) {
392 constexpr field p{
394 };
395 return p - *this;
396 }
397 return *this;
398 }
399
424 static void split_into_endomorphism_scalars(const field& k, field& k1, field& k2)
425 {
426 // if the modulus is a >= 255-bit integer, we need to use a basis where g1, g2 have been shifted by 2^384
427 if constexpr (Params::modulus_3 >= 0x4000000000000000ULL) {
429 } else {
431 k1.data[0] = ret.first[0];
432 k1.data[1] = ret.first[1];
433
434 // TODO(https://github.com/AztecProtocol/barretenberg/issues/851): We should move away from this hack by
435 // returning pair of uint64_t[2] instead of a half-set field
436#if !defined(__clang__) && defined(__GNUC__)
437#pragma GCC diagnostic push
438#pragma GCC diagnostic ignored "-Warray-bounds"
439#endif
440 k2.data[0] = ret.second[0]; // NOLINT
441 k2.data[1] = ret.second[1];
442#if !defined(__clang__) && defined(__GNUC__)
443#pragma GCC diagnostic pop
444#endif
445 }
446 }
447
448 // NOTE: this form is only usable if the modulus is 254 bits or less, otherwise see
449 // split_into_endomorphism_scalars_384.
450 // TODO(https://github.com/AztecProtocol/barretenberg/issues/851): Unify these APIs.
452 {
453 static_assert(Params::modulus_3 < 0x4000000000000000ULL);
454 field input = k.reduce_once();
455
456 constexpr field endo_g1 = { Params::endo_g1_lo, Params::endo_g1_mid, Params::endo_g1_hi, 0 };
457
458 constexpr field endo_g2 = { Params::endo_g2_lo, Params::endo_g2_mid, 0, 0 };
459
460 constexpr field endo_minus_b1 = { Params::endo_minus_b1_lo, Params::endo_minus_b1_mid, 0, 0 };
461
462 constexpr field endo_b2 = { Params::endo_b2_lo, Params::endo_b2_mid, 0, 0 };
463
464 // compute c1 = (g2 * k) >> 256
465 wide_array c1 = endo_g2.mul_512(input);
466 // compute c2 = (g1 * k) >> 256
467 wide_array c2 = endo_g1.mul_512(input);
468
469 // (the bit shifts are implicit, as we only utilize the high limbs of c1, c2
470
471 field c1_hi = {
472 c1.data[4], c1.data[5], c1.data[6], c1.data[7]
473 }; // *(field*)((uintptr_t)(&c1) + (4 * sizeof(uint64_t)));
474 field c2_hi = {
475 c2.data[4], c2.data[5], c2.data[6], c2.data[7]
476 }; // *(field*)((uintptr_t)(&c2) + (4 * sizeof(uint64_t)));
477
478 // compute q1 = c1 * -b1
479 wide_array q1 = c1_hi.mul_512(endo_minus_b1);
480 // compute q2 = c2 * b2
481 wide_array q2 = c2_hi.mul_512(endo_b2);
482
483 // FIX: Avoid using 512-bit multiplication as its not necessary.
484 // c1_hi, c2_hi can be uint256_t's and the final result (without montgomery reduction)
485 // could be casted to a field.
486 field q1_lo{ q1.data[0], q1.data[1], q1.data[2], q1.data[3] };
487 field q2_lo{ q2.data[0], q2.data[1], q2.data[2], q2.data[3] };
488
489 field t1 = (q2_lo - q1_lo).reduce_once();
490 field beta = cube_root_of_unity();
491 field t2 = (t1 * beta + input).reduce_once();
492 return {
493 { t2.data[0], t2.data[1] },
494 { t1.data[0], t1.data[1] },
495 };
496 }
497
498 static void split_into_endomorphism_scalars_384(const field& input, field& k1_out, field& k2_out)
499 {
500 constexpr field minus_b1f{
501 Params::endo_minus_b1_lo,
502 Params::endo_minus_b1_mid,
503 0,
504 0,
505 };
506 constexpr field b2f{
507 Params::endo_b2_lo,
508 Params::endo_b2_mid,
509 0,
510 0,
511 };
512 constexpr uint256_t g1{
513 Params::endo_g1_lo,
514 Params::endo_g1_mid,
515 Params::endo_g1_hi,
516 Params::endo_g1_hihi,
517 };
518 constexpr uint256_t g2{
519 Params::endo_g2_lo,
520 Params::endo_g2_mid,
521 Params::endo_g2_hi,
522 Params::endo_g2_hihi,
523 };
524
525 field kf = input.reduce_once();
526 uint256_t k{ kf.data[0], kf.data[1], kf.data[2], kf.data[3] };
527
528 uint512_t c1 = (uint512_t(k) * static_cast<uint512_t>(g1)) >> 384;
529 uint512_t c2 = (uint512_t(k) * static_cast<uint512_t>(g2)) >> 384;
530
531 field c1f{ c1.lo.data[0], c1.lo.data[1], c1.lo.data[2], c1.lo.data[3] };
532 field c2f{ c2.lo.data[0], c2.lo.data[1], c2.lo.data[2], c2.lo.data[3] };
533
534 c1f.self_to_montgomery_form();
535 c2f.self_to_montgomery_form();
536 c1f = c1f * minus_b1f;
537 c2f = c2f * b2f;
538 field r2f = c1f - c2f;
539 field beta = cube_root_of_unity();
540 field r1f = input.reduce_once() - r2f * beta;
541 k1_out = r1f;
542 k2_out = -r2f;
543 }
544
545 // static constexpr auto coset_generators = compute_coset_generators();
546 // static constexpr std::array<field, 15> coset_generators = compute_coset_generators((1 << 30U));
547
548 friend std::ostream& operator<<(std::ostream& os, const field& a)
549 {
551 std::ios_base::fmtflags f(os.flags());
552 os << std::hex << "0x" << std::setfill('0') << std::setw(16) << out.data[3] << std::setw(16) << out.data[2]
553 << std::setw(16) << out.data[1] << std::setw(16) << out.data[0];
554 os.flags(f);
555 return os;
556 }
557
558 BB_INLINE static void __copy(const field& a, field& r) noexcept { r = a; } // NOLINT
559 BB_INLINE static void __swap(field& src, field& dest) noexcept // NOLINT
560 {
561 field T = dest;
562 dest = src;
563 src = T;
564 }
565
566 static field random_element(numeric::RNG* engine = nullptr) noexcept;
567
568 static constexpr field multiplicative_generator() noexcept;
569
570 // For serialization
571 void msgpack_pack(auto& packer) const;
572 void msgpack_unpack(auto o);
573 void msgpack_schema(auto& packer) const { packer.pack_alias(Params::schema_name, "bin32"); }
574
576 static constexpr uint256_t not_modulus = -modulus;
578
579 struct wnaf_table {
580 uint8_t windows[64]; // NOLINT
581
582 constexpr wnaf_table(const uint256_t& target)
583 : windows{
584 static_cast<uint8_t>(target.data[0] & 15), static_cast<uint8_t>((target.data[0] >> 4) & 15),
585 static_cast<uint8_t>((target.data[0] >> 8) & 15), static_cast<uint8_t>((target.data[0] >> 12) & 15),
586 static_cast<uint8_t>((target.data[0] >> 16) & 15), static_cast<uint8_t>((target.data[0] >> 20) & 15),
587 static_cast<uint8_t>((target.data[0] >> 24) & 15), static_cast<uint8_t>((target.data[0] >> 28) & 15),
588 static_cast<uint8_t>((target.data[0] >> 32) & 15), static_cast<uint8_t>((target.data[0] >> 36) & 15),
589 static_cast<uint8_t>((target.data[0] >> 40) & 15), static_cast<uint8_t>((target.data[0] >> 44) & 15),
590 static_cast<uint8_t>((target.data[0] >> 48) & 15), static_cast<uint8_t>((target.data[0] >> 52) & 15),
591 static_cast<uint8_t>((target.data[0] >> 56) & 15), static_cast<uint8_t>((target.data[0] >> 60) & 15),
592 static_cast<uint8_t>(target.data[1] & 15), static_cast<uint8_t>((target.data[1] >> 4) & 15),
593 static_cast<uint8_t>((target.data[1] >> 8) & 15), static_cast<uint8_t>((target.data[1] >> 12) & 15),
594 static_cast<uint8_t>((target.data[1] >> 16) & 15), static_cast<uint8_t>((target.data[1] >> 20) & 15),
595 static_cast<uint8_t>((target.data[1] >> 24) & 15), static_cast<uint8_t>((target.data[1] >> 28) & 15),
596 static_cast<uint8_t>((target.data[1] >> 32) & 15), static_cast<uint8_t>((target.data[1] >> 36) & 15),
597 static_cast<uint8_t>((target.data[1] >> 40) & 15), static_cast<uint8_t>((target.data[1] >> 44) & 15),
598 static_cast<uint8_t>((target.data[1] >> 48) & 15), static_cast<uint8_t>((target.data[1] >> 52) & 15),
599 static_cast<uint8_t>((target.data[1] >> 56) & 15), static_cast<uint8_t>((target.data[1] >> 60) & 15),
600 static_cast<uint8_t>(target.data[2] & 15), static_cast<uint8_t>((target.data[2] >> 4) & 15),
601 static_cast<uint8_t>((target.data[2] >> 8) & 15), static_cast<uint8_t>((target.data[2] >> 12) & 15),
602 static_cast<uint8_t>((target.data[2] >> 16) & 15), static_cast<uint8_t>((target.data[2] >> 20) & 15),
603 static_cast<uint8_t>((target.data[2] >> 24) & 15), static_cast<uint8_t>((target.data[2] >> 28) & 15),
604 static_cast<uint8_t>((target.data[2] >> 32) & 15), static_cast<uint8_t>((target.data[2] >> 36) & 15),
605 static_cast<uint8_t>((target.data[2] >> 40) & 15), static_cast<uint8_t>((target.data[2] >> 44) & 15),
606 static_cast<uint8_t>((target.data[2] >> 48) & 15), static_cast<uint8_t>((target.data[2] >> 52) & 15),
607 static_cast<uint8_t>((target.data[2] >> 56) & 15), static_cast<uint8_t>((target.data[2] >> 60) & 15),
608 static_cast<uint8_t>(target.data[3] & 15), static_cast<uint8_t>((target.data[3] >> 4) & 15),
609 static_cast<uint8_t>((target.data[3] >> 8) & 15), static_cast<uint8_t>((target.data[3] >> 12) & 15),
610 static_cast<uint8_t>((target.data[3] >> 16) & 15), static_cast<uint8_t>((target.data[3] >> 20) & 15),
611 static_cast<uint8_t>((target.data[3] >> 24) & 15), static_cast<uint8_t>((target.data[3] >> 28) & 15),
612 static_cast<uint8_t>((target.data[3] >> 32) & 15), static_cast<uint8_t>((target.data[3] >> 36) & 15),
613 static_cast<uint8_t>((target.data[3] >> 40) & 15), static_cast<uint8_t>((target.data[3] >> 44) & 15),
614 static_cast<uint8_t>((target.data[3] >> 48) & 15), static_cast<uint8_t>((target.data[3] >> 52) & 15),
615 static_cast<uint8_t>((target.data[3] >> 56) & 15), static_cast<uint8_t>((target.data[3] >> 60) & 15)
616 }
617 {}
618 };
619
620#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
621 BB_INLINE static constexpr void wasm_madd(uint64_t& left_limb,
622 const std::array<uint64_t, WASM_NUM_LIMBS>& right_limbs,
623 uint64_t& result_0,
624 uint64_t& result_1,
625 uint64_t& result_2,
626 uint64_t& result_3,
627 uint64_t& result_4,
628 uint64_t& result_5,
629 uint64_t& result_6,
630 uint64_t& result_7,
631 uint64_t& result_8);
632 BB_INLINE static constexpr void wasm_reduce(uint64_t& result_0,
633 uint64_t& result_1,
634 uint64_t& result_2,
635 uint64_t& result_3,
636 uint64_t& result_4,
637 uint64_t& result_5,
638 uint64_t& result_6,
639 uint64_t& result_7,
640 uint64_t& result_8);
641 BB_INLINE static constexpr void wasm_reduce_yuval(uint64_t& result_0,
642 uint64_t& result_1,
643 uint64_t& result_2,
644 uint64_t& result_3,
645 uint64_t& result_4,
646 uint64_t& result_5,
647 uint64_t& result_6,
648 uint64_t& result_7,
649 uint64_t& result_8,
650 uint64_t& result_9);
651 BB_INLINE static constexpr std::array<uint64_t, WASM_NUM_LIMBS> wasm_convert(const uint64_t* data);
652#endif
653 BB_INLINE static constexpr std::pair<uint64_t, uint64_t> mul_wide(uint64_t a, uint64_t b) noexcept;
654
655 BB_INLINE static constexpr uint64_t mac(
656 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& carry_out) noexcept;
657
658 BB_INLINE static constexpr void mac(
659 uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& out, uint64_t& carry_out) noexcept;
660
661 BB_INLINE static constexpr uint64_t mac_mini(uint64_t a, uint64_t b, uint64_t c, uint64_t& out) noexcept;
662
663 BB_INLINE static constexpr void mac_mini(
664 uint64_t a, uint64_t b, uint64_t c, uint64_t& out, uint64_t& carry_out) noexcept;
665
666 BB_INLINE static constexpr uint64_t mac_discard_lo(uint64_t a, uint64_t b, uint64_t c) noexcept;
667
668 BB_INLINE static constexpr uint64_t addc(uint64_t a, uint64_t b, uint64_t carry_in, uint64_t& carry_out) noexcept;
669
670 BB_INLINE static constexpr uint64_t sbb(uint64_t a, uint64_t b, uint64_t borrow_in, uint64_t& borrow_out) noexcept;
671
672 BB_INLINE static constexpr uint64_t square_accumulate(uint64_t a,
673 uint64_t b,
674 uint64_t c,
675 uint64_t carry_in_lo,
676 uint64_t carry_in_hi,
677 uint64_t& carry_lo,
678 uint64_t& carry_hi) noexcept;
679 BB_INLINE constexpr field reduce() const noexcept;
680 BB_INLINE constexpr field add(const field& other) const noexcept;
681 BB_INLINE constexpr field subtract(const field& other) const noexcept;
682 BB_INLINE constexpr field subtract_coarse(const field& other) const noexcept;
683 BB_INLINE constexpr field montgomery_mul(const field& other) const noexcept;
684 BB_INLINE constexpr field montgomery_mul_big(const field& other) const noexcept;
685 BB_INLINE constexpr field montgomery_square() const noexcept;
686
687#if (BBERG_NO_ASM == 0)
688 BB_INLINE static field asm_mul(const field& a, const field& b) noexcept;
689 BB_INLINE static field asm_sqr(const field& a) noexcept;
690 BB_INLINE static field asm_add(const field& a, const field& b) noexcept;
691 BB_INLINE static field asm_sub(const field& a, const field& b) noexcept;
692 BB_INLINE static field asm_mul_with_coarse_reduction(const field& a, const field& b) noexcept;
693 BB_INLINE static field asm_sqr_with_coarse_reduction(const field& a) noexcept;
694 BB_INLINE static field asm_add_with_coarse_reduction(const field& a, const field& b) noexcept;
695 BB_INLINE static field asm_sub_with_coarse_reduction(const field& a, const field& b) noexcept;
696 BB_INLINE static field asm_add_without_reduction(const field& a, const field& b) noexcept;
697 BB_INLINE static void asm_self_sqr(const field& a) noexcept;
698 BB_INLINE static void asm_self_add(const field& a, const field& b) noexcept;
699 BB_INLINE static void asm_self_sub(const field& a, const field& b) noexcept;
700 BB_INLINE static void asm_self_mul_with_coarse_reduction(const field& a, const field& b) noexcept;
701 BB_INLINE static void asm_self_sqr_with_coarse_reduction(const field& a) noexcept;
702 BB_INLINE static void asm_self_add_with_coarse_reduction(const field& a, const field& b) noexcept;
703 BB_INLINE static void asm_self_sub_with_coarse_reduction(const field& a, const field& b) noexcept;
704 BB_INLINE static void asm_self_add_without_reduction(const field& a, const field& b) noexcept;
705
706 BB_INLINE static void asm_conditional_negate(field& r, uint64_t predicate) noexcept;
707 BB_INLINE static field asm_reduce_once(const field& a) noexcept;
708 BB_INLINE static void asm_self_reduce_once(const field& a) noexcept;
709 static constexpr uint64_t zero_reference = 0x00ULL;
710#endif
711 static constexpr size_t COSET_GENERATOR_SIZE = 15;
712 constexpr field tonelli_shanks_sqrt() const noexcept;
713 static constexpr size_t primitive_root_log_size() noexcept;
714 static constexpr std::array<field, COSET_GENERATOR_SIZE> compute_coset_generators() noexcept;
715
716#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
717 static constexpr uint128_t lo_mask = 0xffffffffffffffffUL;
718#endif
719};
720
721template <typename B, typename Params> void read(B& it, field<Params>& value)
722{
723 using serialize::read;
724 field<Params> result{ 0, 0, 0, 0 };
725 read(it, result.data[3]);
726 read(it, result.data[2]);
727 read(it, result.data[1]);
728 read(it, result.data[0]);
729 value = result.to_montgomery_form();
730}
731template <typename B, typename Params> void write(B& buf, field<Params> const& value)
732{
733 using serialize::write;
734 const field input = value.from_montgomery_form();
735 write(buf, input.data[3]);
736 write(buf, input.data[2]);
737 write(buf, input.data[1]);
738 write(buf, input.data[0]);
739}
740
741} // namespace bb
742
743// Define hash function for field elements, e.g., so that it can be used in maps.
744// See https://en.cppreference.com/w/cpp/utility/hash .
745template <typename Params> struct std::hash<bb::field<Params>> {
746 std::size_t operator()(const bb::field<Params>& ff) const noexcept
747 {
748 // Just like in equality, we need to reduce the field element before hashing.
749 auto reduced = ff.reduce_once();
750 return bb::utils::hash_as_tuple(reduced.data[0], reduced.data[1], reduced.data[2], reduced.data[3]);
751 }
752};
#define ASSERT_IN_CONSTEXPR(expression,...)
Definition assert.hpp:40
group class. Represents an elliptic curve group element. Group is parametrised by Fq and Fr
Definition group.hpp:36
static constexpr uint256_t from_uint128(const uint128_t a) noexcept
Definition uint256.hpp:94
#define BB_INLINE
FF a
FF b
uint8_t const * buf
Definition data_store.hpp:9
numeric::RNG & engine
uint8_t buffer[RANDOM_BUFFER_SIZE]
Definition engine.cpp:34
uintx< uint256_t > uint512_t
Definition uintx.hpp:307
size_t hash_as_tuple(const Ts &... ts)
Definition utils.hpp:22
Entry point for Barretenberg command-line interface.
group< fq2, fr, Bn254G2Params > g2
Definition g2.hpp:39
group< fq, fr, Bn254G1Params > g1
Definition g1.hpp:33
void read(B &it, field2< base_field, Params > &value)
void write(B &buf, field2< base_field, Params > const &value)
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:44
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
static constexpr std::array< uint64_t, 9 > wasm_modulus
static constexpr field get_root_of_unity(size_t subgroup_size) 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 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
BB_INLINE constexpr field subtract(const field &other) const noexcept
static constexpr field external_coset_generator()
static void split_into_endomorphism_scalars_384(const field &input, field &k1_out, field &k2_out)
BB_INLINE constexpr void self_conditional_negate(uint64_t predicate) &noexcept
void msgpack_schema(auto &packer) const
static constexpr field tag_coset_generator()
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
static void split_into_endomorphism_scalars(const field &k, field &k1, field &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
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 this)
static constexpr std::array< field, COSET_GENERATOR_SIZE > compute_coset_generators() noexcept
BB_INLINE constexpr field montgomery_mul_big(const field &other) const noexcept
Mongtomery multiplication for moduli > 2²⁵⁴
static constexpr size_t COSET_GENERATOR_SIZE
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
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 put 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
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 constexpr field coset_generator()
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
BB_INLINE constexpr field subtract_coarse(const field &other) const noexcept
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
static constexpr field multiplicative_generator() noexcept
BB_INLINE constexpr bool is_zero() const noexcept
static constexpr uint256_t not_modulus
static void batch_invert(std::span< field > coeffs) noexcept
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 reconstruct_from_public(const std::span< const field< V >, PUBLIC_INPUTS_SIZE > &limbs)
BB_INLINE constexpr field montgomery_square() const noexcept
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)
BB_INLINE constexpr field reduce() const noexcept
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