1use alloc::vec;
2use alloc::vec::Vec;
3use core::fmt::{Debug, Display, Formatter};
4use core::hash::{Hash, Hasher};
5use core::hint::assert_unchecked;
6use core::iter::{Product, Sum};
7use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
8use core::{array, fmt};
9
10use num_bigint::BigUint;
11use p3_field::exponentiation::exp_10540996611094048183;
12use p3_field::integers::QuotientMap;
13use p3_field::op_assign_macros::{
14 impl_add_assign, impl_div_methods, impl_mul_methods, impl_sub_assign,
15};
16use p3_field::{
17 Field, InjectiveMonomial, Packable, PermutationMonomial, PrimeCharacteristicRing, PrimeField,
18 PrimeField64, RawDataSerializable, TwoAdicField, UniformSamplingField,
19 impl_raw_serializable_primefield64, quotient_map_large_iint, quotient_map_small_int,
20};
21use p3_util::{branch_hint, flatten_to_base, gcd_inner};
22use rand::Rng;
23use rand::distr::{Distribution, StandardUniform};
24use serde::de::Error;
25use serde::{Deserialize, Deserializer, Serialize};
26
27pub(crate) const P: u64 = 0xFFFF_FFFF_0000_0001;
29
30#[derive(Copy, Clone, Default)]
34#[repr(transparent)] #[must_use]
36pub struct Goldilocks {
37 pub(crate) value: u64,
39}
40
41impl Serialize for Goldilocks {
42 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
43 let val = self.as_canonical_u64();
45 if serializer.is_human_readable() {
49 serializer.serialize_u64(val)
50 } else {
51 val.to_le_bytes().serialize(serializer)
52 }
53 }
54}
55
56impl<'de> Deserialize<'de> for Goldilocks {
57 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
58 let human_readable = d.is_human_readable();
59 let val = if human_readable {
60 u64::deserialize(d)?
61 } else {
62 u64::from_le_bytes(<[u8; 8]>::deserialize(d)?)
63 };
64 if val < P {
66 Ok(Self::new(val))
67 } else {
68 Err(D::Error::custom("Goldilocks value is out of range"))
69 }
70 }
71}
72
73impl Goldilocks {
74 #[inline]
79 pub const fn new(value: u64) -> Self {
80 Self { value }
81 }
82
83 #[inline]
87 pub const fn new_array<const N: usize>(input: [u64; N]) -> [Self; N] {
88 let mut output = [Self::ZERO; N];
89 let mut i = 0;
90 while i < N {
91 output[i].value = input[i];
92 i += 1;
93 }
94 output
95 }
96
97 #[inline]
101 pub const fn new_2d_array<const N: usize, const M: usize>(
102 input: [[u64; N]; M],
103 ) -> [[Self; N]; M] {
104 let mut output = [[Self::ZERO; N]; M];
105 let mut i = 0;
106 while i < M {
107 output[i] = Self::new_array(input[i]);
108 i += 1;
109 }
110 output
111 }
112
113 const NEG_ORDER: u64 = Self::ORDER_U64.wrapping_neg();
115
116 pub const TWO_ADIC_GENERATORS: [Self; 33] = Self::new_array([
120 0x0000000000000001,
121 0xffffffff00000000,
122 0x0001000000000000,
123 0xfffffffeff000001,
124 0xefffffff00000001,
125 0x00003fffffffc000,
126 0x0000008000000000,
127 0xf80007ff08000001,
128 0xbf79143ce60ca966,
129 0x1905d02a5c411f4e,
130 0x9d8f2ad78bfed972,
131 0x0653b4801da1c8cf,
132 0xf2c35199959dfcb6,
133 0x1544ef2335d17997,
134 0xe0ee099310bba1e2,
135 0xf6b2cffe2306baac,
136 0x54df9630bf79450e,
137 0xabd0a6e8aa3d8a0e,
138 0x81281a7b05f9beac,
139 0xfbd41c6b8caa3302,
140 0x30ba2ecd5e93e76d,
141 0xf502aef532322654,
142 0x4b2a18ade67246b5,
143 0xea9d5a1336fbc98b,
144 0x86cdcc31c307e171,
145 0x4bbaf5976ecfefd8,
146 0xed41d05b78d6e286,
147 0x10d78dd8915a171d,
148 0x59049500004a4485,
149 0xdfa8c93ba46d2666,
150 0x7e9bd009b86a0845,
151 0x400a7f755588e659,
152 0x185629dcda58878c,
153 ]);
154
155 const POWERS_OF_TWO: [Self; 96] = {
160 let mut powers_of_two = [Self::ONE; 96];
161
162 let mut i = 1;
163 while i < 64 {
164 powers_of_two[i] = Self::new(1 << i);
165 i += 1;
166 }
167 let mut var = Self::new(1 << 63);
168 while i < 96 {
169 var = const_add(var, var);
170 powers_of_two[i] = var;
171 i += 1;
172 }
173 powers_of_two
174 };
175
176 #[cfg(any(
178 test,
179 all(target_arch = "aarch64", target_feature = "neon"),
180 all(
181 target_arch = "x86_64",
182 any(target_feature = "avx2", target_feature = "avx512f")
183 ),
184 all(target_arch = "wasm32", target_feature = "simd128")
185 ))]
186 #[inline]
187 pub(crate) const fn power_of_two(exp: u64) -> Self {
188 let exp = (exp % 192) as usize;
190 if exp < 96 {
191 Self::POWERS_OF_TWO[exp]
192 } else {
193 Self::new(Self::ORDER_U64 - Self::POWERS_OF_TWO[exp - 96].value)
195 }
196 }
197}
198
199impl PartialEq for Goldilocks {
200 fn eq(&self, other: &Self) -> bool {
201 self.as_canonical_u64() == other.as_canonical_u64()
202 }
203}
204
205impl Eq for Goldilocks {}
206
207impl Packable for Goldilocks {}
208
209impl Hash for Goldilocks {
210 fn hash<H: Hasher>(&self, state: &mut H) {
211 state.write_u64(self.as_canonical_u64());
212 }
213}
214
215impl Ord for Goldilocks {
216 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
217 self.as_canonical_u64().cmp(&other.as_canonical_u64())
218 }
219}
220
221impl PartialOrd for Goldilocks {
222 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
223 Some(self.cmp(other))
224 }
225}
226
227impl Display for Goldilocks {
228 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
229 Display::fmt(&self.as_canonical_u64(), f)
230 }
231}
232
233impl Debug for Goldilocks {
234 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
235 Debug::fmt(&self.as_canonical_u64(), f)
236 }
237}
238
239impl Distribution<Goldilocks> for StandardUniform {
240 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Goldilocks {
241 loop {
242 let next_u64 = rng.next_u64();
243 let is_canonical = next_u64 < Goldilocks::ORDER_U64;
244 if is_canonical {
245 return Goldilocks::new(next_u64);
246 }
247 }
248 }
249}
250
251impl UniformSamplingField for Goldilocks {
252 const MAX_SINGLE_SAMPLE_BITS: usize = 32;
253 const SAMPLING_BITS_M: [u64; 64] = {
254 let prime: u64 = P;
255 let mut a = [0u64; 64];
256 let mut k = 0;
257 while k < 64 {
258 if k == 0 {
259 a[k] = prime; } else {
261 let mask = !((1u64 << k) - 1);
263 a[k] = prime & mask;
264 }
265 k += 1;
266 }
267 a
268 };
269}
270
271impl PrimeCharacteristicRing for Goldilocks {
272 type PrimeSubfield = Self;
273
274 const ZERO: Self = Self::new(0);
275 const ONE: Self = Self::new(1);
276 const TWO: Self = Self::new(2);
277 const NEG_ONE: Self = Self::new(Self::ORDER_U64 - 1);
278
279 #[inline]
280 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
281 f
282 }
283
284 #[inline]
285 fn from_bool(b: bool) -> Self {
286 Self::new(b.into())
287 }
288
289 #[inline]
290 fn halve(&self) -> Self {
291 const HALF_P_PLUS_1: u64 = (P + 1) >> 1; let lo_bit = self.value & 1;
296 let half = self.value >> 1;
297 let mask = 0u64.wrapping_sub(lo_bit); Self::new(half.wrapping_add(mask & HALF_P_PLUS_1))
299 }
300
301 #[cfg(target_arch = "wasm32")]
302 #[inline]
303 fn square(&self) -> Self {
304 reduce128(square_wide(self.value))
305 }
306
307 #[inline]
308 fn mul_2exp_u64(&self, exp: u64) -> Self {
309 match exp {
311 0 => *self,
312 1 => *self + *self,
313 _ => {
314 if exp < 96 {
315 *self * Self::POWERS_OF_TWO[exp as usize]
316 } else if exp < 192 {
317 -*self * Self::POWERS_OF_TWO[(exp - 96) as usize]
318 } else {
319 self.mul_2exp_u64(exp % 192)
320 }
321 }
322 }
323 }
324
325 #[inline]
326 fn div_2exp_u64(&self, mut exp: u64) -> Self {
327 exp %= 192;
330 match exp {
331 0 => *self,
332 1 => self.halve(),
333 2..=32 => {
334 let lo = self.value & ((1u64 << exp) - 1);
335 let hi = self.value >> exp;
336
337 let a = hi + (lo << (32 - exp));
341 let b = lo << (64 - exp);
342 let (result, borrow) = a.overflowing_sub(b);
343 Self::new(result.wrapping_sub(Self::NEG_ORDER * u64::from(borrow)))
344 }
345 _ => self.mul_2exp_u64(192 - exp),
346 }
347 }
348
349 #[inline]
350 fn sum_array<const N: usize>(input: &[Self]) -> Self {
351 assert_eq!(N, input.len());
352 match N {
356 0 => Self::ZERO,
357 1 => input[0],
358 2 => input[0] + input[1],
359 3 => input[0] + input[1] + input[2],
360 _ => input.iter().copied().sum(),
361 }
362 }
363
364 #[inline]
365 fn dot_product<const N: usize>(lhs: &[Self; N], rhs: &[Self; N]) -> Self {
366 const OFFSET: u128 = ((P as u128) << 64) - (P as u128) + ((P as u128) << 32);
370 const {
371 assert!((N as u32) <= (1 << 31));
372 }
373 match N {
374 0 => Self::ZERO,
375 1 => lhs[0] * rhs[0],
376 2 => {
377 let long_prod_0 = mul_wide(lhs[0].value, rhs[0].value);
380 let long_prod_1 = mul_wide(lhs[1].value, rhs[1].value);
381
382 let (sum, over) = long_prod_0.overflowing_add(long_prod_1);
385 let sum_corr = sum.wrapping_sub(OFFSET);
387 if over {
388 reduce128(sum_corr)
389 } else {
390 reduce128(sum)
391 }
392 }
393 _ => {
394 let (lo_plus_hi, hi) = lhs
395 .iter()
396 .zip(rhs)
397 .map(|(x, y)| mul_wide(x.value, y.value))
398 .fold((0_u128, 0_u64), |(acc_lo, acc_hi), val| {
399 let val_hi = (val >> 96) as u64;
401 unsafe { (acc_lo.wrapping_add(val), acc_hi.unchecked_add(val_hi)) }
404 });
405 let lo = lo_plus_hi.wrapping_sub((hi as u128) << 96);
407 let sum = unsafe { lo.unchecked_add(P.unchecked_sub(hi) as u128) };
410 reduce128(sum)
411 }
412 }
413 }
414
415 #[inline]
416 fn zero_vec(len: usize) -> Vec<Self> {
417 unsafe { flatten_to_base(vec![0u64; len]) }
422 }
423}
424
425impl InjectiveMonomial<7> for Goldilocks {}
429
430impl PermutationMonomial<7> for Goldilocks {
431 fn injective_exp_root_n(&self) -> Self {
435 exp_10540996611094048183(*self)
436 }
437}
438
439impl RawDataSerializable for Goldilocks {
440 impl_raw_serializable_primefield64!();
441}
442
443#[inline(always)]
445fn exp_2_31_minus_1(x: Goldilocks) -> Goldilocks {
446 let x3 = x.square() * x;
447 let x7 = x3.square() * x;
448 let x63 = x7.exp_power_of_2(3) * x7;
449 let x4095 = x63.exp_power_of_2(6) * x63;
450 let x24 = x4095.exp_power_of_2(12) * x4095;
451 let x30 = x24.exp_power_of_2(6) * x63;
452 x30.square() * x
453}
454
455impl Field for Goldilocks {
456 #[cfg(all(
457 target_arch = "x86_64",
458 target_feature = "avx2",
459 not(target_feature = "avx512f")
460 ))]
461 type Packing = crate::PackedGoldilocksAVX2;
462
463 #[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
464 type Packing = crate::PackedGoldilocksAVX512;
465
466 #[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
467 type Packing = crate::PackedGoldilocksNeon;
468
469 #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
470 type Packing = crate::PackedGoldilocksWasmSimd128;
471
472 #[cfg(not(any(
473 all(
474 target_arch = "x86_64",
475 target_feature = "avx2",
476 not(target_feature = "avx512f")
477 ),
478 all(target_arch = "x86_64", target_feature = "avx512f"),
479 all(target_arch = "aarch64", target_feature = "neon"),
480 all(target_arch = "wasm32", target_feature = "simd128"),
481 )))]
482 type Packing = Self;
483
484 const GENERATOR: Self = Self::new(7);
486
487 const BENEFITS_FROM_LOCKSTEP_EVALUATION: bool = true;
489
490 fn is_zero(&self) -> bool {
491 self.value == 0 || self.value == Self::ORDER_U64
492 }
493
494 fn try_inverse(&self) -> Option<Self> {
495 if self.is_zero() {
496 return None;
497 }
498
499 Some(gcd_inversion(*self))
500 }
501
502 #[inline]
503 fn order() -> BigUint {
504 P.into()
505 }
506
507 #[inline]
508 fn try_sqrt(&self) -> Option<Self> {
509 if self.is_zero() {
511 return Some(Self::ZERO);
512 }
513
514 let u = exp_2_31_minus_1(*self);
517 let mut r = u * *self;
518 let mut t = r * u;
519 let mut m = 32;
520
521 while t != Self::ONE {
522 let mut i = 0;
525 let mut t2i = t;
526 while t2i != Self::ONE {
527 t2i = t2i.square();
528 i += 1;
529 if i == m {
530 return None;
531 }
532 }
533
534 r *= Self::TWO_ADIC_GENERATORS[i + 1];
538 t *= Self::TWO_ADIC_GENERATORS[i];
539 m = i;
540 }
541
542 Some(r)
543 }
544}
545
546quotient_map_small_int!(Goldilocks, u64, [u8, u16, u32]);
548quotient_map_small_int!(Goldilocks, i64, [i8, i16, i32]);
549quotient_map_large_iint!(
550 Goldilocks,
551 i64,
552 "`[-(2^63 - 2^31), 2^63 - 2^31]`",
553 "`[1 + 2^32 - 2^64, 2^64 - 1]`",
554 [(i128, u128)]
555);
556
557impl QuotientMap<u128> for Goldilocks {
558 #[inline]
562 fn from_int(int: u128) -> Self {
563 Self::new(reduce128(int).as_canonical_u64())
564 }
565
566 #[inline]
570 fn from_canonical_checked(int: u128) -> Option<Self> {
571 (int < Self::ORDER_U64 as u128).then(|| Self::new(int as u64))
572 }
573
574 #[inline]
579 unsafe fn from_canonical_unchecked(int: u128) -> Self {
580 Self::new(int as u64)
581 }
582}
583
584impl QuotientMap<u64> for Goldilocks {
585 #[inline]
590 fn from_int(int: u64) -> Self {
591 Self::new(int)
592 }
593
594 #[inline]
598 fn from_canonical_checked(int: u64) -> Option<Self> {
599 (int < Self::ORDER_U64).then(|| Self::new(int))
600 }
601
602 #[inline(always)]
608 unsafe fn from_canonical_unchecked(int: u64) -> Self {
609 Self::new(int)
610 }
611}
612
613impl QuotientMap<i64> for Goldilocks {
614 #[inline]
618 fn from_int(int: i64) -> Self {
619 if int >= 0 {
620 Self::new(int as u64)
621 } else {
622 Self::new(Self::ORDER_U64.wrapping_add_signed(int))
623 }
624 }
625
626 #[inline]
630 fn from_canonical_checked(int: i64) -> Option<Self> {
631 const POS_BOUND: i64 = (P >> 1) as i64;
632 const NEG_BOUND: i64 = -POS_BOUND;
633 match int {
634 0..=POS_BOUND => Some(Self::new(int as u64)),
635 NEG_BOUND..0 => Some(Self::new(Self::ORDER_U64.wrapping_add_signed(int))),
636 _ => None,
637 }
638 }
639
640 #[inline(always)]
646 unsafe fn from_canonical_unchecked(int: i64) -> Self {
647 Self::from_int(int)
648 }
649}
650
651impl PrimeField for Goldilocks {
652 fn as_canonical_biguint(&self) -> BigUint {
653 self.as_canonical_u64().into()
654 }
655}
656
657impl PrimeField64 for Goldilocks {
658 const ORDER_U64: u64 = P;
659
660 #[inline]
661 fn as_canonical_u64(&self) -> u64 {
662 let mut c = self.value;
663 if c >= Self::ORDER_U64 {
665 c -= Self::ORDER_U64;
666 }
667 c
668 }
669}
670
671impl TwoAdicField for Goldilocks {
672 const TWO_ADICITY: usize = 32;
673
674 fn two_adic_generator(bits: usize) -> Self {
675 assert!(bits <= Self::TWO_ADICITY);
676 Self::TWO_ADIC_GENERATORS[bits]
677 }
678}
679
680#[inline]
685const fn const_add(lhs: Goldilocks, rhs: Goldilocks) -> Goldilocks {
686 let (sum, over) = lhs.value.overflowing_add(rhs.value);
687 let (mut sum, over) = sum.overflowing_add((over as u64) * Goldilocks::NEG_ORDER);
688 if over {
689 sum += Goldilocks::NEG_ORDER;
690 }
691 Goldilocks::new(sum)
692}
693
694impl Add for Goldilocks {
695 type Output = Self;
696
697 #[inline]
698 fn add(self, rhs: Self) -> Self {
699 let (sum, over) = self.value.overflowing_add(rhs.value);
700 let (mut sum, over) = sum.overflowing_add(u64::from(over) * Self::NEG_ORDER);
701 if over {
702 unsafe {
710 assert_unchecked(self.value > Self::ORDER_U64 && rhs.value > Self::ORDER_U64);
711 }
712 branch_hint();
713 sum += Self::NEG_ORDER; }
715 Self::new(sum)
716 }
717}
718
719impl Sub for Goldilocks {
720 type Output = Self;
721
722 #[inline]
723 fn sub(self, rhs: Self) -> Self {
724 let (diff, under) = self.value.overflowing_sub(rhs.value);
725 let (mut diff, under) = diff.overflowing_sub(u64::from(under) * Self::NEG_ORDER);
726 if under {
727 unsafe {
735 assert_unchecked(self.value < Self::NEG_ORDER - 1 && rhs.value > Self::ORDER_U64);
736 }
737 branch_hint();
738 diff -= Self::NEG_ORDER; }
740 Self::new(diff)
741 }
742}
743
744impl Neg for Goldilocks {
745 type Output = Self;
746
747 #[inline]
748 fn neg(self) -> Self::Output {
749 Self::new(Self::ORDER_U64 - self.as_canonical_u64())
750 }
751}
752
753impl Mul for Goldilocks {
754 type Output = Self;
755
756 #[inline]
757 fn mul(self, rhs: Self) -> Self {
758 reduce128(mul_wide(self.value, rhs.value))
759 }
760}
761
762#[inline]
765fn mul_wide(x: u64, y: u64) -> u128 {
766 #[cfg(not(target_arch = "wasm32"))]
767 {
768 u128::from(x) * u128::from(y)
769 }
770 #[cfg(target_arch = "wasm32")]
771 {
772 let x_lo = x & Goldilocks::NEG_ORDER;
773 let x_hi = x >> 32;
774 let y_lo = y & Goldilocks::NEG_ORDER;
775 let y_hi = y >> 32;
776 let ll = x_lo * y_lo;
777 let lh = x_lo * y_hi;
778 let hl = x_hi * y_lo;
779 let hh = x_hi * y_hi;
780
781 let t0 = hl + (ll >> 32);
784 let t1 = lh + (t0 & Goldilocks::NEG_ORDER);
785 let hi = hh + (t0 >> 32) + (t1 >> 32);
786 let lo = (ll & Goldilocks::NEG_ORDER) | (t1 << 32);
787 (u128::from(hi) << 64) | u128::from(lo)
788 }
789}
790
791#[cfg(target_arch = "wasm32")]
793#[inline]
794fn square_wide(x: u64) -> u128 {
795 let lo = x & Goldilocks::NEG_ORDER;
796 let hi = x >> 32;
797 let ll = lo * lo;
798 let lh = lo * hi;
799 let hh = hi * hi;
800 let middle = lh + (ll >> 33);
803 let product_hi = hh + (middle >> 31);
804 let product_lo = ll.wrapping_add(lh << 33);
805 (u128::from(product_hi) << 64) | u128::from(product_lo)
806}
807
808impl_add_assign!(Goldilocks);
809impl_sub_assign!(Goldilocks);
810impl_mul_methods!(Goldilocks);
811impl_div_methods!(Goldilocks, Goldilocks);
812
813impl Sum for Goldilocks {
814 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
815 let sum = iter.map(|x| x.value as u128).sum::<u128>();
819 reduce128(sum)
820 }
821}
822
823#[inline]
826pub(crate) fn reduce128(x: u128) -> Goldilocks {
827 let (x_lo, x_hi) = split(x); let x_hi_hi = x_hi >> 32;
829 let x_hi_lo = x_hi & Goldilocks::NEG_ORDER;
830
831 let (mut t0, borrow) = x_lo.overflowing_sub(x_hi_hi);
832 if borrow {
833 branch_hint(); t0 -= Goldilocks::NEG_ORDER; }
836 let t1 = x_hi_lo * Goldilocks::NEG_ORDER;
837 let t2 = unsafe { add_no_canonicalize_trashing_input(t0, t1) };
838 Goldilocks::new(t2)
839}
840
841#[inline]
842#[allow(clippy::cast_possible_truncation)]
843const fn split(x: u128) -> (u64, u64) {
844 (x as u64, (x >> 64) as u64)
845}
846
847#[inline(always)]
853#[cfg(target_arch = "x86_64")]
854unsafe fn add_no_canonicalize_trashing_input(x: u64, y: u64) -> u64 {
855 unsafe {
856 let res_wrapped: u64;
857 let adjustment: u64;
858 core::arch::asm!(
859 "add {0}, {1}",
860 "sbb {1:e}, {1:e}",
869 inlateout(reg) x => res_wrapped,
870 inlateout(reg) y => adjustment,
871 options(pure, nomem, nostack),
872 );
873 assert_unchecked(x != 0 || (res_wrapped == y && adjustment == 0));
874 assert_unchecked(y != 0 || (res_wrapped == x && adjustment == 0));
875 res_wrapped + adjustment
878 }
879}
880
881#[inline(always)]
882#[cfg(not(target_arch = "x86_64"))]
883unsafe fn add_no_canonicalize_trashing_input(x: u64, y: u64) -> u64 {
884 let (res_wrapped, carry) = x.overflowing_add(y);
885 res_wrapped + Goldilocks::NEG_ORDER * u64::from(carry)
887}
888
889fn gcd_inversion(input: Goldilocks) -> Goldilocks {
898 let (mut a, mut b) = (input.value, P);
900
901 const ROUND_SIZE: usize = 63;
905
906 let (f00, _, f10, _) = gcd_inner::<ROUND_SIZE>(&mut a, &mut b);
910 let (_, _, f11, g11) = gcd_inner::<ROUND_SIZE>(&mut a, &mut b);
911
912 let u = from_unusual_int(f00);
915 let v = from_unusual_int(f10);
916 let u_fac11 = from_unusual_int(f11);
917 let v_fac11 = from_unusual_int(g11);
918
919 (u * u_fac11 + v * v_fac11).mul_2exp_u64(66)
922}
923
924const fn from_unusual_int(int: i64) -> Goldilocks {
926 if (int >= 0) || (int == i64::MIN) {
927 Goldilocks::new(int as u64)
928 } else {
929 Goldilocks::new(Goldilocks::ORDER_U64.wrapping_add_signed(int))
930 }
931}
932
933#[cfg(test)]
934mod tests {
935 use p3_field::extension::BinomialExtensionField;
936 use p3_field::{PackedValue, tonelli_shanks_two_adic};
937 use p3_field_testing::{
938 test_field, test_field_dft, test_prime_field, test_prime_field_64, test_two_adic_field,
939 };
940 use rand::rngs::SmallRng;
941 use rand::{RngExt, SeedableRng};
942
943 use super::*;
944
945 type F = Goldilocks;
946 type EF = BinomialExtensionField<F, 5>;
947
948 #[cfg(target_arch = "wasm32")]
951 #[test]
952 fn wasm_wide_products_match_u128_oracle() {
953 const EDGES: [u64; 12] = [
954 0,
955 1,
956 (1 << 32) - 2,
957 (1 << 32) - 1,
958 1 << 32,
959 (1 << 32) + 1,
960 (1 << 63) - 1,
961 1 << 63,
962 P - 1,
963 P,
964 P + 1,
965 u64::MAX,
966 ];
967 let check = |a: u64, b: u64| {
968 let product = u128::from(a) * u128::from(b);
969 let square = u128::from(a) * u128::from(a);
970 assert_eq!(mul_wide(a, b), product, "a={a}, b={b}");
971 assert_eq!(square_wide(a), square, "a={a}");
972 assert_eq!(
973 (F::new(a) * F::new(b)).as_canonical_u64(),
974 (product % u128::from(P)) as u64
975 );
976 assert_eq!(
977 F::new(a).square().as_canonical_u64(),
978 (square % u128::from(P)) as u64
979 );
980 };
981 for a in EDGES {
982 for b in EDGES {
983 check(a, b);
984 }
985 }
986 let mut rng = SmallRng::seed_from_u64(0x64_32_CA77);
987 for _ in 0..10_000 {
988 check(rng.random(), rng.random());
989 }
990 }
991
992 #[test]
995 fn packed_sum_array_matches_full_u64_oracle() {
996 type PF = <F as Field>::Packing;
997
998 const RAW_EDGES: [u64; 10] = [
999 0,
1000 1,
1001 (1 << 32) - 1,
1002 1 << 32,
1003 1 << 63,
1004 P - 1,
1005 P,
1006 P + 1,
1007 u64::MAX - 1,
1008 u64::MAX,
1009 ];
1010
1011 fn check<const N: usize>(values: &[u64]) {
1012 type PF = <F as Field>::Packing;
1013
1014 assert_eq!(values.len(), PF::WIDTH * N);
1015 let input: [PF; N] =
1016 core::array::from_fn(|term| PF::from_fn(|lane| F::new(values[lane * N + term])));
1017 let actual = PF::sum_array::<N>(&input);
1018
1019 for lane in 0..PF::WIDTH {
1020 let expected = (values[lane * N..(lane + 1) * N]
1021 .iter()
1022 .map(|&value| u128::from(value))
1023 .sum::<u128>()
1024 % u128::from(P)) as u64;
1025 assert_eq!(
1026 actual.as_slice()[lane].as_canonical_u64(),
1027 expected,
1028 "N={N}, lane={lane}"
1029 );
1030 }
1031 }
1032
1033 macro_rules! check_length {
1034 ($rng:ident, $n:literal, $random_cases:literal) => {{
1035 let edge_values = (0..PF::WIDTH * $n)
1036 .map(|index| RAW_EDGES[index % RAW_EDGES.len()])
1037 .collect::<Vec<_>>();
1038 check::<$n>(&edge_values);
1039 check::<$n>(&[u64::MAX; PF::WIDTH * $n]);
1040
1041 for _ in 0..$random_cases {
1042 let values = (0..PF::WIDTH * $n)
1043 .map(|_| $rng.random::<u64>())
1044 .collect::<Vec<_>>();
1045 check::<$n>(&values);
1046 }
1047 }};
1048 }
1049
1050 let mut rng = SmallRng::seed_from_u64(0x5A_0B17_5EED);
1051 check_length!(rng, 0, 16);
1052 check_length!(rng, 1, 16);
1053 check_length!(rng, 2, 16);
1054 check_length!(rng, 3, 16);
1055 check_length!(rng, 4, 16);
1056 check_length!(rng, 5, 16);
1057 check_length!(rng, 6, 16);
1058 check_length!(rng, 7, 16);
1059 check_length!(rng, 8, 16);
1060 check_length!(rng, 12, 16);
1061 check_length!(rng, 16, 16);
1062 check_length!(rng, 32, 16);
1063 check_length!(rng, 63, 8);
1064 check_length!(rng, 64, 8);
1065 check_length!(rng, 129, 4);
1066 }
1067
1068 #[test]
1071 fn packed_dot_products_match_full_u64_oracle() {
1072 use p3_field::Algebra;
1073
1074 type PF = <F as Field>::Packing;
1075
1076 const RAW_EDGES: [u64; 10] = [
1077 0,
1078 1,
1079 (1 << 32) - 2,
1080 (1 << 32) - 1,
1081 1 << 32,
1082 1 << 63,
1083 P - 1,
1084 P,
1085 P + 1,
1086 u64::MAX,
1087 ];
1088
1089 fn check<const N: usize>(lhs: &[PF; N], rhs: &[PF; N], coeffs: &[F; N]) {
1090 let ordinary = PF::dot_product(lhs, rhs);
1091 let mixed = PF::mixed_dot_product(lhs, coeffs);
1092 let broadcast = PF::dot_product(lhs, &coeffs.map(PF::from));
1093 assert_eq!(mixed, broadcast, "mixed/broadcast, N={N}");
1094
1095 for lane in 0..PF::WIDTH {
1096 let mut ordinary_expected = 0u128;
1097 let mut mixed_expected = 0u128;
1098 for term in 0..N {
1099 let a = u128::from(lhs[term].as_slice()[lane].value);
1100 let b = u128::from(rhs[term].as_slice()[lane].value);
1101 ordinary_expected += (a * b) % u128::from(P);
1102 mixed_expected += (a * u128::from(coeffs[term].value)) % u128::from(P);
1103 }
1104 assert_eq!(
1105 ordinary.as_slice()[lane].as_canonical_u64(),
1106 (ordinary_expected % u128::from(P)) as u64,
1107 "ordinary, N={N}, lane={lane}"
1108 );
1109 assert_eq!(
1110 mixed.as_slice()[lane].as_canonical_u64(),
1111 (mixed_expected % u128::from(P)) as u64,
1112 "mixed, N={N}, lane={lane}"
1113 );
1114 }
1115 }
1116
1117 fn check_length<const N: usize>(rng: &mut SmallRng) {
1118 for a in RAW_EDGES {
1121 for b in RAW_EDGES {
1122 check::<N>(
1123 &[PF::from(F::new(a)); N],
1124 &[PF::from(F::new(b)); N],
1125 &[F::new(b); N],
1126 );
1127 }
1128 }
1129 for offset in 0..RAW_EDGES.len() {
1130 let lhs = core::array::from_fn(|term| {
1131 PF::from_fn(|lane| F::new(RAW_EDGES[(offset + term + lane) % RAW_EDGES.len()]))
1132 });
1133 let rhs = core::array::from_fn(|term| {
1134 PF::from_fn(|lane| {
1135 F::new(RAW_EDGES[(offset + 3 * term + 7 * lane) % RAW_EDGES.len()])
1136 })
1137 });
1138 let coeffs = core::array::from_fn(|term| {
1139 F::new(RAW_EDGES[(offset + term) % RAW_EDGES.len()])
1140 });
1141 check::<N>(&lhs, &rhs, &coeffs);
1142 }
1143 for _ in 0..128 {
1144 let lhs = core::array::from_fn(|_| PF::from_fn(|_| F::new(rng.random())));
1145 let rhs = core::array::from_fn(|_| PF::from_fn(|_| F::new(rng.random())));
1146 let coeffs = core::array::from_fn(|_| F::new(rng.random()));
1147 check::<N>(&lhs, &rhs, &coeffs);
1148 }
1149 }
1150
1151 let mut rng = SmallRng::seed_from_u64(0xD07_F011_5EED);
1152 check_length::<0>(&mut rng);
1153 check_length::<1>(&mut rng);
1154 check_length::<2>(&mut rng);
1155 check_length::<3>(&mut rng);
1156 check_length::<4>(&mut rng);
1157 check_length::<5>(&mut rng);
1158 check_length::<6>(&mut rng);
1159 check_length::<7>(&mut rng);
1160 check_length::<8>(&mut rng);
1161 check_length::<12>(&mut rng);
1162 check_length::<16>(&mut rng);
1163 check_length::<31>(&mut rng);
1164 check_length::<32>(&mut rng);
1165 check_length::<33>(&mut rng);
1166 check_length::<64>(&mut rng);
1167 check_length::<65>(&mut rng);
1168 check_length::<129>(&mut rng);
1169 }
1170
1171 #[test]
1172 fn power_of_two_coefficient_matches_generic_exponentiation() {
1173 for exp in (0..384).chain([1 << 32, 1 << 63, u64::MAX - 1, u64::MAX]) {
1174 let coefficient = F::power_of_two(exp);
1175 assert_eq!(coefficient, F::TWO.exp_u64(exp), "exp = {exp}");
1176 assert!(
1177 coefficient.value < P,
1178 "noncanonical coefficient: exp = {exp}"
1179 );
1180 assert_eq!(
1181 coefficient * F::power_of_two(192 - exp % 192),
1182 F::ONE,
1183 "inverse coefficient: exp = {exp}"
1184 );
1185 }
1186 }
1187
1188 #[test]
1189 fn packed_powers_of_two_match_scalar_oracle_for_arbitrary_representatives() {
1190 type PF = <F as Field>::Packing;
1191
1192 const EXPONENTS: [u64; 17] = [
1193 0,
1194 1,
1195 2,
1196 3,
1197 5,
1198 31,
1199 32,
1200 33,
1201 63,
1202 95,
1203 96,
1204 191,
1205 192,
1206 194,
1207 224,
1208 225,
1209 u64::MAX,
1210 ];
1211 const RAW_EDGES: [u64; 10] = [
1212 0,
1213 1,
1214 (1 << 32) - 2,
1215 (1 << 32) - 1,
1216 1 << 32,
1217 1 << 63,
1218 P - 1,
1219 P,
1220 P + 1,
1221 u64::MAX,
1222 ];
1223
1224 let check = |raw: &[u64]| {
1225 assert_eq!(raw.len(), PF::WIDTH);
1226 let input = PF::from_fn(|lane| F::new(raw[lane]));
1227
1228 for exp in EXPONENTS {
1229 let power = F::TWO.exp_u64(exp);
1230 let product = input.mul_2exp_u64(exp);
1231 let quotient = input.div_2exp_u64(exp);
1232
1233 for (lane, &raw) in raw.iter().enumerate() {
1234 let scalar = F::new(raw);
1235 assert_eq!(
1236 product.as_slice()[lane],
1237 scalar * power,
1238 "mul: raw = {raw:#018x}, exp = {exp}, lane = {lane}"
1239 );
1240 assert_eq!(
1241 quotient.as_slice()[lane],
1242 scalar / power,
1243 "div: raw = {raw:#018x}, exp = {exp}, lane = {lane}"
1244 );
1245 }
1246 }
1247 };
1248
1249 for offset in 0..RAW_EDGES.len() {
1250 let raw = (0..PF::WIDTH)
1251 .map(|lane| RAW_EDGES[(offset + lane) % RAW_EDGES.len()])
1252 .collect::<Vec<_>>();
1253 check(&raw);
1254 }
1255
1256 let mut rng = SmallRng::seed_from_u64(0x2E80_2E80_5EED);
1257 for _ in 0..256 {
1258 let raw = (0..PF::WIDTH)
1259 .map(|_| rng.random::<u64>())
1260 .collect::<Vec<_>>();
1261 check(&raw);
1262 }
1263 }
1264
1265 #[test]
1266 fn deserialize_rejects_non_canonical_encodings() {
1267 for non_canonical in [P, P + 5, u64::MAX] {
1271 let json = serde_json::to_string(&non_canonical).unwrap();
1272 assert!(serde_json::from_str::<F>(&json).is_err());
1273 }
1274
1275 let max_canonical_json = serde_json::to_string(&(P - 1)).unwrap();
1277 let max_canonical: F = serde_json::from_str(&max_canonical_json).unwrap();
1278 assert_eq!(max_canonical.as_canonical_u64(), P - 1);
1279 }
1280
1281 #[test]
1282 fn serialize_is_canonical() {
1283 let non_canonical = F::new(P + 5);
1287 let json = serde_json::to_string(&non_canonical).unwrap();
1288 assert_eq!(json, "5");
1289
1290 let roundtrip: F = serde_json::from_str(&json).unwrap();
1292 assert_eq!(roundtrip, non_canonical);
1293 }
1294
1295 #[test]
1296 fn test_goldilocks() {
1297 let f = F::new(100);
1298 assert_eq!(f.as_canonical_u64(), 100);
1299
1300 let f = F::new(u64::MAX);
1305 assert_eq!(f.as_canonical_u64(), u32::MAX as u64 - 1);
1306
1307 let f = F::from_u64(u64::MAX);
1308 assert_eq!(f.as_canonical_u64(), u32::MAX as u64 - 1);
1309
1310 let expected_multiplicative_group_generator = F::new(7);
1312 assert_eq!(F::GENERATOR, expected_multiplicative_group_generator);
1313 assert_eq!(F::GENERATOR.as_canonical_u64(), 7_u64);
1314
1315 let x = u128::MAX;
1317 let y = reduce128(x);
1318 let expected_result = -F::TWO.exp_power_of_2(5) - F::ONE;
1327 assert_eq!(y, expected_result);
1328
1329 let f = F::new(100);
1330 assert_eq!(f.injective_exp_n().injective_exp_root_n(), f);
1331 assert_eq!(y.injective_exp_n().injective_exp_root_n(), y);
1332 assert_eq!(F::TWO.injective_exp_n().injective_exp_root_n(), F::TWO);
1333 }
1334
1335 #[test]
1336 fn u128_conversion_matches_modulo_oracle() {
1337 const EDGES: [u128; 12] = [
1338 0,
1339 1,
1340 P as u128 - 1,
1341 P as u128,
1342 P as u128 + 1,
1343 u64::MAX as u128,
1344 1 << 64,
1345 (1 << 64) + P as u128,
1346 1 << 96,
1347 1 << 127,
1348 u128::MAX - 1,
1349 u128::MAX,
1350 ];
1351
1352 let check = |input: u128| {
1353 let expected = (input % P as u128) as u64;
1354 let actual = F::from_int(input);
1355 assert_eq!(actual.value, expected, "input = {input:#034x}");
1356 };
1357
1358 for input in EDGES {
1359 check(input);
1360 }
1361
1362 let mut rng = SmallRng::seed_from_u64(0x128_C0DE);
1363 for _ in 0..10_000 {
1364 check(rng.random());
1365 }
1366 }
1367
1368 #[test]
1369 fn i128_conversion_matches_modulo_oracle() {
1370 const P_I128: i128 = P as i128;
1371 const EDGES: [i128; 14] = [
1372 i128::MIN,
1373 i128::MIN + 1,
1374 -(1 << 96),
1375 -P_I128 - 1,
1376 -P_I128,
1377 -P_I128 + 1,
1378 -1,
1379 0,
1380 1,
1381 P_I128 - 1,
1382 P_I128,
1383 P_I128 + 1,
1384 i128::MAX - 1,
1385 i128::MAX,
1386 ];
1387
1388 let check = |input: i128| {
1389 let magnitude_mod_p = (input.unsigned_abs() % P as u128) as u64;
1390 let expected_raw = if input < 0 {
1391 P - magnitude_mod_p
1392 } else {
1393 magnitude_mod_p
1394 };
1395 let actual = F::from_int(input);
1396 assert_eq!(actual.value, expected_raw, "input = {input}");
1397 };
1398
1399 for input in EDGES {
1400 check(input);
1401 }
1402
1403 let mut rng = SmallRng::seed_from_u64(0x128_51C0);
1404 for _ in 0..10_000 {
1405 check(rng.random());
1406 }
1407 }
1408
1409 #[test]
1410 fn sqrt_matches_generic_tonelli_shanks_for_arbitrary_representatives() {
1411 const RAW_EDGES: [u64; 10] = [
1412 0,
1413 1,
1414 (1 << 32) - 1,
1415 1 << 32,
1416 1 << 63,
1417 P - 1,
1418 P,
1419 P + 1,
1420 u64::MAX - 1,
1421 u64::MAX,
1422 ];
1423
1424 let check = |raw: u64| {
1425 let input = F::new(raw);
1426 let expected = tonelli_shanks_two_adic(input);
1427 let actual = input.try_sqrt();
1428 assert_eq!(actual.is_some(), expected.is_some(), "raw = {raw:#018x}");
1429 if let Some(root) = actual {
1430 assert_eq!(root.square(), input, "raw = {raw:#018x}");
1431 }
1432 };
1433
1434 for raw in RAW_EDGES {
1435 check(raw);
1436 }
1437
1438 let mut rng = SmallRng::seed_from_u64(0x5A7_C0DE);
1439 for _ in 0..10_000 {
1440 check(rng.random());
1441 }
1442 }
1443
1444 #[test]
1445 fn large_integer_checked_conversion_preserves_bounds_and_raw_values() {
1446 let unsigned_cases = [
1447 (0, Some(0)),
1448 (P as u128 - 1, Some(P - 1)),
1449 (P as u128, None),
1450 (P as u128 + 1, None),
1451 (u128::MAX, None),
1452 ];
1453 for (input, expected_raw) in unsigned_cases {
1454 assert_eq!(
1455 F::from_canonical_checked(input).map(|value| value.value),
1456 expected_raw,
1457 "input = {input}"
1458 );
1459 }
1460
1461 const BOUND: i128 = (P >> 1) as i128;
1462 let signed_cases = [
1463 (-BOUND - 1, None),
1464 (-BOUND, Some(P - BOUND as u64)),
1465 (-1, Some(P - 1)),
1466 (0, Some(0)),
1467 (BOUND, Some(BOUND as u64)),
1468 (BOUND + 1, None),
1469 (i128::MIN, None),
1470 (i128::MAX, None),
1471 ];
1472 for (input, expected_raw) in signed_cases {
1473 assert_eq!(
1474 F::from_canonical_checked(input).map(|value| value.value),
1475 expected_raw,
1476 "input = {input}"
1477 );
1478 }
1479 }
1480
1481 #[test]
1482 fn large_integer_unchecked_conversion_preserves_cast_behavior() {
1483 let unsigned_cases = [
1484 (0, 0),
1485 (P as u128 - 1, P - 1),
1486 (P as u128, P),
1487 (u64::MAX as u128, u64::MAX),
1488 ];
1489 for (input, expected_raw) in unsigned_cases {
1490 let actual = unsafe { F::from_canonical_unchecked(input) };
1491 assert_eq!(actual.value, expected_raw, "input = {input}");
1492 }
1493
1494 const MIN_UNCHECKED: i128 = 1 + (1_i128 << 32) - (1_i128 << 64);
1495 let signed_inputs = [
1496 MIN_UNCHECKED,
1497 i64::MIN as i128 - 1,
1498 i64::MIN as i128,
1499 -1,
1500 0,
1501 i64::MAX as i128,
1502 i64::MAX as i128 + 1,
1503 u64::MAX as i128,
1504 ];
1505 for input in signed_inputs {
1506 let narrowed = input as i64;
1507 let expected_raw = if narrowed >= 0 {
1508 narrowed as u64
1509 } else {
1510 P.wrapping_add_signed(narrowed)
1511 };
1512 let actual = unsafe { F::from_canonical_unchecked(input) };
1513 assert_eq!(actual.value, expected_raw, "input = {input}");
1514 }
1515 }
1516
1517 #[test]
1518 fn div_2exp_matches_field_division_for_all_representatives() {
1519 const EPSILON: u64 = (1 << 32) - 1;
1520 const RAW_EDGES: [u64; 10] = [
1521 0,
1522 1,
1523 EPSILON - 1,
1524 EPSILON,
1525 1 << 32,
1526 1 << 63,
1527 P - 1,
1528 P,
1529 P + 1,
1530 u64::MAX,
1531 ];
1532 const LARGE_EXPONENTS: [u64; 5] = [193, 384, 1 << 32, 1 << 63, u64::MAX];
1533
1534 let check = |raw: u64, exp: u64| {
1535 let x = F::new(raw);
1536 let divisor = F::TWO.exp_u64(exp % 192);
1537 assert_eq!(
1538 x.div_2exp_u64(exp),
1539 x / divisor,
1540 "raw = {raw:#018x}, exp = {exp}"
1541 );
1542 };
1543
1544 for raw in RAW_EDGES {
1545 for exp in 0..=192 {
1546 check(raw, exp);
1547 }
1548 for exp in LARGE_EXPONENTS {
1549 check(raw, exp);
1550 }
1551 }
1552
1553 let mut rng = SmallRng::seed_from_u64(0xD12_2E98);
1554 for _ in 0..10_000 {
1555 check(rng.random(), rng.random());
1556 }
1557 }
1558
1559 const ZEROS: [Goldilocks; 2] = [Goldilocks::ZERO, Goldilocks::new(P)];
1561 const ONES: [Goldilocks; 2] = [Goldilocks::ONE, Goldilocks::new(P + 1)];
1562
1563 fn multiplicative_group_prime_factorization() -> [(BigUint, u32); 6] {
1566 [
1567 (BigUint::from(2u8), 32),
1568 (BigUint::from(3u8), 1),
1569 (BigUint::from(5u8), 1),
1570 (BigUint::from(17u8), 1),
1571 (BigUint::from(257u16), 1),
1572 (BigUint::from(65537u32), 1),
1573 ]
1574 }
1575
1576 test_field!(
1577 crate::Goldilocks,
1578 &super::ZEROS,
1579 &super::ONES,
1580 &super::multiplicative_group_prime_factorization()
1581 );
1582 test_prime_field!(crate::Goldilocks);
1583 test_prime_field_64!(crate::Goldilocks, &super::ZEROS, &super::ONES);
1584 test_two_adic_field!(crate::Goldilocks);
1585
1586 test_field_dft!(
1587 radix2dit,
1588 crate::Goldilocks,
1589 super::EF,
1590 p3_dft::Radix2Dit<_>
1591 );
1592 test_field_dft!(bowers, crate::Goldilocks, super::EF, p3_dft::Radix2Bowers);
1593 test_field_dft!(
1594 parallel,
1595 crate::Goldilocks,
1596 super::EF,
1597 p3_dft::Radix2DitParallel<crate::Goldilocks>
1598 );
1599}