use std::fmt;
use digest::{generic_array::GenericArray, typenum};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use super::encoding::{Base64, Encoding};
#[serde_as]
#[derive(Hash, PartialEq, Eq, Clone, Serialize, Deserialize, Ord, PartialOrd, Copy)]
pub struct Digest<const DIGEST_LEN: usize> {
#[serde_as(as = "[_; DIGEST_LEN]")]
pub digest: [u8; DIGEST_LEN],
}
impl<const DIGEST_LEN: usize> Digest<DIGEST_LEN> {
pub fn new(digest: [u8; DIGEST_LEN]) -> Self {
Digest { digest }
}
pub fn size(&self) -> usize {
DIGEST_LEN
}
}
impl<const DIGEST_LEN: usize> fmt::Debug for Digest<DIGEST_LEN> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", Base64::encode(self.digest))
}
}
impl<const DIGEST_LEN: usize> fmt::Display for Digest<DIGEST_LEN> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", Base64::encode(self.digest))
}
}
impl<const DIGEST_LEN: usize> AsRef<[u8]> for Digest<DIGEST_LEN> {
fn as_ref(&self) -> &[u8] {
self.digest.as_ref()
}
}
impl<const DIGEST_LEN: usize> From<Digest<DIGEST_LEN>> for [u8; DIGEST_LEN] {
fn from(digest: Digest<DIGEST_LEN>) -> Self {
digest.digest
}
}
pub trait HashFunction<const DIGEST_LENGTH: usize>: Default {
const OUTPUT_SIZE: usize = DIGEST_LENGTH;
fn new() -> Self {
Self::default()
}
fn update<Data: AsRef<[u8]>>(&mut self, data: Data);
fn finalize(self) -> Digest<DIGEST_LENGTH>;
fn digest<Data: AsRef<[u8]>>(data: Data) -> Digest<DIGEST_LENGTH> {
let mut h = Self::default();
h.update(data);
h.finalize()
}
fn digest_iterator<K: AsRef<[u8]>, I: Iterator<Item = K>>(iter: I) -> Digest<DIGEST_LENGTH> {
let mut h = Self::default();
iter.for_each(|item| h.update(item));
h.finalize()
}
}
pub trait Hash<const DIGEST_LEN: usize> {
type TypedDigest: Into<Digest<DIGEST_LEN>> + Eq + std::hash::Hash + Copy + fmt::Debug;
fn digest(&self) -> Self::TypedDigest;
}
#[derive(Default)]
pub struct HashFunctionWrapper<Variant, const DIGEST_LEN: usize>(Variant);
impl<Variant: digest::Digest + Default, const DIGEST_LEN: usize> HashFunction<DIGEST_LEN>
for HashFunctionWrapper<Variant, DIGEST_LEN>
{
fn update<Data: AsRef<[u8]>>(&mut self, data: Data) {
self.0.update(data);
}
fn finalize(self) -> Digest<DIGEST_LEN> {
let mut digest = [0u8; DIGEST_LEN];
self.0.finalize_into(GenericArray::from_mut_slice(&mut digest));
Digest { digest }
}
}
impl<Variant: digest::Digest + Default, const DIGEST_LEN: usize> std::io::Write
for HashFunctionWrapper<Variant, DIGEST_LEN>
{
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.update(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
pub type Blake2b256 = HashFunctionWrapper<blake2::Blake2b<typenum::U32>, 32>;