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