#![no_std]
pub extern crate byteorder;
pub extern crate block_padding;
pub extern crate generic_array;
extern crate byte_tools;
use byteorder::{ByteOrder, BE};
use byte_tools::zero;
use block_padding::{Padding, PadError};
use generic_array::{GenericArray, ArrayLength};
use core::slice;
#[derive(Clone, Default)]
pub struct BlockBuffer<BlockSize: ArrayLength<u8>> {
buffer: GenericArray<u8, BlockSize>,
pos: usize,
}
#[inline(always)]
unsafe fn cast<N: ArrayLength<u8>>(block: &[u8]) -> &GenericArray<u8, N> {
debug_assert_eq!(block.len(), N::to_usize());
&*(block.as_ptr() as *const GenericArray<u8, N>)
}
impl<BlockSize: ArrayLength<u8>> BlockBuffer<BlockSize> {
#[inline]
pub fn input<F>(&mut self, mut input: &[u8], mut f: F)
where F: FnMut(&GenericArray<u8, BlockSize>)
{
let rem = self.remaining();
if self.pos != 0 && input.len() >= rem {
let (l, r) = input.split_at(rem);
input = r;
self.buffer[self.pos..].copy_from_slice(l);
self.pos = 0;
f(&self.buffer);
}
while input.len() >= self.size() {
let (block, r) = input.split_at(self.size());
input = r;
f(unsafe { cast(block) });
}
self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input);
self.pos += input.len();
}
#[inline]
pub fn input2<F>(&mut self, mut input: &[u8], mut f: F)
where F: FnMut(&[GenericArray<u8, BlockSize>])
{
let rem = self.remaining();
if self.pos != 0 && input.len() >= rem {
let (l, r) = input.split_at(rem);
input = r;
self.buffer[self.pos..].copy_from_slice(l);
self.pos = 0;
f(slice::from_ref(&self.buffer));
}
let n_blocks = input.len()/self.size();
let (left, right) = input.split_at(n_blocks*self.size());
let blocks = unsafe {
slice::from_raw_parts(
left.as_ptr() as *const GenericArray<u8, BlockSize>,
n_blocks,
)
};
f(blocks);
self.buffer[self.pos..self.pos+right.len()].copy_from_slice(right);
self.pos += right.len();
}
#[inline]
pub fn input_lazy<F>(&mut self, mut input: &[u8], mut f: F)
where F: FnMut(&GenericArray<u8, BlockSize>)
{
let rem = self.remaining();
if self.pos != 0 && input.len() > rem {
let (l, r) = input.split_at(rem);
input = r;
self.buffer[self.pos..].copy_from_slice(l);
self.pos = 0;
f(&self.buffer);
}
while input.len() > self.size() {
let (block, r) = input.split_at(self.size());
input = r;
f(unsafe { cast(block) });
}
self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input);
self.pos += input.len();
}
#[inline]
fn digest_pad<F>(&mut self, up_to: usize, f: &mut F)
where F: FnMut(&GenericArray<u8, BlockSize>)
{
if self.pos == self.size() {
f(&self.buffer);
self.pos = 0;
}
self.buffer[self.pos] = 0x80;
self.pos += 1;
zero(&mut self.buffer[self.pos..]);
if self.remaining() < up_to {
f(&self.buffer);
zero(&mut self.buffer[..self.pos]);
}
}
#[inline]
pub fn len64_padding<B, F>(&mut self, data_len: u64, mut f: F)
where B: ByteOrder, F: FnMut(&GenericArray<u8, BlockSize>)
{
self.digest_pad(8, &mut f);
let s = self.size();
B::write_u64(&mut self.buffer[s-8..], data_len);
f(&self.buffer);
self.pos = 0;
}
#[inline]
pub fn len128_padding_be<F>(&mut self, hi: u64, lo: u64, mut f: F)
where F: FnMut(&GenericArray<u8, BlockSize>)
{
self.digest_pad(16, &mut f);
let s = self.size();
BE::write_u64(&mut self.buffer[s-16..s-8], hi);
BE::write_u64(&mut self.buffer[s-8..], lo);
f(&self.buffer);
self.pos = 0;
}
#[inline]
pub fn pad_with<P: Padding>(&mut self)
-> Result<&mut GenericArray<u8, BlockSize>, PadError>
{
P::pad_block(&mut self.buffer[..], self.pos)?;
self.pos = 0;
Ok(&mut self.buffer)
}
#[inline]
pub fn size(&self) -> usize {
BlockSize::to_usize()
}
#[inline]
pub fn position(&self) -> usize {
self.pos
}
#[inline]
pub fn remaining(&self) -> usize {
self.size() - self.pos
}
#[inline]
pub fn reset(&mut self) {
self.pos = 0
}
}