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}