rustic_core/crypto/hasher.rs
1use std::io::{ErrorKind, Read, Result};
2
3use sha2::{Digest, Sha256};
4
5use crate::id::Id;
6
7/// Hashes the given data.
8///
9/// # Arguments
10///
11/// * `data` - The data to hash.
12///
13/// # Returns
14///
15/// The hash Id of the data.
16#[must_use]
17pub fn hash(data: &[u8]) -> Id {
18 Id::new(Sha256::digest(data).into())
19}
20
21/// Hashes the data from a [`Read`]er.
22///
23/// # Arguments
24///
25/// * `reader` - The reader to read the data to hash from.
26///
27/// # Returns
28///
29/// # Errors
30/// - if the reader encounters an error
31///
32/// The hash Id of the data.
33pub fn hash_reader(mut reader: impl Read) -> Result<Id> {
34 let mut buffer = [0; 4096];
35 let mut hasher = Sha256::default();
36
37 loop {
38 match reader.read(&mut buffer) {
39 Err(err) => {
40 if err.kind() != ErrorKind::Interrupted {
41 break Err(err);
42 }
43 }
44 Ok(count) => {
45 if count == 0 {
46 let id = hasher.finalize();
47 break Ok(Id::new(id.into()));
48 }
49 hasher.update(&buffer[..count]);
50 }
51 }
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58 use proptest::prelude::*;
59
60 proptest! {
61 #[test]
62 fn hash_reader_is_identical_to_hash(bytes in prop::collection::vec(prop::num::u8::ANY, 0..65536)) {
63 let hash1 = hash(&bytes);
64 let hash2 = hash_reader(&*bytes).unwrap();
65 prop_assert_eq!(hash1, hash2);
66 }
67 }
68}