1use core::fmt;
5use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
6use rand_core::RngCore;
7use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
8
9use crate::util::{adc, mac, sbb};
10
11#[derive(Copy, Clone)]
15pub struct Fp(pub(crate) [u64; 6]);
16
17impl fmt::Debug for Fp {
18 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19 let tmp = self.to_bytes();
20 write!(f, "0x")?;
21 for &b in tmp.iter() {
22 write!(f, "{:02x}", b)?;
23 }
24 Ok(())
25 }
26}
27
28impl Default for Fp {
29 fn default() -> Self {
30 Fp::zero()
31 }
32}
33
34#[cfg(feature = "zeroize")]
35impl zeroize::DefaultIsZeroes for Fp {}
36
37impl ConstantTimeEq for Fp {
38 fn ct_eq(&self, other: &Self) -> Choice {
39 self.0[0].ct_eq(&other.0[0])
40 & self.0[1].ct_eq(&other.0[1])
41 & self.0[2].ct_eq(&other.0[2])
42 & self.0[3].ct_eq(&other.0[3])
43 & self.0[4].ct_eq(&other.0[4])
44 & self.0[5].ct_eq(&other.0[5])
45 }
46}
47
48impl Eq for Fp {}
49impl PartialEq for Fp {
50 #[inline]
51 fn eq(&self, other: &Self) -> bool {
52 bool::from(self.ct_eq(other))
53 }
54}
55
56impl ConditionallySelectable for Fp {
57 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
58 Fp([
59 u64::conditional_select(&a.0[0], &b.0[0], choice),
60 u64::conditional_select(&a.0[1], &b.0[1], choice),
61 u64::conditional_select(&a.0[2], &b.0[2], choice),
62 u64::conditional_select(&a.0[3], &b.0[3], choice),
63 u64::conditional_select(&a.0[4], &b.0[4], choice),
64 u64::conditional_select(&a.0[5], &b.0[5], choice),
65 ])
66 }
67}
68
69const MODULUS: [u64; 6] = [
71 0xb9fe_ffff_ffff_aaab,
72 0x1eab_fffe_b153_ffff,
73 0x6730_d2a0_f6b0_f624,
74 0x6477_4b84_f385_12bf,
75 0x4b1b_a7b6_434b_acd7,
76 0x1a01_11ea_397f_e69a,
77];
78
79const INV: u64 = 0x89f3_fffc_fffc_fffd;
81
82const R: Fp = Fp([
84 0x7609_0000_0002_fffd,
85 0xebf4_000b_c40c_0002,
86 0x5f48_9857_53c7_58ba,
87 0x77ce_5853_7052_5745,
88 0x5c07_1a97_a256_ec6d,
89 0x15f6_5ec3_fa80_e493,
90]);
91
92const R2: Fp = Fp([
94 0xf4df_1f34_1c34_1746,
95 0x0a76_e6a6_09d1_04f1,
96 0x8de5_476c_4c95_b6d5,
97 0x67eb_88a9_939d_83c0,
98 0x9a79_3e85_b519_952d,
99 0x1198_8fe5_92ca_e3aa,
100]);
101
102const R3: Fp = Fp([
104 0xed48_ac6b_d94c_a1e0,
105 0x315f_831e_03a7_adf8,
106 0x9a53_352a_615e_29dd,
107 0x34c0_4e5e_921e_1761,
108 0x2512_d435_6572_4728,
109 0x0aa6_3460_9175_5d4d,
110]);
111
112impl<'a> Neg for &'a Fp {
113 type Output = Fp;
114
115 #[inline]
116 fn neg(self) -> Fp {
117 self.neg()
118 }
119}
120
121impl Neg for Fp {
122 type Output = Fp;
123
124 #[inline]
125 fn neg(self) -> Fp {
126 -&self
127 }
128}
129
130impl<'a, 'b> Sub<&'b Fp> for &'a Fp {
131 type Output = Fp;
132
133 #[inline]
134 fn sub(self, rhs: &'b Fp) -> Fp {
135 self.sub(rhs)
136 }
137}
138
139impl<'a, 'b> Add<&'b Fp> for &'a Fp {
140 type Output = Fp;
141
142 #[inline]
143 fn add(self, rhs: &'b Fp) -> Fp {
144 self.add(rhs)
145 }
146}
147
148impl<'a, 'b> Mul<&'b Fp> for &'a Fp {
149 type Output = Fp;
150
151 #[inline]
152 fn mul(self, rhs: &'b Fp) -> Fp {
153 self.mul(rhs)
154 }
155}
156
157impl_binops_additive!(Fp, Fp);
158impl_binops_multiplicative!(Fp, Fp);
159
160impl Fp {
161 #[inline]
163 pub const fn zero() -> Fp {
164 Fp([0, 0, 0, 0, 0, 0])
165 }
166
167 #[inline]
169 pub const fn one() -> Fp {
170 R
171 }
172
173 pub fn is_zero(&self) -> Choice {
174 self.ct_eq(&Fp::zero())
175 }
176
177 pub fn from_bytes(bytes: &[u8; 48]) -> CtOption<Fp> {
180 let mut tmp = Fp([0, 0, 0, 0, 0, 0]);
181
182 tmp.0[5] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[0..8]).unwrap());
183 tmp.0[4] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[8..16]).unwrap());
184 tmp.0[3] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[16..24]).unwrap());
185 tmp.0[2] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[24..32]).unwrap());
186 tmp.0[1] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[32..40]).unwrap());
187 tmp.0[0] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[40..48]).unwrap());
188
189 let (_, borrow) = sbb(tmp.0[0], MODULUS[0], 0);
191 let (_, borrow) = sbb(tmp.0[1], MODULUS[1], borrow);
192 let (_, borrow) = sbb(tmp.0[2], MODULUS[2], borrow);
193 let (_, borrow) = sbb(tmp.0[3], MODULUS[3], borrow);
194 let (_, borrow) = sbb(tmp.0[4], MODULUS[4], borrow);
195 let (_, borrow) = sbb(tmp.0[5], MODULUS[5], borrow);
196
197 let is_some = (borrow as u8) & 1;
201
202 tmp *= &R2;
205
206 CtOption::new(tmp, Choice::from(is_some))
207 }
208
209 pub fn to_bytes(self) -> [u8; 48] {
212 let tmp = Fp::montgomery_reduce(
215 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], 0, 0, 0, 0, 0, 0,
216 );
217
218 let mut res = [0; 48];
219 res[0..8].copy_from_slice(&tmp.0[5].to_be_bytes());
220 res[8..16].copy_from_slice(&tmp.0[4].to_be_bytes());
221 res[16..24].copy_from_slice(&tmp.0[3].to_be_bytes());
222 res[24..32].copy_from_slice(&tmp.0[2].to_be_bytes());
223 res[32..40].copy_from_slice(&tmp.0[1].to_be_bytes());
224 res[40..48].copy_from_slice(&tmp.0[0].to_be_bytes());
225
226 res
227 }
228
229 pub(crate) fn random(mut rng: impl RngCore) -> Fp {
230 let mut bytes = [0u8; 96];
231 rng.fill_bytes(&mut bytes);
232
233 Fp::from_u768([
235 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[0..8]).unwrap()),
236 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[8..16]).unwrap()),
237 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[16..24]).unwrap()),
238 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[24..32]).unwrap()),
239 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[32..40]).unwrap()),
240 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[40..48]).unwrap()),
241 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[48..56]).unwrap()),
242 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[56..64]).unwrap()),
243 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[64..72]).unwrap()),
244 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[72..80]).unwrap()),
245 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[80..88]).unwrap()),
246 u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[88..96]).unwrap()),
247 ])
248 }
249
250 fn from_u768(limbs: [u64; 12]) -> Fp {
252 let d1 = Fp([limbs[11], limbs[10], limbs[9], limbs[8], limbs[7], limbs[6]]);
266 let d0 = Fp([limbs[5], limbs[4], limbs[3], limbs[2], limbs[1], limbs[0]]);
267 d0 * R2 + d1 * R3
269 }
270
271 pub fn lexicographically_largest(&self) -> Choice {
274 let tmp = Fp::montgomery_reduce(
281 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], 0, 0, 0, 0, 0, 0,
282 );
283
284 let (_, borrow) = sbb(tmp.0[0], 0xdcff_7fff_ffff_d556, 0);
285 let (_, borrow) = sbb(tmp.0[1], 0x0f55_ffff_58a9_ffff, borrow);
286 let (_, borrow) = sbb(tmp.0[2], 0xb398_6950_7b58_7b12, borrow);
287 let (_, borrow) = sbb(tmp.0[3], 0xb23b_a5c2_79c2_895f, borrow);
288 let (_, borrow) = sbb(tmp.0[4], 0x258d_d3db_21a5_d66b, borrow);
289 let (_, borrow) = sbb(tmp.0[5], 0x0d00_88f5_1cbf_f34d, borrow);
290
291 !Choice::from((borrow as u8) & 1)
298 }
299
300 pub const fn from_raw_unchecked(v: [u64; 6]) -> Fp {
303 Fp(v)
304 }
305
306 pub fn pow_vartime(&self, by: &[u64; 6]) -> Self {
310 let mut res = Self::one();
311 for e in by.iter().rev() {
312 for i in (0..64).rev() {
313 res = res.square();
314
315 if ((*e >> i) & 1) == 1 {
316 res *= self;
317 }
318 }
319 }
320 res
321 }
322
323 #[inline]
324 pub fn sqrt(&self) -> CtOption<Self> {
325 let sqrt = self.pow_vartime(&[
331 0xee7f_bfff_ffff_eaab,
332 0x07aa_ffff_ac54_ffff,
333 0xd9cc_34a8_3dac_3d89,
334 0xd91d_d2e1_3ce1_44af,
335 0x92c6_e9ed_90d2_eb35,
336 0x0680_447a_8e5f_f9a6,
337 ]);
338
339 CtOption::new(sqrt, sqrt.square().ct_eq(self))
340 }
341
342 #[inline]
343 pub fn invert(&self) -> CtOption<Self> {
347 let t = self.pow_vartime(&[
349 0xb9fe_ffff_ffff_aaa9,
350 0x1eab_fffe_b153_ffff,
351 0x6730_d2a0_f6b0_f624,
352 0x6477_4b84_f385_12bf,
353 0x4b1b_a7b6_434b_acd7,
354 0x1a01_11ea_397f_e69a,
355 ]);
356
357 CtOption::new(t, !self.is_zero())
358 }
359
360 #[inline]
361 const fn subtract_p(&self) -> Fp {
362 let (r0, borrow) = sbb(self.0[0], MODULUS[0], 0);
363 let (r1, borrow) = sbb(self.0[1], MODULUS[1], borrow);
364 let (r2, borrow) = sbb(self.0[2], MODULUS[2], borrow);
365 let (r3, borrow) = sbb(self.0[3], MODULUS[3], borrow);
366 let (r4, borrow) = sbb(self.0[4], MODULUS[4], borrow);
367 let (r5, borrow) = sbb(self.0[5], MODULUS[5], borrow);
368
369 let r0 = (self.0[0] & borrow) | (r0 & !borrow);
372 let r1 = (self.0[1] & borrow) | (r1 & !borrow);
373 let r2 = (self.0[2] & borrow) | (r2 & !borrow);
374 let r3 = (self.0[3] & borrow) | (r3 & !borrow);
375 let r4 = (self.0[4] & borrow) | (r4 & !borrow);
376 let r5 = (self.0[5] & borrow) | (r5 & !borrow);
377
378 Fp([r0, r1, r2, r3, r4, r5])
379 }
380
381 #[inline]
382 pub const fn add(&self, rhs: &Fp) -> Fp {
383 let (d0, carry) = adc(self.0[0], rhs.0[0], 0);
384 let (d1, carry) = adc(self.0[1], rhs.0[1], carry);
385 let (d2, carry) = adc(self.0[2], rhs.0[2], carry);
386 let (d3, carry) = adc(self.0[3], rhs.0[3], carry);
387 let (d4, carry) = adc(self.0[4], rhs.0[4], carry);
388 let (d5, _) = adc(self.0[5], rhs.0[5], carry);
389
390 (&Fp([d0, d1, d2, d3, d4, d5])).subtract_p()
393 }
394
395 #[inline]
396 pub const fn neg(&self) -> Fp {
397 let (d0, borrow) = sbb(MODULUS[0], self.0[0], 0);
398 let (d1, borrow) = sbb(MODULUS[1], self.0[1], borrow);
399 let (d2, borrow) = sbb(MODULUS[2], self.0[2], borrow);
400 let (d3, borrow) = sbb(MODULUS[3], self.0[3], borrow);
401 let (d4, borrow) = sbb(MODULUS[4], self.0[4], borrow);
402 let (d5, _) = sbb(MODULUS[5], self.0[5], borrow);
403
404 let mask = (((self.0[0] | self.0[1] | self.0[2] | self.0[3] | self.0[4] | self.0[5]) == 0)
407 as u64)
408 .wrapping_sub(1);
409
410 Fp([
411 d0 & mask,
412 d1 & mask,
413 d2 & mask,
414 d3 & mask,
415 d4 & mask,
416 d5 & mask,
417 ])
418 }
419
420 #[inline]
421 pub const fn sub(&self, rhs: &Fp) -> Fp {
422 (&rhs.neg()).add(self)
423 }
424
425 #[inline]
430 pub(crate) fn sum_of_products<const T: usize>(a: [Fp; T], b: [Fp; T]) -> Fp {
431 let (u0, u1, u2, u3, u4, u5) =
448 (0..6).fold((0, 0, 0, 0, 0, 0), |(u0, u1, u2, u3, u4, u5), j| {
449 let (t0, t1, t2, t3, t4, t5, t6) = (0..T).fold(
452 (u0, u1, u2, u3, u4, u5, 0),
453 |(t0, t1, t2, t3, t4, t5, t6), i| {
454 let (t0, carry) = mac(t0, a[i].0[j], b[i].0[0], 0);
456 let (t1, carry) = mac(t1, a[i].0[j], b[i].0[1], carry);
457 let (t2, carry) = mac(t2, a[i].0[j], b[i].0[2], carry);
458 let (t3, carry) = mac(t3, a[i].0[j], b[i].0[3], carry);
459 let (t4, carry) = mac(t4, a[i].0[j], b[i].0[4], carry);
460 let (t5, carry) = mac(t5, a[i].0[j], b[i].0[5], carry);
461 let (t6, _) = adc(t6, 0, carry);
462
463 (t0, t1, t2, t3, t4, t5, t6)
464 },
465 );
466
467 let k = t0.wrapping_mul(INV);
470 let (_, carry) = mac(t0, k, MODULUS[0], 0);
471 let (r1, carry) = mac(t1, k, MODULUS[1], carry);
472 let (r2, carry) = mac(t2, k, MODULUS[2], carry);
473 let (r3, carry) = mac(t3, k, MODULUS[3], carry);
474 let (r4, carry) = mac(t4, k, MODULUS[4], carry);
475 let (r5, carry) = mac(t5, k, MODULUS[5], carry);
476 let (r6, _) = adc(t6, 0, carry);
477
478 (r1, r2, r3, r4, r5, r6)
479 });
480
481 (&Fp([u0, u1, u2, u3, u4, u5])).subtract_p()
484 }
485
486 #[inline(always)]
487 pub(crate) const fn montgomery_reduce(
488 t0: u64,
489 t1: u64,
490 t2: u64,
491 t3: u64,
492 t4: u64,
493 t5: u64,
494 t6: u64,
495 t7: u64,
496 t8: u64,
497 t9: u64,
498 t10: u64,
499 t11: u64,
500 ) -> Self {
501 let k = t0.wrapping_mul(INV);
506 let (_, carry) = mac(t0, k, MODULUS[0], 0);
507 let (r1, carry) = mac(t1, k, MODULUS[1], carry);
508 let (r2, carry) = mac(t2, k, MODULUS[2], carry);
509 let (r3, carry) = mac(t3, k, MODULUS[3], carry);
510 let (r4, carry) = mac(t4, k, MODULUS[4], carry);
511 let (r5, carry) = mac(t5, k, MODULUS[5], carry);
512 let (r6, r7) = adc(t6, 0, carry);
513
514 let k = r1.wrapping_mul(INV);
515 let (_, carry) = mac(r1, k, MODULUS[0], 0);
516 let (r2, carry) = mac(r2, k, MODULUS[1], carry);
517 let (r3, carry) = mac(r3, k, MODULUS[2], carry);
518 let (r4, carry) = mac(r4, k, MODULUS[3], carry);
519 let (r5, carry) = mac(r5, k, MODULUS[4], carry);
520 let (r6, carry) = mac(r6, k, MODULUS[5], carry);
521 let (r7, r8) = adc(t7, r7, carry);
522
523 let k = r2.wrapping_mul(INV);
524 let (_, carry) = mac(r2, k, MODULUS[0], 0);
525 let (r3, carry) = mac(r3, k, MODULUS[1], carry);
526 let (r4, carry) = mac(r4, k, MODULUS[2], carry);
527 let (r5, carry) = mac(r5, k, MODULUS[3], carry);
528 let (r6, carry) = mac(r6, k, MODULUS[4], carry);
529 let (r7, carry) = mac(r7, k, MODULUS[5], carry);
530 let (r8, r9) = adc(t8, r8, carry);
531
532 let k = r3.wrapping_mul(INV);
533 let (_, carry) = mac(r3, k, MODULUS[0], 0);
534 let (r4, carry) = mac(r4, k, MODULUS[1], carry);
535 let (r5, carry) = mac(r5, k, MODULUS[2], carry);
536 let (r6, carry) = mac(r6, k, MODULUS[3], carry);
537 let (r7, carry) = mac(r7, k, MODULUS[4], carry);
538 let (r8, carry) = mac(r8, k, MODULUS[5], carry);
539 let (r9, r10) = adc(t9, r9, carry);
540
541 let k = r4.wrapping_mul(INV);
542 let (_, carry) = mac(r4, k, MODULUS[0], 0);
543 let (r5, carry) = mac(r5, k, MODULUS[1], carry);
544 let (r6, carry) = mac(r6, k, MODULUS[2], carry);
545 let (r7, carry) = mac(r7, k, MODULUS[3], carry);
546 let (r8, carry) = mac(r8, k, MODULUS[4], carry);
547 let (r9, carry) = mac(r9, k, MODULUS[5], carry);
548 let (r10, r11) = adc(t10, r10, carry);
549
550 let k = r5.wrapping_mul(INV);
551 let (_, carry) = mac(r5, k, MODULUS[0], 0);
552 let (r6, carry) = mac(r6, k, MODULUS[1], carry);
553 let (r7, carry) = mac(r7, k, MODULUS[2], carry);
554 let (r8, carry) = mac(r8, k, MODULUS[3], carry);
555 let (r9, carry) = mac(r9, k, MODULUS[4], carry);
556 let (r10, carry) = mac(r10, k, MODULUS[5], carry);
557 let (r11, _) = adc(t11, r11, carry);
558
559 (&Fp([r6, r7, r8, r9, r10, r11])).subtract_p()
562 }
563
564 #[inline]
565 pub const fn mul(&self, rhs: &Fp) -> Fp {
566 let (t0, carry) = mac(0, self.0[0], rhs.0[0], 0);
567 let (t1, carry) = mac(0, self.0[0], rhs.0[1], carry);
568 let (t2, carry) = mac(0, self.0[0], rhs.0[2], carry);
569 let (t3, carry) = mac(0, self.0[0], rhs.0[3], carry);
570 let (t4, carry) = mac(0, self.0[0], rhs.0[4], carry);
571 let (t5, t6) = mac(0, self.0[0], rhs.0[5], carry);
572
573 let (t1, carry) = mac(t1, self.0[1], rhs.0[0], 0);
574 let (t2, carry) = mac(t2, self.0[1], rhs.0[1], carry);
575 let (t3, carry) = mac(t3, self.0[1], rhs.0[2], carry);
576 let (t4, carry) = mac(t4, self.0[1], rhs.0[3], carry);
577 let (t5, carry) = mac(t5, self.0[1], rhs.0[4], carry);
578 let (t6, t7) = mac(t6, self.0[1], rhs.0[5], carry);
579
580 let (t2, carry) = mac(t2, self.0[2], rhs.0[0], 0);
581 let (t3, carry) = mac(t3, self.0[2], rhs.0[1], carry);
582 let (t4, carry) = mac(t4, self.0[2], rhs.0[2], carry);
583 let (t5, carry) = mac(t5, self.0[2], rhs.0[3], carry);
584 let (t6, carry) = mac(t6, self.0[2], rhs.0[4], carry);
585 let (t7, t8) = mac(t7, self.0[2], rhs.0[5], carry);
586
587 let (t3, carry) = mac(t3, self.0[3], rhs.0[0], 0);
588 let (t4, carry) = mac(t4, self.0[3], rhs.0[1], carry);
589 let (t5, carry) = mac(t5, self.0[3], rhs.0[2], carry);
590 let (t6, carry) = mac(t6, self.0[3], rhs.0[3], carry);
591 let (t7, carry) = mac(t7, self.0[3], rhs.0[4], carry);
592 let (t8, t9) = mac(t8, self.0[3], rhs.0[5], carry);
593
594 let (t4, carry) = mac(t4, self.0[4], rhs.0[0], 0);
595 let (t5, carry) = mac(t5, self.0[4], rhs.0[1], carry);
596 let (t6, carry) = mac(t6, self.0[4], rhs.0[2], carry);
597 let (t7, carry) = mac(t7, self.0[4], rhs.0[3], carry);
598 let (t8, carry) = mac(t8, self.0[4], rhs.0[4], carry);
599 let (t9, t10) = mac(t9, self.0[4], rhs.0[5], carry);
600
601 let (t5, carry) = mac(t5, self.0[5], rhs.0[0], 0);
602 let (t6, carry) = mac(t6, self.0[5], rhs.0[1], carry);
603 let (t7, carry) = mac(t7, self.0[5], rhs.0[2], carry);
604 let (t8, carry) = mac(t8, self.0[5], rhs.0[3], carry);
605 let (t9, carry) = mac(t9, self.0[5], rhs.0[4], carry);
606 let (t10, t11) = mac(t10, self.0[5], rhs.0[5], carry);
607
608 Self::montgomery_reduce(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)
609 }
610
611 #[inline]
613 pub const fn square(&self) -> Self {
614 let (t1, carry) = mac(0, self.0[0], self.0[1], 0);
615 let (t2, carry) = mac(0, self.0[0], self.0[2], carry);
616 let (t3, carry) = mac(0, self.0[0], self.0[3], carry);
617 let (t4, carry) = mac(0, self.0[0], self.0[4], carry);
618 let (t5, t6) = mac(0, self.0[0], self.0[5], carry);
619
620 let (t3, carry) = mac(t3, self.0[1], self.0[2], 0);
621 let (t4, carry) = mac(t4, self.0[1], self.0[3], carry);
622 let (t5, carry) = mac(t5, self.0[1], self.0[4], carry);
623 let (t6, t7) = mac(t6, self.0[1], self.0[5], carry);
624
625 let (t5, carry) = mac(t5, self.0[2], self.0[3], 0);
626 let (t6, carry) = mac(t6, self.0[2], self.0[4], carry);
627 let (t7, t8) = mac(t7, self.0[2], self.0[5], carry);
628
629 let (t7, carry) = mac(t7, self.0[3], self.0[4], 0);
630 let (t8, t9) = mac(t8, self.0[3], self.0[5], carry);
631
632 let (t9, t10) = mac(t9, self.0[4], self.0[5], 0);
633
634 let t11 = t10 >> 63;
635 let t10 = (t10 << 1) | (t9 >> 63);
636 let t9 = (t9 << 1) | (t8 >> 63);
637 let t8 = (t8 << 1) | (t7 >> 63);
638 let t7 = (t7 << 1) | (t6 >> 63);
639 let t6 = (t6 << 1) | (t5 >> 63);
640 let t5 = (t5 << 1) | (t4 >> 63);
641 let t4 = (t4 << 1) | (t3 >> 63);
642 let t3 = (t3 << 1) | (t2 >> 63);
643 let t2 = (t2 << 1) | (t1 >> 63);
644 let t1 = t1 << 1;
645
646 let (t0, carry) = mac(0, self.0[0], self.0[0], 0);
647 let (t1, carry) = adc(t1, 0, carry);
648 let (t2, carry) = mac(t2, self.0[1], self.0[1], carry);
649 let (t3, carry) = adc(t3, 0, carry);
650 let (t4, carry) = mac(t4, self.0[2], self.0[2], carry);
651 let (t5, carry) = adc(t5, 0, carry);
652 let (t6, carry) = mac(t6, self.0[3], self.0[3], carry);
653 let (t7, carry) = adc(t7, 0, carry);
654 let (t8, carry) = mac(t8, self.0[4], self.0[4], carry);
655 let (t9, carry) = adc(t9, 0, carry);
656 let (t10, carry) = mac(t10, self.0[5], self.0[5], carry);
657 let (t11, _) = adc(t11, 0, carry);
658
659 Self::montgomery_reduce(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)
660 }
661}
662
663#[test]
664fn test_conditional_selection() {
665 let a = Fp([1, 2, 3, 4, 5, 6]);
666 let b = Fp([7, 8, 9, 10, 11, 12]);
667
668 assert_eq!(
669 ConditionallySelectable::conditional_select(&a, &b, Choice::from(0u8)),
670 a
671 );
672 assert_eq!(
673 ConditionallySelectable::conditional_select(&a, &b, Choice::from(1u8)),
674 b
675 );
676}
677
678#[test]
679fn test_equality() {
680 fn is_equal(a: &Fp, b: &Fp) -> bool {
681 let eq = a == b;
682 let ct_eq = a.ct_eq(&b);
683
684 assert_eq!(eq, bool::from(ct_eq));
685
686 eq
687 }
688
689 assert!(is_equal(&Fp([1, 2, 3, 4, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
690
691 assert!(!is_equal(&Fp([7, 2, 3, 4, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
692 assert!(!is_equal(&Fp([1, 7, 3, 4, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
693 assert!(!is_equal(&Fp([1, 2, 7, 4, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
694 assert!(!is_equal(&Fp([1, 2, 3, 7, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
695 assert!(!is_equal(&Fp([1, 2, 3, 4, 7, 6]), &Fp([1, 2, 3, 4, 5, 6])));
696 assert!(!is_equal(&Fp([1, 2, 3, 4, 5, 7]), &Fp([1, 2, 3, 4, 5, 6])));
697}
698
699#[test]
700fn test_squaring() {
701 let a = Fp([
702 0xd215_d276_8e83_191b,
703 0x5085_d80f_8fb2_8261,
704 0xce9a_032d_df39_3a56,
705 0x3e9c_4fff_2ca0_c4bb,
706 0x6436_b6f7_f4d9_5dfb,
707 0x1060_6628_ad4a_4d90,
708 ]);
709 let b = Fp([
710 0x33d9_c42a_3cb3_e235,
711 0xdad1_1a09_4c4c_d455,
712 0xa2f1_44bd_729a_aeba,
713 0xd415_0932_be9f_feac,
714 0xe27b_c7c4_7d44_ee50,
715 0x14b6_a78d_3ec7_a560,
716 ]);
717
718 assert_eq!(a.square(), b);
719}
720
721#[test]
722fn test_multiplication() {
723 let a = Fp([
724 0x0397_a383_2017_0cd4,
725 0x734c_1b2c_9e76_1d30,
726 0x5ed2_55ad_9a48_beb5,
727 0x095a_3c6b_22a7_fcfc,
728 0x2294_ce75_d4e2_6a27,
729 0x1333_8bd8_7001_1ebb,
730 ]);
731 let b = Fp([
732 0xb9c3_c7c5_b119_6af7,
733 0x2580_e208_6ce3_35c1,
734 0xf49a_ed3d_8a57_ef42,
735 0x41f2_81e4_9846_e878,
736 0xe076_2346_c384_52ce,
737 0x0652_e893_26e5_7dc0,
738 ]);
739 let c = Fp([
740 0xf96e_f3d7_11ab_5355,
741 0xe8d4_59ea_00f1_48dd,
742 0x53f7_354a_5f00_fa78,
743 0x9e34_a4f3_125c_5f83,
744 0x3fbe_0c47_ca74_c19e,
745 0x01b0_6a8b_bd4a_dfe4,
746 ]);
747
748 assert_eq!(a * b, c);
749}
750
751#[test]
752fn test_addition() {
753 let a = Fp([
754 0x5360_bb59_7867_8032,
755 0x7dd2_75ae_799e_128e,
756 0x5c5b_5071_ce4f_4dcf,
757 0xcdb2_1f93_078d_bb3e,
758 0xc323_65c5_e73f_474a,
759 0x115a_2a54_89ba_be5b,
760 ]);
761 let b = Fp([
762 0x9fd2_8773_3d23_dda0,
763 0xb16b_f2af_738b_3554,
764 0x3e57_a75b_d3cc_6d1d,
765 0x900b_c0bd_627f_d6d6,
766 0xd319_a080_efb2_45fe,
767 0x15fd_caa4_e4bb_2091,
768 ]);
769 let c = Fp([
770 0x3934_42cc_b58b_b327,
771 0x1092_685f_3bd5_47e3,
772 0x3382_252c_ab6a_c4c9,
773 0xf946_94cb_7688_7f55,
774 0x4b21_5e90_93a5_e071,
775 0x0d56_e30f_34f5_f853,
776 ]);
777
778 assert_eq!(a + b, c);
779}
780
781#[test]
782fn test_subtraction() {
783 let a = Fp([
784 0x5360_bb59_7867_8032,
785 0x7dd2_75ae_799e_128e,
786 0x5c5b_5071_ce4f_4dcf,
787 0xcdb2_1f93_078d_bb3e,
788 0xc323_65c5_e73f_474a,
789 0x115a_2a54_89ba_be5b,
790 ]);
791 let b = Fp([
792 0x9fd2_8773_3d23_dda0,
793 0xb16b_f2af_738b_3554,
794 0x3e57_a75b_d3cc_6d1d,
795 0x900b_c0bd_627f_d6d6,
796 0xd319_a080_efb2_45fe,
797 0x15fd_caa4_e4bb_2091,
798 ]);
799 let c = Fp([
800 0x6d8d_33e6_3b43_4d3d,
801 0xeb12_82fd_b766_dd39,
802 0x8534_7bb6_f133_d6d5,
803 0xa21d_aa5a_9892_f727,
804 0x3b25_6cfb_3ad8_ae23,
805 0x155d_7199_de7f_8464,
806 ]);
807
808 assert_eq!(a - b, c);
809}
810
811#[test]
812fn test_negation() {
813 let a = Fp([
814 0x5360_bb59_7867_8032,
815 0x7dd2_75ae_799e_128e,
816 0x5c5b_5071_ce4f_4dcf,
817 0xcdb2_1f93_078d_bb3e,
818 0xc323_65c5_e73f_474a,
819 0x115a_2a54_89ba_be5b,
820 ]);
821 let b = Fp([
822 0x669e_44a6_8798_2a79,
823 0xa0d9_8a50_37b5_ed71,
824 0x0ad5_822f_2861_a854,
825 0x96c5_2bf1_ebf7_5781,
826 0x87f8_41f0_5c0c_658c,
827 0x08a6_e795_afc5_283e,
828 ]);
829
830 assert_eq!(-a, b);
831}
832
833#[test]
834fn test_debug() {
835 assert_eq!(
836 format!(
837 "{:?}",
838 Fp([
839 0x5360_bb59_7867_8032,
840 0x7dd2_75ae_799e_128e,
841 0x5c5b_5071_ce4f_4dcf,
842 0xcdb2_1f93_078d_bb3e,
843 0xc323_65c5_e73f_474a,
844 0x115a_2a54_89ba_be5b,
845 ])
846 ),
847 "0x104bf052ad3bc99bcb176c24a06a6c3aad4eaf2308fc4d282e106c84a757d061052630515305e59bdddf8111bfdeb704"
848 );
849}
850
851#[test]
852fn test_from_bytes() {
853 let mut a = Fp([
854 0xdc90_6d9b_e3f9_5dc8,
855 0x8755_caf7_4596_91a1,
856 0xcff1_a7f4_e958_3ab3,
857 0x9b43_821f_849e_2284,
858 0xf575_54f3_a297_4f3f,
859 0x085d_bea8_4ed4_7f79,
860 ]);
861
862 for _ in 0..100 {
863 a = a.square();
864 let tmp = a.to_bytes();
865 let b = Fp::from_bytes(&tmp).unwrap();
866
867 assert_eq!(a, b);
868 }
869
870 assert_eq!(
871 -Fp::one(),
872 Fp::from_bytes(&[
873 26, 1, 17, 234, 57, 127, 230, 154, 75, 27, 167, 182, 67, 75, 172, 215, 100, 119, 75,
874 132, 243, 133, 18, 191, 103, 48, 210, 160, 246, 176, 246, 36, 30, 171, 255, 254, 177,
875 83, 255, 255, 185, 254, 255, 255, 255, 255, 170, 170
876 ])
877 .unwrap()
878 );
879
880 assert!(bool::from(
881 Fp::from_bytes(&[
882 27, 1, 17, 234, 57, 127, 230, 154, 75, 27, 167, 182, 67, 75, 172, 215, 100, 119, 75,
883 132, 243, 133, 18, 191, 103, 48, 210, 160, 246, 176, 246, 36, 30, 171, 255, 254, 177,
884 83, 255, 255, 185, 254, 255, 255, 255, 255, 170, 170
885 ])
886 .is_none()
887 ));
888
889 assert!(bool::from(Fp::from_bytes(&[0xff; 48]).is_none()));
890}
891
892#[test]
893fn test_sqrt() {
894 let a = Fp::from_raw_unchecked([
896 0xaa27_0000_000c_fff3,
897 0x53cc_0032_fc34_000a,
898 0x478f_e97a_6b0a_807f,
899 0xb1d3_7ebe_e6ba_24d7,
900 0x8ec9_733b_bf78_ab2f,
901 0x09d6_4551_3d83_de7e,
902 ]);
903
904 assert_eq!(
905 -a.sqrt().unwrap(),
907 Fp::from_raw_unchecked([
909 0x3213_0000_0006_554f,
910 0xb93c_0018_d6c4_0005,
911 0x5760_5e0d_b0dd_bb51,
912 0x8b25_6521_ed1f_9bcb,
913 0x6cf2_8d79_0162_2c03,
914 0x11eb_ab9d_bb81_e28c,
915 ])
916 );
917}
918
919#[test]
920fn test_inversion() {
921 let a = Fp([
922 0x43b4_3a50_78ac_2076,
923 0x1ce0_7630_46f8_962b,
924 0x724a_5276_486d_735c,
925 0x6f05_c2a6_282d_48fd,
926 0x2095_bd5b_b4ca_9331,
927 0x03b3_5b38_94b0_f7da,
928 ]);
929 let b = Fp([
930 0x69ec_d704_0952_148f,
931 0x985c_cc20_2219_0f55,
932 0xe19b_ba36_a9ad_2f41,
933 0x19bb_16c9_5219_dbd8,
934 0x14dc_acfd_fb47_8693,
935 0x115f_f58a_fff9_a8e1,
936 ]);
937
938 assert_eq!(a.invert().unwrap(), b);
939 assert!(bool::from(Fp::zero().invert().is_none()));
940}
941
942#[test]
943fn test_lexicographic_largest() {
944 assert!(!bool::from(Fp::zero().lexicographically_largest()));
945 assert!(!bool::from(Fp::one().lexicographically_largest()));
946 assert!(!bool::from(
947 Fp::from_raw_unchecked([
948 0xa1fa_ffff_fffe_5557,
949 0x995b_fff9_76a3_fffe,
950 0x03f4_1d24_d174_ceb4,
951 0xf654_7998_c199_5dbd,
952 0x778a_468f_507a_6034,
953 0x0205_5993_1f7f_8103
954 ])
955 .lexicographically_largest()
956 ));
957 assert!(bool::from(
958 Fp::from_raw_unchecked([
959 0x1804_0000_0001_5554,
960 0x8550_0005_3ab0_0001,
961 0x633c_b57c_253c_276f,
962 0x6e22_d1ec_31eb_b502,
963 0xd391_6126_f2d1_4ca2,
964 0x17fb_b857_1a00_6596,
965 ])
966 .lexicographically_largest()
967 ));
968 assert!(bool::from(
969 Fp::from_raw_unchecked([
970 0x43f5_ffff_fffc_aaae,
971 0x32b7_fff2_ed47_fffd,
972 0x07e8_3a49_a2e9_9d69,
973 0xeca8_f331_8332_bb7a,
974 0xef14_8d1e_a0f4_c069,
975 0x040a_b326_3eff_0206,
976 ])
977 .lexicographically_largest()
978 ));
979}
980
981#[cfg(feature = "zeroize")]
982#[test]
983fn test_zeroize() {
984 use zeroize::Zeroize;
985
986 let mut a = Fp::one();
987 a.zeroize();
988 assert!(bool::from(a.is_zero()));
989}