Skip to main content

turboshake/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![forbid(unsafe_code)]
9
10pub use digest;
11use keccak::{Keccak, State1600};
12use sponge_cursor::SpongeCursor;
13
14use core::fmt;
15use digest::{
16    CollisionResistance, ExtendableOutput, ExtendableOutputReset, HashMarker, Reset, Update,
17    XofReader,
18    common::AlgorithmName,
19    consts::{U16, U32},
20};
21
22/// Number of Keccak rounds used by TurboSHAKE.
23const ROUNDS: usize = 12;
24
25/// Default domain separator value.
26pub const DEFAULT_DS: u8 = 0x1F;
27
28/// TurboSHAKE hasher generic over rate and domain separator.
29///
30/// Domain separator `DS` MUST be in the range `0x01..=0x7f`.
31/// Use [`DEFAULT_DS`] if you want the default value.
32///
33/// Rate MUST be either 168 or 136 for TurboSHAKE128 and TurboSHAKE256 respectively.
34#[derive(Clone)]
35pub struct TurboShake<const RATE: usize, const DS: u8> {
36    state: State1600,
37    cursor: SpongeCursor<RATE>,
38    keccak: Keccak,
39}
40
41impl<const RATE: usize, const DS: u8> Default for TurboShake<RATE, DS> {
42    #[inline]
43    fn default() -> Self {
44        const {
45            assert!(DS >= 0x01 && DS <= 0x7F, "invalid domain separator");
46            assert!(RATE == 168 || RATE == 136, "unsupported rate");
47        }
48        Self {
49            state: Default::default(),
50            cursor: Default::default(),
51            keccak: Keccak::new(),
52        }
53    }
54}
55
56impl<const RATE: usize, const DS: u8> HashMarker for TurboShake<RATE, DS> {}
57
58impl<const RATE: usize, const DS: u8> Update for TurboShake<RATE, DS> {
59    #[inline]
60    fn update(&mut self, data: &[u8]) {
61        self.keccak.with_p1600::<ROUNDS>(|p1600| {
62            self.cursor.absorb_u64_le(&mut self.state, p1600, data);
63        });
64    }
65}
66
67impl<const RATE: usize, const DS: u8> TurboShake<RATE, DS> {
68    fn pad(&mut self) {
69        let pos = self.cursor.pos();
70        let word_offset = pos / 8;
71        let byte_offset = pos % 8;
72
73        let pad = u64::from(DS) << (8 * byte_offset);
74        self.state[word_offset] ^= pad;
75        self.state[RATE / 8 - 1] ^= 1 << 63;
76    }
77}
78
79impl<const RATE: usize, const DS: u8> ExtendableOutput for TurboShake<RATE, DS> {
80    type Reader = TurboShakeReader<RATE>;
81
82    #[inline]
83    fn finalize_xof(mut self) -> Self::Reader {
84        self.pad();
85        Self::Reader {
86            state: self.state,
87            cursor: Default::default(),
88            keccak: self.keccak,
89        }
90    }
91}
92
93impl<const RATE: usize, const DS: u8> ExtendableOutputReset for TurboShake<RATE, DS> {
94    #[inline]
95    fn finalize_xof_reset(&mut self) -> Self::Reader {
96        self.pad();
97        let reader = Self::Reader {
98            state: self.state,
99            cursor: Default::default(),
100            keccak: self.keccak,
101        };
102        self.reset();
103        reader
104    }
105}
106
107impl<const RATE: usize, const DS: u8> Reset for TurboShake<RATE, DS> {
108    #[inline]
109    fn reset(&mut self) {
110        self.state = Default::default();
111        self.cursor = Default::default();
112    }
113}
114
115impl<const RATE: usize, const DS: u8> AlgorithmName for TurboShake<RATE, DS> {
116    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        let alg_name = match RATE {
118            168 => "TurboSHAKE128",
119            136 => "TurboSHAKE256",
120            _ => unreachable!(),
121        };
122        f.write_str(alg_name)
123    }
124}
125
126impl<const RATE: usize, const DS: u8> fmt::Debug for TurboShake<RATE, DS> {
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        let debug_str = match RATE {
129            168 => "TurboShake128 { ... }",
130            136 => "TurboShake256 { ... }",
131            _ => unreachable!(),
132        };
133        f.write_str(debug_str)
134    }
135}
136
137impl<const RATE: usize, const DS: u8> Drop for TurboShake<RATE, DS> {
138    fn drop(&mut self) {
139        #[cfg(feature = "zeroize")]
140        {
141            use digest::zeroize::Zeroize;
142            self.state.zeroize();
143            self.cursor.zeroize();
144        }
145    }
146}
147
148#[cfg(feature = "zeroize")]
149impl<const RATE: usize, const DS: u8> digest::zeroize::ZeroizeOnDrop for TurboShake<RATE, DS> {}
150
151/// Generic TurboSHAKE XOF reader
152#[derive(Clone)]
153pub struct TurboShakeReader<const RATE: usize> {
154    state: State1600,
155    cursor: SpongeCursor<RATE>,
156    keccak: Keccak,
157}
158
159impl<const RATE: usize> XofReader for TurboShakeReader<RATE> {
160    #[inline]
161    fn read(&mut self, buf: &mut [u8]) {
162        self.keccak.with_p1600::<ROUNDS>(|p1600| {
163            self.cursor.squeeze_read_u64_le(&mut self.state, p1600, buf);
164        });
165    }
166}
167
168impl<const RATE: usize> fmt::Debug for TurboShakeReader<RATE> {
169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170        let debug_str = match RATE {
171            168 => "TurboShakeReader128 { ... }",
172            136 => "TurboShakeReader256 { ... }",
173            _ => unreachable!(),
174        };
175        f.write_str(debug_str)
176    }
177}
178
179impl<const RATE: usize> Drop for TurboShakeReader<RATE> {
180    fn drop(&mut self) {
181        #[cfg(feature = "zeroize")]
182        {
183            use digest::zeroize::Zeroize;
184            self.state.zeroize();
185            self.cursor.zeroize();
186        }
187    }
188}
189
190#[cfg(feature = "zeroize")]
191impl<const RATE: usize> digest::zeroize::ZeroizeOnDrop for TurboShakeReader<RATE> {}
192
193/// TurboSHAKE128 hasher with a custom domain separator.
194///
195/// Domain separator `DS` MUST be in the range `0x01..=0x7f`.
196pub type CTurboShake128<const DS: u8> = TurboShake<168, DS>;
197/// TurboSHAKE256 hasher with a custom domain separator.
198///
199/// Domain separator `DS` MUST be in the range `0x01..=0x7f`.
200pub type CTurboShake256<const DS: u8> = TurboShake<136, DS>;
201
202/// TurboSHAKE128 hasher with the default domain separator.
203pub type TurboShake128 = CTurboShake128<DEFAULT_DS>;
204/// TurboSHAKE256 hasher with the default domain separator.
205pub type TurboShake256 = CTurboShake256<DEFAULT_DS>;
206
207/// TurboSHAKE128 XOF reader.
208pub type TurboShake128Reader = TurboShakeReader<168>;
209/// TurboSHAKE256 XOF reader.
210pub type TurboShake256Reader = TurboShakeReader<136>;
211
212impl<const DS: u8> CollisionResistance for CTurboShake128<DS> {
213    // https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-17.html#section-7-7
214    type CollisionResistance = U16;
215}
216
217impl<const DS: u8> CollisionResistance for CTurboShake256<DS> {
218    // https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-17.html#section-7-8
219    type CollisionResistance = U32;
220}