1use binius_field::BinaryField128bGhash as Ghash;
4
5pub const M: usize = 4;
6
7pub const BYTES_PER_GHASH: usize = 16;
8
9pub const NUM_ROUNDS: usize = 8;
10
11pub static B_FWD_COEFFS: [Ghash; 4] = [
12 Ghash::new(0xb0b849b207a0f1c74c29e4d892ca33dd),
13 Ghash::new(0xf2240891aac3c3a5855eeb8ce24c9523),
14 Ghash::new(0xb017e96797ef1fbe9d79908388dd768d),
15 Ghash::new(0x2bf9f0b94c2b2ceb00dbb86a2cb472bb),
16];
17
18pub static B_INV_COEFFS: [Ghash; 1 + 128] = [
19 Ghash::new(0x1d124529af098017d515f025b2107a04),
20 Ghash::new(0xb2733aa187f5954a397b9985012327dc),
21 Ghash::new(0xf9ed22a697f45e3fac28266a3c9c8bf9),
22 Ghash::new(0xb2563578203d5df23ed37df5274f9b62),
23 Ghash::new(0x9f60ca3b6e570f9bb35f672c4cc71e78),
24 Ghash::new(0x2b7839e6c8c6f35c4cfe4dd6ed9988bf),
25 Ghash::new(0xd7e470d53c8a1441335c0e39f8e825ba),
26 Ghash::new(0xc2a0d87c2f6de7f3656d51ee118d93ca),
27 Ghash::new(0xb80cb728430ce418d8763ad073d43c72),
28 Ghash::new(0xf1424d16f8ff5ad20c172fa0bce84a66),
29 Ghash::new(0xf27af010f636dd9d8b47d92989d38c91),
30 Ghash::new(0xeebb7636921fdc8bb35172c4f2904488),
31 Ghash::new(0xf17407875a9069991c532b85716f8278),
32 Ghash::new(0x72032c6e2ef39011b80918ec4884682e),
33 Ghash::new(0xa93dd016787f32dafb792593a1c0664c),
34 Ghash::new(0x2a72f7f35410abe48bf86284d7153568),
35 Ghash::new(0x539206fa82bb0fd3fc257acfd85198cf),
36 Ghash::new(0x6325125ff725e1435f66efa328075c4b),
37 Ghash::new(0x73abb6e9157b3791bc1a05a15a0ba8e2),
38 Ghash::new(0x3447131e361d3a430e26535b49f37884),
39 Ghash::new(0xeeeb383e8b2e366b3b5d33b416320285),
40 Ghash::new(0xa6ef061627c8b7d6b5ea5ddf3b3ceeee),
41 Ghash::new(0x3f97a996898ed33fb4c0b023284209b7),
42 Ghash::new(0xbdf02af9a8b31ed299580c95f214d5a3),
43 Ghash::new(0xfded88f14050f0fc196849074ce0f9ad),
44 Ghash::new(0x6c8b4d18e1ba055c6b631b36bde8d60c),
45 Ghash::new(0x1027cad9488ab75d6741c4f5b9026779),
46 Ghash::new(0x9f1c5193f4762dcadac6b8979fd40e1d),
47 Ghash::new(0x7af3e53f8f00a454d215ee466e50388c),
48 Ghash::new(0x5e3227be2a589427f2870f655f41ef5b),
49 Ghash::new(0xd964ed03293469753b504cb624c60228),
50 Ghash::new(0x43c3a9698d3135080fe4f57716b03036),
51 Ghash::new(0x922b2fb49b13518ec3895e0eb37085b0),
52 Ghash::new(0xaa09df0da87a0fceb212105e5b297b5a),
53 Ghash::new(0x790c7ca5f5905488e82bd9d875c8715a),
54 Ghash::new(0x369411c407a9ef883133bc16aceb21a2),
55 Ghash::new(0xd577819f72b6158c1eca19e57d2e1e95),
56 Ghash::new(0xac4d176698af651f201efd2cfea05ab6),
57 Ghash::new(0x268f4c40a4553eb3a2afbde2b10df863),
58 Ghash::new(0x8749898084983a777debda3686b5e752),
59 Ghash::new(0xc723199815bae544773110e7054256a0),
60 Ghash::new(0x960b23bc674dd468d75ff82b164067b4),
61 Ghash::new(0xb94130b0a65d36009150e505b5e4a818),
62 Ghash::new(0x742b2c52bba058cc8c9a364c0985136b),
63 Ghash::new(0xdf298fbb15e6e58f9edb384f5c34673c),
64 Ghash::new(0x4fdbc95e71fe2bdbcc6bee273caad844),
65 Ghash::new(0x19d487689fe24e3a3eceabdefdcef9e5),
66 Ghash::new(0xb01bf42d575ca9a0df60e3e99d4a4450),
67 Ghash::new(0xe8a777b48d74755f5091a9d460f80660),
68 Ghash::new(0x9f435ce2ff626ba06cb1ee4478a1356f),
69 Ghash::new(0x6804034746f7cca00180116ebfe5b33a),
70 Ghash::new(0xaef4cc5aa39d8f6957c15f9b173601eb),
71 Ghash::new(0x97d15c1e09df82180a062c5268804182),
72 Ghash::new(0x3109fb44aa8caba5fb41f60a49ab9f99),
73 Ghash::new(0x67ff3e7094682c2c7ae9258280b00f7d),
74 Ghash::new(0xbf6a8f87c80acf09f9456b27b9c44a04),
75 Ghash::new(0x4cd2646e793fd4eab1319cb89fb72054),
76 Ghash::new(0x076e92092b1f43709e7b9b2856ed53a9),
77 Ghash::new(0xb987929f99110f41f4f44c08b778e929),
78 Ghash::new(0x09b1c58023e9c9c267451053eed4b989),
79 Ghash::new(0xb27b2fa5789c2749058ebed7e489d0a1),
80 Ghash::new(0xcf9a22da173d17c475c43a59ed45535f),
81 Ghash::new(0x77df29bf03c18bbd103431cf69e35840),
82 Ghash::new(0x2a746d8aec21318be6985ff6dfa5d116),
83 Ghash::new(0x3411ccb789ac3dfc5bbd1c8b967559f6),
84 Ghash::new(0xd6faab5c3e02915dc279b22dbbf81919),
85 Ghash::new(0x2b9a29fd7e4775061fbb90c2033f304d),
86 Ghash::new(0x8a78a5986d399576aade221e1a4a4759),
87 Ghash::new(0x8cc9cb6657270a712b2c776b7f231214),
88 Ghash::new(0xa4206fef28f9fad8b05707b515fa176b),
89 Ghash::new(0x71984ef63a6a49ddefa6b9cb6b8832c4),
90 Ghash::new(0x2347fdcc33e95ee2a1bb2c4edc8da6a9),
91 Ghash::new(0xc63f0aaf33ca8b99a03decedc48b2e94),
92 Ghash::new(0x3237cb90cca2283888cb5729283a8b4d),
93 Ghash::new(0xbe8d8bbd445bf3e3e2947257afff2516),
94 Ghash::new(0xe7524df886b9fd83a2d4bdcfdb252124),
95 Ghash::new(0x6cb5512f7bdd181f675d059cf05799ff),
96 Ghash::new(0xc56e3f62ddedbabb35a200087a5640ce),
97 Ghash::new(0xba0a5c1d5ce94e53f9efb731c6634b44),
98 Ghash::new(0x4280ae86e53b14eb0202f4c147a6d14a),
99 Ghash::new(0xb4dffae679af530c397b2d07ac62d79a),
100 Ghash::new(0xd0311963a7fafcafd3660af96cc461e1),
101 Ghash::new(0x7d4f16aea2ce0d4e4c8c545d4d0040dc),
102 Ghash::new(0xda8304eff41a3ae357f1ec94fe9e062b),
103 Ghash::new(0x1b7c9a9f3666986912070ec52f99f801),
104 Ghash::new(0x004ccc9ddf6ca951f20c1b0ac31fa008),
105 Ghash::new(0x14f6a26f68c0ffd76f8f5fd65aa79542),
106 Ghash::new(0xd31406666953d392634f0e80af43fe0e),
107 Ghash::new(0x020c264e630f8bf516200218fb1d1a0e),
108 Ghash::new(0xdd5a2efdde3cae83465d1315d7af0852),
109 Ghash::new(0x055702e27b6a93676389c452c5e4b41a),
110 Ghash::new(0xc4684448e291abeeaa305e6c0e6af873),
111 Ghash::new(0xd2c1419f07a837e617a10b6ac6d1f275),
112 Ghash::new(0x8c605a36b3ecdd16edfc7c499e550871),
113 Ghash::new(0xe034129a3ccbfd6590ebaa430dcad339),
114 Ghash::new(0x5cb6429235829cdcdfc6a221725c755c),
115 Ghash::new(0x5737eb97111ca259d691ae13f5763345),
116 Ghash::new(0x755cd247d4267e960075f86302a39702),
117 Ghash::new(0xb12a9aa970a91097fa8ad2f2bdfb1b20),
118 Ghash::new(0x0dc789e36c5547c0571e479d7fd9a75f),
119 Ghash::new(0x919900cb8cbe4e756f19ab79df7196ee),
120 Ghash::new(0xbebfc69ba65f89dfecd241385602e25f),
121 Ghash::new(0xcac2967113753aaa7f3d8b4c9df4b9aa),
122 Ghash::new(0xf97eff95e366110b9b47509e730fd04f),
123 Ghash::new(0xf939cdd3b4d28d6f3e30aeb60f0346a0),
124 Ghash::new(0x982a7c68b7e0ae1603e324d5453d2b1d),
125 Ghash::new(0x1a589c0f209aeca97224c0c9db79142b),
126 Ghash::new(0x5219c08df0734e2b98dd90d13bc83d8f),
127 Ghash::new(0x95f1c0b71be50da58a8f752a0724e53b),
128 Ghash::new(0x8c494d44cb21e64e58401414631f3666),
129 Ghash::new(0x07b5f194eaa7cf3c96287d6aaedd3051),
130 Ghash::new(0x12e5008f6b6b3dd1d640a0a72a6c6d42),
131 Ghash::new(0x3329d9133fa80c1e6aba028e9255256c),
132 Ghash::new(0xb859b9f70c7d3da6cb8bc0127316f7ad),
133 Ghash::new(0xc31f1a1e3e98194053a0c5759aba5125),
134 Ghash::new(0x6f7deb6cd260c52090fa62f4b170cc55),
135 Ghash::new(0x991089b8d80963ddcf856990b5b55a89),
136 Ghash::new(0x36ebdacdc017e6cd38a1ccedfa6799d6),
137 Ghash::new(0x6ee345c84ddb46a42c8139c52ef87729),
138 Ghash::new(0x31bc991954d18dfb00a0e9f1c8177027),
139 Ghash::new(0x576056edf9e7f6f349740dffa8adc7d5),
140 Ghash::new(0xd7861327edc091fa6b27b5447b05255e),
141 Ghash::new(0x1ad33492132898f582444df642286e8c),
142 Ghash::new(0xfabef4a4b044b301e6d8a3ed7fd754a2),
143 Ghash::new(0x03dbd4cca837cf33b42622b75fec035a),
144 Ghash::new(0xbb8da06ec7ec3a9c2867a57e2cde5cc6),
145 Ghash::new(0x7f0dfc7829c9ecef117778448e04cc6c),
146 Ghash::new(0x128da4c873150f44e7e43bf88921c090),
147 Ghash::new(0xd9bc6edaf1b4a689ba169b5554228af8),
148];
149
150pub static ROUND_CONSTANTS: [[Ghash; 4]; 1 + 2 * 8] = [
151 [
152 Ghash::new(0xd0e015190f5e0795f4a1d28234ffdf87),
153 Ghash::new(0x6111731acd9a89f6b93ec3a23ec7681b),
154 Ghash::new(0x15da8de707ee3f3918a34a96728b8d29),
155 Ghash::new(0x2ea920e89fbb13a1ed2a216b1d232bfb),
156 ],
157 [
158 Ghash::new(0x52c94b04b178f80fa586c37c798171a3),
159 Ghash::new(0xf0e02cc3459757dc8ec9259341831bcb),
160 Ghash::new(0x025c53bf6d6dee09307a55c008868354),
161 Ghash::new(0x54258ece50ceb1e9b5a8e38e7bbcaa3d),
162 ],
163 [
164 Ghash::new(0x77c332c3ebbfbaa73bffaec318055661),
165 Ghash::new(0x5abbaeac51c6925d2aff59f11d164328),
166 Ghash::new(0x9f8daadefaebb59d77ad096fb56e6462),
167 Ghash::new(0x322de9fd29fb135d569895b07925cacf),
168 ],
169 [
170 Ghash::new(0x95c521abe74b013381778cf1b46e6cbd),
171 Ghash::new(0x85fcfe5a641b67ada8700b95fd906f70),
172 Ghash::new(0x5d61e0714a000a6d491d8e0db8835a16),
173 Ghash::new(0x3bea1f3ff2c984d47f91ec35358f1e16),
174 ],
175 [
176 Ghash::new(0x66b6cd1b70d97c63163197d429553ad3),
177 Ghash::new(0xd1be1516a276fb5f590b628b4f8db8b9),
178 Ghash::new(0x60f3fccd56bfad8cb506e2f1adce50af),
179 Ghash::new(0x205a1e29bd8a90dac5f776c450e88d10),
180 ],
181 [
182 Ghash::new(0x2a02ee3e61560ba34c286e943b3d169f),
183 Ghash::new(0x73e4bfe44495bfbb54f6fd20adedcf8b),
184 Ghash::new(0x23e8322b8a8cf1d3b681c1b577cee348),
185 Ghash::new(0x0d892aeb52c9b2d7096f9698ef0951df),
186 ],
187 [
188 Ghash::new(0x8571aa085a872bfcd96c3a1ebbe26682),
189 Ghash::new(0x3ae1e8efdff55ee0cb6d91af315d614b),
190 Ghash::new(0xdcf3ec9dd466e76de5f9f9e9fd5dbdba),
191 Ghash::new(0x5242d748a66f9abe17d4ca014c92081f),
192 ],
193 [
194 Ghash::new(0x38176034b37ed0b51ea51bade772fd64),
195 Ghash::new(0xdc10902a22159fdc02bc8fc3c43ee732),
196 Ghash::new(0x54eafeed45ab9f55c2a668054e1433f2),
197 Ghash::new(0x18c196024042197b29bba5779e6b4419),
198 ],
199 [
200 Ghash::new(0xeeee77f02774996aff2fbdee3cafd5c6),
201 Ghash::new(0xc09b024ff9e932be0fc9d294001fa6a7),
202 Ghash::new(0x62c063613d99b026579fa6bf82e24cdb),
203 Ghash::new(0x87df42121a98610c661fb711f68ee06e),
204 ],
205 [
206 Ghash::new(0x40405fdefe20704cda9bccfaa1189228),
207 Ghash::new(0xb683ec6a7ff2f49ae429c9f0e0e3f518),
208 Ghash::new(0xa8e472626f047ffe07759441d3d2547f),
209 Ghash::new(0x8c89cca408b7c95407db5cb1cc572a63),
210 ],
211 [
212 Ghash::new(0xcaf9fccf7c70d8a7c2ec4142b9d5397e),
213 Ghash::new(0x414420fface1c14f77cf760b5f7f980f),
214 Ghash::new(0x0c8811f0d2dfb0dfe515f581db7c4d9d),
215 Ghash::new(0x6303211a8c2a68f6103e2f03f7957ca4),
216 ],
217 [
218 Ghash::new(0x10c51b39a067af1e593e9c46a1b77d37),
219 Ghash::new(0x2319f7d203bbf1d50fe342d17066c9d3),
220 Ghash::new(0x3dd51ba31a2018b8da50ec10ed923e6e),
221 Ghash::new(0x676c6481332d0803cdea11539da55247),
222 ],
223 [
224 Ghash::new(0xcd06f2d74ae291550c7cd3e34c3ca94d),
225 Ghash::new(0x2aaea85e1163205f340a28bf015b3488),
226 Ghash::new(0x48e0f19b5886ca1e9ce659ddf1dece57),
227 Ghash::new(0x4b2ea0d6191010f82491ac06b6cbf7ad),
228 ],
229 [
230 Ghash::new(0xb73fb2fc3f8a413ee8806392998452aa),
231 Ghash::new(0x470372c4c732a0a7e61f858edaaa7f97),
232 Ghash::new(0x647c2b2751c258135ccd956db51e7ffa),
233 Ghash::new(0x079e5c6d2ec255a3206f1d231109247b),
234 ],
235 [
236 Ghash::new(0x367538f6742ae83251d22a8112bf6fa1),
237 Ghash::new(0x08539d5a297209d419a8906fee11e0a3),
238 Ghash::new(0x3de8eec08b29b79911eb2420e4336284),
239 Ghash::new(0x2fc0e3b4d3ea4de849486e07be859117),
240 ],
241 [
242 Ghash::new(0xe25e1dbbcabb7885ae28db51bacbee5e),
243 Ghash::new(0x9916b64185652326fda0575231b69ed2),
244 Ghash::new(0x1ff4e4155cbf886110f5545da1f8722d),
245 Ghash::new(0x4dcd1260ab92fbe0cec3b014367f626e),
246 ],
247 [
248 Ghash::new(0x40ae8c84f958d259141595fed91e09cd),
249 Ghash::new(0xf8222584576d0b5fa41584b91cf5f526),
250 Ghash::new(0x5c021db63b4a3a27de7d38be3b26c52f),
251 Ghash::new(0x509c5cb38660fee6ccc20b9abda1189b),
252 ],
253];
254
255#[cfg(test)]
256pub mod tests {
257 use binius_field::{Field, Random, arithmetic_traits::Square};
258 use binius_math::batch_invert::BatchInversion;
259 use rand::{SeedableRng, rngs::StdRng};
260
261 use super::{
262 super::{
263 linear_tables::{LINEAR_B_FWD_TABLE, LINEAR_B_INV_TABLE},
264 permutation::{
265 b_fwd_transform, b_inv_transform, constants_add, linearized_transform_scalar,
266 mds_mul, sbox,
267 },
268 },
269 *,
270 };
271
272 pub fn matrix_mul(matrix: &[Ghash; M * M], vector: &[Ghash; M]) -> [Ghash; M] {
273 std::array::from_fn(|i| {
274 matrix[i * M..(i + 1) * M]
276 .iter()
277 .zip(vector.iter())
278 .map(|(&m_ij, &v_j)| m_ij * v_j)
279 .sum()
280 })
281 }
282
283 pub static INITIAL_CONSTANT: [Ghash; 4] = [
284 Ghash::new(0xd0e015190f5e0795f4a1d28234ffdf87),
285 Ghash::new(0x6111731acd9a89f6b93ec3a23ec7681b),
286 Ghash::new(0x15da8de707ee3f3918a34a96728b8d29),
287 Ghash::new(0x2ea920e89fbb13a1ed2a216b1d232bfb),
288 ];
289
290 pub static CONSTANTS_MATRIX: [Ghash; 16] = [
291 Ghash::new(0x1cac9af051191d2c8ef96344bc8cbd0f),
292 Ghash::new(0x3ceb350e8c2d2f4d4750ab0a854c3a4d),
293 Ghash::new(0x09cc78f7eafef94d8e092e899156946b),
294 Ghash::new(0x1d1ad17c8c7ee715a3d58f7eedb30dbb),
295 Ghash::new(0x06bee572113950b3dd0cdae9dff5dfc5),
296 Ghash::new(0x4799c3743a3560428b4bfa1a5cd3d295),
297 Ghash::new(0x516883bf97b07fcf4cb89ac6bf636d0b),
298 Ghash::new(0x0b681d1621d6aa1fdf1a9113b04d755b),
299 Ghash::new(0xe9ba2f01051f6b4b3ddfe74c125e99e5),
300 Ghash::new(0x1f58efc5ecf2e1b933e31cfb26b916d1),
301 Ghash::new(0x36da671249b5444cf67efc573241fe19),
302 Ghash::new(0x056cae18b867d486615a130556e5eb99),
303 Ghash::new(0x1d8645dd4b1e46b78dd9df84956bcf11),
304 Ghash::new(0x3efa34e48e3b218395efe6255339375b),
305 Ghash::new(0x79bf44bae0d2379397d0812db56c5eff),
306 Ghash::new(0x7fb3b7fce84776e39e538151daddae85),
307 ];
308
309 pub static CONSTANTS_CONSTANT: [Ghash; 4] = [
310 Ghash::new(0x0d42981a71a7c2e493ca17e6bb10203f),
311 Ghash::new(0x9ceed672ccb7030fca17ed48e18717b9),
312 Ghash::new(0x0cec5c463024f2ba95c6ecdb4a349d15),
313 Ghash::new(0xa46023576301b995990418f3a23e3c99),
314 ];
315
316 fn compute_round_constants() -> [[Ghash; M]; 1 + 2 * NUM_ROUNDS] {
317 let mut round_keys = [[Ghash::ZERO; M]; 1 + 2 * NUM_ROUNDS];
318 round_keys[0] = INITIAL_CONSTANT;
319
320 let mut key_state = INITIAL_CONSTANT;
321 let mut key_injection = INITIAL_CONSTANT;
322
323 let mut round_key_index = 1;
324 let mut inverter = BatchInversion::<Ghash>::new(M);
325 for _ in 0..NUM_ROUNDS {
326 for transform in [b_inv_transform, b_fwd_transform] {
327 key_injection = matrix_mul(&CONSTANTS_MATRIX, &key_injection);
328 constants_add(&mut key_injection, &CONSTANTS_CONSTANT);
329
330 sbox(&mut key_state, transform, &mut inverter);
331 mds_mul(&mut key_state);
332 constants_add(&mut key_state, &key_injection);
333
334 round_keys[round_key_index] = key_state;
335 round_key_index += 1;
336 }
337 }
338
339 round_keys
340 }
341
342 #[test]
343 fn test_round_constants() {
344 let round_constants = compute_round_constants();
345 assert_eq!(round_constants, ROUND_CONSTANTS);
346 }
347
348 fn evaluate_b_fwd_linear(input: Ghash) -> Ghash {
349 B_FWD_COEFFS[1] * input
351 + B_FWD_COEFFS[2] * input.square()
352 + B_FWD_COEFFS[3] * input.square().square()
353 }
354
355 fn evaluate_b_fwd_affine(input: Ghash) -> Ghash {
356 B_FWD_COEFFS[0] + evaluate_b_fwd_linear(input)
357 }
358
359 fn evaluate_b_inv_linear(input: Ghash) -> Ghash {
360 let mut result = Ghash::ZERO;
361 let mut x_power = input; for i in 0..128 {
366 result += B_INV_COEFFS[i + 1] * x_power;
367 x_power = x_power.square(); }
369
370 result
371 }
372
373 fn evaluate_b_inv_affine(input: Ghash) -> Ghash {
374 B_INV_COEFFS[0] + evaluate_b_inv_linear(input)
375 }
376
377 #[test]
378 fn test_linear_table_consistency() {
379 let mut rng = StdRng::seed_from_u64(0);
380 let input = Ghash::random(&mut rng);
381
382 let mut b_fwd_result = input;
383 linearized_transform_scalar(&mut b_fwd_result, &LINEAR_B_FWD_TABLE);
384 let expected_b_fwd_result = evaluate_b_fwd_linear(input);
385 assert_eq!(b_fwd_result, expected_b_fwd_result);
386
387 let mut b_inv_result = input;
388 linearized_transform_scalar(&mut b_inv_result, &LINEAR_B_INV_TABLE);
389 let expected_b_inv_result = evaluate_b_inv_linear(input);
390 assert_eq!(b_inv_result, expected_b_inv_result);
391 }
392
393 #[test]
394 fn test_b_inverse_coeffs() {
395 let mut rng = StdRng::seed_from_u64(0);
396 let input = Ghash::random(&mut rng);
397
398 let b_result = evaluate_b_fwd_affine(input);
399 let recovered_input = evaluate_b_inv_affine(b_result);
400 assert_eq!(recovered_input, input, "B_inverse verification failed: B_inv(B(x)) != x");
401 }
402}