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#[derive(Copy, Clone, Default, Hash, PartialEq, Eq, GetSize)]
85#[repr(transparent)]
86pub struct BFieldElement(u64);
87
88#[macro_export]
103macro_rules! bfe {
104 ($value:expr) => {
105 BFieldElement::from($value)
106 };
107}
108
109#[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#[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 pub const P: u64 = 0xffff_ffff_0000_0001;
226 pub const MAX: u64 = Self::P - 1;
227
228 const R2: u64 = 0xffff_fffe_0000_0001;
230
231 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 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 #[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 pub const fn generator() -> Self {
313 BFieldElement::new(7)
314 }
315
316 #[inline]
319 pub const fn lift(&self) -> XFieldElement {
320 XFieldElement::new_const(*self)
321 }
322
323 pub fn increment(&mut self) {
325 *self += Self::ONE;
326 }
327
328 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 #[inline(always)]
357 pub const fn montyred(x: u128) -> u64 {
358 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 r.wrapping_sub((1 + !Self::P) * c as u64)
370 }
371
372 pub const fn raw_bytes(&self) -> [u8; 8] {
375 self.0.to_le_bytes()
376 }
377
378 pub const fn from_raw_bytes(bytes: &[u8; 8]) -> Self {
382 Self(u64::from_le_bytes(*bytes))
383 }
384
385 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 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 #[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 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 let tmp2 = (x_hi_lo << 32) - x_hi_lo;
489
490 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 #[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
613impl From<BFieldElement> for [u8; BFieldElement::BYTES] {
616 fn from(bfe: BFieldElement) -> Self {
617 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 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 let (x1, c1) = self.0.overflowing_sub(Self::P - rhs.0);
722
723 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 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
809impl 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 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 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 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 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 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 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 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 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 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 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 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 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}