1#![cfg_attr(keccak_portable_simd, feature(portable_simd))]
28#![doc(
29 html_logo_url = "https://raw.githubusercontent.com/Enkom-Tech/libQ/main/docs/logo.svg",
30 html_favicon_url = "https://raw.githubusercontent.com/Enkom-Tech/libQ/main/docs/logo.svg"
31)]
32#![allow(non_upper_case_globals)]
33#![warn(
34 clippy::mod_module_files,
35 clippy::unwrap_used,
36 missing_docs,
37 rust_2018_idioms,
38 unused_lifetimes,
39 unused_qualifications
40)]
41#![cfg_attr(not(feature = "std"), no_std)]
42
43#[cfg(feature = "std")]
45extern crate std;
46
47use core::fmt::Debug;
86use core::ops::{
87 BitAnd,
88 BitAndAssign,
89 BitXor,
90 BitXorAssign,
91 Not,
92};
93
94#[rustfmt::skip]
95mod unroll;
96
97#[cfg(all(
100 target_arch = "aarch64",
101 feature = "asm",
102 not(target_os = "windows"), feature = "std",
104 feature = "arm64_sha3" ))]
106mod armv8;
107
108#[cfg(all(
109 target_arch = "aarch64",
110 feature = "asm",
111 not(target_os = "windows"), feature = "std",
113 feature = "arm64_sha3" ))]
115#[inline]
116fn armv8_sha3_runtime_available() -> bool {
117 std::arch::is_aarch64_feature_detected!("sha3")
118}
119
120#[cfg(all(target_arch = "x86_64", feature = "asm"))]
121mod x86;
122
123#[cfg(all(
129 target_arch = "x86_64",
130 not(cross_compile),
131 any(target_feature = "avx2", feature = "std")
132))]
133mod x86_simd;
134
135#[cfg(all(
138 target_arch = "x86_64",
139 not(cross_compile),
140 any(target_feature = "avx512f", feature = "std")
141))]
142mod x86_simd_avx512;
143
144#[cfg(all(feature = "simd", keccak_portable_simd))]
145mod advanced_simd;
146
147mod features;
148mod optimized_core;
149
150#[cfg(all(feature = "multithreading", feature = "std"))]
151mod multithreading;
152
153const PLEN: usize = 25;
154
155const RHO: [u32; 24] = [
156 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
157];
158
159const PI: [usize; 24] = [
160 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
161];
162
163#[allow(clippy::unreadable_literal)]
165const RC: [u64; 24] = [
166 0x0000000000000001,
167 0x0000000000008082,
168 0x800000000000808A,
169 0x8000000080008000,
170 0x000000000000808B,
171 0x0000000080000001,
172 0x8000000080008081,
173 0x8000000000008009,
174 0x000000000000008A,
175 0x0000000000000088,
176 0x0000000080008009,
177 0x000000008000000A,
178 0x000000008000808B,
179 0x800000000000008B,
180 0x8000000000008089,
181 0x8000000000008003,
182 0x8000000000008002,
183 0x8000000000000080,
184 0x000000000000800A,
185 0x800000008000000A,
186 0x8000000080008081,
187 0x8000000000008080,
188 0x0000000080000001,
189 0x8000000080008008,
190];
191
192pub trait LaneSize:
195 Copy
196 + Clone
197 + Debug
198 + Default
199 + PartialEq
200 + BitAndAssign
201 + BitAnd<Output = Self>
202 + BitXorAssign
203 + BitXor<Output = Self>
204 + Not<Output = Self>
205{
206 const KECCAK_F_ROUND_COUNT: usize;
208
209 fn truncate_rc(rc: u64) -> Self;
211
212 fn rotate_left(self, n: u32) -> Self;
214}
215
216macro_rules! impl_lanesize {
217 ($type:ty, $round:expr, $truncate:expr) => {
218 impl LaneSize for $type {
219 const KECCAK_F_ROUND_COUNT: usize = $round;
220
221 fn truncate_rc(rc: u64) -> Self {
222 $truncate(rc)
223 }
224
225 fn rotate_left(self, n: u32) -> Self {
226 self.rotate_left(n)
227 }
228 }
229 };
230}
231
232impl_lanesize!(u8, 18, |rc: u64| { rc.to_le_bytes()[0] });
233impl_lanesize!(u16, 20, |rc: u64| {
234 let tmp = rc.to_le_bytes();
235 let bytes = [tmp[0], tmp[1]];
237 Self::from_le_bytes(bytes)
238});
239impl_lanesize!(u32, 22, |rc: u64| {
240 let tmp = rc.to_le_bytes();
241 let bytes = [tmp[0], tmp[1], tmp[2], tmp[3]];
243 Self::from_le_bytes(bytes)
244});
245impl_lanesize!(u64, 24, |rc: u64| { rc });
246
247macro_rules! impl_keccak {
248 ($pname:ident, $fname:ident, $type:ty) => {
249 pub fn $pname(state: &mut [$type; PLEN], round_count: usize) {
251 keccak_p(state, round_count);
252 }
253
254 pub fn $fname(state: &mut [$type; PLEN]) {
256 keccak_p(state, <$type>::KECCAK_F_ROUND_COUNT);
257 }
258 };
259}
260
261impl_keccak!(p200, f200, u8);
262impl_keccak!(p400, f400, u16);
263impl_keccak!(p800, f800, u32);
264
265#[cfg(not(all(
268 target_arch = "aarch64",
269 feature = "asm",
270 not(target_os = "windows"),
271 feature = "std",
272 feature = "arm64_sha3"
273)))]
274impl_keccak!(p1600, f1600, u64);
275
276#[cfg(all(
278 target_arch = "aarch64",
279 feature = "asm",
280 not(target_os = "windows"),
281 feature = "std",
282 feature = "arm64_sha3"
283))]
284pub fn p1600(state: &mut [u64; PLEN], round_count: usize) {
285 if armv8_sha3_runtime_available() {
286 unsafe { armv8::p1600_armv8_sha3_asm(state, round_count) }
287 } else {
288 keccak_p(state, round_count);
289 }
290}
291
292#[cfg(all(
294 target_arch = "aarch64",
295 feature = "asm",
296 not(target_os = "windows"),
297 feature = "std",
298 feature = "arm64_sha3"
299))]
300pub fn f1600(state: &mut [u64; PLEN]) {
301 if armv8_sha3_runtime_available() {
302 unsafe { armv8::p1600_armv8_sha3_asm(state, 24) }
303 } else {
304 keccak_p(state, u64::KECCAK_F_ROUND_COUNT);
305 }
306}
307
308#[allow(clippy::needless_return)]
324pub fn p1600x4(states: &mut [[u64; PLEN]; 4], round_count: usize) {
325 #[cfg(all(target_arch = "x86_64", target_feature = "avx2", not(cross_compile)))]
328 {
329 unsafe { x86_simd::p1600x4_avx2(states, round_count) };
331 return;
332 }
333
334 #[cfg(all(
336 target_arch = "x86_64",
337 feature = "std",
338 not(target_feature = "avx2"),
339 not(cross_compile)
340 ))]
341 {
342 if std::arch::is_x86_feature_detected!("avx2") {
343 unsafe { x86_simd::p1600x4_avx2(states, round_count) };
345 return;
346 }
347 }
348
349 #[cfg(not(all(target_arch = "x86_64", target_feature = "avx2", not(cross_compile))))]
352 for state in states.iter_mut() {
353 p1600(state, round_count);
354 }
355}
356
357#[allow(clippy::needless_return)]
374pub fn p1600x8(states: &mut [[u64; PLEN]; 8], round_count: usize) {
375 #[cfg(all(target_arch = "x86_64", target_feature = "avx512f", not(cross_compile)))]
377 {
378 unsafe { x86_simd_avx512::p1600x8_avx512(states, round_count) };
380 return;
381 }
382
383 #[cfg(all(
385 target_arch = "x86_64",
386 feature = "std",
387 not(target_feature = "avx512f"),
388 not(cross_compile)
389 ))]
390 {
391 if std::arch::is_x86_feature_detected!("avx512f") {
392 unsafe { x86_simd_avx512::p1600x8_avx512(states, round_count) };
394 return;
395 }
396 }
397
398 #[cfg(not(all(target_arch = "x86_64", target_feature = "avx512f", not(cross_compile))))]
400 for state in states.iter_mut() {
401 p1600(state, round_count);
402 }
403}
404
405#[cfg(all(feature = "simd", keccak_portable_simd))]
406pub mod simd {
408 pub use core::simd::{
409 u64x2,
410 u64x4,
411 u64x8,
412 };
413
414 use crate::{
415 LaneSize,
416 PLEN,
417 keccak_p,
418 };
419
420 macro_rules! impl_lanesize_simd_u64xn {
421 ($type:ty) => {
422 impl LaneSize for $type {
423 const KECCAK_F_ROUND_COUNT: usize = 24;
424
425 fn truncate_rc(rc: u64) -> Self {
426 Self::splat(rc)
427 }
428
429 fn rotate_left(self, n: u32) -> Self {
430 self << Self::splat(n.into()) | self >> Self::splat((64 - n).into())
431 }
432 }
433 };
434 }
435
436 impl_lanesize_simd_u64xn!(u64x2);
437 impl_lanesize_simd_u64xn!(u64x4);
438 impl_lanesize_simd_u64xn!(u64x8);
439
440 impl_keccak!(p1600x2, f1600x2, u64x2);
441 impl_keccak!(p1600x4, f1600x4, u64x4);
442 impl_keccak!(p1600x8, f1600x8, u64x8);
443}
444
445#[cfg(all(feature = "simd", keccak_portable_simd))]
446pub mod advanced {
448 pub use super::advanced_simd::*;
449}
450
451#[allow(unused_assignments)]
452pub fn keccak_p<L: LaneSize>(state: &mut [L; PLEN], round_count: usize) {
454 if round_count > L::KECCAK_F_ROUND_COUNT {
457 return;
459 }
460
461 let round_consts = &RC[(L::KECCAK_F_ROUND_COUNT - round_count)..L::KECCAK_F_ROUND_COUNT];
464
465 for &rc in round_consts {
468 let mut array = [L::default(); 5];
469
470 unroll5!(x, {
472 unroll5!(y, {
473 array[x] ^= state[5 * y + x];
474 });
475 });
476
477 unroll5!(x, {
478 let t1 = array[(x + 4) % 5];
479 let t2 = array[(x + 1) % 5].rotate_left(1);
480 unroll5!(y, {
481 state[5 * y + x] ^= t1 ^ t2;
482 });
483 });
484
485 let mut last = state[1];
487 unroll24!(x, {
488 array[0] = state[PI[x]];
489 state[PI[x]] = last.rotate_left(RHO[x]);
490 last = array[0];
491 });
492
493 unroll5!(y_step, {
495 let y = 5 * y_step;
496
497 array.copy_from_slice(&state[y..][..5]);
498
499 unroll5!(x, {
500 let t1 = !array[(x + 1) % 5];
501 let t2 = array[(x + 2) % 5];
502 state[y + x] = array[x] ^ (t1 & t2);
503 });
504 });
505
506 state[0] ^= L::truncate_rc(rc);
508 }
509}
510
511#[cfg(all(feature = "simd", keccak_portable_simd))]
514pub use crate::advanced_simd::{
515 AdvancedLaneSize,
516 SimdConfig,
517 SimdSecurityValidator,
518 parallel as simd_parallel,
519};
520pub use crate::features::{
521 FeatureConfig,
522 FeatureReport,
523 detection,
524 get_global_config,
525 reset_global_config,
526 set_global_config,
527};
528#[cfg(all(feature = "multithreading", feature = "std"))]
530pub use crate::multithreading::{
531 AffinityStrategy,
532 CryptoThreadPool,
533 ThreadingConfig,
534 WorkerStats,
535 get_global_thread_pool,
536 init_global_thread_pool,
537 process_keccak_states_global,
538};
539#[cfg(feature = "simd")]
540pub use crate::optimized_core::parallel;
541#[cfg(all(feature = "multithreading", feature = "std", feature = "simd"))]
542pub use crate::optimized_core::parallel::p1600_multithreaded;
543pub use crate::optimized_core::{
544 OptimizationLevel,
545 fast_loop_absorb_optimized,
546 p1600_optimized,
547};
548
549#[cfg(test)]
550#[allow(clippy::unreadable_literal)] mod tests {
552 use crate::{
553 LaneSize,
554 PLEN,
555 keccak_p,
556 };
557
558 fn keccak_f<L: LaneSize>(state_first: [L; PLEN], state_second: [L; PLEN]) {
559 let mut state = [L::default(); PLEN];
560
561 keccak_p(&mut state, L::KECCAK_F_ROUND_COUNT);
562 assert_eq!(state, state_first);
563
564 keccak_p(&mut state, L::KECCAK_F_ROUND_COUNT);
565 assert_eq!(state, state_second);
566 }
567
568 #[test]
569 fn keccak_f200() {
570 let state_first = [
573 0x3C, 0x28, 0x26, 0x84, 0x1C, 0xB3, 0x5C, 0x17, 0x1E, 0xAA, 0xE9, 0xB8, 0x11, 0x13,
574 0x4C, 0xEA, 0xA3, 0x85, 0x2C, 0x69, 0xD2, 0xC5, 0xAB, 0xAF, 0xEA,
575 ];
576 let state_second = [
577 0x1B, 0xEF, 0x68, 0x94, 0x92, 0xA8, 0xA5, 0x43, 0xA5, 0x99, 0x9F, 0xDB, 0x83, 0x4E,
578 0x31, 0x66, 0xA1, 0x4B, 0xE8, 0x27, 0xD9, 0x50, 0x40, 0x47, 0x9E,
579 ];
580
581 keccak_f::<u8>(state_first, state_second);
582 }
583
584 #[test]
585 fn keccak_f400() {
586 let state_first = [
589 0x09F5, 0x40AC, 0x0FA9, 0x14F5, 0xE89F, 0xECA0, 0x5BD1, 0x7870, 0xEFF0, 0xBF8F, 0x0337,
590 0x6052, 0xDC75, 0x0EC9, 0xE776, 0x5246, 0x59A1, 0x5D81, 0x6D95, 0x6E14, 0x633E, 0x58EE,
591 0x71FF, 0x714C, 0xB38E,
592 ];
593 let state_second = [
594 0xE537, 0xD5D6, 0xDBE7, 0xAAF3, 0x9BC7, 0xCA7D, 0x86B2, 0xFDEC, 0x692C, 0x4E5B, 0x67B1,
595 0x15AD, 0xA7F7, 0xA66F, 0x67FF, 0x3F8A, 0x2F99, 0xE2C2, 0x656B, 0x5F31, 0x5BA6, 0xCA29,
596 0xC224, 0xB85C, 0x097C,
597 ];
598
599 keccak_f::<u16>(state_first, state_second);
600 }
601
602 #[test]
603 fn keccak_f800() {
604 let state_first = [
607 0xE531D45D, 0xF404C6FB, 0x23A0BF99, 0xF1F8452F, 0x51FFD042, 0xE539F578, 0xF00B80A7,
608 0xAF973664, 0xBF5AF34C, 0x227A2424, 0x88172715, 0x9F685884, 0xB15CD054, 0x1BF4FC0E,
609 0x6166FA91, 0x1A9E599A, 0xA3970A1F, 0xAB659687, 0xAFAB8D68, 0xE74B1015, 0x34001A98,
610 0x4119EFF3, 0x930A0E76, 0x87B28070, 0x11EFE996,
611 ];
612 let state_second = [
613 0x75BF2D0D, 0x9B610E89, 0xC826AF40, 0x64CD84AB, 0xF905BDD6, 0xBC832835, 0x5F8001B9,
614 0x15662CCE, 0x8E38C95E, 0x701FE543, 0x1B544380, 0x89ACDEFF, 0x51EDB5DE, 0x0E9702D9,
615 0x6C19AA16, 0xA2913EEE, 0x60754E9A, 0x9819063C, 0xF4709254, 0xD09F9084, 0x772DA259,
616 0x1DB35DF7, 0x5AA60162, 0x358825D5, 0xB3783BAB,
617 ];
618
619 keccak_f::<u32>(state_first, state_second);
620 }
621
622 #[test]
623 fn keccak_f1600() {
624 let state_first = [
627 0xF1258F7940E1DDE7,
628 0x84D5CCF933C0478A,
629 0xD598261EA65AA9EE,
630 0xBD1547306F80494D,
631 0x8B284E056253D057,
632 0xFF97A42D7F8E6FD4,
633 0x90FEE5A0A44647C4,
634 0x8C5BDA0CD6192E76,
635 0xAD30A6F71B19059C,
636 0x30935AB7D08FFC64,
637 0xEB5AA93F2317D635,
638 0xA9A6E6260D712103,
639 0x81A57C16DBCF555F,
640 0x43B831CD0347C826,
641 0x01F22F1A11A5569F,
642 0x05E5635A21D9AE61,
643 0x64BEFEF28CC970F2,
644 0x613670957BC46611,
645 0xB87C5A554FD00ECB,
646 0x8C3EE88A1CCF32C8,
647 0x940C7922AE3A2614,
648 0x1841F924A2C509E4,
649 0x16F53526E70465C2,
650 0x75F644E97F30A13B,
651 0xEAF1FF7B5CECA249,
652 ];
653 let state_second = [
654 0x2D5C954DF96ECB3C,
655 0x6A332CD07057B56D,
656 0x093D8D1270D76B6C,
657 0x8A20D9B25569D094,
658 0x4F9C4F99E5E7F156,
659 0xF957B9A2DA65FB38,
660 0x85773DAE1275AF0D,
661 0xFAF4F247C3D810F7,
662 0x1F1B9EE6F79A8759,
663 0xE4FECC0FEE98B425,
664 0x68CE61B6B9CE68A1,
665 0xDEEA66C4BA8F974F,
666 0x33C43D836EAFB1F5,
667 0xE00654042719DBD9,
668 0x7CF8A9F009831265,
669 0xFD5449A6BF174743,
670 0x97DDAD33D8994B40,
671 0x48EAD5FC5D0BE774,
672 0xE3B8C8EE55B7B03C,
673 0x91A0226E649E42E9,
674 0x900E3129E7BADD7B,
675 0x202A9EC5FAA3CCE8,
676 0x5B3402464E1C3DB6,
677 0x609F4E62A44C1059,
678 0x20D06CD26A8FBF5C,
679 ];
680
681 keccak_f::<u64>(state_first, state_second);
682 }
683
684 #[cfg(all(test, feature = "simd", keccak_portable_simd))]
685 mod test_simd {
686 use core::simd::{
687 u64x2,
688 u64x4,
689 u64x8,
690 };
691
692 use crate::tests::keccak_f;
693
694 macro_rules! impl_keccak_f1600xn {
695 ($name:ident, $type:ty) => {
696 #[test]
697 fn $name() {
698 let state_first = [
701 <$type>::splat(0xF1258F7940E1DDE7),
702 <$type>::splat(0x84D5CCF933C0478A),
703 <$type>::splat(0xD598261EA65AA9EE),
704 <$type>::splat(0xBD1547306F80494D),
705 <$type>::splat(0x8B284E056253D057),
706 <$type>::splat(0xFF97A42D7F8E6FD4),
707 <$type>::splat(0x90FEE5A0A44647C4),
708 <$type>::splat(0x8C5BDA0CD6192E76),
709 <$type>::splat(0xAD30A6F71B19059C),
710 <$type>::splat(0x30935AB7D08FFC64),
711 <$type>::splat(0xEB5AA93F2317D635),
712 <$type>::splat(0xA9A6E6260D712103),
713 <$type>::splat(0x81A57C16DBCF555F),
714 <$type>::splat(0x43B831CD0347C826),
715 <$type>::splat(0x01F22F1A11A5569F),
716 <$type>::splat(0x05E5635A21D9AE61),
717 <$type>::splat(0x64BEFEF28CC970F2),
718 <$type>::splat(0x613670957BC46611),
719 <$type>::splat(0xB87C5A554FD00ECB),
720 <$type>::splat(0x8C3EE88A1CCF32C8),
721 <$type>::splat(0x940C7922AE3A2614),
722 <$type>::splat(0x1841F924A2C509E4),
723 <$type>::splat(0x16F53526E70465C2),
724 <$type>::splat(0x75F644E97F30A13B),
725 <$type>::splat(0xEAF1FF7B5CECA249),
726 ];
727 let state_second = [
728 <$type>::splat(0x2D5C954DF96ECB3C),
729 <$type>::splat(0x6A332CD07057B56D),
730 <$type>::splat(0x093D8D1270D76B6C),
731 <$type>::splat(0x8A20D9B25569D094),
732 <$type>::splat(0x4F9C4F99E5E7F156),
733 <$type>::splat(0xF957B9A2DA65FB38),
734 <$type>::splat(0x85773DAE1275AF0D),
735 <$type>::splat(0xFAF4F247C3D810F7),
736 <$type>::splat(0x1F1B9EE6F79A8759),
737 <$type>::splat(0xE4FECC0FEE98B425),
738 <$type>::splat(0x68CE61B6B9CE68A1),
739 <$type>::splat(0xDEEA66C4BA8F974F),
740 <$type>::splat(0x33C43D836EAFB1F5),
741 <$type>::splat(0xE00654042719DBD9),
742 <$type>::splat(0x7CF8A9F009831265),
743 <$type>::splat(0xFD5449A6BF174743),
744 <$type>::splat(0x97DDAD33D8994B40),
745 <$type>::splat(0x48EAD5FC5D0BE774),
746 <$type>::splat(0xE3B8C8EE55B7B03C),
747 <$type>::splat(0x91A0226E649E42E9),
748 <$type>::splat(0x900E3129E7BADD7B),
749 <$type>::splat(0x202A9EC5FAA3CCE8),
750 <$type>::splat(0x5B3402464E1C3DB6),
751 <$type>::splat(0x609F4E62A44C1059),
752 <$type>::splat(0x20D06CD26A8FBF5C),
753 ];
754
755 keccak_f::<$type>(state_first, state_second);
756 }
757 };
758 }
759
760 impl_keccak_f1600xn!(keccak_f1600x2, u64x2);
761 impl_keccak_f1600xn!(keccak_f1600x4, u64x4);
762 impl_keccak_f1600xn!(keccak_f1600x8, u64x8);
763 }
764}