1use alloc::vec::Vec;
9
10use super::BLAKE3_OUTPUT_LEN;
11
12#[must_use]
24pub fn blake3(data: &[u8]) -> [u8; BLAKE3_OUTPUT_LEN] {
25 *::blake3::hash(data).as_bytes()
26}
27
28#[must_use]
48pub fn blake3_long(data: &[u8], len: usize) -> Vec<u8> {
49 let mut hasher = ::blake3::Hasher::new();
50 let _ = hasher.update(data);
51 let mut out = alloc::vec![0u8; len];
52 let mut reader = hasher.finalize_xof();
53 reader.fill(&mut out);
54 out
55}
56
57#[derive(Debug, Clone, Default)]
83pub struct Blake3Hasher {
84 inner: ::blake3::Hasher,
85}
86
87impl Blake3Hasher {
88 #[must_use]
90 pub fn new() -> Self {
91 Self {
92 inner: ::blake3::Hasher::new(),
93 }
94 }
95
96 pub fn update(&mut self, data: &[u8]) -> &mut Self {
99 let _ = self.inner.update(data);
100 self
101 }
102
103 #[must_use]
105 pub fn finalize(self) -> [u8; BLAKE3_OUTPUT_LEN] {
106 *self.inner.finalize().as_bytes()
107 }
108
109 #[must_use]
112 pub fn finalize_xof(self, len: usize) -> Vec<u8> {
113 let mut out = alloc::vec![0u8; len];
114 let mut reader = self.inner.finalize_xof();
115 reader.fill(&mut out);
116 out
117 }
118}
119
120#[cfg(test)]
121#[allow(clippy::unwrap_used, clippy::expect_used, unused_results)]
122mod tests {
123 use super::*;
124
125 const KAT_EMPTY: [u8; 32] = [
131 0xaf, 0x13, 0x49, 0xb9, 0xf5, 0xf9, 0xa1, 0xa6, 0xa0, 0x40, 0x4d, 0xea, 0x36, 0xdc, 0xc9,
132 0x49, 0x9b, 0xcb, 0x25, 0xc9, 0xad, 0xc1, 0x12, 0xb7, 0xcc, 0x9a, 0x93, 0xca, 0xe4, 0x1f,
133 0x32, 0x62,
134 ];
135
136 const KAT_IETF: [u8; 32] = [
140 0x83, 0xa2, 0xde, 0x1e, 0xe6, 0xf4, 0xe6, 0xab, 0x68, 0x68, 0x89, 0x24, 0x8f, 0x4e, 0xc0,
141 0xcf, 0x4c, 0xc5, 0x70, 0x94, 0x46, 0xa6, 0x82, 0xff, 0xd1, 0xcb, 0xb4, 0xd6, 0x16, 0x51,
142 0x81, 0xe2,
143 ];
144
145 #[test]
146 fn kat_empty() {
147 assert_eq!(blake3(b""), KAT_EMPTY);
148 }
149
150 #[test]
151 fn kat_ietf() {
152 assert_eq!(blake3(b"IETF"), KAT_IETF);
153 }
154
155 #[test]
156 fn xof_length_matches_request() {
157 for n in [0usize, 1, 16, 32, 64, 128, 1024] {
158 assert_eq!(blake3_long(b"input", n).len(), n);
159 }
160 }
161
162 #[test]
163 fn xof_is_deterministic_in_input() {
164 let a = blake3_long(b"same", 64);
165 let b = blake3_long(b"same", 64);
166 assert_eq!(a, b);
167 let c = blake3_long(b"diff", 64);
168 assert_ne!(a, c);
169 }
170
171 #[test]
172 fn xof_extends_default_output() {
173 let extended = blake3_long(b"foo bar", 64);
176 let short = blake3(b"foo bar");
177 assert_eq!(&extended[..32], &short[..]);
178 }
179
180 #[test]
181 fn streaming_equals_one_shot() {
182 let data = b"the quick brown fox jumps over the lazy dog";
183 let one_shot = blake3(data);
184 let mut h = Blake3Hasher::new();
185 h.update(&data[..10]);
186 h.update(&data[10..25]);
187 h.update(&data[25..]);
188 let streamed = h.finalize();
189 assert_eq!(one_shot, streamed);
190 }
191
192 #[test]
193 fn streaming_chain_returns_self() {
194 let data = b"chain-friendly";
195 let mut h = Blake3Hasher::new();
196 let _ret: &mut Blake3Hasher = h.update(b"chain").update(b"-friendly");
197 let d = blake3(data);
198 let mut h2 = Blake3Hasher::new();
199 h2.update(b"chain").update(b"-friendly");
200 assert_eq!(h2.finalize(), d);
201 }
202
203 #[test]
204 fn streaming_xof_finalize_matches_one_shot_long() {
205 let data = b"streaming-xof";
206 let one_shot = blake3_long(data, 100);
207 let mut h = Blake3Hasher::new();
208 h.update(data);
209 let streamed = h.finalize_xof(100);
210 assert_eq!(one_shot, streamed);
211 }
212
213 #[test]
214 fn empty_input_through_streaming() {
215 let mut h = Blake3Hasher::new();
216 let _ = h.update(b"");
217 assert_eq!(h.finalize(), KAT_EMPTY);
218 }
219}