1use serde::Serialize;
25
26use crate::{
27 error::{ExoError, Result},
28 types::Hash256,
29};
30
31const MERKLE_LEAF_DOMAIN: u8 = 0x00;
32const MERKLE_PARENT_DOMAIN: u8 = 0x01;
33const MERKLE_COUNTED_ROOT_DOMAIN: u8 = 0x02;
34const MERKLE_LEAF_COUNT_BYTES: usize = 16;
35
36#[must_use]
38pub fn canonical_hash(data: &[u8]) -> Hash256 {
39 Hash256::digest(data)
40}
41
42pub fn hash_structured<T: Serialize>(value: &T) -> Result<Hash256> {
48 let mut buf = Vec::new();
49 ciborium::into_writer(value, &mut buf)?;
50 Ok(canonical_hash(&buf))
51}
52
53#[must_use]
61pub fn merkle_root(leaves: &[Hash256]) -> Hash256 {
62 if leaves.is_empty() {
63 return Hash256::ZERO;
64 }
65
66 let mut current: Vec<Hash256> = leaves.iter().map(hash_leaf).collect();
67 while current.len() > 1 {
68 let mut next = Vec::with_capacity(current.len().div_ceil(2));
69 let mut i = 0;
70 while i < current.len() {
71 let left = ¤t[i];
72 let right = if i + 1 < current.len() {
73 ¤t[i + 1]
74 } else {
75 left
77 };
78 next.push(hash_pair(left, right));
79 i += 2;
80 }
81 current = next;
82 }
83 current[0]
84}
85
86#[must_use]
89pub fn merkle_root_with_leaf_count(leaves: &[Hash256]) -> Hash256 {
90 bind_merkle_root_to_leaf_count(&merkle_root(leaves), leaves.len())
91}
92
93#[must_use]
95pub fn bind_merkle_root_to_leaf_count(root: &Hash256, leaf_count: usize) -> Hash256 {
96 let mut combined = [0u8; 1 + MERKLE_LEAF_COUNT_BYTES + 32];
97 let leaf_count_bytes = leaf_count.to_be_bytes();
98 let count_end = 1 + MERKLE_LEAF_COUNT_BYTES;
99 let count_start = count_end - leaf_count_bytes.len();
100
101 combined[0] = MERKLE_COUNTED_ROOT_DOMAIN;
102 combined[count_start..count_end].copy_from_slice(&leaf_count_bytes);
103 combined[count_end..].copy_from_slice(root.as_bytes());
104 canonical_hash(&combined)
105}
106
107pub fn merkle_proof(leaves: &[Hash256], index: usize) -> Result<Vec<Hash256>> {
116 if index >= leaves.len() || leaves.is_empty() {
117 return Err(ExoError::InvalidMerkleProof);
118 }
119 if leaves.len() == 1 {
120 return Ok(Vec::new());
121 }
122
123 let mut proof = Vec::new();
124 let mut current: Vec<Hash256> = leaves.iter().map(hash_leaf).collect();
125 let mut idx = index;
126
127 while current.len() > 1 {
128 if current.len() % 2 != 0 {
130 let last = current[current.len() - 1];
131 current.push(last);
132 }
133 let sibling_idx = if idx % 2 == 0 { idx + 1 } else { idx - 1 };
134 proof.push(current[sibling_idx]);
135
136 let mut next = Vec::with_capacity(current.len() / 2);
138 let mut i = 0;
139 while i < current.len() {
140 next.push(hash_pair(¤t[i], ¤t[i + 1]));
141 i += 2;
142 }
143 current = next;
144 idx /= 2;
145 }
146
147 Ok(proof)
148}
149
150#[must_use]
157pub fn verify_merkle_proof(
158 root: &Hash256,
159 leaf: &Hash256,
160 proof: &[Hash256],
161 index: usize,
162) -> bool {
163 let current = merkle_root_from_proof(leaf, proof, index);
164 hash256_eq_constant_time(¤t, root)
165}
166
167#[must_use]
169pub fn merkle_root_from_proof(leaf: &Hash256, proof: &[Hash256], index: usize) -> Hash256 {
170 let mut current = hash_leaf(leaf);
171 let mut idx = index;
172
173 for sibling in proof {
174 if idx % 2 == 0 {
175 current = hash_pair(¤t, sibling);
176 } else {
177 current = hash_pair(sibling, ¤t);
178 }
179 idx /= 2;
180 }
181
182 current
183}
184
185#[must_use]
193pub fn verify_merkle_proof_with_leaf_count(
194 root: &Hash256,
195 leaf: &Hash256,
196 proof: &[Hash256],
197 index: usize,
198 leaf_count: usize,
199) -> bool {
200 let Ok((current, duplicate_siblings_match)) =
201 fold_merkle_proof_with_leaf_count(leaf, proof, index, leaf_count)
202 else {
203 return false;
204 };
205 let count_bound_root = bind_merkle_root_to_leaf_count(¤t, leaf_count);
206 duplicate_siblings_match && hash256_eq_constant_time(&count_bound_root, root)
207}
208
209pub fn merkle_root_from_proof_with_leaf_count(
219 leaf: &Hash256,
220 proof: &[Hash256],
221 index: usize,
222 leaf_count: usize,
223) -> Result<Hash256> {
224 let (root, duplicate_siblings_match) =
225 fold_merkle_proof_with_leaf_count(leaf, proof, index, leaf_count)?;
226 if duplicate_siblings_match {
227 Ok(bind_merkle_root_to_leaf_count(&root, leaf_count))
228 } else {
229 Err(ExoError::InvalidMerkleProof)
230 }
231}
232
233fn fold_merkle_proof_with_leaf_count(
234 leaf: &Hash256,
235 proof: &[Hash256],
236 index: usize,
237 leaf_count: usize,
238) -> Result<(Hash256, bool)> {
239 if leaf_count == 0 || index >= leaf_count {
240 return Err(ExoError::InvalidMerkleProof);
241 }
242
243 let mut current = hash_leaf(leaf);
244 let mut idx = index;
245 let mut level_count = leaf_count;
246 let mut duplicate_siblings_match = true;
247
248 for sibling in proof {
249 if level_count == 1 || idx >= level_count {
250 return Err(ExoError::InvalidMerkleProof);
251 }
252
253 let is_duplicated_odd_leaf = level_count % 2 != 0 && idx == level_count - 1;
254 if is_duplicated_odd_leaf {
255 duplicate_siblings_match &= hash256_eq_constant_time(¤t, sibling);
256 current = hash_pair(¤t, ¤t);
257 } else if idx % 2 == 0 {
258 current = hash_pair(¤t, sibling);
259 } else {
260 current = hash_pair(sibling, ¤t);
261 }
262
263 idx /= 2;
264 level_count = level_count.div_ceil(2);
265 }
266
267 if level_count == 1 {
268 Ok((current, duplicate_siblings_match))
269 } else {
270 Err(ExoError::InvalidMerkleProof)
271 }
272}
273
274#[must_use]
276pub fn hash256_eq_constant_time(left: &Hash256, right: &Hash256) -> bool {
277 let mut diff = 0u8;
278 for (left_byte, right_byte) in left.as_bytes().iter().zip(right.as_bytes().iter()) {
279 diff |= left_byte ^ right_byte;
280 }
281 diff == 0
282}
283
284#[must_use]
286fn hash_leaf(leaf: &Hash256) -> Hash256 {
287 let mut combined = [0u8; 33];
288 combined[0] = MERKLE_LEAF_DOMAIN;
289 combined[1..].copy_from_slice(leaf.as_bytes());
290 canonical_hash(&combined)
291}
292
293#[must_use]
295fn hash_pair(left: &Hash256, right: &Hash256) -> Hash256 {
296 let mut combined = [0u8; 65];
297 combined[0] = MERKLE_PARENT_DOMAIN;
298 combined[1..33].copy_from_slice(left.as_bytes());
299 combined[33..].copy_from_slice(right.as_bytes());
300 canonical_hash(&combined)
301}
302
303#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn canonical_hash_deterministic() {
313 let h1 = canonical_hash(b"hello world");
314 let h2 = canonical_hash(b"hello world");
315 assert_eq!(h1, h2);
316 }
317
318 #[test]
319 fn canonical_hash_different_inputs() {
320 let h1 = canonical_hash(b"aaa");
321 let h2 = canonical_hash(b"bbb");
322 assert_ne!(h1, h2);
323 }
324
325 #[test]
326 fn hash_structured_deterministic() {
327 #[derive(Serialize)]
328 struct Foo {
329 a: u32,
330 b: String,
331 }
332 let v = Foo {
333 a: 42,
334 b: "hello".into(),
335 };
336 let h1 = hash_structured(&v).expect("ok");
337 let h2 = hash_structured(&v).expect("ok");
338 assert_eq!(h1, h2);
339 }
340
341 #[test]
342 fn hash_structured_different_values() {
343 let h1 = hash_structured(&42u32).expect("ok");
344 let h2 = hash_structured(&43u32).expect("ok");
345 assert_ne!(h1, h2);
346 }
347
348 #[test]
349 fn merkle_root_empty() {
350 assert_eq!(merkle_root(&[]), Hash256::ZERO);
351 }
352
353 #[test]
354 fn merkle_root_single() {
355 let leaf = Hash256::digest(b"only");
356 assert_eq!(merkle_root(&[leaf]), hash_leaf(&leaf));
357 }
358
359 fn raw_concat_pair_hash_for_test(left: &Hash256, right: &Hash256) -> Hash256 {
360 let mut combined = [0u8; 64];
361 combined[..32].copy_from_slice(left.as_bytes());
362 combined[32..].copy_from_slice(right.as_bytes());
363 canonical_hash(&combined)
364 }
365
366 #[test]
367 fn merkle_root_uses_distinct_leaf_and_parent_domains() {
368 let leaf = Hash256::digest(b"domain-separated-leaf");
369 assert_ne!(
370 merkle_root(&[leaf]),
371 leaf,
372 "single-leaf Merkle roots must not be interchangeable with raw leaf hashes"
373 );
374
375 let right = Hash256::digest(b"domain-separated-right");
376 let raw_parent_hash = raw_concat_pair_hash_for_test(&leaf, &right);
377 assert_ne!(
378 merkle_root(&[leaf, right]),
379 raw_parent_hash,
380 "interior Merkle nodes must not use the raw H(left || right) domain"
381 );
382 }
383
384 #[test]
385 fn merkle_root_two_leaves() {
386 let a = Hash256::digest(b"a");
387 let b = Hash256::digest(b"b");
388 let root = merkle_root(&[a, b]);
389 let expected = hash_pair(&hash_leaf(&a), &hash_leaf(&b));
391 assert_eq!(root, expected);
392 }
393
394 #[test]
395 fn merkle_root_three_leaves_odd() {
396 let a = Hash256::digest(b"a");
397 let b = Hash256::digest(b"b");
398 let c = Hash256::digest(b"c");
399 let root = merkle_root(&[a, b, c]);
400 let a_leaf = hash_leaf(&a);
403 let b_leaf = hash_leaf(&b);
404 let c_leaf = hash_leaf(&c);
405 let ab = hash_pair(&a_leaf, &b_leaf);
406 let cc = hash_pair(&c_leaf, &c_leaf);
407 let expected = hash_pair(&ab, &cc);
408 assert_eq!(root, expected);
409 }
410
411 #[test]
412 fn merkle_root_four_leaves() {
413 let leaves: Vec<Hash256> = (0..4u8).map(|i| Hash256::digest(&[i])).collect();
414 let root = merkle_root(&leaves);
415 let leaf_nodes: Vec<Hash256> = leaves.iter().map(hash_leaf).collect();
416 let ab = hash_pair(&leaf_nodes[0], &leaf_nodes[1]);
417 let cd = hash_pair(&leaf_nodes[2], &leaf_nodes[3]);
418 let expected = hash_pair(&ab, &cd);
419 assert_eq!(root, expected);
420 }
421
422 #[test]
423 fn merkle_root_with_leaf_count_binds_count_and_inner_root() {
424 let leaves = [
425 Hash256::digest(b"count-bound-a"),
426 Hash256::digest(b"count-bound-b"),
427 Hash256::digest(b"count-bound-c"),
428 Hash256::digest(b"count-bound-d"),
429 ];
430 let inner_root = merkle_root(&leaves);
431 let bound_root = merkle_root_with_leaf_count(&leaves);
432
433 assert_eq!(
434 bound_root,
435 bind_merkle_root_to_leaf_count(&inner_root, leaves.len())
436 );
437 assert_ne!(
438 bound_root,
439 bind_merkle_root_to_leaf_count(&inner_root, 3),
440 "same inner root must not verify under a different leaf count"
441 );
442 assert_ne!(
443 bound_root, inner_root,
444 "count-bound root must not be interchangeable with the raw Merkle root"
445 );
446 }
447
448 #[test]
449 fn merkle_root_deterministic() {
450 let leaves: Vec<Hash256> = (0..7u8).map(|i| Hash256::digest(&[i])).collect();
451 let r1 = merkle_root(&leaves);
452 let r2 = merkle_root(&leaves);
453 assert_eq!(r1, r2);
454 }
455
456 #[test]
457 fn merkle_proof_empty() {
458 let result = merkle_proof(&[], 0);
459 assert!(result.is_err());
460 }
461
462 #[test]
463 fn merkle_proof_out_of_bounds() {
464 let leaf = Hash256::digest(b"x");
465 let result = merkle_proof(&[leaf], 1);
466 assert!(result.is_err());
467 }
468
469 #[test]
470 fn merkle_proof_single_leaf() {
471 let leaf = Hash256::digest(b"only");
472 let proof = merkle_proof(&[leaf], 0).expect("ok");
473 assert!(proof.is_empty());
474 let root = merkle_root(&[leaf]);
475 assert!(verify_merkle_proof(&root, &leaf, &proof, 0));
476 }
477
478 #[test]
479 fn merkle_proof_two_leaves() {
480 let leaves = vec![Hash256::digest(b"a"), Hash256::digest(b"b")];
481 let root = merkle_root(&leaves);
482
483 for i in 0..2 {
484 let proof = merkle_proof(&leaves, i).expect("ok");
485 assert!(verify_merkle_proof(&root, &leaves[i], &proof, i));
486 }
487 }
488
489 #[test]
490 fn merkle_proof_four_leaves() {
491 let leaves: Vec<Hash256> = (0..4u8).map(|i| Hash256::digest(&[i])).collect();
492 let root = merkle_root(&leaves);
493
494 for i in 0..4 {
495 let proof = merkle_proof(&leaves, i).expect("ok");
496 assert!(
497 verify_merkle_proof(&root, &leaves[i], &proof, i),
498 "proof failed for leaf {i}"
499 );
500 }
501 }
502
503 #[test]
504 fn merkle_proof_odd_leaves() {
505 let leaves: Vec<Hash256> = (0..5u8).map(|i| Hash256::digest(&[i])).collect();
506 let root = merkle_root(&leaves);
507
508 for i in 0..5 {
509 let proof = merkle_proof(&leaves, i).expect("ok");
510 assert!(
511 verify_merkle_proof(&root, &leaves[i], &proof, i),
512 "proof failed for leaf {i}"
513 );
514 }
515 }
516
517 #[test]
518 fn merkle_proof_seven_leaves() {
519 let leaves: Vec<Hash256> = (0..7u8).map(|i| Hash256::digest(&[i])).collect();
520 let root = merkle_root(&leaves);
521
522 for i in 0..7 {
523 let proof = merkle_proof(&leaves, i).expect("ok");
524 assert!(
525 verify_merkle_proof(&root, &leaves[i], &proof, i),
526 "proof failed for leaf {i}"
527 );
528 }
529 }
530
531 #[test]
532 fn verify_merkle_proof_rejects_wrong_leaf() {
533 let leaves: Vec<Hash256> = (0..4u8).map(|i| Hash256::digest(&[i])).collect();
534 let root = merkle_root(&leaves);
535 let proof = merkle_proof(&leaves, 0).expect("ok");
536 let wrong_leaf = Hash256::digest(b"wrong");
537 assert!(!verify_merkle_proof(&root, &wrong_leaf, &proof, 0));
538 }
539
540 #[test]
541 fn verify_merkle_proof_rejects_wrong_index() {
542 let leaves: Vec<Hash256> = (0..4u8).map(|i| Hash256::digest(&[i])).collect();
543 let root = merkle_root(&leaves);
544 let proof = merkle_proof(&leaves, 0).expect("ok");
545 assert!(!verify_merkle_proof(&root, &leaves[0], &proof, 1));
547 }
548
549 #[test]
550 fn verify_merkle_proof_rejects_wrong_root() {
551 let leaves: Vec<Hash256> = (0..4u8).map(|i| Hash256::digest(&[i])).collect();
552 let proof = merkle_proof(&leaves, 0).expect("ok");
553 let wrong_root = Hash256::digest(b"wrong root");
554 assert!(!verify_merkle_proof(&wrong_root, &leaves[0], &proof, 0));
555 }
556
557 #[test]
558 fn merkle_root_from_proof_matches_canonical_root() {
559 let leaves = vec![
560 Hash256::digest(b"root-proof-a"),
561 Hash256::digest(b"root-proof-b"),
562 Hash256::digest(b"root-proof-c"),
563 Hash256::digest(b"root-proof-d"),
564 Hash256::digest(b"root-proof-e"),
565 ];
566 let root = merkle_root(&leaves);
567
568 for (index, leaf) in leaves.iter().enumerate() {
569 let proof = merkle_proof(&leaves, index).expect("proof");
570 assert_eq!(merkle_root_from_proof(leaf, &proof, index), root);
571 }
572 }
573
574 #[test]
575 fn merkle_root_from_proof_with_leaf_count_matches_canonical_root() {
576 let leaves = vec![
577 Hash256::digest(b"count-proof-a"),
578 Hash256::digest(b"count-proof-b"),
579 Hash256::digest(b"count-proof-c"),
580 Hash256::digest(b"count-proof-d"),
581 Hash256::digest(b"count-proof-e"),
582 ];
583 let root = merkle_root_with_leaf_count(&leaves);
584
585 for (index, leaf) in leaves.iter().enumerate() {
586 let proof = merkle_proof(&leaves, index).expect("proof");
587 let computed =
588 merkle_root_from_proof_with_leaf_count(leaf, &proof, index, leaves.len())
589 .expect("leaf-count-bound proof root");
590 assert_eq!(computed, root);
591 assert!(verify_merkle_proof_with_leaf_count(
592 &root,
593 leaf,
594 &proof,
595 index,
596 leaves.len()
597 ));
598 }
599 }
600
601 #[test]
602 fn verify_merkle_proof_with_leaf_count_rejects_false_leaf_count() {
603 let leaves = [
604 Hash256::digest(b"false-count-a"),
605 Hash256::digest(b"false-count-b"),
606 Hash256::digest(b"false-count-c"),
607 Hash256::digest(b"false-count-d"),
608 ];
609 let root = merkle_root_with_leaf_count(&leaves);
610 let target_index = 2;
611 let proof = merkle_proof(&leaves, target_index).expect("proof");
612
613 assert!(!verify_merkle_proof_with_leaf_count(
614 &root,
615 &leaves[target_index],
616 &proof,
617 target_index,
618 3
619 ));
620 }
621
622 #[test]
623 fn verify_merkle_proof_with_leaf_count_rejects_false_prefix_leaf_count() {
624 let leaves = [
625 Hash256::digest(b"false-prefix-count-a"),
626 Hash256::digest(b"false-prefix-count-b"),
627 Hash256::digest(b"false-prefix-count-c"),
628 Hash256::digest(b"false-prefix-count-d"),
629 ];
630 let root = merkle_root_with_leaf_count(&leaves);
631 let target_index = 1;
632 let proof = merkle_proof(&leaves, target_index).expect("proof");
633
634 assert!(!verify_merkle_proof_with_leaf_count(
635 &root,
636 &leaves[target_index],
637 &proof,
638 target_index,
639 3
640 ));
641 }
642
643 #[test]
644 fn verify_merkle_proof_with_leaf_count_rejects_bad_odd_duplicate_sibling() {
645 let leaves = [
646 Hash256::digest(b"odd-count-a"),
647 Hash256::digest(b"odd-count-b"),
648 Hash256::digest(b"odd-count-c"),
649 ];
650 let root = merkle_root_with_leaf_count(&leaves);
651 let target_index = 2;
652 let mut proof = merkle_proof(&leaves, target_index).expect("proof");
653 proof[0] = Hash256::digest(b"attacker-supplied-non-duplicate");
654
655 assert!(!verify_merkle_proof_with_leaf_count(
656 &root,
657 &leaves[target_index],
658 &proof,
659 target_index,
660 leaves.len()
661 ));
662 }
663
664 #[test]
665 fn verify_merkle_proof_uses_constant_time_root_comparison() {
666 let source = include_str!("hash.rs");
667 let Some(after_verify_fn) = source.split("pub fn verify_merkle_proof").nth(1) else {
668 panic!("verify_merkle_proof source exists");
669 };
670 let Some(verify_body) = after_verify_fn.split("/// Hash two nodes together").next() else {
671 panic!("hash_pair marker follows verify_merkle_proof");
672 };
673
674 assert!(
675 verify_body.contains("hash256_eq_constant_time(¤t, root)"),
676 "verify_merkle_proof must compare the reconstructed root in constant time"
677 );
678 assert!(
679 !verify_body.contains("current == *root"),
680 "verify_merkle_proof must not use direct Hash256 equality for the root check"
681 );
682 }
683
684 #[test]
685 fn hash256_eq_constant_time_matches_hash_equality() {
686 let first = Hash256::digest(b"same");
687 let same = Hash256::digest(b"same");
688 let different_first_byte = Hash256::from_bytes({
689 let mut bytes = *first.as_bytes();
690 bytes[0] ^= 0x80;
691 bytes
692 });
693 let different_last_byte = Hash256::from_bytes({
694 let mut bytes = *first.as_bytes();
695 bytes[31] ^= 0x01;
696 bytes
697 });
698
699 assert!(hash256_eq_constant_time(&first, &same));
700 assert!(!hash256_eq_constant_time(&first, &different_first_byte));
701 assert!(!hash256_eq_constant_time(&first, &different_last_byte));
702 }
703
704 #[test]
705 fn hash_pair_deterministic() {
706 let a = Hash256::digest(b"left");
707 let b = Hash256::digest(b"right");
708 let h1 = hash_pair(&a, &b);
709 let h2 = hash_pair(&a, &b);
710 assert_eq!(h1, h2);
711 }
712
713 #[test]
714 fn hash_pair_not_commutative() {
715 let a = Hash256::digest(b"left");
716 let b = Hash256::digest(b"right");
717 assert_ne!(hash_pair(&a, &b), hash_pair(&b, &a));
718 }
719}