Skip to main content

primefield/
monty.rs

1//! Field elements which use an internal Montgomery form representation, implemented using
2//! `crypto-bigint`'s [`MontyForm`].
3
4use crate::ByteOrder;
5use bigint::{
6    ArrayEncoding, ByteArray, Invert, Reduce, Uint, Word, ctutils,
7    hybrid_array::{Array, ArraySize, typenum::Unsigned},
8    modular::{
9        ConstMontyForm as MontyForm, ConstMontyParams, ConstPrimeMontyParams, FixedMontyParams,
10        Retrieve,
11    },
12};
13use common::Generate;
14use core::{
15    cmp::Ordering,
16    fmt,
17    iter::{Product, Sum},
18    ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
19};
20use ff::{Field, PrimeField};
21use rand_core::TryCryptoRng;
22use subtle::{
23    Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
24    CtOption,
25};
26
27/// Extension trait for defining additional field parameters beyond the ones provided by
28/// [`ConstMontyPrimeParams`].
29pub trait MontyFieldParams<const LIMBS: usize>: ConstPrimeMontyParams<LIMBS> {
30    /// Size of a field element when serialized as bytes.
31    type ByteSize: ArraySize;
32
33    /// Byte order to use when serializing a field element as byte.
34    const BYTE_ORDER: ByteOrder;
35
36    /// Field modulus as a hexadecimal string.
37    const MODULUS_HEX: &'static str;
38
39    /// `T = (modulus - 1) >> S`, where `S = (modulus - 1).trailing_zeros()`
40    const T: Uint<LIMBS>;
41}
42
43/// Serialized representation of a field element.
44pub type MontyFieldBytes<MOD, const LIMBS: usize> =
45    Array<u8, <MOD as MontyFieldParams<LIMBS>>::ByteSize>;
46
47/// Field element type which uses an internal Montgomery form representation.
48#[derive(Clone, Copy)]
49pub struct MontyFieldElement<MOD, const LIMBS: usize>
50where
51    MOD: MontyFieldParams<LIMBS>,
52{
53    inner: MontyForm<MOD, LIMBS>,
54}
55
56impl<MOD, const LIMBS: usize> MontyFieldElement<MOD, LIMBS>
57where
58    MOD: MontyFieldParams<LIMBS>,
59{
60    /// Zero element (additive identity).
61    pub const ZERO: Self = Self {
62        inner: MontyForm::ZERO,
63    };
64
65    /// Multiplicative identity.
66    pub const ONE: Self = Self {
67        inner: MontyForm::ONE,
68    };
69
70    /// Number of limbs used by the internal integer representation.
71    pub const LIMBS: usize = LIMBS;
72
73    /// Decode field element from a canonical bytestring representation.
74    #[inline]
75    pub fn from_bytes(repr: &MontyFieldBytes<MOD, LIMBS>) -> CtOption<Self>
76    where
77        Uint<LIMBS>: ArrayEncoding,
78    {
79        let mut byte_array = ByteArray::<Uint<LIMBS>>::default();
80        debug_assert!(repr.len() <= byte_array.len());
81
82        let offset = byte_array.len().saturating_sub(repr.len());
83        let uint = match MOD::BYTE_ORDER {
84            ByteOrder::BigEndian => {
85                byte_array[offset..].copy_from_slice(repr);
86                Uint::from_be_byte_array(byte_array)
87            }
88            ByteOrder::LittleEndian => {
89                // For little-endian encoding we place the serialized bytes starting
90                // from the least-significant end of the buffer.
91                //
92                // `repr` is at most as large as the underlying `Uint` byte size
93                // (see `MontyFieldParams::ByteSize`), so this slice is valid.
94                byte_array[..repr.len()].copy_from_slice(repr);
95                Uint::from_le_byte_array(byte_array)
96            }
97        };
98
99        Self::from_uint(&uint)
100    }
101
102    /// Decode field element from a canonical byte slice.
103    ///
104    /// Slice is expected to be zero padded to the expected byte size.
105    #[inline]
106    #[must_use]
107    pub fn from_slice(slice: &[u8]) -> Option<Self>
108    where
109        Uint<LIMBS>: ArrayEncoding,
110    {
111        let array = Array::try_from(slice).ok()?;
112        Self::from_bytes(&array).into()
113    }
114
115    /// Decode a field element from hex-encoded bytes.
116    ///
117    /// This is primarily intended for defining constants using hex literals.
118    ///
119    /// # Panics
120    ///
121    /// - When hex is malformed
122    /// - When input is the wrong length
123    /// - If input overflows the modulus
124    #[must_use]
125    pub const fn from_hex_vartime(hex: &str) -> Self {
126        let uint = match MOD::BYTE_ORDER {
127            ByteOrder::BigEndian => Uint::from_be_hex(hex),
128            ByteOrder::LittleEndian => Uint::from_le_hex(hex),
129        };
130
131        assert!(
132            uint.cmp_vartime(MOD::PARAMS.modulus().as_ref()).is_lt(),
133            "hex encoded field element overflows modulus"
134        );
135
136        Self::from_uint_reduced(&uint)
137    }
138
139    /// Convert [`Uint`] into [`MontyFieldElement`], first converting it into Montgomery form:
140    ///
141    /// ```text
142    /// w * R^2 * R^-1 mod p = wR mod p
143    /// ```
144    ///
145    /// Reduces the input modulo `p`.
146    #[inline]
147    #[must_use]
148    pub const fn from_uint_reduced(uint: &Uint<LIMBS>) -> Self {
149        Self {
150            inner: MontyForm::new(uint),
151        }
152    }
153
154    /// Convert [`Uint`] into [`MontyFieldElement`], first converting it into Montgomery form:
155    ///
156    /// ```text
157    /// w * R^2 * R^-1 mod p = wR mod p
158    /// ```
159    ///
160    /// # Returns
161    ///
162    /// The `CtOption` equivalent of `None` if the input overflows the modulus.
163    #[inline]
164    #[must_use]
165    pub fn from_uint(uint: &Uint<LIMBS>) -> CtOption<Self> {
166        let is_some = ctutils::CtLt::ct_lt(uint, MOD::PARAMS.modulus());
167
168        // TODO(tarcieri): avoid unnecessary reduction here
169        CtOption::new(Self::from_uint_reduced(uint), is_some.into())
170    }
171
172    /// Convert a `u32` into a [`MontyFieldElement`].
173    ///
174    /// # Panics
175    ///
176    /// If the modulus is 32-bits or smaller.
177    #[inline]
178    #[must_use]
179    pub const fn from_u32(w: u32) -> Self {
180        assert!(
181            MOD::PARAMS.modulus().as_ref().bits() > 32,
182            "modulus is too small to ensure all u32s are in range"
183        );
184
185        Self::from_uint_reduced(&Uint::from_u32(w))
186    }
187
188    /// Convert a `u64` into a [`MontyFieldElement`].
189    ///
190    /// # Panics
191    ///
192    /// If the modulus is 64-bits or smaller.
193    #[inline]
194    #[must_use]
195    pub const fn from_u64(w: u64) -> Self {
196        assert!(
197            MOD::PARAMS.modulus().as_ref().bits() > 64,
198            "modulus is too small to ensure all u64s are in range"
199        );
200
201        Self::from_uint_reduced(&Uint::from_u64(w))
202    }
203
204    /// Create [`MontyFieldElement`] from a [`Uint`] which is already in Montgomery form.
205    ///
206    /// # ⚠️ Warning
207    ///
208    /// This value is expected to be in Montgomery form and reduced. Failure to maintain these
209    /// invariants will lead to miscomputation and potential security issues!
210    #[inline]
211    #[must_use]
212    pub const fn from_montgomery(uint: Uint<LIMBS>) -> Self {
213        Self {
214            inner: MontyForm::from_montgomery(uint),
215        }
216    }
217
218    /// Helper function to construct [`MontyFieldElement`] from words in Montgomery form.
219    // TODO(tarcieri): this is here to simplify the inner type conversion for fiat-crypto.
220    // After we've successfully done that, it would be good to try to remove this
221    #[inline]
222    #[must_use]
223    pub const fn from_montgomery_words(words: [Word; LIMBS]) -> Self {
224        Self::from_montgomery(Uint::from_words(words))
225    }
226
227    /// Borrow the inner [`Uint`] type which is in Montgomery form.
228    ///
229    /// # ⚠️ Warning
230    ///
231    /// Make sure you are actually expecting a value in Montgomery form! This is not the correct
232    /// function for converting *out* of Montgomery form: that would be
233    /// [`MontyFieldElement::to_canonical`].
234    #[must_use]
235    pub const fn as_montgomery(&self) -> &Uint<LIMBS> {
236        self.inner.as_montgomery()
237    }
238
239    /// Retrieve the Montgomery form representation as an array of [`Word`]s.
240    // TODO(tarcieri): like `from_montgomery_words`, phase this out after fiat-crypto is migrated
241    #[must_use]
242    pub const fn to_montgomery_words(&self) -> [Word; LIMBS] {
243        self.as_montgomery().to_words()
244    }
245
246    /// Returns the bytestring encoding of this field element.
247    #[inline]
248    #[must_use]
249    pub fn to_bytes(self) -> MontyFieldBytes<MOD, LIMBS>
250    where
251        MOD: MontyFieldParams<LIMBS>,
252        Uint<LIMBS>: ArrayEncoding,
253    {
254        let mut repr = MontyFieldBytes::<MOD, LIMBS>::default();
255        debug_assert!(repr.len() <= <Uint::<LIMBS> as ArrayEncoding>::ByteSize::USIZE);
256
257        let offset = <Uint<LIMBS> as ArrayEncoding>::ByteSize::USIZE.saturating_sub(repr.len());
258
259        match MOD::BYTE_ORDER {
260            ByteOrder::BigEndian => {
261                let padded = self.inner.retrieve().to_be_byte_array();
262                repr.copy_from_slice(&padded[offset..]);
263            }
264            ByteOrder::LittleEndian => {
265                let padded = self.inner.retrieve().to_le_byte_array();
266                // For little-endian encoding we expose the least-significant bytes
267                // at the beginning of the representation.
268                let len = repr.len();
269                repr.copy_from_slice(&padded[..len]);
270            }
271        }
272
273        repr
274    }
275
276    /// Determine if this field element is odd: `self mod 2 == 1`.
277    ///
278    /// # Returns
279    ///
280    /// If odd, return `Choice(1)`.  Otherwise, return `Choice(0)`.
281    #[inline]
282    #[must_use]
283    pub fn is_odd(&self) -> Choice {
284        self.inner.retrieve().is_odd().into()
285    }
286
287    /// Determine if this field element is even: `self mod 2 == 0`.
288    ///
289    /// # Returns
290    ///
291    /// If even, return `Choice(1)`.  Otherwise, return `Choice(0)`.
292    #[inline]
293    #[must_use]
294    pub fn is_even(&self) -> Choice {
295        !self.is_odd()
296    }
297
298    /// Determine if this field element is zero.
299    ///
300    /// # Returns
301    ///
302    /// If zero, return `Choice(1)`.  Otherwise, return `Choice(0)`.
303    #[inline]
304    #[must_use]
305    pub fn is_zero(&self) -> Choice {
306        self.ct_eq(&Self::ZERO)
307    }
308
309    /// Translate field element out of the Montgomery domain, returning a [`Uint`] in canonical form.
310    #[inline]
311    #[must_use]
312    pub const fn to_canonical(self) -> Uint<LIMBS> {
313        self.inner.retrieve()
314    }
315
316    /// Add elements.
317    #[inline]
318    #[must_use]
319    pub const fn add(&self, rhs: &Self) -> Self {
320        Self {
321            inner: MontyForm::add(&self.inner, &rhs.inner),
322        }
323    }
324
325    /// Double element (add it to itself).
326    #[inline]
327    #[must_use]
328    pub const fn double(&self) -> Self {
329        Self {
330            inner: MontyForm::double(&self.inner),
331        }
332    }
333
334    /// Subtract elements.
335    #[inline]
336    #[must_use]
337    pub const fn sub(&self, rhs: &Self) -> Self {
338        Self {
339            inner: MontyForm::sub(&self.inner, &rhs.inner),
340        }
341    }
342
343    /// Multiply elements.
344    #[inline]
345    #[must_use]
346    pub const fn multiply(&self, rhs: &Self) -> Self {
347        Self {
348            inner: MontyForm::mul(&self.inner, &rhs.inner),
349        }
350    }
351
352    /// Negate element.
353    #[inline]
354    #[must_use]
355    pub const fn neg(&self) -> Self {
356        Self {
357            inner: MontyForm::neg(&self.inner),
358        }
359    }
360
361    /// Compute modular square.
362    #[inline]
363    #[must_use]
364    pub const fn square(&self) -> Self {
365        Self {
366            inner: MontyForm::square(&self.inner),
367        }
368    }
369
370    /// Compute field inversion: `1 / self`.
371    #[inline]
372    #[must_use]
373    pub fn invert(&self) -> CtOption<Self> {
374        CtOption::from(self.inner.invert()).map(|inner| Self { inner })
375    }
376
377    /// Compute field inversion: `1 / self` in variable-time.
378    #[inline]
379    #[must_use]
380    pub fn invert_vartime(&self) -> CtOption<Self> {
381        CtOption::from(self.inner.invert_vartime()).map(|inner| Self { inner })
382    }
383
384    /// Compute field inversion as a `const fn`. Panics if `self` is zero.
385    ///
386    /// This is mainly intended for inverting constants at compile time.
387    #[must_use]
388    pub const fn const_invert(&self) -> Self {
389        Self {
390            inner: self
391                .inner
392                .invert()
393                .expect_copied("input to invert should be non-zero"),
394        }
395    }
396
397    /// Returns `self^exp`, where `exp` is a little-endian integer exponent.
398    ///
399    /// **This operation is variable time with respect to the exponent `exp`.**
400    ///
401    /// If `exp` is fixed, this operation is constant time. Note that `exp` will still be branched
402    /// upon and should NOT be a secret.
403    #[must_use]
404    pub const fn pow_vartime<const RHS_LIMBS: usize>(&self, exp: &Uint<RHS_LIMBS>) -> Self {
405        Self {
406            inner: self.inner.pow_vartime(exp),
407        }
408    }
409
410    /// Returns `self^(2^n) mod p`.
411    ///
412    /// **This operation is variable time with respect to the exponent `n`.**
413    ///
414    /// If the exponent is fixed, this operation is constant time.
415    #[must_use]
416    pub const fn sqn_vartime(&self, n: usize) -> Self {
417        let mut x = *self;
418        let mut i = 0;
419        while i < n {
420            x = x.square();
421            i += 1;
422        }
423        x
424    }
425}
426
427//
428// `ff` crate trait impls
429//
430
431impl<MOD, const LIMBS: usize> Field for MontyFieldElement<MOD, LIMBS>
432where
433    MOD: MontyFieldParams<LIMBS>,
434    MontyFieldBytes<MOD, LIMBS>: Copy,
435    Uint<LIMBS>: ArrayEncoding,
436{
437    const ZERO: Self = Self::ZERO;
438    const ONE: Self = Self::ONE;
439
440    fn try_random<R: rand_core::TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
441        let mut bytes = MontyFieldBytes::<MOD, LIMBS>::default();
442
443        loop {
444            rng.try_fill_bytes(&mut bytes)?;
445            if let Some(fe) = Self::from_bytes(&bytes).into() {
446                return Ok(fe);
447            }
448        }
449    }
450
451    fn is_zero(&self) -> Choice {
452        Self::ZERO.ct_eq(self)
453    }
454
455    fn square(&self) -> Self {
456        self.square()
457    }
458
459    fn double(&self) -> Self {
460        self.double()
461    }
462
463    fn invert(&self) -> CtOption<Self> {
464        self.invert()
465    }
466
467    fn sqrt(&self) -> CtOption<Self> {
468        self.inner.sqrt().map(|inner| Self { inner }).into()
469    }
470
471    fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
472        ff::helpers::sqrt_ratio_generic(num, div)
473    }
474}
475
476impl<MOD, const LIMBS: usize> PrimeField for MontyFieldElement<MOD, LIMBS>
477where
478    MOD: MontyFieldParams<LIMBS>,
479    MontyFieldBytes<MOD, LIMBS>: Copy,
480    Uint<LIMBS>: ArrayEncoding,
481{
482    type Repr = MontyFieldBytes<MOD, LIMBS>;
483
484    const MODULUS: &'static str = MOD::MODULUS_HEX;
485    const NUM_BITS: u32 = MOD::PARAMS.modulus().as_ref().bits_vartime();
486    const CAPACITY: u32 = Self::NUM_BITS - 1;
487    const TWO_INV: Self = Self::from_u64(2).const_invert();
488    const MULTIPLICATIVE_GENERATOR: Self = Self::from_u32(MOD::PRIME_PARAMS.generator().get());
489    const S: u32 = MOD::PRIME_PARAMS.s().get();
490    const ROOT_OF_UNITY: Self = Self::MULTIPLICATIVE_GENERATOR.pow_vartime(&MOD::T);
491    const ROOT_OF_UNITY_INV: Self = Self::ROOT_OF_UNITY.const_invert();
492    const DELTA: Self = Self::MULTIPLICATIVE_GENERATOR.sqn_vartime(Self::S as usize);
493
494    fn from_repr(bytes: Self::Repr) -> CtOption<Self> {
495        Self::from_bytes(&bytes)
496    }
497
498    fn to_repr(&self) -> Self::Repr {
499        self.to_bytes()
500    }
501
502    fn is_odd(&self) -> Choice {
503        self.is_odd()
504    }
505}
506
507//
508// Arithmetic trait impls
509//
510
511/// Emit a `core::ops` trait wrapper for an inherent method.
512macro_rules! monty_field_op {
513    ($op:tt, $func:ident, $inner_func:ident) => {
514        impl<MOD, const LIMBS: usize> $op for MontyFieldElement<MOD, LIMBS>
515        where
516            MOD: MontyFieldParams<LIMBS>,
517        {
518            type Output = MontyFieldElement<MOD, LIMBS>;
519
520            #[inline]
521            fn $func(self, rhs: MontyFieldElement<MOD, LIMBS>) -> MontyFieldElement<MOD, LIMBS> {
522                <MontyFieldElement<MOD, LIMBS>>::$inner_func(&self, &rhs)
523            }
524        }
525
526        impl<MOD, const LIMBS: usize> $op<&Self> for MontyFieldElement<MOD, LIMBS>
527        where
528            MOD: MontyFieldParams<LIMBS>,
529        {
530            type Output = MontyFieldElement<MOD, LIMBS>;
531
532            #[inline]
533            fn $func(self, rhs: &MontyFieldElement<MOD, LIMBS>) -> MontyFieldElement<MOD, LIMBS> {
534                <MontyFieldElement<MOD, LIMBS>>::$inner_func(&self, rhs)
535            }
536        }
537
538        impl<MOD, const LIMBS: usize> $op<Self> for &MontyFieldElement<MOD, LIMBS>
539        where
540            MOD: MontyFieldParams<LIMBS>,
541        {
542            type Output = MontyFieldElement<MOD, LIMBS>;
543
544            #[inline]
545            fn $func(self, rhs: &MontyFieldElement<MOD, LIMBS>) -> MontyFieldElement<MOD, LIMBS> {
546                <MontyFieldElement<MOD, LIMBS>>::$inner_func(self, rhs)
547            }
548        }
549    };
550}
551
552monty_field_op!(Add, add, add);
553monty_field_op!(Sub, sub, sub);
554monty_field_op!(Mul, mul, multiply);
555
556impl<MOD, const LIMBS: usize> AddAssign<Self> for MontyFieldElement<MOD, LIMBS>
557where
558    MOD: MontyFieldParams<LIMBS>,
559{
560    #[inline]
561    fn add_assign(&mut self, other: MontyFieldElement<MOD, LIMBS>) {
562        *self = *self + other;
563    }
564}
565
566impl<MOD, const LIMBS: usize> AddAssign<&Self> for MontyFieldElement<MOD, LIMBS>
567where
568    MOD: MontyFieldParams<LIMBS>,
569{
570    #[inline]
571    fn add_assign(&mut self, other: &MontyFieldElement<MOD, LIMBS>) {
572        *self = *self + other;
573    }
574}
575
576impl<MOD, const LIMBS: usize> SubAssign<Self> for MontyFieldElement<MOD, LIMBS>
577where
578    MOD: MontyFieldParams<LIMBS>,
579{
580    #[inline]
581    fn sub_assign(&mut self, other: MontyFieldElement<MOD, LIMBS>) {
582        *self = *self - other;
583    }
584}
585
586impl<MOD, const LIMBS: usize> SubAssign<&Self> for MontyFieldElement<MOD, LIMBS>
587where
588    MOD: MontyFieldParams<LIMBS>,
589{
590    #[inline]
591    fn sub_assign(&mut self, other: &MontyFieldElement<MOD, LIMBS>) {
592        *self = *self - other;
593    }
594}
595
596impl<MOD, const LIMBS: usize> MulAssign<&Self> for MontyFieldElement<MOD, LIMBS>
597where
598    MOD: MontyFieldParams<LIMBS>,
599{
600    #[inline]
601    fn mul_assign(&mut self, other: &MontyFieldElement<MOD, LIMBS>) {
602        *self = *self * other;
603    }
604}
605
606impl<MOD, const LIMBS: usize> MulAssign for MontyFieldElement<MOD, LIMBS>
607where
608    MOD: MontyFieldParams<LIMBS>,
609{
610    #[inline]
611    fn mul_assign(&mut self, other: MontyFieldElement<MOD, LIMBS>) {
612        *self = *self * other;
613    }
614}
615
616impl<MOD, const LIMBS: usize> Neg for MontyFieldElement<MOD, LIMBS>
617where
618    MOD: MontyFieldParams<LIMBS>,
619{
620    type Output = MontyFieldElement<MOD, LIMBS>;
621
622    #[inline]
623    fn neg(self) -> MontyFieldElement<MOD, LIMBS> {
624        <MontyFieldElement<MOD, LIMBS>>::neg(&self)
625    }
626}
627
628impl<MOD, const LIMBS: usize> Neg for &MontyFieldElement<MOD, LIMBS>
629where
630    MOD: MontyFieldParams<LIMBS>,
631{
632    type Output = MontyFieldElement<MOD, LIMBS>;
633
634    #[inline]
635    fn neg(self) -> MontyFieldElement<MOD, LIMBS> {
636        <MontyFieldElement<MOD, LIMBS>>::neg(self)
637    }
638}
639
640impl<MOD, const LIMBS: usize> Sum for MontyFieldElement<MOD, LIMBS>
641where
642    MOD: MontyFieldParams<LIMBS>,
643{
644    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
645        iter.reduce(Add::add).unwrap_or(Self::ZERO)
646    }
647}
648
649impl<'a, MOD, const LIMBS: usize> Sum<&'a Self> for MontyFieldElement<MOD, LIMBS>
650where
651    MOD: MontyFieldParams<LIMBS>,
652{
653    fn sum<I: Iterator<Item = &'a MontyFieldElement<MOD, LIMBS>>>(iter: I) -> Self {
654        iter.copied().sum()
655    }
656}
657
658impl<MOD, const LIMBS: usize> Product for MontyFieldElement<MOD, LIMBS>
659where
660    MOD: MontyFieldParams<LIMBS>,
661{
662    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
663        iter.reduce(Mul::mul).unwrap_or(Self::ONE)
664    }
665}
666
667impl<'a, MOD: MontyFieldParams<LIMBS>, const LIMBS: usize>
668    Product<&'a MontyFieldElement<MOD, LIMBS>> for MontyFieldElement<MOD, LIMBS>
669{
670    fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
671        iter.copied().product()
672    }
673}
674
675impl<MOD, const LIMBS: usize> Invert for MontyFieldElement<MOD, LIMBS>
676where
677    MOD: MontyFieldParams<LIMBS>,
678    MontyForm<MOD, LIMBS>: Invert<Output = CtOption<MontyForm<MOD, LIMBS>>>,
679{
680    type Output = CtOption<Self>;
681
682    fn invert(&self) -> CtOption<Self> {
683        Self::invert(self)
684    }
685
686    fn invert_vartime(&self) -> CtOption<Self> {
687        Self::invert_vartime(self)
688    }
689}
690
691impl<MOD, const LIMBS: usize> Reduce<Uint<LIMBS>> for MontyFieldElement<MOD, LIMBS>
692where
693    MOD: MontyFieldParams<LIMBS>,
694{
695    #[inline]
696    fn reduce(w: &Uint<LIMBS>) -> Self {
697        Self::from_uint_reduced(w)
698    }
699}
700
701impl<MOD, const LIMBS: usize> Reduce<MontyFieldBytes<MOD, LIMBS>> for MontyFieldElement<MOD, LIMBS>
702where
703    MOD: MontyFieldParams<LIMBS>,
704    Uint<LIMBS>: ArrayEncoding<ByteSize = MOD::ByteSize>,
705{
706    #[inline]
707    fn reduce(bytes: &MontyFieldBytes<MOD, LIMBS>) -> Self {
708        let uint = match MOD::BYTE_ORDER {
709            ByteOrder::BigEndian => Uint::<LIMBS>::from_be_byte_array(bytes.clone()),
710            ByteOrder::LittleEndian => Uint::<LIMBS>::from_le_byte_array(bytes.clone()),
711        };
712
713        Self::reduce(&uint)
714    }
715}
716
717//
718// `subtle` trait impls
719//
720
721impl<MOD, const LIMBS: usize> ConditionallySelectable for MontyFieldElement<MOD, LIMBS>
722where
723    MOD: MontyFieldParams<LIMBS>,
724{
725    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
726        Self {
727            inner: MontyForm::conditional_select(&a.inner, &b.inner, choice),
728        }
729    }
730}
731
732impl<MOD, const LIMBS: usize> ConstantTimeEq for MontyFieldElement<MOD, LIMBS>
733where
734    MOD: MontyFieldParams<LIMBS>,
735{
736    fn ct_eq(&self, other: &Self) -> Choice {
737        self.inner.ct_eq(&other.inner)
738    }
739}
740
741impl<MOD, const LIMBS: usize> ConstantTimeGreater for MontyFieldElement<MOD, LIMBS>
742where
743    MOD: MontyFieldParams<LIMBS>,
744{
745    fn ct_gt(&self, other: &Self) -> Choice {
746        // TODO(tarcieri): impl `ConstantTimeGreater` for `ConstMontyForm`
747        self.inner.retrieve().ct_gt(&other.inner.retrieve())
748    }
749}
750
751impl<MOD, const LIMBS: usize> ConstantTimeLess for MontyFieldElement<MOD, LIMBS>
752where
753    MOD: MontyFieldParams<LIMBS>,
754{
755    fn ct_lt(&self, other: &Self) -> Choice {
756        // TODO(tarcieri): impl `ConstantTimeLess` for `ConstMontyForm`
757        ctutils::CtLt::ct_lt(&self.inner.retrieve(), &other.inner.retrieve()).into()
758    }
759}
760
761//
762// `ctutils` trait impls
763//
764
765impl<MOD, const LIMBS: usize> ctutils::CtEq for MontyFieldElement<MOD, LIMBS>
766where
767    MOD: MontyFieldParams<LIMBS>,
768{
769    fn ct_eq(&self, other: &Self) -> ctutils::Choice {
770        ConstantTimeEq::ct_eq(self, other).into()
771    }
772}
773
774impl<MOD, const LIMBS: usize> ctutils::CtSelect for MontyFieldElement<MOD, LIMBS>
775where
776    MOD: MontyFieldParams<LIMBS>,
777{
778    fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self {
779        ConditionallySelectable::conditional_select(self, other, choice.into())
780    }
781}
782
783impl<MOD, const LIMBS: usize> ctutils::CtGt for MontyFieldElement<MOD, LIMBS>
784where
785    MOD: MontyFieldParams<LIMBS>,
786{
787    fn ct_gt(&self, other: &Self) -> ctutils::Choice {
788        // TODO(tarcieri): impl `ConstantTimeGreater` for `ConstMontyForm`
789        ctutils::CtGt::ct_gt(&self.inner.retrieve(), &other.inner.retrieve())
790    }
791}
792
793impl<MOD, const LIMBS: usize> ctutils::CtLt for MontyFieldElement<MOD, LIMBS>
794where
795    MOD: MontyFieldParams<LIMBS>,
796{
797    fn ct_lt(&self, other: &Self) -> ctutils::Choice {
798        // TODO(tarcieri): impl `ConstantTimeLess` for `ConstMontyForm`
799        ctutils::CtLt::ct_lt(&self.inner.retrieve(), &other.inner.retrieve())
800    }
801}
802
803//
804// `core::fmt` trait impls
805//
806
807impl<MOD, const LIMBS: usize> fmt::Debug for MontyFieldElement<MOD, LIMBS>
808where
809    MOD: MontyFieldParams<LIMBS>,
810{
811    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
812        let canonical = self.to_canonical();
813        write!(
814            f,
815            "MontyFieldElement<p={}>(0x{:X})",
816            MOD::MODULUS_HEX,
817            canonical
818        )
819    }
820}
821
822impl<MOD, const LIMBS: usize> fmt::Display for MontyFieldElement<MOD, LIMBS>
823where
824    MOD: MontyFieldParams<LIMBS>,
825{
826    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
827        fmt::UpperHex::fmt(self, f)
828    }
829}
830
831impl<MOD, const LIMBS: usize> fmt::Binary for MontyFieldElement<MOD, LIMBS>
832where
833    MOD: MontyFieldParams<LIMBS>,
834{
835    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
836        fmt::Binary::fmt(&self.to_canonical(), f)
837    }
838}
839
840impl<MOD, const LIMBS: usize> fmt::LowerHex for MontyFieldElement<MOD, LIMBS>
841where
842    MOD: MontyFieldParams<LIMBS>,
843{
844    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
845        fmt::LowerHex::fmt(&self.to_canonical(), f)
846    }
847}
848
849impl<MOD, const LIMBS: usize> fmt::UpperHex for MontyFieldElement<MOD, LIMBS>
850where
851    MOD: MontyFieldParams<LIMBS>,
852{
853    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
854        fmt::UpperHex::fmt(&self.to_canonical(), f)
855    }
856}
857
858//
859// Miscellaneous trait impls
860//
861
862impl<MOD, const LIMBS: usize> ConstMontyParams<LIMBS> for MontyFieldElement<MOD, LIMBS>
863where
864    MOD: MontyFieldParams<LIMBS>,
865{
866    const LIMBS: usize = LIMBS;
867    const PARAMS: FixedMontyParams<LIMBS> = MOD::PARAMS;
868}
869
870impl<MOD, const LIMBS: usize> Default for MontyFieldElement<MOD, LIMBS>
871where
872    MOD: MontyFieldParams<LIMBS>,
873{
874    fn default() -> Self {
875        Self::ZERO
876    }
877}
878
879impl<MOD: MontyFieldParams<LIMBS>, const LIMBS: usize> Eq for MontyFieldElement<MOD, LIMBS> {}
880impl<MOD: MontyFieldParams<LIMBS>, const LIMBS: usize> PartialEq for MontyFieldElement<MOD, LIMBS> {
881    fn eq(&self, rhs: &Self) -> bool {
882        self.inner.ct_eq(&(rhs.inner)).into()
883    }
884}
885
886impl<MOD, const LIMBS: usize> From<u32> for MontyFieldElement<MOD, LIMBS>
887where
888    MOD: MontyFieldParams<LIMBS>,
889{
890    #[inline]
891    fn from(n: u32) -> MontyFieldElement<MOD, LIMBS> {
892        Self::from_uint_reduced(&Uint::from(n))
893    }
894}
895
896impl<MOD, const LIMBS: usize> From<u64> for MontyFieldElement<MOD, LIMBS>
897where
898    MOD: MontyFieldParams<LIMBS>,
899{
900    #[inline]
901    fn from(n: u64) -> MontyFieldElement<MOD, LIMBS> {
902        Self::from_u64(n)
903    }
904}
905
906impl<MOD, const LIMBS: usize> From<u128> for MontyFieldElement<MOD, LIMBS>
907where
908    MOD: MontyFieldParams<LIMBS>,
909{
910    fn from(n: u128) -> MontyFieldElement<MOD, LIMBS> {
911        Self::from_uint_reduced(&Uint::from(n))
912    }
913}
914
915impl<MOD, const LIMBS: usize> From<MontyFieldElement<MOD, LIMBS>> for MontyFieldBytes<MOD, LIMBS>
916where
917    MOD: MontyFieldParams<LIMBS>,
918    Uint<LIMBS>: ArrayEncoding,
919{
920    fn from(fe: MontyFieldElement<MOD, LIMBS>) -> Self {
921        MontyFieldBytes::<MOD, LIMBS>::from(&fe)
922    }
923}
924
925impl<MOD, const LIMBS: usize> From<&MontyFieldElement<MOD, LIMBS>> for MontyFieldBytes<MOD, LIMBS>
926where
927    MOD: MontyFieldParams<LIMBS>,
928    Uint<LIMBS>: ArrayEncoding,
929{
930    fn from(fe: &MontyFieldElement<MOD, LIMBS>) -> Self {
931        fe.to_bytes()
932    }
933}
934
935impl<MOD, const LIMBS: usize> From<MontyFieldElement<MOD, LIMBS>> for Uint<LIMBS>
936where
937    MOD: MontyFieldParams<LIMBS>,
938{
939    fn from(fe: MontyFieldElement<MOD, LIMBS>) -> Uint<LIMBS> {
940        Uint::from(&fe)
941    }
942}
943
944impl<MOD, const LIMBS: usize> From<&MontyFieldElement<MOD, LIMBS>> for Uint<LIMBS>
945where
946    MOD: MontyFieldParams<LIMBS>,
947{
948    fn from(fe: &MontyFieldElement<MOD, LIMBS>) -> Uint<LIMBS> {
949        fe.to_canonical()
950    }
951}
952
953impl<MOD, const LIMBS: usize> Generate for MontyFieldElement<MOD, LIMBS>
954where
955    MOD: MontyFieldParams<LIMBS>,
956    MontyFieldBytes<MOD, LIMBS>: Copy,
957    Uint<LIMBS>: ArrayEncoding,
958{
959    fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
960        Self::try_random(rng)
961    }
962}
963
964impl<MOD, const LIMBS: usize> Ord for MontyFieldElement<MOD, LIMBS>
965where
966    MOD: MontyFieldParams<LIMBS>,
967{
968    fn cmp(&self, other: &Self) -> Ordering {
969        self.to_canonical().cmp(&other.to_canonical())
970    }
971}
972impl<MOD, const LIMBS: usize> PartialOrd for MontyFieldElement<MOD, LIMBS>
973where
974    MOD: MontyFieldParams<LIMBS>,
975{
976    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
977        Some(self.cmp(other))
978    }
979}
980
981impl<MOD, const LIMBS: usize> Retrieve for MontyFieldElement<MOD, LIMBS>
982where
983    MOD: MontyFieldParams<LIMBS>,
984{
985    type Output = Uint<LIMBS>;
986
987    fn retrieve(&self) -> Uint<LIMBS> {
988        self.to_canonical()
989    }
990}
991
992/// Compute `t = (modulus - 1) >> S`
993#[must_use]
994pub const fn compute_t<const LIMBS: usize>(modulus: &Uint<LIMBS>) -> Uint<LIMBS> {
995    let s = modulus.wrapping_sub(&Uint::ONE).trailing_zeros();
996    modulus.wrapping_sub(&Uint::ONE).unbounded_shr(s)
997}
998
999#[cfg(test)]
1000mod tests {
1001    use super::MontyFieldElement;
1002    use crate::{ByteOrder, monty_field_params, test_primefield};
1003    use bigint::U256;
1004
1005    // Example modulus: P-256 base field.
1006    // p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1
1007    monty_field_params!(
1008        name: P256Params,
1009        modulus: "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
1010        uint: U256,
1011        byte_order: ByteOrder::BigEndian,
1012        multiplicative_generator: 6,
1013        doc: "P-256 field modulus"
1014    );
1015
1016    type FieldElement = MontyFieldElement<P256Params, { U256::LIMBS }>;
1017
1018    test_primefield!(FieldElement, U256);
1019
1020    #[test]
1021    fn modulus_bits_constant() {
1022        assert_eq!(FieldElement::NUM_BITS, 256);
1023    }
1024
1025    #[test]
1026    fn s_constant() {
1027        assert_eq!(FieldElement::S, 1);
1028    }
1029
1030    #[test]
1031    fn computed_delta_constant() {
1032        assert_eq!(FieldElement::DELTA, FieldElement::from_u64(36));
1033    }
1034
1035    // Regression test for little-endian byte order fix
1036    // Verifies that from_bytes/to_bytes correctly handle little-endian encoding
1037    mod little_endian {
1038        use super::*;
1039
1040        // Example modulus: BIGNP-256 base field.
1041        // p = 2^{256} - 189
1042        monty_field_params!(
1043            name: BignParams,
1044            modulus: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43",
1045            uint: U256,
1046            byte_order: ByteOrder::LittleEndian,
1047            multiplicative_generator: 2,
1048            doc: "BIGNP-256 field modulus"
1049        );
1050
1051        type BignP256Element = MontyFieldElement<BignParams, { U256::LIMBS }>;
1052
1053        test_primefield!(BignP256Element, U256);
1054
1055        #[test]
1056        fn byte_order() {
1057            // Verify LSB comes first in little-endian encoding
1058            let value = BignP256Element::from_u64(0x0123456789ABCDEF);
1059            let bytes = value.to_bytes();
1060
1061            assert_eq!(bytes[0], 0xEF); // LSB
1062            assert_eq!(bytes[1], 0xCD);
1063            assert_eq!(bytes[2], 0xAB);
1064            assert_eq!(bytes[3], 0x89);
1065        }
1066
1067        #[test]
1068        fn roundtrip() {
1069            let value = BignP256Element::from_u64(0x0123456789ABCDEF);
1070            let bytes = value.to_bytes();
1071            let recovered = BignP256Element::from_bytes(&bytes).unwrap();
1072            assert_eq!(value, recovered);
1073        }
1074
1075        #[test]
1076        fn modulus_bits_constant() {
1077            assert_eq!(BignP256Element::NUM_BITS, 256);
1078        }
1079
1080        #[test]
1081        fn s_constant() {
1082            assert_eq!(BignP256Element::S, 1);
1083        }
1084
1085        #[test]
1086        fn computed_delta_constant() {
1087            assert_eq!(BignP256Element::DELTA, BignP256Element::from_u64(4));
1088        }
1089    }
1090}