1use once_cell::sync::Lazy;
3
4pub trait HasherBase {
5 fn update<A: AsRef<[u8]>>(&mut self, data: A) -> &mut Self;
6}
7
8pub trait Hasher: HasherBase + Clone + Default {
9 fn finalize(self) -> crate::Hash;
10 fn reset(&mut self);
11 #[inline(always)]
12 fn hash<A: AsRef<[u8]>>(data: A) -> crate::Hash {
13 let mut hasher = Self::default();
14 hasher.update(data);
15 hasher.finalize()
16 }
17}
18
19pub use crate::pow_hashers::{KHeavyHash, PowHash};
23blake2b_hasher! {
24 struct TransactionHash => b"TransactionHash",
25 struct TransactionID => b"TransactionID",
26 struct TransactionSigningHash => b"TransactionSigningHash",
27 struct BlockHash => b"BlockHash",
28 struct ProofOfWorkHash => b"ProofOfWorkHash",
29 struct MerkleBranchHash => b"MerkleBranchHash",
30 struct MuHashElementHash => b"MuHashElement",
31 struct MuHashFinalizeHash => b"MuHashFinalize",
32 struct PersonalMessageSigningHash => b"PersonalMessageSigningHash",
33}
34
35sha256_hasher! {
36 struct TransactionSigningHashECDSA => "TransactionSigningHashECDSA",
37}
38
39macro_rules! sha256_hasher {
40 ($(struct $name:ident => $domain_sep:literal),+ $(,)? ) => {$(
41 #[derive(Clone)]
42 pub struct $name(sha2::Sha256);
43
44 impl $name {
45 #[inline]
46 pub fn new() -> Self {
47 use sha2::{Sha256, Digest};
48 static HASHER: Lazy<$name> = Lazy::new(|| {
51 let mut tmp_state = Sha256::new();
53 tmp_state.update($domain_sep);
54 let mut out = $name(Sha256::new());
55 out.write(tmp_state.finalize());
56
57 out
58 });
59 (*HASHER).clone()
60 }
61
62 pub fn write<A: AsRef<[u8]>>(&mut self, data: A) {
63 sha2::Digest::update(&mut self.0, data.as_ref());
64 }
65
66 #[inline(always)]
67 pub fn finalize(self) -> crate::Hash {
68 let mut out = [0u8; 32];
69 out.copy_from_slice(sha2::Digest::finalize(self.0).as_slice());
70 crate::Hash(out)
71 }
72 }
73 impl_hasher!{ struct $name }
74 )*};
75}
76
77macro_rules! blake2b_hasher {
78 ($(struct $name:ident => $domain_sep:literal),+ $(,)? ) => {$(
79 #[derive(Clone)]
80 pub struct $name(blake2b_simd::State);
81
82 impl $name {
83 #[inline(always)]
84 pub fn new() -> Self {
85 Self(
86 blake2b_simd::Params::new()
87 .hash_length(32)
88 .key($domain_sep)
89 .to_state(),
90 )
91 }
92
93 pub fn write<A: AsRef<[u8]>>(&mut self, data: A) {
94 self.0.update(data.as_ref());
95 }
96
97 #[inline(always)]
98 pub fn finalize(self) -> crate::Hash {
99 let mut out = [0u8; 32];
100 out.copy_from_slice(self.0.finalize().as_bytes());
101 crate::Hash(out)
102 }
103 }
104 impl_hasher!{ struct $name }
105 )*};
106}
107macro_rules! impl_hasher {
108 (struct $name:ident) => {
109 impl HasherBase for $name {
110 #[inline(always)]
111 fn update<A: AsRef<[u8]>>(&mut self, data: A) -> &mut Self {
112 self.write(data);
113 self
114 }
115 }
116 impl Hasher for $name {
117 #[inline(always)]
118 fn finalize(self) -> crate::Hash {
119 $name::finalize(self)
121 }
122 #[inline(always)]
123 fn reset(&mut self) {
124 *self = Self::new();
125 }
126 }
127 impl Default for $name {
128 #[inline(always)]
129 fn default() -> Self {
130 Self::new()
131 }
132 }
133 };
134}
135
136use {blake2b_hasher, impl_hasher, sha256_hasher};
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn test_vectors() {
144 let input_data = [
145 &[],
146 &[1][..],
147 &[
148 5, 199, 126, 44, 71, 32, 82, 139, 122, 217, 43, 48, 52, 112, 40, 209, 180, 83, 139, 231, 72, 48, 136, 48, 168, 226,
149 133, 7, 60, 4, 160, 205,
150 ][..],
151 &[42; 64],
152 &[0; 8][..],
153 ];
154
155 fn run_test_vector<H: Hasher>(input_data: &[&[u8]], hasher_new: impl FnOnce() -> H, expected: &[&str]) {
156 let mut hasher = hasher_new();
157 for (data, expected) in input_data.iter().zip(expected) {
159 println!("data: {data:?}");
160 let hash = hasher.update(data).clone().finalize();
161 assert_eq!(hash.to_string(), *expected, "Type: {}", std::any::type_name::<H>());
162 }
163 }
164
165 run_test_vector(
166 &input_data,
167 TransactionHash::new,
168 &[
169 "50272a9e37c728026f93d0eda6ab4467f627338b879076483c88d291193cb3bf",
170 "f9bf7e04c712621a0f4bb75d763f9ef5f73af6c438fd15b80744393bc96398ad",
171 "8e791f3edcc92b71b8de2778efbc4666ee5bd146acbe8723a55bca26b022b0e0",
172 "a6dab1a3088548c62d13a082fa28e870fdbbe51adcd8c364e2ea37e473c04d81",
173 "3b79b78b967233843ad30f707b165eb3d6a91af8338076be8755c46a963c3d1d",
174 ],
175 );
176 run_test_vector(
177 &input_data,
178 TransactionID::new,
179 &[
180 "e5f65efda0894d2b0590c2e9e46e9acc03032f505a1522f5e8c78c5ec70b1d9c",
181 "aea52cf5e5a13da13a52dd69abd636eb1b0f86e58bc1dda6b17886b94593415a",
182 "a50a2f87bdce075740189e9e23907ae22b5addbd875ccb70c116811b1fa5fb18",
183 "0db7a485f7013a346a8f7f5caf73d52ca3c3b5ee101ad8753adedd4235b7236b",
184 "2afc9c855854b0a6e94a722c3451d0cdfc8c11748b78ef65b9786f87b48d0d07",
185 ],
186 );
187
188 run_test_vector(
189 &input_data,
190 TransactionSigningHash::new,
191 &[
192 "34c75037ad62740d4b3228f88f844f7901c07bfacd55a045be518eabc15e52ce",
193 "8523b0471bcbea04575ccaa635eef9f9114f2890bda54367e5ff8caa3878bf82",
194 "a51c49d9eb3d13f9de16e1aa8d1ff17668d55633ce00f36a643ac714b0fb137f",
195 "487f199ef74c3e893e85bd37770e6334575a2d4d113b2e10474593c49807de93",
196 "6392adc33a8e24e9a0a0c4c5f07f9c1cc958ad40c16d7a9a276e374cebb4e32b",
197 ],
198 );
199 run_test_vector(
200 &input_data,
201 TransactionSigningHashECDSA::new,
202 &[
203 "b31ad1fbbe41b0e2a90e07c84708b38ba581f0c0e9185416913a04fb6d342027",
204 "c43e1f75ea9df6379b56a95074c2b6289ed8c5a01fff2d49d9d44ad5575c164b",
205 "49085f99fa0084b5436663f757a5916b1e4290c3321707fb76921ed4e47844ec",
206 "3f887e866428de813c1d0463b14eef3ca1363c8187e917dda1eee0ec5996490b",
207 "56de89a8c75f0fee2de61b11ab05d0d42e29ed50879467cf128dd80800a52ada",
208 ],
209 );
210
211 run_test_vector(
212 &input_data,
213 BlockHash::new,
214 &[
215 "a80b6aa20f20b15ebabe2b1949527f78a257594a732e774de637d85e6973a768",
216 "5643023add641f9421187b8c9aa3c6c73227d5ec34131c61a08d35b43e7e4b65",
217 "4dc3bf72045431e46f8839a7d390898f27c887fddd8637149bfb70f732f04334",
218 "15d7648e69023dca65c949a61ea166192049f449c604523494813873b19918a7",
219 "3ac41af8385ea5d902ce6d47f509b7accc9c631f1d57a719d777874467f6d877",
220 ],
221 );
222
223 run_test_vector(
224 &input_data,
225 MerkleBranchHash::new,
226 &[
227 "4de3617db456d01248173f17ec58196e92fbd994b636476db4b875ed2ec84054",
228 "5737cd8b6fca5a30c19a491323a14e6b7021641cb3f8875f10c7a2eafd3cf43f",
229 "a49eeda61cc75e0a8e5915829752fe0ad97620d6d32de7c9883595b0810ca33e",
230 "28f33681dcff1313674e07dacc2d74c3089f6d8cea7a4f8792a71fd870988ee5",
231 "2d53a43a42020a5091c125230bcd8a4cf0eeb188333e68325d4bce58a1c75ca3",
232 ],
233 );
234 }
235}