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`] and [`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(feature = "zeroize")]
122        impl<const DS: u8> digest::zeroize::ZeroizeOnDrop for $name<DS> {}
123
124        #[doc = $alg_name]
125        #[doc = " XOF reader."]
126        #[derive(Clone)]
127        pub struct $reader_name {
128            core: SpongeReaderCore<$rate, TURBO_SHAKE_ROUND_COUNT>,
129            buffer: ReadBuffer<$rate>,
130        }
131
132        impl XofReader for $reader_name {
133            #[inline]
134            fn read(&mut self, buf: &mut [u8]) {
135                let Self { core, buffer } = self;
136                buffer.read(buf, |block| {
137                    *block = core.read_block();
138                });
139            }
140        }
141
142        impl fmt::Debug for $reader_name {
143            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144                f.write_str(concat!(stringify!($reader_name), " { ... }"))
145            }
146        }
147    };
148}
149
150impl_turbo_shake!(TurboShake128, TurboShake128Reader, U168, "TurboSHAKE128");
151impl_turbo_shake!(TurboShake256, TurboShake256Reader, U136, "TurboSHAKE256");
152
153impl<const DS: u8> CollisionResistance for TurboShake128<DS> {
154    // https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-17.html#section-7-7
155    type CollisionResistance = U16;
156}
157
158impl<const DS: u8> CollisionResistance for TurboShake256<DS> {
159    // https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-17.html#section-7-8
160    type CollisionResistance = U32;
161}