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};
13
14use crate::fp2::Fp2;
15
16// Little-endian non-Montgomery form.
17#[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
27// Little-endian non-Montgomery form.
28const 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
38/// R = 2^384 mod p
39const 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/// R2 = 2^(384*2) mod p
51#[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/// `Fp` values are always in Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^384. `blst_fp.l`
64/// is in little-endian `u64` limbs format.
65#[derive(Copy, Clone)]
66#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
67#[repr(transparent)]
68pub struct Fp(pub(crate) blst_fp);
69
70// Coefficients for the Frobenius automorphism.
71pub(crate) const FROBENIUS_COEFF_FP2_C1: [Fp; 2] = [
72    // Fp(-1)**(((q^0) - 1) / 2)
73    Fp(blst_fp {
74        l: [
75            0x760900000002fffd,
76            0xebf4000bc40c0002,
77            0x5f48985753c758ba,
78            0x77ce585370525745,
79            0x5c071a97a256ec6d,
80            0x15f65ec3fa80e493,
81        ],
82    }),
83    // Fp(-1)**(((q^1) - 1) / 2)
84    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(u + 1)**(((q^0) - 1) / 3)
98    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(u + 1)**(((q^1) - 1) / 3)
114    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(u + 1)**(((q^2) - 1) / 3)
130    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(u + 1)**(((q^3) - 1) / 3)
146    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(u + 1)**(((q^4) - 1) / 3)
162    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(u + 1)**(((q^5) - 1) / 3)
178    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(u + 1)**(((2q^0) - 2) / 3)
197    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(u + 1)**(((2q^1) - 2) / 3)
213    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(u + 1)**(((2q^2) - 2) / 3)
229    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(u + 1)**(((2q^3) - 2) / 3)
245    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(u + 1)**(((2q^4) - 2) / 3)
261    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(u + 1)**(((2q^5) - 2) / 3)
277    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// Returns `true` if  `le_bytes` is less than the modulus (both are in non-Montgomery form).
477#[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 if matching the modulus
487    false
488}
489
490// Returns `true` if  `le_bytes` is less than the modulus (both are in non-Montgomery form).
491#[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 if matching the modulus
501    false
502}
503
504const NUM_BITS: u32 = 381;
505/// The number of bits we should "shave" from a randomly sampled reputation.
506const 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            // Mask away the unused most-significant bits.
517            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    // Returns `1 mod p` in Montgomery form `1 * R mod p`;
528    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        // ff::helpers::sqrt_ratio_generic(num, div)
561        unimplemented!()
562    }
563}
564
565impl Fp {
566    pub fn char() -> [u8; 48] {
567        MODULUS_REPR
568    }
569
570    /// Attempts to convert a little-endian byte representation of
571    /// a scalar into an `Fp`, failing if the input is not canonical.
572    pub fn from_bytes_le(bytes: &[u8; 48]) -> CtOption<Fp> {
573        // TODO: constant time
574        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    /// Attempts to convert a big-endian byte representation of
582    /// a scalar into an `Fp`, failing if the input is not canonical.
583    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    /// Converts an element of `Fp` into a byte representation in
590    /// little-endian byte order.
591    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    /// Converts an element of `Fp` into a byte representation in
598    /// big-endian byte order.
599    pub fn to_bytes_be(&self) -> [u8; 48] {
600        let mut bytes = self.to_bytes_le();
601        bytes.reverse();
602        bytes
603    }
604
605    /// Constructs an element of `Fp` from a little-endian array of limbs without checking that it
606    /// is canonical and without converting it to Montgomery form (i.e. without multiplying by `R`).
607    pub fn from_raw_unchecked(l: [u64; 6]) -> Fp {
608        Fp(blst_fp { l })
609    }
610
611    /// Multiplies `self` with `3`, returning the result.
612    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    /// Multiplies `self` with `8`, returning the result.
619    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    /// Left shift `self` by `count`, returning the result.
626    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    // `u64s` represent a little-endian non-Montgomery form integer mod p.
633    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            // Random number
731            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            // Test that adding zero has no effect.
743            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            // Add one and test for the result.
758            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            // Add another random number that exercises the reduction.
775            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            // Add one to (q - 1) and test for the result.
799            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            // Add a random number to another one such that the result is q - 1
814            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            // Add one to the result and test for it.
848            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        // Test associativity
855
856        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            // Generate a, b, c and ensure (a + b) + c == a + (b + c).
863            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!(tmp1.is_valid());
876            // assert!(tmp2.is_valid());
877            assert_eq!(tmp1, tmp2);
878        }
879    }
880
881    #[test]
882    fn test_fp_sub_assign() {
883        {
884            // Test arbitrary subtraction that tests reduction.
885            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            // Test the opposite subtraction which doesn't test reduction.
920            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            // Test for sensible results with zero
955            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            // Ensure that (a - b) + (b - a) = 0.
992            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            // Ensure that (a * b) * c = a * (b * c)
1047            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            // Ensure that r * (a + b + c) = r*a + r*b + r*c
1064
1065            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            // Ensure that (a * a) = a^2
1119            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            // Ensure that a * a^-1 = 1
1143            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            // Ensure doubling a is equivalent to adding a to itself.
1159            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            // Ensure (a - (-a)) = 0.
1178            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            // Exponentiate by various small numbers and ensure it consists with repeated
1195            // multiplication.
1196            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            // Exponentiating by the modulus should have no effect in a prime field.
1207            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            // Ensure sqrt(a^2) = a or -a
1225            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            // Ensure sqrt(a)^2 = a for random a
1232            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        // a = 4
1239        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            // sqrt(4) = -2
1250            -a.sqrt().unwrap(),
1251            // 2
1252            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        // q + 1 should not be in the field
1266        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        // Multiply some arbitrary representations to see if the result is as expected.
1279        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        // Zero should be in the field.
1310        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            // Try to turn Fp elements into representations and back again, and compare.
1319            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        // FpRepr's ordering is well-tested, but we still need to make sure the Fp
1380        // elements aren't being compared in Montgomery form.
1381        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}