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