1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use crate::error::Error;
use core::fmt::Debug;

/// Size marker trait.

/// Stack allocated digest trait.
pub trait Digest<const S: usize>:
  AsRef<[u8]>
  + AsMut<[u8]>
  + From<[u8; S]>
  + Into<[u8; S]>
  + Clone
  + core::hash::Hash
  + Debug
  + Default
  + Eq
  + Send
  + Sync
  + 'static {
  /// Size of the digest. Maximum for Some of the Blake family is 2^64-1 bytes
  const SIZE: usize = S;

  /// Wraps the digest bytes.
  fn wrap(digest: &[u8]) -> Result<Self, Error> {
    if digest.len() != S {
      return Err(Error::InvalidSize(digest.len() as _));
    }
    let mut array = [0; S];
    let len = digest.len().min(array.len());
    array[..len].copy_from_slice(&digest[..len]);
    Ok(array.into())
  }

  /// Reads a multihash digest from a byte stream that contains the digest
  /// prefixed with the size.
  ///
  /// The byte stream must not contain the code as prefix.
  #[cfg(feature = "std")]
  fn from_reader<R>(mut r: R) -> Result<Self, Error>
  where R: std::io::Read {
    use unsigned_varint::io::read_u64;

    let size = read_u64(&mut r)?;
    if size > S as u64 || size > u8::max_value() as u64 {
      return Err(Error::InvalidSize(size));
    }
    let mut digest = [0; S];
    r.read_exact(&mut digest[..size as usize])?;
    Ok(Self::from(digest))
  }
}

/// Trait implemented by a hash function implementation.
pub trait StatefulHasher<const S: usize>: Default + Send + Sync {
  /// The maximum Digest size for that hasher (it is stack allocated).

  /// The Digest type to distinguish the output of different `Hasher`
  /// implementations.
  type Digest: Digest<S>;

  /// Consume input and update internal state.
  fn update(&mut self, input: &[u8]);

  /// Returns the final digest.
  fn finalize(&self) -> Self::Digest;

  /// Reset the internal hasher state.
  fn reset(&mut self);
}

/// Trait implemented by a hash function implementation.
///
/// It specifies its own Digest type, so that the output of the hash function
/// can later be distinguished. This way you can create a [`MultihashDigest`]
/// from a `Digest`.
///
/// Every hashing algorithm that is used with Multihash needs to implement
/// those. This trait is very similar to the external [`digest::Digest` trait].
/// There is a small significant difference, which needed the introduction of
/// this `Hasher` trait instead of re-using the widely used `digest::Digest`
/// trait.
///
/// The external `digest::Digest` trait has a single return type called
/// [`Output`], which is used for all hashers that implement it. It's basically
/// a wrapper around the hashed result bytes. For Multihashes we need to
/// distinguish those bytes, as we care about which hash function they
/// were created with (which is the whole point of [Multihashes]). Therefore the
/// [`Hasher`] trait defines an [associated type] [`Hasher::Digest`] for the
/// output of the hasher. This way the implementers can specify their own,
/// hasher specific type (which implements [`Digest`]) for their output.
///
/// [`digest::Digest` trait]: https://docs.rs/digest/0.9.0/digest/trait.Digest.html
/// [`Output`]: https://docs.rs/digest/0.9.0/digest/type.Output.html
/// [Multihashes]: https://github.com/multiformats/multihash
/// [associated type]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types
/// [`MultihashDigest`]: crate::MultihashDigest
pub trait Hasher<const S: usize>: Default + Send + Sync {
  /// The maximum Digest size for that hasher (it is stack allocated).

  /// The Digest type to distinguish the output of different `Hasher`
  /// implementations.
  type Digest: Digest<S>;

  /// the allocated size of the digest.
  const SIZE: usize = S;

  /// Hashes the given `input` data and returns its hash digest.
  fn digest(input: &[u8]) -> Self::Digest
  where Self: Sized;
}

impl<T: StatefulHasher<S>, const S: usize> Hasher<S> for T {
  type Digest = T::Digest;

  fn digest(input: &[u8]) -> Self::Digest {
    let mut hasher = Self::default();
    hasher.update(input);
    hasher.finalize()
  }
}