Skip to content

Commit

Permalink
added error functionality
Browse files Browse the repository at this point in the history
improved tests
removed legacy code
  • Loading branch information
ushinar committed Sep 21, 2024
1 parent bd2e18e commit 95bf4b1
Showing 1 changed file with 58 additions and 55 deletions.
113 changes: 58 additions & 55 deletions crypto/merkle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,6 @@ pub enum LeafRoute
Left,
Right,
}
pub fn calc_merkle_root_legacy(hashes: impl ExactSizeIterator<Item = Hash>) -> 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<Item = Hash>)->Vec<Option<Hash>>{
if hashes.len() == 0 {
return vec!(Some(ZERO_HASH));
Expand Down Expand Up @@ -54,16 +33,19 @@ fn derive_merkle_tree(hashes: impl ExactSizeIterator<Item = Hash>)->Vec<Option<H


pub fn calc_merkle_root(hashes: impl ExactSizeIterator<Item = Hash>) -> 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<Item = Hash>,leaf_index:usize) -> Vec<(Hash,LeafRoute
)>{
pub fn create_merkle_witness(hashes: impl ExactSizeIterator<Item = Hash>,leaf_index:usize)
-> Result<Vec<(Hash,LeafRoute)>,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::<Vec<(Hash,LeafRoute)>, 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![];

Expand All @@ -83,20 +65,18 @@ pub fn create_merkle_witness(hashes: impl ExactSizeIterator<Item = Hash>,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
Expand All @@ -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<u8> = 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<u8> = hash_str_1.as_bytes().to_vec();
result[..bytes.len()].copy_from_slice(&bytes);
Expand All @@ -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]
Expand All @@ -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());
}


Expand Down

0 comments on commit 95bf4b1

Please sign in to comment.