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 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}