Skip to main content

miden_field/native/
mod.rs

1//! Off-chain implementation of [`crate::Felt`].
2
3use alloc::format;
4use core::{
5    array, fmt,
6    hash::{Hash, Hasher},
7    iter::{Product, Sum},
8    ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
9};
10
11use miden_serde_utils::{
12    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
13};
14use num_bigint::BigUint;
15use p3_challenger::UniformSamplingField;
16use p3_field::{
17    Field, InjectiveMonomial, Packable, PermutationMonomial, PrimeCharacteristicRing, PrimeField,
18    PrimeField64, RawDataSerializable, TwoAdicField,
19    extension::{BinomiallyExtendable, BinomiallyExtendableAlgebra, HasTwoAdicBinomialExtension},
20    impl_raw_serializable_primefield64,
21    integers::QuotientMap,
22    quotient_map_large_iint, quotient_map_large_uint, quotient_map_small_int,
23};
24use p3_goldilocks::Goldilocks;
25use rand::{
26    Rng,
27    distr::{Distribution, StandardUniform},
28};
29use subtle::{ConditionallySelectable, ConstantTimeLess};
30
31#[cfg(test)]
32mod tests;
33
34// FELT
35// ================================================================================================
36
37/// A `Felt` backed by Plonky3's Goldilocks field element.
38#[derive(Copy, Clone, Default, serde::Serialize, serde::Deserialize)]
39#[repr(transparent)]
40pub struct Felt(Goldilocks);
41
42impl Felt {
43    /// Order of the field.
44    pub const ORDER: u64 = <Goldilocks as PrimeField64>::ORDER_U64;
45
46    pub const ZERO: Self = Self(Goldilocks::ZERO);
47    pub const ONE: Self = Self(Goldilocks::ONE);
48
49    /// The number of bytes which this field element occupies in memory.
50    pub const NUM_BYTES: usize = Goldilocks::NUM_BYTES;
51
52    /// Creates a new field element from any `u64`.
53    ///
54    /// Any `u64` value is accepted. No reduction is performed since Goldilocks uses a
55    /// non-canonical internal representation.
56    #[inline]
57    pub const fn new(value: u64) -> Self {
58        Self(Goldilocks::new(value))
59    }
60
61    #[inline]
62    pub fn from_u8(value: u8) -> Self {
63        <Self as PrimeCharacteristicRing>::from_u8(value)
64    }
65
66    #[inline]
67    pub fn from_u16(value: u16) -> Self {
68        <Self as PrimeCharacteristicRing>::from_u16(value)
69    }
70
71    #[inline]
72    pub fn from_u32(value: u32) -> Self {
73        <Self as PrimeCharacteristicRing>::from_u32(value)
74    }
75
76    /// The elementary function `double(a) = 2*a`.
77    #[inline]
78    pub fn double(&self) -> Self {
79        <Self as PrimeCharacteristicRing>::double(self)
80    }
81
82    /// The elementary function `square(a) = a^2`.
83    #[inline]
84    pub fn square(&self) -> Self {
85        <Self as PrimeCharacteristicRing>::square(self)
86    }
87
88    /// Exponentiation by a `u64` power.
89    #[inline]
90    pub fn exp_u64(&self, power: u64) -> Self {
91        <Self as PrimeCharacteristicRing>::exp_u64(self, power)
92    }
93
94    /// Exponentiation by a small constant power.
95    #[inline]
96    pub fn exp_const_u64<const POWER: u64>(&self) -> Self {
97        <Self as PrimeCharacteristicRing>::exp_const_u64::<POWER>(self)
98    }
99
100    /// Return the representative of element in canonical form which lies in the range
101    /// `0 <= x < ORDER`.
102    #[inline]
103    pub fn as_canonical_u64(&self) -> u64 {
104        <Self as PrimeField64>::as_canonical_u64(self)
105    }
106
107    /// Constant-time equivalent of `as_canonical_u64()` using the same reduction logic as
108    /// Plonky3's Goldilocks implementation.
109    #[inline]
110    pub fn as_canonical_u64_ct(&self) -> u64 {
111        let raw = raw_felt_u64(self);
112        // Mirrors Goldilocks::as_canonical_u64: conditional subtraction of ORDER.
113        // A single subtraction is sufficient for any u64 value since 2*ORDER > u64::MAX.
114        let reduced = raw.wrapping_sub(Self::ORDER);
115        let reduce = !raw.ct_lt(&Self::ORDER);
116        u64::conditional_select(&raw, &reduced, reduce)
117    }
118}
119
120#[inline]
121fn raw_felt_u64(value: &Felt) -> u64 {
122    const _: () = {
123        assert!(core::mem::size_of::<Felt>() == core::mem::size_of::<u64>());
124        assert!(core::mem::align_of::<Felt>() == core::mem::align_of::<u64>());
125        assert!(2u128 * (Felt::ORDER as u128) > u64::MAX as u128);
126    };
127    // SAFETY: Felt is repr(transparent) over Goldilocks, which is repr(transparent) over u64.
128    unsafe { core::mem::transmute_copy(value) }
129}
130
131impl fmt::Display for Felt {
132    #[inline]
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        fmt::Display::fmt(&self.0, f)
135    }
136}
137
138impl fmt::Debug for Felt {
139    #[inline]
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        fmt::Debug::fmt(&self.0, f)
142    }
143}
144
145impl Hash for Felt {
146    #[inline]
147    fn hash<H: Hasher>(&self, state: &mut H) {
148        state.write_u64(self.as_canonical_u64());
149    }
150}
151
152// FIELD
153// ================================================================================================
154
155impl Field for Felt {
156    type Packing = Self;
157
158    const GENERATOR: Self = Self(Goldilocks::GENERATOR);
159
160    #[inline]
161    fn is_zero(&self) -> bool {
162        self.0.is_zero()
163    }
164
165    #[inline]
166    fn try_inverse(&self) -> Option<Self> {
167        self.0.try_inverse().map(Self)
168    }
169
170    #[inline]
171    fn order() -> BigUint {
172        <Goldilocks as Field>::order()
173    }
174}
175
176impl Packable for Felt {}
177
178impl PrimeCharacteristicRing for Felt {
179    type PrimeSubfield = Goldilocks;
180
181    const ZERO: Self = Self(Goldilocks::ZERO);
182    const ONE: Self = Self(Goldilocks::ONE);
183    const TWO: Self = Self(Goldilocks::TWO);
184    const NEG_ONE: Self = Self(Goldilocks::NEG_ONE);
185
186    #[inline]
187    fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
188        Self(f)
189    }
190
191    #[inline]
192    fn from_bool(value: bool) -> Self {
193        Self::new(value.into())
194    }
195
196    #[inline]
197    fn halve(&self) -> Self {
198        Self(self.0.halve())
199    }
200
201    #[inline]
202    fn mul_2exp_u64(&self, exp: u64) -> Self {
203        Self(self.0.mul_2exp_u64(exp))
204    }
205
206    #[inline]
207    fn div_2exp_u64(&self, exp: u64) -> Self {
208        Self(self.0.div_2exp_u64(exp))
209    }
210
211    #[inline]
212    fn exp_u64(&self, power: u64) -> Self {
213        self.0.exp_u64(power).into()
214    }
215}
216
217quotient_map_small_int!(Felt, u64, [u8, u16, u32]);
218quotient_map_small_int!(Felt, i64, [i8, i16, i32]);
219
220quotient_map_large_uint!(
221    Felt,
222    u64,
223    Felt::ORDER_U64,
224    "`[0, 2^64 - 2^32]`",
225    "`[0, 2^64 - 1]`",
226    [u128]
227);
228quotient_map_large_iint!(
229    Felt,
230    i64,
231    "`[-(2^63 - 2^31), 2^63 - 2^31]`",
232    "`[1 + 2^32 - 2^64, 2^64 - 1]`",
233    [(i128, u128)]
234);
235
236impl QuotientMap<u64> for Felt {
237    #[inline]
238    fn from_int(int: u64) -> Self {
239        Goldilocks::from_int(int).into()
240    }
241
242    #[inline]
243    fn from_canonical_checked(int: u64) -> Option<Self> {
244        Goldilocks::from_canonical_checked(int).map(From::from)
245    }
246
247    #[inline(always)]
248    unsafe fn from_canonical_unchecked(int: u64) -> Self {
249        Goldilocks::new(int).into()
250    }
251}
252
253impl QuotientMap<i64> for Felt {
254    #[inline]
255    fn from_int(int: i64) -> Self {
256        Goldilocks::from_int(int).into()
257    }
258
259    #[inline]
260    fn from_canonical_checked(int: i64) -> Option<Self> {
261        Goldilocks::from_canonical_checked(int).map(From::from)
262    }
263
264    #[inline(always)]
265    unsafe fn from_canonical_unchecked(int: i64) -> Self {
266        unsafe { Goldilocks::from_canonical_unchecked(int).into() }
267    }
268}
269
270impl PrimeField for Felt {
271    #[inline]
272    fn as_canonical_biguint(&self) -> BigUint {
273        <Goldilocks as PrimeField>::as_canonical_biguint(&self.0)
274    }
275}
276
277impl PrimeField64 for Felt {
278    const ORDER_U64: u64 = <Goldilocks as PrimeField64>::ORDER_U64;
279
280    #[inline]
281    fn as_canonical_u64(&self) -> u64 {
282        self.0.as_canonical_u64()
283    }
284}
285
286impl TwoAdicField for Felt {
287    const TWO_ADICITY: usize = <Goldilocks as TwoAdicField>::TWO_ADICITY;
288
289    #[inline]
290    fn two_adic_generator(bits: usize) -> Self {
291        Self(<Goldilocks as TwoAdicField>::two_adic_generator(bits))
292    }
293}
294
295// EXTENSION FIELDS
296// ================================================================================================
297
298impl BinomiallyExtendableAlgebra<Self, 2> for Felt {}
299
300impl BinomiallyExtendable<2> for Felt {
301    const W: Self = Self(<Goldilocks as BinomiallyExtendable<2>>::W);
302
303    const DTH_ROOT: Self = Self(<Goldilocks as BinomiallyExtendable<2>>::DTH_ROOT);
304
305    const EXT_GENERATOR: [Self; 2] = [
306        Self(<Goldilocks as BinomiallyExtendable<2>>::EXT_GENERATOR[0]),
307        Self(<Goldilocks as BinomiallyExtendable<2>>::EXT_GENERATOR[1]),
308    ];
309}
310
311impl HasTwoAdicBinomialExtension<2> for Felt {
312    const EXT_TWO_ADICITY: usize = <Goldilocks as HasTwoAdicBinomialExtension<2>>::EXT_TWO_ADICITY;
313
314    #[inline]
315    fn ext_two_adic_generator(bits: usize) -> [Self; 2] {
316        let [a, b] = <Goldilocks as HasTwoAdicBinomialExtension<2>>::ext_two_adic_generator(bits);
317        [Self(a), Self(b)]
318    }
319}
320
321impl BinomiallyExtendableAlgebra<Self, 5> for Felt {}
322
323impl BinomiallyExtendable<5> for Felt {
324    const W: Self = Self(<Goldilocks as BinomiallyExtendable<5>>::W);
325
326    const DTH_ROOT: Self = Self(<Goldilocks as BinomiallyExtendable<5>>::DTH_ROOT);
327
328    const EXT_GENERATOR: [Self; 5] = [
329        Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[0]),
330        Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[1]),
331        Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[2]),
332        Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[3]),
333        Self(<Goldilocks as BinomiallyExtendable<5>>::EXT_GENERATOR[4]),
334    ];
335}
336
337impl HasTwoAdicBinomialExtension<5> for Felt {
338    const EXT_TWO_ADICITY: usize = <Goldilocks as HasTwoAdicBinomialExtension<5>>::EXT_TWO_ADICITY;
339
340    #[inline]
341    fn ext_two_adic_generator(bits: usize) -> [Self; 5] {
342        let ext_generator =
343            <Goldilocks as HasTwoAdicBinomialExtension<5>>::ext_two_adic_generator(bits);
344        [
345            Self(ext_generator[0]),
346            Self(ext_generator[1]),
347            Self(ext_generator[2]),
348            Self(ext_generator[3]),
349            Self(ext_generator[4]),
350        ]
351    }
352}
353
354impl RawDataSerializable for Felt {
355    impl_raw_serializable_primefield64!();
356}
357
358impl Distribution<Felt> for StandardUniform {
359    #[inline]
360    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Felt {
361        let inner = <StandardUniform as Distribution<Goldilocks>>::sample(self, rng);
362        Felt(inner)
363    }
364}
365
366impl UniformSamplingField for Felt {
367    const MAX_SINGLE_SAMPLE_BITS: usize =
368        <Goldilocks as UniformSamplingField>::MAX_SINGLE_SAMPLE_BITS;
369    const SAMPLING_BITS_M: [u64; 64] = <Goldilocks as UniformSamplingField>::SAMPLING_BITS_M;
370}
371
372impl InjectiveMonomial<7> for Felt {}
373
374impl PermutationMonomial<7> for Felt {
375    #[inline]
376    fn injective_exp_root_n(&self) -> Self {
377        Self(self.0.injective_exp_root_n())
378    }
379}
380
381// CONVERSIONS
382// ================================================================================================
383
384impl From<u8> for Felt {
385    fn from(int: u8) -> Self {
386        Self::from_u8(int)
387    }
388}
389
390impl From<u16> for Felt {
391    fn from(int: u16) -> Self {
392        Self::from_u16(int)
393    }
394}
395
396impl From<u32> for Felt {
397    fn from(int: u32) -> Self {
398        Self::from_u32(int)
399    }
400}
401
402impl TryFrom<u64> for Felt {
403    type Error = FeltFromIntError;
404
405    fn try_from(int: u64) -> Result<Felt, Self::Error> {
406        Felt::from_canonical_checked(int).ok_or(FeltFromIntError(int))
407    }
408}
409
410#[derive(Debug, thiserror::Error)]
411#[error("integer {0} is equal to or exceeds the felt modulus {modulus}", modulus = Felt::ORDER)]
412pub struct FeltFromIntError(u64);
413
414impl FeltFromIntError {
415    /// Returns the integer for which the conversion failed.
416    pub fn as_u64(&self) -> u64 {
417        self.0
418    }
419}
420
421impl Deref for Felt {
422    type Target = Goldilocks;
423
424    #[inline]
425    fn deref(&self) -> &Self::Target {
426        &self.0
427    }
428}
429
430impl DerefMut for Felt {
431    #[inline]
432    fn deref_mut(&mut self) -> &mut Self::Target {
433        &mut self.0
434    }
435}
436
437impl From<Goldilocks> for Felt {
438    #[inline]
439    fn from(value: Goldilocks) -> Self {
440        Self(value)
441    }
442}
443
444impl From<Felt> for Goldilocks {
445    #[inline]
446    fn from(value: Felt) -> Self {
447        value.0
448    }
449}
450
451// ARITHMETIC OPERATIONS
452// ================================================================================================
453
454impl Add for Felt {
455    type Output = Self;
456
457    #[inline]
458    fn add(self, other: Self) -> Self {
459        Self(self.0 + other.0)
460    }
461}
462
463impl AddAssign for Felt {
464    #[inline]
465    fn add_assign(&mut self, other: Self) {
466        *self = *self + other;
467    }
468}
469
470impl Sub for Felt {
471    type Output = Self;
472
473    #[inline]
474    fn sub(self, other: Self) -> Self {
475        Self(self.0 - other.0)
476    }
477}
478
479impl SubAssign for Felt {
480    #[inline]
481    fn sub_assign(&mut self, other: Self) {
482        *self = *self - other;
483    }
484}
485
486impl Mul for Felt {
487    type Output = Self;
488
489    #[inline]
490    fn mul(self, other: Self) -> Self {
491        Self(self.0 * other.0)
492    }
493}
494
495impl MulAssign for Felt {
496    #[inline]
497    fn mul_assign(&mut self, other: Self) {
498        *self = *self * other;
499    }
500}
501
502impl Div for Felt {
503    type Output = Self;
504
505    #[inline]
506    fn div(self, other: Self) -> Self {
507        Self(self.0 / other.0)
508    }
509}
510
511impl DivAssign for Felt {
512    #[inline]
513    fn div_assign(&mut self, other: Self) {
514        *self = *self / other;
515    }
516}
517
518impl Neg for Felt {
519    type Output = Self;
520
521    #[inline]
522    fn neg(self) -> Self {
523        Self(-self.0)
524    }
525}
526
527impl Sum for Felt {
528    #[inline]
529    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
530        Self(iter.map(|x| x.0).sum())
531    }
532}
533
534impl<'a> Sum<&'a Felt> for Felt {
535    #[inline]
536    fn sum<I: Iterator<Item = &'a Felt>>(iter: I) -> Self {
537        Self(iter.map(|x| x.0).sum())
538    }
539}
540
541impl Product for Felt {
542    #[inline]
543    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
544        Self(iter.map(|x| x.0).product())
545    }
546}
547
548impl<'a> Product<&'a Felt> for Felt {
549    #[inline]
550    fn product<I: Iterator<Item = &'a Felt>>(iter: I) -> Self {
551        Self(iter.map(|x| x.0).product())
552    }
553}
554
555// EQUALITY AND COMPARISON OPERATIONS
556// ================================================================================================
557
558impl PartialEq for Felt {
559    #[inline]
560    fn eq(&self, other: &Self) -> bool {
561        self.0 == other.0
562    }
563}
564
565impl PartialEq<Goldilocks> for Felt {
566    #[inline]
567    fn eq(&self, other: &Goldilocks) -> bool {
568        self.0 == *other
569    }
570}
571
572impl Eq for Felt {}
573
574impl PartialOrd for Felt {
575    #[inline]
576    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
577        Some(self.cmp(other))
578    }
579}
580
581impl Ord for Felt {
582    #[inline]
583    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
584        self.0.cmp(&other.0)
585    }
586}
587
588// SERIALIZATION
589// ================================================================================================
590
591impl Serializable for Felt {
592    fn write_into<W: ByteWriter>(&self, target: &mut W) {
593        target.write_u64(self.as_canonical_u64());
594    }
595
596    fn get_size_hint(&self) -> usize {
597        core::mem::size_of::<u64>()
598    }
599}
600
601impl Deserializable for Felt {
602    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
603        let value = source.read_u64()?;
604        Self::from_canonical_checked(value).ok_or_else(|| {
605            DeserializationError::InvalidValue(format!("value {value} is not a valid felt"))
606        })
607    }
608}
609
610// ARBITRARY (proptest)
611// ================================================================================================
612
613#[cfg(all(any(test, feature = "testing"), not(all(target_family = "wasm", miden))))]
614mod arbitrary {
615    use proptest::prelude::*;
616
617    use super::Felt;
618
619    impl Arbitrary for Felt {
620        type Parameters = ();
621        type Strategy = BoxedStrategy<Self>;
622
623        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
624            let canonical = (0u64..Felt::ORDER).prop_map(Felt::new).boxed();
625            // Goldilocks uses representation where values above the field order are valid and
626            // represent wrapped field elements. Generate such values 1/5 of the time to exercise
627            // this behavior.
628            let non_canonical = (Felt::ORDER..=u64::MAX).prop_map(Felt::new).boxed();
629            prop_oneof![4 => canonical, 1 => non_canonical].no_shrink().boxed()
630        }
631    }
632}