Skip to main content

sha3/
turbo_shake.rs

1use crate::{Sha3HasherCore, Sha3ReaderCore};
2use core::fmt;
3use digest::{
4    CollisionResistance, ExtendableOutput, ExtendableOutputReset, HashMarker, Update, XofReader,
5    block_api::{
6        AlgorithmName, BlockSizeUser, ExtendableOutputCore, Reset, UpdateCore, XofReaderCore,
7    },
8    block_buffer::{EagerBuffer, ReadBuffer},
9    consts::{U0, U16, U32, U136, U168},
10};
11
12const TURBO_SHAKE_ROUND_COUNT: usize = 12;
13
14macro_rules! impl_turbo_shake {
15    (
16        $name:ident, $reader_name:ident, $rate:ty, $alg_name:expr
17    ) => {
18        #[doc = $alg_name]
19        #[doc = "hasher with domain separator."]
20        #[doc = ""]
21        #[doc = "Domain separator `DS` MUST be in the range `0x01..=0x7f`, the default value is `0x1F`."]
22        #[doc = "Using `DS` outside of the range will result in a panic during initialization."]
23        #[derive(Clone)]
24        pub struct $name<const DS: u8 = 0x1F> {
25            core: Sha3HasherCore<$rate, U0, DS, TURBO_SHAKE_ROUND_COUNT>,
26            buffer: EagerBuffer<$rate>,
27        }
28
29        impl<const DS: u8> Default for $name<DS> {
30            #[inline]
31            fn default() -> Self {
32                assert!((0x01..=0x7F).contains(&DS), "invalid domain separator");
33                Self {
34                    core: Default::default(),
35                    buffer: Default::default(),
36                }
37            }
38        }
39
40        impl<const DS: u8> HashMarker for $name<DS> {}
41
42        impl<const DS: u8> BlockSizeUser for $name<DS> {
43            type BlockSize = $rate;
44        }
45
46        impl<const DS: u8> Update for $name<DS> {
47            #[inline]
48            fn update(&mut self, data: &[u8]) {
49                let Self { core, buffer } = self;
50                buffer.digest_blocks(data, |blocks| core.update_blocks(blocks));
51            }
52        }
53
54        impl<const DS: u8> ExtendableOutput for $name<DS> {
55            type Reader = $reader_name;
56
57            #[inline]
58            fn finalize_xof(mut self) -> Self::Reader {
59                let Self { core, buffer } = &mut self;
60                let core = core.finalize_xof_core(buffer);
61                let buffer = Default::default();
62                Self::Reader { core, buffer }
63            }
64        }
65
66        impl<const DS: u8> ExtendableOutputReset for $name<DS> {
67            #[inline]
68            fn finalize_xof_reset(&mut self) -> Self::Reader {
69                let Self { core, buffer } = self;
70                let core = core.finalize_xof_core(buffer);
71                self.reset();
72                let buffer = Default::default();
73                Self::Reader { core, buffer }
74            }
75        }
76
77        impl<const DS: u8> Reset for $name<DS> {
78            #[inline]
79            fn reset(&mut self) {
80                *self = Default::default();
81            }
82        }
83
84        impl<const DS: u8> AlgorithmName for $name<DS> {
85            fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
86                f.write_str(stringify!($alg_name))
87            }
88        }
89
90        impl<const DS: u8> fmt::Debug for $name<DS> {
91            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92                f.write_str(concat!(stringify!($name), " { ... }"))
93            }
94        }
95
96        #[cfg(feature = "zeroize")]
97        impl<const DS: u8> digest::zeroize::ZeroizeOnDrop for $name<DS> {}
98
99        #[doc = $alg_name]
100        #[doc = " XOF reader."]
101        #[derive(Clone)]
102        pub struct $reader_name {
103            core: Sha3ReaderCore<$rate, TURBO_SHAKE_ROUND_COUNT>,
104            buffer: ReadBuffer<$rate>,
105        }
106
107        impl XofReader for $reader_name {
108            #[inline]
109            fn read(&mut self, buf: &mut [u8]) {
110                let Self { core, buffer } = self;
111                buffer.read(buf, |block| {
112                    *block = core.read_block();
113                });
114            }
115        }
116
117        impl fmt::Debug for $reader_name {
118            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119                f.write_str(concat!(stringify!($reader_name), " { ... }"))
120            }
121        }
122    };
123}
124
125impl_turbo_shake!(TurboShake128, TurboShake128Reader, U168, "TurboSHAKE128");
126impl_turbo_shake!(TurboShake256, TurboShake256Reader, U136, "TurboSHAKE256");
127
128impl<const DS: u8> CollisionResistance for TurboShake128<DS> {
129    // https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-17.html#section-7-7
130    type CollisionResistance = U16;
131}
132
133impl<const DS: u8> CollisionResistance for TurboShake256<DS> {
134    // https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-17.html#section-7-8
135    type CollisionResistance = U32;
136}