1use std::{
19 fmt::{Debug, Display, Formatter},
20 iter::{Product, Sum},
21 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
22};
23
24use binius_utils::{
25 DeserializeBytes, FixedSizeSerializeBytes, SerializationError, SerializeBytes,
26 bytes::{Buf, BufMut},
27};
28use bytemuck::{Pod, Zeroable};
29
30use super::{
31 binary_field::{BinaryField, BinaryField1b, TowerField, binary_field, impl_field_extension},
32 extension::ExtensionField,
33};
34use crate::{
35 BinaryField128bGhash, Divisible, Field, PackedBinaryGhash2x128b, PackedField,
36 arch::{M128, M256, packed_256::m256_from_u128s},
37 arithmetic_traits::{InvertOrZero, Square, impl_trivial_wide_mul},
38 binary_field_arithmetic::TowerFieldArithmetic,
39 mul_by_binary_field_1b,
40 underlier::U1,
41};
42
43binary_field!(pub GhashSq256b(M256), m256_from_u128s(0, 1));
47
48unsafe impl Pod for GhashSq256b {}
49
50impl GhashSq256b {
51 #[inline]
53 fn to_coeffs(self) -> [BinaryField128bGhash; 2] {
54 let packed = PackedBinaryGhash2x128b::from_underlier(self.0);
57 [packed.get(0), packed.get(1)]
58 }
59
60 #[inline]
62 fn from_coeffs(coeffs: [BinaryField128bGhash; 2]) -> Self {
63 Self(PackedBinaryGhash2x128b::from_scalars(coeffs).to_underlier())
64 }
65}
66
67#[inline]
77fn mul(x: [BinaryField128bGhash; 2], y: [BinaryField128bGhash; 2]) -> [BinaryField128bGhash; 2] {
78 let [x0, x1] = x;
79 let [y0, y1] = y;
80
81 let t0_t2 = PackedBinaryGhash2x128b::from_scalars([x0, x1])
82 * PackedBinaryGhash2x128b::from_scalars([y0, y1]);
83 let t0 = t0_t2.get(0);
84 let t2 = t0_t2.get(1);
85 let t1 = (x0 + x1) * (y0 + y1);
86
87 [t0 + t2.mul_inv_x(), t1 + t0]
88}
89
90#[inline]
95fn square(x: [BinaryField128bGhash; 2]) -> [BinaryField128bGhash; 2] {
96 let t0_t2 = Square::square(PackedBinaryGhash2x128b::from_scalars(x));
97 let t0 = t0_t2.get(0);
98 let t2 = t0_t2.get(1);
99
100 [t0 + t2.mul_inv_x(), t2]
101}
102
103impl TowerField for GhashSq256b {
104 fn min_tower_level(self) -> usize {
105 let [a, b] = self.to_coeffs();
106 if self == Self::ZERO || self == Self::ONE {
107 0
108 } else if b == BinaryField128bGhash::ZERO {
109 a.min_tower_level()
111 } else {
112 8
113 }
114 }
115}
116
117impl TowerFieldArithmetic for GhashSq256b {
118 fn multiply(self, rhs: Self) -> Self {
119 Self::from_coeffs(mul(self.to_coeffs(), rhs.to_coeffs()))
120 }
121
122 fn square(self) -> Self {
123 Self::from_coeffs(square(self.to_coeffs()))
124 }
125}
126
127impl InvertOrZero for GhashSq256b {
128 #[inline]
129 fn invert_or_zero(self) -> Self {
130 let [a, b] = self.to_coeffs();
134
135 let norm = Square::square(a) + a * b + Square::square(b).mul_inv_x();
136 let norm_inv = norm.invert_or_zero();
137
138 let inv_a = (a + b) * norm_inv;
139 let inv_b = b * norm_inv;
140 Self::from_coeffs([inv_a, inv_b])
141 }
142}
143
144impl_trivial_wide_mul!(GhashSq256b);
145
146impl_field_extension!(BinaryField128bGhash(M128) < @1 => GhashSq256b(M256));
150
151impl_field_extension!(BinaryField1b(U1) < @8 => GhashSq256b(M256));
153
154mul_by_binary_field_1b!(GhashSq256b);
155
156impl Mul<BinaryField128bGhash> for GhashSq256b {
158 type Output = Self;
159
160 #[inline]
161 fn mul(self, rhs: BinaryField128bGhash) -> Self::Output {
162 let [a, b] = self.to_coeffs();
163 Self::from_coeffs([a * rhs, b * rhs])
164 }
165}
166
167impl SerializeBytes for GhashSq256b {
168 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
169 self.0.serialize(write_buf)
170 }
171}
172
173impl DeserializeBytes for GhashSq256b {
174 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
175 where
176 Self: Sized,
177 {
178 Ok(Self(DeserializeBytes::deserialize(read_buf)?))
179 }
180}
181
182impl FixedSizeSerializeBytes for GhashSq256b {
183 const BYTE_SIZE: usize = 32;
184}
185
186#[cfg(test)]
187mod tests {
188 use proptest::prelude::*;
189
190 use super::*;
191
192 const GHASH_INV_X: u128 = 0x80000000000000000000000000000043;
194
195 const ORDER_PRIME_FACTORS: [u128; 11] = [
198 3,
199 5,
200 17,
201 257,
202 65537,
203 641,
204 6700417,
205 274177,
206 67280421310721,
207 59649589127497217,
208 5704689200685129054721,
209 ];
210
211 fn ghash_sq(a: u128, b: u128) -> GhashSq256b {
212 GhashSq256b::from_coeffs([BinaryField128bGhash::new(a), BinaryField128bGhash::new(b)])
213 }
214
215 fn arb_elem() -> impl Strategy<Value = GhashSq256b> {
216 any::<[u128; 2]>().prop_map(|[a, b]| ghash_sq(a, b))
217 }
218
219 fn naive_square_transpose<F: BinaryField>(values: &[GhashSq256b]) -> Vec<GhashSq256b>
224 where
225 GhashSq256b: ExtensionField<F>,
226 {
227 let degree = <GhashSq256b as ExtensionField<F>>::DEGREE;
228 assert_eq!(values.len(), degree);
229 let coords: Vec<F> = values
230 .iter()
231 .flat_map(|v| ExtensionField::<F>::iter_bases(v))
232 .collect();
233 (0..degree)
234 .map(|i| {
235 <GhashSq256b as ExtensionField<F>>::from_bases(
236 (0..degree).map(|j| coords[j * degree + i]),
237 )
238 })
239 .collect()
240 }
241
242 fn order_cofactor(p: u128) -> [u64; 4] {
245 let mut quotient = [0u64; 4];
246 let mut rem: u128 = 0;
247 for bit in (0..256).rev() {
249 rem = (rem << 1) | 1;
250 let q_bit = if rem >= p {
251 rem -= p;
252 1u64
253 } else {
254 0
255 };
256 quotient[bit / 64] |= q_bit << (bit % 64);
257 }
258 quotient
259 }
260
261 fn is_generator(g: GhashSq256b) -> bool {
264 ORDER_PRIME_FACTORS
265 .iter()
266 .all(|&p| Field::pow(&g, order_cofactor(p)) != GhashSq256b::ONE)
267 }
268
269 #[test]
270 fn test_quadratic_relation() {
271 let y = ghash_sq(0, 1);
273 assert_eq!(y * y, y + ghash_sq(GHASH_INV_X, 0));
274 }
275
276 #[test]
277 fn test_subfield_embedding() {
278 let a = BinaryField128bGhash::new(0x0123456789abcdef0123456789abcdef);
280 let b = BinaryField128bGhash::new(0xfedcba9876543210fedcba9876543210);
281 assert_eq!(GhashSq256b::from(a) * GhashSq256b::from(b), GhashSq256b::from(a * b),);
282 }
283
284 #[test]
285 fn test_multiplicative_generator() {
286 assert!(
287 is_generator(GhashSq256b::MULTIPLICATIVE_GENERATOR),
288 "baked MULTIPLICATIVE_GENERATOR is not a generator of GF(2^256)*",
289 );
290 }
291
292 #[test]
293 #[ignore = "search utility: prints a valid generator literal to bake into the field"]
294 fn find_generator() {
295 for b in 1u128..256 {
296 for a in 0u128..256 {
297 let candidate = ghash_sq(a, b);
298 if is_generator(candidate) {
299 let [low, high] = candidate.to_coeffs();
300 panic!(
301 "found generator: a={a:#x}, b={b:#x} -> m256_from_u128s({:#034x}, {:#034x})",
302 u128::from(low.val()),
303 u128::from(high.val()),
304 );
305 }
306 }
307 }
308 panic!("no generator found in search range");
309 }
310
311 proptest! {
312 #[test]
313 fn test_mul_commutative(a in arb_elem(), b in arb_elem()) {
314 prop_assert_eq!(a * b, b * a);
315 }
316
317 #[test]
318 fn test_mul_associative(a in arb_elem(), b in arb_elem(), c in arb_elem()) {
319 prop_assert_eq!((a * b) * c, a * (b * c));
320 }
321
322 #[test]
323 fn test_mul_distributive(a in arb_elem(), b in arb_elem(), c in arb_elem()) {
324 prop_assert_eq!(a * (b + c), a * b + a * c);
325 }
326
327 #[test]
328 fn test_mul_identity(a in arb_elem()) {
329 prop_assert_eq!(a * GhashSq256b::ONE, a);
330 }
331
332 #[test]
333 fn test_square_equals_mul(a in arb_elem()) {
334 prop_assert_eq!(Square::square(a), a * a);
335 }
336
337 #[test]
338 fn test_invert(a in arb_elem()) {
339 match a.invert() {
340 Some(inv) => prop_assert_eq!(a * inv, GhashSq256b::ONE),
341 None => prop_assert_eq!(a, GhashSq256b::ZERO),
342 }
343 }
344
345 #[test]
346 fn test_serialization_roundtrip(a in arb_elem()) {
347 let mut buf = Vec::new();
348 a.serialize(&mut buf).unwrap();
349 prop_assert_eq!(buf.len(), GhashSq256b::BYTE_SIZE);
350 let b = GhashSq256b::deserialize(buf.as_slice()).unwrap();
351 prop_assert_eq!(a, b);
352 }
353
354 #[test]
355 fn test_ghash_extension_bases_roundtrip(a in arb_elem()) {
356 let bases: Vec<BinaryField128bGhash> =
357 ExtensionField::<BinaryField128bGhash>::iter_bases(&a).collect();
358 prop_assert_eq!(bases.len(), 2);
359 prop_assert_eq!(
360 <GhashSq256b as ExtensionField<BinaryField128bGhash>>::from_bases(bases),
361 a,
362 );
363 }
364
365 #[test]
366 fn test_b1b_extension_bases_roundtrip(a in arb_elem()) {
367 let bases: Vec<BinaryField1b> =
368 ExtensionField::<BinaryField1b>::iter_bases(&a).collect();
369 prop_assert_eq!(bases.len(), 256);
370 prop_assert_eq!(
371 <GhashSq256b as ExtensionField<BinaryField1b>>::from_bases(bases),
372 a,
373 );
374 }
375
376 #[test]
377 fn test_square_transpose_ghash(a in arb_elem(), b in arb_elem()) {
378 let mut values = [a, b];
379 let expected = naive_square_transpose::<BinaryField128bGhash>(&values);
380 <GhashSq256b as ExtensionField<BinaryField128bGhash>>::square_transpose(&mut values);
381 prop_assert_eq!(values.as_slice(), expected.as_slice());
382 }
383
384 #[test]
385 fn test_square_transpose_b1b(values in prop::collection::vec(arb_elem(), 256)) {
386 let mut values = values;
387 let expected = naive_square_transpose::<BinaryField1b>(&values);
388 <GhashSq256b as ExtensionField<BinaryField1b>>::square_transpose(&mut values);
389 prop_assert_eq!(values, expected);
390 }
391 }
392}