Skip to main content

libcrux_blake2/
impl_digest_trait.rs

1use crate::impl_hacl::*;
2use libcrux_traits::digest::{
3    arrayref, slice, DigestIncrementalBase, Hasher, InitializeDigestState, UpdateError,
4};
5
6use crate::impl_hacl::SupportsOutLen;
7
8macro_rules! impl_digest_traits {
9    ($out_size:ident, $type:ty, $blake2:ty, $hasher:ty, $set:ty, $builder:ty) => {
10        // Digest state initialization
11        impl<const $out_size: usize> InitializeDigestState for $blake2
12        where
13            // implement for supported digest lengths only
14            $set: SupportsOutLen<$out_size>,
15        {
16            fn new() -> Self {
17                <$builder>::new_unkeyed().build_const_digest_len().into()
18            }
19        }
20
21        // Oneshot hash trait implementation
22        impl<const $out_size: usize> arrayref::Hash<$out_size> for $type
23        where
24            // implement for supported digest lengths only
25            $set: SupportsOutLen<$out_size>,
26        {
27            fn hash(
28                digest: &mut [u8; $out_size],
29                payload: &[u8],
30            ) -> Result<(), arrayref::HashError> {
31                let mut digest_state = <$blake2>::new();
32                <Self as DigestIncrementalBase>::update(&mut digest_state, payload).map_err(
33                    |e| match e {
34                        UpdateError::InvalidPayloadLength | UpdateError::MaximumLengthExceeded => {
35                            arrayref::HashError::InvalidPayloadLength
36                        }
37                        UpdateError::Unknown => arrayref::HashError::Unknown,
38                    },
39                )?;
40                <Self as arrayref::DigestIncremental<$out_size>>::finish(&mut digest_state, digest);
41
42                Ok(())
43            }
44        }
45        // Oneshot hash slice trait implementation
46        impl<const $out_size: usize> slice::Hash for $type
47        where
48            // implement for supported digest lengths only
49            $set: SupportsOutLen<$out_size>,
50        {
51            fn hash(digest: &mut [u8], payload: &[u8]) -> Result<usize, slice::HashError> {
52                let digest: &mut [u8; $out_size] = digest
53                    .try_into()
54                    .map_err(|_| slice::HashError::InvalidDigestLength)?;
55
56                <Self as arrayref::Hash<$out_size>>::hash(digest, payload)?;
57
58                Ok($out_size)
59            }
60        }
61
62        // Digest incremental base trait implementation
63        impl<const $out_size: usize> DigestIncrementalBase for $type
64        where
65            // implement for supported digest lengths only
66            $set: SupportsOutLen<$out_size>,
67        {
68            type IncrementalState = $blake2;
69
70            fn update(state: &mut Self::IncrementalState, chunk: &[u8]) -> Result<(), UpdateError> {
71                // maps all known errors returned by this function
72                state.update(chunk).map_err(|e| match e {
73                    Error::InvalidChunkLength => UpdateError::InvalidPayloadLength,
74                    Error::MaximumLengthExceeded => UpdateError::MaximumLengthExceeded,
75                    _ => UpdateError::Unknown,
76                })
77            }
78            fn reset(state: &mut Self::IncrementalState) {
79                state.reset()
80            }
81        }
82
83        // Digest incremental slice trait implementation
84        impl<const $out_size: usize> slice::DigestIncremental for $type
85        where
86            // implement for supported digest lengths only
87            $set: SupportsOutLen<$out_size>,
88        {
89            fn finish(
90                state: &mut Self::IncrementalState,
91                digest: &mut [u8],
92            ) -> Result<usize, slice::FinishError> {
93                let digest: &mut [u8; $out_size] = digest
94                    .try_into()
95                    .map_err(|_| slice::FinishError::InvalidDigestLength)?;
96                <Self as arrayref::DigestIncremental<$out_size>>::finish(state, digest);
97
98                Ok($out_size)
99            }
100        }
101
102        // Digest incremental arrayref trait implementation
103        impl<const $out_size: usize> arrayref::DigestIncremental<$out_size> for $type
104        where
105            // implement for supported digest lengths only
106            $set: SupportsOutLen<$out_size>,
107        {
108            fn finish(state: &mut Self::IncrementalState, dst: &mut [u8; $out_size]) {
109                state.finalize(dst)
110            }
111        }
112
113        // Convert to `libcrux_traits::digest::Hasher`
114        impl<const $out_size: usize> From<$blake2> for $hasher
115        where
116            // implement for supported digest lengths only
117            $set: SupportsOutLen<$out_size>,
118        {
119            fn from(state: $blake2) -> Self {
120                Self { state }
121            }
122        }
123    };
124}
125
126/// A struct that implements [`libcrux_traits::digest`] traits.
127///
128/// [`Blake2bHasher`] is a convenience hasher for this struct.
129pub struct Blake2bHash<const OUT_SIZE: usize>;
130
131impl_digest_traits!(
132    OUT_SIZE,
133    Blake2bHash<OUT_SIZE>,
134    Blake2b<ConstKeyLenConstDigestLen<0, OUT_SIZE>>,
135    Blake2bHasher<OUT_SIZE>,
136    Blake2b<LengthBounds>,
137    Blake2bBuilder<'_, &()>
138);
139
140/// A hasher for [`Blake2bHash`].
141pub type Blake2bHasher<const OUT_SIZE: usize> = Hasher<OUT_SIZE, Blake2bHash<OUT_SIZE>>;
142
143/// A struct that implements [`libcrux_traits::digest`] traits.
144///
145/// [`Blake2sHasher`] is a convenience hasher for this struct.
146pub struct Blake2sHash<const OUT_SIZE: usize>;
147impl_digest_traits!(
148    OUT_SIZE,
149    Blake2sHash<OUT_SIZE>,
150    Blake2s<ConstKeyLenConstDigestLen<0, OUT_SIZE>>,
151    Blake2sHasher<OUT_SIZE>,
152    Blake2s<LengthBounds>,
153    Blake2sBuilder<'_, &()>
154);
155
156/// A hasher for [`Blake2sHash`].
157pub type Blake2sHasher<const OUT_SIZE: usize> = Hasher<OUT_SIZE, Blake2sHash<OUT_SIZE>>;