1extern crate alloc;
2
3use alloc::boxed::Box;
4use core::marker::PhantomData;
5
6use libcrux_hacl_rs::streaming_types::error_code;
7
8use crate::hacl::hash_blake2b::{
9 blake2_params, digest, index, malloc_raw, params_and_key, reset, reset_with_key, state_t,
10 update0,
11};
12
13use super::{
14 ConstDigestLen, ConstKeyLen, ConstKeyLenConstDigestLen, Dynamic, Error, LengthBounds,
15 SupportsKeyLen, SupportsOutLen,
16};
17
18const PARAM_LEN: usize = 16;
19const MAX_LEN: usize = 64;
20
21pub struct Blake2bBuilder<'a, T> {
23 key: T,
24 personal: &'a [u8; PARAM_LEN],
25 salt: &'a [u8; PARAM_LEN],
26}
27
28impl<'a> Blake2bBuilder<'a, &'a ()> {
29 pub fn new_unkeyed() -> Self {
31 Self {
32 key: &(),
33 personal: &[0; PARAM_LEN],
34 salt: &[0; PARAM_LEN],
35 }
36 }
37
38 pub fn build_var_digest_len(self, digest_length: u8) -> Result<Blake2b<ConstKeyLen<0>>, Error> {
40 if digest_length < 1 || digest_length as usize > MAX_LEN {
41 return Err(Error::InvalidDigestLength);
42 }
43
44 let key_length = 0;
45
46 let kk = index {
47 key_length,
48 digest_length,
49 last_node: false,
50 };
51
52 let params = blake2_params {
53 digest_length,
54 key_length,
55 fanout: 1,
56 depth: 1,
57 leaf_length: 0,
58 node_offset: 0,
59 node_depth: 0,
60 inner_length: 0,
61 salt: self.salt,
62 personal: self.personal,
63 };
64
65 let key = params_and_key {
66 fst: &[params],
67 snd: &[],
68 };
69
70 Ok(Blake2b {
71 state: malloc_raw(kk, key),
72 _phantom: PhantomData,
73 })
74 }
75
76 pub fn build_const_digest_len<const OUT_LEN: usize>(
78 self,
79 ) -> Blake2b<ConstKeyLenConstDigestLen<0, OUT_LEN>>
80 where
81 Blake2b<LengthBounds>: SupportsOutLen<OUT_LEN>,
82 {
83 let digest_length = OUT_LEN as u8;
84 let key_length = 0;
85
86 let kk = index {
87 key_length,
88 digest_length,
89 last_node: false,
90 };
91
92 let params = blake2_params {
93 digest_length,
94 key_length,
95 fanout: 1,
96 depth: 1,
97 leaf_length: 0,
98 node_offset: 0,
99 node_depth: 0,
100 inner_length: 0,
101 salt: self.salt,
102 personal: self.personal,
103 };
104
105 let key = params_and_key {
106 fst: &[params],
107 snd: &[],
108 };
109
110 Blake2b {
111 state: malloc_raw(kk, key),
112 _phantom: PhantomData,
113 }
114 }
115}
116
117impl<'a, const KEY_LEN: usize> Blake2bBuilder<'a, &'a [u8; KEY_LEN]>
118where
119 Blake2b<LengthBounds>: SupportsKeyLen<KEY_LEN>,
120{
121 pub fn new_keyed_const(key: &'a [u8; KEY_LEN]) -> Self {
124 Self {
125 key,
126 personal: &[0; PARAM_LEN],
127 salt: &[0; PARAM_LEN],
128 }
129 }
130
131 pub fn build_var_digest_len(
133 self,
134 digest_length: u8,
135 ) -> Result<Blake2b<ConstKeyLen<KEY_LEN>>, Error> {
136 if digest_length < 1 || digest_length as usize > MAX_LEN {
137 return Err(Error::InvalidDigestLength);
138 }
139
140 let key_length = KEY_LEN as u8;
142
143 let kk = index {
144 key_length,
145 digest_length,
146 last_node: false,
147 };
148
149 let params = blake2_params {
150 digest_length,
151 key_length,
152 fanout: 1,
153 depth: 1,
154 leaf_length: 0,
155 node_offset: 0,
156 node_depth: 0,
157 inner_length: 0,
158 salt: self.salt,
159 personal: self.personal,
160 };
161
162 let key = params_and_key {
163 fst: &[params],
164 snd: self.key,
165 };
166
167 Ok(Blake2b::<ConstKeyLen<KEY_LEN>> {
168 state: malloc_raw(kk, key),
169 _phantom: PhantomData,
170 })
171 }
172
173 pub fn build_const_digest_len<const OUT_LEN: usize>(
175 self,
176 ) -> Blake2b<ConstKeyLenConstDigestLen<KEY_LEN, OUT_LEN>>
177 where
178 Blake2b<LengthBounds>: SupportsOutLen<OUT_LEN>,
179 {
180 let key_length = KEY_LEN as u8;
183 let digest_length = OUT_LEN as u8;
184
185 let kk = index {
186 key_length,
187 digest_length,
188 last_node: false,
189 };
190
191 let params = blake2_params {
192 digest_length,
193 key_length,
194 fanout: 1,
195 depth: 1,
196 leaf_length: 0,
197 node_offset: 0,
198 node_depth: 0,
199 inner_length: 0,
200 salt: self.salt,
201 personal: self.personal,
202 };
203
204 let key = params_and_key {
205 fst: &[params],
206 snd: self.key,
207 };
208
209 Blake2b::<ConstKeyLenConstDigestLen<KEY_LEN, OUT_LEN>> {
210 state: malloc_raw(kk, key),
211 _phantom: PhantomData,
212 }
213 }
214}
215
216impl<'a> Blake2bBuilder<'a, &'a [u8]> {
217 pub fn new_keyed_dynamic(key: &'a [u8]) -> Result<Self, Error> {
220 if key.len() > MAX_LEN {
221 return Err(Error::InvalidKeyLength);
222 }
223
224 Ok(Self {
225 key,
226 personal: &[0; PARAM_LEN],
227 salt: &[0; PARAM_LEN],
228 })
229 }
230
231 pub fn build_var_digest_len(self, digest_length: u8) -> Result<Blake2b<Dynamic>, Error> {
233 if digest_length < 1 || digest_length as usize > MAX_LEN {
234 return Err(Error::InvalidDigestLength);
235 }
236
237 let key_length = self.key.len() as u8;
239
240 let kk = index {
241 key_length,
242 digest_length,
243 last_node: false,
244 };
245
246 let params = blake2_params {
247 digest_length,
248 key_length,
249 fanout: 1,
250 depth: 1,
251 leaf_length: 0,
252 node_offset: 0,
253 node_depth: 0,
254 inner_length: 0,
255 salt: self.salt,
256 personal: self.personal,
257 };
258
259 let key = params_and_key {
260 fst: &[params],
261 snd: self.key,
262 };
263
264 Ok(Blake2b {
265 state: malloc_raw(kk, key),
266 _phantom: PhantomData,
267 })
268 }
269
270 pub fn build_const_digest_len<const OUT_LEN: usize>(self) -> Blake2b<ConstDigestLen<OUT_LEN>>
272 where
273 Blake2b<LengthBounds>: SupportsOutLen<OUT_LEN>,
274 {
275 let key_length = self.key.len() as u8;
277 let digest_length = OUT_LEN as u8;
278
279 let kk = index {
280 key_length,
281 digest_length,
282 last_node: false,
283 };
284
285 let params = blake2_params {
286 digest_length,
287 key_length,
288 fanout: 1,
289 depth: 1,
290 leaf_length: 0,
291 node_offset: 0,
292 node_depth: 0,
293 inner_length: 0,
294 salt: self.salt,
295 personal: self.personal,
296 };
297
298 let key = params_and_key {
299 fst: &[params],
300 snd: self.key,
301 };
302
303 Blake2b {
304 state: malloc_raw(kk, key),
305 _phantom: PhantomData,
306 }
307 }
308}
309
310impl<'a, T> Blake2bBuilder<'a, T> {
311 pub fn with_personalization(self, personal: &'a [u8; PARAM_LEN]) -> Self {
313 Self { personal, ..self }
314 }
315
316 pub fn with_salt(self, salt: &'a [u8; PARAM_LEN]) -> Self {
318 Self { salt, ..self }
319 }
320}
321
322pub struct Blake2b<T> {
324 state: Box<[state_t]>,
325 _phantom: PhantomData<T>,
326}
327
328impl<T> Blake2b<T> {
329 pub fn update(&mut self, chunk: &[u8]) -> Result<(), Error> {
331 if chunk.len() > (u32::MAX as usize) {
332 return Err(Error::InvalidChunkLength);
333 }
334
335 match update0(self.state.as_mut(), chunk, chunk.len() as u32) {
336 error_code::Success => Ok(()),
337 error_code::MaximumLengthExceeded => Err(Error::MaximumLengthExceeded),
338 _ => Err(Error::Unexpected),
339 }
340 }
341}
342
343impl<const KEY_LEN: usize> Blake2b<ConstKeyLen<KEY_LEN>> {
344 pub fn finalize(&self, dst: &mut [u8]) -> Result<usize, Error> {
348 let digest_len = self.state[0].block_state.snd;
349 if dst.len() < digest_len as usize {
350 return Err(Error::InvalidDigestLength);
351 }
352
353 Ok(digest(&self.state, dst) as usize)
354 }
355}
356
357impl Blake2b<Dynamic> {
358 pub fn finalize(&self, dst: &mut [u8]) -> Result<usize, Error> {
362 let digest_len = self.state[0].block_state.snd;
363 if dst.len() < digest_len as usize {
364 return Err(Error::InvalidDigestLength);
365 }
366
367 Ok(digest(&self.state, dst) as usize)
368 }
369}
370
371impl<const KEY_LEN: usize, const OUT_LEN: usize>
372 Blake2b<ConstKeyLenConstDigestLen<KEY_LEN, OUT_LEN>>
373{
374 pub fn finalize(&self, dst: &mut [u8; OUT_LEN]) {
376 digest(&self.state, dst);
377 }
378}
379
380impl<const OUT_LEN: usize> Blake2b<ConstDigestLen<OUT_LEN>> {
381 pub fn finalize(&self, dst: &mut [u8; OUT_LEN]) {
383 digest(&self.state, dst);
384 }
385}
386
387impl<const KEY_LEN: usize, const OUT_LEN: usize>
388 Blake2b<ConstKeyLenConstDigestLen<KEY_LEN, OUT_LEN>>
389{
390 pub fn reset_with_key(&mut self, key: &[u8; KEY_LEN]) {
392 reset_with_key(&mut self.state, key);
393 }
394}
395
396impl<const KEY_LEN: usize> Blake2b<ConstKeyLen<KEY_LEN>> {
397 pub fn reset_with_key(&mut self, key: &[u8; KEY_LEN]) {
399 reset_with_key(&mut self.state, key);
400 }
401}
402
403impl<const OUT_LEN: usize> Blake2b<ConstDigestLen<OUT_LEN>> {
404 pub fn reset_with_key(&mut self, key: &[u8]) -> Result<(), Error> {
406 if self.state.as_ref()[0].block_state.fst as usize != key.len() {
408 return Err(Error::InvalidKeyLength);
409 }
410
411 reset_with_key(&mut self.state, key);
412 Ok(())
413 }
414}
415
416impl Blake2b<Dynamic> {
417 pub fn reset_with_key(&mut self, key: &[u8]) -> Result<(), Error> {
419 if self.state[0].block_state.fst as usize != key.len() {
421 return Err(Error::InvalidKeyLength);
422 }
423
424 reset_with_key(&mut self.state, key);
425 Ok(())
426 }
427}
428
429impl Blake2b<ConstKeyLen<0>> {
430 pub fn reset(&mut self) {
432 reset(&mut self.state)
433 }
434}
435
436impl<const OUT_LEN: usize> Blake2b<ConstKeyLenConstDigestLen<0, OUT_LEN>> {
437 pub fn reset(&mut self) {
439 reset(&mut self.state)
440 }
441}
442
443impl<const OUT_LEN: usize> Blake2b<ConstDigestLen<OUT_LEN>> {
444 pub fn reset(&mut self) -> Result<(), Error> {
446 if self.state.as_ref()[0].block_state.fst != 0 {
448 return Err(Error::InvalidKeyLength);
449 }
450
451 reset(&mut self.state);
452 Ok(())
453 }
454}
455
456impl Blake2b<Dynamic> {
457 pub fn reset(&mut self) -> Result<(), Error> {
459 if self.state.as_ref()[0].block_state.fst != 0 {
461 return Err(Error::InvalidKeyLength);
462 }
463
464 reset(&mut self.state);
465 Ok(())
466 }
467}