Skip to main content

crypto/sha3/
shake128.rs

1use super::keccak::Keccak;
2use crate::Xof;
3
4pub(crate) const SHAKE128_RATE: usize = 168;
5const SHAKE128_DOMAIN_SEPARATOR: u8 = 0x1f;
6
7/// SHAKE128 extensible-output function (XOF) as defined in FIPS 202.
8///
9/// Implements the [`Xof`] trait.
10///
11/// # One-shot API
12///
13/// ```ignore
14/// use crypto::sha3::Shake128;
15///
16/// let mut output = [0u8; 32];
17/// Shake128::hash(b"hello world", &mut output);
18/// ```
19///
20/// # Incremental API
21///
22/// ```ignore
23/// use crypto::{sha3::Shake128, Xof};
24///
25/// let mut shake = Shake128::new();
26/// shake.absorb(b"hello ");
27/// shake.absorb(b"world");
28/// let mut out = [0u8; 32];
29/// shake.squeeze(&mut out);
30/// ```
31#[derive(Clone)]
32pub struct Shake128 {
33    keccak: Keccak<24>,
34}
35
36impl Shake128 {
37    #[inline]
38    pub fn new() -> Self {
39        return Shake128 {
40            keccak: Keccak::new(SHAKE128_RATE, SHAKE128_DOMAIN_SEPARATOR),
41        };
42    }
43
44    #[inline]
45    pub fn hash(data: &[u8], output: &mut [u8]) {
46        let mut hasher = Shake128::new();
47        hasher.absorb(data);
48        hasher.squeeze(output);
49    }
50}
51
52impl Xof for Shake128 {
53    #[inline]
54    fn absorb(&mut self, data: &[u8]) {
55        self.keccak.absorb(data);
56    }
57
58    #[inline]
59    fn squeeze(&mut self, out: &mut [u8]) {
60        self.keccak.squeeze(out);
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::Shake128;
67    use crate::Xof;
68
69    // NIST SHAKE128 test vectors
70    fn vectors_shake128() -> Vec<(Vec<u8>, usize, &'static str)> {
71        vec![
72            (
73                b"".to_vec(),
74                32,
75                "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26",
76            ),
77            (
78                b"".to_vec(),
79                64,
80                "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef263cb1eea988004b93103cfb0aeefd2a686e01fa4a58e8a3639ca8a1e3f9ae57e2",
81            ),
82            (
83                b"abc".to_vec(),
84                32,
85                "5881092dd818bf5cf8a3ddb793fbcba74097d5c526a6d35f97b83351940f2cc8",
86            ),
87            (
88                b"The quick brown fox jumps over the lazy dog".to_vec(),
89                32,
90                "f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e",
91            ),
92        ]
93    }
94
95    #[test]
96    fn known_vectors() {
97        for (input, output_len, expected) in vectors_shake128() {
98            let mut output = vec![0u8; output_len];
99            Shake128::hash(&input, &mut output);
100            assert_eq!(hex::encode(&output), expected);
101        }
102    }
103
104    #[test]
105    fn incremental_and_streaming_read() {
106        let mut one_shot = vec![0u8; 64];
107        Shake128::hash(b"", &mut one_shot);
108
109        let mut shake = Shake128::new();
110        shake.absorb(b"");
111        let mut first = [0u8; 32];
112        let mut second = [0u8; 32];
113        shake.squeeze(&mut first);
114        shake.squeeze(&mut second);
115
116        let mut combined = vec![0u8; 64];
117        combined[..32].copy_from_slice(&first);
118        combined[32..].copy_from_slice(&second);
119
120        assert_eq!(combined, one_shot);
121    }
122}