1use sha2::{Digest, Sha256};
6use std::mem::{size_of, size_of_val};
7#[cfg(feature = "xxhash")]
8use xxhash_rust::xxh3::xxh3_64;
9
10use crate::{Hash, HashAlgorithm, BLOCK_SIZE};
11
12type BlockIdentity = [u8; size_of::<u64>() + size_of::<u32>()];
13
14fn make_identity(length: usize, level: usize, offset: usize) -> BlockIdentity {
16 let offset_or_level = (offset as u64 | level as u64).to_le_bytes();
17 let length = (length as u32).to_le_bytes();
18 let mut ret: BlockIdentity = [0; size_of::<BlockIdentity>()];
19 let (ret_offset_or_level, ret_length) = ret.split_at_mut(size_of_val(&offset_or_level));
20 ret_offset_or_level.copy_from_slice(&offset_or_level);
21 ret_length.copy_from_slice(&length);
22 ret
23}
24
25pub(crate) fn hash_size(algorithm: HashAlgorithm) -> usize {
26 match algorithm {
27 HashAlgorithm::SHA256 => 32,
28 #[cfg(feature = "xxhash")]
29 HashAlgorithm::XXHash64 => 8,
30 }
31}
32
33pub(crate) fn hashes_per_block(algorithm: HashAlgorithm) -> usize {
34 BLOCK_SIZE / hash_size(algorithm)
35}
36
37pub(crate) fn hash(data: &[u8], algorithm: HashAlgorithm) -> Vec<u8> {
38 match algorithm {
39 HashAlgorithm::SHA256 => Sha256::digest(data).to_vec(),
40 #[cfg(feature = "xxhash")]
41 HashAlgorithm::XXHash64 => xxh3_64(data).to_le_bytes().to_vec(),
42 }
43}
44
45pub fn hash_block(block: &[u8], offset: usize, algorithm: HashAlgorithm) -> Hash {
56 assert!(block.len() <= BLOCK_SIZE);
57 assert!(offset % BLOCK_SIZE == 0);
58
59 let mut to_hash = Vec::<u8>::new();
60 to_hash.extend_from_slice(&make_identity(block.len(), 0, offset));
61 to_hash.extend_from_slice(block);
62 if block.len() != BLOCK_SIZE && !(block.is_empty() && offset == 0) {
65 to_hash.extend_from_slice(&vec![0; BLOCK_SIZE - block.len()]);
66 }
67
68 hash(&to_hash, algorithm)
69}
70
71pub fn hash_hashes(hashes: &[Hash], level: usize, offset: usize, algorithm: HashAlgorithm) -> Hash {
97 assert_ne!(hashes.len(), 0);
98 assert!(hashes.len() <= hashes_per_block(algorithm));
99 assert!(level > 0);
100 assert!(offset % BLOCK_SIZE == 0);
101
102 let mut to_hash = Vec::<u8>::new();
103 to_hash.extend_from_slice(&make_identity(BLOCK_SIZE, level, offset));
104 for hash in hashes.iter() {
105 to_hash.extend_from_slice(hash);
106 }
107 for _ in 0..(hashes_per_block(algorithm) - hashes.len()) {
108 to_hash.extend_from_slice(&vec![0; hash_size(algorithm)]);
110 }
111
112 hash(&to_hash, algorithm)
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 pub const HASH: HashAlgorithm = HashAlgorithm::SHA256;
120
121 #[test]
122 fn test_hash_block_empty() {
123 let block = [];
124 let hash = hash_block(&block[..], 0, HASH);
125 let expected = "15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b";
126 assert_eq!(expected, &hex::encode(hash));
127 }
128
129 #[test]
130 fn test_hash_block_single() {
131 let block = vec![0xFF; 8192];
132 let hash = hash_block(&block[..], 0, HASH);
133 let expected = "68d131bc271f9c192d4f6dcd8fe61bef90004856da19d0f2f514a7f4098b0737";
134 assert_eq!(expected, &hex::encode(hash));
135 }
136
137 #[test]
138 fn test_hash_hashes_full_block() {
139 let mut leafs = Vec::new();
140 {
141 let block = vec![0xFF; BLOCK_SIZE];
142 for i in 0..hashes_per_block(HASH) {
143 leafs.push(hash_block(&block, i * BLOCK_SIZE, HASH));
144 }
145 }
146 let root = hash_hashes(&leafs, 1, 0, HASH);
147 let expected = "1e6e9c870e2fade25b1b0288ac7c216f6fae31c1599c0c57fb7030c15d385a8d";
148 assert_eq!(expected, &hex::encode(root));
149 }
150
151 #[test]
152 fn test_hash_hashes_zero_pad_same_length() {
153 let data_hash = "15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b";
154 let zero_hash = "0000000000000000000000000000000000000000000000000000000000000000";
155 let hash_of_single_hash = hash_hashes(&[hex::decode(data_hash).unwrap()], 1, 0, HASH);
156 let hash_of_single_hash_and_zero_hash = hash_hashes(
157 &[
158 hex::decode(data_hash).unwrap(),
159 hex::decode(zero_hash).unwrap(),
160 ],
161 1,
162 0,
163 HASH,
164 );
165 assert_eq!(hash_of_single_hash, hash_of_single_hash_and_zero_hash);
166 }
167}