binius_field/
packed_ghash.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use super::{BinaryField128bGhash, PackedField};
4pub use crate::arch::{
5	packed_ghash_128::PackedBinaryGhash1x128b, packed_ghash_256::PackedBinaryGhash2x128b,
6	packed_ghash_512::PackedBinaryGhash4x128b,
7};
8
9// TODO: move to PackedField for an optimized SIMD version
10#[inline]
11pub fn mul_x<P: PackedField<Scalar = BinaryField128bGhash>>(x: P) -> P {
12	P::from_scalars(x.iter().map(|scalar| scalar.mul_x()))
13}
14
15// TODO: move to PackedField for an optimized SIMD version
16#[inline]
17pub fn mul_inv_x<P: PackedField<Scalar = BinaryField128bGhash>>(x: P) -> P {
18	P::from_scalars(x.iter().map(|scalar| scalar.mul_inv_x()))
19}
20
21#[cfg(test)]
22mod test_utils {
23	/// Test if `mult_func` operation is a valid multiply operation on the given values for
24	/// all possible packed fields defined on 8-512 bits.
25	macro_rules! define_multiply_tests {
26		($mult_func:path, $constraint:ty) => {
27			$crate::packed_binary_field::test_utils::define_check_packed_mul!(
28				$mult_func,
29				$constraint
30			);
31
32			proptest! {
33				#[test]
34				fn test_mul_packed_128(a_val in any::<u128>(), b_val in any::<u128>()) {
35					TestMult::<$crate::arch::packed_ghash_128::PackedBinaryGhash1x128b>::test_mul(
36						a_val.into(),
37						b_val.into(),
38					);
39				}
40
41				#[test]
42				fn test_mul_packed_256(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
43					TestMult::<$crate::arch::packed_ghash_256::PackedBinaryGhash2x128b>::test_mul(
44						a_val.into(),
45						b_val.into(),
46					);
47				}
48
49				#[test]
50				fn test_mul_packed_512(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
51					TestMult::<$crate::arch::packed_ghash_512::PackedBinaryGhash4x128b>::test_mul(
52						a_val.into(),
53						b_val.into(),
54					);
55				}
56			}
57		};
58	}
59
60	/// Test if `square_func` operation is a valid square operation on the given value for
61	/// all possible packed fields.
62	macro_rules! define_square_tests {
63		($square_func:path, $constraint:ident) => {
64			$crate::packed_binary_field::test_utils::define_check_packed_square!(
65				$square_func,
66				$constraint
67			);
68
69			proptest! {
70				#[test]
71				fn test_square_packed_128(a_val in any::<u128>()) {
72					TestSquare::<$crate::arch::packed_ghash_128::PackedBinaryGhash1x128b>::test_square(a_val.into());
73				}
74
75				#[test]
76				fn test_square_packed_256(a_val in any::<[u128; 2]>()) {
77					TestSquare::<$crate::arch::packed_ghash_256::PackedBinaryGhash2x128b>::test_square(a_val.into());
78				}
79
80				#[test]
81				fn test_square_packed_512(a_val in any::<[u128; 4]>()) {
82					TestSquare::<$crate::arch::packed_ghash_512::PackedBinaryGhash4x128b>::test_square(a_val.into());
83				}
84			}
85		};
86	}
87
88	/// Test if `invert_func` operation is a valid invert operation on the given value for
89	/// all possible packed fields.
90	macro_rules! define_invert_tests {
91		($invert_func:path, $constraint:ident) => {
92			$crate::packed_binary_field::test_utils::define_check_packed_inverse!(
93				$invert_func,
94				$constraint
95			);
96
97			proptest! {
98				#[test]
99				fn test_invert_packed_128(a_val in any::<u128>()) {
100					TestInvert::<$crate::arch::packed_ghash_128::PackedBinaryGhash1x128b>::test_invert(a_val.into());
101				}
102
103				#[test]
104				fn test_invert_packed_256(a_val in any::<[u128; 2]>()) {
105					TestInvert::<$crate::arch::packed_ghash_256::PackedBinaryGhash2x128b>::test_invert(a_val.into());
106				}
107
108				#[test]
109				fn test_invert_packed_512(a_val in any::<[u128; 4]>()) {
110					TestInvert::<$crate::arch::packed_ghash_512::PackedBinaryGhash4x128b>::test_invert(a_val.into());
111				}
112			}
113		};
114	}
115
116	macro_rules! define_transformation_tests {
117		($constraint:path) => {
118			$crate::packed_binary_field::test_utils::define_check_packed_transformation!(
119				$constraint
120			);
121
122			proptest::proptest! {
123				#[test]
124				fn test_transformation_packed_128(a_val in proptest::prelude::any::<u128>()) {
125					TestTransformation::<$crate::arch::packed_ghash_128::PackedBinaryGhash1x128b>::test_transformation(a_val.into());
126				}
127
128				#[test]
129				fn test_transformation_packed_256(a_val in proptest::prelude::any::<[u128; 2]>()) {
130					TestTransformation::<$crate::arch::packed_ghash_256::PackedBinaryGhash2x128b>::test_transformation(a_val.into());
131				}
132
133				#[test]
134				fn test_transformation_packed_512(a_val in proptest::prelude::any::<[u128; 4]>()) {
135					TestTransformation::<$crate::arch::packed_ghash_512::PackedBinaryGhash4x128b>::test_transformation(a_val.into());
136				}
137			}
138		};
139	}
140
141	pub(crate) use define_invert_tests;
142	pub(crate) use define_multiply_tests;
143	pub(crate) use define_square_tests;
144	pub(crate) use define_transformation_tests;
145}
146
147#[cfg(test)]
148mod tests {
149	use std::ops::Mul;
150
151	use proptest::{arbitrary::any, proptest};
152
153	use super::test_utils::{
154		define_invert_tests, define_multiply_tests, define_square_tests,
155		define_transformation_tests,
156	};
157	use crate::{
158		BinaryField128bGhash, PackedField,
159		arch::{
160			packed_ghash_128::PackedBinaryGhash1x128b, packed_ghash_256::PackedBinaryGhash2x128b,
161			packed_ghash_512::PackedBinaryGhash4x128b,
162		},
163		linear_transformation::PackedTransformationFactory,
164		test_utils::implements_transformation_factory,
165		underlier::WithUnderlier,
166	};
167
168	fn check_get_set<const WIDTH: usize, PT>(a: [u128; WIDTH], b: [u128; WIDTH])
169	where
170		PT: PackedField<Scalar = BinaryField128bGhash>
171			+ WithUnderlier<Underlier: From<[u128; WIDTH]>>,
172	{
173		let mut val = PT::from_underlier(a.into());
174		for i in 0..WIDTH {
175			assert_eq!(val.get(i), BinaryField128bGhash::from(a[i]));
176			val.set(i, BinaryField128bGhash::from(b[i]));
177			assert_eq!(val.get(i), BinaryField128bGhash::from(b[i]));
178		}
179	}
180
181	proptest! {
182		#[test]
183		fn test_get_set_256(a in any::<[u128; 2]>(), b in any::<[u128; 2]>()) {
184			check_get_set::<2, PackedBinaryGhash2x128b>(a, b);
185		}
186
187		#[test]
188		fn test_get_set_512(a in any::<[u128; 4]>(), b in any::<[u128; 4]>()) {
189			check_get_set::<4, PackedBinaryGhash4x128b>(a, b);
190		}
191	}
192
193	define_multiply_tests!(Mul::mul, PackedField);
194
195	define_square_tests!(PackedField::square, PackedField);
196
197	define_invert_tests!(PackedField::invert_or_zero, PackedField);
198
199	#[allow(unused)]
200	trait SelfTransformationFactory: PackedTransformationFactory<Self> {}
201
202	impl<T: PackedTransformationFactory<T>> SelfTransformationFactory for T {}
203
204	define_transformation_tests!(SelfTransformationFactory);
205
206	/// Compile-time test to ensure packed fields implement `PackedTransformationFactory`.
207	#[allow(unused)]
208	const fn test_implement_transformation_factory() {
209		// 128 bit packed ghash
210		implements_transformation_factory::<PackedBinaryGhash1x128b, PackedBinaryGhash1x128b>();
211
212		// 256 bit packed ghash
213		implements_transformation_factory::<PackedBinaryGhash2x128b, PackedBinaryGhash2x128b>();
214
215		// 512 bit packed ghash
216		implements_transformation_factory::<PackedBinaryGhash4x128b, PackedBinaryGhash4x128b>();
217	}
218}