1use candid::{encode_one, CandidType};
2use serde::{ser::SerializeSeq, Serialize, Serializer};
3use serde_bytes::Bytes;
4use sha2::{Digest, Sha256};
5use std::mem;
6
7pub type Hash = [u8; 32];
9
10pub const EMPTY_HASH: Hash = [0u8; 32];
14
15#[derive(Debug, Clone)]
18pub enum HashTree {
19 #[doc(hidden)]
20 Empty,
21 #[doc(hidden)]
22 Fork(Box<(HashTree, HashTree)>),
23 #[doc(hidden)]
24 Labeled(Vec<u8>, Box<HashTree>),
25 #[doc(hidden)]
26 Leaf(Vec<u8>),
27 #[doc(hidden)]
28 Pruned(Hash),
29}
30
31pub fn merge_hash_trees(lhs: HashTree, rhs: HashTree) -> HashTree {
33 use HashTree::{Empty, Fork, Labeled, Leaf, Pruned};
34
35 match (lhs, rhs) {
36 (Pruned(l), Pruned(r)) => {
37 if l != r {
38 panic!("merge_hash_trees: inconsistent hashes");
39 }
40 Pruned(l)
41 }
42 (Pruned(_), r) => r,
43 (l, Pruned(_)) => l,
44 (Fork(l), Fork(r)) => Fork(Box::new((
45 merge_hash_trees(l.0, r.0),
46 merge_hash_trees(l.1, r.1),
47 ))),
48 (Labeled(l_label, l), Labeled(r_label, r)) => {
49 if l_label != r_label {
50 panic!("merge_hash_trees: inconsistent hash tree labels");
51 }
52 Labeled(l_label, Box::new(merge_hash_trees(*l, *r)))
53 }
54 (Empty, Empty) => Empty,
55 (Leaf(l), Leaf(r)) => {
56 if l != r {
57 panic!("merge_hash_trees: inconsistent leaves");
58 }
59 Leaf(l)
60 }
61 (_l, _r) => {
62 panic!("merge_hash_trees: inconsistent tree structure");
63 }
64 }
65}
66
67pub fn traverse_hashtree<Fn: FnMut(&HashTree)>(tree: &HashTree, f: &mut Fn) {
69 f(tree);
70
71 match tree {
72 HashTree::Empty => {}
73 HashTree::Pruned(_) => {}
74 HashTree::Fork(x) => {
75 let a = &x.0;
76 let b = &x.1;
77
78 traverse_hashtree(a, f);
79 traverse_hashtree(b, f);
80 }
81 HashTree::Labeled(_, x) => {
82 traverse_hashtree(x, f);
83 }
84 HashTree::Leaf(_) => {}
85 }
86}
87
88#[doc(hidden)]
89pub fn empty() -> HashTree {
90 HashTree::Empty
91}
92#[doc(hidden)]
93pub fn fork(l: HashTree, r: HashTree) -> HashTree {
94 HashTree::Fork(Box::new((l, r)))
95}
96#[doc(hidden)]
97pub fn labeled(l: Vec<u8>, t: HashTree) -> HashTree {
98 HashTree::Labeled(l, Box::new(t))
99}
100#[doc(hidden)]
101pub fn leaf(val: Vec<u8>) -> HashTree {
102 HashTree::Leaf(val)
103}
104#[doc(hidden)]
105pub fn pruned(h: Hash) -> HashTree {
106 HashTree::Pruned(h)
107}
108
109pub struct WitnessForker(HashTree);
126
127impl Default for WitnessForker {
128 fn default() -> Self {
129 Self(HashTree::Empty)
130 }
131}
132
133impl WitnessForker {
134 #[doc(hidden)]
135 #[inline]
136 pub fn fork_with(&mut self, rh: HashTree) {
137 match &mut self.0 {
138 HashTree::Empty => {
139 self.0 = rh;
140 }
141 it => {
142 let lh = mem::replace(it, HashTree::Empty);
143 *it = fork(lh, rh);
144 }
145 }
146 }
147
148 #[doc(hidden)]
149 #[inline]
150 pub fn finish(self) -> HashTree {
151 self.0
152 }
153}
154
155pub struct HashForker(Hash);
157
158impl Default for HashForker {
159 fn default() -> Self {
160 Self(EMPTY_HASH)
161 }
162}
163
164impl HashForker {
165 #[doc(hidden)]
166 #[inline]
167 pub fn fork_with(&mut self, rh: Hash) {
168 if self.0 == EMPTY_HASH {
169 self.0 = rh;
170 } else {
171 self.0 = fork_hash(&self.0, &rh);
172 }
173 }
174
175 #[doc(hidden)]
176 #[inline]
177 pub fn finish(self) -> Hash {
178 if self.0 == EMPTY_HASH {
179 empty_hash()
180 } else {
181 self.0
182 }
183 }
184}
185
186#[doc(hidden)]
187pub fn fork_hash(l: &Hash, r: &Hash) -> Hash {
188 let mut h = domain_sep("ic-hashtree-fork");
189 h.update(&l[..]);
190 h.update(&r[..]);
191 h.finalize().into()
192}
193
194#[doc(hidden)]
195pub fn leaf_hash(data: &[u8]) -> Hash {
196 let mut h = domain_sep("ic-hashtree-leaf");
197 h.update(data);
198 h.finalize().into()
199}
200
201#[doc(hidden)]
202pub fn labeled_hash(label: &[u8], content_hash: &Hash) -> Hash {
203 let mut h = domain_sep("ic-hashtree-labeled");
204 h.update(label);
205 h.update(&content_hash[..]);
206 h.finalize().into()
207}
208
209#[doc(hidden)]
210pub fn empty_hash() -> Hash {
211 domain_sep("ic-hashtree-empty").finalize().into()
212}
213
214impl HashTree {
215 pub fn reconstruct(&self) -> Hash {
217 match self {
218 Self::Empty => empty_hash(),
219 Self::Fork(f) => fork_hash(&f.0.reconstruct(), &f.1.reconstruct()),
220 Self::Labeled(l, t) => {
221 let thash = t.reconstruct();
222 labeled_hash(l, &thash)
223 }
224 Self::Leaf(data) => leaf_hash(data),
225 Self::Pruned(h) => *h,
226 }
227 }
228}
229
230impl Serialize for HashTree {
231 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
232 where
233 S: Serializer,
234 {
235 match self {
236 HashTree::Empty => {
237 let mut seq = serializer.serialize_seq(Some(1))?;
238 seq.serialize_element(&0u8)?;
239 seq.end()
240 }
241 HashTree::Fork(p) => {
242 let mut seq = serializer.serialize_seq(Some(3))?;
243 seq.serialize_element(&1u8)?;
244 seq.serialize_element(&p.0)?;
245 seq.serialize_element(&p.1)?;
246 seq.end()
247 }
248 HashTree::Labeled(label, tree) => {
249 let mut seq = serializer.serialize_seq(Some(3))?;
250 seq.serialize_element(&2u8)?;
251 seq.serialize_element(Bytes::new(label))?;
252 seq.serialize_element(&tree)?;
253 seq.end()
254 }
255 HashTree::Leaf(leaf_bytes) => {
256 let mut seq = serializer.serialize_seq(Some(2))?;
257 seq.serialize_element(&3u8)?;
258 seq.serialize_element(Bytes::new(leaf_bytes.as_ref()))?;
259 seq.end()
260 }
261 HashTree::Pruned(digest) => {
262 let mut seq = serializer.serialize_seq(Some(2))?;
263 seq.serialize_element(&4u8)?;
264 seq.serialize_element(Bytes::new(&digest[..]))?;
265 seq.end()
266 }
267 }
268 }
269}
270
271fn domain_sep(s: &str) -> Sha256 {
272 let buf: [u8; 1] = [s.len() as u8];
273 let mut h = Sha256::new();
274 h.update(&buf[..]);
275 h.update(s.as_bytes());
276
277 h
278}
279
280pub trait AsHashableBytes {
284 #[doc(hidden)]
285 fn as_hashable_bytes(&self) -> Vec<u8>;
286}
287
288impl AsHashableBytes for Hash {
289 #[inline]
290 fn as_hashable_bytes(&self) -> Vec<u8> {
291 self.to_vec()
292 }
293}
294
295impl AsHashableBytes for () {
296 #[inline]
297 fn as_hashable_bytes(&self) -> Vec<u8> {
298 Vec::new()
299 }
300}
301
302pub trait AsHashTree {
308 fn root_hash(&self) -> Hash;
311
312 fn hash_tree(&self) -> HashTree;
314}
315
316impl AsHashTree for () {
317 fn root_hash(&self) -> Hash {
318 empty_hash()
319 }
320
321 fn hash_tree(&self) -> HashTree {
322 empty()
323 }
324}
325
326#[cfg(test)]
327mod tests {
328 use crate::utils::certification::{
329 domain_sep, empty, fork, fork_hash, labeled, labeled_hash, leaf, leaf_hash, pruned, Hash,
330 EMPTY_HASH,
331 };
332 use serde_test::{assert_ser_tokens, Token};
333 use sha2::Digest;
334
335 #[test]
336 fn test() {
337 let k1 = 1u64;
338 let v1 = 10u64;
339
340 let k2 = 2u64;
341 let v2 = 20u64;
342
343 let wit = fork(
344 pruned(labeled_hash(
345 &k1.to_le_bytes(),
346 &leaf_hash(&v1.to_le_bytes()),
347 )),
348 labeled(k2.to_le_bytes().to_vec(), leaf(v2.to_le_bytes().to_vec())),
349 );
350
351 let root_hash = fork_hash(
352 &labeled_hash(&k1.to_le_bytes(), &leaf_hash(&v1.to_le_bytes())),
353 &labeled_hash(&k2.to_le_bytes(), &leaf_hash(&v2.to_le_bytes())),
354 );
355
356 assert_eq!(wit.reconstruct(), root_hash);
357
358 let wit = fork(
359 labeled(k1.to_le_bytes().to_vec(), leaf(v1.to_le_bytes().to_vec())),
360 pruned(labeled_hash(
361 &k2.to_le_bytes(),
362 &leaf_hash(&v2.to_le_bytes()),
363 )),
364 );
365
366 assert_eq!(wit.reconstruct(), root_hash);
367 }
368
369 #[test]
370 fn works_fine() {
371 let e: Hash = domain_sep("ic-hashtree-empty").finalize().into();
372 assert_eq!(empty().reconstruct(), e);
373 }
374
375 const c: [u8; 10] = [0u8; 10];
376
377 #[test]
378 fn ser_works_fine() {
379 let w1 = empty();
380 let w2 = fork(empty(), empty());
381 let w3 = labeled(vec![0u8; 10], empty());
382 let w4 = leaf(vec![0u8; 10]);
383 let w5 = pruned(EMPTY_HASH);
384
385 assert_ser_tokens(
386 &w1,
387 &[Token::Seq { len: Some(1) }, Token::U8(0), Token::SeqEnd],
388 );
389
390 assert_ser_tokens(
391 &w2,
392 &[
393 Token::Seq { len: Some(3) },
394 Token::U8(1),
395 Token::Seq { len: Some(1) },
396 Token::U8(0),
397 Token::SeqEnd,
398 Token::Seq { len: Some(1) },
399 Token::U8(0),
400 Token::SeqEnd,
401 Token::SeqEnd,
402 ],
403 );
404
405 assert_ser_tokens(
406 &w3,
407 &[
408 Token::Seq { len: Some(3) },
409 Token::U8(2),
410 Token::Bytes(&c),
411 Token::Seq { len: Some(1) },
412 Token::U8(0),
413 Token::SeqEnd,
414 Token::SeqEnd,
415 ],
416 );
417
418 assert_ser_tokens(
419 &w4,
420 &[
421 Token::Seq { len: Some(2) },
422 Token::U8(3),
423 Token::Bytes(&c),
424 Token::SeqEnd,
425 ],
426 );
427
428 assert_ser_tokens(
429 &w5,
430 &[
431 Token::Seq { len: Some(2) },
432 Token::U8(4),
433 Token::Bytes(&EMPTY_HASH),
434 Token::SeqEnd,
435 ],
436 );
437 }
438}