Skip to main content

lib_q_sha3/
turbo_shake.rs

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