dcrypt_algorithms/hash/sha3/
mod.rs1#[cfg(not(feature = "std"))]
6use alloc::vec::Vec;
7use zeroize::Zeroize;
8
9use crate::error::{validate, Result};
10use crate::hash::{Hash, HashAlgorithm, HashFunction};
11use crate::types::Digest;
12
13use core::sync::atomic::{compiler_fence, Ordering};
14
15use dcrypt_params::utils::hash::{
18 SHA3_224_OUTPUT_SIZE, SHA3_256_OUTPUT_SIZE, SHA3_384_OUTPUT_SIZE, SHA3_512_OUTPUT_SIZE,
19};
20
21const KECCAK_ROUNDS: usize = 24;
22const KECCAK_STATE_SIZE: usize = 25; const SHA3_224_RATE: usize = 144; const SHA3_256_RATE: usize = 136; const SHA3_384_RATE: usize = 104; const SHA3_512_RATE: usize = 72; const RC: [u64; KECCAK_ROUNDS] = [
30 0x0000_0000_0000_0001,
31 0x0000_0000_0000_8082,
32 0x8000_0000_0000_808A,
33 0x8000_0000_8000_8000,
34 0x0000_0000_0000_808B,
35 0x0000_0000_8000_0001,
36 0x8000_0000_8000_8081,
37 0x8000_0000_0000_8009,
38 0x0000_0000_0000_008A,
39 0x0000_0000_0000_0088,
40 0x0000_0000_8000_8009,
41 0x0000_0000_8000_000A,
42 0x0000_0000_8000_808B,
43 0x8000_0000_0000_008B,
44 0x8000_0000_0000_8089,
45 0x8000_0000_0000_8003,
46 0x8000_0000_0000_8002,
47 0x8000_0000_0000_0080,
48 0x0000_0000_0000_800A,
49 0x8000_0000_8000_000A,
50 0x8000_0000_8000_8081,
51 0x8000_0000_0000_8080,
52 0x0000_0000_8000_0001,
53 0x8000_0000_8000_8008,
54];
55
56const RHO: [u32; 24] = [
58 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
59];
60
61const PI: [usize; 24] = [
63 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
64];
65
66#[inline(always)]
69fn get_byte_from_state(state: &[u64; KECCAK_STATE_SIZE], pos: usize) -> u8 {
70 let word = pos / 8;
71 let shift = (pos % 8) * 8;
72 ((state[word] >> shift) & 0xFF) as u8
73}
74
75#[inline(always)]
76fn xor_byte_in_state(state: &mut [u64; KECCAK_STATE_SIZE], pos: usize, val: u8) {
77 let word = pos / 8;
81 let shift = (pos % 8) * 8;
82 let mask = (val as u64) << shift;
83
84 let before = state[word];
85 state[word] = before ^ mask;
86
87 compiler_fence(Ordering::SeqCst);
89}
90
91pub enum Sha3_224Algorithm {}
95pub enum Sha3_256Algorithm {}
97pub enum Sha3_384Algorithm {}
99pub enum Sha3_512Algorithm {}
101
102impl HashAlgorithm for Sha3_224Algorithm {
103 const OUTPUT_SIZE: usize = SHA3_224_OUTPUT_SIZE;
104 const BLOCK_SIZE: usize = SHA3_224_RATE;
105 const ALGORITHM_ID: &'static str = "SHA3-224";
106}
107impl HashAlgorithm for Sha3_256Algorithm {
108 const OUTPUT_SIZE: usize = SHA3_256_OUTPUT_SIZE;
109 const BLOCK_SIZE: usize = SHA3_256_RATE;
110 const ALGORITHM_ID: &'static str = "SHA3-256";
111}
112impl HashAlgorithm for Sha3_384Algorithm {
113 const OUTPUT_SIZE: usize = SHA3_384_OUTPUT_SIZE;
114 const BLOCK_SIZE: usize = SHA3_384_RATE;
115 const ALGORITHM_ID: &'static str = "SHA3-384";
116}
117impl HashAlgorithm for Sha3_512Algorithm {
118 const OUTPUT_SIZE: usize = SHA3_512_OUTPUT_SIZE;
119 const BLOCK_SIZE: usize = SHA3_512_RATE;
120 const ALGORITHM_ID: &'static str = "SHA3-512";
121}
122
123#[derive(Clone, Zeroize)]
127pub struct Sha3_224 {
128 state: [u64; KECCAK_STATE_SIZE],
129 pt: usize,
130}
131
132#[derive(Clone, Zeroize)]
134pub struct Sha3_256 {
135 state: [u64; KECCAK_STATE_SIZE],
136 pt: usize,
137}
138
139#[derive(Clone, Zeroize)]
141pub struct Sha3_384 {
142 state: [u64; KECCAK_STATE_SIZE],
143 pt: usize,
144}
145
146#[derive(Clone, Zeroize)]
148pub struct Sha3_512 {
149 state: [u64; KECCAK_STATE_SIZE],
150 pt: usize,
151}
152
153macro_rules! impl_sha3_variant {
156 ($name:ident, $rate:expr, $out:expr, $alg:ty) => {
157 impl $name {
158 #[inline(always)]
159 fn init() -> Self {
160 Self {
161 state: [0u64; KECCAK_STATE_SIZE],
162 pt: 0,
163 }
164 }
165 #[inline(always)]
166 fn rate() -> usize {
167 $rate
168 }
169
170 fn update_internal(&mut self, data: &[u8]) -> Result<()> {
171 validate::parameter(
172 self.pt.checked_add(data.len()).is_some(),
173 "data_length",
174 "Integer overflow",
175 )?;
176 let r = Self::rate();
177 for &b in data {
178 xor_byte_in_state(&mut self.state, self.pt, b);
179 self.pt += 1;
180 if self.pt == r {
181 keccak_f1600(&mut self.state);
182 self.pt = 0;
183 }
184 }
185 Ok(())
186 }
187
188 fn finalize_internal(&mut self) -> Result<Hash> {
189 let r = Self::rate();
190 xor_byte_in_state(&mut self.state, self.pt, 0x06);
191 xor_byte_in_state(&mut self.state, r - 1, 0x80);
192 keccak_f1600(&mut self.state);
193
194 let mut out = vec![0u8; $out];
195 for i in 0..$out {
196 out[i] = get_byte_from_state(&self.state, i);
197 }
198
199 self.state = [0u64; KECCAK_STATE_SIZE];
200 self.pt = 0;
201 Ok(out)
202 }
203 }
204
205 impl HashFunction for $name {
206 type Algorithm = $alg;
207 type Output = Digest<$out>;
208
209 fn new() -> Self {
210 Self::init()
211 }
212
213 fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
214 self.update_internal(data)?;
215 Ok(self)
216 }
217
218 fn finalize(&mut self) -> Result<Self::Output> {
219 let h = self.finalize_internal()?;
220 let mut d = [0u8; $out];
221 d.copy_from_slice(&h);
222 Ok(Digest::new(d))
223 }
224
225 #[inline(always)]
226 fn output_size() -> usize {
227 <$alg as HashAlgorithm>::OUTPUT_SIZE
228 }
229 #[inline(always)]
230 fn block_size() -> usize {
231 <$alg as HashAlgorithm>::BLOCK_SIZE
232 }
233 #[inline(always)]
234 fn name() -> String {
235 <$alg as HashAlgorithm>::ALGORITHM_ID.to_string()
236 }
237 }
238 };
239}
240
241impl_sha3_variant!(
242 Sha3_224,
243 SHA3_224_RATE,
244 SHA3_224_OUTPUT_SIZE,
245 Sha3_224Algorithm
246);
247impl_sha3_variant!(
248 Sha3_256,
249 SHA3_256_RATE,
250 SHA3_256_OUTPUT_SIZE,
251 Sha3_256Algorithm
252);
253impl_sha3_variant!(
254 Sha3_384,
255 SHA3_384_RATE,
256 SHA3_384_OUTPUT_SIZE,
257 Sha3_384Algorithm
258);
259impl_sha3_variant!(
260 Sha3_512,
261 SHA3_512_RATE,
262 SHA3_512_OUTPUT_SIZE,
263 Sha3_512Algorithm
264);
265
266fn keccak_f1600(state: &mut [u64; KECCAK_STATE_SIZE]) {
269 for &rc in RC.iter().take(KECCAK_ROUNDS) {
270 let mut c = [0u64; 5];
272 for x in 0..5 {
273 c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ state[x + 20];
274 }
275 for x in 0..5 {
276 let d = c[(x + 4) % 5] ^ c[(x + 1) % 5].rotate_left(1);
277 for y in 0..5 {
278 state[x + 5 * y] ^= d;
279 }
280 }
281 let mut t = state[1];
283 for i in 0..24 {
284 let j = PI[i];
285 let tmp = state[j];
286 state[j] = t.rotate_left(RHO[i]);
287 t = tmp;
288 }
289 for y in 0..5 {
291 let mut row = [0u64; 5];
292 for x in 0..5 {
293 row[x] = state[x + 5 * y];
294 }
295 for x in 0..5 {
296 state[x + 5 * y] ^= (!row[(x + 1) % 5]) & row[(x + 2) % 5];
297 }
298 }
299 state[0] ^= rc;
301 }
302}
303
304#[cfg(test)]
305mod tests;