use std::io::{self, Read};
use crate::{Hasher, Result, VerifyError};
pub struct VerifiedReader<R, H> {
reader: R,
hasher: H,
}
impl<R, H> VerifiedReader<R, H> {
pub fn new(reader: R, hasher: H) -> Self {
Self { reader, hasher }
}
}
impl<R: Read, H: Hasher> VerifiedReader<R, H> {
pub fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.reader.read(buf)?;
if n > 0 {
self.hasher.update(&buf[..n]);
}
Ok(n)
}
pub fn finish(self, expected: &[u8]) -> Result<()> {
let actual = self.hasher.finalize();
if actual == expected {
Ok(())
} else {
Err(VerifyError::HashMismatch {
expected: expected.to_vec(),
actual,
})
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[cfg(feature = "sha256")]
use crate::Sha256Hasher;
#[cfg(feature = "sha256")]
#[test]
fn test_sha256_hasher() {
let mut hasher = Sha256Hasher::new();
hasher.update(b"hello world");
let hash = hasher.finalize();
let expected =
hex::decode("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9")
.unwrap();
assert_eq!(hash, expected);
}
#[cfg(feature = "sha256")]
#[test]
fn test_verified_reader_success() {
let data = b"test data for verification";
let mut hasher = Sha256Hasher::new();
hasher.update(data);
let expected = hasher.finalize();
let reader = Cursor::new(data);
let hasher = Sha256Hasher::new();
let mut verified = VerifiedReader::new(reader, hasher);
let mut buffer = [0; 32];
verified.read(&mut buffer).unwrap();
verified.finish(&expected).unwrap();
}
#[cfg(feature = "sha256")]
#[test]
fn test_verified_reader_hash_mismatch() {
let data = b"test data";
let reader = Cursor::new(data);
let hasher = Sha256Hasher::new();
let mut verified = VerifiedReader::new(reader, hasher);
let mut buffer = [0; 32];
verified.read(&mut buffer).unwrap();
let wrong_hash = vec![0; 32];
let result = verified.finish(&wrong_hash);
assert!(result.is_err());
if let Err(VerifyError::HashMismatch { expected, actual }) = result {
assert_eq!(expected, vec![0; 32]);
assert_ne!(actual, vec![0; 32]);
} else {
panic!("Expected HashMismatch error");
}
}
}