Skip to main content

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