1const KECCAK_ROUNDS: usize = 24;
15
16const RC: [u64; 24] = [
17 0x0000000000000001,
18 0x0000000000008082,
19 0x800000000000808A,
20 0x8000000080008000,
21 0x000000000000808B,
22 0x0000000080000001,
23 0x8000000080008081,
24 0x8000000000008009,
25 0x000000000000008A,
26 0x0000000000000088,
27 0x0000000080008009,
28 0x000000008000000A,
29 0x000000008000808B,
30 0x800000000000008B,
31 0x8000000000008089,
32 0x8000000000008003,
33 0x8000000000008002,
34 0x8000000000000080,
35 0x000000000000800A,
36 0x800000008000000A,
37 0x8000000080008081,
38 0x8000000000008080,
39 0x0000000080000001,
40 0x8000000080008008,
41];
42
43const ROTC: [u32; 24] = [
44 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
45];
46
47const PI: [usize; 24] = [
48 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
49];
50
51#[inline(always)]
52fn keccak_f(state: &mut [u64; 25]) {
53 for round in 0..KECCAK_ROUNDS {
54 let mut c = [0u64; 5];
56 for x in 0..5 {
57 c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ state[x + 20];
58 }
59 let mut d = [0u64; 5];
60 for x in 0..5 {
61 d[x] = c[(x + 4) % 5] ^ c[(x + 1) % 5].rotate_left(1);
62 }
63 for i in 0..25 {
64 state[i] ^= d[i % 5];
65 }
66
67 let mut last = state[1];
69 for i in 0..24 {
70 let j = PI[i];
71 let temp = state[j];
72 state[j] = last.rotate_left(ROTC[i]);
73 last = temp;
74 }
75
76 for y in (0..25).step_by(5) {
78 let t0 = state[y];
79 let t1 = state[y + 1];
80 let t2 = state[y + 2];
81 let t3 = state[y + 3];
82 let t4 = state[y + 4];
83 state[y] = t0 ^ (!t1 & t2);
84 state[y + 1] = t1 ^ (!t2 & t3);
85 state[y + 2] = t2 ^ (!t3 & t4);
86 state[y + 3] = t3 ^ (!t4 & t0);
87 state[y + 4] = t4 ^ (!t0 & t1);
88 }
89
90 state[0] ^= RC[round];
92 }
93}
94
95pub struct KeccakState {
102 state: [u64; 25],
103 offset: usize,
105 rate: usize,
107 suffix: u8,
109 squeezing: bool,
111}
112
113impl KeccakState {
114 pub fn new(rate: usize, suffix: u8) -> Self {
120 Self {
121 state: [0u64; 25],
122 offset: 0,
123 rate,
124 suffix,
125 squeezing: false,
126 }
127 }
128
129 pub fn absorb(&mut self, data: &[u8]) {
140 debug_assert!(!self.squeezing, "Cannot absorb after squeezing");
141 let mut pos = 0;
142 while pos < data.len() {
143 let block_remaining = self.rate - self.offset;
144 let to_copy = block_remaining.min(data.len() - pos);
145
146 let state_bytes = state_as_bytes_mut(&mut self.state);
148 for i in 0..to_copy {
149 state_bytes[self.offset + i] ^= data[pos + i];
150 }
151 self.offset += to_copy;
152 pos += to_copy;
153
154 if self.offset == self.rate {
155 keccak_f(&mut self.state);
156 self.offset = 0;
157 }
158 }
159 }
160
161 fn finalize(&mut self) {
163 if !self.squeezing {
164 let state_bytes = state_as_bytes_mut(&mut self.state);
165 state_bytes[self.offset] ^= self.suffix;
167 state_bytes[self.rate - 1] ^= 0x80;
168 keccak_f(&mut self.state);
169 self.offset = 0;
170 self.squeezing = true;
171 }
172 }
173
174 pub fn squeeze(&mut self, out: &mut [u8]) {
181 self.finalize();
182 let mut pos = 0;
183 while pos < out.len() {
184 if self.offset == self.rate {
185 keccak_f(&mut self.state);
186 self.offset = 0;
187 }
188 let available = self.rate - self.offset;
189 let to_copy = available.min(out.len() - pos);
190
191 let mut i = 0;
193 while i + 8 <= to_copy && (self.offset + i) % 8 == 0 {
194 let lane = (self.offset + i) / 8;
195 let bytes = self.state[lane].to_le_bytes();
196 out[pos + i..pos + i + 8].copy_from_slice(&bytes);
197 i += 8;
198 }
199 let state_bytes = state_as_bytes(&self.state);
201 while i < to_copy {
202 out[pos + i] = state_bytes[self.offset + i];
203 i += 1;
204 }
205
206 self.offset += to_copy;
207 pos += to_copy;
208 }
209 }
210}
211
212#[inline]
213fn state_as_bytes(state: &[u64; 25]) -> &[u8; 200] {
214 unsafe { &*(state.as_ptr() as *const [u8; 200]) }
215}
216
217#[inline]
218fn state_as_bytes_mut(state: &mut [u64; 25]) -> &mut [u8; 200] {
219 unsafe { &mut *(state.as_mut_ptr() as *mut [u8; 200]) }
220}
221
222pub const SHA3_256_RATE: usize = 136;
228pub const SHA3_512_RATE: usize = 72;
230pub const SHAKE128_RATE: usize = 168;
232pub const SHAKE256_RATE: usize = 136;
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 fn sha3_256(input: &[u8]) -> [u8; 32] {
240 let mut s = KeccakState::new(SHA3_256_RATE, 0x06);
241 s.absorb(input);
242 let mut out = [0u8; 32];
243 s.squeeze(&mut out);
244 out
245 }
246
247 fn sha3_512(input: &[u8]) -> [u8; 64] {
248 let mut s = KeccakState::new(SHA3_512_RATE, 0x06);
249 s.absorb(input);
250 let mut out = [0u8; 64];
251 s.squeeze(&mut out);
252 out
253 }
254
255 #[test]
256 fn sha3_256_empty_kat() {
257 let out = sha3_256(b"");
259 let expected = [
260 0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66, 0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61, 0xd6, 0x62, 0xf5, 0x80,
261 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa, 0x82, 0xd8, 0x0a, 0x4b, 0x80, 0xf8, 0x43, 0x4a,
262 ];
263 assert_eq!(out, expected);
264 }
265
266 #[test]
267 fn sha3_512_empty_kat_first_32() {
268 let out = sha3_512(b"");
269 let expected_first_32 = [
270 0xa6, 0x9f, 0x73, 0xcc, 0xa2, 0x3a, 0x9a, 0xc5, 0xc8, 0xb5, 0x67, 0xdc, 0x18, 0x5a, 0x75, 0x6e, 0x97, 0xc9,
271 0x82, 0x16, 0x4f, 0xe2, 0x58, 0x59, 0xe0, 0xd1, 0xdc, 0xc1, 0x47, 0x5c, 0x80, 0xa6,
272 ];
273 assert_eq!(&out[..32], &expected_first_32);
274 }
275}