1use blst::*;
5
6use core::{
7 cmp, fmt,
8 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
9};
10use ff::Field;
11use rand_core::RngCore;
12use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
13use zeroize::Zeroize;
14
15use crate::fp2::Fp2;
16
17#[allow(dead_code)]
19const MODULUS: [u64; 6] = [
20 0xb9fe_ffff_ffff_aaab,
21 0x1eab_fffe_b153_ffff,
22 0x6730_d2a0_f6b0_f624,
23 0x6477_4b84_f385_12bf,
24 0x4b1b_a7b6_434b_acd7,
25 0x1a01_11ea_397f_e69a,
26];
27
28const MODULUS_REPR: [u8; 48] = [
30 0xab, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xb9, 0xff, 0xff, 0x53, 0xb1, 0xfe, 0xff, 0xab, 0x1e,
31 0x24, 0xf6, 0xb0, 0xf6, 0xa0, 0xd2, 0x30, 0x67, 0xbf, 0x12, 0x85, 0xf3, 0x84, 0x4b, 0x77, 0x64,
32 0xd7, 0xac, 0x4b, 0x43, 0xb6, 0xa7, 0x1b, 0x4b, 0x9a, 0xe6, 0x7f, 0x39, 0xea, 0x11, 0x01, 0x1a,
33];
34
35const ZERO: Fp = Fp(blst_fp {
36 l: [0, 0, 0, 0, 0, 0],
37});
38
39const R: Fp = Fp(blst_fp {
41 l: [
42 0x7609_0000_0002_fffd,
43 0xebf4_000b_c40c_0002,
44 0x5f48_9857_53c7_58ba,
45 0x77ce_5853_7052_5745,
46 0x5c07_1a97_a256_ec6d,
47 0x15f6_5ec3_fa80_e493,
48 ],
49});
50
51#[allow(dead_code)]
53const R2: Fp = Fp(blst_fp {
54 l: [
55 0xf4df_1f34_1c34_1746,
56 0x0a76_e6a6_09d1_04f1,
57 0x8de5_476c_4c95_b6d5,
58 0x67eb_88a9_939d_83c0,
59 0x9a79_3e85_b519_952d,
60 0x1198_8fe5_92ca_e3aa,
61 ],
62});
63
64#[derive(Copy, Clone, Zeroize)]
67#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
68#[repr(transparent)]
69pub struct Fp(pub(crate) blst_fp);
70
71pub(crate) const FROBENIUS_COEFF_FP2_C1: [Fp; 2] = [
73 Fp(blst_fp {
75 l: [
76 0x760900000002fffd,
77 0xebf4000bc40c0002,
78 0x5f48985753c758ba,
79 0x77ce585370525745,
80 0x5c071a97a256ec6d,
81 0x15f65ec3fa80e493,
82 ],
83 }),
84 Fp(blst_fp {
86 l: [
87 0x43f5fffffffcaaae,
88 0x32b7fff2ed47fffd,
89 0x7e83a49a2e99d69,
90 0xeca8f3318332bb7a,
91 0xef148d1ea0f4c069,
92 0x40ab3263eff0206,
93 ],
94 }),
95];
96
97pub const FROBENIUS_COEFF_FP6_C1: [Fp2; 6] = [
98 Fp2::new(
100 Fp(blst_fp {
101 l: [
102 0x760900000002fffd,
103 0xebf4000bc40c0002,
104 0x5f48985753c758ba,
105 0x77ce585370525745,
106 0x5c071a97a256ec6d,
107 0x15f65ec3fa80e493,
108 ],
109 }),
110 Fp(blst_fp {
111 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
112 }),
113 ),
114 Fp2::new(
116 Fp(blst_fp {
117 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
118 }),
119 Fp(blst_fp {
120 l: [
121 0xcd03c9e48671f071,
122 0x5dab22461fcda5d2,
123 0x587042afd3851b95,
124 0x8eb60ebe01bacb9e,
125 0x3f97d6e83d050d2,
126 0x18f0206554638741,
127 ],
128 }),
129 ),
130 Fp2::new(
132 Fp(blst_fp {
133 l: [
134 0x30f1361b798a64e8,
135 0xf3b8ddab7ece5a2a,
136 0x16a8ca3ac61577f7,
137 0xc26a2ff874fd029b,
138 0x3636b76660701c6e,
139 0x51ba4ab241b6160,
140 ],
141 }),
142 Fp(blst_fp {
143 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
144 }),
145 ),
146 Fp2::new(
148 Fp(blst_fp {
149 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
150 }),
151 Fp(blst_fp {
152 l: [
153 0x760900000002fffd,
154 0xebf4000bc40c0002,
155 0x5f48985753c758ba,
156 0x77ce585370525745,
157 0x5c071a97a256ec6d,
158 0x15f65ec3fa80e493,
159 ],
160 }),
161 ),
162 Fp2::new(
164 Fp(blst_fp {
165 l: [
166 0xcd03c9e48671f071,
167 0x5dab22461fcda5d2,
168 0x587042afd3851b95,
169 0x8eb60ebe01bacb9e,
170 0x3f97d6e83d050d2,
171 0x18f0206554638741,
172 ],
173 }),
174 Fp(blst_fp {
175 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
176 }),
177 ),
178 Fp2::new(
180 Fp(blst_fp {
181 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
182 }),
183 Fp(blst_fp {
184 l: [
185 0x30f1361b798a64e8,
186 0xf3b8ddab7ece5a2a,
187 0x16a8ca3ac61577f7,
188 0xc26a2ff874fd029b,
189 0x3636b76660701c6e,
190 0x51ba4ab241b6160,
191 ],
192 }),
193 ),
194];
195
196pub const FROBENIUS_COEFF_FP6_C2: [Fp2; 6] = [
197 Fp2::new(
199 Fp(blst_fp {
200 l: [
201 0x760900000002fffd,
202 0xebf4000bc40c0002,
203 0x5f48985753c758ba,
204 0x77ce585370525745,
205 0x5c071a97a256ec6d,
206 0x15f65ec3fa80e493,
207 ],
208 }),
209 Fp(blst_fp {
210 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
211 }),
212 ),
213 Fp2::new(
215 Fp(blst_fp {
216 l: [
217 0x890dc9e4867545c3,
218 0x2af322533285a5d5,
219 0x50880866309b7e2c,
220 0xa20d1b8c7e881024,
221 0x14e4f04fe2db9068,
222 0x14e56d3f1564853a,
223 ],
224 }),
225 Fp(blst_fp {
226 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
227 }),
228 ),
229 Fp2::new(
231 Fp(blst_fp {
232 l: [
233 0xcd03c9e48671f071,
234 0x5dab22461fcda5d2,
235 0x587042afd3851b95,
236 0x8eb60ebe01bacb9e,
237 0x3f97d6e83d050d2,
238 0x18f0206554638741,
239 ],
240 }),
241 Fp(blst_fp {
242 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
243 }),
244 ),
245 Fp2::new(
247 Fp(blst_fp {
248 l: [
249 0x43f5fffffffcaaae,
250 0x32b7fff2ed47fffd,
251 0x7e83a49a2e99d69,
252 0xeca8f3318332bb7a,
253 0xef148d1ea0f4c069,
254 0x40ab3263eff0206,
255 ],
256 }),
257 Fp(blst_fp {
258 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
259 }),
260 ),
261 Fp2::new(
263 Fp(blst_fp {
264 l: [
265 0x30f1361b798a64e8,
266 0xf3b8ddab7ece5a2a,
267 0x16a8ca3ac61577f7,
268 0xc26a2ff874fd029b,
269 0x3636b76660701c6e,
270 0x51ba4ab241b6160,
271 ],
272 }),
273 Fp(blst_fp {
274 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
275 }),
276 ),
277 Fp2::new(
279 Fp(blst_fp {
280 l: [
281 0xecfb361b798dba3a,
282 0xc100ddb891865a2c,
283 0xec08ff1232bda8e,
284 0xd5c13cc6f1ca4721,
285 0x47222a47bf7b5c04,
286 0x110f184e51c5f59,
287 ],
288 }),
289 Fp(blst_fp {
290 l: [0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
291 }),
292 ),
293];
294
295impl From<u64> for Fp {
296 fn from(val: u64) -> Fp {
297 let mut repr = [0u8; 48];
298 repr[..8].copy_from_slice(&val.to_le_bytes());
299 Self::from_bytes_le(&repr).unwrap()
300 }
301}
302
303impl Ord for Fp {
304 #[allow(clippy::comparison_chain)]
305 fn cmp(&self, other: &Fp) -> cmp::Ordering {
306 for (a, b) in self.to_bytes_be().iter().zip(other.to_bytes_be().iter()) {
307 if a > b {
308 return cmp::Ordering::Greater;
309 } else if a < b {
310 return cmp::Ordering::Less;
311 }
312 }
313 cmp::Ordering::Equal
314 }
315}
316
317impl PartialOrd for Fp {
318 #[inline(always)]
319 fn partial_cmp(&self, other: &Fp) -> Option<cmp::Ordering> {
320 Some(self.cmp(other))
321 }
322}
323
324impl fmt::Debug for Fp {
325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
326 let be_bytes = self.to_bytes_be();
327 write!(f, "Fp(0x")?;
328 for &b in be_bytes.iter() {
329 write!(f, "{:02x}", b)?;
330 }
331 write!(f, ")")?;
332 Ok(())
333 }
334}
335
336impl fmt::Display for Fp {
337 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
338 write!(f, "{:?}", self)
339 }
340}
341
342impl From<Fp> for blst_fp {
343 fn from(val: Fp) -> blst_fp {
344 val.0
345 }
346}
347
348impl From<blst_fp> for Fp {
349 fn from(val: blst_fp) -> Fp {
350 Fp(val)
351 }
352}
353
354impl Default for Fp {
355 fn default() -> Self {
356 Fp::ZERO
357 }
358}
359
360impl Eq for Fp {}
361
362impl PartialEq for Fp {
363 #[inline]
364 fn eq(&self, other: &Self) -> bool {
365 self.ct_eq(other).into()
366 }
367}
368
369impl ConstantTimeEq for Fp {
370 fn ct_eq(&self, other: &Self) -> Choice {
371 self.0.l[0].ct_eq(&other.0.l[0])
372 & self.0.l[1].ct_eq(&other.0.l[1])
373 & self.0.l[2].ct_eq(&other.0.l[2])
374 & self.0.l[3].ct_eq(&other.0.l[3])
375 & self.0.l[4].ct_eq(&other.0.l[4])
376 & self.0.l[5].ct_eq(&other.0.l[5])
377 }
378}
379
380impl ConditionallySelectable for Fp {
381 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
382 Fp(blst_fp {
383 l: [
384 u64::conditional_select(&a.0.l[0], &b.0.l[0], choice),
385 u64::conditional_select(&a.0.l[1], &b.0.l[1], choice),
386 u64::conditional_select(&a.0.l[2], &b.0.l[2], choice),
387 u64::conditional_select(&a.0.l[3], &b.0.l[3], choice),
388 u64::conditional_select(&a.0.l[4], &b.0.l[4], choice),
389 u64::conditional_select(&a.0.l[5], &b.0.l[5], choice),
390 ],
391 })
392 }
393}
394
395impl Neg for &Fp {
396 type Output = Fp;
397
398 #[inline]
399 fn neg(self) -> Fp {
400 let mut out = *self;
401 unsafe { blst_fp_cneg(&mut out.0, &self.0, true) };
402 out
403 }
404}
405
406impl Neg for Fp {
407 type Output = Fp;
408
409 #[inline]
410 fn neg(mut self) -> Fp {
411 unsafe { blst_fp_cneg(&mut self.0, &self.0, true) };
412 self
413 }
414}
415
416impl Sub<&Fp> for &Fp {
417 type Output = Fp;
418
419 #[inline]
420 fn sub(self, rhs: &Fp) -> Fp {
421 let mut out = *self;
422 out -= rhs;
423 out
424 }
425}
426
427impl Add<&Fp> for &Fp {
428 type Output = Fp;
429
430 #[inline]
431 fn add(self, rhs: &Fp) -> Fp {
432 let mut out = *self;
433 out += rhs;
434 out
435 }
436}
437
438impl Mul<&Fp> for &Fp {
439 type Output = Fp;
440
441 #[inline]
442 fn mul(self, rhs: &Fp) -> Fp {
443 let mut out = *self;
444 out *= rhs;
445 out
446 }
447}
448
449impl AddAssign<&Fp> for Fp {
450 #[inline]
451 fn add_assign(&mut self, rhs: &Fp) {
452 unsafe { blst_fp_add(&mut self.0, &self.0, &rhs.0) };
453 }
454}
455
456impl SubAssign<&Fp> for Fp {
457 #[inline]
458 fn sub_assign(&mut self, rhs: &Fp) {
459 unsafe { blst_fp_sub(&mut self.0, &self.0, &rhs.0) };
460 }
461}
462
463impl MulAssign<&Fp> for Fp {
464 #[inline]
465 fn mul_assign(&mut self, rhs: &Fp) {
466 unsafe { blst_fp_mul(&mut self.0, &self.0, &rhs.0) };
467 }
468}
469
470impl_add_sub!(Fp);
471impl_add_sub_assign!(Fp);
472impl_mul!(Fp);
473impl_mul_assign!(Fp);
474impl_sum!(Fp);
475impl_product!(Fp);
476
477#[allow(clippy::comparison_chain)]
479fn is_valid(le_bytes: &[u8; 48]) -> bool {
480 for (a, b) in le_bytes.iter().zip(MODULUS_REPR.iter()).rev() {
481 if a > b {
482 return false;
483 } else if a < b {
484 return true;
485 }
486 }
487 false
489}
490
491#[allow(clippy::comparison_chain)]
493fn is_valid_u64(le_bytes: &[u64; 6]) -> bool {
494 for (a, b) in le_bytes.iter().zip(MODULUS.iter()).rev() {
495 if a > b {
496 return false;
497 } else if a < b {
498 return true;
499 }
500 }
501 false
503}
504
505const NUM_BITS: u32 = 381;
506const REPR_SHAVE_BITS: usize = 384 - NUM_BITS as usize;
508
509impl Field for Fp {
510 fn random(mut rng: impl RngCore) -> Self {
511 loop {
512 let mut raw = [0u64; 6];
513 for int in raw.iter_mut() {
514 *int = rng.next_u64();
515 }
516
517 raw[5] &= 0xffffffffffffffff >> REPR_SHAVE_BITS;
519
520 if let Some(fp) = Fp::from_u64s_le(&raw).into() {
521 return fp;
522 }
523 }
524 }
525
526 const ZERO: Self = ZERO;
527
528 const ONE: Self = R;
530
531 fn is_zero(&self) -> Choice {
532 self.ct_eq(&ZERO)
533 }
534
535 fn square(&self) -> Self {
536 let mut sq = *self;
537 unsafe { blst_fp_sqr(&mut sq.0, &self.0) }
538 sq
539 }
540
541 fn double(&self) -> Self {
542 let mut out = *self;
543 out += self;
544 out
545 }
546
547 fn invert(&self) -> CtOption<Self> {
548 let mut inv = Self::default();
549 unsafe { blst_fp_eucl_inverse(&mut inv.0, &self.0) };
550 let is_invertible = !self.ct_eq(&Fp::ZERO);
551 CtOption::new(inv, is_invertible)
552 }
553
554 fn sqrt(&self) -> CtOption<Self> {
555 let mut out = Self::default();
556 let is_quad_res = unsafe { blst_fp_sqrt(&mut out.0, &self.0) };
557 CtOption::new(out, Choice::from(is_quad_res as u8))
558 }
559
560 fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) {
561 unimplemented!()
563 }
564}
565
566impl Fp {
567 pub fn char() -> [u8; 48] {
568 MODULUS_REPR
569 }
570
571 pub fn from_bytes_le(bytes: &[u8; 48]) -> CtOption<Fp> {
574 let is_some = Choice::from(is_valid(bytes) as u8);
576 let mut out = blst_fp::default();
577 unsafe { blst_fp_from_lendian(&mut out, bytes.as_ptr()) };
578
579 CtOption::new(Fp(out), is_some)
580 }
581
582 pub fn from_bytes_be(be_bytes: &[u8; 48]) -> CtOption<Fp> {
585 let mut le_bytes = *be_bytes;
586 le_bytes.reverse();
587 Self::from_bytes_le(&le_bytes)
588 }
589
590 pub fn to_bytes_le(&self) -> [u8; 48] {
593 let mut repr = [0u8; 48];
594 unsafe { blst_lendian_from_fp(repr.as_mut_ptr(), &self.0) };
595 repr
596 }
597
598 pub fn to_bytes_be(&self) -> [u8; 48] {
601 let mut bytes = self.to_bytes_le();
602 bytes.reverse();
603 bytes
604 }
605
606 pub fn from_raw_unchecked(l: [u64; 6]) -> Fp {
609 Fp(blst_fp { l })
610 }
611
612 pub fn mul3(&self) -> Self {
614 let mut out = *self;
615 unsafe { blst_fp_mul_by_3(&mut out.0, &self.0) };
616 out
617 }
618
619 pub fn mul8(&self) -> Self {
621 let mut out = *self;
622 unsafe { blst_fp_mul_by_8(&mut out.0, &self.0) };
623 out
624 }
625
626 pub fn shl(&self, count: usize) -> Self {
628 let mut out = *self;
629 unsafe { blst_fp_lshift(&mut out.0, &self.0, count) };
630 out
631 }
632
633 pub fn from_u64s_le(bytes: &[u64; 6]) -> CtOption<Self> {
635 let is_some = Choice::from(is_valid_u64(bytes) as u8);
636 let mut out = blst_fp::default();
637 unsafe { blst_fp_from_uint64(&mut out, bytes.as_ptr()) };
638 CtOption::new(Fp(out), is_some)
639 }
640
641 pub fn num_bits(&self) -> u32 {
642 let mut ret = 384;
643 for i in self.to_bytes_be().iter() {
644 let leading = i.leading_zeros();
645 ret -= leading;
646 if leading != 8 {
647 break;
648 }
649 }
650
651 ret
652 }
653
654 pub fn is_quad_res(&self) -> Choice {
655 self.sqrt().is_some()
656 }
657
658 #[inline]
659 pub fn square_assign(&mut self) {
660 unsafe { blst_fp_sqr(&mut self.0, &self.0) };
661 }
662}
663
664#[cfg(feature = "gpu")]
665impl ec_gpu::GpuName for Fp {
666 fn name() -> String {
667 ec_gpu::name!()
668 }
669}
670
671#[cfg(feature = "gpu")]
672impl ec_gpu::GpuField for Fp {
673 fn one() -> Vec<u32> {
674 crate::u64_to_u32(&R.0.l[..])
675 }
676
677 fn r2() -> Vec<u32> {
678 crate::u64_to_u32(&R2.0.l[..])
679 }
680
681 fn modulus() -> Vec<u32> {
682 crate::u64_to_u32(&MODULUS[..])
683 }
684}
685
686#[cfg(test)]
687mod tests {
688 use super::*;
689
690 use ff::Field;
691 use rand_core::SeedableRng;
692 use rand_xorshift::XorShiftRng;
693
694 #[test]
695 fn test_fp_neg_one() {
696 assert_eq!(
697 -Fp::ONE,
698 Fp(blst::blst_fp {
699 l: [
700 0x43f5fffffffcaaae,
701 0x32b7fff2ed47fffd,
702 0x7e83a49a2e99d69,
703 0xeca8f3318332bb7a,
704 0xef148d1ea0f4c069,
705 0x40ab3263eff0206,
706 ]
707 }),
708 );
709 }
710
711 #[test]
712 fn test_fp_from_u64() {
713 let a = Fp::from(100);
714 let mut expected_bytes = [0u8; 48];
715 expected_bytes[0] = 100;
716 assert_eq!(a.to_bytes_le(), expected_bytes);
717 }
718
719 #[test]
720 fn test_fp_is_zero() {
721 assert!(bool::from(Fp::from(0).is_zero()));
722 assert!(!bool::from(Fp::from(1).is_zero()));
723 assert!(!bool::from(
724 Fp::from_u64s_le(&[0, 0, 0, 0, 1, 0]).unwrap().is_zero()
725 ));
726 }
727
728 #[test]
729 fn test_fp_add_assign() {
730 {
731 let mut tmp = Fp(blst::blst_fp {
733 l: [
734 0x624434821df92b69,
735 0x503260c04fd2e2ea,
736 0xd9df726e0d16e8ce,
737 0xfbcb39adfd5dfaeb,
738 0x86b8a22b0c88b112,
739 0x165a2ed809e4201b,
740 ],
741 });
742 assert!(!bool::from(tmp.is_zero()));
743 tmp.add_assign(&Fp::from(0));
745 assert_eq!(
746 tmp,
747 Fp(blst::blst_fp {
748 l: [
749 0x624434821df92b69,
750 0x503260c04fd2e2ea,
751 0xd9df726e0d16e8ce,
752 0xfbcb39adfd5dfaeb,
753 0x86b8a22b0c88b112,
754 0x165a2ed809e4201b
755 ]
756 })
757 );
758 tmp.add_assign(&Fp(blst::blst_fp {
760 l: [1, 0, 0, 0, 0, 0],
761 }));
762 assert_eq!(
763 tmp,
764 Fp(blst::blst_fp {
765 l: [
766 0x624434821df92b6a,
767 0x503260c04fd2e2ea,
768 0xd9df726e0d16e8ce,
769 0xfbcb39adfd5dfaeb,
770 0x86b8a22b0c88b112,
771 0x165a2ed809e4201b
772 ]
773 })
774 );
775 tmp.add_assign(&Fp(blst::blst_fp {
777 l: [
778 0x374d8f8ea7a648d8,
779 0xe318bb0ebb8bfa9b,
780 0x613d996f0a95b400,
781 0x9fac233cb7e4fef1,
782 0x67e47552d253c52,
783 0x5c31b227edf25da,
784 ],
785 }));
786 assert_eq!(
787 tmp,
788 Fp(blst::blst_fp {
789 l: [
790 0xdf92c410c59fc997,
791 0x149f1bd05a0add85,
792 0xd3ec393c20fba6ab,
793 0x37001165c1bde71d,
794 0x421b41c9f662408e,
795 0x21c38104f435f5b
796 ]
797 })
798 );
799 tmp = Fp(blst::blst_fp {
801 l: [
802 0xb9feffffffffaaaa,
803 0x1eabfffeb153ffff,
804 0x6730d2a0f6b0f624,
805 0x64774b84f38512bf,
806 0x4b1ba7b6434bacd7,
807 0x1a0111ea397fe69a,
808 ],
809 });
810 tmp.add_assign(&Fp(blst::blst_fp {
811 l: [1, 0, 0, 0, 0, 0],
812 }));
813 assert!(bool::from(tmp.is_zero()));
814 tmp = Fp(blst::blst_fp {
816 l: [
817 0x531221a410efc95b,
818 0x72819306027e9717,
819 0x5ecefb937068b746,
820 0x97de59cd6feaefd7,
821 0xdc35c51158644588,
822 0xb2d176c04f2100,
823 ],
824 });
825 tmp.add_assign(&Fp(blst::blst_fp {
826 l: [
827 0x66ecde5bef0fe14f,
828 0xac2a6cf8aed568e8,
829 0x861d70d86483edd,
830 0xcc98f1b7839a22e8,
831 0x6ee5e2a4eae7674e,
832 0x194e40737930c599,
833 ],
834 }));
835 assert_eq!(
836 tmp,
837 Fp(blst::blst_fp {
838 l: [
839 0xb9feffffffffaaaa,
840 0x1eabfffeb153ffff,
841 0x6730d2a0f6b0f624,
842 0x64774b84f38512bf,
843 0x4b1ba7b6434bacd7,
844 0x1a0111ea397fe69a
845 ]
846 })
847 );
848 tmp.add_assign(&Fp(blst::blst_fp {
850 l: [1, 0, 0, 0, 0, 0],
851 }));
852 assert!(bool::from(tmp.is_zero()));
853 }
854
855 let mut rng = XorShiftRng::from_seed([
858 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
859 0xbc, 0xe5,
860 ]);
861
862 for _ in 0..1000 {
863 let a = Fp::random(&mut rng);
865 let b = Fp::random(&mut rng);
866 let c = Fp::random(&mut rng);
867
868 let mut tmp1 = a;
869 tmp1.add_assign(&b);
870 tmp1.add_assign(&c);
871
872 let mut tmp2 = b;
873 tmp2.add_assign(&c);
874 tmp2.add_assign(&a);
875
876 assert_eq!(tmp1, tmp2);
879 }
880 }
881
882 #[test]
883 fn test_fp_sub_assign() {
884 {
885 let mut tmp = Fp(blst::blst_fp {
887 l: [
888 0x531221a410efc95b,
889 0x72819306027e9717,
890 0x5ecefb937068b746,
891 0x97de59cd6feaefd7,
892 0xdc35c51158644588,
893 0xb2d176c04f2100,
894 ],
895 });
896 tmp.sub_assign(&Fp(blst::blst_fp {
897 l: [
898 0x98910d20877e4ada,
899 0x940c983013f4b8ba,
900 0xf677dc9b8345ba33,
901 0xbef2ce6b7f577eba,
902 0xe1ae288ac3222c44,
903 0x5968bb602790806,
904 ],
905 }));
906 assert_eq!(
907 tmp,
908 Fp(blst::blst_fp {
909 l: [
910 0x748014838971292c,
911 0xfd20fad49fddde5c,
912 0xcf87f198e3d3f336,
913 0x3d62d6e6e41883db,
914 0x45a3443cd88dc61b,
915 0x151d57aaf755ff94
916 ]
917 })
918 );
919
920 tmp = Fp(blst::blst_fp {
922 l: [
923 0x98910d20877e4ada,
924 0x940c983013f4b8ba,
925 0xf677dc9b8345ba33,
926 0xbef2ce6b7f577eba,
927 0xe1ae288ac3222c44,
928 0x5968bb602790806,
929 ],
930 });
931 tmp.sub_assign(&Fp(blst::blst_fp {
932 l: [
933 0x531221a410efc95b,
934 0x72819306027e9717,
935 0x5ecefb937068b746,
936 0x97de59cd6feaefd7,
937 0xdc35c51158644588,
938 0xb2d176c04f2100,
939 ],
940 }));
941 assert_eq!(
942 tmp,
943 Fp(blst::blst_fp {
944 l: [
945 0x457eeb7c768e817f,
946 0x218b052a117621a3,
947 0x97a8e10812dd02ed,
948 0x2714749e0f6c8ee3,
949 0x57863796abde6bc,
950 0x4e3ba3f4229e706
951 ]
952 })
953 );
954
955 tmp = Fp::from(0);
957 tmp.sub_assign(&Fp::from(0));
958 assert!(bool::from(tmp.is_zero()));
959
960 tmp = Fp(blst::blst_fp {
961 l: [
962 0x98910d20877e4ada,
963 0x940c983013f4b8ba,
964 0xf677dc9b8345ba33,
965 0xbef2ce6b7f577eba,
966 0xe1ae288ac3222c44,
967 0x5968bb602790806,
968 ],
969 });
970 tmp.sub_assign(&Fp::from(0));
971 assert_eq!(
972 tmp,
973 Fp(blst::blst_fp {
974 l: [
975 0x98910d20877e4ada,
976 0x940c983013f4b8ba,
977 0xf677dc9b8345ba33,
978 0xbef2ce6b7f577eba,
979 0xe1ae288ac3222c44,
980 0x5968bb602790806
981 ]
982 })
983 );
984 }
985
986 let mut rng = XorShiftRng::from_seed([
987 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
988 0xbc, 0xe5,
989 ]);
990
991 for _ in 0..1000 {
992 let a = Fp::random(&mut rng);
994 let b = Fp::random(&mut rng);
995
996 let mut tmp1 = a;
997 tmp1.sub_assign(&b);
998
999 let mut tmp2 = b;
1000 tmp2.sub_assign(&a);
1001
1002 tmp1.add_assign(&tmp2);
1003 assert!(bool::from(tmp1.is_zero()));
1004 }
1005 }
1006
1007 #[test]
1008 fn test_fp_mul_assign() {
1009 assert_eq!(
1010 Fp(blst::blst_fp {
1011 l: [
1012 0xcc6200000020aa8a,
1013 0x422800801dd8001a,
1014 0x7f4f5e619041c62c,
1015 0x8a55171ac70ed2ba,
1016 0x3f69cc3a3d07d58b,
1017 0xb972455fd09b8ef,
1018 ]
1019 }) * Fp(blst::blst_fp {
1020 l: [
1021 0x329300000030ffcf,
1022 0x633c00c02cc40028,
1023 0xbef70d925862a942,
1024 0x4f7fa2a82a963c17,
1025 0xdf1eb2575b8bc051,
1026 0x1162b680fb8e9566,
1027 ]
1028 }),
1029 Fp(blst::blst_fp {
1030 l: [
1031 0x9dc4000001ebfe14,
1032 0x2850078997b00193,
1033 0xa8197f1abb4d7bf,
1034 0xc0309573f4bfe871,
1035 0xf48d0923ffaf7620,
1036 0x11d4b58c7a926e66
1037 ]
1038 })
1039 );
1040
1041 let mut rng = XorShiftRng::from_seed([
1042 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1043 0xbc, 0xe5,
1044 ]);
1045
1046 for _ in 0..1000000 {
1047 let a = Fp::random(&mut rng);
1049 let b = Fp::random(&mut rng);
1050 let c = Fp::random(&mut rng);
1051
1052 let mut tmp1 = a;
1053 tmp1.mul_assign(&b);
1054 tmp1.mul_assign(&c);
1055
1056 let mut tmp2 = b;
1057 tmp2.mul_assign(&c);
1058 tmp2.mul_assign(&a);
1059
1060 assert_eq!(tmp1, tmp2);
1061 }
1062
1063 for _ in 0..1000000 {
1064 let r = Fp::random(&mut rng);
1067 let mut a = Fp::random(&mut rng);
1068 let mut b = Fp::random(&mut rng);
1069 let mut c = Fp::random(&mut rng);
1070
1071 let mut tmp1 = a;
1072 tmp1.add_assign(&b);
1073 tmp1.add_assign(&c);
1074 tmp1.mul_assign(&r);
1075
1076 a.mul_assign(&r);
1077 b.mul_assign(&r);
1078 c.mul_assign(&r);
1079
1080 a.add_assign(&b);
1081 a.add_assign(&c);
1082
1083 assert_eq!(tmp1, a);
1084 }
1085 }
1086
1087 #[test]
1088 fn test_fp_squaring() {
1089 let a = Fp(blst::blst_fp {
1090 l: [
1091 0xffffffffffffffff,
1092 0xffffffffffffffff,
1093 0xffffffffffffffff,
1094 0xffffffffffffffff,
1095 0xffffffffffffffff,
1096 0x19ffffffffffffff,
1097 ],
1098 });
1099 assert!(!bool::from(a.is_zero()));
1100 assert_eq!(
1101 a.square(),
1102 Fp::from_u64s_le(&[
1103 0x1cfb28fe7dfbbb86,
1104 0x24cbe1731577a59,
1105 0xcce1d4edc120e66e,
1106 0xdc05c659b4e15b27,
1107 0x79361e5a802c6a23,
1108 0x24bcbe5d51b9a6f
1109 ])
1110 .unwrap()
1111 );
1112
1113 let mut rng = XorShiftRng::from_seed([
1114 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1115 0xbc, 0xe5,
1116 ]);
1117
1118 for _ in 0..1000000 {
1119 let a = Fp::random(&mut rng);
1121
1122 let tmp = a.square();
1123
1124 let mut tmp2 = a;
1125 tmp2.mul_assign(&a);
1126
1127 assert_eq!(tmp, tmp2);
1128 }
1129 }
1130
1131 #[test]
1132 fn test_fp_inverse() {
1133 assert_eq!(Fp::ZERO.invert().is_none().unwrap_u8(), 1);
1134
1135 let mut rng = XorShiftRng::from_seed([
1136 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1137 0xbc, 0xe5,
1138 ]);
1139
1140 let one = Fp::ONE;
1141
1142 for _ in 0..1000 {
1143 let mut a = Fp::random(&mut rng);
1145 let ainv = a.invert().unwrap();
1146 a.mul_assign(&ainv);
1147 assert_eq!(a, one);
1148 }
1149 }
1150
1151 #[test]
1152 fn test_fp_double() {
1153 let mut rng = XorShiftRng::from_seed([
1154 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1155 0xbc, 0xe5,
1156 ]);
1157
1158 for _ in 0..1000 {
1159 let a = Fp::random(&mut rng);
1161 assert_eq!(a.double(), a + a, "{}", a);
1162 }
1163 }
1164
1165 #[test]
1166 fn test_fp_negate() {
1167 {
1168 let a = Fp::ZERO;
1169 assert!(bool::from((-a).is_zero()));
1170 }
1171
1172 let mut rng = XorShiftRng::from_seed([
1173 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1174 0xbc, 0xe5,
1175 ]);
1176
1177 for _ in 0..1000 {
1178 let mut a = Fp::random(&mut rng);
1180 let b = -a;
1181 a.add_assign(&b);
1182
1183 assert!(bool::from(a.is_zero()));
1184 }
1185 }
1186
1187 #[test]
1188 fn test_fp_pow() {
1189 let mut rng = XorShiftRng::from_seed([
1190 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1191 0xbc, 0xe5,
1192 ]);
1193
1194 for i in 0..1000 {
1195 let a = Fp::random(&mut rng);
1198 let target = a.pow_vartime([i]);
1199 let mut c = Fp::ONE;
1200 for _ in 0..i {
1201 c.mul_assign(&a);
1202 }
1203 assert_eq!(c, target);
1204 }
1205
1206 for _ in 0..1000 {
1207 let a = Fp::random(&mut rng);
1209
1210 assert_eq!(a, a.pow_vartime(MODULUS));
1211 }
1212 }
1213
1214 #[test]
1215 fn test_fp_sqrt() {
1216 let mut rng = XorShiftRng::from_seed([
1217 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1218 0xbc, 0xe5,
1219 ]);
1220
1221 assert_eq!(Fp::ZERO.sqrt().unwrap(), Fp::ZERO);
1222 assert_eq!(Fp::ONE.sqrt().unwrap(), Fp::ONE);
1223
1224 for _ in 0..1000 {
1225 let a = Fp::random(&mut rng);
1227 let a_new = a.square().sqrt().unwrap();
1228 assert!(a_new == a || a_new == -a);
1229 }
1230
1231 for _ in 0..1000 {
1232 let a = Fp::random(&mut rng);
1234 let sqrt = a.sqrt();
1235 if sqrt.is_some().into() {
1236 assert_eq!(sqrt.unwrap().square(), a);
1237 }
1238 }
1239 let a = Fp::from_raw_unchecked([
1241 0xaa27_0000_000c_fff3,
1242 0x53cc_0032_fc34_000a,
1243 0x478f_e97a_6b0a_807f,
1244 0xb1d3_7ebe_e6ba_24d7,
1245 0x8ec9_733b_bf78_ab2f,
1246 0x09d6_4551_3d83_de7e,
1247 ]);
1248
1249 assert_eq!(
1250 -a.sqrt().unwrap(),
1252 Fp::from_raw_unchecked([
1254 0x3213_0000_0006_554f,
1255 0xb93c_0018_d6c4_0005,
1256 0x5760_5e0d_b0dd_bb51,
1257 0x8b25_6521_ed1f_9bcb,
1258 0x6cf2_8d79_0162_2c03,
1259 0x11eb_ab9d_bb81_e28c,
1260 ])
1261 );
1262 }
1263
1264 #[test]
1265 fn test_fp_from_into_repr() {
1266 assert!(bool::from(
1268 Fp::from_u64s_le(&[
1269 0xb9feffffffffaaac,
1270 0x1eabfffeb153ffff,
1271 0x6730d2a0f6b0f624,
1272 0x64774b84f38512bf,
1273 0x4b1ba7b6434bacd7,
1274 0x1a0111ea397fe69a
1275 ])
1276 .is_none()
1277 ));
1278
1279 let mut a = Fp::from_u64s_le(&[
1281 0x4a49dad4ff6cde2d,
1282 0xac62a82a8f51cd50,
1283 0x2b1f41ab9f36d640,
1284 0x908a387f480735f1,
1285 0xae30740c08a875d7,
1286 0x6c80918a365ef78,
1287 ])
1288 .unwrap();
1289 let b = Fp::from_u64s_le(&[
1290 0xbba57917c32f0cf0,
1291 0xe7f878cf87f05e5d,
1292 0x9498b4292fd27459,
1293 0xd59fd94ee4572cfa,
1294 0x1f607186d5bb0059,
1295 0xb13955f5ac7f6a3,
1296 ])
1297 .unwrap();
1298 let c = Fp::from_u64s_le(&[
1299 0xf5f70713b717914c,
1300 0x355ea5ac64cbbab1,
1301 0xce60dd43417ec960,
1302 0xf16b9d77b0ad7d10,
1303 0xa44c204c1de7cdb7,
1304 0x1684487772bc9a5a,
1305 ])
1306 .unwrap();
1307 a.mul_assign(&b);
1308 assert_eq!(a, c);
1309
1310 assert!(bool::from(Fp::from(0).is_zero()));
1312
1313 let mut rng = XorShiftRng::from_seed([
1314 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1315 0xbc, 0xe5,
1316 ]);
1317
1318 for _ in 0..1000 {
1319 let a = Fp::random(&mut rng);
1321 let a_repr = a.to_bytes_le();
1322 let b = Fp::from_bytes_le(&a_repr).unwrap();
1323 let b_repr = b.to_bytes_le();
1324 assert_eq!(a, b);
1325 assert_eq!(a_repr, b_repr);
1326 }
1327 }
1328
1329 #[test]
1330 fn test_fp_display() {
1331 assert_eq!(
1332 format!("{}", Fp::from_u64s_le(&[
1333 0xa956babf9301ea24,
1334 0x39a8f184f3535c7b,
1335 0xb38d35b3f6779585,
1336 0x676cc4eef4c46f2c,
1337 0xb1d4aad87651e694,
1338 0x1947f0d5f4fe325a
1339 ])
1340 .unwrap()),
1341 "Fp(0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24)".to_string()
1342 );
1343
1344 assert_eq!(
1345 format!("{}", Fp::from_u64s_le(&[
1346 0xe28e79396ac2bbf8,
1347 0x413f6f7f06ea87eb,
1348 0xa4b62af4a792a689,
1349 0xb7f89f88f59c1dc5,
1350 0x9a551859b1e43a9a,
1351 0x6c9f5a1060de974
1352 ])
1353 .unwrap()),
1354 "Fp(0x06c9f5a1060de9749a551859b1e43a9ab7f89f88f59c1dc5a4b62af4a792a689413f6f7f06ea87ebe28e79396ac2bbf8)".to_string()
1355 );
1356 }
1357
1358 #[test]
1359 fn test_fp_num_bits() {
1360 assert_eq!(NUM_BITS, 381);
1361
1362 let mut a = Fp::from(0);
1363 assert_eq!(0, a.num_bits());
1364 a = Fp::from(1);
1365 assert_eq!(1, a.num_bits());
1366 for i in 2..NUM_BITS {
1367 a = a.shl(1);
1368 assert_eq!(i, a.num_bits());
1369 }
1370 }
1371
1372 #[test]
1373 fn fp_field_tests() {
1374 crate::tests::field::random_field_tests::<Fp>();
1375 crate::tests::field::random_sqrt_tests::<Fp>();
1376 }
1377
1378 #[test]
1379 fn test_fp_ordering() {
1380 for i in 0..100 {
1383 let a = Fp::from(i + 1);
1384 let b = Fp::from(i);
1385 assert!(a > b, "{}: {:?} > {:?}", i, a, b);
1386 }
1387 }
1388
1389 #[test]
1390 fn test_inversion() {
1391 let a = Fp::from_raw_unchecked([
1392 0x43b4_3a50_78ac_2076,
1393 0x1ce0_7630_46f8_962b,
1394 0x724a_5276_486d_735c,
1395 0x6f05_c2a6_282d_48fd,
1396 0x2095_bd5b_b4ca_9331,
1397 0x03b3_5b38_94b0_f7da,
1398 ]);
1399 let b = Fp::from_raw_unchecked([
1400 0x69ec_d704_0952_148f,
1401 0x985c_cc20_2219_0f55,
1402 0xe19b_ba36_a9ad_2f41,
1403 0x19bb_16c9_5219_dbd8,
1404 0x14dc_acfd_fb47_8693,
1405 0x115f_f58a_fff9_a8e1,
1406 ]);
1407
1408 assert_eq!(a.invert().unwrap(), b);
1409 assert!(bool::from(Fp::ZERO.invert().is_none()));
1410 }
1411}