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#[derive(Clone, Copy, Eq, PartialEq, Hash)]
22#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
23pub struct Fq(pub(crate) [u64; 4]);
24
25const MODULUS: Fq = Fq([
28 0xffffffffffffffed,
29 0xffffffffffffffff,
30 0xffffffffffffffff,
31 0x7fffffffffffffff,
32]);
33
34#[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
47const MODULUS_STR: &str = "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed";
49
50const MULTIPLICATIVE_GENERATOR: Fq = Fq::from_raw([0x02, 0x0, 0x0, 0x0]);
53
54const INV: u64 = 0x86bca1af286bca1b;
56
57const R: Fq = Fq([0x26, 0, 0, 0]);
60
61const R2: Fq = Fq([0x5a4, 0, 0, 0]);
64
65const R3: Fq = Fq([0xd658, 0, 0, 0]);
68
69const TWO_INV: Fq = Fq::from_raw([
71 0xfffffffffffffff7,
72 0xffffffffffffffff,
73 0xffffffffffffffff,
74 0x3fffffffffffffff,
75]);
76
77const SQRT_MINUS_ONE: Fq = Fq::from_raw([
79 0xc4ee1b274a0ea0b0,
80 0x2f431806ad2fe478,
81 0x2b4d00993dfbd7a7,
82 0x2b8324804fc1df0b,
83]);
84
85const ZETA: Fq = Fq::from_raw([
89 0xaa86d89d8618e538,
90 0x1a1aada8413a4550,
91 0xd9872fccc55bd529,
92 0x381cba36aa6565b5,
93]);
94const ROOT_OF_UNITY: Fq = Fq::from_raw([
100 0xc4ee1b274a0ea0b0,
101 0x2f431806ad2fe478,
102 0x2b4d00993dfbd7a7,
103 0x2b8324804fc1df0b,
104]);
105const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([
107 0x3b11e4d8b5f15f3d,
108 0xd0bce7f952d01b87,
109 0xd4b2ff66c2042858,
110 0x547cdb7fb03e20f4,
111]);
112const 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 fn sqrt(&self) -> CtOption<Self> {
175 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 fn invert(&self) -> CtOption<Self> {
203 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 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 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 let is_some = (borrow as u8) & 1;
265
266 tmp *= &R2;
269
270 CtOption::new(tmp, Choice::from(is_some))
271 }
272
273 fn to_repr(&self) -> Self::Repr {
274 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 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 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}