1use alloc::{format, vec, vec::Vec};
4use core::{
5 array, fmt,
6 hash::{Hash, Hasher},
7 iter::{Product, Sum},
8 mem::{align_of, size_of},
9 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
10};
11
12use miden_serde_utils::{
13 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
14};
15use num_bigint::BigUint;
16use p3_challenger::UniformSamplingField;
17use p3_field::{
18 Field, InjectiveMonomial, Packable, PermutationMonomial, PrimeCharacteristicRing, PrimeField,
19 PrimeField64, RawDataSerializable, TwoAdicField,
20 extension::{
21 Binomial, BinomiallyExtendable, ExtensionAlgebra, HasTwoAdicBinomialExtension,
22 binomial_mul, binomial_square,
23 },
24 impl_raw_serializable_primefield64,
25 integers::QuotientMap,
26 quotient_map_large_iint, quotient_map_large_uint, quotient_map_small_int,
27};
28use p3_goldilocks::Goldilocks;
29use p3_util::flatten_to_base;
30use rand::{
31 Rng,
32 distr::{Distribution, StandardUniform},
33};
34use subtle::{ConditionallySelectable, ConstantTimeLess};
35
36#[cfg(any(
37 all(target_arch = "x86_64", target_feature = "avx2"),
38 all(target_arch = "aarch64", target_feature = "neon"),
39 all(target_arch = "wasm32", target_feature = "simd128"),
40))]
41mod packed;
42#[cfg(any(
43 all(target_arch = "x86_64", target_feature = "avx2"),
44 all(target_arch = "aarch64", target_feature = "neon"),
45 all(target_arch = "wasm32", target_feature = "simd128"),
46))]
47pub use packed::PackedFelt;
48
49#[cfg(test)]
50mod tests;
51
52#[derive(Copy, Clone, Default, serde::Serialize, serde::Deserialize)]
57#[repr(transparent)]
58pub struct Felt(Goldilocks);
59
60impl Felt {
61 pub const ORDER: u64 = <Goldilocks as PrimeField64>::ORDER_U64;
63
64 pub const ZERO: Self = Self(Goldilocks::ZERO);
65 pub const ONE: Self = Self(Goldilocks::ONE);
66
67 pub const MAX: Self = Self::new_unchecked(Self::ORDER - 1);
69
70 pub const NUM_BYTES: usize = Goldilocks::NUM_BYTES;
72
73 pub fn new(value: u64) -> Result<Self, FeltFromIntError> {
79 Felt::from_canonical_checked(value).ok_or(FeltFromIntError(value))
80 }
81
82 #[inline]
87 pub const fn new_unchecked(value: u64) -> Self {
88 Self(Goldilocks::new(value))
89 }
90
91 #[inline]
93 pub const fn from_u8(value: u8) -> Self {
94 Self::new_unchecked(value as u64)
95 }
96
97 #[inline]
99 pub const fn from_u16(value: u16) -> Self {
100 Self::new_unchecked(value as u64)
101 }
102
103 #[inline]
105 pub const fn from_u32(value: u32) -> Self {
106 Self::new_unchecked(value as u64)
107 }
108
109 #[inline]
111 pub fn double(&self) -> Self {
112 <Self as PrimeCharacteristicRing>::double(self)
113 }
114
115 #[inline]
117 pub fn square(&self) -> Self {
118 <Self as PrimeCharacteristicRing>::square(self)
119 }
120
121 #[inline]
123 pub fn exp_u64(&self, power: u64) -> Self {
124 <Self as PrimeCharacteristicRing>::exp_u64(self, power)
125 }
126
127 #[inline]
129 pub fn exp_const_u64<const POWER: u64>(&self) -> Self {
130 <Self as PrimeCharacteristicRing>::exp_const_u64::<POWER>(self)
131 }
132
133 #[inline]
136 pub fn as_canonical_u64(&self) -> u64 {
137 <Self as PrimeField64>::as_canonical_u64(self)
138 }
139
140 #[inline]
143 pub fn as_canonical_u64_ct(&self) -> u64 {
144 let raw = raw_felt_u64(*self);
145 let reduced = raw.wrapping_sub(Self::ORDER);
148 let reduce = !raw.ct_lt(&Self::ORDER);
149 u64::conditional_select(&raw, &reduced, reduce)
150 }
151}
152
153#[inline]
154fn raw_felt_u64(value: Felt) -> u64 {
155 const _: () = {
156 assert!(size_of::<Felt>() == size_of::<u64>());
157 assert!(align_of::<Felt>() == align_of::<u64>());
158 assert!(2u128 * (Felt::ORDER as u128) > u64::MAX as u128);
159 };
160 unsafe { core::mem::transmute_copy(&value) }
162}
163
164#[inline]
170fn felts_as_goldilocks_slice(s: &[Felt]) -> &[Goldilocks] {
171 unsafe { core::slice::from_raw_parts(s.as_ptr().cast::<Goldilocks>(), s.len()) }
173}
174
175#[inline]
181fn felts_as_goldilocks_array<const N: usize>(a: &[Felt; N]) -> &[Goldilocks; N] {
182 unsafe { &*(a as *const [Felt; N] as *const [Goldilocks; N]) }
184}
185
186impl fmt::Display for Felt {
187 #[inline]
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 fmt::Display::fmt(&self.0, f)
190 }
191}
192
193impl fmt::Debug for Felt {
194 #[inline]
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 fmt::Debug::fmt(&self.0, f)
197 }
198}
199
200impl Hash for Felt {
201 #[inline]
202 fn hash<H: Hasher>(&self, state: &mut H) {
203 state.write_u64(self.as_canonical_u64());
204 }
205}
206
207impl Field for Felt {
211 #[cfg(all(target_arch = "x86_64", target_feature = "avx2", not(target_feature = "avx512f")))]
212 type Packing = PackedFelt;
213
214 #[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
215 type Packing = PackedFelt;
216
217 #[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
218 type Packing = PackedFelt;
219
220 #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
221 type Packing = PackedFelt;
222
223 #[cfg(not(any(
224 all(target_arch = "x86_64", target_feature = "avx2", not(target_feature = "avx512f")),
225 all(target_arch = "x86_64", target_feature = "avx512f"),
226 target_arch = "aarch64",
227 all(target_arch = "wasm32", target_feature = "simd128"),
228 )))]
229 type Packing = Self;
230
231 const GENERATOR: Self = Self(Goldilocks::GENERATOR);
232
233 #[inline]
234 fn is_zero(&self) -> bool {
235 self.0.is_zero()
236 }
237
238 #[inline]
239 fn try_inverse(&self) -> Option<Self> {
240 self.0.try_inverse().map(Self)
241 }
242
243 #[inline]
244 fn order() -> BigUint {
245 <Goldilocks as Field>::order()
246 }
247}
248
249impl Packable for Felt {}
250
251impl PrimeCharacteristicRing for Felt {
252 type PrimeSubfield = Goldilocks;
253
254 const ZERO: Self = Self(Goldilocks::ZERO);
255 const ONE: Self = Self(Goldilocks::ONE);
256 const TWO: Self = Self(Goldilocks::TWO);
257 const NEG_ONE: Self = Self(Goldilocks::NEG_ONE);
258
259 #[inline]
260 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
261 Self(f)
262 }
263
264 #[inline]
265 fn from_bool(value: bool) -> Self {
266 Self::new_unchecked(value.into())
267 }
268
269 #[inline]
270 fn halve(&self) -> Self {
271 Self(self.0.halve())
272 }
273
274 #[inline]
275 fn mul_2exp_u64(&self, exp: u64) -> Self {
276 Self(self.0.mul_2exp_u64(exp))
277 }
278
279 #[inline]
280 fn div_2exp_u64(&self, exp: u64) -> Self {
281 Self(self.0.div_2exp_u64(exp))
282 }
283
284 #[inline]
285 fn exp_u64(&self, power: u64) -> Self {
286 self.0.exp_u64(power).into()
287 }
288
289 #[inline]
290 fn sum_array<const N: usize>(input: &[Self]) -> Self {
291 assert_eq!(N, input.len());
292 let g = felts_as_goldilocks_slice(input);
293 Self(Goldilocks::sum_array::<N>(g))
294 }
295
296 #[inline]
297 fn dot_product<const N: usize>(lhs: &[Self; N], rhs: &[Self; N]) -> Self {
298 let lhs_g = felts_as_goldilocks_array(lhs);
299 let rhs_g = felts_as_goldilocks_array(rhs);
300 Self(Goldilocks::dot_product(lhs_g, rhs_g))
301 }
302
303 #[inline]
304 fn zero_vec(len: usize) -> Vec<Self> {
305 unsafe { flatten_to_base(vec![0u64; len]) }
310 }
311}
312
313quotient_map_small_int!(Felt, u64, [u8, u16, u32]);
314quotient_map_small_int!(Felt, i64, [i8, i16, i32]);
315
316quotient_map_large_uint!(
317 Felt,
318 u64,
319 Felt::ORDER_U64,
320 "`[0, 2^64 - 2^32]`",
321 "`[0, 2^64 - 1]`",
322 [u128]
323);
324quotient_map_large_iint!(
325 Felt,
326 i64,
327 "`[-(2^63 - 2^31), 2^63 - 2^31]`",
328 "`[1 + 2^32 - 2^64, 2^64 - 1]`",
329 [(i128, u128)]
330);
331
332impl QuotientMap<u64> for Felt {
333 #[inline]
334 fn from_int(int: u64) -> Self {
335 Goldilocks::from_int(int).into()
336 }
337
338 #[inline]
339 fn from_canonical_checked(int: u64) -> Option<Self> {
340 Goldilocks::from_canonical_checked(int).map(From::from)
341 }
342
343 #[inline(always)]
344 unsafe fn from_canonical_unchecked(int: u64) -> Self {
345 Goldilocks::new(int).into()
346 }
347}
348
349impl QuotientMap<i64> for Felt {
350 #[inline]
351 fn from_int(int: i64) -> Self {
352 Goldilocks::from_int(int).into()
353 }
354
355 #[inline]
356 fn from_canonical_checked(int: i64) -> Option<Self> {
357 Goldilocks::from_canonical_checked(int).map(From::from)
358 }
359
360 #[inline(always)]
361 unsafe fn from_canonical_unchecked(int: i64) -> Self {
362 unsafe { Goldilocks::from_canonical_unchecked(int).into() }
363 }
364}
365
366impl PrimeField for Felt {
367 #[inline]
368 fn as_canonical_biguint(&self) -> BigUint {
369 <Goldilocks as PrimeField>::as_canonical_biguint(&self.0)
370 }
371}
372
373impl PrimeField64 for Felt {
374 const ORDER_U64: u64 = <Goldilocks as PrimeField64>::ORDER_U64;
375
376 #[inline]
377 fn as_canonical_u64(&self) -> u64 {
378 self.0.as_canonical_u64()
379 }
380}
381
382impl TwoAdicField for Felt {
383 const TWO_ADICITY: usize = <Goldilocks as TwoAdicField>::TWO_ADICITY;
384
385 #[inline]
386 fn two_adic_generator(bits: usize) -> Self {
387 Self(<Goldilocks as TwoAdicField>::two_adic_generator(bits))
388 }
389}
390
391impl ExtensionAlgebra<Self, 2, Binomial<Self>> for Felt {
395 #[inline]
396 fn ext_mul(a: &[Self; 2], b: &[Self; 2], res: &mut [Self; 2]) {
397 binomial_mul::<Self, Self, Self, 2>(a, b, res, <Self as BinomiallyExtendable<2>>::W);
398 }
399
400 #[inline]
401 fn ext_square(a: &[Self; 2], res: &mut [Self; 2]) {
402 binomial_square::<Self, Self, 2>(a, res, <Self as BinomiallyExtendable<2>>::W);
403 }
404}
405
406impl BinomiallyExtendable<2> for Felt {
407 fn binomial_algebra_id() -> Vec<u8> {
408 <Goldilocks as BinomiallyExtendable<2>>::binomial_algebra_id()
409 }
410
411 const W: Self = Self(<Goldilocks as BinomiallyExtendable<2>>::W);
412
413 const DTH_ROOT: Self = Self(<Goldilocks as BinomiallyExtendable<2>>::DTH_ROOT);
414
415 const EXT_GENERATOR: [Self; 2] = [
416 Self(<Goldilocks as BinomiallyExtendable<2>>::EXT_GENERATOR[0]),
417 Self(<Goldilocks as BinomiallyExtendable<2>>::EXT_GENERATOR[1]),
418 ];
419}
420
421impl HasTwoAdicBinomialExtension<2> for Felt {
422 const EXT_TWO_ADICITY: usize = <Goldilocks as HasTwoAdicBinomialExtension<2>>::EXT_TWO_ADICITY;
423
424 #[inline]
425 fn ext_two_adic_generator(bits: usize) -> [Self; 2] {
426 let [a, b] = <Goldilocks as HasTwoAdicBinomialExtension<2>>::ext_two_adic_generator(bits);
427 [Self(a), Self(b)]
428 }
429}
430
431impl ExtensionAlgebra<Self, 5, Binomial<Self>> for Felt {
432 #[inline]
433 fn ext_mul(a: &[Self; 5], b: &[Self; 5], res: &mut [Self; 5]) {
434 binomial_mul::<Self, Self, Self, 5>(a, b, res, <Self as BinomiallyExtendable<5>>::W);
435 }
436
437 #[inline]
438 fn ext_square(a: &[Self; 5], res: &mut [Self; 5]) {
439 binomial_square::<Self, Self, 5>(a, res, <Self as BinomiallyExtendable<5>>::W);
440 }
441}
442
443impl BinomiallyExtendable<5> for Felt {
444 fn binomial_algebra_id() -> Vec<u8> {
445 <Goldilocks as BinomiallyExtendable<5>>::binomial_algebra_id()
446 }
447
448 const W: Self = Self(<Goldilocks as BinomiallyExtendable<5>>::W);
449
450 const DTH_ROOT: Self = Self(<Goldilocks as BinomiallyExtendable<5>>::DTH_ROOT);
451
452 const EXT_GENERATOR: [Self; 5] = [
453 Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[0]),
454 Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[1]),
455 Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[2]),
456 Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[3]),
457 Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[4]),
458 ];
459}
460
461impl HasTwoAdicBinomialExtension<5> for Felt {
462 const EXT_TWO_ADICITY: usize = <Goldilocks as HasTwoAdicBinomialExtension<5>>::EXT_TWO_ADICITY;
463
464 #[inline]
465 fn ext_two_adic_generator(bits: usize) -> [Self; 5] {
466 let ext_generator =
467 <Goldilocks as HasTwoAdicBinomialExtension<5>>::ext_two_adic_generator(bits);
468 [
469 Self(ext_generator[0]),
470 Self(ext_generator[1]),
471 Self(ext_generator[2]),
472 Self(ext_generator[3]),
473 Self(ext_generator[4]),
474 ]
475 }
476}
477
478impl RawDataSerializable for Felt {
479 impl_raw_serializable_primefield64!();
480}
481
482impl Distribution<Felt> for StandardUniform {
483 #[inline]
484 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Felt {
485 let inner = <StandardUniform as Distribution<Goldilocks>>::sample(self, rng);
486 Felt(inner)
487 }
488}
489
490impl UniformSamplingField for Felt {
491 const MAX_SINGLE_SAMPLE_BITS: usize =
492 <Goldilocks as UniformSamplingField>::MAX_SINGLE_SAMPLE_BITS;
493 const SAMPLING_BITS_M: [u64; 64] = <Goldilocks as UniformSamplingField>::SAMPLING_BITS_M;
494}
495
496impl InjectiveMonomial<7> for Felt {}
497
498impl PermutationMonomial<7> for Felt {
499 #[inline]
500 fn injective_exp_root_n(&self) -> Self {
501 Self(self.0.injective_exp_root_n())
502 }
503}
504
505impl From<u8> for Felt {
509 fn from(int: u8) -> Self {
510 Self::from_u8(int)
511 }
512}
513
514impl From<u16> for Felt {
515 fn from(int: u16) -> Self {
516 Self::from_u16(int)
517 }
518}
519
520impl From<u32> for Felt {
521 fn from(int: u32) -> Self {
522 Self::from_u32(int)
523 }
524}
525
526impl TryFrom<u64> for Felt {
527 type Error = FeltFromIntError;
528
529 fn try_from(int: u64) -> Result<Felt, Self::Error> {
530 Felt::new(int)
531 }
532}
533
534#[derive(Debug, thiserror::Error)]
535#[error("integer {0} is equal to or exceeds the felt modulus {modulus}", modulus = Felt::ORDER)]
536pub struct FeltFromIntError(u64);
537
538impl FeltFromIntError {
539 pub fn as_u64(&self) -> u64 {
541 self.0
542 }
543}
544
545impl From<Goldilocks> for Felt {
546 #[inline]
547 fn from(value: Goldilocks) -> Self {
548 Self(value)
549 }
550}
551
552impl From<Felt> for Goldilocks {
553 #[inline]
554 fn from(value: Felt) -> Self {
555 value.0
556 }
557}
558
559impl Add for Felt {
563 type Output = Self;
564
565 #[inline]
566 fn add(self, other: Self) -> Self {
567 Self(self.0 + other.0)
568 }
569}
570
571impl AddAssign for Felt {
572 #[inline]
573 fn add_assign(&mut self, other: Self) {
574 *self = *self + other;
575 }
576}
577
578impl Sub for Felt {
579 type Output = Self;
580
581 #[inline]
582 fn sub(self, other: Self) -> Self {
583 Self(self.0 - other.0)
584 }
585}
586
587impl SubAssign for Felt {
588 #[inline]
589 fn sub_assign(&mut self, other: Self) {
590 *self = *self - other;
591 }
592}
593
594impl Mul for Felt {
595 type Output = Self;
596
597 #[inline]
598 fn mul(self, other: Self) -> Self {
599 Self(self.0 * other.0)
600 }
601}
602
603impl MulAssign for Felt {
604 #[inline]
605 fn mul_assign(&mut self, other: Self) {
606 *self = *self * other;
607 }
608}
609
610impl Div for Felt {
611 type Output = Self;
612
613 #[inline]
614 fn div(self, other: Self) -> Self {
615 Self(self.0 / other.0)
616 }
617}
618
619impl DivAssign for Felt {
620 #[inline]
621 fn div_assign(&mut self, other: Self) {
622 *self = *self / other;
623 }
624}
625
626impl Neg for Felt {
627 type Output = Self;
628
629 #[inline]
630 fn neg(self) -> Self {
631 Self(-self.0)
632 }
633}
634
635impl Sum for Felt {
636 #[inline]
637 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
638 Self(iter.map(|x| x.0).sum())
639 }
640}
641
642impl<'a> Sum<&'a Felt> for Felt {
643 #[inline]
644 fn sum<I: Iterator<Item = &'a Felt>>(iter: I) -> Self {
645 Self(iter.map(|x| x.0).sum())
646 }
647}
648
649impl Product for Felt {
650 #[inline]
651 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
652 Self(iter.map(|x| x.0).product())
653 }
654}
655
656impl<'a> Product<&'a Felt> for Felt {
657 #[inline]
658 fn product<I: Iterator<Item = &'a Felt>>(iter: I) -> Self {
659 Self(iter.map(|x| x.0).product())
660 }
661}
662
663impl PartialEq for Felt {
667 #[inline]
668 fn eq(&self, other: &Self) -> bool {
669 self.0 == other.0
670 }
671}
672
673impl PartialEq<Goldilocks> for Felt {
674 #[inline]
675 fn eq(&self, other: &Goldilocks) -> bool {
676 self.0 == *other
677 }
678}
679
680impl Eq for Felt {}
681
682impl PartialOrd for Felt {
683 #[inline]
684 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
685 Some(self.cmp(other))
686 }
687}
688
689impl Ord for Felt {
690 #[inline]
691 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
692 self.0.cmp(&other.0)
693 }
694}
695
696impl Serializable for Felt {
700 fn write_into<W: ByteWriter>(&self, target: &mut W) {
701 target.write_u64(self.as_canonical_u64());
702 }
703
704 fn get_size_hint(&self) -> usize {
705 size_of::<u64>()
706 }
707}
708
709impl Deserializable for Felt {
710 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
711 let value = source.read_u64()?;
712 Self::from_canonical_checked(value).ok_or_else(|| {
713 DeserializationError::InvalidValue(format!("value {value} is not a valid felt"))
714 })
715 }
716}
717
718#[cfg(all(any(test, feature = "arbitrary"), not(all(target_family = "wasm", miden))))]
722mod arbitrary {
723 use proptest::prelude::*;
724
725 use super::Felt;
726
727 impl Arbitrary for Felt {
728 type Parameters = ();
729 type Strategy = BoxedStrategy<Self>;
730
731 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
732 prop_oneof![4 => arb_felt_canonical(), 1 => arb_felt_noncanonical()].boxed()
733 }
734 }
735
736 pub fn arb_felt_canonical() -> impl Strategy<Value = Felt> {
738 (0u64..Felt::ORDER).prop_map(Felt::new_unchecked)
739 }
740
741 pub fn arb_felt_noncanonical() -> impl Strategy<Value = Felt> {
743 (Felt::ORDER..=u64::MAX).prop_map(Felt::new_unchecked)
744 }
745}
746
747#[cfg(all(any(test, feature = "arbitrary"), not(all(target_family = "wasm", miden))))]
748pub use arbitrary::{arb_felt_canonical, arb_felt_noncanonical};