1use super::keccak::KeccakSponge;
2use crate::{Bytes, Hash, Hasher, Xof};
3
4pub(crate) const SHAKE128_RATE: usize = 168;
5const SHAKE128_DOMAIN_SEPARATOR: u8 = 0x1f;
6
7#[derive(Clone)]
32#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
33pub struct Shake128 {
34 keccak: KeccakSponge<24>,
35}
36
37impl Shake128 {
38 #[inline]
39 pub fn new() -> Self {
40 return Shake128 {
41 keccak: KeccakSponge::new(SHAKE128_RATE, SHAKE128_DOMAIN_SEPARATOR),
42 };
43 }
44
45 #[inline]
46 pub fn hash(data: &[u8], output: &mut [u8]) {
47 let mut hasher = Shake128::new();
48 hasher.absorb(data);
49 hasher.squeeze(output);
50 }
51}
52
53impl Hasher for Shake128 {
54 const BLOCK_SIZE: usize = SHAKE128_RATE;
55 const OUTPUT_SIZE: usize = 32;
56
57 #[inline]
58 fn new() -> Self {
59 return Shake128::new();
60 }
61
62 #[inline]
63 fn update(&mut self, data: &[u8]) {
64 self.absorb(data);
65 }
66
67 #[inline]
68 fn sum(mut self) -> Hash {
69 let mut hash = Bytes::<64>::with_length(Self::OUTPUT_SIZE);
70 self.squeeze(hash.as_mut());
71 return Hash(hash);
72 }
73}
74
75impl Xof for Shake128 {
76 #[inline]
77 fn absorb(&mut self, data: &[u8]) {
78 self.keccak.absorb(data);
79 }
80
81 #[inline]
82 fn squeeze(&mut self, out: &mut [u8]) {
83 self.keccak.squeeze(out);
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::Shake128;
90 use crate::Xof;
91
92 fn vectors_shake128() -> Vec<(Vec<u8>, usize, &'static str)> {
94 vec![
95 (
96 b"".to_vec(),
97 32,
98 "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26",
99 ),
100 (
101 b"".to_vec(),
102 64,
103 "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef263cb1eea988004b93103cfb0aeefd2a686e01fa4a58e8a3639ca8a1e3f9ae57e2",
104 ),
105 (
106 b"abc".to_vec(),
107 32,
108 "5881092dd818bf5cf8a3ddb793fbcba74097d5c526a6d35f97b83351940f2cc8",
109 ),
110 (
111 b"The quick brown fox jumps over the lazy dog".to_vec(),
112 32,
113 "f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e",
114 ),
115 ]
116 }
117
118 #[test]
119 fn known_vectors() {
120 for (input, output_len, expected) in vectors_shake128() {
121 let mut output = vec![0u8; output_len];
122 Shake128::hash(&input, &mut output);
123 assert_eq!(hex::encode(&output), expected);
124 }
125 }
126
127 #[test]
128 fn incremental_and_streaming_read() {
129 let mut one_shot = vec![0u8; 64];
130 Shake128::hash(b"", &mut one_shot);
131
132 let mut shake = Shake128::new();
133 shake.absorb(b"");
134 let mut first = [0u8; 32];
135 let mut second = [0u8; 32];
136 shake.squeeze(&mut first);
137 shake.squeeze(&mut second);
138
139 let mut combined = vec![0u8; 64];
140 combined[..32].copy_from_slice(&first);
141 combined[32..].copy_from_slice(&second);
142
143 assert_eq!(combined, one_shot);
144 }
145}