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