diff --git a/coordinator/tributary/src/merkle.rs b/coordinator/tributary/src/merkle.rs index ed44a5cc..175ec022 100644 --- a/coordinator/tributary/src/merkle.rs +++ b/coordinator/tributary/src/merkle.rs @@ -18,7 +18,7 @@ pub(crate) fn merkle(hash_args: &[[u8; 32]]) -> [u8; 32] { b"branch_hash".as_ref(), hashes[i].as_ref(), hashes - .get(i + i) + .get(i + 1) .map(|hash| { let res: &[u8] = hash.as_ref(); res diff --git a/coordinator/tributary/src/tests/merkle.rs b/coordinator/tributary/src/tests/merkle.rs new file mode 100644 index 00000000..c3b0e626 --- /dev/null +++ b/coordinator/tributary/src/tests/merkle.rs @@ -0,0 +1,34 @@ +use std::collections::HashSet; + +use rand_core::{RngCore, OsRng}; + +#[test] +fn merkle() { + let mut used = HashSet::new(); + // Test this produces a unique root + let mut test = |hashes: &[[u8; 32]]| { + let hash = crate::merkle(hashes); + assert!(!used.contains(&hash)); + used.insert(hash); + }; + + // Zero should be a special case which return 0 + assert_eq!(crate::merkle(&[]), [0; 32]); + test(&[]); + + let mut one = [0; 32]; + OsRng.fill_bytes(&mut one); + let mut two = [0; 32]; + OsRng.fill_bytes(&mut two); + let mut three = [0; 32]; + OsRng.fill_bytes(&mut three); + + // Make sure it's deterministic + assert_eq!(crate::merkle(&[one]), crate::merkle(&[one])); + + // Test a few basic structures + test(&[one]); + test(&[one, two]); + test(&[one, two, three]); + test(&[one, three]); +}