twenty_first/math/
b_field_element.rs

1use std::convert::TryFrom;
2use std::fmt;
3use std::fmt::Formatter;
4use std::hash::Hash;
5use std::iter::Sum;
6use std::num::TryFromIntError;
7use std::ops::Add;
8use std::ops::AddAssign;
9use std::ops::Div;
10use std::ops::Mul;
11use std::ops::MulAssign;
12use std::ops::Neg;
13use std::ops::Sub;
14use std::ops::SubAssign;
15use std::str::FromStr;
16
17use arbitrary::Arbitrary;
18use arbitrary::Unstructured;
19use get_size2::GetSize;
20use num_traits::ConstOne;
21use num_traits::ConstZero;
22use num_traits::One;
23use num_traits::Zero;
24use phf::phf_map;
25use rand::Rng;
26use rand::distr::Distribution;
27use rand::distr::StandardUniform;
28use serde::Deserialize;
29use serde::Deserializer;
30use serde::Serialize;
31use serde::Serializer;
32
33use super::traits::Inverse;
34use super::traits::PrimitiveRootOfUnity;
35use super::x_field_element::XFieldElement;
36use crate::error::ParseBFieldElementError;
37use crate::math::traits::CyclicGroupGenerator;
38use crate::math::traits::FiniteField;
39use crate::math::traits::ModPowU32;
40use crate::math::traits::ModPowU64;
41
42const PRIMITIVE_ROOTS: phf::Map<u64, u64> = phf_map! {
43    0u64 => 1,
44    1u64 => 1,
45    2u64 => 18446744069414584320,
46    4u64 => 281474976710656,
47    8u64 => 18446744069397807105,
48    16u64 => 17293822564807737345,
49    32u64 => 70368744161280,
50    64u64 => 549755813888,
51    128u64 => 17870292113338400769,
52    256u64 => 13797081185216407910,
53    512u64 => 1803076106186727246,
54    1024u64 => 11353340290879379826,
55    2048u64 => 455906449640507599,
56    4096u64 => 17492915097719143606,
57    8192u64 => 1532612707718625687,
58    16384u64 => 16207902636198568418,
59    32768u64 => 17776499369601055404,
60    65536u64 => 6115771955107415310,
61    131072u64 => 12380578893860276750,
62    262144u64 => 9306717745644682924,
63    524288u64 => 18146160046829613826,
64    1048576u64 => 3511170319078647661,
65    2097152u64 => 17654865857378133588,
66    4194304u64 => 5416168637041100469,
67    8388608u64 => 16905767614792059275,
68    16777216u64 => 9713644485405565297,
69    33554432u64 => 5456943929260765144,
70    67108864u64 => 17096174751763063430,
71    134217728u64 => 1213594585890690845,
72    268435456u64 => 6414415596519834757,
73    536870912u64 => 16116352524544190054,
74    1073741824u64 => 9123114210336311365,
75    2147483648u64 => 4614640910117430873,
76    4294967296u64 => 1753635133440165772,
77};
78
79/// Base field element ∈ ℤ_{2^64 - 2^32 + 1}.
80///
81/// In Montgomery representation. This implementation follows <https://eprint.iacr.org/2022/274.pdf>
82/// and <https://github.com/novifinancial/winterfell/pull/101/files>.
83#[derive(Copy, Clone, Default, Hash, PartialEq, Eq, GetSize)]
84#[repr(transparent)]
85pub struct BFieldElement(u64);
86
87/// Simplifies constructing [base field element][BFieldElement]s.
88///
89/// The type [`BFieldElement`] must be in scope for this macro to work.
90/// See [`BFieldElement::from`] for supported types.
91///
92/// # Examples
93///
94/// ```
95/// # use twenty_first::prelude::*;
96/// let a = bfe!(42);
97/// let b = bfe!(-12); // correctly translates to `BFieldElement::P - 12`
98/// let c = bfe!(42 - 12);
99/// assert_eq!(a + b, c);
100///```
101#[macro_export]
102macro_rules! bfe {
103    ($value:expr) => {
104        BFieldElement::from($value)
105    };
106}
107
108/// Simplifies constructing vectors of [base field element][BFieldElement]s.
109///
110/// The type [`BFieldElement`] must be in scope for this macro to work. See also [`bfe!`].
111///
112/// # Examples
113///
114/// ```
115/// # use twenty_first::prelude::*;
116/// let a = bfe_vec![1, 2, 3];
117/// let b = vec![bfe!(1), bfe!(2), bfe!(3)];
118/// assert_eq!(a, b);
119/// ```
120///
121/// ```
122/// # use twenty_first::prelude::*;
123/// let a = bfe_vec![42; 15];
124/// let b = vec![bfe!(42); 15];
125/// assert_eq!(a, b);
126/// ```
127///
128#[macro_export]
129macro_rules! bfe_vec {
130    ($b:expr; $n:expr) => {
131        vec![BFieldElement::from($b); $n]
132    };
133    ($($b:expr),* $(,)?) => {
134        vec![$(BFieldElement::from($b)),*]
135    };
136}
137
138/// Simplifies constructing arrays of [base field element][BFieldElement]s.
139///
140/// The type [`BFieldElement`] must be in scope for this macro to work. See also [`bfe!`].
141///
142/// # Examples
143///
144/// ```
145/// # use twenty_first::prelude::*;
146/// let a = bfe_array![1, 2, 3];
147/// let b = [bfe!(1), bfe!(2), bfe!(3)];
148/// assert_eq!(a, b);
149/// ```
150///
151/// ```
152/// # use twenty_first::prelude::*;
153/// let a = bfe_array![42; 15];
154/// let b = [bfe!(42); 15];
155/// assert_eq!(a, b);
156/// ```
157#[macro_export]
158macro_rules! bfe_array {
159    ($b:expr; $n:expr) => {
160        [BFieldElement::from($b); $n]
161    };
162    ($($b:expr),* $(,)?) => {
163        [$(BFieldElement::from($b)),*]
164    };
165}
166
167impl fmt::Debug for BFieldElement {
168    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
169        f.debug_tuple("BFieldElement").field(&self.value()).finish()
170    }
171}
172
173impl fmt::LowerHex for BFieldElement {
174    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
175        fmt::LowerHex::fmt(&self.value(), f)
176    }
177}
178
179impl fmt::UpperHex for BFieldElement {
180    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
181        fmt::UpperHex::fmt(&self.value(), f)
182    }
183}
184
185impl<'a> Arbitrary<'a> for BFieldElement {
186    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
187        u.arbitrary().map(BFieldElement::new)
188    }
189}
190
191impl Serialize for BFieldElement {
192    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193    where
194        S: Serializer,
195    {
196        self.value().serialize(serializer)
197    }
198}
199
200impl<'de> Deserialize<'de> for BFieldElement {
201    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
202    where
203        D: Deserializer<'de>,
204    {
205        Ok(Self::new(u64::deserialize(deserializer)?))
206    }
207}
208
209impl Sum for BFieldElement {
210    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
211        iter.reduce(|a, b| a + b)
212            .unwrap_or_else(BFieldElement::zero)
213    }
214}
215
216impl BFieldElement {
217    pub const BYTES: usize = 8;
218
219    /// The base field's prime, _i.e._, 2^64 - 2^32 + 1.
220    pub const P: u64 = 0xffff_ffff_0000_0001;
221    pub const MAX: u64 = Self::P - 1;
222
223    /// 2^128 mod P; this is used for conversion of elements into Montgomery representation.
224    const R2: u64 = 0xffff_fffe_0000_0001;
225
226    /// -2^-1
227    pub const MINUS_TWO_INVERSE: Self = Self::new(0x7fff_ffff_8000_0000);
228
229    #[inline]
230    pub const fn new(value: u64) -> Self {
231        Self(Self::montyred((value as u128) * (Self::R2 as u128)))
232    }
233
234    /// Construct a new base field element iff the given value is
235    /// [canonical][Self::is_canonical], an error otherwise.
236    fn try_new(v: u64) -> Result<Self, ParseBFieldElementError> {
237        Self::is_canonical(v)
238            .then(|| Self::new(v))
239            .ok_or(ParseBFieldElementError::NotCanonical(i128::from(v)))
240    }
241
242    #[inline]
243    pub const fn value(&self) -> u64 {
244        self.canonical_representation()
245    }
246
247    #[must_use]
248    #[inline]
249    pub fn inverse(&self) -> Self {
250        #[inline(always)]
251        const fn exp(base: BFieldElement, exponent: u64) -> BFieldElement {
252            let mut res = base;
253            let mut i = 0;
254            while i < exponent {
255                res = BFieldElement(BFieldElement::montyred(res.0 as u128 * res.0 as u128));
256                i += 1;
257            }
258            res
259        }
260
261        let x = *self;
262        assert_ne!(
263            x,
264            Self::ZERO,
265            "Attempted to find the multiplicative inverse of zero."
266        );
267
268        let bin_2_ones = x.square() * x;
269        let bin_3_ones = bin_2_ones.square() * x;
270        let bin_6_ones = exp(bin_3_ones, 3) * bin_3_ones;
271        let bin_12_ones = exp(bin_6_ones, 6) * bin_6_ones;
272        let bin_24_ones = exp(bin_12_ones, 12) * bin_12_ones;
273        let bin_30_ones = exp(bin_24_ones, 6) * bin_6_ones;
274        let bin_31_ones = bin_30_ones.square() * x;
275        let bin_31_ones_1_zero = bin_31_ones.square();
276        let bin_32_ones = bin_31_ones.square() * x;
277
278        exp(bin_31_ones_1_zero, 32) * bin_32_ones
279    }
280
281    /// Square the base M times and multiply the result by the tail value
282    #[inline]
283    pub const fn power_accumulator<const N: usize, const M: usize>(
284        base: [Self; N],
285        tail: [Self; N],
286    ) -> [Self; N] {
287        let mut result = base;
288        let mut i = 0;
289        while i < M {
290            let mut j = 0;
291            while j < N {
292                result[j] = Self(Self::montyred(result[j].0 as u128 * result[j].0 as u128));
293                j += 1;
294            }
295            i += 1;
296        }
297
298        let mut j = 0;
299        while j < N {
300            result[j] = Self(Self::montyred(result[j].0 as u128 * tail[j].0 as u128));
301            j += 1;
302        }
303        result
304    }
305
306    /// A generator for the entire base field.
307    pub const fn generator() -> Self {
308        BFieldElement::new(7)
309    }
310
311    /// Turn this base field element into the corresponding extension field
312    /// element.
313    #[inline]
314    pub const fn lift(&self) -> XFieldElement {
315        XFieldElement::new_const(*self)
316    }
317
318    /// Add [`BFieldElement::ONE`] to `self`.
319    pub fn increment(&mut self) {
320        *self += Self::ONE;
321    }
322
323    /// Subtract [`BFieldElement::ONE`] from `self`.
324    pub fn decrement(&mut self) {
325        *self -= Self::ONE;
326    }
327
328    #[inline]
329    const fn canonical_representation(&self) -> u64 {
330        Self::montyred(self.0 as u128)
331    }
332
333    #[must_use]
334    #[inline]
335    pub const fn mod_pow(&self, exp: u64) -> Self {
336        let mut acc = BFieldElement::ONE;
337        let bit_length = u64::BITS - exp.leading_zeros();
338        let mut i = 0;
339        while i < bit_length {
340            acc = Self(Self::montyred(acc.0 as u128 * acc.0 as u128));
341            if exp & (1 << (bit_length - 1 - i)) != 0 {
342                acc = Self(Self::montyred(acc.0 as u128 * self.0 as u128));
343            }
344            i += 1;
345        }
346
347        acc
348    }
349
350    /// Montgomery reduction
351    #[inline(always)]
352    pub const fn montyred(x: u128) -> u64 {
353        // See reference above for a description of the following implementation.
354        let xl = x as u64;
355        let xh = (x >> 64) as u64;
356        let (a, e) = xl.overflowing_add(xl << 32);
357
358        let b = a.wrapping_sub(a >> 32).wrapping_sub(e as u64);
359
360        let (r, c) = xh.overflowing_sub(b);
361
362        // See https://github.com/Neptune-Crypto/twenty-first/pull/70 for various ways
363        // of expressing this.
364        r.wrapping_sub((1 + !Self::P) * c as u64)
365    }
366
367    /// Return the raw bytes or 8-bit chunks of the Montgomery
368    /// representation, in little-endian byte order
369    pub const fn raw_bytes(&self) -> [u8; 8] {
370        self.0.to_le_bytes()
371    }
372
373    /// Take a slice of 8 bytes and interpret it as an integer in
374    /// little-endian byte order, and cast it to a BFieldElement
375    /// in Montgomery representation
376    pub const fn from_raw_bytes(bytes: &[u8; 8]) -> Self {
377        Self(u64::from_le_bytes(*bytes))
378    }
379
380    /// Return the raw 16-bit chunks of the Montgomery
381    /// representation, in little-endian chunk order
382    pub const fn raw_u16s(&self) -> [u16; 4] {
383        [
384            (self.0 & 0xffff) as u16,
385            ((self.0 >> 16) & 0xffff) as u16,
386            ((self.0 >> 32) & 0xffff) as u16,
387            ((self.0 >> 48) & 0xffff) as u16,
388        ]
389    }
390
391    /// Take a slice of 4 16-bit chunks and interpret it as an integer in
392    /// little-endian chunk order, and cast it to a BFieldElement
393    /// in Montgomery representation
394    pub const fn from_raw_u16s(chunks: &[u16; 4]) -> Self {
395        Self(
396            ((chunks[3] as u64) << 48)
397                | ((chunks[2] as u64) << 32)
398                | ((chunks[1] as u64) << 16)
399                | (chunks[0] as u64),
400        )
401    }
402
403    #[inline]
404    pub fn raw_u128(&self) -> u128 {
405        self.0.into()
406    }
407
408    #[inline]
409    pub const fn from_raw_u64(e: u64) -> BFieldElement {
410        BFieldElement(e)
411    }
412
413    #[inline]
414    pub const fn raw_u64(&self) -> u64 {
415        self.0
416    }
417
418    #[inline]
419    pub const fn is_canonical(x: u64) -> bool {
420        x < Self::P
421    }
422}
423
424impl fmt::Display for BFieldElement {
425    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426        let canonical_value = Self::canonical_representation(self);
427        let cutoff = 256;
428        if canonical_value >= Self::P - cutoff {
429            write!(f, "-{}", Self::P - canonical_value)
430        } else if canonical_value <= cutoff {
431            write!(f, "{canonical_value}")
432        } else {
433            write!(f, "{canonical_value:>020}")
434        }
435    }
436}
437
438impl FromStr for BFieldElement {
439    type Err = ParseBFieldElementError;
440
441    fn from_str(s: &str) -> Result<Self, Self::Err> {
442        let parsed = s.parse::<i128>().map_err(Self::Err::ParseIntError)?;
443
444        let p = i128::from(Self::P);
445        let normalized = match parsed {
446            n if n <= -p => return Err(Self::Err::NotCanonical(parsed)),
447            n if n < 0 => n + p,
448            n => n,
449        };
450
451        let bfe_value = u64::try_from(normalized).map_err(|_| Self::Err::NotCanonical(parsed))?;
452        Self::try_new(bfe_value)
453    }
454}
455
456impl From<usize> for BFieldElement {
457    fn from(value: usize) -> Self {
458        // targets with wider target pointers don't exist at the time of writing
459        #[cfg(any(
460            target_pointer_width = "16",
461            target_pointer_width = "32",
462            target_pointer_width = "64",
463        ))]
464        Self::new(value as u64)
465    }
466}
467
468impl From<u128> for BFieldElement {
469    fn from(value: u128) -> Self {
470        fn mod_reduce(x: u128) -> u64 {
471            const LOWER_MASK: u64 = 0xFFFF_FFFF;
472
473            let x_lo = x as u64;
474            let x_hi = (x >> 64) as u64;
475            let x_hi_lo = (x_hi as u32) as u64;
476            let x_hi_hi = x_hi >> 32;
477
478            // x_lo - x_hi_hi; potential underflow because `x_hi_hi` may be greater than `x_lo`
479            let (tmp0, is_underflow) = x_lo.overflowing_sub(x_hi_hi);
480            let tmp1 = tmp0.wrapping_sub(LOWER_MASK * (is_underflow as u64));
481
482            // guaranteed not to underflow
483            let tmp2 = (x_hi_lo << 32) - x_hi_lo;
484
485            // adding tmp values gives final result;
486            // potential overflow because each of the `tmp`s may be up to 64 bits
487            let (result, is_overflow) = tmp1.overflowing_add(tmp2);
488            result.wrapping_add(LOWER_MASK * (is_overflow as u64))
489        }
490
491        Self::new(mod_reduce(value))
492    }
493}
494
495macro_rules! impl_from_small_unsigned_int_for_bfe {
496    ($($t:ident),+ $(,)?) => {$(
497        impl From<$t> for BFieldElement {
498            fn from(value: $t) -> Self {
499                Self::new(u64::from(value))
500            }
501        }
502    )+};
503}
504
505impl_from_small_unsigned_int_for_bfe!(u8, u16, u32, u64);
506
507impl From<isize> for BFieldElement {
508    fn from(value: isize) -> Self {
509        // targets with wider target pointers don't exist at the time of writing
510        #[cfg(target_pointer_width = "16")]
511        {
512            (value as i16).into()
513        }
514        #[cfg(target_pointer_width = "32")]
515        {
516            (value as i32).into()
517        }
518        #[cfg(target_pointer_width = "64")]
519        {
520            (value as i64).into()
521        }
522    }
523}
524
525impl From<i64> for BFieldElement {
526    fn from(value: i64) -> Self {
527        match i128::from(value) {
528            0.. => value as u128,
529            _ => (value as u128) - BFieldElement::R2 as u128,
530        }
531        .into()
532    }
533}
534
535macro_rules! impl_from_small_signed_int_for_bfe {
536    ($($t:ident),+ $(,)?) => {$(
537        impl From<$t> for BFieldElement {
538            fn from(value: $t) -> Self {
539                i64::from(value).into()
540            }
541        }
542    )+};
543}
544
545impl_from_small_signed_int_for_bfe!(i8, i16, i32);
546
547macro_rules! impl_try_from_bfe_for_int {
548    ($($t:ident),+ $(,)?) => {$(
549        impl TryFrom<BFieldElement> for $t {
550            type Error = TryFromIntError;
551
552            fn try_from(value: BFieldElement) -> Result<Self, Self::Error> {
553                $t::try_from(value.canonical_representation())
554            }
555        }
556
557        impl TryFrom<&BFieldElement> for $t {
558            type Error = TryFromIntError;
559
560            fn try_from(value: &BFieldElement) -> Result<Self, Self::Error> {
561                $t::try_from(value.canonical_representation())
562            }
563        }
564    )+};
565}
566
567impl_try_from_bfe_for_int!(u8, i8, u16, i16, u32, i32, usize, isize);
568
569macro_rules! impl_from_bfe_for_int {
570    ($($t:ident),+ $(,)?) => {$(
571        impl From<BFieldElement> for $t {
572            fn from(elem: BFieldElement) -> Self {
573                Self::from(elem.canonical_representation())
574            }
575        }
576
577        impl From<&BFieldElement> for $t {
578            fn from(elem: &BFieldElement) -> Self {
579                Self::from(elem.canonical_representation())
580            }
581        }
582    )+};
583}
584
585impl_from_bfe_for_int!(u64, u128, i128);
586
587impl From<BFieldElement> for i64 {
588    fn from(elem: BFieldElement) -> Self {
589        bfe_to_i64(&elem)
590    }
591}
592
593impl From<&BFieldElement> for i64 {
594    fn from(elem: &BFieldElement) -> Self {
595        bfe_to_i64(elem)
596    }
597}
598
599const fn bfe_to_i64(bfe: &BFieldElement) -> i64 {
600    let v = bfe.canonical_representation();
601    if v <= i64::MAX as u64 {
602        v as i64
603    } else {
604        (v as i128 - BFieldElement::P as i128) as i64
605    }
606}
607
608/// Convert a B-field element to a byte array.
609/// The client uses this for its database.
610impl From<BFieldElement> for [u8; BFieldElement::BYTES] {
611    fn from(bfe: BFieldElement) -> Self {
612        // It's crucial to map this to the canonical representation before converting.
613        // Otherwise, the representation is degenerate.
614        bfe.canonical_representation().to_le_bytes()
615    }
616}
617
618impl TryFrom<[u8; BFieldElement::BYTES]> for BFieldElement {
619    type Error = ParseBFieldElementError;
620
621    fn try_from(array: [u8; BFieldElement::BYTES]) -> Result<Self, Self::Error> {
622        Self::try_new(u64::from_le_bytes(array))
623    }
624}
625
626impl TryFrom<&[u8]> for BFieldElement {
627    type Error = ParseBFieldElementError;
628
629    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
630        <[u8; BFieldElement::BYTES]>::try_from(bytes)
631            .map_err(|_| Self::Error::InvalidNumBytes(bytes.len()))?
632            .try_into()
633    }
634}
635
636impl Inverse for BFieldElement {
637    #[inline]
638    fn inverse(&self) -> Self {
639        self.inverse()
640    }
641}
642
643impl ModPowU32 for BFieldElement {
644    #[inline]
645    fn mod_pow_u32(&self, exp: u32) -> Self {
646        self.mod_pow(exp as u64)
647    }
648}
649
650impl CyclicGroupGenerator for BFieldElement {
651    fn get_cyclic_group_elements(&self, max: Option<usize>) -> Vec<Self> {
652        let mut val = *self;
653        let mut ret: Vec<Self> = vec![Self::one()];
654
655        loop {
656            ret.push(val);
657            val *= *self;
658            if val.is_one() || max.is_some() && ret.len() >= max.unwrap() {
659                break;
660            }
661        }
662        ret
663    }
664}
665
666impl Distribution<BFieldElement> for StandardUniform {
667    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BFieldElement {
668        BFieldElement::new(rng.random_range(0..=BFieldElement::MAX))
669    }
670}
671
672impl FiniteField for BFieldElement {}
673
674impl Zero for BFieldElement {
675    #[inline]
676    fn zero() -> Self {
677        Self::ZERO
678    }
679
680    #[inline]
681    fn is_zero(&self) -> bool {
682        self == &Self::ZERO
683    }
684}
685
686impl ConstZero for BFieldElement {
687    const ZERO: Self = Self::new(0);
688}
689
690impl One for BFieldElement {
691    #[inline]
692    fn one() -> Self {
693        Self::ONE
694    }
695
696    #[inline]
697    fn is_one(&self) -> bool {
698        self == &Self::ONE
699    }
700}
701
702impl ConstOne for BFieldElement {
703    const ONE: Self = Self::new(1);
704}
705
706impl Add for BFieldElement {
707    type Output = Self;
708
709    #[expect(clippy::suspicious_arithmetic_impl)]
710    #[inline(always)]
711    fn add(self, rhs: Self) -> Self {
712        // Compute a + b = a - (p - b).
713        let (x1, c1) = self.0.overflowing_sub(Self::P - rhs.0);
714
715        // The following if/else is equivalent to the commented-out code below but
716        // the if/else was found to be faster.
717        // let adj = 0u32.wrapping_sub(c1 as u32);
718        // Self(x1.wrapping_sub(adj as u64))
719        // See
720        // https://github.com/Neptune-Crypto/twenty-first/pull/70
721        if c1 {
722            Self(x1.wrapping_add(Self::P))
723        } else {
724            Self(x1)
725        }
726    }
727}
728
729impl AddAssign for BFieldElement {
730    #[inline(always)]
731    fn add_assign(&mut self, rhs: Self) {
732        *self = *self + rhs
733    }
734}
735
736impl SubAssign for BFieldElement {
737    #[inline]
738    fn sub_assign(&mut self, rhs: Self) {
739        *self = *self - rhs
740    }
741}
742
743impl MulAssign for BFieldElement {
744    #[inline]
745    fn mul_assign(&mut self, rhs: Self) {
746        *self = *self * rhs;
747    }
748}
749
750impl Mul for BFieldElement {
751    type Output = Self;
752
753    #[inline]
754    fn mul(self, rhs: Self) -> Self {
755        Self(Self::montyred((self.0 as u128) * (rhs.0 as u128)))
756    }
757}
758
759impl Neg for BFieldElement {
760    type Output = Self;
761
762    #[inline]
763    fn neg(self) -> Self {
764        Self::zero() - self
765    }
766}
767
768impl Sub for BFieldElement {
769    type Output = Self;
770
771    #[inline]
772    fn sub(self, rhs: Self) -> Self {
773        let (x1, c1) = self.0.overflowing_sub(rhs.0);
774
775        // The following code is equivalent to the commented-out code below
776        // but they were determined to have near-equiavalent running times. Maybe because
777        // subtraction is not used very often.
778        // See: https://github.com/Neptune-Crypto/twenty-first/pull/70
779        // 1st alternative:
780        // if c1 {
781        //     Self(x1.wrapping_add(Self::P))
782        // } else {
783        //     Self(x1)
784        // }
785        // 2nd alternative:
786        // let adj = 0u32.wrapping_sub(c1 as u32);
787        // Self(x1.wrapping_sub(adj as u64))
788        Self(x1.wrapping_sub((1 + !Self::P) * c1 as u64))
789    }
790}
791
792impl Div for BFieldElement {
793    type Output = Self;
794
795    #[expect(clippy::suspicious_arithmetic_impl)]
796    fn div(self, other: Self) -> Self {
797        other.inverse() * self
798    }
799}
800
801// TODO: We probably wanna make use of Rust's Pow, but for now we copy from ...big:
802impl ModPowU64 for BFieldElement {
803    #[inline]
804    fn mod_pow_u64(&self, pow: u64) -> Self {
805        self.mod_pow(pow)
806    }
807}
808
809impl PrimitiveRootOfUnity for BFieldElement {
810    fn primitive_root_of_unity(n: u64) -> Option<BFieldElement> {
811        PRIMITIVE_ROOTS.get(&n).map(|&r| BFieldElement::new(r))
812    }
813}
814
815#[cfg(test)]
816#[cfg_attr(coverage_nightly, coverage(off))]
817mod tests {
818    use std::collections::hash_map::DefaultHasher;
819    use std::hash::Hasher;
820
821    use itertools::izip;
822    use proptest::prelude::*;
823    use rand::random;
824
825    use crate::math::b_field_element::*;
826    use crate::math::other::random_elements;
827    use crate::math::polynomial::Polynomial;
828    use crate::proptest_arbitrary_interop::arb;
829    use crate::tests::proptest;
830    use crate::tests::test;
831
832    impl proptest::arbitrary::Arbitrary for BFieldElement {
833        type Parameters = ();
834
835        fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
836            arb().boxed()
837        }
838
839        type Strategy = BoxedStrategy<Self>;
840    }
841
842    #[macro_rules_attr::apply(proptest)]
843    fn get_size(bfe: BFieldElement) {
844        prop_assert_eq!(8, bfe.get_size());
845    }
846
847    #[macro_rules_attr::apply(proptest)]
848    fn serialization_and_deserialization_to_and_from_json_is_identity(bfe: BFieldElement) {
849        let serialized = serde_json::to_string(&bfe).unwrap();
850        let deserialized: BFieldElement = serde_json::from_str(&serialized).unwrap();
851        prop_assert_eq!(bfe, deserialized);
852    }
853
854    #[macro_rules_attr::apply(proptest)]
855    fn deserializing_u64_is_like_calling_new(#[strategy(0..=BFieldElement::MAX)] value: u64) {
856        let bfe = BFieldElement::new(value);
857        let deserialized: BFieldElement = serde_json::from_str(&value.to_string()).unwrap();
858        prop_assert_eq!(bfe, deserialized);
859    }
860
861    #[macro_rules_attr::apply(test)]
862    fn parsing_interval_is_open_minus_p_to_p() {
863        let p = i128::from(BFieldElement::P);
864        let display_then_parse = |v: i128| BFieldElement::from_str(&v.to_string());
865
866        assert!(display_then_parse(-p).is_err());
867        assert!(display_then_parse(-p + 1).is_ok());
868        assert!(display_then_parse(p - 1).is_ok());
869        assert!(display_then_parse(p).is_err());
870    }
871
872    #[macro_rules_attr::apply(proptest)]
873    fn parsing_string_representing_canonical_negative_integer_gives_correct_bfield_element(
874        #[strategy(0..=BFieldElement::MAX)] v: u64,
875    ) {
876        let bfe = BFieldElement::from_str(&(-i128::from(v)).to_string())?;
877        prop_assert_eq!(BFieldElement::P - v, bfe.value());
878    }
879
880    #[macro_rules_attr::apply(proptest)]
881    fn parsing_string_representing_canonical_positive_integer_gives_correct_bfield_element(
882        #[strategy(0..=BFieldElement::MAX)] v: u64,
883    ) {
884        let bfe = BFieldElement::from_str(&v.to_string())?;
885        prop_assert_eq!(v, bfe.value());
886    }
887
888    #[macro_rules_attr::apply(proptest)]
889    fn parsing_string_representing_too_big_positive_integer_as_bfield_element_gives_error(
890        #[strategy(i128::from(BFieldElement::P)..)] v: i128,
891    ) {
892        let err = BFieldElement::from_str(&v.to_string()).unwrap_err();
893        prop_assert_eq!(ParseBFieldElementError::NotCanonical(v), err);
894    }
895
896    #[macro_rules_attr::apply(proptest)]
897    fn parsing_string_representing_too_small_negative_integer_as_bfield_element_gives_error(
898        #[strategy(..=i128::from(BFieldElement::P))] v: i128,
899    ) {
900        let err = BFieldElement::from_str(&v.to_string()).unwrap_err();
901        prop_assert_eq!(ParseBFieldElementError::NotCanonical(v), err);
902    }
903
904    #[macro_rules_attr::apply(proptest)]
905    fn zero_is_neutral_element_for_addition(bfe: BFieldElement) {
906        let zero = BFieldElement::ZERO;
907        prop_assert_eq!(bfe + zero, bfe);
908    }
909
910    #[macro_rules_attr::apply(proptest)]
911    fn one_is_neutral_element_for_multiplication(bfe: BFieldElement) {
912        let one = BFieldElement::ONE;
913        prop_assert_eq!(bfe * one, bfe);
914    }
915
916    #[macro_rules_attr::apply(proptest)]
917    fn addition_is_commutative(element_0: BFieldElement, element_1: BFieldElement) {
918        prop_assert_eq!(element_0 + element_1, element_1 + element_0);
919    }
920
921    #[macro_rules_attr::apply(proptest)]
922    fn multiplication_is_commutative(element_0: BFieldElement, element_1: BFieldElement) {
923        prop_assert_eq!(element_0 * element_1, element_1 * element_0);
924    }
925
926    #[macro_rules_attr::apply(proptest)]
927
928    fn addition_is_associative(
929        element_0: BFieldElement,
930        element_1: BFieldElement,
931        element_2: BFieldElement,
932    ) {
933        prop_assert_eq!(
934            (element_0 + element_1) + element_2,
935            element_0 + (element_1 + element_2)
936        );
937    }
938
939    #[macro_rules_attr::apply(proptest)]
940    fn multiplication_is_associative(
941        element_0: BFieldElement,
942        element_1: BFieldElement,
943        element_2: BFieldElement,
944    ) {
945        prop_assert_eq!(
946            (element_0 * element_1) * element_2,
947            element_0 * (element_1 * element_2)
948        );
949    }
950
951    #[macro_rules_attr::apply(proptest)]
952    fn multiplication_distributes_over_addition(
953        element_0: BFieldElement,
954        element_1: BFieldElement,
955        element_2: BFieldElement,
956    ) {
957        prop_assert_eq!(
958            element_0 * (element_1 + element_2),
959            element_0 * element_1 + element_0 * element_2
960        );
961    }
962
963    #[macro_rules_attr::apply(proptest)]
964    fn multiplication_with_inverse_gives_identity(#[filter(!#bfe.is_zero())] bfe: BFieldElement) {
965        prop_assert!((bfe.inverse() * bfe).is_one());
966    }
967
968    #[macro_rules_attr::apply(proptest)]
969    fn division_by_self_gives_identity(#[filter(!#bfe.is_zero())] bfe: BFieldElement) {
970        prop_assert!((bfe / bfe).is_one());
971    }
972
973    #[macro_rules_attr::apply(proptest)]
974    fn values_larger_than_modulus_are_handled_correctly(
975        #[strategy(BFieldElement::P..)] large_value: u64,
976    ) {
977        let bfe = BFieldElement::new(large_value);
978        let expected_value = large_value - BFieldElement::P;
979        prop_assert_eq!(expected_value, bfe.value());
980    }
981
982    #[macro_rules_attr::apply(test)]
983    fn display_test() {
984        let seven = BFieldElement::new(7);
985        assert_eq!("7", format!("{seven}"));
986        assert_eq!("7", format!("{seven:x}"));
987        assert_eq!("7", format!("{seven:X}"));
988        assert_eq!("0x7", format!("{seven:#x}"));
989        assert_eq!("0x7", format!("{seven:#X}"));
990        assert_eq!("BFieldElement(7)", format!("{seven:?}"));
991
992        let forty_two = BFieldElement::new(42);
993        assert_eq!("42", format!("{forty_two}"));
994        assert_eq!("2a", format!("{forty_two:x}"));
995        assert_eq!("2A", format!("{forty_two:X}"));
996        assert_eq!("0x2a", format!("{forty_two:#x}"));
997        assert_eq!("0x2A", format!("{forty_two:#X}"));
998        assert_eq!("BFieldElement(42)", format!("{forty_two:?}"));
999
1000        let minus_one = BFieldElement::new(BFieldElement::P - 1);
1001        assert_eq!("-1", format!("{minus_one}"));
1002        assert_eq!("ffffffff00000000", format!("{minus_one:x}"));
1003        assert_eq!("FFFFFFFF00000000", format!("{minus_one:X}"));
1004        assert_eq!("0xffffffff00000000", format!("{minus_one:#x}"));
1005        assert_eq!("0xFFFFFFFF00000000", format!("{minus_one:#X}"));
1006        assert_eq!(
1007            "BFieldElement(18446744069414584320)",
1008            format!("{minus_one:?}")
1009        );
1010
1011        let minus_fifteen = BFieldElement::new(BFieldElement::P - 15);
1012        assert_eq!("-15", format!("{minus_fifteen}"));
1013        assert_eq!("fffffffefffffff2", format!("{minus_fifteen:x}"));
1014        assert_eq!("FFFFFFFEFFFFFFF2", format!("{minus_fifteen:X}"));
1015        assert_eq!("0xfffffffefffffff2", format!("{minus_fifteen:#x}"));
1016        assert_eq!("0xFFFFFFFEFFFFFFF2", format!("{minus_fifteen:#X}"));
1017        assert_eq!(
1018            "BFieldElement(18446744069414584306)",
1019            format!("{minus_fifteen:?}")
1020        );
1021    }
1022
1023    #[macro_rules_attr::apply(test)]
1024    fn display_and_from_str_are_reciprocal_unit_test() {
1025        for bfe in bfe_array![
1026            -1000, -500, -200, -100, -10, -1, 0, 1, 10, 100, 200, 500, 1000
1027        ] {
1028            let bfe_again = bfe.to_string().parse().unwrap();
1029            assert_eq!(bfe, bfe_again);
1030        }
1031    }
1032
1033    #[macro_rules_attr::apply(proptest)]
1034    fn display_and_from_str_are_reciprocal_prop_test(bfe: BFieldElement) {
1035        let bfe_again = bfe.to_string().parse()?;
1036        prop_assert_eq!(bfe, bfe_again);
1037    }
1038
1039    #[macro_rules_attr::apply(test)]
1040    fn zero_is_zero() {
1041        let zero = BFieldElement::zero();
1042        assert!(zero.is_zero());
1043        assert_eq!(zero, BFieldElement::ZERO);
1044    }
1045
1046    #[macro_rules_attr::apply(proptest)]
1047    fn not_zero_is_nonzero(bfe: BFieldElement) {
1048        if bfe.value() == 0 {
1049            return Ok(());
1050        }
1051        prop_assert!(!bfe.is_zero());
1052    }
1053
1054    #[macro_rules_attr::apply(test)]
1055    fn one_is_one() {
1056        let one = BFieldElement::one();
1057        assert!(one.is_one());
1058        assert_eq!(one, BFieldElement::ONE);
1059    }
1060
1061    #[macro_rules_attr::apply(proptest)]
1062    fn not_one_is_not_one(bfe: BFieldElement) {
1063        if bfe.value() == 1 {
1064            return Ok(());
1065        }
1066        prop_assert!(!bfe.is_one());
1067    }
1068
1069    #[macro_rules_attr::apply(test)]
1070    fn one_unequal_zero() {
1071        let one = BFieldElement::ONE;
1072        let zero = BFieldElement::ZERO;
1073        assert_ne!(one, zero);
1074    }
1075
1076    #[macro_rules_attr::apply(proptest)]
1077    fn byte_array_of_small_field_elements_is_zero_at_high_indices(value: u8) {
1078        let bfe = BFieldElement::new(value as u64);
1079        let byte_array: [u8; 8] = bfe.into();
1080
1081        prop_assert_eq!(value, byte_array[0]);
1082        (1..8).for_each(|i| {
1083            assert_eq!(0, byte_array[i]);
1084        });
1085    }
1086
1087    #[macro_rules_attr::apply(proptest)]
1088    fn byte_array_conversion(bfe: BFieldElement) {
1089        let array: [u8; 8] = bfe.into();
1090        let bfe_recalculated: BFieldElement = array.try_into()?;
1091        prop_assert_eq!(bfe, bfe_recalculated);
1092    }
1093
1094    #[macro_rules_attr::apply(proptest)]
1095    fn byte_array_outside_range_is_not_accepted(#[strategy(BFieldElement::P..)] value: u64) {
1096        let byte_array = value.to_le_bytes();
1097        prop_assert!(BFieldElement::try_from(byte_array).is_err());
1098    }
1099
1100    #[macro_rules_attr::apply(proptest)]
1101    fn value_is_preserved(#[strategy(0..BFieldElement::P)] value: u64) {
1102        prop_assert_eq!(value, BFieldElement::new(value).value());
1103    }
1104
1105    #[macro_rules_attr::apply(test)]
1106    fn supposed_generator_is_generator() {
1107        let generator = BFieldElement::generator();
1108        let largest_meaningful_power = BFieldElement::P - 1;
1109        let generator_pow_p = generator.mod_pow(largest_meaningful_power);
1110        let generator_pow_p_half = generator.mod_pow(largest_meaningful_power / 2);
1111
1112        assert_eq!(BFieldElement::ONE, generator_pow_p);
1113        assert_ne!(BFieldElement::ONE, generator_pow_p_half);
1114    }
1115
1116    #[macro_rules_attr::apply(proptest)]
1117    fn lift_then_unlift_preserves_element(bfe: BFieldElement) {
1118        prop_assert_eq!(Some(bfe), bfe.lift().unlift());
1119    }
1120
1121    #[macro_rules_attr::apply(proptest)]
1122    fn increment(mut bfe: BFieldElement) {
1123        let old_value = bfe.value();
1124        bfe.increment();
1125        let expected_value = (old_value + 1) % BFieldElement::P;
1126        prop_assert_eq!(expected_value, bfe.value());
1127    }
1128
1129    #[macro_rules_attr::apply(test)]
1130    fn incrementing_max_value_wraps_around() {
1131        let mut bfe = BFieldElement::new(BFieldElement::MAX);
1132        bfe.increment();
1133        assert_eq!(0, bfe.value());
1134    }
1135
1136    #[macro_rules_attr::apply(proptest)]
1137    fn decrement(mut bfe: BFieldElement) {
1138        let old_value = bfe.value();
1139        bfe.decrement();
1140        let expected_value = old_value.checked_sub(1).unwrap_or(BFieldElement::P - 1);
1141        prop_assert_eq!(expected_value, bfe.value());
1142    }
1143
1144    #[macro_rules_attr::apply(test)]
1145    fn decrementing_min_value_wraps_around() {
1146        let mut bfe = BFieldElement::ZERO;
1147        bfe.decrement();
1148        assert_eq!(BFieldElement::MAX, bfe.value());
1149    }
1150
1151    #[macro_rules_attr::apply(test)]
1152    fn empty_batch_inversion() {
1153        let empty_inv = BFieldElement::batch_inversion(vec![]);
1154        assert!(empty_inv.is_empty());
1155    }
1156
1157    #[macro_rules_attr::apply(proptest)]
1158    fn batch_inversion(bfes: Vec<BFieldElement>) {
1159        let bfes_inv = BFieldElement::batch_inversion(bfes.clone());
1160        prop_assert_eq!(bfes.len(), bfes_inv.len());
1161        for (bfe, bfe_inv) in izip!(bfes, bfes_inv) {
1162            prop_assert_eq!(BFieldElement::ONE, bfe * bfe_inv);
1163        }
1164    }
1165
1166    #[macro_rules_attr::apply(test)]
1167    fn power_accumulator_simple_test() {
1168        let input_a = [
1169            BFieldElement::new(10),
1170            BFieldElement::new(100),
1171            BFieldElement::new(1000),
1172            BFieldElement::new(1),
1173        ];
1174        let input_b = [
1175            BFieldElement::new(5),
1176            BFieldElement::new(6),
1177            BFieldElement::new(7),
1178            BFieldElement::new(8),
1179        ];
1180        let powers: [BFieldElement; 4] = BFieldElement::power_accumulator::<4, 2>(input_a, input_b);
1181        assert_eq!(BFieldElement::new(50000), powers[0]);
1182        assert_eq!(BFieldElement::new(600000000), powers[1]);
1183        assert_eq!(BFieldElement::new(7000000000000), powers[2]);
1184        assert_eq!(BFieldElement::new(8), powers[3]);
1185    }
1186
1187    #[macro_rules_attr::apply(test)]
1188    fn mul_div_plus_minus_neg_property_based_test() {
1189        let elements: Vec<BFieldElement> = random_elements(300);
1190        let power_input_b: [BFieldElement; 6] = random();
1191        for i in 1..elements.len() {
1192            let a = elements[i - 1];
1193            let b = elements[i];
1194
1195            let ab = a * b;
1196            let a_o_b = a / b;
1197            let b_o_a = b / a;
1198            assert_eq!(a, ab / b);
1199            assert_eq!(b, ab / a);
1200            assert_eq!(a, a_o_b * b);
1201            assert_eq!(b, b_o_a * a);
1202            assert!((a_o_b * b_o_a).is_one());
1203            assert_eq!(a * a, a.square());
1204
1205            assert_eq!(a - b + b, a);
1206            assert_eq!(b - a + a, b);
1207            assert!((a - a).is_zero());
1208            assert!((b - b).is_zero());
1209
1210            // Test the add/sub/mul assign operators
1211            let mut a_minus_b = a;
1212            a_minus_b -= b;
1213            assert_eq!(a - b, a_minus_b);
1214
1215            let mut a_plus_b = a;
1216            a_plus_b += b;
1217            assert_eq!(a + b, a_plus_b);
1218
1219            let mut a_mul_b = a;
1220            a_mul_b *= b;
1221            assert_eq!(a * b, a_mul_b);
1222            assert_eq!(b * a, a_mul_b);
1223
1224            // Test negation
1225            assert!((-a + a).is_zero());
1226            assert!((-b + b).is_zero());
1227            assert!((-ab + ab).is_zero());
1228            assert!((-a_o_b + a_o_b).is_zero());
1229            assert!((-b_o_a + b_o_a).is_zero());
1230            assert!((-a_minus_b + a_minus_b).is_zero());
1231            assert!((-a_plus_b + a_plus_b).is_zero());
1232            assert!((-a_mul_b + a_mul_b).is_zero());
1233
1234            // Test power_accumulator
1235            let power_input_a = [a, b, ab, a_o_b, b_o_a, a_minus_b];
1236            let powers = BFieldElement::power_accumulator::<6, 4>(power_input_a, power_input_b);
1237            for ((result_element, input_a), input_b) in powers
1238                .iter()
1239                .zip(power_input_a.iter())
1240                .zip(power_input_b.iter())
1241            {
1242                assert_eq!(input_a.mod_pow(16) * *input_b, *result_element);
1243            }
1244        }
1245    }
1246
1247    #[macro_rules_attr::apply(test)]
1248    fn mul_div_pbt() {
1249        // Verify that the mul result is sane
1250        let rands: Vec<BFieldElement> = random_elements(100);
1251        for i in 1..rands.len() {
1252            let prod_mul = rands[i - 1] * rands[i];
1253            let mut prod_mul_assign = rands[i - 1];
1254            prod_mul_assign *= rands[i];
1255            assert_eq!(
1256                prod_mul, prod_mul_assign,
1257                "mul and mul_assign must be the same for B field elements"
1258            );
1259            assert_eq!(prod_mul / rands[i - 1], rands[i]);
1260            assert_eq!(prod_mul / rands[i], rands[i - 1]);
1261        }
1262    }
1263
1264    #[macro_rules_attr::apply(test)]
1265    fn add_sub_wrap_around_test() {
1266        // Ensure that something that exceeds P but is smaller than $2^64$
1267        // is still the correct field element. The property-based test is unlikely
1268        // to hit such an element as the chances of doing so are about 2^(-32) for
1269        // random uniform numbers. So we test this in a separate test
1270        let element = BFieldElement::new(4);
1271        let sum = BFieldElement::new(BFieldElement::MAX) + element;
1272        assert_eq!(BFieldElement::new(3), sum);
1273        let diff = sum - element;
1274        assert_eq!(BFieldElement::new(BFieldElement::MAX), diff);
1275    }
1276
1277    #[macro_rules_attr::apply(test)]
1278    fn neg_test() {
1279        assert_eq!(-BFieldElement::ZERO, BFieldElement::ZERO);
1280        assert_eq!(
1281            (-BFieldElement::ONE).canonical_representation(),
1282            BFieldElement::MAX
1283        );
1284        let max = BFieldElement::new(BFieldElement::MAX);
1285        let max_plus_one = max + BFieldElement::ONE;
1286        let max_plus_two = max_plus_one + BFieldElement::ONE;
1287        assert_eq!(BFieldElement::ZERO, -max_plus_one);
1288        assert_eq!(max, -max_plus_two);
1289    }
1290
1291    #[macro_rules_attr::apply(test)]
1292    fn equality_and_hash_test() {
1293        assert_eq!(BFieldElement::ZERO, BFieldElement::ZERO);
1294        assert_eq!(BFieldElement::ONE, BFieldElement::ONE);
1295        assert_ne!(BFieldElement::ONE, BFieldElement::ZERO);
1296        assert_eq!(BFieldElement::new(42), BFieldElement::new(42));
1297        assert_ne!(BFieldElement::new(42), BFieldElement::new(43));
1298
1299        assert_eq!(
1300            BFieldElement::new(102),
1301            BFieldElement::new(BFieldElement::MAX) + BFieldElement::new(103)
1302        );
1303        assert_ne!(
1304            BFieldElement::new(103),
1305            BFieldElement::new(BFieldElement::MAX) + BFieldElement::new(103)
1306        );
1307
1308        // Verify that hashing works for canonical representations
1309        let mut hasher_a = DefaultHasher::new();
1310        let mut hasher_b = DefaultHasher::new();
1311
1312        std::hash::Hash::hash(&BFieldElement::new(42), &mut hasher_a);
1313        std::hash::Hash::hash(&BFieldElement::new(42), &mut hasher_b);
1314        assert_eq!(hasher_a.finish(), hasher_b.finish());
1315
1316        // Verify that hashing works for non-canonical representations
1317        hasher_a = DefaultHasher::new();
1318        hasher_b = DefaultHasher::new();
1319        let non_canonical = BFieldElement::new(BFieldElement::MAX) + BFieldElement::new(103);
1320        std::hash::Hash::hash(&(non_canonical), &mut hasher_a);
1321        std::hash::Hash::hash(&BFieldElement::new(102), &mut hasher_b);
1322        assert_eq!(hasher_a.finish(), hasher_b.finish());
1323    }
1324
1325    #[macro_rules_attr::apply(test)]
1326    fn create_polynomial_test() {
1327        let a = Polynomial::from([1, 3, 7]);
1328        let b = Polynomial::from([2, 5, -1]);
1329        let expected = Polynomial::<BFieldElement>::from([3, 8, 6]);
1330
1331        assert_eq!(expected, a + b);
1332    }
1333
1334    #[macro_rules_attr::apply(test)]
1335    fn mod_pow_test_powers_of_two() {
1336        let two = BFieldElement::new(2);
1337        // 2^63 < 2^64, so no wrap-around of B-field element
1338        for i in 0..64 {
1339            assert_eq!(BFieldElement::new(1 << i), two.mod_pow(i));
1340        }
1341    }
1342
1343    #[macro_rules_attr::apply(test)]
1344    fn mod_pow_test_powers_of_three() {
1345        let three = BFieldElement::new(3);
1346        // 3^40 < 2^64, so no wrap-around of B-field element
1347        for i in 0..41 {
1348            assert_eq!(BFieldElement::new(3u64.pow(i as u32)), three.mod_pow(i));
1349        }
1350    }
1351
1352    #[macro_rules_attr::apply(test)]
1353    fn mod_pow_test() {
1354        // These values were found by finding primitive roots of unity and verifying
1355        // that they are group generators of the right order
1356        assert!(BFieldElement::new(281474976710656).mod_pow(4).is_one());
1357        assert_eq!(
1358            BFieldElement::new(281474976710656),
1359            BFieldElement::new(281474976710656).mod_pow(5)
1360        );
1361        assert!(BFieldElement::new(18446744069414584320).mod_pow(2).is_one());
1362        assert!(BFieldElement::new(18446744069397807105).mod_pow(8).is_one());
1363        assert!(BFieldElement::new(2625919085333925275).mod_pow(10).is_one());
1364        assert!(BFieldElement::new(281474976645120).mod_pow(12).is_one());
1365        assert!(BFieldElement::new(0).mod_pow(0).is_one());
1366    }
1367
1368    #[macro_rules_attr::apply(test)]
1369    fn get_primitive_root_of_unity_test() {
1370        for i in 1..33 {
1371            let power = 1 << i;
1372            let root_result = BFieldElement::primitive_root_of_unity(power);
1373            match root_result {
1374                Some(root) => println!("{power} => {root},"),
1375                None => println!("Found no primitive root of unity for n = {power}"),
1376            };
1377            let root = root_result.unwrap();
1378            assert!(root.mod_pow(power).is_one());
1379            assert!(!root.mod_pow(power / 2).is_one());
1380        }
1381    }
1382
1383    #[macro_rules_attr::apply(test)]
1384    #[should_panic(expected = "Attempted to find the multiplicative inverse of zero.")]
1385    fn multiplicative_inverse_of_zero() {
1386        let zero = BFieldElement::ZERO;
1387        let _ = zero.inverse();
1388    }
1389
1390    #[macro_rules_attr::apply(test)]
1391    fn u32_conversion() {
1392        let val = BFieldElement::new(u32::MAX as u64);
1393        let as_u32: u32 = val.try_into().unwrap();
1394        assert_eq!(u32::MAX, as_u32);
1395
1396        for i in 1..100 {
1397            let invalid_val_0 = BFieldElement::new((u32::MAX as u64) + i);
1398            let converted_0 = TryInto::<u32>::try_into(invalid_val_0);
1399            assert!(converted_0.is_err());
1400        }
1401    }
1402
1403    #[macro_rules_attr::apply(test)]
1404    fn inverse_or_zero_bfe() {
1405        let zero = BFieldElement::ZERO;
1406        let one = BFieldElement::ONE;
1407        assert_eq!(zero, zero.inverse_or_zero());
1408
1409        let mut rng = rand::rng();
1410        let elem: BFieldElement = rng.random();
1411        if elem.is_zero() {
1412            assert_eq!(zero, elem.inverse_or_zero())
1413        } else {
1414            assert_eq!(one, elem * elem.inverse_or_zero());
1415        }
1416    }
1417
1418    #[macro_rules_attr::apply(test)]
1419    fn test_random_squares() {
1420        let mut rng = rand::rng();
1421        let p = BFieldElement::P;
1422        for _ in 0..100 {
1423            let a = rng.random_range(0..p);
1424            let asq = (((a as u128) * (a as u128)) % (p as u128)) as u64;
1425            let b = BFieldElement::new(a);
1426            let bsq = BFieldElement::new(asq);
1427            assert_eq!(bsq, b * b);
1428            assert_eq!(bsq.value(), (b * b).value());
1429            assert_eq!(b.value(), a);
1430            assert_eq!(bsq.value(), asq);
1431        }
1432        let one = BFieldElement::new(1);
1433        assert_eq!(one, one * one);
1434    }
1435
1436    #[macro_rules_attr::apply(test)]
1437    fn equals() {
1438        let a = BFieldElement::ONE;
1439        let b = bfe!(BFieldElement::MAX) * bfe!(BFieldElement::MAX);
1440
1441        // elements are equal
1442        assert_eq!(a, b);
1443        assert_eq!(a.value(), b.value());
1444    }
1445
1446    #[macro_rules_attr::apply(test)]
1447    fn test_random_raw() {
1448        let mut rng = rand::rng();
1449        for _ in 0..100 {
1450            let e: BFieldElement = rng.random();
1451            let bytes = e.raw_bytes();
1452            let c = BFieldElement::from_raw_bytes(&bytes);
1453            assert_eq!(e, c);
1454
1455            let mut f = 0u64;
1456            for (i, b) in bytes.iter().enumerate() {
1457                f += (*b as u64) << (8 * i);
1458            }
1459            assert_eq!(e, BFieldElement(f));
1460
1461            let chunks = e.raw_u16s();
1462            let g = BFieldElement::from_raw_u16s(&chunks);
1463            assert_eq!(e, g);
1464
1465            let mut h = 0u64;
1466            for (i, ch) in chunks.iter().enumerate() {
1467                h += (*ch as u64) << (16 * i);
1468            }
1469            assert_eq!(e, BFieldElement(h));
1470        }
1471    }
1472
1473    #[macro_rules_attr::apply(test)]
1474    fn test_fixed_inverse() {
1475        // (8561862112314395584, 17307602810081694772)
1476        let a = BFieldElement::new(8561862112314395584);
1477        let a_inv = a.inverse();
1478        let a_inv_or_0 = a.inverse_or_zero();
1479        let expected = BFieldElement::new(17307602810081694772);
1480        assert_eq!(a_inv, a_inv_or_0);
1481        assert_eq!(a_inv, expected);
1482    }
1483
1484    #[macro_rules_attr::apply(test)]
1485    fn test_fixed_modpow() {
1486        let exponent = 16608971246357572739u64;
1487        let base = BFieldElement::new(7808276826625786800);
1488        let expected = BFieldElement::new(2288673415394035783);
1489        assert_eq!(base.mod_pow_u64(exponent), expected);
1490    }
1491
1492    #[macro_rules_attr::apply(test)]
1493    fn test_fixed_mul() {
1494        {
1495            let a = BFieldElement::new(2779336007265862836);
1496            let b = BFieldElement::new(8146517303801474933);
1497            let c = a * b;
1498            let expected = BFieldElement::new(1857758653037316764);
1499            assert_eq!(c, expected);
1500        }
1501
1502        {
1503            let a = BFieldElement::new(9223372036854775808);
1504            let b = BFieldElement::new(9223372036854775808);
1505            let c = a * b;
1506            let expected = BFieldElement::new(18446744068340842497);
1507            assert_eq!(c, expected);
1508        }
1509    }
1510
1511    #[macro_rules_attr::apply(proptest)]
1512    fn conversion_from_i32_to_bfe_is_correct(v: i32) {
1513        let bfe = BFieldElement::from(v);
1514        match v {
1515            0.. => prop_assert_eq!(u64::try_from(v)?, bfe.value()),
1516            _ => prop_assert_eq!(u64::try_from(-v)?, BFieldElement::P - bfe.value()),
1517        }
1518    }
1519
1520    #[macro_rules_attr::apply(proptest)]
1521    fn conversion_from_isize_to_bfe_is_correct(v: isize) {
1522        let bfe = BFieldElement::from(v);
1523        match v {
1524            0.. => prop_assert_eq!(u64::try_from(v)?, bfe.value()),
1525            _ => prop_assert_eq!(u64::try_from(-v)?, BFieldElement::P - bfe.value()),
1526        }
1527    }
1528
1529    #[macro_rules_attr::apply(test)]
1530    fn bfield_element_can_be_converted_to_and_from_many_types() {
1531        let _ = BFieldElement::from(0_u8);
1532        let _ = BFieldElement::from(0_u16);
1533        let _ = BFieldElement::from(0_u32);
1534        let _ = BFieldElement::from(0_u64);
1535        let _ = BFieldElement::from(0_u128);
1536        let _ = BFieldElement::from(0_usize);
1537
1538        let max = bfe!(BFieldElement::MAX);
1539        assert_eq!(max, BFieldElement::from(-1_i8));
1540        assert_eq!(max, BFieldElement::from(-1_i16));
1541        assert_eq!(max, BFieldElement::from(-1_i32));
1542        assert_eq!(max, BFieldElement::from(-1_i64));
1543        assert_eq!(max, BFieldElement::from(-1_isize));
1544
1545        assert!(u8::try_from(BFieldElement::ZERO).is_ok());
1546        assert!(i8::try_from(BFieldElement::ZERO).is_ok());
1547        assert!(u16::try_from(BFieldElement::ZERO).is_ok());
1548        assert!(i16::try_from(BFieldElement::ZERO).is_ok());
1549        assert!(u32::try_from(BFieldElement::ZERO).is_ok());
1550        assert!(i32::try_from(BFieldElement::ZERO).is_ok());
1551        assert!(usize::try_from(BFieldElement::ZERO).is_ok());
1552        assert!(isize::try_from(BFieldElement::ZERO).is_ok());
1553
1554        let _ = u64::from(max);
1555        let _ = i64::from(max);
1556        let _ = u128::from(max);
1557        let _ = i128::from(max);
1558    }
1559
1560    #[macro_rules_attr::apply(test)]
1561    fn bfield_conversion_works_for_types_min_and_max() {
1562        let _ = BFieldElement::from(u8::MIN);
1563        let _ = BFieldElement::from(u8::MAX);
1564        let _ = BFieldElement::from(u16::MIN);
1565        let _ = BFieldElement::from(u16::MAX);
1566        let _ = BFieldElement::from(u32::MIN);
1567        let _ = BFieldElement::from(u32::MAX);
1568        let _ = BFieldElement::from(u64::MIN);
1569        let _ = BFieldElement::from(u64::MAX);
1570        let _ = BFieldElement::from(u128::MIN);
1571        let _ = BFieldElement::from(u128::MAX);
1572        let _ = BFieldElement::from(usize::MIN);
1573        let _ = BFieldElement::from(usize::MAX);
1574        let _ = BFieldElement::from(i8::MIN);
1575        let _ = BFieldElement::from(i8::MAX);
1576        let _ = BFieldElement::from(i16::MIN);
1577        let _ = BFieldElement::from(i16::MAX);
1578        let _ = BFieldElement::from(i32::MIN);
1579        let _ = BFieldElement::from(i32::MAX);
1580        let _ = BFieldElement::from(i64::MIN);
1581        let _ = BFieldElement::from(i64::MAX);
1582        let _ = BFieldElement::from(isize::MIN);
1583        let _ = BFieldElement::from(isize::MAX);
1584    }
1585
1586    #[macro_rules_attr::apply(proptest)]
1587    fn naive_and_actual_conversion_from_u128_agree(v: u128) {
1588        fn naive_conversion(x: u128) -> BFieldElement {
1589            let p = BFieldElement::P as u128;
1590            let value = (x % p) as u64;
1591            BFieldElement::new(value)
1592        }
1593
1594        prop_assert_eq!(naive_conversion(v), BFieldElement::from(v));
1595    }
1596
1597    #[macro_rules_attr::apply(proptest)]
1598    fn naive_and_actual_conversion_from_i64_agree(v: i64) {
1599        fn naive_conversion(x: i64) -> BFieldElement {
1600            let p = BFieldElement::P as i128;
1601            let value = i128::from(x).rem_euclid(p) as u64;
1602            BFieldElement::new(value)
1603        }
1604
1605        prop_assert_eq!(naive_conversion(v), BFieldElement::from(v));
1606    }
1607
1608    #[macro_rules_attr::apply(test)]
1609    fn bfe_macro_can_be_used() {
1610        let b = bfe!(42);
1611        let _ = bfe!(42u32);
1612        let _ = bfe!(-1);
1613        let _ = bfe!(b);
1614        let _ = bfe!(b.0);
1615        let _ = bfe!(42_usize);
1616        let _ = bfe!(-2_isize);
1617
1618        let c: Vec<BFieldElement> = bfe_vec![1, 2, 3];
1619        let d: [BFieldElement; 3] = bfe_array![1, 2, 3];
1620        assert_eq!(c, d);
1621    }
1622
1623    #[macro_rules_attr::apply(proptest)]
1624    fn bfe_macro_produces_same_result_as_calling_new(value: u64) {
1625        prop_assert_eq!(BFieldElement::new(value), bfe!(value));
1626    }
1627
1628    #[macro_rules_attr::apply(test)]
1629    fn const_minus_two_inverse_is_really_minus_two_inverse() {
1630        assert_eq!(bfe!(-2).inverse(), BFieldElement::MINUS_TWO_INVERSE);
1631    }
1632}