Skip to main content

binius_field/
aes_field.rs

1// Copyright 2024-2025 Irreducible Inc.
2// Copyright 2026 The Binius Developers
3
4use std::{
5	fmt::{Debug, Display, Formatter},
6	iter::{Product, Sum},
7	marker::PhantomData,
8	ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
9};
10
11use binius_utils::{
12	DeserializeBytes, FixedSizeSerializeBytes, SerializationError, SerializeBytes,
13	bytes::{Buf, BufMut},
14};
15use bytemuck::{Pod, Zeroable};
16
17use super::{
18	PackedExtension, PackedSubfield,
19	arithmetic_traits::InvertOrZero,
20	binary_field::{BinaryField, BinaryField1b, binary_field, impl_field_extension},
21	binary_field_arithmetic::TowerFieldArithmetic,
22	mul_by_binary_field_1b,
23};
24use crate::{
25	ExtensionField, Field, TowerField, binary_field_arithmetic::impl_arithmetic_using_packed,
26	linear_transformation::Transformation, underlier::U1,
27};
28
29// These fields represent a tower based on AES GF(2^8) field (GF(256)/x^8+x^4+x^3+x+1)
30// that is isomorphically included into binary tower, i.e.:
31//  - AESTowerField16b is GF(2^16) / (x^2 + x * x_2 + 1) where `x_2` is 0x10 from
32// BinaryField8b isomorphically projected to AESTowerField8b.
33//  - AESTowerField32b is GF(2^32) / (x^2 + x * x_3 + 1), where `x_3` is 0x1000 from
34//    AESTowerField16b.
35//  ...
36binary_field!(pub AESTowerField8b(u8), 0xD0);
37
38crate::arithmetic_traits::impl_trivial_wide_mul!(AESTowerField8b);
39
40unsafe impl Pod for AESTowerField8b {}
41
42impl_field_extension!(BinaryField1b(U1) < @3 => AESTowerField8b(u8));
43
44mul_by_binary_field_1b!(AESTowerField8b);
45
46impl_arithmetic_using_packed!(AESTowerField8b);
47
48impl TowerField for AESTowerField8b {
49	fn min_tower_level(self) -> usize {
50		match self {
51			Self::ZERO | Self::ONE => 0,
52			_ => 3,
53		}
54	}
55}
56
57/// A 3- step transformation :
58/// 1. Cast to base b-bit packed field
59/// 2. Apply linear transformation between aes and binary b8 tower fields
60/// 3. Cast back to the target field
61pub struct SubfieldTransformer<IF, OF, T> {
62	inner_transform: T,
63	_ip_pd: PhantomData<IF>,
64	_op_pd: PhantomData<OF>,
65}
66
67impl<IF, OF, IEP, OEP, T> Transformation<IEP, OEP> for SubfieldTransformer<IF, OF, T>
68where
69	IF: Field,
70	OF: Field,
71	IEP: PackedExtension<IF>,
72	OEP: PackedExtension<OF>,
73	T: Transformation<PackedSubfield<IEP, IF>, PackedSubfield<OEP, OF>>,
74{
75	fn transform(&self, input: &IEP) -> OEP {
76		OEP::cast_ext(self.inner_transform.transform(IEP::cast_base_ref(input)))
77	}
78}
79
80impl SerializeBytes for AESTowerField8b {
81	fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
82		self.0.serialize(write_buf)
83	}
84}
85
86impl DeserializeBytes for AESTowerField8b {
87	fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
88	where
89		Self: Sized,
90	{
91		Ok(Self(DeserializeBytes::deserialize(read_buf)?))
92	}
93}
94
95impl FixedSizeSerializeBytes for AESTowerField8b {
96	const BYTE_SIZE: usize = 1;
97}
98
99#[cfg(test)]
100mod tests {
101	use binius_utils::{SerializeBytes, bytes::BytesMut};
102	use proptest::{arbitrary::any, proptest};
103	use rand::prelude::*;
104
105	use super::*;
106	use crate::{Random, binary_field::tests::is_binary_field_valid_generator};
107
108	fn check_square(f: impl Field) {
109		assert_eq!(f.square(), f * f);
110	}
111
112	proptest! {
113		#[test]
114		fn test_square_8(a in any::<u8>()) {
115			check_square(AESTowerField8b::from(a))
116		}
117	}
118
119	fn check_invert(f: impl Field) {
120		let inversed = f.invert();
121		if f.is_zero() {
122			assert!(inversed.is_none());
123		} else {
124			assert_eq!(inversed.unwrap() * f, Field::ONE);
125		}
126	}
127
128	proptest! {
129		#[test]
130		fn test_invert_8(a in any::<u8>()) {
131			check_invert(AESTowerField8b::from(a))
132		}
133	}
134
135	fn check_mul_by_one<F: Field>(f: F) {
136		assert_eq!(F::ONE * f, f);
137		assert_eq!(f * F::ONE, f);
138	}
139
140	fn check_commutative<F: Field>(f_1: F, f_2: F) {
141		assert_eq!(f_1 * f_2, f_2 * f_1);
142	}
143
144	fn check_associativity_and_lineraity<F: Field>(f_1: F, f_2: F, f_3: F) {
145		assert_eq!(f_1 * (f_2 * f_3), (f_1 * f_2) * f_3);
146		assert_eq!(f_1 * (f_2 + f_3), f_1 * f_2 + f_1 * f_3);
147	}
148
149	fn check_mul<F: Field>(f_1: F, f_2: F, f_3: F) {
150		check_mul_by_one(f_1);
151		check_mul_by_one(f_2);
152		check_mul_by_one(f_3);
153
154		check_commutative(f_1, f_2);
155		check_commutative(f_1, f_3);
156		check_commutative(f_2, f_3);
157
158		check_associativity_and_lineraity(f_1, f_2, f_3);
159		check_associativity_and_lineraity(f_1, f_3, f_2);
160		check_associativity_and_lineraity(f_2, f_1, f_3);
161		check_associativity_and_lineraity(f_2, f_3, f_1);
162		check_associativity_and_lineraity(f_3, f_1, f_2);
163		check_associativity_and_lineraity(f_3, f_2, f_1);
164	}
165
166	proptest! {
167		#[test]
168		fn test_mul_8(a in any::<u8>(), b in any::<u8>(), c in any::<u8>()) {
169			check_mul(AESTowerField8b::from(a), AESTowerField8b::from(b), AESTowerField8b::from(c))
170		}
171	}
172
173	#[test]
174	fn test_multiplicative_generators() {
175		assert!(is_binary_field_valid_generator::<AESTowerField8b>());
176	}
177
178	#[test]
179	fn test_serialization() {
180		let mut buffer = BytesMut::new();
181		let mut rng = StdRng::seed_from_u64(0);
182		let aes8 = AESTowerField8b::random(&mut rng);
183
184		SerializeBytes::serialize(&aes8, &mut buffer).unwrap();
185
186		let mut read_buffer = buffer.freeze();
187
188		assert_eq!(AESTowerField8b::deserialize(&mut read_buffer).unwrap(), aes8);
189	}
190}