use hash::{Hasher, NodeHasher};
use tree::Children;
pub extern crate digest_hash;
pub extern crate generic_array;
use self::digest_hash::digest::{FixedOutput, Input};
use self::digest_hash::{Endian, EndianInput, Hash};
use self::generic_array::GenericArray;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
pub struct DefaultNodeHasher<D> {
phantom: PhantomData<D>,
}
impl<D> DefaultNodeHasher<D> {
pub fn new() -> Self {
DefaultNodeHasher {
phantom: PhantomData,
}
}
}
impl<D> Default for DefaultNodeHasher<D> {
fn default() -> Self {
DefaultNodeHasher::new()
}
}
impl<D> Clone for DefaultNodeHasher<D> {
fn clone(&self) -> Self {
DefaultNodeHasher::new()
}
}
impl<D> Debug for DefaultNodeHasher<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.write_str("DefaultNodeHasher")
}
}
impl<D> NodeHasher for DefaultNodeHasher<D>
where
D: Default,
D: Input + FixedOutput,
{
type HashOutput = GenericArray<u8, D::OutputSize>;
fn hash_children<'a, L>(
&'a self,
iter: Children<'a, Self::HashOutput, L>,
) -> Self::HashOutput {
let mut digest = D::default();
digest.input(&[1u8]);
for node in iter {
digest.input(node.hash_bytes());
}
digest.fixed_result()
}
}
pub struct DigestHasher<D, Nh = DefaultNodeHasher<D>>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
{
node_hasher: Nh,
phantom: PhantomData<D>,
}
impl<D, Nh> DigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
Nh: Default,
{
pub fn new() -> Self {
Self::with_node_hasher(Nh::default())
}
}
impl<D, Nh> DigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
{
pub fn with_node_hasher(node_hasher: Nh) -> Self {
DigestHasher {
node_hasher,
phantom: PhantomData,
}
}
}
impl<D, Nh> Default for DigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
Nh: Default,
{
fn default() -> Self {
DigestHasher::new()
}
}
impl<D, Nh> Clone for DigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
Nh: Clone,
{
fn clone(&self) -> Self {
DigestHasher {
node_hasher: self.node_hasher.clone(),
phantom: PhantomData,
}
}
}
impl<D, Nh> Debug for DigestHasher<D, Nh>
where
D: EndianInput + FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
Nh: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_tuple("DigestHasher")
.field(&self.node_hasher)
.field(&Endian::<D, D::ByteOrder>::byte_order_str())
.finish()
}
}
impl<D, Nh, In: ?Sized> Hasher<In> for DigestHasher<D, Nh>
where
In: Hash,
D: Default,
D: EndianInput + FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
{
fn hash_input(&self, input: &In) -> Self::HashOutput {
let mut digest = D::default();
digest.input(&[0u8]);
input.hash(&mut digest);
digest.fixed_result()
}
}
impl<D, Nh> NodeHasher for DigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
{
type HashOutput = GenericArray<u8, D::OutputSize>;
fn hash_children<'a, L>(
&'a self,
iter: Children<'a, Self::HashOutput, L>,
) -> Self::HashOutput {
self.node_hasher.hash_children(iter)
}
}
pub struct ByteDigestHasher<D, Nh = DefaultNodeHasher<D>>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
{
node_hasher: Nh,
phantom: PhantomData<D>,
}
impl<D, Nh> ByteDigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
Nh: Default,
{
pub fn new() -> Self {
Self::with_node_hasher(Nh::default())
}
}
impl<D, Nh> ByteDigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
{
pub fn with_node_hasher(node_hasher: Nh) -> Self {
ByteDigestHasher {
node_hasher,
phantom: PhantomData,
}
}
}
impl<D, Nh> Default for ByteDigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
Nh: Default,
{
fn default() -> Self {
ByteDigestHasher::new()
}
}
impl<D, Nh> Clone for ByteDigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
Nh: Clone,
{
fn clone(&self) -> Self {
ByteDigestHasher {
node_hasher: self.node_hasher.clone(),
phantom: PhantomData,
}
}
}
impl<D, Nh> Debug for ByteDigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
Nh: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_tuple("DigestHasher")
.field(&self.node_hasher)
.finish()
}
}
impl<D, Nh, In: ?Sized> Hasher<In> for ByteDigestHasher<D, Nh>
where
In: AsRef<[u8]>,
D: Default,
D: Input + FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
{
fn hash_input(&self, input: &In) -> Self::HashOutput {
let mut digest = D::default();
digest.input(&[0u8]);
digest.input(input.as_ref());
digest.fixed_result()
}
}
impl<D, Nh> NodeHasher for ByteDigestHasher<D, Nh>
where
D: FixedOutput,
Nh: NodeHasher<HashOutput = GenericArray<u8, D::OutputSize>>,
{
type HashOutput = GenericArray<u8, D::OutputSize>;
fn hash_children<'a, L>(
&'a self,
iter: Children<'a, Self::HashOutput, L>,
) -> Self::HashOutput {
self.node_hasher.hash_children(iter)
}
}
#[cfg(test)]
mod tests {
use super::{ByteDigestHasher, DigestHasher};
use hash::{Hasher, NodeHasher};
use leaf;
use tree::{Builder, Children};
extern crate sha2;
use self::sha2::{Digest, Sha256};
use super::digest_hash::digest::FixedOutput;
use super::digest_hash::BigEndian;
use super::generic_array::GenericArray;
use std::fmt;
use std::fmt::Debug;
const TEST_DATA: &'static [u8] =
b"The quick brown fox jumps over the lazy dog";
fn leaf_digest(
data: &[u8],
) -> GenericArray<u8, <Sha256 as FixedOutput>::OutputSize> {
let mut digest = Sha256::new();
digest.input(&[0u8]);
digest.input(data);
digest.result()
}
#[test]
fn hash_byte_input() {
let hasher = ByteDigestHasher::<Sha256>::new();
let hash = hasher.hash_input(&TEST_DATA);
assert_eq!(hash, leaf_digest(TEST_DATA));
}
#[test]
fn hash_endian_input() {
let hasher = DigestHasher::<BigEndian<Sha256>>::new();
let hash = hasher.hash_input(&42u16);
assert_eq!(hash, leaf_digest(&[0, 42][..]));
}
#[derive(Default)]
struct CustomNodeHasher;
impl Debug for CustomNodeHasher {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.write_str("CustomNodeHasher")
}
}
impl NodeHasher for CustomNodeHasher {
type HashOutput = GenericArray<u8, <Sha256 as FixedOutput>::OutputSize>;
fn hash_children<'a, L>(
&'a self,
iter: Children<'a, Self::HashOutput, L>,
) -> Self::HashOutput {
let mut digest = Sha256::default();
for node in iter {
digest.input(node.hash_bytes())
}
digest.fixed_result()
}
}
#[test]
fn byte_digest_with_custom_node_hasher() {
const CHUNK_SIZE: usize = 15;
let hasher =
ByteDigestHasher::<Sha256, _>::with_node_hasher(CustomNodeHasher);
let builder = Builder::from_hasher_leaf_data(hasher, leaf::no_data());
let leaves = TEST_DATA
.chunks(CHUNK_SIZE)
.map(|chunk| builder.make_leaf(chunk));
let tree = builder.collect_children_from(leaves).unwrap();
let mut root_digest = Sha256::new();
TEST_DATA
.chunks(CHUNK_SIZE)
.map(|chunk| leaf_digest(chunk))
.for_each(|leaf_hash| {
root_digest.input(leaf_hash.as_slice());
});
assert_eq!(*tree.root().hash(), root_digest.fixed_result());
}
#[test]
fn endian_digest_with_custom_node_hasher() {
let test_input = [42u16, 43u16];
let hasher = DigestHasher::<BigEndian<Sha256>, _>::with_node_hasher(
CustomNodeHasher,
);
let builder = Builder::from_hasher_leaf_data(hasher, leaf::no_data());
let leaves = test_input.iter().map(|input| builder.make_leaf(input));
let tree = builder.collect_children_from(leaves).unwrap();
let mut root_digest = Sha256::new();
test_input
.iter()
.map(|v| leaf_digest(&[0, *v as u8]))
.for_each(|leaf_hash| {
root_digest.input(leaf_hash.as_slice());
});
assert_eq!(*tree.root().hash(), root_digest.fixed_result());
}
}