1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6#[cfg(feature = "alloc")]
7use alloc::{vec, vec::Vec};
8
9#[cfg(feature = "ethereum_types")]
10mod ethereum_types;
11
12use libssz::SszEncode;
13
14pub type Node = [u8; 32];
16
17include!(concat!(env!("OUT_DIR"), "/zero_hashes.rs"));
18
19pub trait Sha256Hasher {
24 fn hash(&self, data: &[u8]) -> [u8; 32];
25}
26
27#[cfg(feature = "sha2-backend")]
29pub struct Sha2Hasher;
30
31#[cfg(feature = "sha2-backend")]
32impl Sha256Hasher for Sha2Hasher {
33 fn hash(&self, data: &[u8]) -> [u8; 32] {
34 use sha2::{Digest, Sha256};
35 Sha256::digest(data).into()
36 }
37}
38
39#[inline]
41pub fn hash_nodes(hasher: &impl Sha256Hasher, a: &Node, b: &Node) -> Node {
42 let mut buf = [0u8; 64];
43 buf[..32].copy_from_slice(a);
44 buf[32..].copy_from_slice(b);
45 hasher.hash(&buf)
46}
47
48#[cfg(feature = "alloc")]
50pub fn pack(values: &[u8]) -> Vec<Node> {
51 if values.is_empty() {
52 return Vec::new();
53 }
54 let num_chunks = values.len().div_ceil(32);
55 let mut chunks = Vec::with_capacity(num_chunks);
56 for i in 0..num_chunks {
57 let start = i * 32;
58 let end = core::cmp::min(start + 32, values.len());
59 let mut chunk = [0u8; 32];
60 chunk[..end - start].copy_from_slice(&values[start..end]);
61 chunks.push(chunk);
62 }
63 chunks
64}
65
66#[cfg(feature = "alloc")]
69pub fn pack_bits(bits: &[u8], num_bits: usize) -> Vec<Node> {
70 let num_bytes = num_bits.div_ceil(8);
71 let effective = &bits[..core::cmp::min(num_bytes, bits.len())];
72 pack(effective)
73}
74
75#[cfg(feature = "alloc")]
84pub fn merkleize(hasher: &impl Sha256Hasher, chunks: &[Node], limit: Option<usize>) -> Node {
85 let count = match limit {
86 Some(l) => {
87 assert!(
88 chunks.len() <= l,
89 "bug: chunk count {} exceeds limit {} — bounded type invariant violated",
90 chunks.len(),
91 l
92 );
93 l
94 }
95 None => chunks.len(),
96 };
97
98 if count == 0 {
99 return ZERO_HASHES[0];
100 }
101
102 let depth = count.next_power_of_two().trailing_zeros() as usize;
103
104 if chunks.is_empty() {
106 return ZERO_HASHES[depth];
107 }
108
109 let real_depth = chunks.len().next_power_of_two().trailing_zeros() as usize;
112
113 let mut layer: Vec<Node> = chunks.to_vec();
120 let mut next: Vec<Node> = Vec::with_capacity(layer.len().div_ceil(2));
121
122 for zero_hash in ZERO_HASHES.iter().take(real_depth) {
123 next.clear();
124 let mut pairs = layer.chunks_exact(2);
125 for pair in &mut pairs {
126 next.push(hash_nodes(hasher, &pair[0], &pair[1]));
127 }
128 if let [odd] = pairs.remainder() {
129 next.push(hash_nodes(hasher, odd, zero_hash));
130 }
131 core::mem::swap(&mut layer, &mut next);
132 }
133
134 let mut root = layer[0];
136 for zero_hash in ZERO_HASHES.iter().take(depth).skip(real_depth) {
137 root = hash_nodes(hasher, &root, zero_hash);
138 }
139
140 root
141}
142
143#[cfg(feature = "alloc")]
152pub fn merkleize_progressive(hasher: &impl Sha256Hasher, chunks: &[Node]) -> Node {
153 merkleize_progressive_inner(hasher, chunks, 1)
154}
155
156#[cfg(feature = "alloc")]
157fn merkleize_progressive_inner(
158 hasher: &impl Sha256Hasher,
159 chunks: &[Node],
160 num_leaves: usize,
161) -> Node {
162 if chunks.is_empty() {
163 return [0u8; 32];
164 }
165
166 let take = core::cmp::min(num_leaves, chunks.len());
167 let subtree = merkleize(hasher, &chunks[..take], Some(num_leaves));
168 let rest = merkleize_progressive_inner(hasher, &chunks[take..], num_leaves * 4);
169 hash_nodes(hasher, &subtree, &rest)
173}
174
175#[cfg(feature = "alloc")]
177pub fn mix_in_active_fields(
178 hasher: &impl Sha256Hasher,
179 root: &Node,
180 active_fields: &[bool],
181) -> Node {
182 let mut bits_bytes = vec![0u8; active_fields.len().div_ceil(8)];
184 for (i, &active) in active_fields.iter().enumerate() {
185 if active {
186 bits_bytes[i / 8] |= 1 << (i % 8);
187 }
188 }
189 let chunks = pack_bits(&bits_bytes, active_fields.len());
190 let af_node = chunks.first().copied().unwrap_or([0u8; 32]);
191 hash_nodes(hasher, root, &af_node)
192}
193
194#[inline]
196pub fn mix_in_length(hasher: &impl Sha256Hasher, root: &Node, length: usize) -> Node {
197 let mut length_node = [0u8; 32];
198 length_node[..8].copy_from_slice(&(length as u64).to_le_bytes());
199 hash_nodes(hasher, root, &length_node)
200}
201
202#[inline]
204pub fn mix_in_selector(hasher: &impl Sha256Hasher, root: &Node, selector: u8) -> Node {
205 let mut selector_node = [0u8; 32];
206 selector_node[0] = selector;
207 hash_nodes(hasher, root, &selector_node)
208}
209
210pub trait HashTreeRoot {
212 fn hash_tree_root(&self, hasher: &impl Sha256Hasher) -> Node;
213
214 fn is_basic_type() -> bool
218 where
219 Self: Sized,
220 {
221 false
222 }
223}
224
225impl HashTreeRoot for bool {
228 #[inline(always)]
229 fn hash_tree_root(&self, _hasher: &impl Sha256Hasher) -> Node {
230 let mut node = [0u8; 32];
231 node[0] = *self as u8;
232 node
233 }
234
235 fn is_basic_type() -> bool {
236 true
237 }
238}
239
240impl HashTreeRoot for u8 {
243 #[inline(always)]
244 fn hash_tree_root(&self, _hasher: &impl Sha256Hasher) -> Node {
245 let mut node = [0u8; 32];
246 let bytes = self.to_le_bytes();
247 node[..bytes.len()].copy_from_slice(&bytes);
248 node
249 }
250
251 fn is_basic_type() -> bool {
252 true
253 }
254}
255
256impl HashTreeRoot for u16 {
257 #[inline(always)]
258 fn hash_tree_root(&self, _hasher: &impl Sha256Hasher) -> Node {
259 let mut node = [0u8; 32];
260 let bytes = self.to_le_bytes();
261 node[..bytes.len()].copy_from_slice(&bytes);
262 node
263 }
264
265 fn is_basic_type() -> bool {
266 true
267 }
268}
269
270impl HashTreeRoot for u32 {
271 #[inline(always)]
272 fn hash_tree_root(&self, _hasher: &impl Sha256Hasher) -> Node {
273 let mut node = [0u8; 32];
274 let bytes = self.to_le_bytes();
275 node[..bytes.len()].copy_from_slice(&bytes);
276 node
277 }
278
279 fn is_basic_type() -> bool {
280 true
281 }
282}
283
284impl HashTreeRoot for u64 {
285 #[inline(always)]
286 fn hash_tree_root(&self, _hasher: &impl Sha256Hasher) -> Node {
287 let mut node = [0u8; 32];
288 let bytes = self.to_le_bytes();
289 node[..bytes.len()].copy_from_slice(&bytes);
290 node
291 }
292
293 fn is_basic_type() -> bool {
294 true
295 }
296}
297
298impl HashTreeRoot for u128 {
299 #[inline(always)]
300 fn hash_tree_root(&self, _hasher: &impl Sha256Hasher) -> Node {
301 let mut node = [0u8; 32];
302 let bytes = self.to_le_bytes();
303 node[..bytes.len()].copy_from_slice(&bytes);
304 node
305 }
306
307 fn is_basic_type() -> bool {
308 true
309 }
310}
311
312#[cfg(feature = "alloc")]
315impl<const N: usize> HashTreeRoot for [u8; N] {
316 fn hash_tree_root(&self, hasher: &impl Sha256Hasher) -> Node {
317 if N <= 32 {
318 let mut node = [0u8; 32];
319 node[..N].copy_from_slice(self);
320 node
321 } else {
322 merkleize(hasher, &pack(self), None)
323 }
324 }
325
326 fn is_basic_type() -> bool {
327 N <= 32
328 }
329}
330
331#[cfg(feature = "alloc")]
334impl<T: HashTreeRoot + SszEncode> HashTreeRoot for Vec<T> {
335 fn hash_tree_root(&self, hasher: &impl Sha256Hasher) -> Node {
336 let chunks: Vec<Node> = if T::is_basic_type() {
337 let mut serialized = Vec::new();
338 for item in self {
339 item.ssz_append(&mut serialized);
340 }
341 pack(&serialized)
342 } else {
343 self.iter()
344 .map(|item| item.hash_tree_root(hasher))
345 .collect()
346 };
347 let root = if chunks.is_empty() {
348 merkleize(hasher, &[ZERO_HASHES[0]], None)
349 } else {
350 merkleize(hasher, &chunks, None)
351 };
352 mix_in_length(hasher, &root, self.len())
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359 use alloc::vec;
360 use alloc::vec::Vec;
361
362 #[cfg(feature = "sha2-backend")]
363 use crate::Sha2Hasher;
364
365 #[cfg(feature = "sha2-backend")]
368 #[test]
369 fn hash_nodes_of_two_zero_nodes() {
370 let zero = [0u8; 32];
371 let result = hash_nodes(&Sha2Hasher, &zero, &zero);
372 use sha2::{Digest, Sha256};
373 let mut sha = Sha256::new();
374 sha.update([0u8; 64]);
375 let expected: [u8; 32] = sha.finalize().into();
376 assert_eq!(result, expected);
377 }
378
379 #[cfg(feature = "sha2-backend")]
380 #[test]
381 fn hash_nodes_is_not_commutative() {
382 let a = [1u8; 32];
383 let b = [2u8; 32];
384 assert_ne!(
385 hash_nodes(&Sha2Hasher, &a, &b),
386 hash_nodes(&Sha2Hasher, &b, &a)
387 );
388 }
389
390 #[test]
393 fn zero_hash_level_0_is_all_zeros() {
394 assert_eq!(ZERO_HASHES[0], [0u8; 32]);
395 }
396
397 #[cfg(feature = "sha2-backend")]
398 #[test]
399 fn zero_hash_level_1_is_hash_of_two_zeros() {
400 let expected = hash_nodes(&Sha2Hasher, &[0u8; 32], &[0u8; 32]);
401 assert_eq!(ZERO_HASHES[1], expected);
402 }
403
404 #[cfg(feature = "sha2-backend")]
405 #[test]
406 fn zero_hash_level_2_is_hash_of_two_level_1() {
407 let expected = hash_nodes(&Sha2Hasher, &ZERO_HASHES[1], &ZERO_HASHES[1]);
408 assert_eq!(ZERO_HASHES[2], expected);
409 }
410
411 #[test]
414 fn pack_empty_returns_empty() {
415 let result = pack(&[]);
416 assert!(result.is_empty());
417 }
418
419 #[test]
420 fn pack_single_byte() {
421 let result = pack(&[0x42]);
422 assert_eq!(result.len(), 1);
423 let mut expected = [0u8; 32];
424 expected[0] = 0x42;
425 assert_eq!(result[0], expected);
426 }
427
428 #[test]
429 fn pack_exactly_32_bytes() {
430 let input = [0xAB; 32];
431 let result = pack(&input);
432 assert_eq!(result.len(), 1);
433 assert_eq!(result[0], input);
434 }
435
436 #[test]
437 fn pack_33_bytes_produces_two_chunks() {
438 let input = [0xFF; 33];
439 let result = pack(&input);
440 assert_eq!(result.len(), 2);
441 assert_eq!(result[0], [0xFF; 32]);
442 let mut expected_second = [0u8; 32];
443 expected_second[0] = 0xFF;
444 assert_eq!(result[1], expected_second);
445 }
446
447 #[test]
448 fn pack_two_u64_values() {
449 let val1: u64 = 1;
450 let val2: u64 = 2;
451 let mut serialized = Vec::new();
452 serialized.extend_from_slice(&val1.to_le_bytes());
453 serialized.extend_from_slice(&val2.to_le_bytes());
454 let result = pack(&serialized);
455 assert_eq!(result.len(), 1); let mut expected = [0u8; 32];
457 expected[..8].copy_from_slice(&1u64.to_le_bytes());
458 expected[8..16].copy_from_slice(&2u64.to_le_bytes());
459 assert_eq!(result[0], expected);
460 }
461
462 #[test]
465 fn pack_bits_7_bits() {
466 let bits = [0b0111_1111u8]; let result = pack_bits(&bits, 7);
468 assert_eq!(result.len(), 1);
469 let mut expected = [0u8; 32];
470 expected[0] = 0b0111_1111;
471 assert_eq!(result[0], expected);
472 }
473
474 #[test]
475 fn pack_bits_8_bits() {
476 let bits = [0xFF];
477 let result = pack_bits(&bits, 8);
478 assert_eq!(result.len(), 1);
479 let mut expected = [0u8; 32];
480 expected[0] = 0xFF;
481 assert_eq!(result[0], expected);
482 }
483
484 #[test]
485 fn pack_bits_9_bits() {
486 let bits = [0xFF, 0x01]; let result = pack_bits(&bits, 9);
488 assert_eq!(result.len(), 1);
489 let mut expected = [0u8; 32];
490 expected[0] = 0xFF;
491 expected[1] = 0x01;
492 assert_eq!(result[0], expected);
493 }
494
495 #[cfg(feature = "sha2-backend")]
498 #[test]
499 fn merkleize_empty_returns_zero_hash() {
500 let result = merkleize(&Sha2Hasher, &[], None);
501 assert_eq!(result, ZERO_HASHES[0]);
502 }
503
504 #[cfg(feature = "sha2-backend")]
505 #[test]
506 fn merkleize_one_chunk_is_identity() {
507 let chunk = [0x42u8; 32];
508 let result = merkleize(&Sha2Hasher, &[chunk], None);
509 assert_eq!(result, chunk);
510 }
511
512 #[cfg(feature = "sha2-backend")]
513 #[test]
514 fn merkleize_two_chunks() {
515 let a = [1u8; 32];
516 let b = [2u8; 32];
517 let result = merkleize(&Sha2Hasher, &[a, b], None);
518 assert_eq!(result, hash_nodes(&Sha2Hasher, &a, &b));
519 }
520
521 #[cfg(feature = "sha2-backend")]
522 #[test]
523 fn merkleize_three_chunks_pads_to_four() {
524 let a = [1u8; 32];
525 let b = [2u8; 32];
526 let c = [3u8; 32];
527 let result = merkleize(&Sha2Hasher, &[a, b, c], None);
528 let left = hash_nodes(&Sha2Hasher, &a, &b);
530 let right = hash_nodes(&Sha2Hasher, &c, &ZERO_HASHES[0]);
531 assert_eq!(result, hash_nodes(&Sha2Hasher, &left, &right));
532 }
533
534 #[cfg(feature = "sha2-backend")]
535 #[test]
536 fn merkleize_with_limit_pads_with_zero_hashes() {
537 let a = [1u8; 32];
538 let result = merkleize(&Sha2Hasher, &[a], Some(4));
540 let left = hash_nodes(&Sha2Hasher, &a, &ZERO_HASHES[0]);
542 let right = ZERO_HASHES[1]; assert_eq!(result, hash_nodes(&Sha2Hasher, &left, &right));
544 }
545
546 #[cfg(feature = "sha2-backend")]
547 #[test]
548 fn merkleize_with_limit_equal_to_count() {
549 let a = [1u8; 32];
550 let b = [2u8; 32];
551 assert_eq!(
553 merkleize(&Sha2Hasher, &[a, b], Some(2)),
554 merkleize(&Sha2Hasher, &[a, b], None)
555 );
556 }
557
558 #[cfg(feature = "sha2-backend")]
559 #[test]
560 #[should_panic(expected = "chunk count")]
561 fn merkleize_panics_if_count_exceeds_limit() {
562 let chunks = [[0u8; 32]; 3];
563 merkleize(&Sha2Hasher, &chunks, Some(2));
564 }
565
566 #[cfg(feature = "sha2-backend")]
572 fn merkleize_fully_materialized(chunks: &[Node], limit: Option<usize>) -> Node {
573 let count = core::cmp::max(limit.unwrap_or(chunks.len()), chunks.len());
574 if count == 0 {
575 return ZERO_HASHES[0];
576 }
577 let mut layer = chunks.to_vec();
578 layer.resize(count.next_power_of_two(), ZERO_HASHES[0]);
579 while layer.len() > 1 {
580 layer = layer
581 .chunks(2)
582 .map(|pair| hash_nodes(&Sha2Hasher, &pair[0], &pair[1]))
583 .collect();
584 }
585 layer[0]
586 }
587
588 #[cfg(feature = "sha2-backend")]
591 struct CountingHasher {
592 calls: core::cell::Cell<usize>,
593 }
594
595 #[cfg(feature = "sha2-backend")]
596 impl CountingHasher {
597 fn new() -> Self {
598 Self {
599 calls: core::cell::Cell::new(0),
600 }
601 }
602 }
603
604 #[cfg(feature = "sha2-backend")]
605 impl Sha256Hasher for CountingHasher {
606 fn hash(&self, data: &[u8]) -> [u8; 32] {
607 self.calls.set(self.calls.get() + 1);
608 Sha2Hasher.hash(data)
609 }
610 }
611
612 fn zero_aware_hash_count(chunk_count: usize, limit: Option<usize>) -> usize {
616 let count = limit.unwrap_or(chunk_count);
617 if count == 0 || chunk_count == 0 {
618 return 0;
619 }
620 let depth = count.next_power_of_two().trailing_zeros() as usize;
621 let real_depth = chunk_count.next_power_of_two().trailing_zeros() as usize;
622
623 let mut total = depth - real_depth;
624 let mut len = chunk_count;
625 for _ in 0..real_depth {
626 len = len.div_ceil(2);
627 total += len;
628 }
629 total
630 }
631
632 #[cfg(feature = "sha2-backend")]
633 #[test]
634 fn merkleize_matches_fully_materialized_oracle() {
635 for n in 0..=70 {
636 let chunks: Vec<Node> = (0..n).map(|i| [i as u8 + 1; 32]).collect();
637 assert_eq!(
638 merkleize(&Sha2Hasher, &chunks, None),
639 merkleize_fully_materialized(&chunks, None),
640 "no limit, {n} chunks"
641 );
642 for limit in [n, n + 1, n + 7, 64, 128, 1024] {
643 if limit < n {
644 continue;
645 }
646 assert_eq!(
647 merkleize(&Sha2Hasher, &chunks, Some(limit)),
648 merkleize_fully_materialized(&chunks, Some(limit)),
649 "limit {limit}, {n} chunks"
650 );
651 }
652 }
653 }
654
655 #[cfg(feature = "sha2-backend")]
656 #[test]
657 fn merkleize_does_not_hash_zero_subtrees() {
658 for n in [1usize, 2, 3, 5, 9, 17, 33, 65, 100, 1025] {
659 let chunks: Vec<Node> = (0..n).map(|i| [i as u8; 32]).collect();
660 for limit in [
661 None,
662 Some(n),
663 Some(n.next_power_of_two() * 4),
664 Some(1 << 18),
665 ] {
666 if limit.is_some_and(|l| l < n) {
667 continue;
668 }
669 let hasher = CountingHasher::new();
670 merkleize(&hasher, &chunks, limit);
671 assert_eq!(
672 hasher.calls.get(),
673 zero_aware_hash_count(n, limit),
674 "{n} chunks, limit {limit:?}"
675 );
676 }
677 }
678 }
679
680 #[cfg(feature = "sha2-backend")]
684 #[test]
685 fn merkleize_cost_is_linear_across_power_of_two_boundary() {
686 let count_for = |n: usize| {
687 let chunks: Vec<Node> = (0..n).map(|i| [i as u8; 32]).collect();
688 let hasher = CountingHasher::new();
689 merkleize(&hasher, &chunks, Some(1 << 18));
690 hasher.calls.get()
691 };
692
693 let below = count_for(1024);
694 let above = count_for(1025);
695 assert!(
696 above < below + 20,
697 "one extra chunk added {} hashes (1024 -> {below}, 1025 -> {above})",
698 above - below
699 );
700 }
701
702 #[cfg(feature = "sha2-backend")]
703 #[test]
704 fn merkleize_empty_with_limit_is_the_precomputed_zero_hash() {
705 for (depth, zero_hash) in ZERO_HASHES.iter().enumerate().take(8) {
706 let limit = 1usize << depth;
707 assert_eq!(merkleize(&Sha2Hasher, &[], Some(limit)), *zero_hash);
708 }
709 assert_eq!(merkleize(&Sha2Hasher, &[], Some(3)), ZERO_HASHES[2]);
711 assert_eq!(merkleize(&Sha2Hasher, &[], Some(100)), ZERO_HASHES[7]);
712 }
713
714 #[cfg(feature = "sha2-backend")]
718 fn node_from_hex(s: &str) -> Node {
719 let bytes = s.as_bytes();
720 assert_eq!(bytes.len(), 64, "expected 64 hex characters");
721 let mut out = [0u8; 32];
722 for (i, byte) in out.iter_mut().enumerate() {
723 let hi = char::from(bytes[i * 2]).to_digit(16).expect("hex digit");
724 let lo = char::from(bytes[i * 2 + 1])
725 .to_digit(16)
726 .expect("hex digit");
727 *byte = ((hi << 4) | lo) as u8;
728 }
729 out
730 }
731
732 #[cfg(feature = "sha2-backend")]
734 fn progressive_u64_list_root(values: &[u64]) -> Node {
735 let mut serialized = Vec::with_capacity(values.len() * 8);
736 for value in values {
737 serialized.extend_from_slice(&value.to_le_bytes());
738 }
739 let root = merkleize_progressive(&Sha2Hasher, &pack(&serialized));
740 mix_in_length(&Sha2Hasher, &root, values.len())
741 }
742
743 #[cfg(feature = "sha2-backend")]
744 #[test]
745 fn merkleize_progressive_empty_is_zero_node() {
746 assert_eq!(merkleize_progressive(&Sha2Hasher, &[]), [0u8; 32]);
747 }
748
749 #[cfg(feature = "sha2-backend")]
752 #[test]
753 fn merkleize_progressive_puts_subtree_on_the_left() {
754 let chunk = [0x11u8; 32];
755 assert_eq!(
756 merkleize_progressive(&Sha2Hasher, &[chunk]),
757 hash_nodes(&Sha2Hasher, &chunk, &[0u8; 32])
758 );
759 }
760
761 #[cfg(feature = "sha2-backend")]
767 #[test]
768 fn merkleize_progressive_matches_reference_roots() {
769 let cases: [(u64, &str); 5] = [
770 (
771 0,
772 "f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b",
773 ),
774 (
775 1,
776 "905efb51c2764c2c7a4efb0548e372569df06db82115c3b1896c186632f3fe5b",
777 ),
778 (
779 2,
780 "4250789d7838bee417a2b0d7639d928b05e8b75f1fc59588a4301b6e8f70ba58",
781 ),
782 (
783 5,
784 "29918e0447260511bc5be0f7dbb9817201e16e30c56af228b9cb931a16e8799d",
785 ),
786 (
787 21,
788 "ed360c03ecbdfbb6f4b1cf5d9cbf6887038423e31121700797de968a9969aaed",
789 ),
790 ];
791 for (n, expected) in cases {
792 let values: Vec<u64> = (1..=n).collect();
793 assert_eq!(
794 progressive_u64_list_root(&values),
795 node_from_hex(expected),
796 "ProgressiveList[uint64] of 1..={n}"
797 );
798 }
799 }
800
801 #[cfg(feature = "sha2-backend")]
804 #[test]
805 fn merkleize_progressive_matches_consensus_spec_vectors() {
806 let cases: [(usize, u64, &str, &str); 5] = [
807 (
808 1,
809 u64::MAX,
810 "7bea313629252f757f27d17a1ce515715beedeff41a3f7f6c9ac47bfddcf447c",
811 "proglist_uint64_max_1",
812 ),
813 (
814 4,
815 u64::MAX,
816 "06e8318500bbdb0b6e9b55e63e819cbed45668f6481c24c67bd1d8eaf8703ca8",
817 "proglist_uint64_max_20",
818 ),
819 (
820 21,
821 u64::MAX,
822 "d444bef5f61103078f3ca9bdb2857a9b5e883d738b213a1607a9f3a770a332d2",
823 "proglist_uint64_max_22",
824 ),
825 (
826 7,
827 0,
828 "13a56a67f02ea52c0841043aba35de738bec8519fee07860658d13e2d0442782",
829 "proglist_uint64_zero_8",
830 ),
831 (
832 53,
833 0,
834 "2935884058446007e2592494fe88884e83ee80ecd2041779447c30642fe63ac8",
835 "proglist_uint64_zero_86",
836 ),
837 ];
838 for (count, value, expected, case_name) in cases {
839 let values = vec![value; count];
840 assert_eq!(
841 progressive_u64_list_root(&values),
842 node_from_hex(expected),
843 "{case_name}"
844 );
845 }
846 }
847
848 #[cfg(feature = "sha2-backend")]
851 #[test]
852 fn mix_in_length_known_value() {
853 let root = [0u8; 32];
854 let result = mix_in_length(&Sha2Hasher, &root, 5);
855 let mut len_node = [0u8; 32];
856 len_node[..8].copy_from_slice(&5u64.to_le_bytes());
857 assert_eq!(result, hash_nodes(&Sha2Hasher, &root, &len_node));
858 }
859
860 #[cfg(feature = "sha2-backend")]
861 #[test]
862 fn mix_in_length_zero() {
863 let root = [0xAB; 32];
864 let result = mix_in_length(&Sha2Hasher, &root, 0);
865 assert_eq!(result, hash_nodes(&Sha2Hasher, &root, &[0u8; 32]));
867 }
868
869 #[cfg(feature = "sha2-backend")]
872 #[test]
873 fn mix_in_selector_known_value() {
874 let root = [0u8; 32];
875 let result = mix_in_selector(&Sha2Hasher, &root, 3);
876 let mut sel_node = [0u8; 32];
877 sel_node[0] = 3;
878 assert_eq!(result, hash_nodes(&Sha2Hasher, &root, &sel_node));
879 }
880
881 #[cfg(feature = "sha2-backend")]
884 #[test]
885 fn hash_tree_root_bool_false() {
886 let result = false.hash_tree_root(&Sha2Hasher);
887 assert_eq!(result, [0u8; 32]);
888 }
889
890 #[cfg(feature = "sha2-backend")]
891 #[test]
892 fn hash_tree_root_bool_true() {
893 let result = true.hash_tree_root(&Sha2Hasher);
894 let mut expected = [0u8; 32];
895 expected[0] = 1;
896 assert_eq!(result, expected);
897 }
898
899 #[cfg(feature = "sha2-backend")]
900 #[test]
901 fn hash_tree_root_u64() {
902 let val: u64 = 0x0102030405060708;
903 let result = val.hash_tree_root(&Sha2Hasher);
904 let mut expected = [0u8; 32];
905 expected[..8].copy_from_slice(&val.to_le_bytes());
906 assert_eq!(result, expected);
907 }
908
909 #[cfg(feature = "sha2-backend")]
910 #[test]
911 fn hash_tree_root_u8() {
912 let val: u8 = 42;
913 let result = val.hash_tree_root(&Sha2Hasher);
914 let mut expected = [0u8; 32];
915 expected[0] = 42;
916 assert_eq!(result, expected);
917 }
918
919 #[cfg(feature = "sha2-backend")]
920 #[test]
921 fn hash_tree_root_u128() {
922 let val: u128 = 1;
923 let result = val.hash_tree_root(&Sha2Hasher);
924 let mut expected = [0u8; 32];
925 expected[..16].copy_from_slice(&val.to_le_bytes());
926 assert_eq!(result, expected);
927 }
928
929 #[cfg(feature = "sha2-backend")]
930 #[test]
931 fn hash_tree_root_byte_array_32_is_identity() {
932 let arr = [0xab_u8; 32];
933 assert_eq!(arr.hash_tree_root(&Sha2Hasher), arr);
934 assert!(<[u8; 32]>::is_basic_type());
935 }
936
937 #[cfg(feature = "sha2-backend")]
938 #[test]
939 fn hash_tree_root_byte_array_20_is_padded() {
940 let arr = [0xcd_u8; 20];
941 let root = arr.hash_tree_root(&Sha2Hasher);
942 assert_eq!(&root[..20], &arr[..]);
943 assert_eq!(&root[20..], &[0u8; 12]);
944 assert!(<[u8; 20]>::is_basic_type());
945 }
946
947 #[cfg(feature = "sha2-backend")]
948 #[test]
949 fn hash_tree_root_byte_array_4_is_padded() {
950 let arr = [0x01, 0x02, 0x03, 0x04];
951 let root = arr.hash_tree_root(&Sha2Hasher);
952 assert_eq!(&root[..4], &arr[..]);
953 assert_eq!(&root[4..], &[0u8; 28]);
954 assert!(<[u8; 4]>::is_basic_type());
955 }
956
957 #[cfg(feature = "sha2-backend")]
958 #[test]
959 fn hash_tree_root_byte_array_7_is_padded() {
960 let arr = [0xff_u8; 7];
961 let root = arr.hash_tree_root(&Sha2Hasher);
962 assert_eq!(&root[..7], &arr[..]);
963 assert_eq!(&root[7..], &[0u8; 25]);
964 assert!(<[u8; 7]>::is_basic_type());
965 }
966
967 #[cfg(feature = "sha2-backend")]
968 #[test]
969 fn hash_tree_root_byte_array_48_is_merkleized() {
970 let arr = [0xab_u8; 48];
971 let root = arr.hash_tree_root(&Sha2Hasher);
972 let expected = merkleize(&Sha2Hasher, &pack(&arr), None);
974 assert_eq!(root, expected);
975 assert!(!<[u8; 48]>::is_basic_type());
976 }
977
978 #[cfg(feature = "sha2-backend")]
979 #[test]
980 fn hash_tree_root_byte_array_52_is_merkleized() {
981 let arr = [0xcd_u8; 52];
982 let root = arr.hash_tree_root(&Sha2Hasher);
983 let expected = merkleize(&Sha2Hasher, &pack(&arr), None);
984 assert_eq!(root, expected);
985 assert!(!<[u8; 52]>::is_basic_type());
986 }
987
988 #[cfg(feature = "sha2-backend")]
989 #[test]
990 fn hash_tree_root_byte_array_96_is_merkleized() {
991 let arr = [0xff_u8; 96];
992 let root = arr.hash_tree_root(&Sha2Hasher);
993 let expected = merkleize(&Sha2Hasher, &pack(&arr), None);
994 assert_eq!(root, expected);
995 assert!(!<[u8; 96]>::is_basic_type());
996 }
997
998 #[cfg(feature = "sha2-backend")]
999 #[test]
1000 fn hash_tree_root_vec_u64_empty() {
1001 let val: Vec<u64> = vec![];
1002 let result = val.hash_tree_root(&Sha2Hasher);
1003 let root = merkleize(&Sha2Hasher, &[ZERO_HASHES[0]], None);
1005 assert_eq!(result, mix_in_length(&Sha2Hasher, &root, 0));
1006 }
1007
1008 #[cfg(feature = "sha2-backend")]
1009 #[test]
1010 fn hash_tree_root_vec_u64() {
1011 let val: Vec<u64> = vec![1, 2, 3, 4];
1012 let result = val.hash_tree_root(&Sha2Hasher);
1013
1014 let mut serialized = Vec::new();
1016 for v in &val {
1017 serialized.extend_from_slice(&v.to_le_bytes());
1018 }
1019 let chunks = pack(&serialized);
1020 let root = merkleize(&Sha2Hasher, &chunks, None);
1021 assert_eq!(result, mix_in_length(&Sha2Hasher, &root, 4));
1022 }
1023
1024 #[cfg(feature = "sha2-backend")]
1025 #[test]
1026 fn hash_tree_root_vec_u64_five_elements() {
1027 let val: Vec<u64> = vec![1, 2, 3, 4, 5];
1028 let result = val.hash_tree_root(&Sha2Hasher);
1029
1030 let mut serialized = Vec::new();
1032 for v in &val {
1033 serialized.extend_from_slice(&v.to_le_bytes());
1034 }
1035 let chunks = pack(&serialized);
1036 assert_eq!(chunks.len(), 2);
1037 let root = merkleize(&Sha2Hasher, &chunks, None);
1038 assert_eq!(result, mix_in_length(&Sha2Hasher, &root, 5));
1039 }
1040
1041 #[cfg(feature = "sha2-backend")]
1042 #[test]
1043 fn custom_hasher_works() {
1044 struct MockHasher;
1045 impl Sha256Hasher for MockHasher {
1046 fn hash(&self, data: &[u8]) -> [u8; 32] {
1047 let mut out = [0u8; 32];
1048 for (i, &b) in data.iter().enumerate() {
1049 out[i % 32] ^= b;
1050 }
1051 out
1052 }
1053 }
1054 let val: u64 = 42;
1055 let root_sha2 = val.hash_tree_root(&Sha2Hasher);
1056 let root_mock = val.hash_tree_root(&MockHasher);
1057 assert_eq!(root_sha2, root_mock);
1059
1060 let arr = [0xab_u8; 48];
1062 let root_sha2 = arr.hash_tree_root(&Sha2Hasher);
1063 let root_mock = arr.hash_tree_root(&MockHasher);
1064 assert_ne!(root_sha2, root_mock);
1065 }
1066}