cabin_core/hash.rs
1//! Shared hash-encoding helpers used across the workspace.
2
3use std::fmt::Write as _;
4use std::io::Read;
5
6use sha2::{Digest, Sha256};
7
8/// Lower-case hex encoding of a digest (or any byte slice).
9pub fn hex_digest(digest: &[u8]) -> String {
10 let mut hex = String::with_capacity(2 * digest.len());
11 for byte in digest {
12 let _ = write!(hex, "{byte:02x}");
13 }
14 hex
15}
16
17/// Stream `reader` through SHA-256 in 64 KiB chunks and return the
18/// lower-case hex digest. This is the shared primitive behind every
19/// Cabin file / archive integrity check; callers own opening the
20/// file and mapping any [`std::io::Error`] into their crate's own
21/// error type (and re-attaching path context).
22///
23/// # Errors
24/// Returns the [`std::io::Error`] propagated from reading `reader`.
25pub fn hash_reader<R: Read>(mut reader: R) -> std::io::Result<String> {
26 let mut hasher = Sha256::new();
27 let mut buf = vec![0u8; 64 * 1024];
28 loop {
29 let n = reader.read(&mut buf)?;
30 if n == 0 {
31 break;
32 }
33 hasher.update(&buf[..n]);
34 }
35 Ok(hex_digest(&hasher.finalize()))
36}