1use crate::hacl::{
17 blake2,
18 sha2::{
19 self,
20 streaming::{Sha224, Sha256, Sha384, Sha512},
21 },
22 sha3,
23};
24
25use libcrux_platform::{simd128_support, simd256_support};
26
27#[derive(Debug)]
28pub enum Error {
29 InvalidStateFinished,
30 ModeUnsupportedForStreaming,
31}
32
33#[derive(Copy, Clone, Debug, PartialEq)]
35#[repr(u32)]
36pub enum Algorithm {
37 Sha1 = 1,
38 Sha224 = 2,
39 Sha256 = 3,
40 Sha384 = 4,
41 Sha512 = 5,
42 Blake2s = 6,
43 Blake2b = 7,
44 Sha3_224 = 8,
45 Sha3_256 = 9,
46 Sha3_384 = 10,
47 Sha3_512 = 11,
48}
49
50impl From<u32> for Algorithm {
51 fn from(v: u32) -> Algorithm {
52 match v {
53 1 => Algorithm::Sha1,
54 2 => Algorithm::Sha224,
55 3 => Algorithm::Sha256,
56 4 => Algorithm::Sha384,
57 5 => Algorithm::Sha512,
58 6 => Algorithm::Blake2s,
59 7 => Algorithm::Blake2b,
60 8 => Algorithm::Sha3_224,
61 9 => Algorithm::Sha3_256,
62 10 => Algorithm::Sha3_384,
63 11 => Algorithm::Sha3_512,
64 _ => panic!("Unknown Digest mode {}", v),
65 }
66 }
67}
68
69impl From<Algorithm> for u32 {
70 fn from(v: Algorithm) -> u32 {
71 match v {
72 Algorithm::Sha1 => 1,
73 Algorithm::Sha224 => 2,
74 Algorithm::Sha256 => 3,
75 Algorithm::Sha384 => 4,
76 Algorithm::Sha512 => 5,
77 Algorithm::Blake2s => 6,
78 Algorithm::Blake2b => 7,
79 Algorithm::Sha3_224 => 8,
80 Algorithm::Sha3_256 => 9,
81 Algorithm::Sha3_384 => 10,
82 Algorithm::Sha3_512 => 11,
83 }
84 }
85}
86
87pub const fn digest_size(mode: Algorithm) -> usize {
89 match mode {
90 Algorithm::Sha1 => 20,
91 Algorithm::Sha224 => 28,
92 Algorithm::Sha256 => 32,
93 Algorithm::Sha384 => 48,
94 Algorithm::Sha512 => 64,
95 Algorithm::Blake2s => 32,
96 Algorithm::Blake2b => 64,
97 Algorithm::Sha3_224 => 28,
98 Algorithm::Sha3_256 => 32,
99 Algorithm::Sha3_384 => 48,
100 Algorithm::Sha3_512 => 64,
101 }
102}
103
104impl Algorithm {
105 pub fn size(self) -> usize {
106 digest_size(self)
107 }
108}
109
110pub type Sha2_224Digest = [u8; digest_size(Algorithm::Sha224)];
111pub type Sha2_256Digest = [u8; digest_size(Algorithm::Sha256)];
112pub type Sha2_384Digest = [u8; digest_size(Algorithm::Sha384)];
113pub type Sha2_512Digest = [u8; digest_size(Algorithm::Sha512)];
114
115pub type Sha3_224Digest = [u8; digest_size(Algorithm::Sha3_224)];
116pub type Sha3_256Digest = [u8; digest_size(Algorithm::Sha3_256)];
117pub type Sha3_384Digest = [u8; digest_size(Algorithm::Sha3_384)];
118pub type Sha3_512Digest = [u8; digest_size(Algorithm::Sha3_512)];
119
120macro_rules! sha3_impl {
123 ($fun_name:ident, $output:ty, $jasmin_fun:expr, $hacl_fun:expr) => {
124 #[cfg(all(target_arch = "x86_64", any(target_os = "linux", target_os = "macos")))]
125 pub fn $fun_name(payload: &[u8]) -> $output {
126 $jasmin_fun(payload)
128 }
129
130 #[cfg(not(all(target_arch = "x86_64", any(target_os = "linux", target_os = "macos"))))]
131 pub fn $fun_name(payload: &[u8]) -> $output {
132 $hacl_fun(payload)
134 }
135 };
136}
137
138sha3_impl!(
139 sha3_224,
140 Sha3_224Digest,
141 crate::jasmin::sha3::sha3_224,
142 sha3::sha224
143);
144sha3_impl!(
145 sha3_256,
146 Sha3_256Digest,
147 crate::jasmin::sha3::sha3_256,
148 sha3::sha256
149);
150sha3_impl!(
151 sha3_384,
152 Sha3_384Digest,
153 crate::jasmin::sha3::sha3_384,
154 sha3::sha384
155);
156sha3_impl!(
157 sha3_512,
158 Sha3_512Digest,
159 crate::jasmin::sha3::sha3_512,
160 sha3::sha512
161);
162
163pub fn hash(alg: Algorithm, payload: &[u8]) -> Vec<u8> {
170 match alg {
173 Algorithm::Sha1 => todo!(),
174 Algorithm::Sha224 => sha2::sha224(payload).into(),
175 Algorithm::Sha256 => sha2::sha256(payload).into(),
176 Algorithm::Sha384 => sha2::sha384(payload).into(),
177 Algorithm::Sha512 => sha2::sha512(payload).into(),
178 Algorithm::Blake2s => blake2s(payload, &[]),
179 Algorithm::Blake2b => blake2b(payload, &[]),
180 Algorithm::Sha3_224 => sha3_224(payload).into(),
181 Algorithm::Sha3_256 => sha3_256(payload).into(),
182 Algorithm::Sha3_384 => sha3_384(payload).into(),
183 Algorithm::Sha3_512 => sha3_512(payload).into(),
184 }
185}
186
187#[cfg(simd128)]
188fn blake2s_128<const LEN: usize>(payload: &[u8], key: &[u8]) -> [u8; LEN] {
189 blake2::simd128::blake2s(payload, key)
190}
191
192#[cfg(not(simd128))]
193fn blake2s_128<const LEN: usize>(payload: &[u8], key: &[u8]) -> [u8; LEN] {
194 blake2::blake2s::<LEN>(payload, key)
195}
196
197fn blake2s(payload: &[u8], key: &[u8]) -> Vec<u8> {
199 const DIGEST_LEN: usize = digest_size(Algorithm::Blake2s);
200 if simd128_support() {
201 blake2s_128::<DIGEST_LEN>(payload, key)
202 } else {
203 blake2::blake2s::<DIGEST_LEN>(payload, key)
204 }
205 .into()
206}
207
208#[cfg(simd256)]
209fn blake2b_256<const LEN: usize>(payload: &[u8], key: &[u8]) -> [u8; LEN] {
210 blake2::simd256::blake2b(payload, key)
211}
212
213#[cfg(not(simd256))]
214fn blake2b_256<const LEN: usize>(payload: &[u8], key: &[u8]) -> [u8; LEN] {
215 blake2::blake2b::<LEN>(payload, key)
216}
217
218fn blake2b(payload: &[u8], key: &[u8]) -> Vec<u8> {
220 const DIGEST_LEN: usize = digest_size(Algorithm::Blake2b);
221 if simd256_support() {
222 blake2b_256::<DIGEST_LEN>(payload, key)
223 } else {
224 blake2::blake2b::<DIGEST_LEN>(payload, key)
225 }
226 .into()
227}
228
229pub fn sha2_224(payload: &[u8]) -> Sha2_224Digest {
231 sha2::sha224(payload)
232}
233
234pub fn sha2_256(payload: &[u8]) -> Sha2_256Digest {
236 sha2::sha256(payload)
237}
238
239pub fn sha2_384(payload: &[u8]) -> Sha2_384Digest {
241 sha2::sha384(payload)
242}
243
244pub fn sha2_512(payload: &[u8]) -> Sha2_512Digest {
246 sha2::sha512(payload)
247}
248
249macro_rules! impl_streaming {
251 ($name:ident, $state:ty, $result:ty) => {
252 pub struct $name {
253 state: $state,
254 }
255 impl $name {
256 pub fn new() -> Self {
258 Self {
259 state: <$state>::new(),
260 }
261 }
262
263 pub fn update(&mut self, payload: &[u8]) {
265 self.state.update(payload);
266 }
267
268 pub fn finish(&mut self) -> $result {
273 self.state.finish()
274 }
275 }
276
277 impl Default for $name {
278 fn default() -> Self {
279 Self::new()
280 }
281 }
282 };
283}
284impl_streaming!(Sha2_224, Sha224, Sha2_224Digest);
285impl_streaming!(Sha2_256, Sha256, Sha2_256Digest);
286impl_streaming!(Sha2_384, Sha384, Sha2_384Digest);
287impl_streaming!(Sha2_512, Sha512, Sha2_512Digest);
288
289pub fn shake128<const LEN: usize>(data: &[u8]) -> [u8; LEN] {
295 sha3::shake128(data)
296}
297
298pub fn shake256<const LEN: usize>(data: &[u8]) -> [u8; LEN] {
302 sha3::shake256(data)
303}