Skip to main content

nam_blstrs/
fp.rs

1//! This module provides an implementation of the BLS12-381 base field `GF(p)`
2//! where `p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab`
3
4use 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// Little-endian non-Montgomery form.
18#[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
28// Little-endian non-Montgomery form.
29const 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
39/// R = 2^384 mod p
40const 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/// R2 = 2^(384*2) mod p
52#[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/// `Fp` values are always in Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^384. `blst_fp.l`
65/// is in little-endian `u64` limbs format.
66#[derive(Copy, Clone, Zeroize)]
67#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
68#[repr(transparent)]
69pub struct Fp(pub(crate) blst_fp);
70
71// Coefficients for the Frobenius automorphism.
72pub(crate) const FROBENIUS_COEFF_FP2_C1: [Fp; 2] = [
73    // Fp(-1)**(((q^0) - 1) / 2)
74    Fp(blst_fp {
75        l: [
76            0x760900000002fffd,
77            0xebf4000bc40c0002,
78            0x5f48985753c758ba,
79            0x77ce585370525745,
80            0x5c071a97a256ec6d,
81            0x15f65ec3fa80e493,
82        ],
83    }),
84    // Fp(-1)**(((q^1) - 1) / 2)
85    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(u + 1)**(((q^0) - 1) / 3)
99    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(u + 1)**(((q^1) - 1) / 3)
115    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(u + 1)**(((q^2) - 1) / 3)
131    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(u + 1)**(((q^3) - 1) / 3)
147    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(u + 1)**(((q^4) - 1) / 3)
163    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(u + 1)**(((q^5) - 1) / 3)
179    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(u + 1)**(((2q^0) - 2) / 3)
198    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(u + 1)**(((2q^1) - 2) / 3)
214    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(u + 1)**(((2q^2) - 2) / 3)
230    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(u + 1)**(((2q^3) - 2) / 3)
246    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(u + 1)**(((2q^4) - 2) / 3)
262    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(u + 1)**(((2q^5) - 2) / 3)
278    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// Returns `true` if  `le_bytes` is less than the modulus (both are in non-Montgomery form).
478#[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 if matching the modulus
488    false
489}
490
491// Returns `true` if  `le_bytes` is less than the modulus (both are in non-Montgomery form).
492#[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 if matching the modulus
502    false
503}
504
505const NUM_BITS: u32 = 381;
506/// The number of bits we should "shave" from a randomly sampled reputation.
507const 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            // Mask away the unused most-significant bits.
518            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    // Returns `1 mod p` in Montgomery form `1 * R mod p`;
529    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        // ff::helpers::sqrt_ratio_generic(num, div)
562        unimplemented!()
563    }
564}
565
566impl Fp {
567    pub fn char() -> [u8; 48] {
568        MODULUS_REPR
569    }
570
571    /// Attempts to convert a little-endian byte representation of
572    /// a scalar into an `Fp`, failing if the input is not canonical.
573    pub fn from_bytes_le(bytes: &[u8; 48]) -> CtOption<Fp> {
574        // TODO: constant time
575        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    /// Attempts to convert a big-endian byte representation of
583    /// a scalar into an `Fp`, failing if the input is not canonical.
584    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    /// Converts an element of `Fp` into a byte representation in
591    /// little-endian byte order.
592    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    /// Converts an element of `Fp` into a byte representation in
599    /// big-endian byte order.
600    pub fn to_bytes_be(&self) -> [u8; 48] {
601        let mut bytes = self.to_bytes_le();
602        bytes.reverse();
603        bytes
604    }
605
606    /// Constructs an element of `Fp` from a little-endian array of limbs without checking that it
607    /// is canonical and without converting it to Montgomery form (i.e. without multiplying by `R`).
608    pub fn from_raw_unchecked(l: [u64; 6]) -> Fp {
609        Fp(blst_fp { l })
610    }
611
612    /// Multiplies `self` with `3`, returning the result.
613    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    /// Multiplies `self` with `8`, returning the result.
620    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    /// Left shift `self` by `count`, returning the result.
627    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    // `u64s` represent a little-endian non-Montgomery form integer mod p.
634    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            // Random number
732            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            // Test that adding zero has no effect.
744            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            // Add one and test for the result.
759            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            // Add another random number that exercises the reduction.
776            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            // Add one to (q - 1) and test for the result.
800            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            // Add a random number to another one such that the result is q - 1
815            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            // Add one to the result and test for it.
849            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        // Test associativity
856
857        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            // Generate a, b, c and ensure (a + b) + c == a + (b + c).
864            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!(tmp1.is_valid());
877            // assert!(tmp2.is_valid());
878            assert_eq!(tmp1, tmp2);
879        }
880    }
881
882    #[test]
883    fn test_fp_sub_assign() {
884        {
885            // Test arbitrary subtraction that tests reduction.
886            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            // Test the opposite subtraction which doesn't test reduction.
921            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            // Test for sensible results with zero
956            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            // Ensure that (a - b) + (b - a) = 0.
993            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            // Ensure that (a * b) * c = a * (b * c)
1048            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            // Ensure that r * (a + b + c) = r*a + r*b + r*c
1065
1066            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            // Ensure that (a * a) = a^2
1120            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            // Ensure that a * a^-1 = 1
1144            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            // Ensure doubling a is equivalent to adding a to itself.
1160            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            // Ensure (a - (-a)) = 0.
1179            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            // Exponentiate by various small numbers and ensure it consists with repeated
1196            // multiplication.
1197            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            // Exponentiating by the modulus should have no effect in a prime field.
1208            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            // Ensure sqrt(a^2) = a or -a
1226            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            // Ensure sqrt(a)^2 = a for random a
1233            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        // a = 4
1240        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            // sqrt(4) = -2
1251            -a.sqrt().unwrap(),
1252            // 2
1253            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        // q + 1 should not be in the field
1267        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        // Multiply some arbitrary representations to see if the result is as expected.
1280        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        // Zero should be in the field.
1311        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            // Try to turn Fp elements into representations and back again, and compare.
1320            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        // FpRepr's ordering is well-tested, but we still need to make sure the Fp
1381        // elements aren't being compared in Montgomery form.
1382        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}