Skip to main content

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}