diff --git a/crypto/merkle/src/lib.rs b/crypto/merkle/src/lib.rs index 25f4ca504..0f40606c5 100644 --- a/crypto/merkle/src/lib.rs +++ b/crypto/merkle/src/lib.rs @@ -6,27 +6,6 @@ pub enum LeafRoute Left, Right, } -pub fn calc_merkle_root_legacy(hashes: impl ExactSizeIterator) -> Hash { - if hashes.len() == 0 { - return ZERO_HASH; - } - let next_pot = hashes.len().next_power_of_two(); - let vec_len = 2 * next_pot - 1; - let mut merkles = vec![None; vec_len]; - for (i, hash) in hashes.enumerate() { - merkles[i] = Some(hash); - } - let mut offset = next_pot; - for i in (0..vec_len - 1).step_by(2) { - if merkles[i].is_none() { - merkles[offset] = None; - } else { - merkles[offset] = Some(merkle_hash(merkles[i].unwrap(), merkles[i + 1].unwrap_or(ZERO_HASH))); - } - offset += 1 - } - merkles.last().unwrap().unwrap() -} fn derive_merkle_tree(hashes: impl ExactSizeIterator)->Vec>{ if hashes.len() == 0 { return vec!(Some(ZERO_HASH)); @@ -54,16 +33,19 @@ fn derive_merkle_tree(hashes: impl ExactSizeIterator)->Vec) -> Hash { - - // create the merkle witness for an arbitrary transaction index, - // the last element in the witness is always the merkle tree root. + // derive the merkle tree + // the last element in the tree is always the merkle tree root. let merkles=derive_merkle_tree(hashes); merkles.last().unwrap().unwrap() } -pub fn create_merkle_witness(hashes: impl ExactSizeIterator,leaf_index:usize) -> Vec<(Hash,LeafRoute -)>{ +pub fn create_merkle_witness(hashes: impl ExactSizeIterator,leaf_index:usize) +-> Result,String>{ + //leaf index must be smaller than amount of leaves, otherwise an error is returned let next_pot = hashes.len().next_power_of_two();//maximal number of leaves in last level of tree - let vec_len = 2 * next_pot - 1;//maximal number of nodes in mekle tree + if leaf_index>=next_pot { + return Err::, String>(format!("leaf index is {} but only {} possible leaves in merkle tree.",leaf_index,next_pot)); + } + let merkles=derive_merkle_tree(hashes); let mut witness_vec=vec![]; @@ -83,20 +65,18 @@ pub fn create_merkle_witness(hashes: impl ExactSizeIterator,leaf_in level_length=level_length/2; level_index=level_index/2; } - assert_eq!(level_start,vec_len-1); - assert_eq!(level_index,0); - witness_vec + // assert_eq!(level_start,vec_len-1); + // assert_eq!(level_index,0); + Ok(witness_vec) } pub fn verify_merkle_witness(witness_vec: &Vec<(Hash,LeafRoute)>,leaf_value:Hash,merkle_root_hash:Hash) ->bool{ let vec_len = witness_vec.len(); - // if(vec_len==0) - // panic!("witness vector is not of a valid size") let mut current_hash=leaf_value; - for i in 0..vec_len {//ignore root - //the LeafRoute describes which branch the leaf is at + for i in 0..vec_len { + //the LeafRoute describes which branch the leaf is at from bottom to top match witness_vec[i].1 { LeafRoute ::Right @@ -120,15 +100,37 @@ fn merkle_hash(left_node: Hash, right_node: Hash) -> Hash { #[cfg(test)] mod tests { use kaspa_hashes::Hash; - use kaspa_hashes::ZERO_HASH; - use super::{create_merkle_witness,calc_merkle_root_legacy,calc_merkle_root,verify_merkle_witness}; + use kaspa_hashes::{ZERO_HASH,HASH_SIZE}; + use super::{create_merkle_witness,calc_merkle_root,verify_merkle_witness}; + + // test the case of the empty tree which gets missed in the more general tests #[test] - fn test_witnesses_basic(){ - // test the case of the empty tree which gets missed in the more general test, alongside a single leaf and double leaf tree + fn test_witnesses_empty(){ let empty_vec=vec!(); + let empty_witness=create_merkle_witness(empty_vec.clone().into_iter(),0).unwrap(); + let merkle_root=calc_merkle_root(empty_vec.clone().into_iter()); + + //sanity checks + assert_eq!(empty_vec,vec!()); + assert_eq!(merkle_root,ZERO_HASH); + assert!(verify_merkle_witness(&empty_witness,ZERO_HASH,merkle_root)); + //check false is returned for other hashes + let hash_str_1 = "8e40af02265360d99f4ecf9ae9ebf8f7"; + let mut result = [0u8; HASH_SIZE];//HASH_SIZE=32 + let bytes:Vec = hash_str_1.as_bytes().to_vec(); + result[..bytes.len()].copy_from_slice(&bytes); + let hash1 = Hash::from_bytes(result); + assert_eq!(false,verify_merkle_witness(&empty_witness,hash1,merkle_root)); + //check error behaves as expected + assert!(create_merkle_witness(empty_vec.clone().into_iter(),1).is_err()); + + } + // test separately the single leaf and double leaf tree cases + #[test] + fn test_witnesses_basic(){ let hash_str_1 = "8e40af02265360d59f4ecf9ae9ebf8f7"; let hash_str_2 = "88700k0226a660d7a14ecfpae9eb0no2"; - let mut result = [0u8; 32]; + let mut result = [0u8; HASH_SIZE];//HASH_SIZE=32 let mut bytes:Vec = hash_str_1.as_bytes().to_vec(); result[..bytes.len()].copy_from_slice(&bytes); @@ -140,13 +142,14 @@ mod tests { let single_vec=vec!(hash1); let double_vec=vec!(hash1,hash2); - //Zero hash sent as leaf value when there is no leaf - assert!(verify_merkle_witness(&create_merkle_witness(empty_vec.clone().into_iter(),0),ZERO_HASH,calc_merkle_root(empty_vec.clone().into_iter()))); - - assert!(verify_merkle_witness(&create_merkle_witness(single_vec.clone().into_iter(),0),hash1,calc_merkle_root(single_vec.clone().into_iter()))); - assert!(verify_merkle_witness(&create_merkle_witness(double_vec.clone().into_iter(),0),hash1,calc_merkle_root(double_vec.clone().into_iter()))); - assert!(verify_merkle_witness(&create_merkle_witness(double_vec.clone().into_iter(),1),hash2,calc_merkle_root(double_vec.clone().into_iter()))); - + assert!(verify_merkle_witness(&create_merkle_witness(single_vec.clone().into_iter(),0).unwrap(),hash1,calc_merkle_root(single_vec.clone().into_iter()))); + assert!(verify_merkle_witness(&create_merkle_witness(double_vec.clone().into_iter(),0).unwrap(),hash1,calc_merkle_root(double_vec.clone().into_iter()))); + assert!(verify_merkle_witness(&create_merkle_witness(double_vec.clone().into_iter(),1).unwrap(),hash2,calc_merkle_root(double_vec.clone().into_iter()))); + //testing error behaviour + assert!(create_merkle_witness(single_vec.clone().into_iter(),1).is_err()); + assert!(create_merkle_witness(single_vec.clone().into_iter(),10).is_err()); + assert!(create_merkle_witness(double_vec.clone().into_iter(),2).is_err()); + assert!(create_merkle_witness(double_vec.clone().into_iter(),12).is_err()); } #[test] @@ -159,22 +162,22 @@ mod tests { for i in 0..TREE_LENGTH{ let mut new_bytes = bytes.clone(); new_bytes[i] = b'5'; - let mut result = [0u8; 32]; + let mut result = [0u8; HASH_SIZE];//HASH_SIZE=32 result[..new_bytes.len()].copy_from_slice(&new_bytes); let hash = Hash::from_bytes(result); hash_vec.push(hash); } - for j in 0..TREE_LENGTH{ + for j in 1..TREE_LENGTH{// disregard the 0 edge case as it is tested separately // let j=TREE_LENGTH-1; - for i in 0..j{ - let witness=create_merkle_witness(hash_vec.clone().into_iter().take(j),i); - let merkle1=calc_merkle_root(hash_vec.clone().into_iter().take(j)); - let merkle2=calc_merkle_root_legacy(hash_vec.clone().into_iter().take(j)); - assert_eq!(merkle1,merkle2); - assert!(verify_merkle_witness(&witness,hash_vec[i],merkle1)); - println!("{}",merkle1); + for leaf_index in 0..j{ + let witness=create_merkle_witness(hash_vec.clone().into_iter().take(j),leaf_index).unwrap(); + let merkle_root=calc_merkle_root(hash_vec.clone().into_iter().take(j)); + assert!(verify_merkle_witness(&witness,hash_vec[leaf_index],merkle_root)); } + //testing error behaviour + let leaf_index=2*j-1; + assert!(create_merkle_witness(hash_vec.clone().into_iter().take(j),leaf_index).is_err()); }