1use crate::constants::{
38 CRYPTO_HASH_SHA256_BYTES, CRYPTO_HASH_SHA512_BYTES, CRYPTO_HASH_SHA3256_BYTES,
39 CRYPTO_HASH_SHA3512_BYTES,
40};
41use crate::sha3::{Sha3256, Sha3512};
42use crate::sha256::Sha256;
43use crate::sha512::*;
44
45pub type Digest = Sha512Digest;
47pub type Sha256Digest = [u8; CRYPTO_HASH_SHA256_BYTES];
49pub type Sha512Digest = [u8; CRYPTO_HASH_SHA512_BYTES];
51pub type Sha3256Digest = [u8; CRYPTO_HASH_SHA3256_BYTES];
53pub type Sha3512Digest = [u8; CRYPTO_HASH_SHA3512_BYTES];
55
56pub fn crypto_hash(output: &mut Digest, input: &[u8]) {
59 crypto_hash_sha512(output, input);
60}
61
62macro_rules! crypto_hash_state {
66 (
67 $(#[$state_meta:meta])*
68 state: $state:ident($hasher:ty),
69 $(#[$init_meta:meta])*
70 init: $init:ident,
71 $(#[$update_meta:meta])*
72 update: $update:ident,
73 $(#[$final_meta:meta])*
74 final: $final:ident($digest:ty)
75 ) => {
76 $(#[$state_meta])*
77 #[derive(Default)]
78 pub struct $state {
79 pub(super) hasher: $hasher,
80 }
81
82 $(#[$init_meta])*
83 #[must_use]
84 pub fn $init() -> $state {
85 <$state>::default()
86 }
87
88 $(#[$update_meta])*
89 pub fn $update(state: &mut $state, input: &[u8]) {
90 state.hasher.update(input);
91 }
92
93 $(#[$final_meta])*
94 pub fn $final(state: $state, output: &mut $digest) {
95 state.hasher.finalize_into_bytes(output)
96 }
97 };
98}
99
100pub fn crypto_hash_sha256(output: &mut Sha256Digest, input: &[u8]) {
102 Sha256::compute_into_bytes(output, input);
103}
104
105crypto_hash_state! {
106 state: Sha256State(Sha256),
108 init: crypto_hash_sha256_init,
110 update: crypto_hash_sha256_update,
112 final: crypto_hash_sha256_final(Sha256Digest)
115}
116
117pub fn crypto_hash_sha512(output: &mut Digest, input: &[u8]) {
119 Sha512::compute_into_bytes(output, input);
120}
121
122crypto_hash_state! {
123 state: Sha512State(Sha512),
125 init: crypto_hash_sha512_init,
127 update: crypto_hash_sha512_update,
129 final: crypto_hash_sha512_final(Digest)
132}
133
134pub fn crypto_hash_sha3256(output: &mut Sha3256Digest, input: &[u8]) {
136 let mut state = crypto_hash_sha3256_init();
137 crypto_hash_sha3256_update(&mut state, input);
138 crypto_hash_sha3256_final(state, output);
139}
140
141crypto_hash_state! {
142 state: Sha3256State(Sha3256),
144 init: crypto_hash_sha3256_init,
146 update: crypto_hash_sha3256_update,
148 final: crypto_hash_sha3256_final(Sha3256Digest)
151}
152
153pub fn crypto_hash_sha3512(output: &mut Sha3512Digest, input: &[u8]) {
155 let mut state = crypto_hash_sha3512_init();
156 crypto_hash_sha3512_update(&mut state, input);
157 crypto_hash_sha3512_final(state, output);
158}
159
160crypto_hash_state! {
161 state: Sha3512State(Sha3512),
163 init: crypto_hash_sha3512_init,
165 update: crypto_hash_sha3512_update,
167 final: crypto_hash_sha3512_final(Sha3512Digest)
170}
171
172#[cfg(test)]
173mod tests {
174 use sha2::Digest as _;
175
176 use super::*;
177 use crate::sha3::test_vectors::{SHA3_256_RATE, SHA3_512_RATE, sha3_256, sha3_512};
178 use crate::test_prelude::*;
179 use crate::utils::test_util::hex;
180
181 fn pattern(len: usize) -> Vec<u8> {
182 (0..len as u32).map(|i| (i * 31 % 251) as u8).collect()
183 }
184
185 fn sha2_lengths(block: usize, length_field: usize) -> impl Iterator<Item = usize> {
190 let pad = block - length_field;
191 [
192 0,
193 1,
194 pad - 1,
195 pad,
196 pad + 1,
197 block - 1,
198 block,
199 block + 1,
200 2 * block - 1,
201 2 * block,
202 ]
203 .into_iter()
204 }
205
206 fn streamed<S>(
210 message: &[u8],
211 block: usize,
212 init: impl Fn() -> S,
213 update: impl Fn(&mut S, &[u8]),
214 finalize: impl Fn(S) -> Vec<u8>,
215 ) -> [Vec<u8>; 3] {
216 let mut one = init();
217 update(&mut one, message);
218
219 let mut blocks = init();
220 for chunk in message.chunks(block) {
221 update(&mut blocks, chunk);
222 }
223
224 let mut bytes = init();
225 update(&mut bytes, b"");
226 for byte in message {
227 update(&mut bytes, core::slice::from_ref(byte));
228 update(&mut bytes, b"");
229 }
230
231 [finalize(one), finalize(blocks), finalize(bytes)]
232 }
233
234 #[test]
236 fn test_crypto_hash_sha256() {
237 for (message, expected) in [
238 (
239 &b""[..],
240 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
241 ),
242 (
243 b"abc",
244 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
245 ),
246 (
247 b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
248 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
249 ),
250 ] {
251 let mut digest = [0u8; CRYPTO_HASH_SHA256_BYTES];
252 crypto_hash_sha256(&mut digest, message);
253 assert_eq!(digest.to_vec(), hex(expected));
254 }
255 }
256
257 #[test]
260 fn test_crypto_hash_is_sha512() {
261 for (message, expected) in [
262 (
263 &b"abc"[..],
264 concat!(
265 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a",
266 "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
267 ),
268 ),
269 (
270 b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno\
271 ijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
272 concat!(
273 "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018",
274 "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909",
275 ),
276 ),
277 ] {
278 let expected = hex(expected);
279 let mut digest = [0u8; CRYPTO_HASH_SHA512_BYTES];
280 crypto_hash(&mut digest, message);
281 assert_eq!(digest.to_vec(), expected);
282
283 for actual in streamed(
284 message,
285 128,
286 crypto_hash_sha512_init,
287 crypto_hash_sha512_update,
288 |state| {
289 let mut digest = [0u8; CRYPTO_HASH_SHA512_BYTES];
290 crypto_hash_sha512_final(state, &mut digest);
291 digest.to_vec()
292 },
293 ) {
294 assert_eq!(actual, expected);
295 }
296 }
297 }
298
299 #[test]
302 fn test_crypto_hash_sha256_boundaries_match_sha2() {
303 for len in sha2_lengths(64, 8) {
304 let message = pattern(len);
305 let expected = sha2::Sha256::digest(&message).to_vec();
306 let mut digest = [0u8; CRYPTO_HASH_SHA256_BYTES];
307 crypto_hash_sha256(&mut digest, &message);
308 assert_eq!(digest.to_vec(), expected, "one-shot len {len}");
309 for actual in streamed(
310 &message,
311 64,
312 crypto_hash_sha256_init,
313 crypto_hash_sha256_update,
314 |state| {
315 let mut digest = [0u8; CRYPTO_HASH_SHA256_BYTES];
316 crypto_hash_sha256_final(state, &mut digest);
317 digest.to_vec()
318 },
319 ) {
320 assert_eq!(actual, expected, "streamed len {len}");
321 }
322 }
323 }
324
325 #[test]
328 fn test_crypto_hash_sha512_boundaries_match_sha2() {
329 for len in sha2_lengths(128, 16) {
330 let message = pattern(len);
331 let expected = sha2::Sha512::digest(&message).to_vec();
332 let mut digest = [0u8; CRYPTO_HASH_SHA512_BYTES];
333 crypto_hash_sha512(&mut digest, &message);
334 assert_eq!(digest.to_vec(), expected, "one-shot len {len}");
335 for actual in streamed(
336 &message,
337 128,
338 crypto_hash_sha512_init,
339 crypto_hash_sha512_update,
340 |state| {
341 let mut digest = [0u8; CRYPTO_HASH_SHA512_BYTES];
342 crypto_hash_sha512_final(state, &mut digest);
343 digest.to_vec()
344 },
345 ) {
346 assert_eq!(actual, expected, "streamed len {len}");
347 }
348 }
349 }
350
351 #[test]
355 fn test_crypto_hash_sha3256_known_answers() {
356 for (message, expected) in sha3_256() {
357 let len = message.len();
358 let mut digest = [0u8; CRYPTO_HASH_SHA3256_BYTES];
359 crypto_hash_sha3256(&mut digest, &message);
360 assert_eq!(digest.to_vec(), expected, "one-shot len {len}");
361 if len > 2 * SHA3_256_RATE {
362 continue;
364 }
365 for actual in streamed(
366 &message,
367 SHA3_256_RATE,
368 crypto_hash_sha3256_init,
369 crypto_hash_sha3256_update,
370 |state| {
371 let mut digest = [0u8; CRYPTO_HASH_SHA3256_BYTES];
372 crypto_hash_sha3256_final(state, &mut digest);
373 digest.to_vec()
374 },
375 ) {
376 assert_eq!(actual, expected, "streamed len {len}");
377 }
378 }
379 }
380
381 #[test]
382 fn test_crypto_hash_sha3512_known_answers() {
383 for (message, expected) in sha3_512() {
384 let len = message.len();
385 let mut digest = [0u8; CRYPTO_HASH_SHA3512_BYTES];
386 crypto_hash_sha3512(&mut digest, &message);
387 assert_eq!(digest.to_vec(), expected, "one-shot len {len}");
388 if len > 2 * SHA3_512_RATE {
389 continue;
390 }
391 for actual in streamed(
392 &message,
393 SHA3_512_RATE,
394 crypto_hash_sha3512_init,
395 crypto_hash_sha3512_update,
396 |state| {
397 let mut digest = [0u8; CRYPTO_HASH_SHA3512_BYTES];
398 crypto_hash_sha3512_final(state, &mut digest);
399 digest.to_vec()
400 },
401 ) {
402 assert_eq!(actual, expected, "streamed len {len}");
403 }
404 }
405 }
406
407 #[cfg(dryoc_native_tests)]
410 #[test]
411 fn test_crypto_hash_sha512_matches_libsodium() {
412 use crate::native_test_util::{self as sodium, HashSha512State};
413
414 for len in sha2_lengths(128, 16) {
415 let message = pattern(len);
416 let expected = sodium::crypto_hash_sha512(&message);
417 let mut digest = [0u8; CRYPTO_HASH_SHA512_BYTES];
418 crypto_hash(&mut digest, &message);
419 assert_eq!(digest, expected, "one-shot len {len}");
420
421 let mut theirs = HashSha512State::new();
422 let mut ours = crypto_hash_sha512_init();
423 for chunk in message.chunks(127) {
424 theirs.update(chunk);
425 crypto_hash_sha512_update(&mut ours, chunk);
426 theirs.update(b"");
427 crypto_hash_sha512_update(&mut ours, b"");
428 }
429 crypto_hash_sha512_final(ours, &mut digest);
430 assert_eq!(digest, theirs.finalize(), "streamed len {len}");
431 }
432 }
433
434 #[cfg(dryoc_native_tests)]
438 fn sha3_lengths(rate: usize) -> impl Iterator<Item = usize> {
439 [
440 0,
441 1,
442 rate - 2,
443 rate - 1,
444 rate,
445 rate + 1,
446 2 * rate - 1,
447 2 * rate,
448 2 * rate + 1,
449 3 * rate + 17,
450 ]
451 .into_iter()
452 }
453
454 #[cfg(dryoc_native_tests)]
458 #[test]
459 fn test_crypto_hash_sha3_matches_libsodium() {
460 use crate::native_test_util::{self as sodium, HashSha3256State, HashSha3512State};
461
462 macro_rules! check {
463 (
464 $rate:expr,
465 $bytes:expr,
466 $oneshot:ident,
467 $init:ident,
468 $update:ident,
469 $final:ident,
470 $theirs:ident
471 ) => {
472 for len in sha3_lengths($rate) {
473 let message = pattern(len);
474 let expected = sodium::$oneshot(&message);
475 let mut digest = [0u8; $bytes];
476 $oneshot(&mut digest, &message);
477 assert_eq!(digest, expected, "one-shot len {len}");
478
479 for chunk_len in [1, 67, $rate] {
480 let mut theirs = $theirs::new();
481 let mut ours = $init();
482 for chunk in message.chunks(chunk_len) {
483 theirs.update(chunk);
484 $update(&mut ours, chunk);
485 theirs.update(b"");
486 $update(&mut ours, b"");
487 }
488 $final(ours, &mut digest);
489 assert_eq!(
490 digest,
491 theirs.finalize(),
492 "streamed len {len}, chunks of {chunk_len}"
493 );
494 }
495 }
496 };
497 }
498
499 check!(
500 SHA3_256_RATE,
501 CRYPTO_HASH_SHA3256_BYTES,
502 crypto_hash_sha3256,
503 crypto_hash_sha3256_init,
504 crypto_hash_sha3256_update,
505 crypto_hash_sha3256_final,
506 HashSha3256State
507 );
508 check!(
509 SHA3_512_RATE,
510 CRYPTO_HASH_SHA3512_BYTES,
511 crypto_hash_sha3512,
512 crypto_hash_sha3512_init,
513 crypto_hash_sha3512_update,
514 crypto_hash_sha3512_final,
515 HashSha3512State
516 );
517 }
518}