use crate::hash;
use crate::hash::Hash;
use crate::hash::Hash32;
pub(super) const MODULO: u32 = 65521;
const NMAX: usize = 5552;
const SIZE: usize = 4;
pub struct Digest {
hash: u32,
}
pub fn new() -> Digest {
Digest::new()
}
impl hash::Hash for Digest {
fn reset(&mut self) {
self.hash = 1
}
fn size(&self) -> usize {
SIZE
}
fn block_size(&self) -> usize {
4
}
fn sum(&self, b: &[u8]) -> Vec<u8> {
let s = self.hash;
let mut res = b.to_vec();
res.extend_from_slice(&[(s >> 24) as u8, (s >> 16) as u8, (s >> 8) as u8, (s) as u8]);
res
}
}
impl std::io::Write for Digest {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.update(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl Digest {
pub fn new() -> Self {
let mut d = Digest { hash: 0 };
d.reset();
d
}
fn update(&mut self, p: &[u8]) {
let mut s1 = self.hash & 0xffff;
let mut s2 = self.hash >> 16;
let mut p = p;
while !p.is_empty() {
let mut q: &[u8] = &[];
if p.len() > NMAX {
q = &p[NMAX..];
p = &p[0..NMAX];
}
while p.len() >= 4 {
s1 += p[0] as u32;
s2 += s1;
s1 += p[1] as u32;
s2 += s1;
s1 += p[2] as u32;
s2 += s1;
s1 += p[3] as u32;
s2 += s1;
p = &p[4..];
}
for x in p {
s1 += *x as u32;
s2 += s1;
}
s1 %= MODULO;
s2 %= MODULO;
p = q
}
self.hash = s2 << 16 | s1;
}
}
impl Default for Digest {
fn default() -> Self {
Self::new()
}
}
impl Hash32 for Digest {
fn sum32(&self) -> u32 {
self.hash
}
}
pub fn checksum(data: &[u8]) -> u32 {
let mut d = Digest::new();
d.update(data);
d.hash
}