Skip to main content

lib_q_hash/
turbo_shake.rs

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