1#![no_std]
40#![cfg_attr(docsrs, feature(doc_auto_cfg))]
41#![cfg_attr(feature = "simd", feature(portable_simd))]
42#![doc(
43 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
44 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
45)]
46#![allow(non_upper_case_globals)]
47#![warn(
48 clippy::mod_module_files,
49 clippy::unwrap_used,
50 missing_docs,
51 rust_2018_idioms,
52 unused_lifetimes,
53 unused_qualifications
54)]
55
56use core::{
57 convert::TryInto,
58 fmt::Debug,
59 mem::size_of,
60 ops::{BitAnd, BitAndAssign, BitXor, BitXorAssign, Not},
61};
62
63#[rustfmt::skip]
64mod unroll;
65
66#[cfg(all(target_arch = "aarch64", feature = "asm"))]
67mod armv8;
68
69#[cfg(all(target_arch = "aarch64", feature = "asm"))]
70cpufeatures::new!(armv8_sha3_intrinsics, "sha3");
71
72const PLEN: usize = 25;
73
74const RHO: [u32; 24] = [
75 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
76];
77
78const PI: [usize; 24] = [
79 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
80];
81
82const RC: [u64; 24] = [
83 0x0000000000000001,
84 0x0000000000008082,
85 0x800000000000808a,
86 0x8000000080008000,
87 0x000000000000808b,
88 0x0000000080000001,
89 0x8000000080008081,
90 0x8000000000008009,
91 0x000000000000008a,
92 0x0000000000000088,
93 0x0000000080008009,
94 0x000000008000000a,
95 0x000000008000808b,
96 0x800000000000008b,
97 0x8000000000008089,
98 0x8000000000008003,
99 0x8000000000008002,
100 0x8000000000000080,
101 0x000000000000800a,
102 0x800000008000000a,
103 0x8000000080008081,
104 0x8000000000008080,
105 0x0000000080000001,
106 0x8000000080008008,
107];
108
109pub trait LaneSize:
112 Copy
113 + Clone
114 + Debug
115 + Default
116 + PartialEq
117 + BitAndAssign
118 + BitAnd<Output = Self>
119 + BitXorAssign
120 + BitXor<Output = Self>
121 + Not<Output = Self>
122{
123 const KECCAK_F_ROUND_COUNT: usize;
125
126 fn truncate_rc(rc: u64) -> Self;
128
129 fn rotate_left(self, n: u32) -> Self;
131}
132
133macro_rules! impl_lanesize {
134 ($type:ty, $round:expr, $truncate:expr) => {
135 impl LaneSize for $type {
136 const KECCAK_F_ROUND_COUNT: usize = $round;
137
138 fn truncate_rc(rc: u64) -> Self {
139 $truncate(rc)
140 }
141
142 fn rotate_left(self, n: u32) -> Self {
143 self.rotate_left(n)
144 }
145 }
146 };
147}
148
149impl_lanesize!(u8, 18, |rc: u64| { rc.to_le_bytes()[0] });
150impl_lanesize!(u16, 20, |rc: u64| {
151 let tmp = rc.to_le_bytes();
152 #[allow(clippy::unwrap_used)]
153 Self::from_le_bytes(tmp[..size_of::<Self>()].try_into().unwrap())
154});
155impl_lanesize!(u32, 22, |rc: u64| {
156 let tmp = rc.to_le_bytes();
157 #[allow(clippy::unwrap_used)]
158 Self::from_le_bytes(tmp[..size_of::<Self>()].try_into().unwrap())
159});
160impl_lanesize!(u64, 24, |rc: u64| { rc });
161
162macro_rules! impl_keccak {
163 ($pname:ident, $fname:ident, $type:ty) => {
164 pub fn $pname(state: &mut [$type; PLEN], round_count: usize) {
166 keccak_p(state, round_count);
167 }
168
169 pub fn $fname(state: &mut [$type; PLEN]) {
171 keccak_p(state, <$type>::KECCAK_F_ROUND_COUNT);
172 }
173 };
174}
175
176impl_keccak!(p200, f200, u8);
177impl_keccak!(p400, f400, u16);
178impl_keccak!(p800, f800, u32);
179
180#[cfg(not(all(target_arch = "aarch64", feature = "asm")))]
181impl_keccak!(p1600, f1600, u64);
182
183#[cfg(all(target_arch = "aarch64", feature = "asm"))]
185pub fn p1600(state: &mut [u64; PLEN], round_count: usize) {
186 if armv8_sha3_intrinsics::get() {
187 unsafe { armv8::p1600_armv8_sha3_asm(state, round_count) }
188 } else {
189 keccak_p(state, round_count);
190 }
191}
192
193#[cfg(all(target_arch = "aarch64", feature = "asm"))]
195pub fn f1600(state: &mut [u64; PLEN]) {
196 if armv8_sha3_intrinsics::get() {
197 unsafe { armv8::p1600_armv8_sha3_asm(state, 24) }
198 } else {
199 keccak_p(state, u64::KECCAK_F_ROUND_COUNT);
200 }
201}
202
203#[cfg(feature = "simd")]
204pub mod simd {
206 use crate::{keccak_p, LaneSize, PLEN};
207 pub use core::simd::{u64x2, u64x4, u64x8};
208
209 macro_rules! impl_lanesize_simd_u64xn {
210 ($type:ty) => {
211 impl LaneSize for $type {
212 const KECCAK_F_ROUND_COUNT: usize = 24;
213
214 fn truncate_rc(rc: u64) -> Self {
215 Self::splat(rc)
216 }
217
218 fn rotate_left(self, n: u32) -> Self {
219 self << Self::splat(n.into()) | self >> Self::splat((64 - n).into())
220 }
221 }
222 };
223 }
224
225 impl_lanesize_simd_u64xn!(u64x2);
226 impl_lanesize_simd_u64xn!(u64x4);
227 impl_lanesize_simd_u64xn!(u64x8);
228
229 impl_keccak!(p1600x2, f1600x2, u64x2);
230 impl_keccak!(p1600x4, f1600x4, u64x4);
231 impl_keccak!(p1600x8, f1600x8, u64x8);
232}
233
234#[allow(unused_assignments)]
235pub fn keccak_p<L: LaneSize>(state: &mut [L; PLEN], round_count: usize) {
237 if round_count > L::KECCAK_F_ROUND_COUNT {
238 panic!("A round_count greater than KECCAK_F_ROUND_COUNT is not supported!");
239 }
240
241 let round_consts = &RC[(L::KECCAK_F_ROUND_COUNT - round_count)..L::KECCAK_F_ROUND_COUNT];
244
245 for &rc in round_consts {
248 let mut array = [L::default(); 5];
249
250 unroll5!(x, {
252 unroll5!(y, {
253 array[x] ^= state[5 * y + x];
254 });
255 });
256
257 unroll5!(x, {
258 unroll5!(y, {
259 let t1 = array[(x + 4) % 5];
260 let t2 = array[(x + 1) % 5].rotate_left(1);
261 state[5 * y + x] ^= t1 ^ t2;
262 });
263 });
264
265 let mut last = state[1];
267 unroll24!(x, {
268 array[0] = state[PI[x]];
269 state[PI[x]] = last.rotate_left(RHO[x]);
270 last = array[0];
271 });
272
273 unroll5!(y_step, {
275 let y = 5 * y_step;
276
277 unroll5!(x, {
278 array[x] = state[y + x];
279 });
280
281 unroll5!(x, {
282 let t1 = !array[(x + 1) % 5];
283 let t2 = array[(x + 2) % 5];
284 state[y + x] = array[x] ^ (t1 & t2);
285 });
286 });
287
288 state[0] ^= L::truncate_rc(rc);
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use crate::{keccak_p, LaneSize, PLEN};
296
297 fn keccak_f<L: LaneSize>(state_first: [L; PLEN], state_second: [L; PLEN]) {
298 let mut state = [L::default(); PLEN];
299
300 keccak_p(&mut state, L::KECCAK_F_ROUND_COUNT);
301 assert_eq!(state, state_first);
302
303 keccak_p(&mut state, L::KECCAK_F_ROUND_COUNT);
304 assert_eq!(state, state_second);
305 }
306
307 #[test]
308 fn keccak_f200() {
309 let state_first = [
312 0x3C, 0x28, 0x26, 0x84, 0x1C, 0xB3, 0x5C, 0x17, 0x1E, 0xAA, 0xE9, 0xB8, 0x11, 0x13,
313 0x4C, 0xEA, 0xA3, 0x85, 0x2C, 0x69, 0xD2, 0xC5, 0xAB, 0xAF, 0xEA,
314 ];
315 let state_second = [
316 0x1B, 0xEF, 0x68, 0x94, 0x92, 0xA8, 0xA5, 0x43, 0xA5, 0x99, 0x9F, 0xDB, 0x83, 0x4E,
317 0x31, 0x66, 0xA1, 0x4B, 0xE8, 0x27, 0xD9, 0x50, 0x40, 0x47, 0x9E,
318 ];
319
320 keccak_f::<u8>(state_first, state_second);
321 }
322
323 #[test]
324 fn keccak_f400() {
325 let state_first = [
328 0x09F5, 0x40AC, 0x0FA9, 0x14F5, 0xE89F, 0xECA0, 0x5BD1, 0x7870, 0xEFF0, 0xBF8F, 0x0337,
329 0x6052, 0xDC75, 0x0EC9, 0xE776, 0x5246, 0x59A1, 0x5D81, 0x6D95, 0x6E14, 0x633E, 0x58EE,
330 0x71FF, 0x714C, 0xB38E,
331 ];
332 let state_second = [
333 0xE537, 0xD5D6, 0xDBE7, 0xAAF3, 0x9BC7, 0xCA7D, 0x86B2, 0xFDEC, 0x692C, 0x4E5B, 0x67B1,
334 0x15AD, 0xA7F7, 0xA66F, 0x67FF, 0x3F8A, 0x2F99, 0xE2C2, 0x656B, 0x5F31, 0x5BA6, 0xCA29,
335 0xC224, 0xB85C, 0x097C,
336 ];
337
338 keccak_f::<u16>(state_first, state_second);
339 }
340
341 #[test]
342 fn keccak_f800() {
343 let state_first = [
346 0xE531D45D, 0xF404C6FB, 0x23A0BF99, 0xF1F8452F, 0x51FFD042, 0xE539F578, 0xF00B80A7,
347 0xAF973664, 0xBF5AF34C, 0x227A2424, 0x88172715, 0x9F685884, 0xB15CD054, 0x1BF4FC0E,
348 0x6166FA91, 0x1A9E599A, 0xA3970A1F, 0xAB659687, 0xAFAB8D68, 0xE74B1015, 0x34001A98,
349 0x4119EFF3, 0x930A0E76, 0x87B28070, 0x11EFE996,
350 ];
351 let state_second = [
352 0x75BF2D0D, 0x9B610E89, 0xC826AF40, 0x64CD84AB, 0xF905BDD6, 0xBC832835, 0x5F8001B9,
353 0x15662CCE, 0x8E38C95E, 0x701FE543, 0x1B544380, 0x89ACDEFF, 0x51EDB5DE, 0x0E9702D9,
354 0x6C19AA16, 0xA2913EEE, 0x60754E9A, 0x9819063C, 0xF4709254, 0xD09F9084, 0x772DA259,
355 0x1DB35DF7, 0x5AA60162, 0x358825D5, 0xB3783BAB,
356 ];
357
358 keccak_f::<u32>(state_first, state_second);
359 }
360
361 #[test]
362 fn keccak_f1600() {
363 let state_first = [
366 0xF1258F7940E1DDE7,
367 0x84D5CCF933C0478A,
368 0xD598261EA65AA9EE,
369 0xBD1547306F80494D,
370 0x8B284E056253D057,
371 0xFF97A42D7F8E6FD4,
372 0x90FEE5A0A44647C4,
373 0x8C5BDA0CD6192E76,
374 0xAD30A6F71B19059C,
375 0x30935AB7D08FFC64,
376 0xEB5AA93F2317D635,
377 0xA9A6E6260D712103,
378 0x81A57C16DBCF555F,
379 0x43B831CD0347C826,
380 0x01F22F1A11A5569F,
381 0x05E5635A21D9AE61,
382 0x64BEFEF28CC970F2,
383 0x613670957BC46611,
384 0xB87C5A554FD00ECB,
385 0x8C3EE88A1CCF32C8,
386 0x940C7922AE3A2614,
387 0x1841F924A2C509E4,
388 0x16F53526E70465C2,
389 0x75F644E97F30A13B,
390 0xEAF1FF7B5CECA249,
391 ];
392 let state_second = [
393 0x2D5C954DF96ECB3C,
394 0x6A332CD07057B56D,
395 0x093D8D1270D76B6C,
396 0x8A20D9B25569D094,
397 0x4F9C4F99E5E7F156,
398 0xF957B9A2DA65FB38,
399 0x85773DAE1275AF0D,
400 0xFAF4F247C3D810F7,
401 0x1F1B9EE6F79A8759,
402 0xE4FECC0FEE98B425,
403 0x68CE61B6B9CE68A1,
404 0xDEEA66C4BA8F974F,
405 0x33C43D836EAFB1F5,
406 0xE00654042719DBD9,
407 0x7CF8A9F009831265,
408 0xFD5449A6BF174743,
409 0x97DDAD33D8994B40,
410 0x48EAD5FC5D0BE774,
411 0xE3B8C8EE55B7B03C,
412 0x91A0226E649E42E9,
413 0x900E3129E7BADD7B,
414 0x202A9EC5FAA3CCE8,
415 0x5B3402464E1C3DB6,
416 0x609F4E62A44C1059,
417 0x20D06CD26A8FBF5C,
418 ];
419
420 keccak_f::<u64>(state_first, state_second);
421 }
422
423 #[cfg(feature = "simd")]
424 mod simd {
425 use super::keccak_f;
426 use core::simd::{u64x2, u64x4, u64x8};
427
428 macro_rules! impl_keccak_f1600xn {
429 ($name:ident, $type:ty) => {
430 #[test]
431 fn $name() {
432 let state_first = [
435 <$type>::splat(0xF1258F7940E1DDE7),
436 <$type>::splat(0x84D5CCF933C0478A),
437 <$type>::splat(0xD598261EA65AA9EE),
438 <$type>::splat(0xBD1547306F80494D),
439 <$type>::splat(0x8B284E056253D057),
440 <$type>::splat(0xFF97A42D7F8E6FD4),
441 <$type>::splat(0x90FEE5A0A44647C4),
442 <$type>::splat(0x8C5BDA0CD6192E76),
443 <$type>::splat(0xAD30A6F71B19059C),
444 <$type>::splat(0x30935AB7D08FFC64),
445 <$type>::splat(0xEB5AA93F2317D635),
446 <$type>::splat(0xA9A6E6260D712103),
447 <$type>::splat(0x81A57C16DBCF555F),
448 <$type>::splat(0x43B831CD0347C826),
449 <$type>::splat(0x01F22F1A11A5569F),
450 <$type>::splat(0x05E5635A21D9AE61),
451 <$type>::splat(0x64BEFEF28CC970F2),
452 <$type>::splat(0x613670957BC46611),
453 <$type>::splat(0xB87C5A554FD00ECB),
454 <$type>::splat(0x8C3EE88A1CCF32C8),
455 <$type>::splat(0x940C7922AE3A2614),
456 <$type>::splat(0x1841F924A2C509E4),
457 <$type>::splat(0x16F53526E70465C2),
458 <$type>::splat(0x75F644E97F30A13B),
459 <$type>::splat(0xEAF1FF7B5CECA249),
460 ];
461 let state_second = [
462 <$type>::splat(0x2D5C954DF96ECB3C),
463 <$type>::splat(0x6A332CD07057B56D),
464 <$type>::splat(0x093D8D1270D76B6C),
465 <$type>::splat(0x8A20D9B25569D094),
466 <$type>::splat(0x4F9C4F99E5E7F156),
467 <$type>::splat(0xF957B9A2DA65FB38),
468 <$type>::splat(0x85773DAE1275AF0D),
469 <$type>::splat(0xFAF4F247C3D810F7),
470 <$type>::splat(0x1F1B9EE6F79A8759),
471 <$type>::splat(0xE4FECC0FEE98B425),
472 <$type>::splat(0x68CE61B6B9CE68A1),
473 <$type>::splat(0xDEEA66C4BA8F974F),
474 <$type>::splat(0x33C43D836EAFB1F5),
475 <$type>::splat(0xE00654042719DBD9),
476 <$type>::splat(0x7CF8A9F009831265),
477 <$type>::splat(0xFD5449A6BF174743),
478 <$type>::splat(0x97DDAD33D8994B40),
479 <$type>::splat(0x48EAD5FC5D0BE774),
480 <$type>::splat(0xE3B8C8EE55B7B03C),
481 <$type>::splat(0x91A0226E649E42E9),
482 <$type>::splat(0x900E3129E7BADD7B),
483 <$type>::splat(0x202A9EC5FAA3CCE8),
484 <$type>::splat(0x5B3402464E1C3DB6),
485 <$type>::splat(0x609F4E62A44C1059),
486 <$type>::splat(0x20D06CD26A8FBF5C),
487 ];
488
489 keccak_f::<$type>(state_first, state_second);
490 }
491 };
492 }
493
494 impl_keccak_f1600xn!(keccak_f1600x2, u64x2);
495 impl_keccak_f1600xn!(keccak_f1600x4, u64x4);
496 impl_keccak_f1600xn!(keccak_f1600x8, u64x8);
497 }
498}