halo2curves_axiom/secp256r1/
fp.rs
1use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb};
2use crate::extend_field_legendre;
3use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
4use crate::{
5 field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output,
6 impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
7 impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod,
8};
9use core::convert::TryInto;
10use core::fmt;
11use core::ops::{Add, Mul, Neg, Sub};
12use rand::RngCore;
13use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
14
15#[derive(Clone, Copy, PartialEq, Eq, Hash)]
24pub struct Fp(pub(crate) [u64; 4]);
25
26#[cfg(feature = "derive_serde")]
27crate::serialize_deserialize_32_byte_primefield!(Fp);
28
29const MODULUS: Fp = Fp([
32 0xffffffffffffffff,
33 0x00000000ffffffff,
34 0x0000000000000000,
35 0xffffffff00000001,
36]);
37
38const MULTIPLICATIVE_GENERATOR: Fp = Fp::from_raw([0x06, 0x00, 0x00, 0x00]);
41
42#[cfg(not(target_pointer_width = "64"))]
44const MODULUS_LIMBS_32: [u32; 8] = [
45 0xffff_ffff,
46 0xffff_ffff,
47 0xffff_ffff,
48 0x0000_0000,
49 0x0000_0000,
50 0x0000_0000,
51 0x0000_0001,
52 0xffff_ffff,
53];
54
55const MODULUS_STR: &str = "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
57
58const INV: u64 = 0x1;
60
61const R: Fp = Fp([
64 0x0000000000000001,
65 0xffffffff00000000,
66 0xffffffffffffffff,
67 0xfffffffe,
68]);
69
70const R2: Fp = Fp([
73 0x0000000000000003,
74 0xfffffffbffffffff,
75 0xfffffffffffffffe,
76 0x4fffffffd,
77]);
78
79const R3: Fp = Fp([
82 0xfffffffd0000000a,
83 0xffffffedfffffff7,
84 0x00000005fffffffc,
85 0x1800000001,
86]);
87
88const TWO_INV: Fp = Fp::from_raw([
91 0x0000000000000000,
92 0x0000000080000000,
93 0x8000000000000000,
94 0x7fffffff80000000,
95]);
96
97const ZETA: Fp = Fp::from_raw([
98 0xd964598eb819acce,
99 0x2e68c59bdef3e53f,
100 0x62388a8e0ef62331,
101 0x4d6ea8928adb86cf,
102]);
103
104const DELTA: Fp = Fp::from_raw([0x24, 0, 0, 0]);
108
109const ROOT_OF_UNITY: Fp = Fp::from_raw([
117 0xfffffffffffffffe,
118 0x00000000ffffffff,
119 0x0000000000000000,
120 0xffffffff00000001,
121]);
122
123const ROOT_OF_UNITY_INV: Fp = Fp::from_raw([
126 0xfffffffffffffffe,
127 0x00000000ffffffff,
128 0x0000000000000000,
129 0xffffffff00000001,
130]);
131
132impl_binops_additive!(Fp, Fp);
133impl_binops_multiplicative!(Fp, Fp);
134field_common!(
135 Fp,
136 MODULUS,
137 INV,
138 MODULUS_STR,
139 TWO_INV,
140 ROOT_OF_UNITY_INV,
141 DELTA,
142 ZETA,
143 R,
144 R2,
145 R3
146);
147impl_from_u64!(Fp, R2);
148field_arithmetic!(Fp, MODULUS, INV, dense);
149impl_sum_prod!(Fp);
150
151#[cfg(target_pointer_width = "64")]
152field_bits!(Fp, MODULUS);
153#[cfg(not(target_pointer_width = "64"))]
154field_bits!(Fp, MODULUS, MODULUS_LIMBS_32);
155
156impl Fp {
157 pub const fn size() -> usize {
158 32
159 }
160}
161
162impl ff::Field for Fp {
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 tmp = self.pow([
191 0x0000000000000000,
192 0x0000000040000000,
193 0x4000000000000000,
194 0x3fffffffc0000000,
195 ]);
196
197 CtOption::new(tmp, tmp.square().ct_eq(self))
198 }
199
200 fn invert(&self) -> CtOption<Self> {
203 self.invert()
204 }
205
206 fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
207 let mut res = Self::one();
208 let mut found_one = false;
209 for e in exp.as_ref().iter().rev() {
210 for i in (0..64).rev() {
211 if found_one {
212 res = res.square();
213 }
214
215 if ((*e >> i) & 1) == 1 {
216 found_one = true;
217 res *= self;
218 }
219 }
220 }
221 res
222 }
223
224 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
225 ff::helpers::sqrt_ratio_generic(num, div)
226 }
227}
228
229impl ff::PrimeField for Fp {
230 type Repr = [u8; 32];
231
232 const MODULUS: &'static str = MODULUS_STR;
233 const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR;
234 const TWO_INV: Self = TWO_INV;
235 const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
236 const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
237 const DELTA: Self = DELTA;
238 const NUM_BITS: u32 = 256;
239 const CAPACITY: u32 = 255;
240 const S: u32 = 1;
241
242 fn from_repr(repr: Self::Repr) -> CtOption<Self> {
243 let mut tmp = Fp([0, 0, 0, 0]);
244
245 tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
246 tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
247 tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
248 tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
249
250 let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
252 let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
253 let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
254 let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
255
256 let is_some = (borrow as u8) & 1;
260
261 tmp *= &R2;
264
265 CtOption::new(tmp, Choice::from(is_some))
266 }
267
268 fn to_repr(&self) -> Self::Repr {
269 let tmp: [u64; 4] = (*self).into();
270 let mut res = [0; 32];
271 res[0..8].copy_from_slice(&tmp[0].to_le_bytes());
272 res[8..16].copy_from_slice(&tmp[1].to_le_bytes());
273 res[16..24].copy_from_slice(&tmp[2].to_le_bytes());
274 res[24..32].copy_from_slice(&tmp[3].to_le_bytes());
275
276 res
277 }
278
279 fn from_u128(v: u128) -> Self {
280 Self::from_raw([v as u64, (v >> 64) as u64, 0, 0])
281 }
282
283 fn is_odd(&self) -> Choice {
284 Choice::from(self.to_repr()[0] & 1)
285 }
286}
287
288impl FromUniformBytes<64> for Fp {
289 fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
292 Self::from_u512([
293 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
294 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
295 u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
296 u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
297 u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
298 u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
299 u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
300 u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
301 ])
302 }
303}
304
305impl WithSmallOrderMulGroup<3> for Fp {
306 const ZETA: Self = ZETA;
307}
308
309extend_field_legendre!(Fp);
310
311#[cfg(test)]
312mod test {
313 use super::*;
314 use ff::Field;
315 use rand_core::OsRng;
316
317 #[test]
318 fn test_sqrt() {
319 let v = (Fp::TWO_INV).square().sqrt().unwrap();
321 assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV);
322
323 for _ in 0..10000 {
324 let a = Fp::random(OsRng);
325 let mut b = a;
326 b = b.square();
327
328 let b = b.sqrt().unwrap();
329 let mut negb = b;
330 negb = negb.neg();
331
332 assert!(a == b || a == negb);
333 }
334 }
335
336 #[test]
337 fn test_constants() {
338 assert_eq!(
339 Fp::MODULUS,
340 "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
341 );
342
343 assert_eq!(Fp::from(2) * Fp::TWO_INV, Fp::ONE);
344 }
345
346 #[test]
347 fn test_delta() {
348 assert_eq!(Fp::DELTA, MULTIPLICATIVE_GENERATOR.pow([1u64 << Fp::S]));
349 }
350
351 #[test]
352 fn test_root_of_unity() {
353 assert_eq!(Fp::ROOT_OF_UNITY.pow_vartime([1 << Fp::S]), Fp::one());
354 }
355
356 #[test]
357 fn test_inv_root_of_unity() {
358 assert_eq!(Fp::ROOT_OF_UNITY_INV, Fp::ROOT_OF_UNITY.invert().unwrap());
359 }
360
361 #[test]
362 fn test_field() {
363 crate::tests::field::random_field_tests::<Fp>("secp256r1 base".to_string());
364 }
365
366 #[test]
367 fn test_conversion() {
368 crate::tests::field::random_conversion_tests::<Fp>("secp256r1 base".to_string());
369 }
370
371 #[test]
372 #[cfg(feature = "bits")]
373 fn test_bits() {
374 crate::tests::field::random_bits_tests::<Fp>("secp256r1 base".to_string());
375 }
376
377 #[test]
378 fn test_serialization() {
379 crate::tests::field::random_serialization_test::<Fp>("secp256r1 base".to_string());
380 #[cfg(feature = "derive_serde")]
381 crate::tests::field::random_serde_test::<Fp>("secp256r1 base".to_string());
382 }
383
384 #[test]
385 fn test_quadratic_residue() {
386 crate::tests::field::random_quadratic_residue_test::<Fp>();
387 }
388}