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