halo2curves_axiom/ed25519/
fr.rs

1use core::convert::TryInto;
2use core::fmt;
3use core::ops::{Add, Mul, Neg, Sub};
4use ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
5use rand::RngCore;
6use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
7
8#[cfg(feature = "derive_serde")]
9use serde::{Deserialize, Serialize};
10
11use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb};
12
13/// This represents an element of $\mathbb{F}_q$ where
14///
15/// `r = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed`
16///
17/// is the scalar field of the ed25519 curve.
18// The internal representation of this type is four 64-bit unsigned
19// integers in little-endian order. `Fr` values are always in
20// Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256.
21#[derive(Clone, Copy, Eq, PartialEq, Hash)]
22#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
23pub struct Fr(pub(crate) [u64; 4]);
24
25/// Constant representing the modulus
26/// r = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
27const MODULUS: Fr = Fr([
28    0x5812631a5cf5d3ed,
29    0x14def9dea2f79cd6,
30    0x0000000000000000,
31    0x1000000000000000,
32]);
33
34/// The modulus as u32 limbs.
35#[cfg(not(target_pointer_width = "64"))]
36const MODULUS_LIMBS_32: [u32; 8] = [
37    0x5cf5_d3ed,
38    0x5812_631a,
39    0xa2f7_9cd6,
40    0x14de_f9de,
41    0x0000_0000,
42    0x0000_0000,
43    0x0000_0000,
44    0x1000_0000,
45];
46
47///Constant representing the modulus as static str
48const MODULUS_STR: &str = "0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed";
49
50/// Obtained with sage:
51/// `GF(r).primitive_element()`
52const MULTIPLICATIVE_GENERATOR: Fr = Fr::from_raw([0x02, 0x0, 0x0, 0x0]);
53
54/// INV = -(r^{-1} mod 2^64) mod 2^64
55const INV: u64 = 0xd2b51da312547e1b;
56
57/// R = 2^256 mod r
58/// 0xffffffffffffffffffffffffffffffec6ef5bf4737dcf70d6ec31748d98951d
59const R: Fr = Fr([
60    0xd6ec31748d98951d,
61    0xc6ef5bf4737dcf70,
62    0xfffffffffffffffe,
63    0x0fffffffffffffff,
64]);
65
66/// R^2 = 2^512 mod r
67/// 0x399411b7c309a3dceec73d217f5be65d00e1ba768859347a40611e3449c0f01
68const R2: Fr = Fr([
69    0xa40611e3449c0f01,
70    0xd00e1ba768859347,
71    0xceec73d217f5be65,
72    0x0399411b7c309a3d,
73]);
74
75/// R^3 = 2^768 mod r
76/// 0xe530b773599cec78065dc6c04ec5b65278324e6aef7f3ec2a9e49687b83a2db
77const R3: Fr = Fr([
78    0x2a9e49687b83a2db,
79    0x278324e6aef7f3ec,
80    0x8065dc6c04ec5b65,
81    0x0e530b773599cec7,
82]);
83
84/// 1 / 2 mod r
85const TWO_INV: Fr = Fr::from_raw([
86    0x2c09318d2e7ae9f7,
87    0x0a6f7cef517bce6b,
88    0x0000000000000000,
89    0x0800000000000000,
90]);
91
92/// sqrt(-1) mod r = 2^((r - 1) / 4) mod r
93const SQRT_MINUS_ONE: Fr = Fr::from_raw([
94    0xbe8775dfebbe07d4,
95    0x0ef0565342ce83fe,
96    0x7d3d6d60abc1c27a,
97    0x094a7310e07981e7,
98]);
99
100// Element in small order subgroup (3-order)
101// Sage:
102// `GF(r).primitive_element() ** ((r - 1) // N)` where N = 3
103const ZETA: Fr = Fr::from_raw([
104    0x158687e51e07e223,
105    0x471dd911c6cce91e,
106    0xeb08f579fb8841ae,
107    0x0378d9ddc674005f,
108]);
109// The `2^s` root of unity.
110// It can be calculated by exponentiating `MULTIPLICATIVE_GENERATOR` by `t`,
111// where `2^s * t = r - 1` with `t` odd.
112// Sage:
113// `GF(r).primitive_element() ** t`
114const ROOT_OF_UNITY: Fr = Fr::from_raw([
115    0xbe8775dfebbe07d4,
116    0x0ef0565342ce83fe,
117    0x7d3d6d60abc1c27a,
118    0x094a7310e07981e7,
119]);
120// Inverse of `ROOT_OF_UNITY`
121const ROOT_OF_UNITY_INV: Fr = Fr::from_raw([
122    0x998aed3a7137cc19,
123    0x05eea38b602918d7,
124    0x82c2929f543e3d86,
125    0x06b58cef1f867e18,
126]);
127// Generator of the `t-order` multiplicative subgroup
128// Sage:
129// `GF(r).primitive_element() ** (2**s)`
130const DELTA: Fr = Fr::from_raw([0x10, 0, 0, 0]);
131
132use crate::{
133    field_arithmetic, field_common, field_specific, impl_add_binop_specify_output,
134    impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
135    impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod,
136};
137impl_binops_additive!(Fr, Fr);
138impl_binops_multiplicative!(Fr, Fr);
139field_common!(
140    Fr,
141    MODULUS,
142    INV,
143    MODULUS_STR,
144    TWO_INV,
145    ROOT_OF_UNITY_INV,
146    DELTA,
147    ZETA,
148    R,
149    R2,
150    R3
151);
152field_arithmetic!(Fr, MODULUS, INV, dense);
153impl_sum_prod!(Fr);
154impl_from_u64!(Fr, R2);
155
156impl Fr {
157    pub const fn size() -> usize {
158        32
159    }
160}
161
162impl ff::Field for Fr {
163    const ZERO: Self = Self::zero();
164    const ONE: Self = Self::one();
165
166    fn random(mut rng: impl RngCore) -> Self {
167        Self::from_u512([
168            rng.next_u64(),
169            rng.next_u64(),
170            rng.next_u64(),
171            rng.next_u64(),
172            rng.next_u64(),
173            rng.next_u64(),
174            rng.next_u64(),
175            rng.next_u64(),
176        ])
177    }
178
179    fn double(&self) -> Self {
180        self.double()
181    }
182
183    #[inline(always)]
184    fn square(&self) -> Self {
185        self.square()
186    }
187
188    /// Computes the square root of this element, if it exists.
189    fn sqrt(&self) -> CtOption<Self> {
190        // Sqrt = a^((p + 3) / 8)
191        //        OR
192        //      = a^((p + 3) / 8) * sqrt(-1)
193        //      = a^((p + 3) / 8) * (2^((p - 1) / 4))
194        //        OR
195        //        Doesn't exist
196        let x1 = self.pow([
197            0xcb024c634b9eba7e,
198            0x029bdf3bd45ef39a,
199            0x0000000000000000,
200            0x0200000000000000,
201        ]);
202
203        let choice1 = x1.square().ct_eq(self);
204        let choice2 = x1.square().ct_eq(&-self);
205
206        let sqrt = Self::conditional_select(&x1, &(x1 * SQRT_MINUS_ONE), choice2);
207
208        CtOption::new(sqrt, choice1 | choice2)
209    }
210
211    fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
212        ff::helpers::sqrt_ratio_generic(num, div)
213    }
214
215    /// Computes the multiplicative inverse of this element,
216    /// failing if the element is zero.
217    fn invert(&self) -> CtOption<Self> {
218        let tmp = self.pow_vartime([
219            0x5812631a5cf5d3eb,
220            0x14def9dea2f79cd6,
221            0x0000000000000000,
222            0x1000000000000000,
223        ]);
224
225        CtOption::new(tmp, !self.ct_eq(&Self::zero()))
226    }
227
228    fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
229        let mut res = Self::one();
230        let mut found_one = false;
231        for e in exp.as_ref().iter().rev() {
232            for i in (0..64).rev() {
233                if found_one {
234                    res = res.square();
235                }
236
237                if ((*e >> i) & 1) == 1 {
238                    found_one = true;
239                    res *= self;
240                }
241            }
242        }
243        res
244    }
245}
246
247impl ff::PrimeField for Fr {
248    type Repr = [u8; 32];
249
250    const MODULUS: &'static str = MODULUS_STR;
251    const NUM_BITS: u32 = 256;
252    const CAPACITY: u32 = 255;
253    const TWO_INV: Self = TWO_INV;
254    const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR;
255    // An integer `s` satisfying the equation `2^s * t = modulus - 1` with `t` odd.
256    const S: u32 = 2;
257    const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
258    const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
259    const DELTA: Self = DELTA;
260
261    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
262        let mut tmp = Fr([0, 0, 0, 0]);
263
264        tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
265        tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
266        tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
267        tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
268
269        // Try to subtract the modulus
270        let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
271        let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
272        let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
273        let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
274
275        // If the element is smaller than MODULUS then the
276        // subtraction will underflow, producing a borrow value
277        // of 0xffff...ffff. Otherwise, it'll be zero.
278        let is_some = (borrow as u8) & 1;
279
280        // Convert to Montgomery form by computing
281        // (a.R^0 * R^2) / R = a.R
282        tmp *= &R2;
283
284        CtOption::new(tmp, Choice::from(is_some))
285    }
286
287    fn to_repr(&self) -> Self::Repr {
288        // Turn into canonical form by computing
289        // (a.R) / R = a
290        let tmp = Fr::montgomery_reduce_short(&self.0);
291
292        let mut res = [0; 32];
293        res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
294        res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
295        res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
296        res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
297
298        res
299    }
300
301    fn is_odd(&self) -> Choice {
302        Choice::from(self.to_repr()[0] & 1)
303    }
304}
305
306impl FromUniformBytes<64> for Fr {
307    /// Converts a 512-bit little endian integer into
308    /// an `Fq` by reducing by the modulus.
309    fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
310        Self::from_u512([
311            u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
312            u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
313            u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
314            u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
315            u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
316            u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
317            u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
318            u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
319        ])
320    }
321}
322
323impl WithSmallOrderMulGroup<3> for Fr {
324    const ZETA: Self = ZETA;
325}
326
327#[cfg(test)]
328mod test {
329    use super::*;
330    use ff::Field;
331    use rand_core::OsRng;
332
333    #[test]
334    fn test_sqrt() {
335        // NB: TWO_INV is standing in as a "random" field element
336        let v = (Fr::TWO_INV).square().sqrt().unwrap();
337        assert!(v == Fr::TWO_INV || (-v) == Fr::TWO_INV);
338
339        for _ in 0..10000 {
340            let a = Fr::random(OsRng);
341            let mut b = a;
342            b = b.square();
343
344            let b = b.sqrt().unwrap();
345            let mut negb = b;
346            negb = negb.neg();
347
348            assert!(a == b || a == negb);
349        }
350    }
351
352    #[test]
353    fn test_invert() {
354        let v = Fr::one().double().invert().unwrap();
355        assert!(v == Fr::TWO_INV);
356
357        for _ in 0..10000 {
358            let a = Fr::random(OsRng);
359            let b = a.invert().unwrap().invert().unwrap();
360
361            assert!(a == b);
362        }
363    }
364
365    #[test]
366    fn test_field() {
367        crate::tests::field::random_field_tests::<Fr>("ed25519 scalar".to_string());
368    }
369
370    #[test]
371    fn test_serialization() {
372        crate::tests::field::random_serialization_test::<Fr>("ed25519 scalar".to_string());
373    }
374}