use {Hash, ParameterBlock, compress, IV};
use slice_ext::{SliceExt};
#[derive(Clone, Debug)]
pub struct Blake2b {
hash: [u64; 8],
counter: (u64, u64),
len: usize
}
impl Blake2b {
pub fn new(len: usize) -> Self {
Self::with_parameter_block(len, ParameterBlock::new().set_digest_len(len as u8).set_fanout(1).set_max_depth(1))
}
pub fn with_parameter_block(len: usize, parameter_block: ParameterBlock) -> Self {
assert!(len >= 1 && len <= 64, "len must be >= 1 and <= 64");
let mut hash = parameter_block.0;
for (a, b) in hash.iter_mut().zip(IV.iter()) {
*a ^= *b;
}
Blake2b {
hash: hash,
counter: (0, 0),
len: len
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn update(&mut self, block: &[u64; 16]) {
self.add_counter(128);
compress(block, &mut self.hash, self.counter, (0, 0));
}
pub fn finish(mut self, block: &[u64; 16], len: usize) -> Hash {
assert!(len <= 128);
debug_assert!(block.as_bytes()[len..].iter().all(|&i| i == 0));
self.add_counter(len as u64);
compress(block, &mut self.hash, self.counter, (!0, 0));
Hash::new(self.hash, self.len)
}
fn add_counter(&mut self, v: u64) {
debug_assert!(v <= 128);
let (v, b) = self.counter.0.overflowing_add(v);
self.counter.0 = v;
if b {
self.counter.1 = self.counter.1.checked_add(1).expect("blake2b counter overflowed");
}
}
}
impl Default for Blake2b {
fn default() -> Self {
Self::new(64)
}
}