1use alloc::vec::Vec;
14use core::fmt::{self, Debug, Display, Formatter};
15use core::iter::{Product, Sum};
16use core::mem::ManuallyDrop;
17use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
18
19use num_bigint::BigUint;
20use p3_field::op_assign_macros::{
21 impl_add_assign, impl_add_base_field, impl_div_methods, impl_mul_methods, impl_sub_assign,
22 impl_sub_base_field, ring_sum,
23};
24use p3_field::{Algebra, Field, Packable, PrimeCharacteristicRing, RawDataSerializable};
25use rand::Rng;
26use rand::distr::{Distribution, StandardUniform};
27use serde::de::Error;
28use serde::{Deserialize, Deserializer, Serialize};
29
30use crate::clmul::{HAS_HARDWARE_CLMUL, mul_64, mul_128};
31use crate::gf2::characteristic_two_methods;
32use crate::{Gf2, tables};
33
34pub(crate) mod private {
41 pub trait Sealed {}
42}
43
44pub trait TowerLevel: Field + private::Sealed {
53 type Repr: Copy;
55
56 const LOG_BITS: usize;
58 fn from_repr(r: Self::Repr) -> Self;
60 fn to_repr(self) -> Self::Repr;
62 fn mul_alpha(self) -> Self;
64 fn from_le_byte_iter(bytes: impl Iterator<Item = u8>) -> Self;
70 fn cantor_basis(i: usize) -> Self;
75}
76
77const BYTE_STREAM_ENDED: &str = "byte stream ended before a whole element was read";
79
80impl private::Sealed for Gf2 {}
81
82impl TowerLevel for Gf2 {
83 type Repr = u8;
84
85 const LOG_BITS: usize = 0;
86
87 #[inline]
88 fn from_repr(r: Self::Repr) -> Self {
89 Self::from_bool((r & 1) == 1)
90 }
91
92 #[inline]
93 fn to_repr(self) -> Self::Repr {
94 u8::from(self.is_one())
95 }
96
97 #[inline]
99 fn mul_alpha(self) -> Self {
100 self
101 }
102
103 #[inline]
104 fn from_le_byte_iter(mut bytes: impl Iterator<Item = u8>) -> Self {
105 Self::from_le_bytes([bytes.next().expect(BYTE_STREAM_ENDED)])
106 }
107
108 #[inline]
110 fn cantor_basis(i: usize) -> Self {
111 assert!(i < 1, "Cantor basis index out of range");
112 Self::ONE
113 }
114}
115
116macro_rules! binary_tower_level {
122 ($name:ident, $bits:literal, $repr:ty, $lower:ty, $lower_repr:ty, $generator:literal, $mul:ident, $square:ident, $try_inverse:ident) => {
123 #[doc = concat!("The binary tower field `GF(2^", stringify!($bits), ")`.")]
124 #[doc = concat!("A quadratic extension of [`", stringify!($lower), "`] generated by a root `X` of")]
126 #[derive(Copy, Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
135 #[serde(transparent)]
136 #[repr(transparent)]
137 #[must_use]
138 pub struct $name($repr);
139
140 impl $name {
141 pub(crate) const BITS: usize = $bits;
143
144 const MASK: $repr = <$repr>::MAX >> (<$repr>::BITS as usize - $bits);
146
147 const HALF_BITS: usize = $bits / 2;
149
150 const HALF_MASK: $repr = Self::MASK >> Self::HALF_BITS;
152
153 #[inline]
155 pub(crate) fn split(self) -> ($lower, $lower) {
156 let a0 = (self.0 & Self::HALF_MASK) as $lower_repr;
157 let a1 = (self.0 >> Self::HALF_BITS) as $lower_repr;
158 (<$lower>::from_repr(a0), <$lower>::from_repr(a1))
159 }
160
161 #[inline]
163 pub(crate) fn join(a0: $lower, a1: $lower) -> Self {
164 Self((a0.to_repr() as $repr) | ((a1.to_repr() as $repr) << Self::HALF_BITS))
165 }
166
167 #[doc(hidden)]
176 #[inline]
177 pub fn reference_mul(self, rhs: Self) -> Self {
178 let (a0, a1) = self.split();
179 let (b0, b1) = rhs.split();
180 let z0 = a0.reference_mul(b0);
181 let z2 = a1.reference_mul(b1);
182 let z1 = (a0 + a1).reference_mul(b0 + b1) + z0 + z2;
183 Self::join(z0 + z2, z1 + z2.mul_alpha())
184 }
185
186 #[allow(dead_code)]
193 #[inline]
194 fn reference_square(self) -> Self {
195 let (a0, a1) = self.split();
196 let a0_sq = a0.square();
197 let a1_sq = a1.square();
198 Self::join(a0_sq + a1_sq, a1_sq.mul_alpha())
199 }
200
201 #[allow(dead_code)]
209 #[inline]
210 fn reference_try_inverse(self) -> Option<Self> {
211 if self.0 == 0 {
212 return None;
213 }
214 let (a0, a1) = self.split();
215 let norm = a0.square() + (a0 * a1).mul_alpha() + a1.square();
216 let norm_inv = norm
217 .try_inverse()
218 .expect("the norm of a nonzero element is nonzero");
219 if HAS_HARDWARE_CLMUL && Self::BITS == 128 {
220 let (lo, hi) = crate::clmul::mul_pair_64(
221 (a0 + a1.mul_alpha()).to_repr() as u64,
222 a1.to_repr() as u64,
223 norm_inv.to_repr() as u64,
224 );
225 return Some(Self::from_repr(lo as $repr | ((hi as $repr) << (Self::BITS / 2))));
226 }
227 Some(Self::join((a0 + a1.mul_alpha()) * norm_inv, a1 * norm_inv))
228 }
229
230 #[inline]
235 pub fn from_le_bytes(bytes: [u8; core::mem::size_of::<$repr>()]) -> Self {
236 <Self as TowerLevel>::from_repr(<$repr>::from_le_bytes(bytes))
237 }
238 }
239
240 impl private::Sealed for $name {}
241
242 impl TowerLevel for $name {
243 type Repr = $repr;
244
245 const LOG_BITS: usize = Self::BITS.trailing_zeros() as usize;
246
247 #[inline]
248 fn from_repr(r: Self::Repr) -> Self {
249 Self(r & Self::MASK)
250 }
251
252 #[inline]
253 fn to_repr(self) -> Self::Repr {
254 self.0
255 }
256
257 #[inline]
259 fn mul_alpha(self) -> Self {
260 let (c0, c1) = self.split();
261 Self::join(c1, c0 + c1.mul_alpha())
262 }
263
264 #[inline]
265 fn from_le_byte_iter(mut bytes: impl Iterator<Item = u8>) -> Self {
266 let mut buffer = [0u8; core::mem::size_of::<$repr>()];
267 for byte in &mut buffer {
268 *byte = bytes.next().expect(BYTE_STREAM_ENDED);
269 }
270 Self::from_le_bytes(buffer)
271 }
272
273 #[inline]
274 fn cantor_basis(i: usize) -> Self {
275 assert!(i < $bits, "Cantor basis index out of range");
276 Self::from_repr(crate::cantor::CANTOR_BASIS_128[i] as $repr)
278 }
279 }
280
281 impl<'de> Deserialize<'de> for $name {
282 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
283 let val = <$repr>::deserialize(d)?;
284 if val <= Self::MASK {
287 Ok(Self(val))
288 } else {
289 Err(D::Error::custom("Value is out of range"))
290 }
291 }
292 }
293
294 impl Packable for $name {}
295
296 impl Display for $name {
297 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
298 Display::fmt(&self.0, f)
299 }
300 }
301
302 impl Debug for $name {
303 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
304 Debug::fmt(&self.0, f)
305 }
306 }
307
308 impl Distribution<$name> for StandardUniform {
309 #[inline]
310 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $name {
311 let mut bytes = [0u8; core::mem::size_of::<$repr>()];
312 rng.fill_bytes(&mut bytes);
313 <$name>::from_repr(<$repr>::from_le_bytes(bytes))
314 }
315 }
316
317 impl PrimeCharacteristicRing for $name {
318 type PrimeSubfield = Gf2;
319
320 const ZERO: Self = Self(0);
321 const ONE: Self = Self(1);
322 const TWO: Self = Self(0);
324 const NEG_ONE: Self = Self(1);
326
327 #[inline]
328 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
329 Self::from_bool(f.is_one())
330 }
331
332 #[inline]
333 fn from_bool(b: bool) -> Self {
334 Self(<$repr>::from(b))
335 }
336
337 characteristic_two_methods!();
338
339 #[inline]
340 fn square(&self) -> Self {
341 if Self::BITS >= 16 {
342 Self::from_repr(match Self::BITS {
343 16 => crate::linear::square_16(self.0 as u16) as $repr,
344 32 => BinaryField32::from_repr(self.0 as u32).byte_square().to_repr() as $repr,
345 64 => crate::linear::square_64(self.0 as u64) as $repr,
346 128 => crate::linear::square_128(self.0 as u128) as $repr,
347 _ => unreachable!(),
348 })
349 } else {
350 self.$square()
351 }
352 }
353
354 #[inline]
355 fn exp_power_of_2(&self, power_log: usize) -> Self {
356 let mut power = power_log % Self::BITS;
357 let mut value = *self;
358 if power >= Self::BITS / 2 {
360 let (lo, hi) = value.split();
361 value = Self::join(lo + hi.mul_alpha(), hi);
362 power -= Self::BITS / 2;
363 }
364 if power == 1 {
365 return value.square();
366 }
367 if Self::BITS >= 16 {
368 Self::from_repr(match Self::BITS {
369 16 => crate::linear::frobenius_16(value.0 as u16, power) as $repr,
370 32 => crate::linear::frobenius_32(value.0 as u32, power) as $repr,
371 64 => crate::linear::frobenius_64(value.0 as u64, power) as $repr,
372 128 => crate::linear::frobenius_128(value.0 as u128, power) as $repr,
373 _ => unreachable!(),
374 })
375 } else {
376 for _ in 0..power { value = value.square(); }
377 value
378 }
379 }
380
381 #[inline]
382 fn dot_product<const N: usize>(u: &[Self; N], v: &[Self; N]) -> Self {
383 if N == 0 { return Self::ZERO; }
384 if N == 1 { return u[0] * v[0]; }
385 if HAS_HARDWARE_CLMUL && Self::BITS == 32 {
386 Self::from_repr(crate::clmul::dot_product_32(
387 u.iter().zip(v).map(|(a, b)| (a.0 as u32, b.0 as u32)),
388 ) as $repr)
389 } else if HAS_HARDWARE_CLMUL && Self::BITS == 64 {
390 Self::from_repr(crate::clmul::dot_product_64(
391 u.iter().zip(v).map(|(a, b)| (a.0 as u64, b.0 as u64)),
392 ) as $repr)
393 } else if HAS_HARDWARE_CLMUL && Self::BITS == 128 {
394 Self::from_repr(crate::clmul::dot_product_128(
395 u.iter().zip(v).map(|(a, b)| (a.0 as u128, b.0 as u128)),
396 ) as $repr)
397 } else {
398 u.iter().zip(v).map(|(&a, &b)| a * b).sum()
399 }
400 }
401
402 #[inline]
403 fn zero_vec(len: usize) -> Vec<Self> {
404 let mut values = ManuallyDrop::new(alloc::vec![0 as $repr; len]);
405 unsafe {
408 Vec::from_raw_parts(values.as_mut_ptr().cast(), values.len(), values.capacity())
409 }
410 }
411
412 #[inline]
416 fn bool_check(&self) -> Self {
417 self.square() + *self
418 }
419 }
420
421 impl Field for $name {
422 type Packing = Self;
423
424 const GENERATOR: Self = Self($generator);
425
426 #[inline]
427 fn try_inverse(&self) -> Option<Self> {
428 self.$try_inverse()
429 }
430
431 #[inline]
432 fn try_sqrt(&self) -> Option<Self> {
433 if Self::BITS >= 16 {
435 Some(Self::from_repr(match Self::BITS {
436 16 => crate::linear::sqrt_16(self.0 as u16) as $repr,
437 32 => crate::linear::sqrt_32(self.0 as u32) as $repr,
438 64 => crate::linear::sqrt_64(self.0 as u64) as $repr,
439 128 => crate::linear::sqrt_128(self.0 as u128) as $repr,
440 _ => unreachable!(),
441 }))
442 } else {
443 Some(self.exp_power_of_2(Self::BITS - 1))
444 }
445 }
446
447 #[inline]
448 fn order() -> BigUint {
449 BigUint::from(1u8) << (1usize << <Self as TowerLevel>::LOG_BITS)
450 }
451
452 #[inline]
460 fn interpolation_node(i: usize) -> Self {
461 assert!(
462 usize::BITS as usize <= Self::BITS || i < (1usize << Self::BITS),
463 "interpolation node index out of range"
464 );
465 Self::from_repr(i as $repr)
466 }
467
468 #[inline]
470 fn bits() -> usize {
471 Self::BITS
472 }
473 }
474
475 impl RawDataSerializable for $name {
476 const NUM_BYTES: usize = core::mem::size_of::<$repr>();
477
478 #[allow(refining_impl_trait)]
479 #[inline]
480 fn into_bytes(self) -> [u8; core::mem::size_of::<$repr>()] {
481 self.0.to_le_bytes()
482 }
483
484 #[inline]
485 fn into_parallel_byte_streams<const N: usize>(
486 input: impl IntoIterator<Item = [Self; N]>,
487 ) -> impl IntoIterator<Item = [u8; N]> {
488 input.into_iter().flat_map(|vector| {
489 let bytes = vector.map(Self::into_bytes);
490 (0..Self::NUM_BYTES).map(move |i| core::array::from_fn(|j| bytes[j][i]))
491 })
492 }
493
494 #[inline]
495 fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
496 Self::into_parallel_u64_streams(input.into_iter().map(|elem| [elem]))
497 .into_iter()
498 .map(|[word]| word)
499 }
500
501 #[inline]
502 fn into_parallel_u64_streams<const N: usize>(
503 input: impl IntoIterator<Item = [Self; N]>,
504 ) -> impl IntoIterator<Item = [u64; N]> {
505 let mut input = input.into_iter();
509 let mut high: Option<[u64; N]> = None;
510 core::iter::from_fn(move || {
511 if let Some(word) = high.take() {
512 return Some(word);
513 }
514 let first = input.next()?;
515 if Self::NUM_BYTES >= 8 {
516 let wide = first.map(|elem| elem.0 as u128);
517 if Self::NUM_BYTES == 16 {
518 high = Some(wide.map(|value| (value >> 64) as u64));
519 }
520 return Some(wide.map(|value| value as u64));
521 }
522 let bits = 8 * Self::NUM_BYTES;
523 let mut word = first.map(|elem| elem.0 as u64);
524 let mut shift = bits;
525 while shift < 64 {
526 let Some(next) = input.next() else { break };
527 for (lane, elem) in word.iter_mut().zip(next) {
528 *lane |= (elem.0 as u64) << shift;
529 }
530 shift += bits;
531 }
532 Some(word)
533 })
534 }
535 }
536
537 impl Add for $name {
538 type Output = Self;
539
540 #[inline]
541 #[allow(clippy::suspicious_arithmetic_impl)]
542 fn add(self, rhs: Self) -> Self {
543 Self(self.0 ^ rhs.0)
545 }
546 }
547
548 impl Sub for $name {
549 type Output = Self;
550
551 #[inline]
552 #[allow(clippy::suspicious_arithmetic_impl)]
553 fn sub(self, rhs: Self) -> Self {
554 self + rhs
556 }
557 }
558
559 impl Neg for $name {
560 type Output = Self;
561
562 #[inline]
563 fn neg(self) -> Self::Output {
564 self
566 }
567 }
568
569 impl Mul for $name {
570 type Output = Self;
571
572 #[inline]
573 fn mul(self, rhs: Self) -> Self {
574 self.$mul(rhs)
575 }
576 }
577
578 impl_add_assign!($name);
579 impl_sub_assign!($name);
580 impl_mul_methods!($name);
581 impl_div_methods!($name, $name);
582 ring_sum!($name);
583
584 impl From<Gf2> for $name {
585 #[inline]
587 fn from(x: Gf2) -> Self {
588 Self::from_prime_subfield(x)
589 }
590 }
591
592 impl_add_base_field!($name, Gf2);
593 impl_sub_base_field!($name, Gf2);
594 impl Mul<Gf2> for $name {
595 type Output = Self;
596
597 #[inline]
598 #[allow(clippy::suspicious_arithmetic_impl)]
599 fn mul(self, rhs: Gf2) -> Self {
600 Self(self.0 & (0 as $repr).wrapping_sub(rhs.to_repr() as $repr))
601 }
602 }
603
604 impl Mul<$name> for Gf2 {
605 type Output = $name;
606
607 #[inline]
608 fn mul(self, rhs: $name) -> $name {
609 rhs * self
610 }
611 }
612
613 impl Algebra<Gf2> for $name {}
614 };
615}
616
617binary_tower_level!(
618 BinaryField2,
619 2,
620 u8,
621 Gf2,
622 u8,
623 2,
624 reference_mul,
625 reference_square,
626 reference_try_inverse
627);
628binary_tower_level!(
629 BinaryField4,
630 4,
631 u8,
632 BinaryField2,
633 u8,
634 5,
635 reference_mul,
636 reference_square,
637 reference_try_inverse
638);
639binary_tower_level!(
640 BinaryField8,
641 8,
642 u8,
643 BinaryField4,
644 u8,
645 19,
646 table_mul,
647 table_square,
648 table_try_inverse
649);
650binary_tower_level!(
651 BinaryField16,
652 16,
653 u16,
654 BinaryField8,
655 u8,
656 258,
657 karatsuba_mul,
658 reference_square,
659 reference_try_inverse
660);
661binary_tower_level!(
662 BinaryField32,
663 32,
664 u32,
665 BinaryField16,
666 u16,
667 65541,
668 karatsuba_mul,
669 reference_square,
670 reference_try_inverse
671);
672binary_tower_level!(
673 BinaryField64,
674 64,
675 u64,
676 BinaryField32,
677 u32,
678 4294967300,
679 dispatched_mul,
680 table_square,
681 reference_try_inverse
682);
683binary_tower_level!(
684 BinaryField128,
685 128,
686 u128,
687 BinaryField64,
688 u64,
689 18446744073709551621,
690 dispatched_mul,
691 table_square,
692 reference_try_inverse
693);
694
695impl BinaryField8 {
696 #[inline]
698 const fn table_mul(self, rhs: Self) -> Self {
699 Self(tables::mul(self.0, rhs.0))
700 }
701
702 #[inline]
704 const fn table_square(self) -> Self {
705 Self(tables::square(self.0))
706 }
707
708 #[inline]
710 const fn table_try_inverse(self) -> Option<Self> {
711 match tables::try_inverse(self.0) {
712 Some(inverse) => Some(Self(inverse)),
713 None => None,
714 }
715 }
716}
717
718impl BinaryField32 {
719 #[inline]
721 fn byte_square(self) -> Self {
722 let (a0, a1) = self.split();
723 let a0_sq = a0.reference_square();
724 let a1_sq = a1.reference_square();
725 Self::join(a0_sq + a1_sq, a1_sq.mul_alpha())
726 }
727}
728
729macro_rules! karatsuba_over_the_level_below {
735 ($name:ident) => {
736 impl $name {
737 #[inline]
742 fn karatsuba_mul(self, rhs: Self) -> Self {
743 let (a0, a1) = self.split();
744 let (b0, b1) = rhs.split();
745 let z0 = a0 * b0;
746 let z2 = a1 * b1;
747 let z1 = (a0 + a1) * (b0 + b1) + z0 + z2;
748 Self::join(z0 + z2, z1 + z2.mul_alpha())
749 }
750 }
751 };
752}
753
754karatsuba_over_the_level_below!(BinaryField16);
755karatsuba_over_the_level_below!(BinaryField32);
756karatsuba_over_the_level_below!(BinaryField64);
757karatsuba_over_the_level_below!(BinaryField128);
758
759impl BinaryField64 {
760 #[inline]
765 fn dispatched_mul(self, rhs: Self) -> Self {
766 if HAS_HARDWARE_CLMUL {
767 Self(mul_64(self.0, rhs.0))
768 } else {
769 self.karatsuba_mul(rhs)
770 }
771 }
772
773 #[inline]
775 fn table_square(self) -> Self {
776 Self(crate::clmul::square_64(self.0))
777 }
778}
779
780impl BinaryField128 {
781 #[inline]
786 fn dispatched_mul(self, rhs: Self) -> Self {
787 if HAS_HARDWARE_CLMUL {
788 Self(mul_128(self.0, rhs.0))
789 } else {
790 self.karatsuba_mul(rhs)
791 }
792 }
793
794 #[inline]
796 fn table_square(self) -> Self {
797 Self(crate::clmul::square_128(self.0))
798 }
799}
800
801#[cfg(test)]
802mod tests {
803 extern crate std;
804
805 use std::println;
806 use std::vec::Vec;
807
808 use p3_field::{Field, PrimeCharacteristicRing, RawDataSerializable};
809 use proptest::prelude::*;
810
811 use super::*;
812
813 #[test]
814 fn zero_vectors_preserve_layout_and_support_growth() {
815 macro_rules! check {
816 ($field:ty) => {
817 for len in [0, 1, 33, 1024] {
818 let mut values = <$field>::zero_vec(len);
819 assert_eq!(values.len(), len);
820 assert!(values.iter().all(|x| *x == <$field>::ZERO));
821 values.push(<$field>::ONE);
822 values.reserve(100);
823 assert_eq!(values.pop(), Some(<$field>::ONE));
824 }
825 };
826 }
827 check!(BinaryField2);
828 check!(BinaryField4);
829 check!(BinaryField8);
830 check!(BinaryField16);
831 check!(BinaryField32);
832 check!(BinaryField64);
833 check!(BinaryField128);
834 }
835
836 #[test]
837 fn fused_dot_products_match_reference_for_arbitrary_lengths() {
838 fn check<const N: usize>() {
839 let u: [BinaryField128; N] = core::array::from_fn(|i| {
840 BinaryField128::from_repr(
841 (i as u128 + 1).wrapping_mul(0xfeed_dead_beef_9876_0123_4567_cafe_dcba),
842 )
843 });
844 let v = core::array::from_fn(|i| u[N - 1 - i] + BinaryField128::ONE);
845 let expected = u
846 .iter()
847 .zip(&v)
848 .map(|(&a, &b)| a.reference_mul(b))
849 .sum::<BinaryField128>();
850 assert_eq!(BinaryField128::dot_product(&u, &v), expected);
851 let u32 = u.map(|x| BinaryField32::from_repr(x.to_repr() as u32));
852 let v32 = v.map(|x| BinaryField32::from_repr(x.to_repr() as u32));
853 assert_eq!(
854 BinaryField32::dot_product(&u32, &v32),
855 u32.iter()
856 .zip(&v32)
857 .map(|(&a, &b)| a.reference_mul(b))
858 .sum()
859 );
860 let u = u.map(|x| BinaryField64::from_repr(x.to_repr() as u64));
861 let v = v.map(|x| BinaryField64::from_repr(x.to_repr() as u64));
862 assert_eq!(
863 BinaryField64::dot_product(&u, &v),
864 u.iter().zip(&v).map(|(&a, &b)| a.reference_mul(b)).sum()
865 );
866 }
867 check::<0>();
868 check::<1>();
869 check::<2>();
870 check::<3>();
871 check::<7>();
872 check::<16>();
873 check::<33>();
874 check::<128>();
875 }
876
877 #[test]
878 fn prime_subfield_scaling_is_selection() {
879 macro_rules! check {
880 ($field:ty, $value:expr) => {{
881 let x = <$field>::from_repr($value);
882 assert_eq!(x * Gf2::ZERO, <$field>::ZERO);
883 assert_eq!(Gf2::ZERO * x, <$field>::ZERO);
884 assert_eq!(x * Gf2::ONE, x);
885 assert_eq!(Gf2::ONE * x, x);
886 }};
887 }
888 check!(BinaryField2, 3);
889 check!(BinaryField4, 15);
890 check!(BinaryField8, 255);
891 check!(BinaryField16, 0xdead);
892 check!(BinaryField32, 0xdead_beef);
893 check!(BinaryField64, 0xdead_beef_cafe_8765);
894 check!(BinaryField128, 0xdead_beef_cafe_8765_0123_4567_89ab_cdef);
895 }
896
897 const FACTORS_2: [u128; 1] = [3];
899 const FACTORS_4: [u128; 2] = [3, 5];
900 const FACTORS_8: [u128; 3] = [3, 5, 17];
901 const FACTORS_16: [u128; 4] = [3, 5, 17, 257];
902 const FACTORS_32: [u128; 5] = [3, 5, 17, 257, 65537];
903 const FACTORS_64: [u128; 7] = [3, 5, 17, 257, 641, 65537, 6700417];
904 const FACTORS_128: [u128; 9] = [3, 5, 17, 257, 641, 65537, 274177, 6700417, 67280421310721];
905
906 const fn group_order(bits: u32) -> u128 {
908 if bits == 128 {
909 u128::MAX
910 } else {
911 (1u128 << bits) - 1
912 }
913 }
914
915 fn pow_u128<F: Field>(base: F, mut exp: u128) -> F {
917 let mut acc = F::ONE;
918 let mut cur = base;
919 while exp != 0 {
920 if exp & 1 == 1 {
921 acc *= cur;
922 }
923 cur = cur.square();
924 exp >>= 1;
925 }
926 acc
927 }
928
929 fn has_full_order<F: Field>(g: F, bits: u32, factors: &[u128]) -> bool {
934 let order = group_order(bits);
935 factors.iter().all(|&q| pow_u128(g, order / q) != F::ONE)
936 }
937
938 macro_rules! assert_full_order {
939 ($t:ty, $bits:expr, $factors:expr) => {
940 assert!(
941 has_full_order(<$t>::GENERATOR, $bits, &$factors),
942 concat!(
943 stringify!($t),
944 "::GENERATOR does not generate the multiplicative group"
945 )
946 );
947 };
948 }
949
950 macro_rules! assert_defining_relation {
951 ($t:ty, $repr:ty, $bits:expr) => {{
952 let x = <$t>::from_repr((1 as $repr) << ($bits / 2));
956 let alpha = <$t>::from_repr((1 as $repr) << ($bits / 4));
957 assert_eq!(
958 x.square(),
959 alpha * x + <$t>::ONE,
960 concat!(stringify!($t), " does not satisfy X^2 = alpha*X + 1")
961 );
962 }};
963 }
964
965 macro_rules! search_generator {
966 ($t:ty, $repr:ty, $bits:expr, $factors:expr) => {{
967 let start = 1u128 << ($bits / 2);
970 let found = (start..start + 1024)
971 .map(|cand| (cand, <$t>::from_repr(cand as $repr)))
972 .find(|&(_, g)| has_full_order(g, $bits, &$factors));
973 println!(
974 "{}: GENERATOR = {:?}",
975 stringify!($t),
976 found.map(|(cand, _)| cand)
977 );
978 }};
979 }
980
981 #[test]
982 fn gf4_multiplication_table() {
983 let x = BinaryField2::from_repr(2);
985 assert_eq!(x * x, x + BinaryField2::ONE); assert_eq!(x * (x + BinaryField2::ONE), BinaryField2::ONE); assert_eq!(x.inverse(), x + BinaryField2::ONE);
988 }
989
990 #[test]
991 fn frobenius_fixes_every_element_of_each_level() {
992 for r in 0..=u8::MAX {
993 let a = BinaryField8::from_repr(r);
994 assert_eq!(a.exp_power_of_2(8), a); }
996 for r in 0..=u8::MAX {
997 let a = BinaryField4::from_repr(r & 0x0f);
998 assert_eq!(a.exp_power_of_2(4), a); }
1000 }
1001
1002 #[test]
1005 fn the_table_square_agrees_with_the_recursive_squaring_on_gf256() {
1006 for r in 0..=u8::MAX {
1007 let a = BinaryField8::from_repr(r);
1008 assert_eq!(a.table_square(), a.reference_square(), "square({r})");
1009 }
1010 }
1011
1012 #[test]
1015 fn the_table_inverse_agrees_with_the_recursive_inverse_on_gf256() {
1016 for r in 0..=u8::MAX {
1017 let a = BinaryField8::from_repr(r);
1018 assert_eq!(
1019 a.table_try_inverse(),
1020 a.reference_try_inverse(),
1021 "inverse({r})"
1022 );
1023 }
1024 }
1025
1026 #[test]
1029 fn karatsuba_agrees_with_the_recursive_product_over_every_gf16_operand() {
1030 let others = [0u16, 1, 2, 0x00ff, 0x0100, 0x1234, 0xfffe, 0xffff];
1031 for r in 0..=u16::MAX {
1032 let a = BinaryField16::from_repr(r);
1033 for other in others {
1034 let b = BinaryField16::from_repr(other);
1035 assert_eq!(a.karatsuba_mul(b), a.reference_mul(b), "mul({r}, {other})");
1036 }
1037 }
1038 }
1039
1040 #[test]
1041 fn inverse_agrees_with_fermat_on_gf256() {
1042 for r in 1..=u8::MAX {
1043 let a = BinaryField8::from_repr(r);
1044 assert_eq!(a.inverse(), a.exp_u64(254));
1045 assert_eq!(a * a.inverse(), BinaryField8::ONE);
1046 }
1047 }
1048
1049 #[test]
1050 fn square_roots_square_back_to_the_input() {
1051 for r in 0..=u8::MAX {
1052 let a = BinaryField8::from_repr(r);
1053 assert_eq!(a.try_sqrt().unwrap().square(), a);
1054 }
1055 let a = BinaryField128::from_repr(0x0123_4567_89ab_cdef_fedc_ba98_7654_3210);
1056 assert_eq!(a.try_sqrt().unwrap().square(), a);
1057 }
1058
1059 #[test]
1063 fn serde_round_trip_rejects_non_canonical_encodings() {
1064 assert_eq!(
1065 serde_json::to_string(&BinaryField4::from_repr(9)).unwrap(),
1066 "9"
1067 );
1068 assert_eq!(
1069 serde_json::from_str::<BinaryField4>("9").unwrap(),
1070 BinaryField4::from_repr(9)
1071 );
1072
1073 assert!(serde_json::from_str::<BinaryField2>("3").is_ok());
1076 assert!(serde_json::from_str::<BinaryField2>("4").is_err());
1077 assert!(serde_json::from_str::<BinaryField4>("15").is_ok());
1078 assert!(serde_json::from_str::<BinaryField4>("16").is_err());
1079
1080 assert!(serde_json::from_str::<BinaryField8>("255").is_ok());
1082 assert!(serde_json::from_str::<BinaryField8>("256").is_err());
1083 }
1084
1085 #[test]
1086 fn bytes_round_trip_and_postcard() {
1087 let a = BinaryField128::from_repr(0x8000_0000_0000_0000_0000_0000_0000_0001);
1088 let bytes: Vec<u8> = a.into_bytes().into_iter().collect();
1089 assert_eq!(bytes.len(), 16);
1090 assert_eq!(BinaryField128::from_le_bytes(bytes.try_into().unwrap()), a);
1091
1092 let encoded = postcard::to_allocvec(&a).unwrap();
1093 assert_eq!(postcard::from_bytes::<BinaryField128>(&encoded).unwrap(), a);
1094 }
1095
1096 #[test]
1100 fn from_le_bytes_round_trips_every_level() {
1101 macro_rules! assert_bytes_round_trip {
1102 ($t:ty, $repr:ty, $val:expr) => {{
1103 let a = <$t>::from_repr($val as $repr);
1104 let bytes: Vec<u8> = a.into_bytes().into_iter().collect();
1105 assert_eq!(bytes.len(), core::mem::size_of::<$repr>());
1106 assert_eq!(<$t>::from_le_bytes(bytes.try_into().unwrap()), a);
1107 }};
1108 }
1109
1110 assert_bytes_round_trip!(BinaryField2, u8, 0b11);
1111 assert_bytes_round_trip!(BinaryField4, u8, 0b1001);
1112 assert_bytes_round_trip!(BinaryField8, u8, 0xab);
1113 assert_bytes_round_trip!(BinaryField16, u16, 0x1234);
1114 assert_bytes_round_trip!(BinaryField32, u32, 0x1234_5678);
1115 assert_bytes_round_trip!(BinaryField64, u64, 0x0123_4567_89ab_cdef);
1116 assert_bytes_round_trip!(
1117 BinaryField128,
1118 u128,
1119 0x8000_0000_0000_0000_0000_0000_0000_0001
1120 );
1121 }
1122
1123 #[test]
1129 fn from_le_bytes_masks_out_of_range_high_bits() {
1130 assert_eq!(
1131 BinaryField2::from_le_bytes([0xff]),
1132 BinaryField2::from_repr(0b11)
1133 );
1134 assert_eq!(
1135 BinaryField2::from_le_bytes([0b1010_0110]),
1136 BinaryField2::from_repr(0b10)
1137 );
1138 assert_eq!(
1139 BinaryField4::from_le_bytes([0xff]),
1140 BinaryField4::from_repr(0b1111)
1141 );
1142 assert_eq!(
1143 BinaryField4::from_le_bytes([0b1010_0111]),
1144 BinaryField4::from_repr(0b0111)
1145 );
1146 }
1147
1148 #[test]
1151 fn from_le_byte_iter_consumes_one_element_worth_of_bytes() {
1152 macro_rules! assert_reads_one_element {
1153 ($t:ty, $repr:ty) => {{
1154 let width = core::mem::size_of::<$repr>();
1155 let stream: Vec<u8> = (0..2 * width as u8).map(|i| i.wrapping_mul(37)).collect();
1156
1157 let mut iter = stream.iter().copied();
1158 let first = <$t as TowerLevel>::from_le_byte_iter(&mut iter);
1159 let second = <$t as TowerLevel>::from_le_byte_iter(&mut iter);
1160
1161 assert_eq!(iter.next(), None, "the stream must be fully consumed");
1162 assert_eq!(
1163 first,
1164 <$t>::from_le_bytes(stream[..width].try_into().unwrap())
1165 );
1166 assert_eq!(
1167 second,
1168 <$t>::from_le_bytes(stream[width..].try_into().unwrap())
1169 );
1170 }};
1171 }
1172
1173 assert_reads_one_element!(Gf2, u8);
1174 assert_reads_one_element!(BinaryField2, u8);
1175 assert_reads_one_element!(BinaryField4, u8);
1176 assert_reads_one_element!(BinaryField8, u8);
1177 assert_reads_one_element!(BinaryField16, u16);
1178 assert_reads_one_element!(BinaryField32, u32);
1179 assert_reads_one_element!(BinaryField64, u64);
1180 assert_reads_one_element!(BinaryField128, u128);
1181 }
1182
1183 #[test]
1184 #[should_panic = "byte stream ended before a whole element was read"]
1185 fn from_le_byte_iter_rejects_a_truncated_stream() {
1186 let truncated = [0u8; 15];
1187 let _ = BinaryField128::from_le_byte_iter(truncated.into_iter());
1188 }
1189
1190 #[test]
1191 fn field_testing_into_stream_matches_every_level() {
1192 p3_field_testing::test_into_stream::<BinaryField2>();
1193 p3_field_testing::test_into_stream::<BinaryField4>();
1194 p3_field_testing::test_into_stream::<BinaryField8>();
1195 p3_field_testing::test_into_stream::<BinaryField16>();
1196 p3_field_testing::test_into_stream::<BinaryField32>();
1197 p3_field_testing::test_into_stream::<BinaryField64>();
1198 p3_field_testing::test_into_stream::<BinaryField128>();
1199 }
1200
1201 #[test]
1202 fn word_streams_zero_pad_a_partial_final_word_at_every_level() {
1203 fn words_of(bytes: &[u8]) -> Vec<u64> {
1205 bytes
1206 .chunks(8)
1207 .map(|chunk| {
1208 let mut word = [0u8; 8];
1209 word[..chunk.len()].copy_from_slice(chunk);
1210 u64::from_le_bytes(word)
1211 })
1212 .collect()
1213 }
1214
1215 macro_rules! check {
1216 ($field:ty) => {
1217 for len in 0..=17 {
1218 let lanes: Vec<[$field; 3]> = (0..len)
1219 .map(|i| {
1220 core::array::from_fn(|lane| {
1221 <$field>::from_le_bytes(core::array::from_fn(|byte| {
1222 (i * 31 + lane * 7 + byte * 13 + 1) as u8
1223 }))
1224 })
1225 })
1226 .collect();
1227
1228 let lane_words: [Vec<u64>; 3] = core::array::from_fn(|lane| {
1229 let bytes: Vec<u8> = lanes
1230 .iter()
1231 .flat_map(|vector| vector[lane].into_bytes())
1232 .collect();
1233 words_of(&bytes)
1234 });
1235
1236 let scalar: Vec<u64> =
1237 <$field>::into_u64_stream(lanes.iter().map(|vector| vector[0]))
1238 .into_iter()
1239 .collect();
1240 assert_eq!(
1241 scalar,
1242 lane_words[0],
1243 "{} scalar, len {len}",
1244 stringify!($field)
1245 );
1246
1247 let parallel: Vec<[u64; 3]> =
1248 <$field>::into_parallel_u64_streams(lanes.iter().copied())
1249 .into_iter()
1250 .collect();
1251 let expected: Vec<[u64; 3]> = (0..lane_words[0].len())
1252 .map(|word| core::array::from_fn(|lane| lane_words[lane][word]))
1253 .collect();
1254 assert_eq!(
1255 parallel,
1256 expected,
1257 "{} parallel, len {len}",
1258 stringify!($field)
1259 );
1260 }
1261 };
1262 }
1263
1264 check!(BinaryField2);
1265 check!(BinaryField4);
1266 check!(BinaryField8);
1267 check!(BinaryField16);
1268 check!(BinaryField32);
1269 check!(BinaryField64);
1270 check!(BinaryField128);
1271 }
1272
1273 #[test]
1274 fn order_counts_the_elements_of_each_level() {
1275 assert_eq!(BinaryField2::order(), BigUint::from(4u32));
1276 assert_eq!(BinaryField4::order(), BigUint::from(16u32));
1277 assert_eq!(BinaryField8::order(), BigUint::from(256u32));
1278 assert_eq!(BinaryField16::order(), BigUint::from(65536u32));
1279 assert_eq!(BinaryField32::order(), BigUint::from(1u64 << 32));
1280 assert_eq!(BinaryField64::order(), BigUint::from(1u128 << 64));
1281 assert_eq!(BinaryField128::order(), BigUint::from(1u8) << 128usize);
1282 }
1283
1284 #[test]
1285 fn interpolation_nodes_are_basis_expansion() {
1286 assert_eq!(BinaryField128::interpolation_node(0), BinaryField128::ZERO);
1287 assert_eq!(BinaryField128::interpolation_node(1), BinaryField128::ONE);
1288 assert_eq!(
1289 BinaryField128::interpolation_node(2),
1290 BinaryField128::from_repr(2)
1291 );
1292 assert_eq!(
1293 BinaryField128::interpolation_node(5),
1294 BinaryField128::from_repr(5)
1295 );
1296 }
1297
1298 #[test]
1301 fn interpolation_nodes_cover_the_whole_level() {
1302 assert_eq!(
1303 BinaryField4::interpolation_node(15),
1304 BinaryField4::from_repr(15)
1305 );
1306 assert_eq!(
1307 BinaryField8::interpolation_node(255),
1308 BinaryField8::from_repr(255)
1309 );
1310 }
1311
1312 #[test]
1313 #[should_panic = "interpolation node index out of range"]
1314 fn interpolation_node_rejects_an_index_beyond_the_level() {
1315 let _node = BinaryField8::interpolation_node(256);
1316 }
1317
1318 #[test]
1319 fn each_level_satisfies_the_tower_defining_relation() {
1320 assert_defining_relation!(BinaryField2, u8, 2);
1321 assert_defining_relation!(BinaryField4, u8, 4);
1322 assert_defining_relation!(BinaryField8, u8, 8);
1323 assert_defining_relation!(BinaryField16, u16, 16);
1324 assert_defining_relation!(BinaryField32, u32, 32);
1325 assert_defining_relation!(BinaryField64, u64, 64);
1326 assert_defining_relation!(BinaryField128, u128, 128);
1327 }
1328
1329 #[test]
1332 fn every_level_is_an_algebra_over_gf2() {
1333 const fn assert_algebra_over_gf2<T: Algebra<Gf2>>() {}
1335
1336 macro_rules! assert_gf2_algebra {
1337 ($t:ty) => {{
1338 assert_algebra_over_gf2::<$t>();
1339
1340 assert_eq!(<$t>::from(Gf2::ZERO), <$t>::ZERO);
1341 assert_eq!(<$t>::from(Gf2::ONE), <$t>::ONE);
1342
1343 for x in [Gf2::ZERO, Gf2::ONE] {
1344 for y in [Gf2::ZERO, Gf2::ONE] {
1345 assert_eq!(<$t>::from(x + y), <$t>::from(x) + <$t>::from(y));
1346 assert_eq!(<$t>::from(x * y), <$t>::from(x) * <$t>::from(y));
1347 }
1348 }
1349
1350 for a in [
1351 <$t>::ZERO,
1352 <$t>::ONE,
1353 <$t>::GENERATOR,
1354 <$t>::GENERATOR.square(),
1355 ] {
1356 for bit in [Gf2::ZERO, Gf2::ONE] {
1357 let embedded = <$t>::from(bit);
1358
1359 assert_eq!(a + bit, a + embedded);
1360 assert_eq!(a - bit, a - embedded);
1361 assert_eq!(a * bit, a * embedded);
1362 assert_eq!(bit + a, embedded + a);
1363 assert_eq!(bit - a, embedded - a);
1364 assert_eq!(bit * a, embedded * a);
1365
1366 let mut acc = a;
1367 acc += bit;
1368 assert_eq!(acc, a + embedded);
1369 let mut acc = a;
1370 acc -= bit;
1371 assert_eq!(acc, a - embedded);
1372 let mut acc = a;
1373 acc *= bit;
1374 assert_eq!(acc, a * embedded);
1375 }
1376 }
1377 }};
1378 }
1379
1380 assert_gf2_algebra!(BinaryField2);
1381 assert_gf2_algebra!(BinaryField4);
1382 assert_gf2_algebra!(BinaryField8);
1383 assert_gf2_algebra!(BinaryField16);
1384 assert_gf2_algebra!(BinaryField32);
1385 assert_gf2_algebra!(BinaryField64);
1386 assert_gf2_algebra!(BinaryField128);
1387 }
1388
1389 #[test]
1390 fn generators_generate_the_multiplicative_group() {
1391 assert_full_order!(BinaryField2, 2, FACTORS_2);
1392 assert_full_order!(BinaryField4, 4, FACTORS_4);
1393 assert_full_order!(BinaryField8, 8, FACTORS_8);
1394 assert_full_order!(BinaryField16, 16, FACTORS_16);
1395 assert_full_order!(BinaryField32, 32, FACTORS_32);
1396 assert_full_order!(BinaryField64, 64, FACTORS_64);
1397 assert_full_order!(BinaryField128, 128, FACTORS_128);
1398 }
1399
1400 #[test]
1405 #[ignore = "one-off search used to pin the GENERATOR constants"]
1406 fn search_generators() {
1407 search_generator!(BinaryField2, u8, 2, FACTORS_2);
1408 search_generator!(BinaryField4, u8, 4, FACTORS_4);
1409 search_generator!(BinaryField8, u8, 8, FACTORS_8);
1410 search_generator!(BinaryField16, u16, 16, FACTORS_16);
1411 search_generator!(BinaryField32, u32, 32, FACTORS_32);
1412 search_generator!(BinaryField64, u64, 64, FACTORS_64);
1413 search_generator!(BinaryField128, u128, 128, FACTORS_128);
1414 }
1415
1416 fn bf128() -> impl Strategy<Value = BinaryField128> {
1417 any::<u128>().prop_map(BinaryField128::from_repr)
1418 }
1419
1420 fn bf64() -> impl Strategy<Value = BinaryField64> {
1421 any::<u64>().prop_map(BinaryField64::from_repr)
1422 }
1423
1424 fn bf32() -> impl Strategy<Value = BinaryField32> {
1425 any::<u32>().prop_map(BinaryField32::from_repr)
1426 }
1427
1428 fn bf16() -> impl Strategy<Value = BinaryField16> {
1429 any::<u16>().prop_map(BinaryField16::from_repr)
1430 }
1431
1432 fn bf8() -> impl Strategy<Value = BinaryField8> {
1433 any::<u8>().prop_map(BinaryField8::from_repr)
1434 }
1435
1436 fn bf4() -> impl Strategy<Value = BinaryField4> {
1437 any::<u8>().prop_map(BinaryField4::from_repr)
1438 }
1439
1440 fn bf2() -> impl Strategy<Value = BinaryField2> {
1441 any::<u8>().prop_map(BinaryField2::from_repr)
1442 }
1443
1444 #[test]
1445 fn bool_check_matches_the_vanishing_polynomial_at_zero_and_one() {
1446 macro_rules! check {
1447 ($field:ty) => {
1448 for x in [<$field>::ZERO, <$field>::ONE] {
1449 assert_eq!(x.bool_check(), x * (x - <$field>::ONE));
1450 }
1451 };
1452 }
1453 check!(BinaryField2);
1454 check!(BinaryField4);
1455 check!(BinaryField8);
1456 check!(BinaryField16);
1457 check!(BinaryField32);
1458 check!(BinaryField64);
1459 check!(BinaryField128);
1460 }
1461
1462 proptest! {
1463 #![proptest_config(ProptestConfig::with_cases(1000))]
1464
1465 #[test]
1466 fn mul_is_commutative(a in bf128(), b in bf128()) {
1467 prop_assert_eq!(a * b, b * a);
1468 }
1469
1470 #[test]
1471 fn mul_is_associative(a in bf128(), b in bf128(), c in bf128()) {
1472 prop_assert_eq!((a * b) * c, a * (b * c));
1473 }
1474
1475 #[test]
1476 fn mul_distributes_over_addition(a in bf128(), b in bf128(), c in bf128()) {
1477 prop_assert_eq!(a * (b + c), a * b + a * c);
1478 }
1479
1480 #[test]
1481 fn nonzero_times_its_inverse_is_one(a in bf128()) {
1482 prop_assume!(a != BinaryField128::ZERO);
1483 prop_assert_eq!(a * a.inverse(), BinaryField128::ONE);
1484 }
1485
1486 #[test]
1488 fn square_agrees_with_the_reference_squaring(a in bf128(), b in bf64()) {
1489 prop_assert_eq!(a.square(), a.reference_square());
1490 prop_assert_eq!(b.square(), b.reference_square());
1491 }
1492
1493 #[test]
1496 fn square_agrees_with_the_reference_product(a in bf128(), b in bf64(), c in any::<u32>()) {
1497 prop_assert_eq!(a.square(), a.reference_mul(a));
1498 prop_assert_eq!(b.square(), b.reference_mul(b));
1499 let c = BinaryField32::from_repr(c);
1500 prop_assert_eq!(c.square(), c.reference_mul(c));
1501 }
1502
1503 #[test]
1504 fn square_agrees_with_self_multiplication(a in bf128(), b in bf64()) {
1505 prop_assert_eq!(a.square(), a * a);
1506 prop_assert_eq!(b.square(), b * b);
1507 }
1508
1509 #[test]
1514 fn karatsuba_agrees_with_the_recursive_product(
1515 a in bf32(),
1516 b in bf32(),
1517 c in bf16(),
1518 d in bf16(),
1519 e in bf64(),
1520 f in bf64(),
1521 g in bf128(),
1522 h in bf128(),
1523 ) {
1524 prop_assert_eq!(a.karatsuba_mul(b), a.reference_mul(b));
1525 prop_assert_eq!(c.karatsuba_mul(d), c.reference_mul(d));
1526 prop_assert_eq!(e.karatsuba_mul(f), e.reference_mul(f));
1527 prop_assert_eq!(g.karatsuba_mul(h), g.reference_mul(h));
1528 }
1529
1530 #[test]
1534 fn bool_check_agrees_with_the_vanishing_polynomial(
1535 a2 in bf2(),
1536 a4 in bf4(),
1537 a8 in bf8(),
1538 a16 in bf16(),
1539 a32 in bf32(),
1540 a64 in bf64(),
1541 a128 in bf128(),
1542 ) {
1543 prop_assert_eq!(a2.bool_check(), a2 * (a2 - BinaryField2::ONE));
1544 prop_assert_eq!(a4.bool_check(), a4 * (a4 - BinaryField4::ONE));
1545 prop_assert_eq!(a8.bool_check(), a8 * (a8 - BinaryField8::ONE));
1546 prop_assert_eq!(a16.bool_check(), a16 * (a16 - BinaryField16::ONE));
1547 prop_assert_eq!(a32.bool_check(), a32 * (a32 - BinaryField32::ONE));
1548 prop_assert_eq!(a64.bool_check(), a64 * (a64 - BinaryField64::ONE));
1549 prop_assert_eq!(a128.bool_check(), a128 * (a128 - BinaryField128::ONE));
1550 }
1551 }
1552}