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