pallas_crypto/hash/
hasher.rs

1use crate::hash::Hash;
2use cryptoxide::blake2b::Blake2b;
3use pallas_codec::minicbor;
4
5/// handy method to create a hash of given `SIZE` bit size.
6///
7/// The hash algorithm is `Blake2b` and the constant parameter is
8/// the number of bits to generate. Good values are `256` or `224` for
9/// Cardano.
10///
11/// # Generate a cryptographic hash with Blake2b 256
12///
13/// The following will generate a 32 bytes digest output
14///
15/// ```
16/// # use pallas_crypto::hash::Hasher;
17///
18/// let mut hasher = Hasher::<256>::new();
19/// hasher.input(b"My transaction");
20///
21/// let digest = hasher.finalize();
22/// # assert_eq!(
23/// #   "0d8d00cdd4657ac84d82f0a56067634a7adfdf43da41cb534bcaa45060973d21",
24/// #   hex::encode(digest)
25/// # );
26/// ```
27///
28/// # Generate a cryptographic hash with Blake2b 224
29///
30/// The following will generate a 28 bytes digest output. This is used
31/// to generate the hash of public keys for addresses.
32///
33/// ```
34/// # use pallas_crypto::hash::Hasher;
35///
36/// let digest = Hasher::<224>::hash(b"My Public Key");
37/// # assert_eq!(
38/// #   "c123c9bc0e9e31a20a4aa23518836ec5fb54bdc85735c56b38eb79a5",
39/// #   hex::encode(digest)
40/// # );
41/// ```
42pub struct Hasher<const BITS: usize>(Blake2b);
43
44impl<const BITS: usize> Hasher<BITS> {
45    /// update the [`Hasher`] with the given inputs
46    #[inline]
47    pub fn input(&mut self, bytes: &[u8]) {
48        use cryptoxide::digest::Digest as _;
49        self.0.input(bytes);
50    }
51}
52
53macro_rules! common_hasher {
54    ($size:literal) => {
55        impl Hasher<$size> {
56            /// create a new [`Hasher`]
57            #[inline]
58            pub fn new() -> Self {
59                Self(Blake2b::new($size / 8))
60            }
61
62            /// convenient function to directly generate the hash
63            /// of the given bytes without creating the intermediary
64            /// types [`Hasher`] and calling [`Hasher::input`].
65            #[inline]
66            pub fn hash(bytes: &[u8]) -> Hash<{ $size / 8 }> {
67                let mut hasher = Self::new();
68                hasher.input(bytes);
69                hasher.finalize()
70            }
71
72            #[inline]
73            pub fn hash_tagged(bytes: &[u8], tag: u8) -> Hash<{ $size / 8 }> {
74                let mut hasher = Self::new();
75                hasher.input(&[tag]);
76                hasher.input(bytes);
77                hasher.finalize()
78            }
79
80            /// convenient function to directly generate the hash
81            /// of the given [minicbor::Encode] data object
82            #[inline]
83            pub fn hash_cbor(data: &impl minicbor::Encode<()>) -> Hash<{ $size / 8 }> {
84                let mut hasher = Self::new();
85                let () = minicbor::encode(data, &mut hasher).expect("Infallible");
86                hasher.finalize()
87            }
88
89            #[inline]
90            pub fn hash_tagged_cbor(
91                data: &impl minicbor::Encode<()>,
92                tag: u8,
93            ) -> Hash<{ $size / 8 }> {
94                let mut hasher = Self::new();
95                hasher.input(&[tag]);
96                let () = minicbor::encode(data, &mut hasher).expect("Infallible");
97                hasher.finalize()
98            }
99
100            /// consume the [`Hasher`] and returns the computed digest
101            pub fn finalize(mut self) -> Hash<{ $size / 8 }> {
102                use cryptoxide::digest::Digest as _;
103                let mut hash = [0; $size / 8];
104                self.0.result(&mut hash);
105                Hash::new(hash)
106            }
107        }
108
109        impl Default for Hasher<$size> {
110            fn default() -> Self {
111                Self::new()
112            }
113        }
114    };
115}
116
117common_hasher!(160);
118common_hasher!(224);
119common_hasher!(256);
120
121/*
122TODO: somehow the `minicbor::Write` does not allow to implement this
123      version of the trait and to automatically have the impl of the
124      other one automatically derived by default.
125
126impl<const BITS: usize> Write for Hasher<BITS> {
127    type Error = std::convert::Infallible;
128
129    #[inline]
130    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
131        self.input(buf);
132        Ok(())
133    }
134}
135*/
136
137impl<const BITS: usize> minicbor::encode::Write for &mut Hasher<BITS> {
138    type Error = std::convert::Infallible;
139
140    #[inline]
141    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
142        self.input(buf);
143        Ok(())
144    }
145}