binius_field/packed_fields/
ghash.rs1use crate::{
5 Ghash128b,
6 arch::{
7 GhashInvert1x, GhashInvert2x, GhashInvert4x, GhashMulX1x, GhashMulX2x, GhashMulX4x,
8 GhashSquare1x, GhashSquare2x, GhashSquare4x, GhashWideMul1x, GhashWideMul2x,
9 GhashWideMul4x, M128, M256, M512, portable::packed_macros::*,
10 },
11 arithmetic_traits::impl_mul_x_with,
12};
13
14define_packed_binary_field!(
15 PackedGhash1x128b,
16 Ghash128b,
17 M128,
18 (GhashSquare1x),
19 (GhashInvert1x),
20 (GhashWideMul1x)
21);
22
23define_packed_binary_field!(
24 PackedGhash2x128b,
25 Ghash128b,
26 M256,
27 (GhashSquare2x),
28 (GhashInvert2x),
29 (GhashWideMul2x)
30);
31
32define_packed_binary_field!(
33 PackedGhash4x128b,
34 Ghash128b,
35 M512,
36 (GhashSquare4x),
37 (GhashInvert4x),
38 (GhashWideMul4x)
39);
40
41impl_mul_x_with!(PackedGhash1x128b @ GhashMulX1x);
44impl_mul_x_with!(PackedGhash2x128b @ GhashMulX2x);
45impl_mul_x_with!(PackedGhash4x128b @ GhashMulX4x);
46
47#[cfg(test)]
48mod tests {
49 use proptest::{arbitrary::any, proptest};
50
51 use super::*;
52 use crate::{
53 Ghash128b, MulX, PackedField, packed_fields::test_utils::packed_field_tests,
54 underlier::UnderlierView,
55 };
56
57 fn check_get_set<const WIDTH: usize, PT>(a: [u128; WIDTH], b: [u128; WIDTH])
58 where
59 PT: PackedField<Scalar = Ghash128b> + UnderlierView<Underlier: From<[u128; WIDTH]>>,
60 {
61 let mut val = PT::from_underlier(a.into());
62 for i in 0..WIDTH {
63 assert_eq!(val.get(i), Ghash128b::from(a[i]));
64 val.set(i, Ghash128b::from(b[i]));
65 assert_eq!(val.get(i), Ghash128b::from(b[i]));
66 }
67 }
68
69 fn check_mul_x<P>(underlier: P::Underlier)
74 where
75 P: PackedField<Scalar = Ghash128b> + UnderlierView + MulX,
76 {
77 let packed = P::from_underlier(underlier);
78 let scaled = packed.mul_x();
79 let x = Ghash128b::new(2);
80
81 for i in 0..P::WIDTH {
82 assert_eq!(scaled.get(i), packed.get(i) * x, "lane {i}");
83 }
84 }
85
86 proptest! {
87 #[test]
88 fn test_get_set_256(a in any::<[u128; 2]>(), b in any::<[u128; 2]>()) {
89 check_get_set::<2, PackedGhash2x128b>(a, b);
90 }
91
92 #[test]
93 fn test_get_set_512(a in any::<[u128; 4]>(), b in any::<[u128; 4]>()) {
94 check_get_set::<4, PackedGhash4x128b>(a, b);
95 }
96
97 #[test]
98 #[allow(clippy::useless_conversion)] fn mul_x_is_multiplication_by_x_1x(a in any::<u128>()) {
100 check_mul_x::<PackedGhash1x128b>(a.into());
101 }
102
103 #[test]
104 fn mul_x_is_multiplication_by_x_2x(a in any::<[u128; 2]>()) {
105 check_mul_x::<PackedGhash2x128b>(a.into());
106 }
107
108 #[test]
109 fn mul_x_is_multiplication_by_x_4x(a in any::<[u128; 4]>()) {
110 check_mul_x::<PackedGhash4x128b>(a.into());
111 }
112 }
113
114 packed_field_tests!(ghash_1x128b, PackedGhash1x128b);
115 packed_field_tests!(ghash_2x128b, PackedGhash2x128b);
116 packed_field_tests!(ghash_4x128b, PackedGhash4x128b);
117
118 #[test]
119 fn test_wide_mul_zero_inputs() {
120 use super::PackedGhash1x128b as P;
121 use crate::{WideMul, field::FieldOps};
122
123 let zero = P::default();
124 let one = P::one();
125
126 assert_eq!(P::reduce(P::wide_mul(zero, zero)), zero);
127 assert_eq!(P::reduce(P::wide_mul(zero, one)), zero);
128 assert_eq!(P::reduce(P::wide_mul(one, zero)), zero);
129 assert_eq!(P::reduce(P::wide_mul(one, one)), one);
130
131 let wide_zero = <P as WideMul>::Output::default();
132 assert_eq!(P::reduce(wide_zero), zero);
133 }
134
135 #[test]
136 fn test_wide_mul_single_accumulation() {
137 use rand::{SeedableRng, rngs::StdRng};
138
139 use super::PackedGhash1x128b as P;
140 use crate::{Random, WideMul};
141
142 let mut rng = StdRng::seed_from_u64(77);
143 let a = P::random(&mut rng);
144 let b = P::random(&mut rng);
145
146 let wide = P::wide_mul(a, b);
147 let sum = wide + <P as WideMul>::Output::default();
148 assert_eq!(P::reduce(sum), a * b);
149 }
150}