1use core::fmt::{self, Debug, Display, Formatter};
14use core::iter::{Product, Sum};
15use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
16
17use num_bigint::BigUint;
18use p3_field::op_assign_macros::{
19 impl_add_assign, impl_add_base_field, impl_div_methods, impl_mul_base_field, impl_mul_methods,
20 impl_sub_assign, impl_sub_base_field, ring_sum,
21};
22use p3_field::{Algebra, Field, Packable, PrimeCharacteristicRing, RawDataSerializable};
23use rand::Rng;
24use rand::distr::{Distribution, StandardUniform};
25use serde::de::Error;
26use serde::{Deserialize, Deserializer, Serialize};
27
28use crate::clmul::{HAS_HARDWARE_CLMUL, mul_64, mul_128, square_64, square_128};
29use crate::{Gf2, tables};
30
31mod private {
38 pub trait Sealed {}
39}
40
41pub trait TowerLevel: Field + private::Sealed {
43 type Repr: Copy;
44 const LOG_BITS: usize;
45 fn from_repr(r: Self::Repr) -> Self;
47 fn to_repr(self) -> Self::Repr;
49 fn mul_alpha(self) -> Self;
51 fn from_le_byte_iter(bytes: impl Iterator<Item = u8>) -> Self;
57 fn cantor_basis(i: usize) -> Self;
62}
63
64const BYTE_STREAM_ENDED: &str = "byte stream ended before a whole element was read";
66
67impl private::Sealed for Gf2 {}
68
69impl TowerLevel for Gf2 {
70 type Repr = u8;
71
72 const LOG_BITS: usize = 0;
73
74 #[inline]
75 fn from_repr(r: Self::Repr) -> Self {
76 Self::from_bool((r & 1) == 1)
77 }
78
79 #[inline]
80 fn to_repr(self) -> Self::Repr {
81 u8::from(self.is_one())
82 }
83
84 #[inline]
86 fn mul_alpha(self) -> Self {
87 self
88 }
89
90 #[inline]
91 fn from_le_byte_iter(mut bytes: impl Iterator<Item = u8>) -> Self {
92 Self::from_le_bytes([bytes.next().expect(BYTE_STREAM_ENDED)])
93 }
94
95 #[inline]
97 fn cantor_basis(i: usize) -> Self {
98 assert!(i < 1, "Cantor basis index out of range");
99 Self::ONE
100 }
101}
102
103macro_rules! binary_tower_level {
109 ($name:ident, $bits:literal, $repr:ty, $lower:ty, $lower_repr:ty, $generator:literal, $mul:ident, $square:ident, $try_inverse:ident) => {
110 #[doc = concat!("The binary tower field `GF(2^", stringify!($bits), ")`.")]
111 #[doc = concat!("A quadratic extension of [`", stringify!($lower), "`] generated by a root `X` of")]
113 #[derive(Copy, Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
122 #[serde(transparent)]
123 #[repr(transparent)]
124 #[must_use]
125 pub struct $name($repr);
126
127 impl $name {
128 pub(crate) const BITS: usize = $bits;
130
131 const MASK: $repr = <$repr>::MAX >> (<$repr>::BITS as usize - $bits);
133
134 const HALF_BITS: usize = $bits / 2;
136
137 const HALF_MASK: $repr = Self::MASK >> Self::HALF_BITS;
139
140 #[inline]
142 fn split(self) -> ($lower, $lower) {
143 let a0 = (self.0 & Self::HALF_MASK) as $lower_repr;
144 let a1 = (self.0 >> Self::HALF_BITS) as $lower_repr;
145 (<$lower>::from_repr(a0), <$lower>::from_repr(a1))
146 }
147
148 #[inline]
150 fn join(a0: $lower, a1: $lower) -> Self {
151 Self((a0.to_repr() as $repr) | ((a1.to_repr() as $repr) << Self::HALF_BITS))
152 }
153
154 #[doc(hidden)]
163 #[inline]
164 pub fn reference_mul(self, rhs: Self) -> Self {
165 let (a0, a1) = self.split();
166 let (b0, b1) = rhs.split();
167 let z0 = a0.reference_mul(b0);
168 let z2 = a1.reference_mul(b1);
169 let z1 = (a0 + a1).reference_mul(b0 + b1) + z0 + z2;
170 Self::join(z0 + z2, z1 + z2.mul_alpha())
171 }
172
173 #[allow(dead_code)]
180 #[inline]
181 fn reference_square(self) -> Self {
182 let (a0, a1) = self.split();
183 let a0_sq = a0.square();
184 let a1_sq = a1.square();
185 Self::join(a0_sq + a1_sq, a1_sq.mul_alpha())
186 }
187
188 #[allow(dead_code)]
196 #[inline]
197 fn reference_try_inverse(self) -> Option<Self> {
198 if self.0 == 0 {
199 return None;
200 }
201 let (a0, a1) = self.split();
202 let norm = a0.square() + (a0 * a1).mul_alpha() + a1.square();
203 let norm_inv = norm
204 .try_inverse()
205 .expect("the norm of a nonzero element is nonzero");
206 Some(Self::join((a0 + a1.mul_alpha()) * norm_inv, a1 * norm_inv))
207 }
208
209 #[inline]
214 pub fn from_le_bytes(bytes: [u8; core::mem::size_of::<$repr>()]) -> Self {
215 <Self as TowerLevel>::from_repr(<$repr>::from_le_bytes(bytes))
216 }
217 }
218
219 impl private::Sealed for $name {}
220
221 impl TowerLevel for $name {
222 type Repr = $repr;
223
224 const LOG_BITS: usize = Self::BITS.trailing_zeros() as usize;
225
226 #[inline]
227 fn from_repr(r: Self::Repr) -> Self {
228 Self(r & Self::MASK)
229 }
230
231 #[inline]
232 fn to_repr(self) -> Self::Repr {
233 self.0
234 }
235
236 #[inline]
238 fn mul_alpha(self) -> Self {
239 let (c0, c1) = self.split();
240 Self::join(c1, c0 + c1.mul_alpha())
241 }
242
243 #[inline]
244 fn from_le_byte_iter(mut bytes: impl Iterator<Item = u8>) -> Self {
245 let mut buffer = [0u8; core::mem::size_of::<$repr>()];
246 for byte in &mut buffer {
247 *byte = bytes.next().expect(BYTE_STREAM_ENDED);
248 }
249 Self::from_le_bytes(buffer)
250 }
251
252 #[inline]
253 fn cantor_basis(i: usize) -> Self {
254 assert!(i < $bits, "Cantor basis index out of range");
255 Self::from_repr(crate::cantor::CANTOR_BASIS_128[i] as $repr)
257 }
258 }
259
260 impl<'de> Deserialize<'de> for $name {
261 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
262 let val = <$repr>::deserialize(d)?;
263 if val <= Self::MASK {
266 Ok(Self(val))
267 } else {
268 Err(D::Error::custom("Value is out of range"))
269 }
270 }
271 }
272
273 impl Packable for $name {}
274
275 impl Display for $name {
276 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
277 Display::fmt(&self.0, f)
278 }
279 }
280
281 impl Debug for $name {
282 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
283 Debug::fmt(&self.0, f)
284 }
285 }
286
287 impl Distribution<$name> for StandardUniform {
288 #[inline]
289 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $name {
290 let mut bytes = [0u8; core::mem::size_of::<$repr>()];
291 rng.fill_bytes(&mut bytes);
292 <$name>::from_repr(<$repr>::from_le_bytes(bytes))
293 }
294 }
295
296 impl PrimeCharacteristicRing for $name {
297 type PrimeSubfield = Gf2;
298
299 const ZERO: Self = Self(0);
300 const ONE: Self = Self(1);
301 const TWO: Self = Self(0);
303 const NEG_ONE: Self = Self(1);
305
306 #[inline]
307 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
308 Self::from_bool(f.is_one())
309 }
310
311 #[inline]
312 fn from_bool(b: bool) -> Self {
313 Self(<$repr>::from(b))
314 }
315
316 #[inline]
317 fn double(&self) -> Self {
318 Self::ZERO
320 }
321
322 #[inline]
325 fn halve(&self) -> Self {
326 panic!("halve is undefined in characteristic 2")
327 }
328
329 #[inline]
330 fn square(&self) -> Self {
331 self.$square()
332 }
333
334 #[inline]
335 fn xor(&self, y: &Self) -> Self {
336 *self + *y
337 }
338
339 #[inline]
340 fn mul_2exp_u64(&self, exp: u64) -> Self {
341 if exp == 0 { *self } else { Self::ZERO }
342 }
343
344 #[inline]
347 fn div_2exp_u64(&self, _exp: u64) -> Self {
348 panic!("div_2exp_u64 is undefined in characteristic 2")
349 }
350 }
351
352 impl Field for $name {
353 type Packing = Self;
354
355 const GENERATOR: Self = Self($generator);
356
357 #[inline]
358 fn try_inverse(&self) -> Option<Self> {
359 self.$try_inverse()
360 }
361
362 #[inline]
363 fn try_sqrt(&self) -> Option<Self> {
364 Some(self.exp_power_of_2(Self::BITS - 1))
366 }
367
368 #[inline]
369 fn order() -> BigUint {
370 BigUint::from(1u8) << (1usize << <Self as TowerLevel>::LOG_BITS)
371 }
372
373 #[inline]
381 fn interpolation_node(i: usize) -> Self {
382 assert!(
383 usize::BITS as usize <= Self::BITS || i < (1usize << Self::BITS),
384 "interpolation node index out of range"
385 );
386 Self::from_repr(i as $repr)
387 }
388
389 #[inline]
391 fn bits() -> usize {
392 Self::BITS
393 }
394 }
395
396 impl RawDataSerializable for $name {
397 const NUM_BYTES: usize = core::mem::size_of::<$repr>();
398
399 #[inline]
400 fn into_bytes(self) -> impl IntoIterator<Item = u8> {
401 self.0.to_le_bytes()
402 }
403 }
404
405 impl Add for $name {
406 type Output = Self;
407
408 #[inline]
409 #[allow(clippy::suspicious_arithmetic_impl)]
410 fn add(self, rhs: Self) -> Self {
411 Self(self.0 ^ rhs.0)
413 }
414 }
415
416 impl Sub for $name {
417 type Output = Self;
418
419 #[inline]
420 #[allow(clippy::suspicious_arithmetic_impl)]
421 fn sub(self, rhs: Self) -> Self {
422 self + rhs
424 }
425 }
426
427 impl Neg for $name {
428 type Output = Self;
429
430 #[inline]
431 fn neg(self) -> Self::Output {
432 self
434 }
435 }
436
437 impl Mul for $name {
438 type Output = Self;
439
440 #[inline]
441 fn mul(self, rhs: Self) -> Self {
442 self.$mul(rhs)
443 }
444 }
445
446 impl_add_assign!($name);
447 impl_sub_assign!($name);
448 impl_mul_methods!($name);
449 impl_div_methods!($name, $name);
450 ring_sum!($name);
451
452 impl From<Gf2> for $name {
453 #[inline]
455 fn from(x: Gf2) -> Self {
456 Self::from_prime_subfield(x)
457 }
458 }
459
460 impl_add_base_field!($name, Gf2);
461 impl_sub_base_field!($name, Gf2);
462 impl_mul_base_field!($name, Gf2);
463
464 impl Algebra<Gf2> for $name {}
465 };
466}
467
468binary_tower_level!(
469 BinaryField2,
470 2,
471 u8,
472 Gf2,
473 u8,
474 2,
475 reference_mul,
476 reference_square,
477 reference_try_inverse
478);
479binary_tower_level!(
480 BinaryField4,
481 4,
482 u8,
483 BinaryField2,
484 u8,
485 5,
486 reference_mul,
487 reference_square,
488 reference_try_inverse
489);
490binary_tower_level!(
491 BinaryField8,
492 8,
493 u8,
494 BinaryField4,
495 u8,
496 19,
497 table_mul,
498 table_square,
499 table_try_inverse
500);
501binary_tower_level!(
502 BinaryField16,
503 16,
504 u16,
505 BinaryField8,
506 u8,
507 258,
508 karatsuba_mul,
509 reference_square,
510 reference_try_inverse
511);
512binary_tower_level!(
513 BinaryField32,
514 32,
515 u32,
516 BinaryField16,
517 u16,
518 65541,
519 karatsuba_mul,
520 reference_square,
521 reference_try_inverse
522);
523binary_tower_level!(
524 BinaryField64,
525 64,
526 u64,
527 BinaryField32,
528 u32,
529 4294967300,
530 dispatched_mul,
531 dispatched_square,
532 reference_try_inverse
533);
534binary_tower_level!(
535 BinaryField128,
536 128,
537 u128,
538 BinaryField64,
539 u64,
540 18446744073709551621,
541 dispatched_mul,
542 dispatched_square,
543 reference_try_inverse
544);
545
546impl BinaryField8 {
547 #[inline]
549 const fn table_mul(self, rhs: Self) -> Self {
550 Self(tables::mul(self.0, rhs.0))
551 }
552
553 #[inline]
555 const fn table_square(self) -> Self {
556 Self(tables::square(self.0))
557 }
558
559 #[inline]
561 const fn table_try_inverse(self) -> Option<Self> {
562 match tables::try_inverse(self.0) {
563 Some(inverse) => Some(Self(inverse)),
564 None => None,
565 }
566 }
567}
568
569macro_rules! karatsuba_over_the_level_below {
575 ($name:ident) => {
576 impl $name {
577 #[inline]
582 fn karatsuba_mul(self, rhs: Self) -> Self {
583 let (a0, a1) = self.split();
584 let (b0, b1) = rhs.split();
585 let z0 = a0 * b0;
586 let z2 = a1 * b1;
587 let z1 = (a0 + a1) * (b0 + b1) + z0 + z2;
588 Self::join(z0 + z2, z1 + z2.mul_alpha())
589 }
590 }
591 };
592}
593
594karatsuba_over_the_level_below!(BinaryField16);
595karatsuba_over_the_level_below!(BinaryField32);
596
597impl BinaryField64 {
598 #[inline]
603 fn dispatched_mul(self, rhs: Self) -> Self {
604 if HAS_HARDWARE_CLMUL {
605 Self(mul_64(self.0, rhs.0))
606 } else {
607 self.reference_mul(rhs)
608 }
609 }
610
611 #[inline]
614 fn dispatched_square(self) -> Self {
615 if HAS_HARDWARE_CLMUL {
616 Self(square_64(self.0))
617 } else {
618 self.reference_square()
619 }
620 }
621}
622
623impl BinaryField128 {
624 #[inline]
629 fn dispatched_mul(self, rhs: Self) -> Self {
630 if HAS_HARDWARE_CLMUL {
631 Self(mul_128(self.0, rhs.0))
632 } else {
633 self.reference_mul(rhs)
634 }
635 }
636
637 #[inline]
640 fn dispatched_square(self) -> Self {
641 if HAS_HARDWARE_CLMUL {
642 Self(square_128(self.0))
643 } else {
644 self.reference_square()
645 }
646 }
647}
648
649#[cfg(test)]
650mod tests {
651 extern crate std;
652
653 use std::println;
654 use std::vec::Vec;
655
656 use p3_field::{Field, PrimeCharacteristicRing, RawDataSerializable};
657 use proptest::prelude::*;
658
659 use super::*;
660
661 const FACTORS_2: [u128; 1] = [3];
663 const FACTORS_4: [u128; 2] = [3, 5];
664 const FACTORS_8: [u128; 3] = [3, 5, 17];
665 const FACTORS_16: [u128; 4] = [3, 5, 17, 257];
666 const FACTORS_32: [u128; 5] = [3, 5, 17, 257, 65537];
667 const FACTORS_64: [u128; 7] = [3, 5, 17, 257, 641, 65537, 6700417];
668 const FACTORS_128: [u128; 9] = [3, 5, 17, 257, 641, 65537, 274177, 6700417, 67280421310721];
669
670 const fn group_order(bits: u32) -> u128 {
672 if bits == 128 {
673 u128::MAX
674 } else {
675 (1u128 << bits) - 1
676 }
677 }
678
679 fn pow_u128<F: Field>(base: F, mut exp: u128) -> F {
681 let mut acc = F::ONE;
682 let mut cur = base;
683 while exp != 0 {
684 if exp & 1 == 1 {
685 acc *= cur;
686 }
687 cur = cur.square();
688 exp >>= 1;
689 }
690 acc
691 }
692
693 fn has_full_order<F: Field>(g: F, bits: u32, factors: &[u128]) -> bool {
698 let order = group_order(bits);
699 factors.iter().all(|&q| pow_u128(g, order / q) != F::ONE)
700 }
701
702 macro_rules! assert_full_order {
703 ($t:ty, $bits:expr, $factors:expr) => {
704 assert!(
705 has_full_order(<$t>::GENERATOR, $bits, &$factors),
706 concat!(
707 stringify!($t),
708 "::GENERATOR does not generate the multiplicative group"
709 )
710 );
711 };
712 }
713
714 macro_rules! assert_defining_relation {
715 ($t:ty, $repr:ty, $bits:expr) => {{
716 let x = <$t>::from_repr((1 as $repr) << ($bits / 2));
720 let alpha = <$t>::from_repr((1 as $repr) << ($bits / 4));
721 assert_eq!(
722 x.square(),
723 alpha * x + <$t>::ONE,
724 concat!(stringify!($t), " does not satisfy X^2 = alpha*X + 1")
725 );
726 }};
727 }
728
729 macro_rules! search_generator {
730 ($t:ty, $repr:ty, $bits:expr, $factors:expr) => {{
731 let start = 1u128 << ($bits / 2);
734 let found = (start..start + 1024)
735 .map(|cand| (cand, <$t>::from_repr(cand as $repr)))
736 .find(|&(_, g)| has_full_order(g, $bits, &$factors));
737 println!(
738 "{}: GENERATOR = {:?}",
739 stringify!($t),
740 found.map(|(cand, _)| cand)
741 );
742 }};
743 }
744
745 #[test]
746 fn gf4_multiplication_table() {
747 let x = BinaryField2::from_repr(2);
749 assert_eq!(x * x, x + BinaryField2::ONE); assert_eq!(x * (x + BinaryField2::ONE), BinaryField2::ONE); assert_eq!(x.inverse(), x + BinaryField2::ONE);
752 }
753
754 #[test]
755 fn frobenius_fixes_every_element_of_each_level() {
756 for r in 0..=u8::MAX {
757 let a = BinaryField8::from_repr(r);
758 assert_eq!(a.exp_power_of_2(8), a); }
760 for r in 0..=u8::MAX {
761 let a = BinaryField4::from_repr(r & 0x0f);
762 assert_eq!(a.exp_power_of_2(4), a); }
764 }
765
766 #[test]
769 fn the_table_square_agrees_with_the_recursive_squaring_on_gf256() {
770 for r in 0..=u8::MAX {
771 let a = BinaryField8::from_repr(r);
772 assert_eq!(a.table_square(), a.reference_square(), "square({r})");
773 }
774 }
775
776 #[test]
779 fn the_table_inverse_agrees_with_the_recursive_inverse_on_gf256() {
780 for r in 0..=u8::MAX {
781 let a = BinaryField8::from_repr(r);
782 assert_eq!(
783 a.table_try_inverse(),
784 a.reference_try_inverse(),
785 "inverse({r})"
786 );
787 }
788 }
789
790 #[test]
793 fn karatsuba_agrees_with_the_recursive_product_over_every_gf16_operand() {
794 let others = [0u16, 1, 2, 0x00ff, 0x0100, 0x1234, 0xfffe, 0xffff];
795 for r in 0..=u16::MAX {
796 let a = BinaryField16::from_repr(r);
797 for other in others {
798 let b = BinaryField16::from_repr(other);
799 assert_eq!(a.karatsuba_mul(b), a.reference_mul(b), "mul({r}, {other})");
800 }
801 }
802 }
803
804 #[test]
805 fn inverse_agrees_with_fermat_on_gf256() {
806 for r in 1..=u8::MAX {
807 let a = BinaryField8::from_repr(r);
808 assert_eq!(a.inverse(), a.exp_u64(254));
809 assert_eq!(a * a.inverse(), BinaryField8::ONE);
810 }
811 }
812
813 #[test]
814 fn square_roots_square_back_to_the_input() {
815 for r in 0..=u8::MAX {
816 let a = BinaryField8::from_repr(r);
817 assert_eq!(a.try_sqrt().unwrap().square(), a);
818 }
819 let a = BinaryField128::from_repr(0x0123_4567_89ab_cdef_fedc_ba98_7654_3210);
820 assert_eq!(a.try_sqrt().unwrap().square(), a);
821 }
822
823 #[test]
827 fn serde_round_trip_rejects_non_canonical_encodings() {
828 assert_eq!(
829 serde_json::to_string(&BinaryField4::from_repr(9)).unwrap(),
830 "9"
831 );
832 assert_eq!(
833 serde_json::from_str::<BinaryField4>("9").unwrap(),
834 BinaryField4::from_repr(9)
835 );
836
837 assert!(serde_json::from_str::<BinaryField2>("3").is_ok());
840 assert!(serde_json::from_str::<BinaryField2>("4").is_err());
841 assert!(serde_json::from_str::<BinaryField4>("15").is_ok());
842 assert!(serde_json::from_str::<BinaryField4>("16").is_err());
843
844 assert!(serde_json::from_str::<BinaryField8>("255").is_ok());
846 assert!(serde_json::from_str::<BinaryField8>("256").is_err());
847 }
848
849 #[test]
850 fn bytes_round_trip_and_postcard() {
851 let a = BinaryField128::from_repr(0x8000_0000_0000_0000_0000_0000_0000_0001);
852 let bytes: Vec<u8> = a.into_bytes().into_iter().collect();
853 assert_eq!(bytes.len(), 16);
854 assert_eq!(BinaryField128::from_le_bytes(bytes.try_into().unwrap()), a);
855
856 let encoded = postcard::to_allocvec(&a).unwrap();
857 assert_eq!(postcard::from_bytes::<BinaryField128>(&encoded).unwrap(), a);
858 }
859
860 #[test]
864 fn from_le_bytes_round_trips_every_level() {
865 macro_rules! assert_bytes_round_trip {
866 ($t:ty, $repr:ty, $val:expr) => {{
867 let a = <$t>::from_repr($val as $repr);
868 let bytes: Vec<u8> = a.into_bytes().into_iter().collect();
869 assert_eq!(bytes.len(), core::mem::size_of::<$repr>());
870 assert_eq!(<$t>::from_le_bytes(bytes.try_into().unwrap()), a);
871 }};
872 }
873
874 assert_bytes_round_trip!(BinaryField2, u8, 0b11);
875 assert_bytes_round_trip!(BinaryField4, u8, 0b1001);
876 assert_bytes_round_trip!(BinaryField8, u8, 0xab);
877 assert_bytes_round_trip!(BinaryField16, u16, 0x1234);
878 assert_bytes_round_trip!(BinaryField32, u32, 0x1234_5678);
879 assert_bytes_round_trip!(BinaryField64, u64, 0x0123_4567_89ab_cdef);
880 assert_bytes_round_trip!(
881 BinaryField128,
882 u128,
883 0x8000_0000_0000_0000_0000_0000_0000_0001
884 );
885 }
886
887 #[test]
893 fn from_le_bytes_masks_out_of_range_high_bits() {
894 assert_eq!(
895 BinaryField2::from_le_bytes([0xff]),
896 BinaryField2::from_repr(0b11)
897 );
898 assert_eq!(
899 BinaryField2::from_le_bytes([0b1010_0110]),
900 BinaryField2::from_repr(0b10)
901 );
902 assert_eq!(
903 BinaryField4::from_le_bytes([0xff]),
904 BinaryField4::from_repr(0b1111)
905 );
906 assert_eq!(
907 BinaryField4::from_le_bytes([0b1010_0111]),
908 BinaryField4::from_repr(0b0111)
909 );
910 }
911
912 #[test]
915 fn from_le_byte_iter_consumes_one_element_worth_of_bytes() {
916 macro_rules! assert_reads_one_element {
917 ($t:ty, $repr:ty) => {{
918 let width = core::mem::size_of::<$repr>();
919 let stream: Vec<u8> = (0..2 * width as u8).map(|i| i.wrapping_mul(37)).collect();
920
921 let mut iter = stream.iter().copied();
922 let first = <$t as TowerLevel>::from_le_byte_iter(&mut iter);
923 let second = <$t as TowerLevel>::from_le_byte_iter(&mut iter);
924
925 assert_eq!(iter.next(), None, "the stream must be fully consumed");
926 assert_eq!(
927 first,
928 <$t>::from_le_bytes(stream[..width].try_into().unwrap())
929 );
930 assert_eq!(
931 second,
932 <$t>::from_le_bytes(stream[width..].try_into().unwrap())
933 );
934 }};
935 }
936
937 assert_reads_one_element!(Gf2, u8);
938 assert_reads_one_element!(BinaryField2, u8);
939 assert_reads_one_element!(BinaryField4, u8);
940 assert_reads_one_element!(BinaryField8, u8);
941 assert_reads_one_element!(BinaryField16, u16);
942 assert_reads_one_element!(BinaryField32, u32);
943 assert_reads_one_element!(BinaryField64, u64);
944 assert_reads_one_element!(BinaryField128, u128);
945 }
946
947 #[test]
948 #[should_panic = "byte stream ended before a whole element was read"]
949 fn from_le_byte_iter_rejects_a_truncated_stream() {
950 let truncated = [0u8; 15];
951 let _ = BinaryField128::from_le_byte_iter(truncated.into_iter());
952 }
953
954 #[test]
955 fn field_testing_into_stream_matches_binary_field_128() {
956 p3_field_testing::test_into_stream::<BinaryField128>();
957 }
958
959 #[test]
960 fn order_counts_the_elements_of_each_level() {
961 assert_eq!(BinaryField2::order(), BigUint::from(4u32));
962 assert_eq!(BinaryField4::order(), BigUint::from(16u32));
963 assert_eq!(BinaryField8::order(), BigUint::from(256u32));
964 assert_eq!(BinaryField16::order(), BigUint::from(65536u32));
965 assert_eq!(BinaryField32::order(), BigUint::from(1u64 << 32));
966 assert_eq!(BinaryField64::order(), BigUint::from(1u128 << 64));
967 assert_eq!(BinaryField128::order(), BigUint::from(1u8) << 128usize);
968 }
969
970 #[test]
971 fn interpolation_nodes_are_basis_expansion() {
972 assert_eq!(BinaryField128::interpolation_node(0), BinaryField128::ZERO);
973 assert_eq!(BinaryField128::interpolation_node(1), BinaryField128::ONE);
974 assert_eq!(
975 BinaryField128::interpolation_node(2),
976 BinaryField128::from_repr(2)
977 );
978 assert_eq!(
979 BinaryField128::interpolation_node(5),
980 BinaryField128::from_repr(5)
981 );
982 }
983
984 #[test]
987 fn interpolation_nodes_cover_the_whole_level() {
988 assert_eq!(
989 BinaryField4::interpolation_node(15),
990 BinaryField4::from_repr(15)
991 );
992 assert_eq!(
993 BinaryField8::interpolation_node(255),
994 BinaryField8::from_repr(255)
995 );
996 }
997
998 #[test]
999 #[should_panic = "interpolation node index out of range"]
1000 fn interpolation_node_rejects_an_index_beyond_the_level() {
1001 let _node = BinaryField8::interpolation_node(256);
1002 }
1003
1004 #[test]
1005 fn each_level_satisfies_the_tower_defining_relation() {
1006 assert_defining_relation!(BinaryField2, u8, 2);
1007 assert_defining_relation!(BinaryField4, u8, 4);
1008 assert_defining_relation!(BinaryField8, u8, 8);
1009 assert_defining_relation!(BinaryField16, u16, 16);
1010 assert_defining_relation!(BinaryField32, u32, 32);
1011 assert_defining_relation!(BinaryField64, u64, 64);
1012 assert_defining_relation!(BinaryField128, u128, 128);
1013 }
1014
1015 #[test]
1018 fn every_level_is_an_algebra_over_gf2() {
1019 const fn assert_algebra_over_gf2<T: Algebra<Gf2>>() {}
1021
1022 macro_rules! assert_gf2_algebra {
1023 ($t:ty) => {{
1024 assert_algebra_over_gf2::<$t>();
1025
1026 assert_eq!(<$t>::from(Gf2::ZERO), <$t>::ZERO);
1027 assert_eq!(<$t>::from(Gf2::ONE), <$t>::ONE);
1028
1029 for x in [Gf2::ZERO, Gf2::ONE] {
1030 for y in [Gf2::ZERO, Gf2::ONE] {
1031 assert_eq!(<$t>::from(x + y), <$t>::from(x) + <$t>::from(y));
1032 assert_eq!(<$t>::from(x * y), <$t>::from(x) * <$t>::from(y));
1033 }
1034 }
1035
1036 for a in [
1037 <$t>::ZERO,
1038 <$t>::ONE,
1039 <$t>::GENERATOR,
1040 <$t>::GENERATOR.square(),
1041 ] {
1042 for bit in [Gf2::ZERO, Gf2::ONE] {
1043 let embedded = <$t>::from(bit);
1044
1045 assert_eq!(a + bit, a + embedded);
1046 assert_eq!(a - bit, a - embedded);
1047 assert_eq!(a * bit, a * embedded);
1048 assert_eq!(bit + a, embedded + a);
1049 assert_eq!(bit - a, embedded - a);
1050 assert_eq!(bit * a, embedded * a);
1051
1052 let mut acc = a;
1053 acc += bit;
1054 assert_eq!(acc, a + embedded);
1055 let mut acc = a;
1056 acc -= bit;
1057 assert_eq!(acc, a - embedded);
1058 let mut acc = a;
1059 acc *= bit;
1060 assert_eq!(acc, a * embedded);
1061 }
1062 }
1063 }};
1064 }
1065
1066 assert_gf2_algebra!(BinaryField2);
1067 assert_gf2_algebra!(BinaryField4);
1068 assert_gf2_algebra!(BinaryField8);
1069 assert_gf2_algebra!(BinaryField16);
1070 assert_gf2_algebra!(BinaryField32);
1071 assert_gf2_algebra!(BinaryField64);
1072 assert_gf2_algebra!(BinaryField128);
1073 }
1074
1075 #[test]
1076 fn generators_generate_the_multiplicative_group() {
1077 assert_full_order!(BinaryField2, 2, FACTORS_2);
1078 assert_full_order!(BinaryField4, 4, FACTORS_4);
1079 assert_full_order!(BinaryField8, 8, FACTORS_8);
1080 assert_full_order!(BinaryField16, 16, FACTORS_16);
1081 assert_full_order!(BinaryField32, 32, FACTORS_32);
1082 assert_full_order!(BinaryField64, 64, FACTORS_64);
1083 assert_full_order!(BinaryField128, 128, FACTORS_128);
1084 }
1085
1086 #[test]
1091 #[ignore = "one-off search used to pin the GENERATOR constants"]
1092 fn search_generators() {
1093 search_generator!(BinaryField2, u8, 2, FACTORS_2);
1094 search_generator!(BinaryField4, u8, 4, FACTORS_4);
1095 search_generator!(BinaryField8, u8, 8, FACTORS_8);
1096 search_generator!(BinaryField16, u16, 16, FACTORS_16);
1097 search_generator!(BinaryField32, u32, 32, FACTORS_32);
1098 search_generator!(BinaryField64, u64, 64, FACTORS_64);
1099 search_generator!(BinaryField128, u128, 128, FACTORS_128);
1100 }
1101
1102 fn bf128() -> impl Strategy<Value = BinaryField128> {
1103 any::<u128>().prop_map(BinaryField128::from_repr)
1104 }
1105
1106 fn bf64() -> impl Strategy<Value = BinaryField64> {
1107 any::<u64>().prop_map(BinaryField64::from_repr)
1108 }
1109
1110 fn bf32() -> impl Strategy<Value = BinaryField32> {
1111 any::<u32>().prop_map(BinaryField32::from_repr)
1112 }
1113
1114 fn bf16() -> impl Strategy<Value = BinaryField16> {
1115 any::<u16>().prop_map(BinaryField16::from_repr)
1116 }
1117
1118 proptest! {
1119 #![proptest_config(ProptestConfig::with_cases(1000))]
1120
1121 #[test]
1122 fn mul_is_commutative(a in bf128(), b in bf128()) {
1123 prop_assert_eq!(a * b, b * a);
1124 }
1125
1126 #[test]
1127 fn mul_is_associative(a in bf128(), b in bf128(), c in bf128()) {
1128 prop_assert_eq!((a * b) * c, a * (b * c));
1129 }
1130
1131 #[test]
1132 fn mul_distributes_over_addition(a in bf128(), b in bf128(), c in bf128()) {
1133 prop_assert_eq!(a * (b + c), a * b + a * c);
1134 }
1135
1136 #[test]
1137 fn nonzero_times_its_inverse_is_one(a in bf128()) {
1138 prop_assume!(a != BinaryField128::ZERO);
1139 prop_assert_eq!(a * a.inverse(), BinaryField128::ONE);
1140 }
1141
1142 #[test]
1144 fn square_agrees_with_the_reference_squaring(a in bf128(), b in bf64()) {
1145 prop_assert_eq!(a.square(), a.reference_square());
1146 prop_assert_eq!(b.square(), b.reference_square());
1147 }
1148
1149 #[test]
1152 fn square_agrees_with_the_reference_product(a in bf128(), b in bf64()) {
1153 prop_assert_eq!(a.square(), a.reference_mul(a));
1154 prop_assert_eq!(b.square(), b.reference_mul(b));
1155 }
1156
1157 #[test]
1158 fn square_agrees_with_self_multiplication(a in bf128(), b in bf64()) {
1159 prop_assert_eq!(a.square(), a * a);
1160 prop_assert_eq!(b.square(), b * b);
1161 }
1162
1163 #[test]
1166 fn karatsuba_agrees_with_the_recursive_product(a in bf32(), b in bf32(), c in bf16(), d in bf16()) {
1167 prop_assert_eq!(a.karatsuba_mul(b), a.reference_mul(b));
1168 prop_assert_eq!(c.karatsuba_mul(d), c.reference_mul(d));
1169 }
1170 }
1171}