Skip to main content

binius_field/
binary_field.rs

1// Copyright 2023-2025 Irreducible Inc.
2// Copyright 2026 The Binius Developers
3
4use std::{
5	fmt::{Debug, Display, Formatter},
6	iter::{Product, Sum},
7	ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
8};
9
10use binius_utils::{
11	DeserializeBytes, FixedSizeSerializeBytes, SerializationError, SerializeBytes,
12	bytes::{Buf, BufMut},
13};
14use bytemuck::Zeroable;
15
16use super::{UnderlierType, WithUnderlier, extension::ExtensionField};
17use crate::{Field, underlier::U1};
18
19/// A finite field with characteristic 2.
20pub trait BinaryField:
21	ExtensionField<BinaryField1b> + WithUnderlier<Underlier: UnderlierType>
22{
23	const N_BITS: usize = Self::ORDER_EXPONENT;
24
25	/// An element whose absolute trace is 1.
26	///
27	/// The absolute trace is the $\mathbb{F}_2$-linear map
28	///
29	/// $$\operatorname{Tr}(x) = \sum_{i=0}^{n-1} x^{2^i},$$
30	///
31	/// which lands in $\mathbb{F}_2$ and is surjective, so such an element always exists and
32	/// exactly half the field has trace 1. Which one is named here is arbitrary; each field picks
33	/// a single-bit element, the lowest one that qualifies.
34	///
35	/// The NTT's Gao-Mateer domain context seeds its basis with this: the descent
36	/// $\beta_i = \beta_{i+1}^2 + \beta_{i+1}$ reaches $\beta_0 = 1$ exactly when it starts from
37	/// an element of trace 1.
38	const TRACE_ONE_ELEMENT: Self;
39}
40
41/// Generates a binary field type over an underlier `$typ`.
42///
43/// `$gen` is the multiplicative generator and `$trace_one` an element of trace 1, both as raw
44/// underlier values.
45///
46/// The default form derives the field's arithmetic from its width-one packing.
47/// The `custom_arithmetic` form omits that, for a field that defines its own arithmetic.
48macro_rules! binary_field {
49	// Default: the field's arithmetic is its width-one packing's arithmetic.
50	($vis:vis $name:ident($typ:ty), $gen:expr, $trace_one:expr) => {
51		binary_field!(@base $vis $name($typ), $gen, $trace_one);
52		binary_field!(@arithmetic_via_packed $name, $typ);
53	};
54	// The field provides its own `Mul`/`Square`/`InvertOrZero`/`WideMul` separately.
55	(custom_arithmetic $vis:vis $name:ident($typ:ty), $gen:expr, $trace_one:expr) => {
56		binary_field!(@base $vis $name($typ), $gen, $trace_one);
57	};
58
59	(@base $vis:vis $name:ident($typ:ty), $gen:expr, $trace_one:expr) => {
60		#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroable, bytemuck::TransparentWrapper)]
61		#[repr(transparent)]
62		$vis struct $name(pub(crate) $typ);
63
64		// NOTE: `new` is intentionally NOT generated here. Each field defines its own `new` so it
65		// can take an ergonomic constructor type independent of the underlier (e.g.
66		// `BinaryField128bGhash::new` takes `u128` even though its underlier is `M128`).
67		impl $name {
68			pub const fn val(self) -> $typ {
69				self.0
70			}
71		}
72
73		unsafe impl $crate::underlier::WithUnderlier for $name {
74			type Underlier = $typ;
75		}
76
77		impl Neg for $name {
78			type Output = Self;
79
80			fn neg(self) -> Self::Output {
81				self
82			}
83		}
84
85		impl Add<Self> for $name {
86			type Output = Self;
87
88			#[allow(clippy::suspicious_arithmetic_impl)]
89			fn add(self, rhs: Self) -> Self::Output {
90				$name(self.0 ^ rhs.0)
91			}
92		}
93
94		impl Add<&Self> for $name {
95			type Output = Self;
96
97			#[allow(clippy::suspicious_arithmetic_impl)]
98			fn add(self, rhs: &Self) -> Self::Output {
99				$name(self.0 ^ rhs.0)
100			}
101		}
102
103		impl Sub<Self> for $name {
104			type Output = Self;
105
106			#[allow(clippy::suspicious_arithmetic_impl)]
107			fn sub(self, rhs: Self) -> Self::Output {
108				$name(self.0 ^ rhs.0)
109			}
110		}
111
112		impl Sub<&Self> for $name {
113			type Output = Self;
114
115			#[allow(clippy::suspicious_arithmetic_impl)]
116			fn sub(self, rhs: &Self) -> Self::Output {
117				$name(self.0 ^ rhs.0)
118			}
119		}
120
121		impl Mul<&Self> for $name {
122			type Output = Self;
123
124			fn mul(self, rhs: &Self) -> Self::Output {
125				self * *rhs
126			}
127		}
128
129		impl AddAssign<Self> for $name {
130			fn add_assign(&mut self, rhs: Self) {
131				*self = *self + rhs;
132			}
133		}
134
135		impl AddAssign<&Self> for $name {
136			fn add_assign(&mut self, rhs: &Self) {
137				*self = *self + *rhs;
138			}
139		}
140
141		impl SubAssign<Self> for $name {
142			fn sub_assign(&mut self, rhs: Self) {
143				*self = *self - rhs;
144			}
145		}
146
147		impl SubAssign<&Self> for $name {
148			fn sub_assign(&mut self, rhs: &Self) {
149				*self = *self - *rhs;
150			}
151		}
152
153		impl MulAssign<Self> for $name {
154			fn mul_assign(&mut self, rhs: Self) {
155				*self = *self * rhs;
156			}
157		}
158
159		impl MulAssign<&Self> for $name {
160			fn mul_assign(&mut self, rhs: &Self) {
161				*self = *self * rhs;
162			}
163		}
164
165		impl Sum<Self> for $name {
166			fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
167				iter.fold(Self::ZERO, |acc, x| acc + x)
168			}
169		}
170
171		impl<'a> Sum<&'a Self> for $name {
172			fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
173				iter.fold(Self::ZERO, |acc, x| acc + x)
174			}
175		}
176
177		impl Product<Self> for $name {
178			fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
179				iter.fold(Self::ONE, |acc, x| acc * x)
180			}
181		}
182
183		impl<'a> Product<&'a Self> for $name {
184			fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
185				iter.fold(Self::ONE, |acc, x| acc * x)
186			}
187		}
188
189
190		impl Field for $name {
191			const ZERO: Self = $name(<$typ as $crate::underlier::UnderlierType>::ZERO);
192			const ONE: Self = $name(<$typ as $crate::underlier::UnderlierType>::ONE);
193			const CHARACTERISTIC: usize = 2;
194			const ORDER_EXPONENT: usize = <$typ as $crate::underlier::UnderlierType>::BITS;
195			const MULTIPLICATIVE_GENERATOR: $name = $name($gen);
196
197			fn double(&self) -> Self {
198				Self::ZERO
199			}
200		}
201
202		// A field element divides into exactly one element of itself. This makes the field a
203		// degenerate packed field of width one (see the `PackedField` impl below).
204		impl $crate::Divisible<$name> for $name {
205			const LOG_N: usize = 0;
206
207			#[inline]
208			fn value_iter(value: Self) -> impl ExactSizeIterator<Item = $name> + Send + Clone {
209				std::iter::once(value)
210			}
211
212			#[inline]
213			fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = $name> + Send + Clone + '_ {
214				std::iter::once(*value)
215			}
216
217			#[inline]
218			fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = $name> + Send + Clone + '_ {
219				slice.iter().copied()
220			}
221
222			#[inline]
223			unsafe fn get_unchecked(&self, _index: usize) -> $name {
224				*self
225			}
226
227			#[inline]
228			unsafe fn set_unchecked(&mut self, _index: usize, val: $name) {
229				*self = val;
230			}
231
232			#[inline]
233			fn broadcast(val: $name) -> Self {
234				val
235			}
236
237			#[inline]
238			fn from_iter(mut iter: impl Iterator<Item = $name>) -> Self {
239				iter.next().unwrap_or(Self::ZERO)
240			}
241		}
242
243		// As a width-one packed field, a field element is masked by its single selector: kept
244		// when selected, otherwise zeroed. Uses the same underlier bitmask strategy as
245		// PackedPrimitiveType so the mask type and AND operation are consistent.
246		impl $crate::Maskable<$name> for $name {
247			type Mask = $typ;
248
249			#[inline]
250			fn make_mask(mut selectors: impl Iterator<Item = bool>) -> $typ {
251				<$typ as $crate::underlier::UnderlierType>::fill_with_bit(
252					u8::from(selectors.next().unwrap_or(false)),
253				)
254			}
255
256			#[inline]
257			fn select(&self, mask: &$typ) -> Self {
258				Self(self.0 & *mask)
259			}
260		}
261
262		impl $crate::PackedField for $name {
263			#[inline]
264			fn iter(&self) -> impl Iterator<Item = Self::Scalar> + Send + Clone + '_ {
265				std::iter::once(*self)
266			}
267
268			#[inline]
269			fn into_iter(self) -> impl Iterator<Item = Self::Scalar> + Send + Clone {
270				std::iter::once(self)
271			}
272
273			#[inline]
274			fn iter_slice(slice: &[Self]) -> impl Iterator<Item = Self::Scalar> + Send + Clone + '_ {
275				slice.iter().copied()
276			}
277
278			fn interleave(self, _other: Self, _log_block_len: usize) -> (Self, Self) {
279				panic!("cannot interleave when WIDTH = 1");
280			}
281
282			fn unzip(self, _other: Self, _log_block_len: usize) -> (Self, Self) {
283				panic!("cannot transpose when WIDTH = 1");
284			}
285
286			#[inline]
287			fn from_fn(mut f: impl FnMut(usize) -> Self::Scalar) -> Self {
288				f(0)
289			}
290
291			#[inline]
292			unsafe fn spread_unchecked(self, _log_block_len: usize, _block_idx: usize) -> Self {
293				self
294			}
295		}
296
297		impl ::rand::distr::Distribution<$name> for ::rand::distr::StandardUniform {
298			fn sample<R: ::rand::Rng + ?Sized>(&self, rng: &mut R) -> $name {
299				$name(::rand::distr::StandardUniform.sample(rng))
300			}
301		}
302
303		impl Display for $name {
304			fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
305				write!(f, "0x{repr:0>width$x}", repr=self.val(), width=Self::N_BITS.max(4) / 4)
306			}
307		}
308
309		impl Debug for $name {
310			fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
311				let structure_name = std::any::type_name::<$name>().split("::").last().expect("exist");
312
313				write!(f, "{}({})",structure_name, self)
314			}
315		}
316
317		impl BinaryField for $name {
318			const TRACE_ONE_ELEMENT: Self = $name($trace_one);
319		}
320
321		impl From<$typ> for $name {
322			fn from(val: $typ) -> Self {
323				return Self(val)
324			}
325		}
326
327		impl From<$name> for $typ {
328			fn from(val: $name) -> Self {
329				return val.0
330			}
331		}
332	};
333
334	// Each op lifts the underlier into the width-one packing, runs its arithmetic, and lowers back.
335	(@arithmetic_via_packed $name:ident, $typ:ty) => {
336		impl Mul<Self> for $name {
337			type Output = Self;
338
339			#[inline]
340			fn mul(self, rhs: Self) -> Self {
341				$crate::tracing::trace_multiplication!($name);
342				type P = $crate::arch::PackedPrimitiveType<$typ, $name>;
343				Self((P::from_underlier(self.0) * P::from_underlier(rhs.0)).to_underlier())
344			}
345		}
346
347		impl $crate::arithmetic_traits::Square for $name {
348			#[inline]
349			fn square(self) -> Self {
350				type P = $crate::arch::PackedPrimitiveType<$typ, $name>;
351				Self(
352					$crate::arithmetic_traits::Square::square(P::from_underlier(self.0)).to_underlier(),
353				)
354			}
355		}
356
357		impl $crate::arithmetic_traits::InvertOrZero for $name {
358			#[inline]
359			fn invert_or_zero(self) -> Self {
360				type P = $crate::arch::PackedPrimitiveType<$typ, $name>;
361				Self(
362					$crate::arithmetic_traits::InvertOrZero::invert_or_zero(P::from_underlier(self.0))
363						.to_underlier(),
364				)
365			}
366		}
367
368		impl $crate::arithmetic_traits::WideMul for $name {
369			type Output = <$crate::arch::PackedPrimitiveType<$typ, $name> as $crate::arithmetic_traits::WideMul>::Output;
370
371			#[inline]
372			fn wide_mul(a: Self, b: Self) -> Self::Output {
373				type P = $crate::arch::PackedPrimitiveType<$typ, $name>;
374				<P as $crate::arithmetic_traits::WideMul>::wide_mul(
375					P::from_underlier(a.0),
376					P::from_underlier(b.0),
377				)
378			}
379
380			#[inline]
381			fn reduce(wide: Self::Output) -> Self {
382				type P = $crate::arch::PackedPrimitiveType<$typ, $name>;
383				Self(<P as $crate::arithmetic_traits::WideMul>::reduce(wide).to_underlier())
384			}
385		}
386	};
387}
388
389pub(crate) use binary_field;
390
391macro_rules! mul_by_binary_field_1b {
392	($name:ident) => {
393		impl Mul<BinaryField1b> for $name {
394			type Output = Self;
395
396			#[inline]
397			#[allow(clippy::suspicious_arithmetic_impl)]
398			fn mul(self, rhs: BinaryField1b) -> Self::Output {
399				use $crate::underlier::{UnderlierType, WithUnderlier};
400
401				$crate::tracing::trace_multiplication!(BinaryField128b, BinaryField1b);
402
403				Self(self.0 & <$name as WithUnderlier>::Underlier::fill_with_bit(u8::from(rhs.0)))
404			}
405		}
406	};
407}
408
409pub(crate) use mul_by_binary_field_1b;
410
411macro_rules! impl_field_extension {
412	($subfield_name:ident($subfield_typ:ty) < @$log_degree:expr => $name:ident($typ:ty)) => {
413		impl TryFrom<$name> for $subfield_name {
414			type Error = ();
415
416			#[inline]
417			fn try_from(elem: $name) -> Result<Self, Self::Error> {
418				use $crate::underlier::{Divisible, UnderlierType};
419
420				// `elem` lies in the subfield iff every subfield-underlier limb above the
421				// least-significant one is zero (equivalent to `elem >> N_BITS == 0`).
422				let in_subfield = Divisible::<$subfield_typ>::ref_iter(&elem.0)
423					.skip(1)
424					.all(|limb| limb == <$subfield_typ as UnderlierType>::ZERO);
425				if in_subfield {
426					Ok($subfield_name(Divisible::<$subfield_typ>::get(&elem.0, 0)))
427				} else {
428					Err(())
429				}
430			}
431		}
432
433		impl From<$subfield_name> for $name {
434			#[inline]
435			fn from(elem: $subfield_name) -> Self {
436				$name(<$typ>::from(elem.val()))
437			}
438		}
439
440		impl Add<$subfield_name> for $name {
441			type Output = Self;
442
443			#[inline]
444			fn add(self, rhs: $subfield_name) -> Self::Output {
445				self + Self::from(rhs)
446			}
447		}
448
449		impl Sub<$subfield_name> for $name {
450			type Output = Self;
451
452			#[inline]
453			fn sub(self, rhs: $subfield_name) -> Self::Output {
454				self - Self::from(rhs)
455			}
456		}
457
458		impl AddAssign<$subfield_name> for $name {
459			#[inline]
460			fn add_assign(&mut self, rhs: $subfield_name) {
461				*self = *self + rhs;
462			}
463		}
464
465		impl SubAssign<$subfield_name> for $name {
466			#[inline]
467			fn sub_assign(&mut self, rhs: $subfield_name) {
468				*self = *self - rhs;
469			}
470		}
471
472		impl MulAssign<$subfield_name> for $name {
473			#[inline]
474			fn mul_assign(&mut self, rhs: $subfield_name) {
475				*self = *self * rhs;
476			}
477		}
478
479		impl Add<$name> for $subfield_name {
480			type Output = $name;
481
482			#[inline]
483			fn add(self, rhs: $name) -> Self::Output {
484				rhs + self
485			}
486		}
487
488		impl Sub<$name> for $subfield_name {
489			type Output = $name;
490
491			#[allow(clippy::suspicious_arithmetic_impl)]
492			#[inline]
493			fn sub(self, rhs: $name) -> Self::Output {
494				rhs + self
495			}
496		}
497
498		impl Mul<$name> for $subfield_name {
499			type Output = $name;
500
501			#[inline]
502			fn mul(self, rhs: $name) -> Self::Output {
503				rhs * self
504			}
505		}
506
507		impl ExtensionField<$subfield_name> for $name {
508			const LOG_DEGREE: usize = $log_degree;
509
510			#[inline]
511			fn basis(i: usize) -> Self {
512				use $crate::underlier::{Divisible, UnderlierType};
513
514				assert!(
515					i < 1 << $log_degree,
516					"index {} out of range for degree {}",
517					i,
518					1 << $log_degree
519				);
520				// The `i`-th basis element sets subfield-underlier limb `i` to one, i.e. bit
521				// `i * N_BITS` (equivalent to `ONE << (i * N_BITS)`).
522				let mut underlier = <$typ as UnderlierType>::ZERO;
523				Divisible::<$subfield_typ>::set(
524					&mut underlier,
525					i,
526					<$subfield_typ as UnderlierType>::ONE,
527				);
528				Self(underlier)
529			}
530
531			#[inline]
532			fn from_bases_sparse(
533				base_elems: impl IntoIterator<Item = $subfield_name>,
534				log_stride: usize,
535			) -> Self {
536				use $crate::underlier::{Divisible, UnderlierType};
537
538				debug_assert!($name::N_BITS.is_power_of_two());
539				let shift_step = ($subfield_name::N_BITS << log_stride) & ($name::N_BITS - 1);
540				let mut underlier = <$typ as UnderlierType>::ZERO;
541				let mut shift = 0;
542
543				for elem in base_elems.into_iter() {
544					assert!(shift < $name::N_BITS, "too many base elements for extension degree");
545					// `shift` is a multiple of the subfield width, so it addresses limb
546					// `shift / N_BITS`; OR the element in (matching the previous `|= .. << shift`).
547					let limb = shift / $subfield_name::N_BITS;
548					let acc = Divisible::<$subfield_typ>::get(&underlier, limb) | elem.val();
549					Divisible::<$subfield_typ>::set(&mut underlier, limb, acc);
550					shift += shift_step;
551				}
552
553				Self(underlier)
554			}
555
556			#[inline]
557			fn iter_bases(&self) -> impl Iterator<Item = $subfield_name> {
558				use binius_utils::iter::IterExtensions;
559				use $crate::underlier::{Divisible, WithUnderlier};
560
561				Divisible::<<$subfield_name as WithUnderlier>::Underlier>::ref_iter(&self.0)
562					.map_skippable($subfield_name::from)
563			}
564
565			#[inline]
566			unsafe fn get_base_unchecked(&self, i: usize) -> $subfield_name {
567				use $crate::underlier::{Divisible, WithUnderlier};
568				// Safety: the caller guarantees `i < Self::N` (over subfield elements).
569				unsafe {
570					$subfield_name::from_underlier(Divisible::<
571						<$subfield_name as WithUnderlier>::Underlier,
572					>::get_unchecked(&self.to_underlier(), i))
573				}
574			}
575
576			#[inline]
577			fn square_transpose(values: &mut [Self]) {
578				crate::transpose::square_transforms_extension_field::<$subfield_name, Self>(values)
579			}
580		}
581	};
582}
583
584pub(crate) use impl_field_extension;
585
586// The trace over the prime field is the identity here, so `ONE` is the only trace-1 element.
587binary_field!(pub BinaryField1b(U1), U1::new(0x1), U1::new(0x1));
588
589macro_rules! serialize_deserialize {
590	($bin_type:ty) => {
591		impl SerializeBytes for $bin_type {
592			fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
593				self.0.serialize(write_buf)
594			}
595		}
596
597		impl DeserializeBytes for $bin_type {
598			fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError> {
599				Ok(Self(DeserializeBytes::deserialize(read_buf)?))
600			}
601		}
602	};
603}
604
605serialize_deserialize!(BinaryField1b);
606
607impl FixedSizeSerializeBytes for BinaryField1b {
608	const BYTE_SIZE: usize = 1;
609}
610
611impl BinaryField1b {
612	pub const fn new(value: U1) -> Self {
613		Self(value)
614	}
615}
616
617impl From<u8> for BinaryField1b {
618	#[inline]
619	fn from(val: u8) -> Self {
620		Self::new(U1::new(val))
621	}
622}
623
624impl From<BinaryField1b> for u8 {
625	#[inline]
626	fn from(value: BinaryField1b) -> Self {
627		value.val().into()
628	}
629}
630
631impl From<bool> for BinaryField1b {
632	#[inline]
633	fn from(value: bool) -> Self {
634		Self::from(U1::new_unchecked(value.into()))
635	}
636}
637
638#[cfg(test)]
639pub(crate) mod tests {
640	use binius_utils::{DeserializeBytes, SerializeBytes, bytes::BytesMut};
641	use proptest::prelude::*;
642
643	use super::BinaryField1b as BF1;
644	use crate::{
645		AESTowerField8b, BinaryField, BinaryField1b, BinaryField128bGhash, ExtensionField, Field,
646		GhashSq256b, arithmetic_traits::InvertOrZero,
647	};
648
649	#[test]
650	fn test_gf2_add() {
651		assert_eq!(BF1::from(0) + BF1::from(0), BF1::from(0));
652		assert_eq!(BF1::from(0) + BF1::from(1), BF1::from(1));
653		assert_eq!(BF1::from(1) + BF1::from(0), BF1::from(1));
654		assert_eq!(BF1::from(1) + BF1::from(1), BF1::from(0));
655	}
656
657	#[test]
658	fn test_gf2_sub() {
659		assert_eq!(BF1::from(0) - BF1::from(0), BF1::from(0));
660		assert_eq!(BF1::from(0) - BF1::from(1), BF1::from(1));
661		assert_eq!(BF1::from(1) - BF1::from(0), BF1::from(1));
662		assert_eq!(BF1::from(1) - BF1::from(1), BF1::from(0));
663	}
664
665	#[test]
666	fn test_gf2_mul() {
667		assert_eq!(BF1::from(0) * BF1::from(0), BF1::from(0));
668		assert_eq!(BF1::from(0) * BF1::from(1), BF1::from(0));
669		assert_eq!(BF1::from(1) * BF1::from(0), BF1::from(0));
670		assert_eq!(BF1::from(1) * BF1::from(1), BF1::from(1));
671	}
672
673	pub(crate) fn is_binary_field_valid_generator<F: BinaryField>() -> bool {
674		// Binary fields should contain a multiplicative subgroup of size 2^n - 1
675		let mut order = if F::N_BITS == 128 {
676			u128::MAX
677		} else {
678			(1 << F::N_BITS) - 1
679		};
680
681		// Naive factorization of group order - represented as a multiset of prime factors
682		let mut factorization = Vec::new();
683
684		let mut prime = 2;
685		while prime * prime <= order {
686			while order.is_multiple_of(prime) {
687				order /= prime;
688				factorization.push(prime);
689			}
690
691			prime += if prime > 2 { 2 } else { 1 };
692		}
693
694		if order > 1 {
695			factorization.push(order);
696		}
697
698		// Iterate over all divisors (some may be tested several times if order is non-square-free)
699		for mask in 0..(1 << factorization.len()) {
700			let mut divisor = 1;
701
702			for (bit_index, &prime) in factorization.iter().enumerate() {
703				if (1 << bit_index) & mask != 0 {
704					divisor *= prime;
705				}
706			}
707
708			// Compute pow(generator, divisor) in log time
709			divisor = divisor.reverse_bits();
710
711			let mut pow_divisor = F::ONE;
712			while divisor > 0 {
713				pow_divisor *= pow_divisor;
714
715				if divisor & 1 != 0 {
716					pow_divisor *= F::MULTIPLICATIVE_GENERATOR;
717				}
718
719				divisor >>= 1;
720			}
721
722			// Generator invariant
723			let is_root_of_unity = pow_divisor == F::ONE;
724			let is_full_group = mask + 1 == 1 << factorization.len();
725
726			if is_root_of_unity && !is_full_group || !is_root_of_unity && is_full_group {
727				return false;
728			}
729		}
730
731		true
732	}
733
734	#[test]
735	fn test_multiplicative_generators() {
736		assert!(is_binary_field_valid_generator::<BinaryField1b>());
737		assert!(is_binary_field_valid_generator::<AESTowerField8b>());
738		assert!(is_binary_field_valid_generator::<BinaryField128bGhash>());
739	}
740
741	/// The absolute trace $\operatorname{Tr}(x) = \sum_{i=0}^{n-1} x^{2^i}$, computed by repeated
742	/// squaring rather than by any property of the field's representation.
743	fn trace<F: BinaryField>(x: F) -> F {
744		let mut acc = F::ZERO;
745		let mut square = x;
746		for _ in 0..F::N_BITS {
747			acc += square;
748			square = square.square();
749		}
750		acc
751	}
752
753	/// Every field's declared element really has trace 1.
754	///
755	/// A wrong constant would not fail loudly on its own: the Gao-Mateer basis it seeds asserts
756	/// $\beta_0 = 1$, so it would surface as a panic deep inside NTT setup rather than here.
757	#[test]
758	fn test_trace_one_elements() {
759		fn check<F: BinaryField>() {
760			assert_eq!(trace(F::TRACE_ONE_ELEMENT), F::ONE);
761		}
762		check::<BinaryField1b>();
763		check::<AESTowerField8b>();
764		check::<BinaryField128bGhash>();
765		check::<GhashSq256b>();
766	}
767
768	/// The trace lands in $\mathbb{F}_2$ for every element, not just the declared one. This pins
769	/// the helper above, so a `trace` that silently computed something else could not make the
770	/// previous test pass.
771	#[test]
772	fn test_trace_lands_in_the_prime_subfield() {
773		for value in 0..=u8::MAX {
774			let t = trace(AESTowerField8b::new(value));
775			assert!(t == AESTowerField8b::ZERO || t == AESTowerField8b::ONE, "value {value:#04x}");
776		}
777	}
778
779	#[test]
780	fn test_field_degrees() {
781		assert_eq!(BinaryField1b::N_BITS, 1);
782		assert_eq!(AESTowerField8b::N_BITS, 8);
783		assert_eq!(BinaryField128bGhash::N_BITS, 128);
784	}
785
786	#[test]
787	fn test_field_formatting() {
788		assert_eq!(format!("{}", BinaryField1b::from(1)), "0x1");
789		assert_eq!(format!("{}", AESTowerField8b::from(3)), "0x03");
790		assert_eq!(
791			format!("{}", BinaryField128bGhash::new(5)),
792			"0x00000000000000000000000000000005"
793		);
794	}
795
796	#[test]
797	fn test_inverse_on_zero() {
798		assert!(BinaryField1b::ZERO.invert_or_zero().is_zero());
799		assert!(AESTowerField8b::ZERO.invert_or_zero().is_zero());
800		assert!(BinaryField128bGhash::ZERO.invert_or_zero().is_zero());
801	}
802
803	proptest! {
804		#[test]
805		fn test_inverse_8b(val in 1u8..) {
806			let x = AESTowerField8b::new(val);
807			// Safety: `val` is in `1..`, so `x` is non-zero.
808			let x_inverse = unsafe { x.invert() };
809			assert_eq!(x * x_inverse, AESTowerField8b::ONE);
810		}
811
812		#[test]
813		fn test_inverse_128b(val in 1u128..) {
814			let x = BinaryField128bGhash::from(val);
815			// Safety: `val` is in `1..`, so `x` is non-zero.
816			let x_inverse = unsafe { x.invert() };
817			assert_eq!(x * x_inverse, BinaryField128bGhash::ONE);
818		}
819	}
820
821	/// Checks the `TryFrom` conversion narrowing an extension field element to its subfield:
822	/// elements embedded from the subfield must round-trip, and elements with a nonzero
823	/// coefficient outside the subfield must be rejected.
824	fn assert_subfield_extraction<FSub: Field, F: ExtensionField<FSub>>() {
825		assert_eq!(TryInto::<FSub>::try_into(F::from(FSub::ZERO)).ok(), Some(FSub::ZERO));
826
827		// `BinaryField1b` has a trivial multiplicative group, so for the three pairs with that
828		// subfield this sweeps `ONE` alone, which together with `ZERO` is already the whole field.
829		// Only `BinaryField128bGhash` in `GhashSq256b` walks non-trivial subfield values.
830		let mut elem = FSub::ONE;
831		for _ in 0..4 {
832			assert_eq!(TryInto::<FSub>::try_into(F::from(elem)).ok(), Some(elem));
833			elem *= FSub::MULTIPLICATIVE_GENERATOR;
834		}
835
836		// `basis(i)` for `i > 0` has a zero coefficient of `1` and a nonzero higher coefficient,
837		// so it lies outside the subfield - with or without a subfield part added on.
838		for i in 1..F::DEGREE {
839			assert!(TryInto::<FSub>::try_into(F::basis(i)).is_err());
840			assert!(TryInto::<FSub>::try_into(F::basis(i) + F::ONE).is_err());
841		}
842	}
843
844	#[test]
845	fn test_subfield_extraction() {
846		assert_subfield_extraction::<BinaryField1b, BinaryField128bGhash>();
847		assert_subfield_extraction::<BinaryField1b, AESTowerField8b>();
848		assert_subfield_extraction::<BinaryField128bGhash, GhashSq256b>();
849		assert_subfield_extraction::<BinaryField1b, GhashSq256b>();
850	}
851
852	#[test]
853	fn test_serialization() {
854		let mut buffer = BytesMut::new();
855		let b1 = BinaryField1b::from(0x1);
856		let b8 = AESTowerField8b::new(0x12);
857		let b128 = BinaryField128bGhash::new(0x147AD0369CF258BE8899AABBCCDDEEFF);
858
859		b1.serialize(&mut buffer).unwrap();
860		b8.serialize(&mut buffer).unwrap();
861		b128.serialize(&mut buffer).unwrap();
862
863		let mut read_buffer = buffer.freeze();
864
865		assert_eq!(BinaryField1b::deserialize(&mut read_buffer).unwrap(), b1);
866		assert_eq!(AESTowerField8b::deserialize(&mut read_buffer).unwrap(), b8);
867		assert_eq!(BinaryField128bGhash::deserialize(&mut read_buffer).unwrap(), b128);
868	}
869}