halo2curves_axiom/secp256r1/
fq.rs
1use crate::arithmetic::{adc, bigint_geq, mac, macx, sbb};
2use crate::extend_field_legendre;
3use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
4use core::fmt;
5use core::ops::{Add, Mul, Neg, Sub};
6use rand::RngCore;
7use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
8
9#[derive(Clone, Copy, PartialEq, Eq, Hash)]
18pub struct Fq(pub(crate) [u64; 4]);
19
20#[cfg(feature = "derive_serde")]
21crate::serialize_deserialize_32_byte_primefield!(Fq);
22
23const MODULUS: Fq = Fq([
26 0xf3b9cac2fc632551,
27 0xbce6faada7179e84,
28 0xffffffffffffffff,
29 0xffffffff00000000,
30]);
31
32#[cfg(not(target_pointer_width = "64"))]
34const MODULUS_LIMBS_32: [u32; 8] = [
35 0xfc63_2551,
36 0xf3b9_cac2,
37 0xa717_9e84,
38 0xbce6_faad,
39 0xffff_ffff,
40 0xffff_ffff,
41 0x0000_0000,
42 0xffff_ffff,
43];
44
45const MODULUS_STR: &str = "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551";
47
48const INV: u64 = 0xccd1c8aaee00bc4f;
50
51const R: Fq = Fq([
54 0x0c46353d039cdaaf,
55 0x4319055258e8617b,
56 0x0000000000000000,
57 0xffffffff,
58]);
59
60const R2: Fq = Fq([
63 0x83244c95be79eea2,
64 0x4699799c49bd6fa6,
65 0x2845b2392b6bec59,
66 0x66e12d94f3d95620,
67]);
68
69const R3: Fq = Fq([
72 0xac8ebec90b65a624,
73 0x111f28ae0c0555c9,
74 0x2543b9246ba5e93f,
75 0x503a54e76407be65,
76]);
77
78const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]);
82
83const ROOT_OF_UNITY: Fq = Fq::from_raw([
86 0x0592d7fbb41e6602,
87 0x1546cad004378daf,
88 0xba807ace842a3dfc,
89 0xffc97f062a770992,
90]);
91
92const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([
95 0x379c7f0657c73764,
96 0xe3ac117c794c4137,
97 0xc645fa0458131cae,
98 0xa0a66a5562d46f2a,
99]);
100
101const TWO_INV: Fq = Fq::from_raw([
103 0x79dce5617e3192a9,
104 0xde737d56d38bcf42,
105 0x7fffffffffffffff,
106 0x7fffffff80000000,
107]);
108
109const ZETA: Fq = Fq::from_raw([
110 0x7cbf87ff12884e21,
111 0x9405335ce9c83e1d,
112 0x4e786d0777fd6aef,
113 0x52891d43d946a035,
114]);
115
116const DELTA: Fq = Fq::from_raw([0x1e39a5057d81, 0, 0, 0]);
119
120use crate::{
121 field_arithmetic, field_common, field_specific, impl_add_binop_specify_output,
122 impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
123 impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod,
124};
125impl_binops_additive!(Fq, Fq);
126impl_binops_multiplicative!(Fq, Fq);
127field_common!(
128 Fq,
129 MODULUS,
130 INV,
131 MODULUS_STR,
132 TWO_INV,
133 ROOT_OF_UNITY_INV,
134 DELTA,
135 ZETA,
136 R,
137 R2,
138 R3
139);
140impl_from_u64!(Fq, R2);
141field_arithmetic!(Fq, MODULUS, INV, dense);
142impl_sum_prod!(Fq);
143
144impl Fq {
145 pub const fn size() -> usize {
146 32
147 }
148}
149
150impl ff::Field for Fq {
151 const ZERO: Self = Self::zero();
152 const ONE: Self = Self::one();
153
154 fn random(mut rng: impl RngCore) -> Self {
155 Self::from_u512([
156 rng.next_u64(),
157 rng.next_u64(),
158 rng.next_u64(),
159 rng.next_u64(),
160 rng.next_u64(),
161 rng.next_u64(),
162 rng.next_u64(),
163 rng.next_u64(),
164 ])
165 }
166
167 fn double(&self) -> Self {
168 self.double()
169 }
170
171 #[inline(always)]
172 fn square(&self) -> Self {
173 self.square()
174 }
175
176 fn invert(&self) -> CtOption<Self> {
179 self.invert()
180 }
181
182 fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
183 let mut res = Self::one();
184 let mut found_one = false;
185 for e in exp.as_ref().iter().rev() {
186 for i in (0..64).rev() {
187 if found_one {
188 res = res.square();
189 }
190
191 if ((*e >> i) & 1) == 1 {
192 found_one = true;
193 res *= self;
194 }
195 }
196 }
197 res
198 }
199
200 fn sqrt(&self) -> CtOption<Self> {
201 let tm1d2 = [
203 0x279dce5617e3192a,
204 0xfde737d56d38bcf4,
205 0x07ffffffffffffff,
206 0x7fffffff8000000,
207 ];
208
209 ff::helpers::sqrt_tonelli_shanks(self, tm1d2)
210 }
211
212 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
213 ff::helpers::sqrt_ratio_generic(num, div)
214 }
215}
216
217impl ff::PrimeField for Fq {
218 type Repr = [u8; 32];
219
220 const NUM_BITS: u32 = 256;
221 const CAPACITY: u32 = 255;
222 const MODULUS: &'static str = MODULUS_STR;
223 const MULTIPLICATIVE_GENERATOR: Self = GENERATOR;
224 const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
225 const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
226 const TWO_INV: Self = TWO_INV;
227 const DELTA: Self = DELTA;
228 const S: u32 = 4;
229
230 fn from_repr(repr: Self::Repr) -> CtOption<Self> {
231 let mut tmp = Fq([0, 0, 0, 0]);
232
233 tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
234 tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
235 tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
236 tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
237
238 let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
240 let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
241 let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
242 let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
243
244 let is_some = (borrow as u8) & 1;
248
249 tmp *= &R2;
252
253 CtOption::new(tmp, Choice::from(is_some))
254 }
255
256 fn to_repr(&self) -> Self::Repr {
257 let tmp: [u64; 4] = (*self).into();
258 let mut res = [0; 32];
259 res[0..8].copy_from_slice(&tmp[0].to_le_bytes());
260 res[8..16].copy_from_slice(&tmp[1].to_le_bytes());
261 res[16..24].copy_from_slice(&tmp[2].to_le_bytes());
262 res[24..32].copy_from_slice(&tmp[3].to_le_bytes());
263
264 res
265 }
266
267 fn is_odd(&self) -> Choice {
268 Choice::from(self.to_repr()[0] & 1)
269 }
270}
271
272impl FromUniformBytes<64> for Fq {
273 fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
276 Self::from_u512([
277 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
278 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
279 u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
280 u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
281 u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
282 u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
283 u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
284 u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
285 ])
286 }
287}
288
289impl WithSmallOrderMulGroup<3> for Fq {
290 const ZETA: Self = ZETA;
291}
292
293extend_field_legendre!(Fq);
294
295#[cfg(test)]
296mod test {
297 use super::*;
298 use ff::Field;
299 use rand_core::OsRng;
300
301 #[test]
302 fn test_zeta() {
303 assert_eq!(Fq::ZETA * Fq::ZETA * Fq::ZETA, Fq::ONE);
304 assert_ne!(Fq::ZETA * Fq::ZETA, Fq::ONE);
305 }
306
307 #[test]
308 fn test_sqrt() {
309 for _ in 0..10000 {
314 let a = Fq::random(OsRng);
315 let mut b = a;
316 b = b.square();
317
318 let b = b.sqrt().unwrap();
319 let mut negb = b;
320 negb = negb.neg();
321
322 assert!(a == b || a == negb);
323 }
324 }
325
326 #[test]
327 fn test_constants() {
328 assert_eq!(
329 Fq::MODULUS,
330 "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
331 );
332
333 assert_eq!(Fq::from(2) * Fq::TWO_INV, Fq::ONE);
334 }
335
336 #[test]
337 fn test_delta() {
338 assert_eq!(Fq::DELTA, Fq::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fq::S]));
339 }
340
341 #[test]
342 fn test_root_of_unity() {
343 assert_eq!(Fq::ROOT_OF_UNITY.pow_vartime([1 << Fq::S]), Fq::one());
344 }
345
346 #[test]
347 fn test_inv_root_of_unity() {
348 assert_eq!(Fq::ROOT_OF_UNITY_INV, Fq::ROOT_OF_UNITY.invert().unwrap());
349 }
350
351 #[test]
352 fn test_field() {
353 crate::tests::field::random_field_tests::<Fq>("secp256r1 scalar".to_string());
354 }
355
356 #[test]
357 fn test_conversion() {
358 crate::tests::field::random_conversion_tests::<Fq>("secp256r1 scalar".to_string());
359 }
360
361 #[test]
362 fn test_serialization() {
363 crate::tests::field::random_serialization_test::<Fq>("secp256r1 scalar".to_string());
364 #[cfg(feature = "derive_serde")]
365 crate::tests::field::random_serde_test::<Fq>("secp256r1 scalar".to_string());
366 }
367
368 #[test]
369 fn test_quadratic_residue() {
370 crate::tests::field::random_quadratic_residue_test::<Fq>();
371 }
372}