mod md5;
mod sha1;
mod sha256;
mod xxh64;
pub use md5::Md5;
pub use sha1::Sha1;
pub use sha256::Sha256;
pub use xxh64::{Xxh64, xxh64};
const BLOCK: usize = 64;
#[derive(Clone)]
struct BlockBuffer {
buf: [u8; BLOCK],
len: usize,
total: u64,
}
impl BlockBuffer {
const fn new() -> Self {
Self {
buf: [0; BLOCK],
len: 0,
total: 0,
}
}
fn update(&mut self, data: &[u8], compress: &mut impl FnMut(&[u8; BLOCK])) {
self.total = self.total.wrapping_add(data.len() as u64);
self.feed(data, compress);
}
fn feed(&mut self, mut data: &[u8], compress: &mut impl FnMut(&[u8; BLOCK])) {
if self.len != 0 {
if let Some(free) = self.buf.get_mut(self.len..) {
let take = free.len().min(data.len());
if let (Some(dst), Some((src, rest))) =
(free.get_mut(..take), data.split_at_checked(take))
{
dst.copy_from_slice(src);
data = rest;
self.len = self.len.saturating_add(take);
}
}
if self.len < BLOCK {
return;
}
compress(&self.buf);
self.len = 0;
}
let (blocks, rest) = data.as_chunks::<BLOCK>();
for block in blocks {
compress(block);
}
if let Some(dst) = self.buf.get_mut(..rest.len()) {
dst.copy_from_slice(rest);
self.len = rest.len();
}
}
fn finish(&mut self, length: [u8; 8], compress: &mut impl FnMut(&[u8; BLOCK])) {
let mut pad = [0u8; BLOCK];
pad[0] = 0x80;
let pad_len = if self.len < 56 {
56usize.saturating_sub(self.len)
} else {
120usize.saturating_sub(self.len)
};
self.feed(pad.get(..pad_len).unwrap_or(&pad), compress);
self.feed(&length, compress);
}
fn bit_length(&self) -> u64 {
self.total.wrapping_mul(8)
}
}