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}