1use std::{marker::PhantomData, mem::MaybeUninit};
4
5pub trait HashDigest<T> {
10 type Digest;
12 fn hash(data: impl AsRef<[T]>) -> Self::Digest;
13}
14
15pub struct HasherDigest<T, H: Hasher<T>> {
17 _t_marker: PhantomData<T>,
18 _h_marker: PhantomData<H>,
19}
20
21impl<T, H: Hasher<T>> HashDigest<T> for HasherDigest<T, H> {
22 type Digest = <H as Hasher<T>>::Digest;
23
24 fn hash(data: impl AsRef<[T]>) -> Self::Digest {
25 hasher_hash::<T, H>(data)
26 }
27}
28
29pub struct FixedLenHasherDigest<T, H: FixedLenHasher<T>> {
31 _t_marker: PhantomData<T>,
32 _h_marker: PhantomData<H>,
33}
34
35impl<T, H: FixedLenHasher<T>> HashDigest<T> for FixedLenHasherDigest<T, H> {
36 type Digest = <H as FixedLenHasher<T>>::Digest;
37
38 fn hash(data: impl AsRef<[T]>) -> Self::Digest {
39 fixed_len_hash::<T, H>(data)
40 }
41}
42
43pub trait Hasher<T>: Sync + Send {
49 type Digest;
51
52 fn new() -> Self;
53 fn update(&mut self, data: impl AsRef<[T]>);
54 fn chain_update(self, data: impl AsRef<[T]>) -> Self;
55 fn finalize(self) -> Self::Digest;
56 fn finalize_into(self, out: &mut MaybeUninit<Self::Digest>);
57
58 fn finalize_reset(&mut self) -> Self::Digest;
59 fn finalize_into_reset(&mut self, out: &mut MaybeUninit<Self::Digest>);
60 fn reset(&mut self);
61}
62
63#[derive(Debug, thiserror::Error)]
64pub enum HashError {
65 #[error("Not enough data to finalize hash (expected {committed} elements, hashed {hashed} elements)")]
66 NotEnoughData { committed: u64, hashed: u64 },
67 #[error("Too much data to hash (expected {committed} elements, received {received} elements)")]
68 TooMuchData { committed: u64, received: u64 },
69}
70
71pub trait FixedLenHasher<T>
82where
83 Self: Sized,
84{
85 type Digest;
87
88 fn new(msg_len: u64) -> Self;
92 fn update(&mut self, data: impl AsRef<[T]>);
93 fn chain_update(self, data: impl AsRef<[T]>) -> Self;
94 fn finalize(self) -> Result<Self::Digest, HashError>;
95
96 fn reset(&mut self);
98}
99
100pub fn hasher_hash<T, H: Hasher<T>>(data: impl AsRef<[T]>) -> H::Digest {
101 H::new().chain_update(data).finalize()
102}
103
104pub fn fixed_len_hash<T, H: FixedLenHasher<T>>(data: impl AsRef<[T]>) -> H::Digest {
105 H::new(data.as_ref().len() as u64)
106 .chain_update(data)
107 .finalize()
108 .unwrap()
109}