1pub trait HasherBase {
4 fn update<A: AsRef<[u8]>>(&mut self, data: A) -> &mut Self;
5}
6
7pub trait Hasher: HasherBase + Clone + Default {
8 fn finalize(self) -> crate::Hash;
9 fn reset(&mut self);
10 #[inline(always)]
11 fn hash<A: AsRef<[u8]>>(data: A) -> crate::Hash {
12 let mut hasher = Self::default();
13 hasher.update(data);
14 hasher.finalize()
15 }
16}
17
18pub use crate::pow_hashers::{KHeavyHash, PowHash};
22blake2b_hasher! {
23 struct TransactionHash => b"TransactionHash",
24 struct TransactionID => b"TransactionID",
25 struct TransactionSigningHash => b"TransactionSigningHash",
26 struct BlockHash => b"BlockHash",
27 struct ProofOfWorkHash => b"ProofOfWorkHash",
28 struct MerkleBranchHash => b"MerkleBranchHash",
29 struct MuHashElementHash => b"MuHashElement",
30 struct MuHashFinalizeHash => b"MuHashFinalize",
31 struct PersonalMessageSigningHash => b"PersonalMessageSigningHash",
32 struct CovenantID => b"CovenantID",
33}
34
35sha256_hasher! {
36 struct TransactionSigningHashECDSA => b"TransactionSigningHashECDSA",
37}
38
39blake3_hasher! {
40 struct SeqCommitMerkleBranch => b"SeqCommitmentMerkleBranchHash",
41 struct PayloadDigest => b"PayloadDigest",
42 struct TransactionRest => b"TransactionRest",
43 struct TransactionV1Id => b"TransactionV1Id",
44 struct SeqCommitLaneKey => b"SeqCommitLaneKey",
45 struct SeqCommitLaneTip => b"SeqCommitLaneTip",
46 struct SeqCommitActivityLeaf => b"SeqCommitActivityLeaf",
47 struct SeqCommitMergesetContext => b"SeqCommitMergesetContext",
48 struct SeqCommitMinerPayloadLeaf => b"SeqCommitMinerPayloadLeaf",
49 struct SeqCommitActivityRoot => b"SeqCommitActivityRoot",
50
51 struct SeqCommitActiveLeaf => b"SeqCommitActiveLeaf",
52 struct SeqCommitActiveNode => b"SeqCommitActiveNode",
53 struct SeqCommitActiveCollapsedNode => b"SeqCommitActiveCollapsedNode",
54}
55
56#[macro_export]
57macro_rules! sha256_hasher {
58 ($(struct $name:ident => $domain_sep:literal),+ $(,)? ) => {$(
59 #[derive(Clone)]
60 pub struct $name($crate::sha2::Sha256);
61
62 impl $name {
63 #[inline]
64 pub fn new() -> Self {
65 use $crate::sha2::{Digest as _};
66 const DOMAIN_HASH: [u8; 32] = {
67 $crate::sha2_const_stable::Sha256::new().update($domain_sep).finalize()
68 };
69 Self($crate::sha2::Sha256::new_with_prefix(DOMAIN_HASH))
70 }
71
72 pub fn write<A: AsRef<[u8]>>(&mut self, data: A) {
73 $crate::sha2::Digest::update(&mut self.0, data.as_ref());
74 }
75
76 #[inline(always)]
77 pub fn finalize(self) -> $crate::Hash {
78 let mut out = [0u8; 32];
79 out.copy_from_slice($crate::sha2::Digest::finalize(self.0).as_slice());
80 $crate::Hash::from_bytes(out)
81 }
82 }
83 $crate::impl_hasher!{ struct $name }
84 )*};
85}
86
87#[macro_export]
88macro_rules! blake2b_hasher {
89 ($(struct $name:ident => $domain_sep:literal),+ $(,)? ) => {$(
90 #[derive(Clone)]
91 pub struct $name($crate::blake2b_simd::State);
92
93 impl $name {
94 #[inline(always)]
95 pub fn new() -> Self {
96 Self(
97 $crate::blake2b_simd::Params::new()
98 .hash_length(32)
99 .key($domain_sep)
100 .to_state(),
101 )
102 }
103
104 pub fn write<A: AsRef<[u8]>>(&mut self, data: A) {
105 self.0.update(data.as_ref());
106 }
107
108 #[inline(always)]
109 pub fn finalize(self) -> $crate::Hash {
110 let mut out = [0u8; 32];
111 out.copy_from_slice(self.0.finalize().as_bytes());
112 $crate::Hash::from_bytes(out)
113 }
114 }
115 $crate::impl_hasher!{ struct $name }
116 )*};
117}
118
119#[macro_export]
120macro_rules! blake3_hasher {
121 ($(struct $name:ident => $domain_sep:literal),+ $(,)? ) => {$(
122 #[derive(Clone)]
123 pub struct $name($crate::blake3::Hasher);
124
125 impl $name {
126 #[inline(always)]
127 pub fn new() -> Self {
128 const KEY: [u8; $crate::blake3::KEY_LEN] = {
129 let mut key = [0u8; $crate::blake3::KEY_LEN];
130 let mut i = 0usize;
131 while i < $domain_sep.len() {
132 key[i] = $domain_sep[i];
133 i += 1;
134 }
135 key
136 };
137
138 Self($crate::blake3::Hasher::new_keyed(&KEY))
139 }
140
141 pub fn write<A: AsRef<[u8]>>(&mut self, data: A) {
142 self.0.update(data.as_ref());
143 }
144
145 #[inline(always)]
146 pub fn finalize(self) -> $crate::Hash {
147 let mut out = [0u8; 32];
148 out.copy_from_slice(self.0.finalize().as_bytes());
149 $crate::Hash::from_bytes(out)
150 }
151 }
152 $crate::impl_hasher!{ struct $name }
153 )*};
154}
155
156#[macro_export]
157macro_rules! impl_hasher {
158 (struct $name:ident) => {
159 impl $crate::HasherBase for $name {
160 #[inline(always)]
161 fn update<A: AsRef<[u8]>>(&mut self, data: A) -> &mut Self {
162 self.write(data);
163 self
164 }
165 }
166 impl $crate::Hasher for $name {
167 #[inline(always)]
168 fn finalize(self) -> $crate::Hash {
169 $name::finalize(self)
171 }
172 #[inline(always)]
173 fn reset(&mut self) {
174 *self = Self::new();
175 }
176 }
177 impl Default for $name {
178 #[inline(always)]
179 fn default() -> Self {
180 Self::new()
181 }
182 }
183 };
184}
185
186use {blake2b_hasher, blake3_hasher, sha256_hasher};
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use std::println;
192 use std::string::ToString;
193
194 fn run_test_vector<H: Hasher>(input_data: &[&[u8]], hasher_new: impl FnOnce() -> H, expected: &[&str]) {
195 let mut hasher = hasher_new();
196 for (data, expected) in input_data.iter().zip(expected) {
198 println!("data: {data:?}");
199 let hash = hasher.update(data).clone().finalize();
200 assert_eq!(hash.to_string(), *expected, "Type: {}", std::any::type_name::<H>());
201 }
202 }
203
204 #[test]
205 fn test_vectors() {
206 let input_data = [
207 &[],
208 &[1][..],
209 &[
210 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,
211 133, 7, 60, 4, 160, 205,
212 ][..],
213 &[42; 64],
214 &[0; 8][..],
215 ];
216
217 run_test_vector(
218 &input_data,
219 TransactionHash::new,
220 &[
221 "50272a9e37c728026f93d0eda6ab4467f627338b879076483c88d291193cb3bf",
222 "f9bf7e04c712621a0f4bb75d763f9ef5f73af6c438fd15b80744393bc96398ad",
223 "8e791f3edcc92b71b8de2778efbc4666ee5bd146acbe8723a55bca26b022b0e0",
224 "a6dab1a3088548c62d13a082fa28e870fdbbe51adcd8c364e2ea37e473c04d81",
225 "3b79b78b967233843ad30f707b165eb3d6a91af8338076be8755c46a963c3d1d",
226 ],
227 );
228 run_test_vector(
229 &input_data,
230 TransactionID::new,
231 &[
232 "e5f65efda0894d2b0590c2e9e46e9acc03032f505a1522f5e8c78c5ec70b1d9c",
233 "aea52cf5e5a13da13a52dd69abd636eb1b0f86e58bc1dda6b17886b94593415a",
234 "a50a2f87bdce075740189e9e23907ae22b5addbd875ccb70c116811b1fa5fb18",
235 "0db7a485f7013a346a8f7f5caf73d52ca3c3b5ee101ad8753adedd4235b7236b",
236 "2afc9c855854b0a6e94a722c3451d0cdfc8c11748b78ef65b9786f87b48d0d07",
237 ],
238 );
239
240 run_test_vector(
241 &input_data,
242 TransactionSigningHash::new,
243 &[
244 "34c75037ad62740d4b3228f88f844f7901c07bfacd55a045be518eabc15e52ce",
245 "8523b0471bcbea04575ccaa635eef9f9114f2890bda54367e5ff8caa3878bf82",
246 "a51c49d9eb3d13f9de16e1aa8d1ff17668d55633ce00f36a643ac714b0fb137f",
247 "487f199ef74c3e893e85bd37770e6334575a2d4d113b2e10474593c49807de93",
248 "6392adc33a8e24e9a0a0c4c5f07f9c1cc958ad40c16d7a9a276e374cebb4e32b",
249 ],
250 );
251 run_test_vector(
252 &input_data,
253 TransactionSigningHashECDSA::new,
254 &[
255 "b31ad1fbbe41b0e2a90e07c84708b38ba581f0c0e9185416913a04fb6d342027",
256 "c43e1f75ea9df6379b56a95074c2b6289ed8c5a01fff2d49d9d44ad5575c164b",
257 "49085f99fa0084b5436663f757a5916b1e4290c3321707fb76921ed4e47844ec",
258 "3f887e866428de813c1d0463b14eef3ca1363c8187e917dda1eee0ec5996490b",
259 "56de89a8c75f0fee2de61b11ab05d0d42e29ed50879467cf128dd80800a52ada",
260 ],
261 );
262
263 run_test_vector(
264 &input_data,
265 BlockHash::new,
266 &[
267 "a80b6aa20f20b15ebabe2b1949527f78a257594a732e774de637d85e6973a768",
268 "5643023add641f9421187b8c9aa3c6c73227d5ec34131c61a08d35b43e7e4b65",
269 "4dc3bf72045431e46f8839a7d390898f27c887fddd8637149bfb70f732f04334",
270 "15d7648e69023dca65c949a61ea166192049f449c604523494813873b19918a7",
271 "3ac41af8385ea5d902ce6d47f509b7accc9c631f1d57a719d777874467f6d877",
272 ],
273 );
274
275 run_test_vector(
276 &input_data,
277 MerkleBranchHash::new,
278 &[
279 "4de3617db456d01248173f17ec58196e92fbd994b636476db4b875ed2ec84054",
280 "5737cd8b6fca5a30c19a491323a14e6b7021641cb3f8875f10c7a2eafd3cf43f",
281 "a49eeda61cc75e0a8e5915829752fe0ad97620d6d32de7c9883595b0810ca33e",
282 "28f33681dcff1313674e07dacc2d74c3089f6d8cea7a4f8792a71fd870988ee5",
283 "2d53a43a42020a5091c125230bcd8a4cf0eeb188333e68325d4bce58a1c75ca3",
284 ],
285 );
286 }
287
288 #[test]
289 fn test_blake3_vectors() {
290 let input_data = [
291 &[][..],
292 &[1][..],
293 &[
294 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,
295 133, 7, 60, 4, 160, 205,
296 ][..],
297 &[42; 64],
298 &[0; 8][..],
299 ];
300
301 run_test_vector(
302 &input_data,
303 SeqCommitLaneKey::new,
304 &[
305 "ffb48ccf5a7d24d449a8da0dd09a73b1e0a20ee10a7331c21930042e58d2aa24",
306 "4daeb9c121484df93175020a60c04463b3c8b6ccfa4a06b7a8e6aff9ace7cfa4",
307 "41a1aa1d34375a2ef257571a8ca52c73957483811cb4852a3b815fd72b3d773c",
308 "a240e37f30a735d5791e589f4ca193e3ec801e24565f2f797faec33f88c10f9e",
309 "a2df04afbd137a8ee9ed44a001af5dcc98cfffd14100163ebd2f899c542127a0",
310 ],
311 );
312 run_test_vector(
313 &input_data,
314 SeqCommitLaneTip::new,
315 &[
316 "255d4f981ed1e613ec87d46750254527c3044e42ce6b639dfa4190ab3965d777",
317 "274025031a8f9b81346e0f1e0cd215929736c89bcf3b3589b744b196663dbf02",
318 "72790c6e65fda13ddf64d48c062ad0f18d218f8a8c83c9426d13911ba60da4e6",
319 "3359cef7e345290fa4f5270849ecdf154efcb06b189b7fbcf6889691cda5d3eb",
320 "932c73359760c7f04ef38be45dd863b7a31372756c7f34ffec263edbc6b75362",
321 ],
322 );
323 run_test_vector(
324 &input_data,
325 SeqCommitActivityLeaf::new,
326 &[
327 "925e8cc9643d7b2ae93e38f7a0022f1f0c694eeb6608d991389f77be5f3dab3e",
328 "de3a34c353bcd4dc1be835c5412d6fb3bcb55801750ce68f07ccd25d5d6446ee",
329 "65abaa78c27d5400a4d28df2d6d6219939f4b4973012f651086fbef6f4159346",
330 "5d3121321c6baaaec650f3746a1aea65b3310d1d544e8dc6a2d93ca6b0baf3c3",
331 "dab38f396da66f90cedd52e3cf7ccf6846756cb1693465ef93791c657f8fc868",
332 ],
333 );
334 run_test_vector(
335 &input_data,
336 SeqCommitMergesetContext::new,
337 &[
338 "cd2b97a22304873dfa189e15c0a13636ea60570c11f763c6c1c6efc49d469489",
339 "6cf9af3a32964ffea8b4eccd2cd2002d5b92cdb5ac11fea6ec1dfe229ddf652c",
340 "55fa8db49590d0ef4f3d36e9c0b3b41e6791eaf8eda968f3499e66d952766e6e",
341 "394d104cdb22f9429374dd15b6cb2e601876e6b97985803da9837a15d43aab42",
342 "c8c5d211df896199dc349aeadc6da0fe3c3375f3539d1936268f9a6c64b6ed39",
343 ],
344 );
345 run_test_vector(
346 &input_data,
347 PayloadDigest::new,
348 &[
349 "9c0ca2acb45e92ffe6ceb4ae29188b35c82d9676cdd3ce067fd6ccc30a9c4a38",
350 "a69883bfb2bb000249639d8bbf5019fd08ceb7daa7a86f170530522dfedba124",
351 "04d7abe0495ff2c520f93ed31bb37f58a9375abb48d50b163864335af8d834de",
352 "5a4aa21c7235ec3edb7bd198b576f78cca6c5027dd7938ed41e74ae982858021",
353 "d6e0e23e9130b0e44734f3639489e22e7f7d928f474386599db6fca3b02d6295",
354 ],
355 );
356 run_test_vector(
357 &input_data,
358 SeqCommitMinerPayloadLeaf::new,
359 &[
360 "1f53866c878ac122fe24c45ae3dd7931d9d045559f53ee64512aabf9dc1a0892",
361 "4f0987631ad1a5a7b47c44309fc9690a5a1bab2351807d1282c6dabe1b06b235",
362 "5dd4ed4f4a7fbc7054ec04df67f2acc8db259ca045614cb5390f6dc1b5a8275f",
363 "fd4f1c71ecdff8ac4448a4ebccc540e6f30705c214ea62944bd41498e0409ed7",
364 "b870bed32130d2e8a9697b4f205d9c9ddc26d4adcb5cf9df666acea8f071bb44",
365 ],
366 );
367 run_test_vector(
368 &input_data,
369 SeqCommitActiveLeaf::new,
370 &[
371 "9bccebe22e721372272c9d8520d2b3654bb93db82f41d77d460b682d97de1120",
372 "3fde1c896d32bf8d24cff1ed22df7f5a76c10b45b37b5f836cdbbe3a9fe28a58",
373 "a603c38c61e68d8fa7020cd1d4d6b07658985863192d589d0e6cffaa706e67cd",
374 "35a96a743bc1521c7f5cc15968a407a82270c7b888fa0e4389d95afdbf0b0637",
375 "4fd0302a50d9b4394a8db8bfb7e92d29f5731c89bb7e0523ebafed0098af76c2",
376 ],
377 );
378 run_test_vector(
379 &input_data,
380 SeqCommitActiveNode::new,
381 &[
382 "6e1c8cc1d31bca65366d150b2d6ce3fff9436f5fb9549bb5f4e656c3e79bb385",
383 "833ff5ffa0262a58ff7a062d1d8ad5f943b8433648b6699a7db4bfb144490c3b",
384 "e4ba2f5b76d7385deeb8ca384c83ba47457bcdec14508f73ffb4c9a359c8c5b7",
385 "ece4a35bea3f577e961f8a3cd6f6e140013166cd045cbc12a60e6029713a286b",
386 "d66a35eca6ea9be29cbf16fa3e1da9d6550f62ae6db9d54f00a21f8315723594",
387 ],
388 );
389 }
390}