halo2curves_axiom/secp256k1/
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 0xfffffffefffffc2f,
33 0xffffffffffffffff,
34 0xffffffffffffffff,
35 0xffffffffffffffff,
36]);
37
38const MULTIPLICATIVE_GENERATOR: Fp = Fp::from_raw([0x03, 0x00, 0x00, 0x00]);
41
42#[cfg(not(target_pointer_width = "64"))]
44const MODULUS_LIMBS_32: [u32; 8] = [
45 0xffff_fc2f,
46 0xffff_fffe,
47 0xffff_ffff,
48 0xffff_ffff,
49 0xffff_ffff,
50 0xffff_ffff,
51 0xffff_ffff,
52 0xffff_ffff,
53];
54
55const MODULUS_STR: &str = "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f";
57
58const INV: u64 = 0xd838091dd2253531;
60
61const R: Fp = Fp([0x1000003d1, 0, 0, 0]);
64
65const R2: Fp = Fp([0x000007a2000e90a1, 0x1, 0, 0]);
68
69const R3: Fp = Fp([0x002bb1e33795f671, 0x100000b73, 0, 0]);
72
73const TWO_INV: Fp = Fp::from_raw([
75 0xffffffff7ffffe18,
76 0xffffffffffffffff,
77 0xffffffffffffffff,
78 0x7fffffffffffffff,
79]);
80
81const ZETA: Fp = Fp::from_raw([
82 0xc1396c28719501ee,
83 0x9cf0497512f58995,
84 0x6e64479eac3434e9,
85 0x7ae96a2b657c0710,
86]);
87
88const DELTA: Fp = Fp([0x900002259u64, 0, 0, 0]);
92
93const ROOT_OF_UNITY: Fp = Fp([
100 0xfffffffdfffff85eu64,
101 0xffffffffffffffffu64,
102 0xffffffffffffffffu64,
103 0xffffffffffffffffu64,
104]);
105
106const ROOT_OF_UNITY_INV: Fp = Fp([
108 0xfffffffdfffff85eu64,
109 0xffffffffffffffffu64,
110 0xffffffffffffffffu64,
111 0xffffffffffffffffu64,
112]);
113
114impl_binops_additive!(Fp, Fp);
115impl_binops_multiplicative!(Fp, Fp);
116field_common!(
117 Fp,
118 MODULUS,
119 INV,
120 MODULUS_STR,
121 TWO_INV,
122 ROOT_OF_UNITY_INV,
123 DELTA,
124 ZETA,
125 R,
126 R2,
127 R3
128);
129impl_from_u64!(Fp, R2);
130field_arithmetic!(Fp, MODULUS, INV, dense);
131impl_sum_prod!(Fp);
132
133#[cfg(target_pointer_width = "64")]
134field_bits!(Fp, MODULUS);
135#[cfg(not(target_pointer_width = "64"))]
136field_bits!(Fp, MODULUS, MODULUS_LIMBS_32);
137
138impl Fp {
139 pub const fn size() -> usize {
140 32
141 }
142}
143
144impl ff::Field for Fp {
145 const ZERO: Self = Self::zero();
146 const ONE: Self = Self::one();
147
148 fn random(mut rng: impl RngCore) -> Self {
149 Self::from_u512([
150 rng.next_u64(),
151 rng.next_u64(),
152 rng.next_u64(),
153 rng.next_u64(),
154 rng.next_u64(),
155 rng.next_u64(),
156 rng.next_u64(),
157 rng.next_u64(),
158 ])
159 }
160
161 fn double(&self) -> Self {
162 self.double()
163 }
164
165 #[inline(always)]
166 fn square(&self) -> Self {
167 self.square()
168 }
169
170 fn sqrt(&self) -> CtOption<Self> {
172 let tmp = self.pow([
173 0xffffffffbfffff0c,
174 0xffffffffffffffff,
175 0xffffffffffffffff,
176 0x3fffffffffffffff,
177 ]);
178
179 CtOption::new(tmp, tmp.square().ct_eq(self))
180 }
181
182 fn invert(&self) -> CtOption<Self> {
185 self.invert()
186 }
187
188 fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
189 let mut res = Self::one();
190 let mut found_one = false;
191 for e in exp.as_ref().iter().rev() {
192 for i in (0..64).rev() {
193 if found_one {
194 res = res.square();
195 }
196
197 if ((*e >> i) & 1) == 1 {
198 found_one = true;
199 res *= self;
200 }
201 }
202 }
203 res
204 }
205
206 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
207 ff::helpers::sqrt_ratio_generic(num, div)
208 }
209}
210
211impl ff::PrimeField for Fp {
212 type Repr = [u8; 32];
213
214 const MODULUS: &'static str = MODULUS_STR;
215 const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR;
216 const TWO_INV: Self = TWO_INV;
217 const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
218 const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
219 const DELTA: Self = DELTA;
220 const NUM_BITS: u32 = 256;
221 const CAPACITY: u32 = 255;
222 const S: u32 = 1;
223
224 fn from_repr(repr: Self::Repr) -> CtOption<Self> {
225 let mut tmp = Fp([0, 0, 0, 0]);
226
227 tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
228 tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
229 tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
230 tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
231
232 let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
234 let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
235 let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
236 let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
237
238 let is_some = (borrow as u8) & 1;
242
243 tmp *= &R2;
246
247 CtOption::new(tmp, Choice::from(is_some))
248 }
249
250 fn to_repr(&self) -> Self::Repr {
251 let tmp: [u64; 4] = (*self).into();
252 let mut res = [0; 32];
253 res[0..8].copy_from_slice(&tmp[0].to_le_bytes());
254 res[8..16].copy_from_slice(&tmp[1].to_le_bytes());
255 res[16..24].copy_from_slice(&tmp[2].to_le_bytes());
256 res[24..32].copy_from_slice(&tmp[3].to_le_bytes());
257
258 res
259 }
260
261 fn from_u128(v: u128) -> Self {
262 Self::from_raw([v as u64, (v >> 64) as u64, 0, 0])
263 }
264
265 fn is_odd(&self) -> Choice {
266 Choice::from(self.to_repr()[0] & 1)
267 }
268}
269
270impl FromUniformBytes<64> for Fp {
271 fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
274 Self::from_u512([
275 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
276 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
277 u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
278 u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
279 u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
280 u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
281 u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
282 u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
283 ])
284 }
285}
286
287impl WithSmallOrderMulGroup<3> for Fp {
288 const ZETA: Self = ZETA;
289}
290
291extend_field_legendre!(Fp);
292
293#[cfg(test)]
294mod test {
295 use super::*;
296 use ff::Field;
297 use rand_core::OsRng;
298
299 #[test]
300 fn test_sqrt() {
301 let v = (Fp::TWO_INV).square().sqrt().unwrap();
303 assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV);
304
305 for _ in 0..10000 {
306 let a = Fp::random(OsRng);
307 let mut b = a;
308 b = b.square();
309
310 let b = b.sqrt().unwrap();
311 let mut negb = b;
312 negb = negb.neg();
313
314 assert!(a == b || a == negb);
315 }
316 }
317
318 #[test]
319 fn test_constants() {
320 assert_eq!(
321 Fp::MODULUS,
322 "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
323 );
324
325 assert_eq!(Fp::from(2) * Fp::TWO_INV, Fp::ONE);
326 }
327
328 #[test]
329 fn test_delta() {
330 assert_eq!(Fp::DELTA, MULTIPLICATIVE_GENERATOR.pow([1u64 << Fp::S]));
331 }
332
333 #[test]
334 fn test_root_of_unity() {
335 assert_eq!(Fp::ROOT_OF_UNITY.pow_vartime([1 << Fp::S]), Fp::one());
336 }
337
338 #[test]
339 fn test_inv_root_of_unity() {
340 assert_eq!(Fp::ROOT_OF_UNITY_INV, Fp::ROOT_OF_UNITY.invert().unwrap());
341 }
342
343 #[test]
344 fn test_field() {
345 crate::tests::field::random_field_tests::<Fp>("secp256k1 base".to_string());
346 }
347
348 #[test]
349 fn test_conversion() {
350 crate::tests::field::random_conversion_tests::<Fp>("secp256k1 base".to_string());
351 }
352
353 #[test]
354 #[cfg(feature = "bits")]
355 fn test_bits() {
356 crate::tests::field::random_bits_tests::<Fp>("secp256k1 base".to_string());
357 }
358
359 #[test]
360 fn test_serialization() {
361 crate::tests::field::random_serialization_test::<Fp>("secp256k1 base".to_string());
362 #[cfg(feature = "derive_serde")]
363 crate::tests::field::random_serde_test::<Fp>("secp256k1 base".to_string());
364 }
365
366 #[test]
367 fn test_quadratic_residue() {
368 crate::tests::field::random_quadratic_residue_test::<Fp>();
369 }
370}