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