1use rhdl::prelude::*;
4
5use crate::KeccakState;
6
7pub const ROUND_CONSTANTS: [u64; 24] = [
9 0x0000_0000_0000_0001,
10 0x0000_0000_0000_8082,
11 0x8000_0000_0000_808a,
12 0x8000_0000_8000_8000,
13 0x0000_0000_0000_808b,
14 0x0000_0000_8000_0001,
15 0x8000_0000_8000_8081,
16 0x8000_0000_0000_8009,
17 0x0000_0000_0000_008a,
18 0x0000_0000_0000_0088,
19 0x0000_0000_8000_8009,
20 0x0000_0000_8000_000a,
21 0x0000_0000_8000_808b,
22 0x8000_0000_0000_008b,
23 0x8000_0000_0000_8089,
24 0x8000_0000_0000_8003,
25 0x8000_0000_0000_8002,
26 0x8000_0000_0000_0080,
27 0x0000_0000_0000_800a,
28 0x8000_0000_8000_000a,
29 0x8000_0000_8000_8081,
30 0x8000_0000_0000_8080,
31 0x0000_0000_8000_0001,
32 0x8000_0000_8000_8008,
33];
34
35pub const ROTATION_OFFSETS: [[u32; 5]; 5] = [
37 [0, 36, 3, 41, 18],
38 [1, 44, 10, 45, 2],
39 [62, 6, 43, 15, 61],
40 [28, 55, 25, 21, 56],
41 [27, 20, 39, 8, 14],
42];
43
44macro_rules! fixed_rotate {
47 ($name:ident, $left:literal, $right:literal) => {
48 #[kernel]
49 fn $name(value: b64) -> b64 {
50 (value << $left) | (value >> $right)
51 }
52 };
53}
54
55fixed_rotate!(rol01, 1, 63);
56fixed_rotate!(rol02, 2, 62);
57fixed_rotate!(rol03, 3, 61);
58fixed_rotate!(rol06, 6, 58);
59fixed_rotate!(rol08, 8, 56);
60fixed_rotate!(rol10, 10, 54);
61fixed_rotate!(rol14, 14, 50);
62fixed_rotate!(rol15, 15, 49);
63fixed_rotate!(rol18, 18, 46);
64fixed_rotate!(rol20, 20, 44);
65fixed_rotate!(rol21, 21, 43);
66fixed_rotate!(rol25, 25, 39);
67fixed_rotate!(rol27, 27, 37);
68fixed_rotate!(rol28, 28, 36);
69fixed_rotate!(rol36, 36, 28);
70fixed_rotate!(rol39, 39, 25);
71fixed_rotate!(rol41, 41, 23);
72fixed_rotate!(rol43, 43, 21);
73fixed_rotate!(rol44, 44, 20);
74fixed_rotate!(rol45, 45, 19);
75fixed_rotate!(rol55, 55, 9);
76fixed_rotate!(rol56, 56, 8);
77fixed_rotate!(rol61, 61, 3);
78fixed_rotate!(rol62, 62, 2);
79
80#[kernel]
81#[allow(clippy::match_same_arms)] fn iota_constant(round: b5) -> b64 {
83 match round {
84 Bits::<5>(0) => b64(0x0000_0000_0000_0001),
85 Bits::<5>(1) => b64(0x0000_0000_0000_8082),
86 Bits::<5>(2) => b64(0x8000_0000_0000_808a),
87 Bits::<5>(3) => b64(0x8000_0000_8000_8000),
88 Bits::<5>(4) => b64(0x0000_0000_0000_808b),
89 Bits::<5>(5) => b64(0x0000_0000_8000_0001),
90 Bits::<5>(6) => b64(0x8000_0000_8000_8081),
91 Bits::<5>(7) => b64(0x8000_0000_0000_8009),
92 Bits::<5>(8) => b64(0x0000_0000_0000_008a),
93 Bits::<5>(9) => b64(0x0000_0000_0000_0088),
94 Bits::<5>(10) => b64(0x0000_0000_8000_8009),
95 Bits::<5>(11) => b64(0x0000_0000_8000_000a),
96 Bits::<5>(12) => b64(0x0000_0000_8000_808b),
97 Bits::<5>(13) => b64(0x8000_0000_0000_008b),
98 Bits::<5>(14) => b64(0x8000_0000_0000_8089),
99 Bits::<5>(15) => b64(0x8000_0000_0000_8003),
100 Bits::<5>(16) => b64(0x8000_0000_0000_8002),
101 Bits::<5>(17) => b64(0x8000_0000_0000_0080),
102 Bits::<5>(18) => b64(0x0000_0000_0000_800a),
103 Bits::<5>(19) => b64(0x8000_0000_8000_000a),
104 Bits::<5>(20) => b64(0x8000_0000_8000_8081),
105 Bits::<5>(21) => b64(0x8000_0000_0000_8080),
106 Bits::<5>(22) => b64(0x0000_0000_8000_0001),
107 _ => b64(0x8000_0000_8000_8008),
108 }
109}
110
111#[kernel]
112fn keccak_round_with_constant(mut a: KeccakState, round_constant: b64) -> KeccakState {
113 let c0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20];
115 let c1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21];
116 let c2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22];
117 let c3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23];
118 let c4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24];
119 let d0 = c4 ^ rol01(c1);
120 let d1 = c0 ^ rol01(c2);
121 let d2 = c1 ^ rol01(c3);
122 let d3 = c2 ^ rol01(c4);
123 let d4 = c3 ^ rol01(c0);
124 a[0] ^= d0;
125 a[5] ^= d0;
126 a[10] ^= d0;
127 a[15] ^= d0;
128 a[20] ^= d0;
129 a[1] ^= d1;
130 a[6] ^= d1;
131 a[11] ^= d1;
132 a[16] ^= d1;
133 a[21] ^= d1;
134 a[2] ^= d2;
135 a[7] ^= d2;
136 a[12] ^= d2;
137 a[17] ^= d2;
138 a[22] ^= d2;
139 a[3] ^= d3;
140 a[8] ^= d3;
141 a[13] ^= d3;
142 a[18] ^= d3;
143 a[23] ^= d3;
144 a[4] ^= d4;
145 a[9] ^= d4;
146 a[14] ^= d4;
147 a[19] ^= d4;
148 a[24] ^= d4;
149
150 let mut b = [b64(0); 25];
152 b[0] = a[0];
153 b[10] = rol01(a[1]);
154 b[20] = rol62(a[2]);
155 b[5] = rol28(a[3]);
156 b[15] = rol27(a[4]);
157 b[16] = rol36(a[5]);
158 b[1] = rol44(a[6]);
159 b[11] = rol06(a[7]);
160 b[21] = rol55(a[8]);
161 b[6] = rol20(a[9]);
162 b[7] = rol03(a[10]);
163 b[17] = rol10(a[11]);
164 b[2] = rol43(a[12]);
165 b[12] = rol25(a[13]);
166 b[22] = rol39(a[14]);
167 b[23] = rol41(a[15]);
168 b[8] = rol45(a[16]);
169 b[18] = rol15(a[17]);
170 b[3] = rol21(a[18]);
171 b[13] = rol08(a[19]);
172 b[14] = rol18(a[20]);
173 b[24] = rol02(a[21]);
174 b[9] = rol61(a[22]);
175 b[19] = rol56(a[23]);
176 b[4] = rol14(a[24]);
177
178 let mut out = [b64(0); 25];
180 out[0] = b[0] ^ ((!b[1]) & b[2]);
181 out[1] = b[1] ^ ((!b[2]) & b[3]);
182 out[2] = b[2] ^ ((!b[3]) & b[4]);
183 out[3] = b[3] ^ ((!b[4]) & b[0]);
184 out[4] = b[4] ^ ((!b[0]) & b[1]);
185 out[5] = b[5] ^ ((!b[6]) & b[7]);
186 out[6] = b[6] ^ ((!b[7]) & b[8]);
187 out[7] = b[7] ^ ((!b[8]) & b[9]);
188 out[8] = b[8] ^ ((!b[9]) & b[5]);
189 out[9] = b[9] ^ ((!b[5]) & b[6]);
190 out[10] = b[10] ^ ((!b[11]) & b[12]);
191 out[11] = b[11] ^ ((!b[12]) & b[13]);
192 out[12] = b[12] ^ ((!b[13]) & b[14]);
193 out[13] = b[13] ^ ((!b[14]) & b[10]);
194 out[14] = b[14] ^ ((!b[10]) & b[11]);
195 out[15] = b[15] ^ ((!b[16]) & b[17]);
196 out[16] = b[16] ^ ((!b[17]) & b[18]);
197 out[17] = b[17] ^ ((!b[18]) & b[19]);
198 out[18] = b[18] ^ ((!b[19]) & b[15]);
199 out[19] = b[19] ^ ((!b[15]) & b[16]);
200 out[20] = b[20] ^ ((!b[21]) & b[22]);
201 out[21] = b[21] ^ ((!b[22]) & b[23]);
202 out[22] = b[22] ^ ((!b[23]) & b[24]);
203 out[23] = b[23] ^ ((!b[24]) & b[20]);
204 out[24] = b[24] ^ ((!b[20]) & b[21]);
205
206 out[0] ^= round_constant;
208 out
209}
210
211#[kernel]
218pub fn keccak_round(state: KeccakState, round: b5) -> KeccakState {
219 keccak_round_with_constant(state, iota_constant(round))
220}
221
222macro_rules! fixed_round {
227 ($name:ident, $number:literal, $constant:literal) => {
228 #[doc = concat!(
229 "Apply compile-time `Keccak-f[1600]` round ",
230 stringify!($number),
231 "."
232 )]
233 #[kernel]
234 pub fn $name(state: KeccakState) -> KeccakState {
235 keccak_round_with_constant(state, b64($constant))
236 }
237 };
238}
239
240fixed_round!(keccak_round_00, 0, 0x0000_0000_0000_0001);
241fixed_round!(keccak_round_01, 1, 0x0000_0000_0000_8082);
242fixed_round!(keccak_round_02, 2, 0x8000_0000_0000_808a);
243fixed_round!(keccak_round_03, 3, 0x8000_0000_8000_8000);
244fixed_round!(keccak_round_04, 4, 0x0000_0000_0000_808b);
245fixed_round!(keccak_round_05, 5, 0x0000_0000_8000_0001);
246fixed_round!(keccak_round_06, 6, 0x8000_0000_8000_8081);
247fixed_round!(keccak_round_07, 7, 0x8000_0000_0000_8009);
248fixed_round!(keccak_round_08, 8, 0x0000_0000_0000_008a);
249fixed_round!(keccak_round_09, 9, 0x0000_0000_0000_0088);
250fixed_round!(keccak_round_10, 10, 0x0000_0000_8000_8009);
251fixed_round!(keccak_round_11, 11, 0x0000_0000_8000_000a);
252fixed_round!(keccak_round_12, 12, 0x0000_0000_8000_808b);
253fixed_round!(keccak_round_13, 13, 0x8000_0000_0000_008b);
254fixed_round!(keccak_round_14, 14, 0x8000_0000_0000_8089);
255fixed_round!(keccak_round_15, 15, 0x8000_0000_0000_8003);
256fixed_round!(keccak_round_16, 16, 0x8000_0000_0000_8002);
257fixed_round!(keccak_round_17, 17, 0x8000_0000_0000_0080);
258fixed_round!(keccak_round_18, 18, 0x0000_0000_0000_800a);
259fixed_round!(keccak_round_19, 19, 0x8000_0000_8000_000a);
260fixed_round!(keccak_round_20, 20, 0x8000_0000_8000_8081);
261fixed_round!(keccak_round_21, 21, 0x8000_0000_0000_8080);
262fixed_round!(keccak_round_22, 22, 0x0000_0000_8000_0001);
263fixed_round!(keccak_round_23, 23, 0x8000_0000_8000_8008);
264
265#[must_use]
274pub fn software_keccak_round(mut a: [u64; 25], round: usize) -> [u64; 25] {
275 assert!(
276 round < ROUND_CONSTANTS.len(),
277 "Keccak round must be below 24"
278 );
279 let mut c = [0_u64; 5];
280 for x in 0..5 {
281 c[x] = a[x] ^ a[x + 5] ^ a[x + 10] ^ a[x + 15] ^ a[x + 20];
282 }
283 for x in 0..5 {
284 let d = c[(x + 4) % 5] ^ c[(x + 1) % 5].rotate_left(1);
285 for y in 0..5 {
286 a[x + 5 * y] ^= d;
287 }
288 }
289
290 let mut b = [0_u64; 25];
291 for x in 0..5 {
292 for y in 0..5 {
293 b[y + 5 * ((2 * x + 3 * y) % 5)] = a[x + 5 * y].rotate_left(ROTATION_OFFSETS[x][y]);
294 }
295 }
296
297 for x in 0..5 {
298 for y in 0..5 {
299 a[x + 5 * y] = b[x + 5 * y] ^ ((!b[(x + 1) % 5 + 5 * y]) & b[(x + 2) % 5 + 5 * y]);
300 }
301 }
302 a[0] ^= ROUND_CONSTANTS[round];
303 a
304}