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
26/// Macro to generate an implementation of a BinaryField.
27macro_rules! binary_field {
28	($vis:vis $name:ident($typ:ty), $gen:expr) => {
29		#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroable, bytemuck::TransparentWrapper)]
30		#[repr(transparent)]
31		$vis struct $name(pub(crate) $typ);
32
33		// NOTE: `new` is intentionally NOT generated here. Each field defines its own `new` so it
34		// can take an ergonomic constructor type independent of the underlier (e.g.
35		// `BinaryField128bGhash::new` takes `u128` even though its underlier is `M128`).
36		impl $name {
37			pub const fn val(self) -> $typ {
38				self.0
39			}
40		}
41
42		unsafe impl $crate::underlier::WithUnderlier for $name {
43			type Underlier = $typ;
44		}
45
46		impl Neg for $name {
47			type Output = Self;
48
49			fn neg(self) -> Self::Output {
50				self
51			}
52		}
53
54		impl Add<Self> for $name {
55			type Output = Self;
56
57			#[allow(clippy::suspicious_arithmetic_impl)]
58			fn add(self, rhs: Self) -> Self::Output {
59				$name(self.0 ^ rhs.0)
60			}
61		}
62
63		impl Add<&Self> for $name {
64			type Output = Self;
65
66			#[allow(clippy::suspicious_arithmetic_impl)]
67			fn add(self, rhs: &Self) -> Self::Output {
68				$name(self.0 ^ rhs.0)
69			}
70		}
71
72		impl Sub<Self> for $name {
73			type Output = Self;
74
75			#[allow(clippy::suspicious_arithmetic_impl)]
76			fn sub(self, rhs: Self) -> Self::Output {
77				$name(self.0 ^ rhs.0)
78			}
79		}
80
81		impl Sub<&Self> for $name {
82			type Output = Self;
83
84			#[allow(clippy::suspicious_arithmetic_impl)]
85			fn sub(self, rhs: &Self) -> Self::Output {
86				$name(self.0 ^ rhs.0)
87			}
88		}
89
90		impl Mul<&Self> for $name {
91			type Output = Self;
92
93			fn mul(self, rhs: &Self) -> Self::Output {
94				self * *rhs
95			}
96		}
97
98		impl AddAssign<Self> for $name {
99			fn add_assign(&mut self, rhs: Self) {
100				*self = *self + rhs;
101			}
102		}
103
104		impl AddAssign<&Self> for $name {
105			fn add_assign(&mut self, rhs: &Self) {
106				*self = *self + *rhs;
107			}
108		}
109
110		impl SubAssign<Self> for $name {
111			fn sub_assign(&mut self, rhs: Self) {
112				*self = *self - rhs;
113			}
114		}
115
116		impl SubAssign<&Self> for $name {
117			fn sub_assign(&mut self, rhs: &Self) {
118				*self = *self - *rhs;
119			}
120		}
121
122		impl MulAssign<Self> for $name {
123			fn mul_assign(&mut self, rhs: Self) {
124				*self = *self * rhs;
125			}
126		}
127
128		impl MulAssign<&Self> for $name {
129			fn mul_assign(&mut self, rhs: &Self) {
130				*self = *self * rhs;
131			}
132		}
133
134		impl Sum<Self> for $name {
135			fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
136				iter.fold(Self::ZERO, |acc, x| acc + x)
137			}
138		}
139
140		impl<'a> Sum<&'a Self> for $name {
141			fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
142				iter.fold(Self::ZERO, |acc, x| acc + x)
143			}
144		}
145
146		impl Product<Self> for $name {
147			fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
148				iter.fold(Self::ONE, |acc, x| acc * x)
149			}
150		}
151
152		impl<'a> Product<&'a Self> for $name {
153			fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
154				iter.fold(Self::ONE, |acc, x| acc * x)
155			}
156		}
157
158
159		impl Field for $name {
160			const ZERO: Self = $name(<$typ as $crate::underlier::UnderlierType>::ZERO);
161			const ONE: Self = $name(<$typ as $crate::underlier::UnderlierType>::ONE);
162			const CHARACTERISTIC: usize = 2;
163			const ORDER_EXPONENT: usize = <$typ as $crate::underlier::UnderlierType>::BITS;
164			const MULTIPLICATIVE_GENERATOR: $name = $name($gen);
165
166			fn double(&self) -> Self {
167				Self::ZERO
168			}
169		}
170
171		// A field element divides into exactly one element of itself. This makes the field a
172		// degenerate packed field of width one (see the blanket `PackedField for Field` impl).
173		impl $crate::Divisible<$name> for $name {
174			const LOG_N: usize = 0;
175
176			#[inline]
177			fn value_iter(value: Self) -> impl ExactSizeIterator<Item = $name> + Send + Clone {
178				std::iter::once(value)
179			}
180
181			#[inline]
182			fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = $name> + Send + Clone + '_ {
183				std::iter::once(*value)
184			}
185
186			#[inline]
187			fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = $name> + Send + Clone + '_ {
188				slice.iter().copied()
189			}
190
191			#[inline]
192			unsafe fn get_unchecked(&self, _index: usize) -> $name {
193				*self
194			}
195
196			#[inline]
197			unsafe fn set_unchecked(&mut self, _index: usize, val: $name) {
198				*self = val;
199			}
200
201			#[inline]
202			fn broadcast(val: $name) -> Self {
203				val
204			}
205
206			#[inline]
207			fn from_iter(mut iter: impl Iterator<Item = $name>) -> Self {
208				iter.next().unwrap_or(Self::ZERO)
209			}
210		}
211
212		// As a width-one packed field, a field element is masked by its single selector: kept
213		// when selected, otherwise zeroed. Uses the same underlier bitmask strategy as
214		// PackedPrimitiveType so the mask type and AND operation are consistent.
215		impl $crate::Maskable<$name> for $name {
216			type Mask = $typ;
217
218			#[inline]
219			fn make_mask(mut selectors: impl Iterator<Item = bool>) -> $typ {
220				<$typ as $crate::underlier::UnderlierType>::fill_with_bit(
221					u8::from(selectors.next().unwrap_or(false)),
222				)
223			}
224
225			#[inline]
226			fn select(&self, mask: &$typ) -> Self {
227				Self(self.0 & *mask)
228			}
229		}
230
231		impl ::rand::distr::Distribution<$name> for ::rand::distr::StandardUniform {
232			fn sample<R: ::rand::Rng + ?Sized>(&self, rng: &mut R) -> $name {
233				$name(::rand::distr::StandardUniform.sample(rng))
234			}
235		}
236
237		impl Display for $name {
238			fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
239				write!(f, "0x{repr:0>width$x}", repr=self.val(), width=Self::N_BITS.max(4) / 4)
240			}
241		}
242
243		impl Debug for $name {
244			fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
245				let structure_name = std::any::type_name::<$name>().split("::").last().expect("exist");
246
247				write!(f, "{}({})",structure_name, self)
248			}
249		}
250
251		impl BinaryField for $name {}
252
253		impl From<$typ> for $name {
254			fn from(val: $typ) -> Self {
255				return Self(val)
256			}
257		}
258
259		impl From<$name> for $typ {
260			fn from(val: $name) -> Self {
261				return val.0
262			}
263		}
264	}
265}
266
267pub(crate) use binary_field;
268
269macro_rules! mul_by_binary_field_1b {
270	($name:ident) => {
271		impl Mul<BinaryField1b> for $name {
272			type Output = Self;
273
274			#[inline]
275			#[allow(clippy::suspicious_arithmetic_impl)]
276			fn mul(self, rhs: BinaryField1b) -> Self::Output {
277				use $crate::underlier::{UnderlierType, WithUnderlier};
278
279				$crate::tracing::trace_multiplication!(BinaryField128b, BinaryField1b);
280
281				Self(self.0 & <$name as WithUnderlier>::Underlier::fill_with_bit(u8::from(rhs.0)))
282			}
283		}
284	};
285}
286
287pub(crate) use mul_by_binary_field_1b;
288
289macro_rules! impl_field_extension {
290	($subfield_name:ident($subfield_typ:ty) < @$log_degree:expr => $name:ident($typ:ty)) => {
291		impl TryFrom<$name> for $subfield_name {
292			type Error = ();
293
294			#[inline]
295			fn try_from(elem: $name) -> Result<Self, Self::Error> {
296				use $crate::underlier::{Divisible, NumCast, UnderlierType};
297
298				// `elem` lies in the subfield iff every subfield-underlier limb above the
299				// least-significant one is zero (equivalent to `elem >> N_BITS == 0`).
300				let in_subfield = Divisible::<$subfield_typ>::ref_iter(&elem.0)
301					.skip(1)
302					.all(|limb| limb == <$subfield_typ as UnderlierType>::ZERO);
303				if in_subfield {
304					Ok($subfield_name(<$subfield_typ>::num_cast_from(elem.val())))
305				} else {
306					Err(())
307				}
308			}
309		}
310
311		impl From<$subfield_name> for $name {
312			#[inline]
313			fn from(elem: $subfield_name) -> Self {
314				$name(<$typ>::from(elem.val()))
315			}
316		}
317
318		impl Add<$subfield_name> for $name {
319			type Output = Self;
320
321			#[inline]
322			fn add(self, rhs: $subfield_name) -> Self::Output {
323				self + Self::from(rhs)
324			}
325		}
326
327		impl Sub<$subfield_name> for $name {
328			type Output = Self;
329
330			#[inline]
331			fn sub(self, rhs: $subfield_name) -> Self::Output {
332				self - Self::from(rhs)
333			}
334		}
335
336		impl AddAssign<$subfield_name> for $name {
337			#[inline]
338			fn add_assign(&mut self, rhs: $subfield_name) {
339				*self = *self + rhs;
340			}
341		}
342
343		impl SubAssign<$subfield_name> for $name {
344			#[inline]
345			fn sub_assign(&mut self, rhs: $subfield_name) {
346				*self = *self - rhs;
347			}
348		}
349
350		impl MulAssign<$subfield_name> for $name {
351			#[inline]
352			fn mul_assign(&mut self, rhs: $subfield_name) {
353				*self = *self * rhs;
354			}
355		}
356
357		impl Add<$name> for $subfield_name {
358			type Output = $name;
359
360			#[inline]
361			fn add(self, rhs: $name) -> Self::Output {
362				rhs + self
363			}
364		}
365
366		impl Sub<$name> for $subfield_name {
367			type Output = $name;
368
369			#[allow(clippy::suspicious_arithmetic_impl)]
370			#[inline]
371			fn sub(self, rhs: $name) -> Self::Output {
372				rhs + self
373			}
374		}
375
376		impl Mul<$name> for $subfield_name {
377			type Output = $name;
378
379			#[inline]
380			fn mul(self, rhs: $name) -> Self::Output {
381				rhs * self
382			}
383		}
384
385		impl ExtensionField<$subfield_name> for $name {
386			const LOG_DEGREE: usize = $log_degree;
387
388			#[inline]
389			fn basis(i: usize) -> Self {
390				use $crate::underlier::{Divisible, UnderlierType};
391
392				assert!(
393					i < 1 << $log_degree,
394					"index {} out of range for degree {}",
395					i,
396					1 << $log_degree
397				);
398				// The `i`-th basis element sets subfield-underlier limb `i` to one, i.e. bit
399				// `i * N_BITS` (equivalent to `ONE << (i * N_BITS)`).
400				let mut underlier = <$typ as UnderlierType>::ZERO;
401				Divisible::<$subfield_typ>::set(
402					&mut underlier,
403					i,
404					<$subfield_typ as UnderlierType>::ONE,
405				);
406				Self(underlier)
407			}
408
409			#[inline]
410			fn from_bases_sparse(
411				base_elems: impl IntoIterator<Item = $subfield_name>,
412				log_stride: usize,
413			) -> Self {
414				use $crate::underlier::{Divisible, UnderlierType};
415
416				debug_assert!($name::N_BITS.is_power_of_two());
417				let shift_step = ($subfield_name::N_BITS << log_stride) & ($name::N_BITS - 1);
418				let mut underlier = <$typ as UnderlierType>::ZERO;
419				let mut shift = 0;
420
421				for elem in base_elems.into_iter() {
422					assert!(shift < $name::N_BITS, "too many base elements for extension degree");
423					// `shift` is a multiple of the subfield width, so it addresses limb
424					// `shift / N_BITS`; OR the element in (matching the previous `|= .. << shift`).
425					let limb = shift / $subfield_name::N_BITS;
426					let acc = Divisible::<$subfield_typ>::get(&underlier, limb) | elem.val();
427					Divisible::<$subfield_typ>::set(&mut underlier, limb, acc);
428					shift += shift_step;
429				}
430
431				Self(underlier)
432			}
433
434			#[inline]
435			fn iter_bases(&self) -> impl Iterator<Item = $subfield_name> {
436				use binius_utils::iter::IterExtensions;
437				use $crate::underlier::{Divisible, WithUnderlier};
438
439				Divisible::<<$subfield_name as WithUnderlier>::Underlier>::ref_iter(&self.0)
440					.map_skippable($subfield_name::from)
441			}
442
443			#[inline]
444			fn into_iter_bases(self) -> impl Iterator<Item = $subfield_name> {
445				use binius_utils::iter::IterExtensions;
446				use $crate::underlier::{Divisible, WithUnderlier};
447
448				Divisible::<<$subfield_name as WithUnderlier>::Underlier>::value_iter(self.0)
449					.map_skippable($subfield_name::from)
450			}
451
452			#[inline]
453			unsafe fn get_base_unchecked(&self, i: usize) -> $subfield_name {
454				use $crate::underlier::{Divisible, WithUnderlier};
455				// Safety: the caller guarantees `i < Self::N` (over subfield elements).
456				unsafe {
457					$subfield_name::from_underlier(Divisible::<
458						<$subfield_name as WithUnderlier>::Underlier,
459					>::get_unchecked(&self.to_underlier(), i))
460				}
461			}
462
463			#[inline]
464			fn square_transpose(values: &mut [Self]) {
465				crate::transpose::square_transforms_extension_field::<$subfield_name, Self>(values)
466			}
467		}
468	};
469}
470
471pub(crate) use impl_field_extension;
472
473binary_field!(pub BinaryField1b(U1), U1::new(0x1));
474
475crate::arithmetic_traits::impl_trivial_wide_mul!(BinaryField1b);
476
477macro_rules! serialize_deserialize {
478	($bin_type:ty) => {
479		impl SerializeBytes for $bin_type {
480			fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
481				self.0.serialize(write_buf)
482			}
483		}
484
485		impl DeserializeBytes for $bin_type {
486			fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError> {
487				Ok(Self(DeserializeBytes::deserialize(read_buf)?))
488			}
489		}
490	};
491}
492
493serialize_deserialize!(BinaryField1b);
494
495impl FixedSizeSerializeBytes for BinaryField1b {
496	const BYTE_SIZE: usize = 1;
497}
498
499impl BinaryField1b {
500	pub const fn new(value: U1) -> Self {
501		Self(value)
502	}
503
504	/// Creates value without checking that it is within valid range (0 or 1)
505	///
506	/// # Safety
507	/// Value should not exceed 1
508	#[inline]
509	pub unsafe fn new_unchecked(val: u8) -> Self {
510		debug_assert!(val < 2, "val has to be less than 2, but it's {val}");
511
512		Self::new(U1::new_unchecked(val))
513	}
514}
515
516impl From<u8> for BinaryField1b {
517	#[inline]
518	fn from(val: u8) -> Self {
519		Self::new(U1::new(val))
520	}
521}
522
523impl From<BinaryField1b> for u8 {
524	#[inline]
525	fn from(value: BinaryField1b) -> Self {
526		value.val().into()
527	}
528}
529
530impl From<bool> for BinaryField1b {
531	#[inline]
532	fn from(value: bool) -> Self {
533		Self::from(U1::new_unchecked(value.into()))
534	}
535}
536
537#[cfg(test)]
538pub(crate) mod tests {
539	use binius_utils::{DeserializeBytes, SerializeBytes, bytes::BytesMut};
540	use proptest::prelude::*;
541
542	use super::BinaryField1b as BF1;
543	use crate::{
544		AESTowerField8b, BinaryField, BinaryField1b, BinaryField128bGhash, Field,
545		arithmetic_traits::InvertOrZero,
546	};
547
548	#[test]
549	fn test_gf2_add() {
550		assert_eq!(BF1::from(0) + BF1::from(0), BF1::from(0));
551		assert_eq!(BF1::from(0) + BF1::from(1), BF1::from(1));
552		assert_eq!(BF1::from(1) + BF1::from(0), BF1::from(1));
553		assert_eq!(BF1::from(1) + BF1::from(1), BF1::from(0));
554	}
555
556	#[test]
557	fn test_gf2_sub() {
558		assert_eq!(BF1::from(0) - BF1::from(0), BF1::from(0));
559		assert_eq!(BF1::from(0) - BF1::from(1), BF1::from(1));
560		assert_eq!(BF1::from(1) - BF1::from(0), BF1::from(1));
561		assert_eq!(BF1::from(1) - BF1::from(1), BF1::from(0));
562	}
563
564	#[test]
565	fn test_gf2_mul() {
566		assert_eq!(BF1::from(0) * BF1::from(0), BF1::from(0));
567		assert_eq!(BF1::from(0) * BF1::from(1), BF1::from(0));
568		assert_eq!(BF1::from(1) * BF1::from(0), BF1::from(0));
569		assert_eq!(BF1::from(1) * BF1::from(1), BF1::from(1));
570	}
571
572	pub(crate) fn is_binary_field_valid_generator<F: BinaryField>() -> bool {
573		// Binary fields should contain a multiplicative subgroup of size 2^n - 1
574		let mut order = if F::N_BITS == 128 {
575			u128::MAX
576		} else {
577			(1 << F::N_BITS) - 1
578		};
579
580		// Naive factorization of group order - represented as a multiset of prime factors
581		let mut factorization = Vec::new();
582
583		let mut prime = 2;
584		while prime * prime <= order {
585			while order.is_multiple_of(prime) {
586				order /= prime;
587				factorization.push(prime);
588			}
589
590			prime += if prime > 2 { 2 } else { 1 };
591		}
592
593		if order > 1 {
594			factorization.push(order);
595		}
596
597		// Iterate over all divisors (some may be tested several times if order is non-square-free)
598		for mask in 0..(1 << factorization.len()) {
599			let mut divisor = 1;
600
601			for (bit_index, &prime) in factorization.iter().enumerate() {
602				if (1 << bit_index) & mask != 0 {
603					divisor *= prime;
604				}
605			}
606
607			// Compute pow(generator, divisor) in log time
608			divisor = divisor.reverse_bits();
609
610			let mut pow_divisor = F::ONE;
611			while divisor > 0 {
612				pow_divisor *= pow_divisor;
613
614				if divisor & 1 != 0 {
615					pow_divisor *= F::MULTIPLICATIVE_GENERATOR;
616				}
617
618				divisor >>= 1;
619			}
620
621			// Generator invariant
622			let is_root_of_unity = pow_divisor == F::ONE;
623			let is_full_group = mask + 1 == 1 << factorization.len();
624
625			if is_root_of_unity && !is_full_group || !is_root_of_unity && is_full_group {
626				return false;
627			}
628		}
629
630		true
631	}
632
633	#[test]
634	fn test_multiplicative_generators() {
635		assert!(is_binary_field_valid_generator::<BinaryField1b>());
636		assert!(is_binary_field_valid_generator::<AESTowerField8b>());
637		assert!(is_binary_field_valid_generator::<BinaryField128bGhash>());
638	}
639
640	#[test]
641	fn test_field_degrees() {
642		assert_eq!(BinaryField1b::N_BITS, 1);
643		assert_eq!(AESTowerField8b::N_BITS, 8);
644		assert_eq!(BinaryField128bGhash::N_BITS, 128);
645	}
646
647	#[test]
648	fn test_field_formatting() {
649		assert_eq!(format!("{}", BinaryField1b::from(1)), "0x1");
650		assert_eq!(format!("{}", AESTowerField8b::from(3)), "0x03");
651		assert_eq!(
652			format!("{}", BinaryField128bGhash::new(5)),
653			"0x00000000000000000000000000000005"
654		);
655	}
656
657	#[test]
658	fn test_inverse_on_zero() {
659		assert!(BinaryField1b::ZERO.invert_or_zero().is_zero());
660		assert!(AESTowerField8b::ZERO.invert_or_zero().is_zero());
661		assert!(BinaryField128bGhash::ZERO.invert_or_zero().is_zero());
662	}
663
664	proptest! {
665		#[test]
666		fn test_inverse_8b(val in 1u8..) {
667			let x = AESTowerField8b::new(val);
668			// Safety: `val` is in `1..`, so `x` is non-zero.
669			let x_inverse = unsafe { x.invert() };
670			assert_eq!(x * x_inverse, AESTowerField8b::ONE);
671		}
672
673		#[test]
674		fn test_inverse_128b(val in 1u128..) {
675			let x = BinaryField128bGhash::from(val);
676			// Safety: `val` is in `1..`, so `x` is non-zero.
677			let x_inverse = unsafe { x.invert() };
678			assert_eq!(x * x_inverse, BinaryField128bGhash::ONE);
679		}
680	}
681
682	#[test]
683	fn test_serialization() {
684		let mut buffer = BytesMut::new();
685		let b1 = BinaryField1b::from(0x1);
686		let b8 = AESTowerField8b::new(0x12);
687		let b128 = BinaryField128bGhash::new(0x147AD0369CF258BE8899AABBCCDDEEFF);
688
689		b1.serialize(&mut buffer).unwrap();
690		b8.serialize(&mut buffer).unwrap();
691		b128.serialize(&mut buffer).unwrap();
692
693		let mut read_buffer = buffer.freeze();
694
695		assert_eq!(BinaryField1b::deserialize(&mut read_buffer).unwrap(), b1);
696		assert_eq!(AESTowerField8b::deserialize(&mut read_buffer).unwrap(), b8);
697		assert_eq!(BinaryField128bGhash::deserialize(&mut read_buffer).unwrap(), b128);
698	}
699
700	#[test]
701	fn test_gf2_new_unchecked() {
702		for i in 0..2 {
703			assert_eq!(unsafe { BF1::new_unchecked(i) }, BF1::from(i));
704		}
705	}
706}