use cryptoxide::blake2b::Blake2b;
use cryptoxide::digest::Digest;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[cfg_attr(feature = "fuzzing", derive(fuzzcheck::DefaultMutator))]
#[derive(Serialize, Deserialize, Error, Debug, PartialEq, Clone, Copy)]
pub enum Blake2bError {
#[error("Output digest length must be between 16 and 64 bytes.")]
InvalidLength,
#[error("Blake2b failed")]
Other,
}
impl From<()> for Blake2bError {
fn from(_: ()) -> Self {
Self::Other
}
}
pub fn digest_256(data: &[u8]) -> Result<Vec<u8>, Blake2bError> {
digest(data, 32)
}
pub fn digest_160(data: &[u8]) -> Result<Vec<u8>, Blake2bError> {
digest(data, 20)
}
pub fn digest_128(data: &[u8]) -> Result<Vec<u8>, Blake2bError> {
digest(data, 16)
}
pub fn digest(data: &[u8], out_len: usize) -> Result<Vec<u8>, Blake2bError> {
if !(16..=64).contains(&out_len) {
return Err(Blake2bError::InvalidLength);
}
let mut hasher = Blake2b::new(out_len);
hasher.input(data);
let mut result = vec![0; hasher.output_bytes()];
hasher.result(result.as_mut_slice());
Ok(result)
}
pub fn digest_all<T, I>(data: T, out_len: usize) -> Result<Vec<u8>, Blake2bError>
where
T: IntoIterator<Item = I>,
I: AsRef<[u8]>,
{
if !(16..=64).contains(&out_len) {
return Err(Blake2bError::InvalidLength);
}
let mut hasher = Blake2b::new(out_len);
for d in data.into_iter() {
hasher.input(d.as_ref());
}
let mut result = vec![0; hasher.output_bytes()];
hasher.result(result.as_mut_slice());
Ok(result)
}
pub fn merkle_tree<Leaf>(list: &[Leaf]) -> Result<Vec<u8>, Blake2bError>
where
Leaf: AsRef<Vec<u8>>,
{
use std::ops::{Index, RangeFrom, RangeTo};
struct RepeatingSlice<'a, Leaf>(pub &'a [Leaf]);
impl<'a, Leaf> Index<usize> for RepeatingSlice<'a, Leaf> {
type Output = Leaf;
fn index(&self, index: usize) -> &Self::Output {
if self.0.is_empty() {
panic!();
} else if index < self.0.len() {
self.0.index(index)
} else {
self.0.last().unwrap()
}
}
}
impl<'a, Leaf> Index<RangeFrom<usize>> for RepeatingSlice<'a, Leaf> {
type Output = [Leaf];
fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
if self.0.is_empty() {
panic!();
} else if index.start < self.0.len() {
&self.0[index]
} else {
&self.0[(self.0.len() - 1)..]
}
}
}
impl<'a, Leaf> Index<RangeTo<usize>> for RepeatingSlice<'a, Leaf> {
type Output = [Leaf];
fn index(&self, index: RangeTo<usize>) -> &Self::Output {
if self.0.is_empty() {
panic!();
} else if index.end <= self.0.len() {
&self.0[index]
} else {
&self.0[..self.0.len()]
}
}
}
fn merkle_tree_inner<Leaf>(
list: &RepeatingSlice<Leaf>,
degree: u32,
) -> Result<Vec<u8>, Blake2bError>
where
Leaf: AsRef<Vec<u8>>,
{
match degree {
0 => digest_256(list[0].as_ref()),
d => {
let middle = 1 << (d - 1);
digest_all(
&[
merkle_tree_inner(&RepeatingSlice(&list[..middle]), d - 1)?,
merkle_tree_inner(&RepeatingSlice(&list[middle..]), d - 1)?,
],
32,
)
}
}
}
if list.is_empty() {
digest_256(&[])
} else {
merkle_tree_inner(&RepeatingSlice(list), 64 - (list.len() - 1).leading_zeros())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn blake2b_256() {
let hash = digest_256(b"hello world").unwrap();
let expected =
hex::decode("256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610")
.unwrap();
assert_eq!(expected, hash)
}
#[test]
fn blake2b_128() {
let hash = digest_128(b"hello world").unwrap();
let expected = hex::decode("e9a804b2e527fd3601d2ffc0bb023cd6").unwrap();
assert_eq!(expected, hash);
}
#[test]
fn blake2b_less_than_128() {
assert!(digest(b"hello world", 15).is_err())
}
#[test]
fn blake2b_more_than_512() {
assert!(digest(b"hello world", 65).is_err())
}
#[test]
fn blake2b_digest() {
let hash = digest(b"hello world", 32).unwrap();
assert_eq!(
hash,
hex::decode("256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610")
.unwrap()
);
}
#[test]
fn blake2b_digest_all() {
let hash = digest_all(&["hello", " ", "world"], 32).unwrap();
assert_eq!(
hash,
hex::decode("256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610")
.unwrap()
);
}
}