Skip to main content

binius_field/
binary_field.rs

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