use crypto::digest::{Digest, OutputSizeUser};
pub type GenericArray<D> = crypto::common::generic_array::GenericArray<
u8,
<D as crypto::common::OutputSizeUser>::OutputSize,
>;
pub trait Hasher {
type Output: AsRef<[u8]> + Clone;
fn hash(&self, data: impl AsRef<[u8]>) -> Self::Output;
fn concat(&self, lhs: impl AsRef<[u8]>, rhs: impl AsRef<[u8]>) -> Self::Output;
fn concat_slice<T: AsRef<[u8]>>(&self, data: &[T]) -> Self::Output;
fn certificate(&self, leaf: bool) -> u8 {
if leaf { 0x00 } else { 0x01 }
}
}
pub struct MrkleHasher<D: Digest> {
phantom: core::marker::PhantomData<D>,
}
impl<D: Digest> Default for MrkleHasher<D> {
fn default() -> Self {
Self::new()
}
}
impl<D: Digest> MrkleHasher<D> {
pub fn new() -> Self {
MrkleHasher::<D> {
phantom: core::marker::PhantomData,
}
}
pub fn digest<T: AsRef<[u8]>>(
input: T,
) -> crypto::common::generic_array::GenericArray<u8, <D as OutputSizeUser>::OutputSize> {
D::digest(input)
}
}
impl<D: Digest> Hasher for MrkleHasher<D> {
type Output = GenericArray<D>;
fn hash(&self, data: impl AsRef<[u8]>) -> Self::Output {
D::digest(data)
}
#[inline]
fn concat(&self, lhs: impl AsRef<[u8]>, rhs: impl AsRef<[u8]>) -> Self::Output {
let mut hasher = D::new();
hasher.update(lhs.as_ref());
hasher.update(rhs.as_ref());
hasher.finalize()
}
#[inline]
fn concat_slice<T: AsRef<[u8]>>(&self, data: &[T]) -> Self::Output {
let mut hasher = D::new();
for ptr in data {
hasher.update(ptr);
}
hasher.finalize()
}
}
#[cfg(test)]
mod test {
use crate::hasher::Hasher;
use super::MrkleHasher;
use crypto::digest::Digest;
use sha1::Sha1;
use sha2::Sha256;
use sha3::Keccak256;
#[test]
fn test_sha1_hasher() {
let hasher = MrkleHasher::<Sha1>::new();
let output = hasher.hash("hello world");
let expected = sha1::Sha1::digest("hello world");
assert_eq!(output, expected)
}
#[test]
fn test_sha2_hasher() {
let hasher = MrkleHasher::<Sha256>::new();
let output = hasher.hash("hello world");
let expected = sha2::Sha256::digest("hello world");
assert_eq!(output, expected)
}
#[test]
fn test_sha2_hasher_concat() {
let hasher = MrkleHasher::<Sha256>::new();
let output = hasher.concat("hello", "world");
let expected = sha2::Sha256::digest("helloworld");
assert_eq!(output, expected)
}
#[test]
fn test_sha2_hasher_twice() {
let hasher = MrkleHasher::<Sha256>::new();
let output = hasher.hash("hello world");
let expected = hasher.hash("hello world");
assert_eq!(output, expected)
}
#[test]
fn test_sha2_hasher_double_twice() {
let hasher = MrkleHasher::<Sha256>::new();
let output = hasher.hash(hasher.hash("hello world"));
let expected = sha2::Sha256::digest(sha2::Sha256::digest("hello world"));
assert_eq!(output, expected)
}
#[test]
fn test_generate_certificate() {
let hasher = MrkleHasher::<Sha256>::new();
assert!(hasher.certificate(true) == 0x00);
assert!(hasher.certificate(false) == 0x01)
}
#[test]
fn test_sha3_keccak() {
let plaintext = b"hello world";
let hasher = MrkleHasher::<Keccak256>::new();
let output = hasher.hash(plaintext);
let expected = Keccak256::digest(plaintext);
assert_eq!(output, expected)
}
#[test]
fn test_sha3_keccak_digest() {
let plaintext = b"hello world";
let output = MrkleHasher::<Keccak256>::digest(plaintext);
let expected = Keccak256::digest(plaintext);
assert_eq!(output, expected)
}
}