Skip to main content

libcrux_blake2/impl_hacl/
blake2b.rs

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
21/// A builder for [`Blake2b`]. `T` determines whether
22pub 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    /// Creates the builder for an unkeyed hasher.
30    pub fn new_unkeyed() -> Self {
31        Self {
32            key: &(),
33            personal: &[0; PARAM_LEN],
34            salt: &[0; PARAM_LEN],
35        }
36    }
37
38    /// Constructs the [`Blake2b`] hasher for unkeyed hashes and dynamic digest length.
39    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    /// Constructs the [`Blake2b`] hasher for unkeyed hashes and constant digest length.
77    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    /// Creates the builder for an keyed hasher for keys where the length is known at compile
122    /// time.
123    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    /// Constructs the [`Blake2b`] hasher for hashes with const key length and dynamic digest length.
132    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        // This is safe because it's at most 64, enforced in the constructor.
141        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    /// Constructs the [`Blake2b`] hasher for hashes with const key length and constant digest length.
174    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        // These are safe because they both are at most 64, enforced either above or in the
181        // constructor.
182        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    /// Creates the builder for an keyed hasher for keys where the length is not known at compile
218    /// time.
219    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    /// Constructs the fully dynamic [`Blake2b`] hasher.
232    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        // This is safe because it's at most 64, enforced in the constructor.
238        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    /// Constructs the [`Blake2b`] hasher with dynamic key length and constant digest length.
271    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        // these are safe because they both are at most 64
276        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    /// Sets the personalization bytes to be used in the hasher.
312    pub fn with_personalization(self, personal: &'a [u8; PARAM_LEN]) -> Self {
313        Self { personal, ..self }
314    }
315
316    /// Sets the salt to be used in the hasher.
317    pub fn with_salt(self, salt: &'a [u8; PARAM_LEN]) -> Self {
318        Self { salt, ..self }
319    }
320}
321
322/// A hasher struct for the Blake2b (optionally keyed) hash function.
323pub struct Blake2b<T> {
324    state: Box<[state_t]>,
325    _phantom: PhantomData<T>,
326}
327
328impl<T> Blake2b<T> {
329    /// Updates the hash state by adding the bytes from `chunk` to the hashed data.
330    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    /// Compute the hash for the current hash state and write it to `dst`.
345    ///
346    /// Returns a `Result` that contains the length of the digest on success.
347    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    /// Compute the hash for the current hash state and write it to `dst`.
359    ///
360    /// Returns a `Result` that contains the length of the digest on success.
361    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    /// Compute the hash for the current hash state and write it to `dst`.
375    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    /// Compute the hash for the current hash state and write it to `dst`.
382    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    /// Reset the hash state and update the key to the contents of `key`.
391    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    /// Reset the hash state and update the key to the contents of `key`.
398    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    /// Reset the hash state and update the key to the contents of `key`.
405    pub fn reset_with_key(&mut self, key: &[u8]) -> Result<(), Error> {
406        // check that the key length matches
407        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    /// Reset the hash state and update the key to the contents of `key`.
418    pub fn reset_with_key(&mut self, key: &[u8]) -> Result<(), Error> {
419        // check that the key length matches
420        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    /// Reset the hash state.
431    pub fn reset(&mut self) {
432        reset(&mut self.state)
433    }
434}
435
436impl<const OUT_LEN: usize> Blake2b<ConstKeyLenConstDigestLen<0, OUT_LEN>> {
437    /// Reset the hash state.
438    pub fn reset(&mut self) {
439        reset(&mut self.state)
440    }
441}
442
443impl<const OUT_LEN: usize> Blake2b<ConstDigestLen<OUT_LEN>> {
444    /// Reset the hash state.
445    pub fn reset(&mut self) -> Result<(), Error> {
446        // check that the key length matches
447        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    /// Reset the hash state.
458    pub fn reset(&mut self) -> Result<(), Error> {
459        // check that the key length matches
460        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}