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#[derive(Clone, Copy, Eq, PartialEq, Hash)]
22#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
23pub struct Fr(pub(crate) [u64; 4]);
24
25const MODULUS: Fr = Fr([
28 0x5812631a5cf5d3ed,
29 0x14def9dea2f79cd6,
30 0x0000000000000000,
31 0x1000000000000000,
32]);
33
34#[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
47const MODULUS_STR: &str = "0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed";
49
50const MULTIPLICATIVE_GENERATOR: Fr = Fr::from_raw([0x02, 0x0, 0x0, 0x0]);
53
54const INV: u64 = 0xd2b51da312547e1b;
56
57const R: Fr = Fr([
60 0xd6ec31748d98951d,
61 0xc6ef5bf4737dcf70,
62 0xfffffffffffffffe,
63 0x0fffffffffffffff,
64]);
65
66const R2: Fr = Fr([
69 0xa40611e3449c0f01,
70 0xd00e1ba768859347,
71 0xceec73d217f5be65,
72 0x0399411b7c309a3d,
73]);
74
75const R3: Fr = Fr([
78 0x2a9e49687b83a2db,
79 0x278324e6aef7f3ec,
80 0x8065dc6c04ec5b65,
81 0x0e530b773599cec7,
82]);
83
84const TWO_INV: Fr = Fr::from_raw([
86 0x2c09318d2e7ae9f7,
87 0x0a6f7cef517bce6b,
88 0x0000000000000000,
89 0x0800000000000000,
90]);
91
92const SQRT_MINUS_ONE: Fr = Fr::from_raw([
94 0xbe8775dfebbe07d4,
95 0x0ef0565342ce83fe,
96 0x7d3d6d60abc1c27a,
97 0x094a7310e07981e7,
98]);
99
100const ZETA: Fr = Fr::from_raw([
104 0x158687e51e07e223,
105 0x471dd911c6cce91e,
106 0xeb08f579fb8841ae,
107 0x0378d9ddc674005f,
108]);
109const ROOT_OF_UNITY: Fr = Fr::from_raw([
115 0xbe8775dfebbe07d4,
116 0x0ef0565342ce83fe,
117 0x7d3d6d60abc1c27a,
118 0x094a7310e07981e7,
119]);
120const ROOT_OF_UNITY_INV: Fr = Fr::from_raw([
122 0x998aed3a7137cc19,
123 0x05eea38b602918d7,
124 0x82c2929f543e3d86,
125 0x06b58cef1f867e18,
126]);
127const 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 fn sqrt(&self) -> CtOption<Self> {
190 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 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 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 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 let is_some = (borrow as u8) & 1;
279
280 tmp *= &R2;
283
284 CtOption::new(tmp, Choice::from(is_some))
285 }
286
287 fn to_repr(&self) -> Self::Repr {
288 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 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 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}