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:
9 Copy
10 + Clone
11 + Default
12 + PartialEq
13 + BitAndAssign
14 + BitAnd<Output = Self>
15 + BitXorAssign
16 + BitXor<Output = Self>
17 + Not<Output = Self>
18{
19 const KECCAK_F_ROUND_COUNT: usize;
21
22 fn truncate_rc(rc: u64) -> Self;
24
25 #[must_use]
27 fn rotate_left(self, n: u32) -> Self;
28}
29
30macro_rules! impl_lanesize {
31 ($type:ty, $round:expr) => {
32 impl LaneSize for $type {
33 const KECCAK_F_ROUND_COUNT: usize = $round;
34
35 #[allow(clippy::cast_possible_truncation, trivial_numeric_casts)]
36 fn truncate_rc(rc: u64) -> Self {
37 rc as Self
38 }
39
40 fn rotate_left(self, n: u32) -> Self {
41 self.rotate_left(n)
42 }
43 }
44 };
45}
46
47impl_lanesize!(u8, F200_ROUNDS);
48impl_lanesize!(u16, F400_ROUNDS);
49impl_lanesize!(u32, F800_ROUNDS);
50impl_lanesize!(u64, F1600_ROUNDS);
51
52#[rustfmt::skip]
53macro_rules! unroll5 {
54 ($var: ident, $body: block) => {
55 #[cfg(not(keccak_backend_soft = "compact"))]
56 {
57 { const $var: usize = 0; $body; }
58 { const $var: usize = 1; $body; }
59 { const $var: usize = 2; $body; }
60 { const $var: usize = 3; $body; }
61 { const $var: usize = 4; $body; }
62 }
63 #[cfg(keccak_backend_soft = "compact")]
64 {
65 for $var in 0..5 $body
66 }
67 };
68}
69
70#[rustfmt::skip]
71macro_rules! unroll24 {
72 ($var: ident, $body: block) => {
73 #[cfg(not(keccak_backend_soft = "compact"))]
74 {
75 { const $var: usize = 0; $body; }
76 { const $var: usize = 1; $body; }
77 { const $var: usize = 2; $body; }
78 { const $var: usize = 3; $body; }
79 { const $var: usize = 4; $body; }
80 { const $var: usize = 5; $body; }
81 { const $var: usize = 6; $body; }
82 { const $var: usize = 7; $body; }
83 { const $var: usize = 8; $body; }
84 { const $var: usize = 9; $body; }
85 { const $var: usize = 10; $body; }
86 { const $var: usize = 11; $body; }
87 { const $var: usize = 12; $body; }
88 { const $var: usize = 13; $body; }
89 { const $var: usize = 14; $body; }
90 { const $var: usize = 15; $body; }
91 { const $var: usize = 16; $body; }
92 { const $var: usize = 17; $body; }
93 { const $var: usize = 18; $body; }
94 { const $var: usize = 19; $body; }
95 { const $var: usize = 20; $body; }
96 { const $var: usize = 21; $body; }
97 { const $var: usize = 22; $body; }
98 { const $var: usize = 23; $body; }
99 }
100 #[cfg(keccak_backend_soft = "compact")]
101 {
102 for $var in 0..24 $body
103 }
104 };
105}
106
107#[allow(non_upper_case_globals, unused_assignments)]
112pub(crate) fn keccak_p<L: LaneSize, const ROUNDS: usize>(state: &mut [L; PLEN]) {
113 let round_consts = RC[..L::KECCAK_F_ROUND_COUNT]
116 .last_chunk::<ROUNDS>()
117 .expect("Number of rounds greater than `KECCAK_F_ROUND_COUNT` is not supported!")
118 .map(L::truncate_rc);
119
120 for rc in round_consts {
123 let mut array = [L::default(); 5];
124
125 unroll5!(x, {
127 unroll5!(y, {
128 array[x] ^= state[5 * y + x];
129 });
130 });
131
132 unroll5!(x, {
133 let t1 = array[(x + 4) % 5];
134 let t2 = array[(x + 1) % 5].rotate_left(1);
135 unroll5!(y, {
136 state[5 * y + x] ^= t1 ^ t2;
137 });
138 });
139
140 let mut last = state[1];
142 unroll24!(x, {
143 array[0] = state[PI[x]];
144 state[PI[x]] = last.rotate_left(RHO[x]);
145 last = array[0];
146 });
147
148 unroll5!(y_step, {
150 let y = 5 * y_step;
151
152 array.copy_from_slice(&state[y..][..5]);
153
154 unroll5!(x, {
155 let t1 = !array[(x + 1) % 5];
156 let t2 = array[(x + 2) % 5];
157 state[y + x] = array[x] ^ (t1 & t2);
158 });
159 });
160
161 state[0] ^= rc;
163 }
164}
165
166pub(crate) struct Backend;
168
169impl super::Backend for Backend {
170 #[cfg(feature = "parallel")]
171 type ParSize1600 = U1;
172
173 #[inline]
174 fn get_p1600<const ROUNDS: usize>() -> Fn1600 {
175 keccak_p::<u64, ROUNDS>
176 }
177}