1use crate::{consts::*, types::Fn1600};
2use core::ops::{BitAnd, BitAndAssign, BitXor, BitXorAssign, Not};
3#[cfg(feature = "parallel")]
4use hybrid_array::typenum::U1;
5
6pub trait LaneSize:
8 Copy
9 + Clone
10 + Default
11 + PartialEq
12 + BitAndAssign
13 + BitAnd<Output = Self>
14 + BitXorAssign
15 + BitXor<Output = Self>
16 + Not<Output = Self>
17 + 'static
18{
19 const RC: &[Self];
21
22 #[must_use]
24 fn rotate_left(self, n: u32) -> Self;
25}
26
27macro_rules! impl_lanesize {
28 ($type:ty, $round:expr) => {
29 impl LaneSize for $type {
30 const RC: &[Self] = &{
31 let mut res = [0; $round];
32 let mut i = 0;
33 #[allow(clippy::cast_possible_truncation, trivial_numeric_casts)]
34 while i < res.len() {
35 res[i] = RC[i] as Self;
36 i += 1;
37 }
38 res
39 };
40
41 fn rotate_left(self, n: u32) -> Self {
42 self.rotate_left(n)
43 }
44 }
45 };
46}
47
48impl_lanesize!(u8, F200_ROUNDS);
49impl_lanesize!(u16, F400_ROUNDS);
50impl_lanesize!(u32, F800_ROUNDS);
51impl_lanesize!(u64, F1600_ROUNDS);
52
53pub(crate) fn keccak_p<L: LaneSize, const ROUNDS: usize>(state: &mut [L; PLEN]) {
58 const { assert!(ROUNDS <= L::RC.len()) };
59
60 let round_consts = L::RC
63 .last_chunk::<ROUNDS>()
64 .expect("Number of rounds is checked above");
65
66 for rc in round_consts {
69 let mut array = [L::default(); 5];
70
71 for x in 0..5 {
73 for y in 0..5 {
74 array[x] ^= state[5 * y + x];
75 }
76 }
77
78 for x in 0..5 {
79 let t1 = array[(x + 4) % 5];
80 let t2 = array[(x + 1) % 5].rotate_left(1);
81 for y in 0..5 {
82 state[5 * y + x] ^= t1 ^ t2;
83 }
84 }
85
86 let mut last = state[1];
88 for x in 0..24 {
89 array[0] = state[PI[x]];
90 state[PI[x]] = last.rotate_left(RHO[x]);
91 last = array[0];
92 }
93
94 for y_step in 0..5 {
96 let y = 5 * y_step;
97
98 array.copy_from_slice(&state[y..][..5]);
99
100 for x in 0..5 {
101 let t1 = !array[(x + 1) % 5];
102 let t2 = array[(x + 2) % 5];
103 state[y + x] = array[x] ^ (t1 & t2);
104 }
105 }
106
107 state[0] ^= *rc;
109 }
110}
111
112pub(crate) struct Backend;
114
115impl super::Backend for Backend {
116 #[cfg(feature = "parallel")]
117 type ParSize1600 = U1;
118
119 #[inline]
120 fn get_p1600<const ROUNDS: usize>() -> Fn1600 {
121 keccak_p::<u64, ROUNDS>
122 }
123}