dcrypt_algorithms/hash/sha3/
mod.rs1#[cfg(feature = "alloc")]
6use crate::alloc_prelude::*;
7use dcrypt_internal::zeroing::{Zeroize, ZeroizeOnDrop, Zeroizing};
8
9use crate::error::{validate, Result};
10use crate::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
91#[inline(always)]
92fn xor_bit_in_state(state: &mut [u64; KECCAK_STATE_SIZE], pos: usize, bit: u8) {
93 let byte_pos = pos / 8;
94 let bit_in_byte = pos % 8;
95 xor_byte_in_state(state, byte_pos, (bit & 1) << bit_in_byte);
96}
97
98fn validate_bit_string(data: &[u8], bit_len: usize) -> Result<(usize, usize)> {
99 let rounded_len = bit_len
100 .checked_add(7)
101 .ok_or_else(|| crate::error::Error::param("bit_length", "Bit length is too large"))?
102 / 8;
103 validate::length("bit-oriented SHA-3 input", data.len(), rounded_len)?;
104
105 let partial_bits = bit_len % 8;
106 if partial_bits != 0 {
107 let unused_mask = (1u8 << (8 - partial_bits)) - 1;
108 validate::parameter(
109 data[rounded_len - 1] & unused_mask == 0,
110 "data",
111 "Unused low bits in the final byte must be zero",
112 )?;
113 }
114
115 Ok((bit_len / 8, partial_bits))
116}
117
118pub enum Sha3_224Algorithm {}
122pub enum Sha3_256Algorithm {}
124pub enum Sha3_384Algorithm {}
126pub enum Sha3_512Algorithm {}
128
129impl HashAlgorithm for Sha3_224Algorithm {
130 const OUTPUT_SIZE: usize = SHA3_224_OUTPUT_SIZE;
131 const BLOCK_SIZE: usize = SHA3_224_RATE;
132 const ALGORITHM_ID: &'static str = "SHA3-224";
133}
134impl HashAlgorithm for Sha3_256Algorithm {
135 const OUTPUT_SIZE: usize = SHA3_256_OUTPUT_SIZE;
136 const BLOCK_SIZE: usize = SHA3_256_RATE;
137 const ALGORITHM_ID: &'static str = "SHA3-256";
138}
139impl HashAlgorithm for Sha3_384Algorithm {
140 const OUTPUT_SIZE: usize = SHA3_384_OUTPUT_SIZE;
141 const BLOCK_SIZE: usize = SHA3_384_RATE;
142 const ALGORITHM_ID: &'static str = "SHA3-384";
143}
144impl HashAlgorithm for Sha3_512Algorithm {
145 const OUTPUT_SIZE: usize = SHA3_512_OUTPUT_SIZE;
146 const BLOCK_SIZE: usize = SHA3_512_RATE;
147 const ALGORITHM_ID: &'static str = "SHA3-512";
148}
149
150#[derive(Clone)]
154pub struct Sha3_224 {
155 state: [u64; KECCAK_STATE_SIZE],
156 pt: usize,
157}
158
159#[derive(Clone)]
161pub struct Sha3_256 {
162 state: [u64; KECCAK_STATE_SIZE],
163 pt: usize,
164}
165
166#[derive(Clone)]
168pub struct Sha3_384 {
169 state: [u64; KECCAK_STATE_SIZE],
170 pt: usize,
171}
172
173#[derive(Clone)]
175pub struct Sha3_512 {
176 state: [u64; KECCAK_STATE_SIZE],
177 pt: usize,
178}
179
180macro_rules! impl_sha3_zeroize {
181 ($name:ident) => {
182 impl Zeroize for $name {
183 fn zeroize(&mut self) {
184 self.state.zeroize();
185 self.pt.zeroize();
186 }
187 }
188
189 impl Drop for $name {
190 fn drop(&mut self) {
191 self.zeroize();
192 }
193 }
194
195 impl ZeroizeOnDrop for $name {}
196 };
197}
198
199impl_sha3_zeroize!(Sha3_224);
200impl_sha3_zeroize!(Sha3_256);
201impl_sha3_zeroize!(Sha3_384);
202impl_sha3_zeroize!(Sha3_512);
203
204macro_rules! impl_sha3_variant {
207 ($name:ident, $rate:expr, $out:expr, $alg:ty) => {
208 impl $name {
209 #[inline(always)]
210 fn init() -> Self {
211 Self {
212 state: [0u64; KECCAK_STATE_SIZE],
213 pt: 0,
214 }
215 }
216 #[inline(always)]
217 fn rate() -> usize {
218 $rate
219 }
220
221 fn update_internal(&mut self, data: &[u8]) -> Result<()> {
222 validate::parameter(
223 self.pt.checked_add(data.len()).is_some(),
224 "data_length",
225 "Integer overflow",
226 )?;
227 let r = Self::rate();
228 for &b in data {
229 xor_byte_in_state(&mut self.state, self.pt, b);
230 self.pt += 1;
231 if self.pt == r {
232 keccak_f1600(&mut self.state);
233 self.pt = 0;
234 }
235 }
236 Ok(())
237 }
238
239 fn finalize_internal(&mut self) -> Result<Zeroizing<[u8; $out]>> {
240 let r = Self::rate();
241 xor_byte_in_state(&mut self.state, self.pt, 0x06);
242 xor_byte_in_state(&mut self.state, r - 1, 0x80);
243 keccak_f1600(&mut self.state);
244
245 let mut out = Zeroizing::new([0u8; $out]);
246 for i in 0..$out {
247 out[i] = get_byte_from_state(&self.state, i);
248 }
249
250 self.zeroize();
251 Ok(out)
252 }
253
254 fn finalize_bits_internal(
255 &mut self,
256 mut partial_byte: u8,
257 partial_bits: usize,
258 ) -> Result<Zeroizing<[u8; $out]>> {
259 let rate_bits = Self::rate() * 8;
260 let mut bit_pos = self.pt * 8;
261
262 for i in 0..partial_bits {
266 xor_bit_in_state(&mut self.state, bit_pos, (partial_byte >> i) & 1);
267 bit_pos += 1;
268 if bit_pos == rate_bits {
269 keccak_f1600(&mut self.state);
270 bit_pos = 0;
271 }
272 }
273 partial_byte.zeroize();
274 for i in 0..3 {
275 xor_bit_in_state(&mut self.state, bit_pos, (0x06 >> i) & 1);
276 bit_pos += 1;
277 if bit_pos == rate_bits {
278 keccak_f1600(&mut self.state);
279 bit_pos = 0;
280 }
281 }
282
283 xor_bit_in_state(&mut self.state, rate_bits - 1, 1);
285 keccak_f1600(&mut self.state);
286
287 let mut out = Zeroizing::new([0u8; $out]);
288 for i in 0..$out {
289 out[i] = get_byte_from_state(&self.state, i);
290 }
291
292 self.zeroize();
293 Ok(out)
294 }
295
296 #[doc(hidden)]
304 pub fn digest_bits(data: &[u8], bit_len: usize) -> Result<Digest<$out>> {
305 let (full_bytes, partial_bits) = validate_bit_string(data, bit_len)?;
306 let mut hasher = Self::init();
307 hasher.update_internal(&data[..full_bytes])?;
308 let mut partial_byte = if partial_bits == 0 {
309 0
310 } else {
311 data[full_bytes] >> (8 - partial_bits)
312 };
313 let hash = hasher.finalize_bits_internal(partial_byte, partial_bits)?;
314 partial_byte.zeroize();
315 let mut digest = Digest::<$out>::zeroed();
316 digest.as_mut().copy_from_slice(&hash[..]);
317 Ok(digest)
318 }
319 }
320
321 impl HashFunction for $name {
322 type Algorithm = $alg;
323 type Output = Digest<$out>;
324
325 fn new() -> Self {
326 Self::init()
327 }
328
329 fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
330 self.update_internal(data)?;
331 Ok(self)
332 }
333
334 fn finalize(&mut self) -> Result<Self::Output> {
335 let h = self.finalize_internal()?;
336 let mut digest = Digest::<$out>::zeroed();
337 digest.as_mut().copy_from_slice(&h[..]);
338 Ok(digest)
339 }
340
341 #[inline(always)]
342 fn output_size() -> usize {
343 <$alg as HashAlgorithm>::OUTPUT_SIZE
344 }
345 #[inline(always)]
346 fn block_size() -> usize {
347 <$alg as HashAlgorithm>::BLOCK_SIZE
348 }
349 #[inline(always)]
350 fn name() -> String {
351 <$alg as HashAlgorithm>::ALGORITHM_ID.to_string()
352 }
353 }
354 };
355}
356
357impl_sha3_variant!(
358 Sha3_224,
359 SHA3_224_RATE,
360 SHA3_224_OUTPUT_SIZE,
361 Sha3_224Algorithm
362);
363impl_sha3_variant!(
364 Sha3_256,
365 SHA3_256_RATE,
366 SHA3_256_OUTPUT_SIZE,
367 Sha3_256Algorithm
368);
369impl_sha3_variant!(
370 Sha3_384,
371 SHA3_384_RATE,
372 SHA3_384_OUTPUT_SIZE,
373 Sha3_384Algorithm
374);
375impl_sha3_variant!(
376 Sha3_512,
377 SHA3_512_RATE,
378 SHA3_512_OUTPUT_SIZE,
379 Sha3_512Algorithm
380);
381
382fn keccak_f1600(state: &mut [u64; KECCAK_STATE_SIZE]) {
385 for &rc in RC.iter().take(KECCAK_ROUNDS) {
386 let mut c = Zeroizing::new([0u64; 5]);
388 for x in 0..5 {
389 c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ state[x + 20];
390 }
391 for x in 0..5 {
392 let mut d = c[(x + 4) % 5] ^ c[(x + 1) % 5].rotate_left(1);
393 for y in 0..5 {
394 state[x + 5 * y] ^= d;
395 }
396 d.zeroize();
397 }
398 let mut t = state[1];
400 for i in 0..24 {
401 let j = PI[i];
402 let tmp = state[j];
403 state[j] = t.rotate_left(RHO[i]);
404 t = tmp;
405 }
406 t.zeroize();
407 for y in 0..5 {
409 let mut row = Zeroizing::new([0u64; 5]);
410 for x in 0..5 {
411 row[x] = state[x + 5 * y];
412 }
413 for x in 0..5 {
414 state[x + 5 * y] ^= (!row[(x + 1) % 5]) & row[(x + 2) % 5];
415 }
416 }
417 state[0] ^= rc;
419 }
420}
421
422#[cfg(test)]
423mod tests;