secp256kfun_k256_backend/arithmetic/
field.rs

1//! Field arithmetic modulo p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
2
3use cfg_if::cfg_if;
4
5cfg_if! {
6    if #[cfg(feature = "field-montgomery")] {
7        mod field_montgomery;
8    } else if #[cfg(any(target_pointer_width = "32", feature = "force-32-bit"))] {
9        mod field_10x26;
10    } else if #[cfg(target_pointer_width = "64")] {
11        mod field_5x52;
12    }
13}
14
15cfg_if! {
16    if #[cfg(all(debug_assertions, not(feature = "field-montgomery")))] {
17        mod field_impl;
18        use field_impl::FieldElementImpl;
19    } else {
20        cfg_if! {
21            if #[cfg(feature = "field-montgomery")] {
22                use field_montgomery::FieldElementMontgomery as FieldElementImpl;
23            } else if #[cfg(any(target_pointer_width = "32", feature = "force-32-bit"))] {
24                use field_10x26::FieldElement10x26 as FieldElementImpl;
25            } else if #[cfg(target_pointer_width = "64")] {
26                use field_5x52::FieldElement5x52 as FieldElementImpl;
27            }
28        }
29    }
30}
31
32use crate::FieldBytes;
33use core::ops::{Add, AddAssign, Mul, MulAssign};
34use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
35
36#[cfg(feature = "zeroize")]
37use elliptic_curve::zeroize::Zeroize;
38
39#[cfg(test)]
40use num_bigint::{BigUint, ToBigUint};
41
42/// An element in the finite field used for curve coordinates.
43#[derive(Clone, Copy, Debug)]
44pub struct FieldElement(FieldElementImpl);
45
46impl FieldElement {
47    /// Returns the zero element.
48    pub const fn zero() -> Self {
49        Self(FieldElementImpl::zero())
50    }
51
52    /// Returns the multiplicative identity.
53    pub const fn one() -> Self {
54        Self(FieldElementImpl::one())
55    }
56
57    /// Determine if this `FieldElement10x26` is zero.
58    ///
59    /// # Returns
60    ///
61    /// If zero, return `Choice(1)`.  Otherwise, return `Choice(0)`.
62    pub fn is_zero(&self) -> Choice {
63        self.0.is_zero()
64    }
65
66    /// Determine if this `FieldElement10x26` is odd in the SEC1 sense: `self mod 2 == 1`.
67    ///
68    /// # Returns
69    ///
70    /// If odd, return `Choice(1)`.  Otherwise, return `Choice(0)`.
71    pub fn is_odd(&self) -> Choice {
72        self.0.is_odd()
73    }
74
75    /// Attempts to parse the given byte array as an SEC1-encoded field element.
76    /// Does not check the result for being in the correct range.
77    pub const fn from_bytes_unchecked(bytes: &[u8; 32]) -> Self {
78        Self(FieldElementImpl::from_bytes_unchecked(bytes))
79    }
80
81    /// Attempts to parse the given byte array as an SEC1-encoded field element.
82    ///
83    /// Returns None if the byte array does not contain a big-endian integer in the range
84    /// [0, p).
85    pub fn from_bytes(bytes: &FieldBytes) -> CtOption<Self> {
86        FieldElementImpl::from_bytes(bytes).map(Self)
87    }
88
89    /// Returns the SEC1 encoding of this field element.
90    pub fn to_bytes(&self) -> FieldBytes {
91        self.0.normalize().to_bytes()
92    }
93
94    /// Returns -self, treating it as a value of given magnitude.
95    /// The provided magnitude must be equal or greater than the actual magnitude of `self`.
96    pub fn negate(&self, magnitude: u32) -> Self {
97        Self(self.0.negate(magnitude))
98    }
99
100    /// Fully normalizes the field element.
101    /// Brings the magnitude to 1 and modulo reduces the value.
102    pub fn normalize(&self) -> Self {
103        Self(self.0.normalize())
104    }
105
106    /// Weakly normalizes the field element.
107    /// Brings the magnitude to 1, but does not guarantee the value to be less than the modulus.
108    pub fn normalize_weak(&self) -> Self {
109        Self(self.0.normalize_weak())
110    }
111
112    /// Checks if the field element becomes zero if normalized.
113    pub fn normalizes_to_zero(&self) -> Choice {
114        self.0.normalizes_to_zero()
115    }
116
117    /// Multiplies by a single-limb integer.
118    /// Multiplies the magnitude by the same value.
119    pub fn mul_single(&self, rhs: u32) -> Self {
120        Self(self.0.mul_single(rhs))
121    }
122
123    /// Returns 2*self.
124    /// Doubles the magnitude.
125    pub fn double(&self) -> Self {
126        Self(self.0.add(&(self.0)))
127    }
128
129    /// Returns self * rhs mod p
130    /// Brings the magnitude to 1 (but doesn't normalize the result).
131    /// The magnitudes of arguments should be <= 8.
132    pub fn mul(&self, rhs: &Self) -> Self {
133        Self(self.0.mul(&(rhs.0)))
134    }
135
136    /// Returns self * self
137    /// Brings the magnitude to 1 (but doesn't normalize the result).
138    /// The magnitudes of arguments should be <= 8.
139    pub fn square(&self) -> Self {
140        Self(self.0.square())
141    }
142
143    /// Raises the scalar to the power `2^k`
144    fn pow2k(&self, k: usize) -> Self {
145        let mut x = *self;
146        for _j in 0..k {
147            x = x.square();
148        }
149        x
150    }
151
152    /// Returns the multiplicative inverse of self, if self is non-zero.
153    /// The result has magnitude 1, but is not normalized.
154    pub fn invert(&self) -> CtOption<Self> {
155        // The binary representation of (p - 2) has 5 blocks of 1s, with lengths in
156        // { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
157        // [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
158
159        let x2 = self.pow2k(1).mul(self);
160        let x3 = x2.pow2k(1).mul(self);
161        let x6 = x3.pow2k(3).mul(&x3);
162        let x9 = x6.pow2k(3).mul(&x3);
163        let x11 = x9.pow2k(2).mul(&x2);
164        let x22 = x11.pow2k(11).mul(&x11);
165        let x44 = x22.pow2k(22).mul(&x22);
166        let x88 = x44.pow2k(44).mul(&x44);
167        let x176 = x88.pow2k(88).mul(&x88);
168        let x220 = x176.pow2k(44).mul(&x44);
169        let x223 = x220.pow2k(3).mul(&x3);
170
171        // The final result is then assembled using a sliding window over the blocks.
172        let res = x223
173            .pow2k(23)
174            .mul(&x22)
175            .pow2k(5)
176            .mul(self)
177            .pow2k(3)
178            .mul(&x2)
179            .pow2k(2)
180            .mul(self);
181
182        CtOption::new(res, !self.normalizes_to_zero())
183    }
184
185    /// Returns the square root of self mod p, or `None` if no square root exists.
186    /// The result has magnitude 1, but is not normalized.
187    pub fn sqrt(&self) -> CtOption<Self> {
188        /*
189        Given that p is congruent to 3 mod 4, we can compute the square root of
190        a mod p as the (p+1)/4'th power of a.
191
192        As (p+1)/4 is an even number, it will have the same result for a and for
193        (-a). Only one of these two numbers actually has a square root however,
194        so we test at the end by squaring and comparing to the input.
195        Also because (p+1)/4 is an even number, the computed square root is
196        itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).
197        */
198
199        // The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
200        // { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
201        // 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
202
203        let x2 = self.pow2k(1).mul(&self);
204        let x3 = x2.pow2k(1).mul(&self);
205        let x6 = x3.pow2k(3).mul(&x3);
206        let x9 = x6.pow2k(3).mul(&x3);
207        let x11 = x9.pow2k(2).mul(&x2);
208        let x22 = x11.pow2k(11).mul(&x11);
209        let x44 = x22.pow2k(22).mul(&x22);
210        let x88 = x44.pow2k(44).mul(&x44);
211        let x176 = x88.pow2k(88).mul(&x88);
212        let x220 = x176.pow2k(44).mul(&x44);
213        let x223 = x220.pow2k(3).mul(&x3);
214
215        // The final result is then assembled using a sliding window over the blocks.
216        let res = x223.pow2k(23).mul(&x22).pow2k(6).mul(&x2).pow2k(2);
217
218        let is_root = (res.mul(&res).negate(1) + self).normalizes_to_zero();
219
220        // Only return Some if it's the square root.
221        CtOption::new(res, is_root)
222    }
223
224    #[cfg(test)]
225    pub fn modulus_as_biguint() -> BigUint {
226        Self::one().negate(1).to_biguint().unwrap() + 1.to_biguint().unwrap()
227    }
228}
229
230impl PartialEq for FieldElement {
231    fn eq(&self, other: &Self) -> bool {
232        self.0.ct_eq(&(other.0)).into()
233    }
234}
235
236impl Default for FieldElement {
237    fn default() -> Self {
238        Self::zero()
239    }
240}
241
242impl ConditionallySelectable for FieldElement {
243    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
244        Self(FieldElementImpl::conditional_select(&(a.0), &(b.0), choice))
245    }
246}
247
248impl ConstantTimeEq for FieldElement {
249    fn ct_eq(&self, other: &Self) -> Choice {
250        self.0.ct_eq(&(other.0))
251    }
252}
253
254impl Add<&FieldElement> for &FieldElement {
255    type Output = FieldElement;
256
257    fn add(self, other: &FieldElement) -> FieldElement {
258        FieldElement(self.0.add(&(other.0)))
259    }
260}
261
262impl Add<&FieldElement> for FieldElement {
263    type Output = FieldElement;
264
265    fn add(self, other: &FieldElement) -> FieldElement {
266        FieldElement(self.0.add(&(other.0)))
267    }
268}
269
270impl AddAssign<FieldElement> for FieldElement {
271    fn add_assign(&mut self, rhs: FieldElement) {
272        *self = *self + &rhs;
273    }
274}
275
276impl Mul<&FieldElement> for &FieldElement {
277    type Output = FieldElement;
278
279    fn mul(self, other: &FieldElement) -> FieldElement {
280        FieldElement(self.0.mul(&(other.0)))
281    }
282}
283
284impl Mul<&FieldElement> for FieldElement {
285    type Output = FieldElement;
286
287    fn mul(self, other: &FieldElement) -> FieldElement {
288        FieldElement(self.0.mul(&(other.0)))
289    }
290}
291
292impl MulAssign<FieldElement> for FieldElement {
293    fn mul_assign(&mut self, rhs: FieldElement) {
294        *self = *self * &rhs;
295    }
296}
297
298#[cfg(feature = "zeroize")]
299impl Zeroize for FieldElement {
300    fn zeroize(&mut self) {
301        self.0.zeroize();
302    }
303}
304
305#[cfg(test)]
306mod tests {
307    use num_bigint::{BigUint, ToBigUint};
308    use proptest::prelude::*;
309
310    use super::FieldElement;
311    use crate::{
312        arithmetic::util::{biguint_to_bytes, bytes_to_biguint},
313        test_vectors::field::DBL_TEST_VECTORS,
314        FieldBytes,
315    };
316
317    impl From<&BigUint> for FieldElement {
318        fn from(x: &BigUint) -> Self {
319            let bytes = biguint_to_bytes(x);
320            Self::from_bytes(&bytes.into()).unwrap()
321        }
322    }
323
324    impl ToBigUint for FieldElement {
325        fn to_biguint(&self) -> Option<BigUint> {
326            Some(bytes_to_biguint(self.to_bytes().as_ref()))
327        }
328    }
329
330    #[test]
331    fn zero_is_additive_identity() {
332        let zero = FieldElement::zero();
333        let one = FieldElement::one();
334        assert_eq!((zero + &zero).normalize(), zero);
335        assert_eq!((one + &zero).normalize(), one);
336    }
337
338    #[test]
339    fn one_is_multiplicative_identity() {
340        let one = FieldElement::one();
341        assert_eq!((one * &one).normalize(), one);
342    }
343
344    #[test]
345    fn from_bytes() {
346        assert_eq!(
347            FieldElement::from_bytes(&FieldBytes::default()).unwrap(),
348            FieldElement::zero()
349        );
350        assert_eq!(
351            FieldElement::from_bytes(
352                &[
353                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
354                    0, 0, 0, 0, 0, 1
355                ]
356                .into()
357            )
358            .unwrap(),
359            FieldElement::one()
360        );
361        assert!(bool::from(
362            FieldElement::from_bytes(&[0xff; 32].into()).is_none()
363        ));
364    }
365
366    #[test]
367    fn to_bytes() {
368        assert_eq!(FieldElement::zero().to_bytes(), [0; 32].into());
369        assert_eq!(
370            FieldElement::one().to_bytes(),
371            [
372                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
373                0, 0, 0, 1
374            ]
375            .into()
376        );
377    }
378
379    #[test]
380    fn repeated_add() {
381        let mut r = FieldElement::one();
382        for i in 0..DBL_TEST_VECTORS.len() {
383            assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into());
384            r = (r + &r).normalize();
385        }
386    }
387
388    #[test]
389    fn repeated_double() {
390        let mut r = FieldElement::one();
391        for i in 0..DBL_TEST_VECTORS.len() {
392            assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into());
393            r = r.double().normalize();
394        }
395    }
396
397    #[test]
398    fn repeated_mul() {
399        let mut r = FieldElement::one();
400        let two = r + &r;
401        for i in 0..DBL_TEST_VECTORS.len() {
402            assert_eq!(r.normalize().to_bytes(), DBL_TEST_VECTORS[i].into());
403            r = r * &two;
404        }
405    }
406
407    #[test]
408    fn negation() {
409        let two = FieldElement::one().double();
410        let neg_two = two.negate(2);
411        assert_eq!((two + &neg_two).normalize(), FieldElement::zero());
412        assert_eq!(neg_two.negate(3).normalize(), two.normalize());
413    }
414
415    #[test]
416    fn invert() {
417        assert!(bool::from(FieldElement::zero().invert().is_none()));
418
419        let one = FieldElement::one();
420        assert_eq!(one.invert().unwrap().normalize(), one);
421
422        let two = one + &one;
423        let inv_two = two.invert().unwrap();
424        assert_eq!((two * &inv_two).normalize(), one);
425    }
426
427    #[test]
428    fn sqrt() {
429        let one = FieldElement::one();
430        let two = one + &one;
431        let four = two.square();
432        assert_eq!(four.sqrt().unwrap().normalize(), two.normalize());
433    }
434
435    prop_compose! {
436        fn field_element()(bytes in any::<[u8; 32]>()) -> FieldElement {
437            let mut res = bytes_to_biguint(&bytes);
438            let m = FieldElement::modulus_as_biguint();
439            // Modulus is 256 bit long, same as the maximum `res`,
440            // so this is guaranteed to land us in the correct range.
441            if res >= m {
442                res -= m;
443            }
444            FieldElement::from(&res)
445        }
446    }
447
448    proptest! {
449
450        #[test]
451        fn fuzzy_add(
452            a in field_element(),
453            b in field_element()
454        ) {
455            let a_bi = a.to_biguint().unwrap();
456            let b_bi = b.to_biguint().unwrap();
457            let res_bi = (&a_bi + &b_bi) % FieldElement::modulus_as_biguint();
458            let res_ref = FieldElement::from(&res_bi);
459            let res_test = (&a + &b).normalize();
460            assert_eq!(res_test, res_ref);
461        }
462
463        #[test]
464        fn fuzzy_mul(
465            a in field_element(),
466            b in field_element()
467        ) {
468            let a_bi = a.to_biguint().unwrap();
469            let b_bi = b.to_biguint().unwrap();
470            let res_bi = (&a_bi * &b_bi) % FieldElement::modulus_as_biguint();
471            let res_ref = FieldElement::from(&res_bi);
472            let res_test = (&a * &b).normalize();
473            assert_eq!(res_test, res_ref);
474        }
475
476        #[test]
477        fn fuzzy_square(
478            a in field_element()
479        ) {
480            let a_bi = a.to_biguint().unwrap();
481            let res_bi = (&a_bi * &a_bi) % FieldElement::modulus_as_biguint();
482            let res_ref = FieldElement::from(&res_bi);
483            let res_test = a.square().normalize();
484            assert_eq!(res_test, res_ref);
485        }
486
487        #[test]
488        fn fuzzy_negate(
489            a in field_element()
490        ) {
491            let m = FieldElement::modulus_as_biguint();
492            let a_bi = a.to_biguint().unwrap();
493            let res_bi = (&m - &a_bi) % &m;
494            let res_ref = FieldElement::from(&res_bi);
495            let res_test = a.negate(1).normalize();
496            assert_eq!(res_test, res_ref);
497        }
498
499        #[test]
500        fn fuzzy_sqrt(
501            a in field_element()
502        ) {
503            let m = FieldElement::modulus_as_biguint();
504            let a_bi = a.to_biguint().unwrap();
505            let sqr_bi = (&a_bi * &a_bi) % &m;
506            let sqr = FieldElement::from(&sqr_bi);
507
508            let res_ref1 = a;
509            let possible_sqrt = (&m - &a_bi) % &m;
510            let res_ref2 = FieldElement::from(&possible_sqrt);
511            let res_test = sqr.sqrt().unwrap().normalize();
512            // FIXME: is there a rule which square root is returned?
513            assert!(res_test == res_ref1 || res_test == res_ref2);
514        }
515
516        #[test]
517        fn fuzzy_invert(
518            a in field_element()
519        ) {
520            let a = if bool::from(a.is_zero()) { FieldElement::one() } else { a };
521            let a_bi = a.to_biguint().unwrap();
522            let inv = a.invert().unwrap().normalize();
523            let inv_bi = inv.to_biguint().unwrap();
524            let m = FieldElement::modulus_as_biguint();
525            assert_eq!((&inv_bi * &a_bi) % &m, 1.to_biguint().unwrap());
526        }
527    }
528}