tiny_keccak/
cshake.rs

1//! The `cSHAKE` extendable-output functions defined in [`SP800-185`].
2//!
3//! [`SP800-185`]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf
4
5use crate::{bits_to_rate, keccakf::KeccakF, left_encode, Hasher, KeccakState, Xof};
6
7/// The `cSHAKE` extendable-output functions defined in [`SP800-185`].
8///
9/// # Usage
10///
11/// ```toml
12/// [dependencies]
13/// tiny-keccak = { version = "2.0.0", features = ["cshake"] }
14/// ```
15///
16/// [`SP800-185`]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf
17#[derive(Clone)]
18pub struct CShake {
19    state: KeccakState<KeccakF>,
20}
21
22impl CShake {
23    const DELIM: u8 = 0x04;
24
25    /// Creates  new [`CShake`] hasher with a security level of 128 bits.
26    ///
27    /// [`CShake`]: struct.CShake.html
28    pub fn v128(name: &[u8], custom_string: &[u8]) -> CShake {
29        CShake::new(name, custom_string, 128)
30    }
31
32    /// Creates  new [`CShake`] hasher with a security level of 256 bits.
33    ///
34    /// [`CShake`]: struct.CShake.html
35    pub fn v256(name: &[u8], custom_string: &[u8]) -> CShake {
36        CShake::new(name, custom_string, 256)
37    }
38
39    pub(crate) fn new(name: &[u8], custom_string: &[u8], bits: usize) -> CShake {
40        let rate = bits_to_rate(bits);
41        // if there is no name and no customization string
42        // cSHAKE is SHAKE
43        if name.is_empty() && custom_string.is_empty() {
44            let state = KeccakState::new(rate, 0x1f);
45            return CShake { state };
46        }
47
48        let mut state = KeccakState::new(rate, Self::DELIM);
49        state.update(left_encode(rate).value());
50        state.update(left_encode(name.len() * 8).value());
51        state.update(name);
52        state.update(left_encode(custom_string.len() * 8).value());
53        state.update(custom_string);
54        state.fill_block();
55        CShake { state }
56    }
57
58    pub(crate) fn fill_block(&mut self) {
59        self.state.fill_block();
60    }
61}
62
63impl Hasher for CShake {
64    fn update(&mut self, input: &[u8]) {
65        self.state.update(input);
66    }
67
68    fn finalize(self, output: &mut [u8]) {
69        self.state.finalize(output);
70    }
71}
72
73impl Xof for CShake {
74    fn squeeze(&mut self, output: &mut [u8]) {
75        self.state.squeeze(output);
76    }
77}