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#[derive(Clone)]
8pub struct Shake128 {
9    keccak: Keccak<24>,
10}
11
12impl Shake128 {
13    #[inline]
14    pub fn new() -> Self {
15        return Shake128 {
16            keccak: Keccak::new(SHAKE128_RATE, SHAKE128_DOMAIN_SEPARATOR),
17        };
18    }
19
20    #[inline]
21    pub fn hash(data: &[u8], output: &mut [u8]) {
22        let mut hasher = Shake128::new();
23        hasher.absorb(data);
24        hasher.squeeze(output);
25    }
26}
27
28impl Xof for Shake128 {
29    #[inline]
30    fn absorb(&mut self, data: &[u8]) {
31        self.keccak.absorb(data);
32    }
33
34    #[inline]
35    fn squeeze(&mut self, out: &mut [u8]) {
36        self.keccak.squeeze(out);
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::Shake128;
43    use crate::Xof;
44
45    // NIST SHAKE128 test vectors
46    fn vectors_shake128() -> Vec<(Vec<u8>, usize, &'static str)> {
47        vec![
48            (
49                b"".to_vec(),
50                32,
51                "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26",
52            ),
53            (
54                b"".to_vec(),
55                64,
56                "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef263cb1eea988004b93103cfb0aeefd2a686e01fa4a58e8a3639ca8a1e3f9ae57e2",
57            ),
58            (
59                b"abc".to_vec(),
60                32,
61                "5881092dd818bf5cf8a3ddb793fbcba74097d5c526a6d35f97b83351940f2cc8",
62            ),
63            (
64                b"The quick brown fox jumps over the lazy dog".to_vec(),
65                32,
66                "f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e",
67            ),
68        ]
69    }
70
71    #[test]
72    fn known_vectors() {
73        for (input, output_len, expected) in vectors_shake128() {
74            let mut output = vec![0u8; output_len];
75            Shake128::hash(&input, &mut output);
76            assert_eq!(hex::encode(&output), expected);
77        }
78    }
79
80    #[test]
81    fn incremental_and_streaming_read() {
82        let mut one_shot = vec![0u8; 64];
83        Shake128::hash(b"", &mut one_shot);
84
85        let mut shake = Shake128::new();
86        shake.absorb(b"");
87        let mut first = [0u8; 32];
88        let mut second = [0u8; 32];
89        shake.squeeze(&mut first);
90        shake.squeeze(&mut second);
91
92        let mut combined = vec![0u8; 64];
93        combined[..32].copy_from_slice(&first);
94        combined[32..].copy_from_slice(&second);
95
96        assert_eq!(combined, one_shot);
97    }
98}