use bytes::{Bytes, BytesMut};
use crate::{BlakeHash, Error, Result};
pub(crate) struct Verifier {
expected: BlakeHash,
hasher: blake3::Hasher,
buf: BytesMut,
}
impl Verifier {
pub fn new(expected: BlakeHash) -> Self {
Self {
expected,
hasher: blake3::Hasher::new(),
buf: BytesMut::new(),
}
}
pub fn update(&mut self, chunk: &[u8]) {
self.hasher.update(chunk);
self.buf.extend_from_slice(chunk);
}
pub fn finish(self) -> Result<Bytes> {
let actual = BlakeHash::from_bytes(*self.hasher.finalize().as_bytes());
if actual != self.expected {
return Err(Error::HashMismatch { expected: self.expected, actual });
}
Ok(self.buf.freeze())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_correct_hash() {
let data = b"hello verifier";
let hash = BlakeHash::hash(data);
let mut v = Verifier::new(hash);
v.update(data);
assert!(v.finish().is_ok());
}
#[test]
fn verify_chunked_input() {
let data = b"chunk one chunk two chunk three";
let hash = BlakeHash::hash(data);
let mut v = Verifier::new(hash);
v.update(&data[..10]);
v.update(&data[10..20]);
v.update(&data[20..]);
let result = v.finish().unwrap();
assert_eq!(&result[..], data);
}
#[test]
fn verify_wrong_hash() {
let data = b"correct bytes";
let wrong_hash = BlakeHash::hash(b"different bytes");
let mut v = Verifier::new(wrong_hash);
v.update(data);
assert!(matches!(v.finish(), Err(Error::HashMismatch { .. })));
}
#[test]
fn verify_empty_blob() {
let data = b"";
let hash = BlakeHash::hash(data);
let v = Verifier::new(hash);
let result = v.finish().unwrap();
assert_eq!(result.len(), 0);
}
}