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}