blake2b 0.6.1

BLAKE2b hash function
Documentation
use std::cmp::{min};

use {Blake2b, Hash, ParameterBlock};
use slice_ext::{SliceExt};
use unbuffered;

pub struct Blake2xb {
	blake2b: Blake2b,
	parameter_block: ParameterBlock,
	len: u32,
}

pub struct Iter {
	parameter_block: ParameterBlock,
	block: [u64; 16],
	block_len: usize,
	max_out_len: u32,
	out_len: u32,
}

impl Blake2xb {
	pub fn new(len: Option<u32>) -> Self {
		Self::keyed(len, &[])
	}

	pub fn keyed(len: Option<u32>, key: &[u8]) -> Self {
		assert!(len.map(|len| len != 0 && len != u32::max_value()).unwrap_or(true), "len must be >= 1 and <= 2^32 - 2");

		let parameter_block = ParameterBlock::new()
			.set_digest_len(64)
			.set_key_len(key.len() as u8)
			.set_fanout(1)
			.set_max_depth(1)
			.set_node_offset((len.unwrap_or(u32::max_value()) as u64) << 32);

		Self::with_parameter_block_keyed(len, key, parameter_block)
	}

	pub fn with_parameter_block_keyed(len: Option<u32>, key: &[u8], parameter_block: ParameterBlock) -> Self {
		assert!(len.map(|len| len != 0 && len != u32::max_value()).unwrap_or(true), "len must be >= 1 and <= 2^32 - 2");

		Blake2xb {
			blake2b: Blake2b::with_parameter_block_keyed(64, key, parameter_block.clone()),
			parameter_block: parameter_block,
			len: len.unwrap_or(u32::max_value())
		}
	}

	pub fn len(&self) -> usize {
		self.len as usize
	}

	pub fn update(&mut self, data: &[u8]) {
		self.blake2b.update(data);
	}

	pub fn finish(self) -> Iter {
		let mut block = [0; 16];
		block[..8].copy_from_slice(AsRef::<[u64]>::as_ref(&self.blake2b.finish()));

		let parameter_block = self.parameter_block
			.set_key_len(0)
			.set_fanout(0)
			.set_max_depth(0)
			.set_max_leaf_len(64)
			.set_node_depth(0)
			.set_inner_len(64);

		Iter {
			parameter_block: parameter_block,
			block: block,
			block_len: 64,
			max_out_len: self.len,
			out_len: 0,
		}
	}
}

impl Iter {
	pub fn new(len: Option<u32>, seed: &[u8]) -> Self {
		let parameter_block = ParameterBlock::new()
			.set_max_leaf_len(64)
			.set_inner_len(64);

		Self::with_parameter_block(len, seed, parameter_block)
	}

	pub fn with_parameter_block(len: Option<u32>, seed: &[u8], parameter_block: ParameterBlock) -> Self {
		assert!(len.map(|len| len != 0 && len != u32::max_value()).unwrap_or(true), "len must be >= 1 and <= 2^32 - 2");
		assert!(seed.len() <= 128, "seed length must be <= 128");

		let mut block = [0; 16];
		block.as_mut_bytes()[..seed.len()].copy_from_slice(seed);

		Iter {
			parameter_block: parameter_block,
			block: block,
			block_len: seed.len(),
			max_out_len: len.unwrap_or(u32::max_value()),
			out_len: 0
		}
	}

	pub fn max_out_len(&self) -> usize {
		self.max_out_len as usize
	}

	pub fn out_len(&self) -> usize {
		self.out_len as usize
	}
}

impl Iterator for Iter {
	type Item = Hash;

	fn next(&mut self) -> Option<Self::Item> {
		if self.out_len == self.max_out_len {
			return None;
		}

		let len = min(self.max_out_len - self.out_len, 64);
		let parameter_block = self.parameter_block.clone()
			.set_digest_len(len as u8)
			.set_node_offset((self.out_len as u64 / 64) | ((self.max_out_len as u64) << 32));

		self.out_len += len;
		Some(unbuffered::Blake2b::with_parameter_block(len as usize, parameter_block).finish(&self.block, self.block_len))
	}

	fn size_hint(&self) -> (usize, Option<usize>) {
		let i = (self.max_out_len - self.out_len) as usize / 64 + if self.max_out_len % 64 != 0 { 1 } else { 0 };
		(i, Some(i))
	}
}