tiny_multihash/
hasher.rs

1use crate::error::Error;
2use core::fmt::Debug;
3use generic_array::typenum::marker_traits::Unsigned;
4use generic_array::{ArrayLength, GenericArray};
5
6/// Size marker trait.
7pub trait Size:
8    ArrayLength<u8> + Debug + Default + Eq + core::hash::Hash + Send + Sync + 'static
9{
10}
11
12impl<T: ArrayLength<u8> + Debug + Default + Eq + core::hash::Hash + Send + Sync + 'static> Size
13    for T
14{
15}
16
17/// Stack allocated digest trait.
18pub trait Digest<S: Size>:
19    AsRef<[u8]>
20    + AsMut<[u8]>
21    + From<GenericArray<u8, S>>
22    + Into<GenericArray<u8, S>>
23    + Clone
24    + core::hash::Hash
25    + Debug
26    + Default
27    + Eq
28    + Send
29    + Sync
30    + 'static
31{
32    /// Size of the digest.
33    fn size(&self) -> u8 {
34        S::to_u8()
35    }
36
37    /// Wraps the digest bytes.
38    fn wrap(digest: &[u8]) -> Result<Self, Error> {
39        if digest.len() != S::to_usize() {
40            return Err(Error::InvalidSize(digest.len() as _));
41        }
42        let mut array = GenericArray::default();
43        let len = digest.len().min(array.len());
44        array[..len].copy_from_slice(&digest[..len]);
45        Ok(array.into())
46    }
47
48    /// Reads a multihash digest from a byte stream that contains the digest prefixed with the size.
49    ///
50    /// The byte stream must not contain the code as prefix.
51    #[cfg(feature = "std")]
52    fn from_reader<R>(mut r: R) -> Result<Self, Error>
53    where
54        R: std::io::Read,
55    {
56        use unsigned_varint::io::read_u64;
57
58        let size = read_u64(&mut r)?;
59        if size > S::to_u64() || size > u8::max_value() as u64 {
60            return Err(Error::InvalidSize(size));
61        }
62        let mut digest = GenericArray::default();
63        r.read_exact(&mut digest[..size as usize])?;
64        Ok(Self::from(digest))
65    }
66}
67
68/// Trait implemented by a hash function implementation.
69pub trait StatefulHasher: Default + Send + Sync {
70    /// The maximum Digest size for that hasher (it is stack allocated).
71    type Size: Size;
72
73    /// The Digest type to distinguish the output of different `Hasher` implementations.
74    type Digest: Digest<Self::Size>;
75
76    /// Consume input and update internal state.
77    fn update(&mut self, input: &[u8]);
78
79    /// Returns the final digest.
80    fn finalize(&self) -> Self::Digest;
81
82    /// Reset the internal hasher state.
83    fn reset(&mut self);
84}
85
86/// Trait implemented by a hash function implementation.
87///
88/// It specifies its own Digest type, so that the output of the hash function can later be
89/// distinguished. This way you can create a [`MultihashDigest`] from a `Digest`.
90///
91/// Every hashing algorithm that is used with Multihash needs to implement those. This trait is
92/// very similar to the external [`digest::Digest` trait]. There is a small significant
93/// difference, which needed the introduction of this `Hasher` trait instead of re-using the
94/// widely used `digest::Digest` trait.
95///
96/// The external `digest::Digest` trait has a single return type called [`Output`], which is used
97/// for all hashers that implement it. It's basically a wrapper around the hashed result bytes.
98/// For Multihashes we need to distinguish those bytes, as we care about which hash function they
99/// were created with (which is the whole point of [Multihashes]). Therefore the [`Hasher`] trait
100/// defines an [associated type] [`Hasher::Digest`] for the output of the hasher. This way the
101/// implementers can specify their own, hasher specific type (which implements [`Digest`]) for
102/// their output.
103///
104/// [`digest::Digest` trait]: https://docs.rs/digest/0.9.0/digest/trait.Digest.html
105/// [`Output`]: https://docs.rs/digest/0.9.0/digest/type.Output.html
106/// [Multihashes]: https://github.com/multiformats/multihash
107/// [associated type]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types
108/// [`MultihashDigest`]: crate::MultihashDigest
109pub trait Hasher: Default + Send + Sync {
110    /// The maximum Digest size for that hasher (it is stack allocated).
111    type Size: Size;
112
113    /// The Digest type to distinguish the output of different `Hasher` implementations.
114    type Digest: Digest<Self::Size>;
115
116    /// Returns the allocated size of the digest.
117    fn size() -> u8 {
118        Self::Size::to_u8()
119    }
120
121    /// Hashes the given `input` data and returns its hash digest.
122    fn digest(input: &[u8]) -> Self::Digest
123    where
124        Self: Sized;
125}
126
127impl<T: StatefulHasher> Hasher for T {
128    type Size = T::Size;
129    type Digest = T::Digest;
130
131    fn digest(input: &[u8]) -> Self::Digest {
132        let mut hasher = Self::default();
133        hasher.update(input);
134        hasher.finalize()
135    }
136}
137
138/// New type wrapper for a hasher that implements the `std::io::Write` trait.
139#[cfg(feature = "std")]
140pub struct WriteHasher<H: Hasher>(H);
141
142#[cfg(feature = "std")]
143impl<H: StatefulHasher> std::io::Write for WriteHasher<H> {
144    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
145        self.0.update(buf);
146        Ok(buf.len())
147    }
148
149    fn flush(&mut self) -> std::io::Result<()> {
150        Ok(())
151    }
152}