Skip to main content

binius_field/
packed_ghash.rs

1// Copyright 2024-2025 Irreducible Inc.
2// Copyright 2026 The Binius Developers
3
4use crate::{
5	Ghash128b,
6	arch::{
7		GhashInvert1x, GhashInvert2x, GhashInvert4x, GhashSquare1x, GhashSquare2x, GhashSquare4x,
8		GhashWideMul1x, GhashWideMul2x, GhashWideMul4x, M128, M256, M512, MulFromWideMul,
9		portable::packed_macros::{portable_macros::*, *},
10	},
11};
12
13define_packed_binary_field!(
14	PackedBinaryGhash1x128b,
15	Ghash128b,
16	M128,
17	(MulFromWideMul),
18	(GhashSquare1x),
19	(GhashInvert1x),
20	(GhashWideMul1x)
21);
22
23define_packed_binary_field!(
24	PackedBinaryGhash2x128b,
25	Ghash128b,
26	M256,
27	(MulFromWideMul),
28	(GhashSquare2x),
29	(GhashInvert2x),
30	(GhashWideMul2x)
31);
32
33define_packed_binary_field!(
34	PackedBinaryGhash4x128b,
35	Ghash128b,
36	M512,
37	(MulFromWideMul),
38	(GhashSquare4x),
39	(GhashInvert4x),
40	(GhashWideMul4x)
41);
42
43#[cfg(test)]
44mod tests {
45	use proptest::{arbitrary::any, proptest};
46
47	use super::*;
48	use crate::{
49		Ghash128b, PackedField, packed_binary_field::test_utils::packed_field_tests,
50		underlier::WithUnderlier,
51	};
52
53	fn check_get_set<const WIDTH: usize, PT>(a: [u128; WIDTH], b: [u128; WIDTH])
54	where
55		PT: PackedField<Scalar = Ghash128b> + WithUnderlier<Underlier: From<[u128; WIDTH]>>,
56	{
57		let mut val = PT::from_underlier(a.into());
58		for i in 0..WIDTH {
59			assert_eq!(val.get(i), Ghash128b::from(a[i]));
60			val.set(i, Ghash128b::from(b[i]));
61			assert_eq!(val.get(i), Ghash128b::from(b[i]));
62		}
63	}
64
65	proptest! {
66		#[test]
67		fn test_get_set_256(a in any::<[u128; 2]>(), b in any::<[u128; 2]>()) {
68			check_get_set::<2, PackedBinaryGhash2x128b>(a, b);
69		}
70
71		#[test]
72		fn test_get_set_512(a in any::<[u128; 4]>(), b in any::<[u128; 4]>()) {
73			check_get_set::<4, PackedBinaryGhash4x128b>(a, b);
74		}
75	}
76
77	packed_field_tests!(ghash_1x128b, PackedBinaryGhash1x128b);
78	packed_field_tests!(ghash_2x128b, PackedBinaryGhash2x128b);
79	packed_field_tests!(ghash_4x128b, PackedBinaryGhash4x128b);
80
81	#[test]
82	fn test_wide_mul_zero_inputs() {
83		use super::PackedBinaryGhash1x128b as P;
84		use crate::{WideMul, field::FieldOps};
85
86		let zero = P::default();
87		let one = P::one();
88
89		assert_eq!(P::reduce(P::wide_mul(zero, zero)), zero);
90		assert_eq!(P::reduce(P::wide_mul(zero, one)), zero);
91		assert_eq!(P::reduce(P::wide_mul(one, zero)), zero);
92		assert_eq!(P::reduce(P::wide_mul(one, one)), one);
93
94		let wide_zero = <P as WideMul>::Output::default();
95		assert_eq!(P::reduce(wide_zero), zero);
96	}
97
98	#[test]
99	fn test_wide_mul_single_accumulation() {
100		use rand::{SeedableRng, rngs::StdRng};
101
102		use super::PackedBinaryGhash1x128b as P;
103		use crate::{Random, WideMul};
104
105		let mut rng = StdRng::seed_from_u64(77);
106		let a = P::random(&mut rng);
107		let b = P::random(&mut rng);
108
109		let wide = P::wide_mul(a, b);
110		let sum = wide + <P as WideMul>::Output::default();
111		assert_eq!(P::reduce(sum), a * b);
112	}
113}