//! SHA-256 of a model file, streamed (a model can be hundreds of megabytes). use std::io::{self, Read}; use std::path::Path; use sha2::{Digest, Sha256}; /// Lowercase hex SHA-256 of everything `r` yields. pub fn sha256_reader(mut r: R) -> io::Result { let mut h = Sha256::new(); let mut buf = vec![0u8; 1 << 20]; loop { let n = r.read(&mut buf)?; if n == 0 { break; } h.update(buf.get(..n).unwrap_or(&[])); } Ok(hex(&h.finalize())) } /// Lowercase hex SHA-256 of a file. pub fn sha256_file(path: &Path) -> io::Result { sha256_reader(io::BufReader::new(std::fs::File::open(path)?)) } /// Lowercase hex SHA-256 of `bytes`. pub fn sha256_hex(bytes: &[u8]) -> String { hex(&Sha256::digest(bytes)) } fn hex(bytes: &[u8]) -> String { bytes.iter().map(|b| format!("{b:02x}")).collect() } #[cfg(test)] mod tests { use super::*; #[test] fn known_digests() { assert_eq!(sha256_hex(b""), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); assert_eq!(sha256_hex(b"abc"), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); assert_eq!(sha256_reader(&b"abc"[..]).unwrap(), sha256_hex(b"abc")); } }