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