diff --git a/pallets/helpers/Cargo.toml b/pallets/helpers/Cargo.toml index 54d2641..61103e1 100644 --- a/pallets/helpers/Cargo.toml +++ b/pallets/helpers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ghost-helpers" -version = "0.0.11" +version = "0.0.12" description = "Cryptographic utility suite for custom runtimes: optimized Bitmaps, UTXO parsing, Merkle Tree proofs, and Hash Chain components." license.workspace = true authors.workspace = true diff --git a/pallets/helpers/src/hash_chain.rs b/pallets/helpers/src/hash_chain.rs index 35e1229..0f6ecbd 100644 --- a/pallets/helpers/src/hash_chain.rs +++ b/pallets/helpers/src/hash_chain.rs @@ -1,19 +1,5 @@ use ghost_traits::hashing::GhostHasher; -fn combine_values(left: V, right: V) -> H::Hash -where - H: GhostHasher, - V: AsRef<[u8]>, -{ - let hash_len = H::hash_len(); - let mut combined = sp_std::vec![0u8; hash_len * 2]; - - combined[..hash_len].copy_from_slice(left.as_ref()); - combined[hash_len..].copy_from_slice(right.as_ref()); - - H::hash(&combined) -} - pub fn cumulative_hash(raw_values: S) -> H::Hash where H: GhostHasher, @@ -24,7 +10,7 @@ where .into_iter() .fold(H::empty(), |acc_hash, raw_value| { let hashed_value = H::hash(raw_value.as_ref()); - combine_values::(acc_hash, hashed_value) + H::combine_hashes(acc_hash, hashed_value) }) } @@ -47,7 +33,7 @@ where iter.fold(current_hash, |acc_hash, raw_value| { let next_hash = H::from_slice(raw_value.as_ref()); - combine_values::(acc_hash, next_hash) + H::combine_hashes(acc_hash, next_hash) }) } @@ -94,45 +80,14 @@ where mod tests { use super::*; use sp_core::H256; - use sp_io::hashing::{blake2_256, sha2_256}; use sp_std::vec::Vec; - pub struct TestBlake2Hasher; - impl GhostHasher for TestBlake2Hasher { - type Hash = H256; - type HashBytes = [u8; 32]; - - fn hash(data: &[u8]) -> Self::Hash { - H256::from(blake2_256(data)) - } - fn empty() -> Self::Hash { - H256::zero() - } - fn hash_len() -> usize { - H256::len_bytes() - } - } - - pub struct TestSha2Hasher; - impl GhostHasher for TestSha2Hasher { - type Hash = H256; - type HashBytes = [u8; 32]; - fn hash(data: &[u8]) -> Self::Hash { - let first_pass: [u8; 32] = sha2_256(data); - let second_pass: [u8; 32] = sha2_256(&first_pass); - - H256::from(second_pass) - } - fn hash_len() -> usize { - H256::len_bytes() - } - fn empty() -> Self::Hash { - H256::zero() - } - } + use crate::{ + SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher, + }; fn mock_sequential_hash(header: &[u8; 80]) -> H256 { - sequential_hash::(core::iter::once(header)) + sequential_hash::(core::iter::once(header)) } fn create_header(prev_hash: [u8; 32]) -> [u8; 80] { @@ -141,89 +96,101 @@ mod tests { header } - #[test] - fn test_generate_empty_values() { - let empty_list: Vec> = sp_std::vec![]; - let result = cumulative_hash::(empty_list); - assert_eq!(H256::zero(), result); + macro_rules! run_hasher_tests { + ($hasher_type:ty, $mod_name:ident) => { + mod $mod_name { + use super::*; + + #[test] + fn test_generate_empty_values() { + let empty_list: Vec> = sp_std::vec![]; + let result = cumulative_hash::<$hasher_type, _>(empty_list); + assert_eq!(H256::zero(), result); + } + + #[test] + fn test_cumulative_hash_determinism_and_avalanche() { + let dataset_1 = sp_std::vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]; + let dataset_2 = sp_std::vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]; + let dataset_3 = sp_std::vec![vec![9, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]; + + let hash_1 = cumulative_hash::<$hasher_type, _>(dataset_1); + let hash_2 = cumulative_hash::<$hasher_type, _>(dataset_2); + let hash_3 = cumulative_hash::<$hasher_type, _>(dataset_3); + + assert_eq!(hash_1, hash_2); + assert_ne!(hash_1, hash_3); + assert_ne!(hash_2, hash_3); + } + + #[test] + fn test_cumulative_hash_order_sensitive() { + let dataset_forward = sp_std::vec![sp_std::vec![1, 1, 1], sp_std::vec![2, 2, 2]]; + let dataset_reversed = sp_std::vec![sp_std::vec![2, 2, 2], sp_std::vec![1, 1, 1]]; + + let hash_forward = cumulative_hash::<$hasher_type, _>(dataset_forward); + let hash_reversed = cumulative_hash::<$hasher_type, _>(dataset_reversed); + + assert_ne!(hash_forward, hash_reversed); + } + + #[test] + fn test_cumulative_hash_with_slices() { + let slice_data: &[&[u8]] = &[&[1, 2, 3], &[4, 5, 6]]; + let hash_from_slice = cumulative_hash::<$hasher_type, _>(slice_data.iter()); + assert_ne!(hash_from_slice, H256::zero()); + } + + #[test] + fn test_sequential_hash_empty() { + let empty_list: Vec> = sp_std::vec![]; + let result = sequential_hash::<$hasher_type, _>(empty_list); + assert_eq!(H256::zero(), result); + } + + #[test] + fn test_sequential_hash_single_element() { + let single_item = sp_std::vec![sp_std::vec![1, 2, 3]]; + let result = sequential_hash::<$hasher_type, _>(single_item); + let expected = <$hasher_type>::hash(&[1, 2, 3]); + assert_eq!(result, expected); + } + + #[test] + fn test_sequential_hash_determinism_and_order() { + let data_1 = sp_std::vec![sp_std::vec![1], sp_std::vec![2], sp_std::vec![3]]; + let data_2 = sp_std::vec![sp_std::vec![1], sp_std::vec![2], sp_std::vec![3]]; + let data_reversed = sp_std::vec![sp_std::vec![3], sp_std::vec![2], sp_std::vec![1]]; + + let hash_1 = sequential_hash::<$hasher_type, _>(data_1); + let hash_2 = sequential_hash::<$hasher_type, _>(data_2); + let hash_reversed = sequential_hash::<$hasher_type, _>(data_reversed); + + assert_eq!(hash_1, hash_2); + assert_ne!(hash_1, hash_reversed); + } + + #[test] + fn test_sequential_vs_cumulative_hash() { + let dataset = sp_std::vec![sp_std::vec![1, 2, 3], sp_std::vec![4, 5, 6]]; + let seq_hash = sequential_hash::<$hasher_type, _>(dataset.clone()); + let cum_hash = cumulative_hash::<$hasher_type, _>(dataset); + assert_ne!(seq_hash, cum_hash); + } + + #[test] + fn test_sequential_hash_with_slices() { + let slice_data: &[&[u8]] = &[&[10, 20], &[30, 40]]; + let result = sequential_hash::<$hasher_type, _>(slice_data.iter()); + assert_ne!(result, H256::zero()); + } + } + } } - #[test] - fn test_cumulative_hash_determinism_and_avalanche() { - let dataset_1 = sp_std::vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]; - let dataset_2 = sp_std::vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]; - let dataset_3 = sp_std::vec![vec![9, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]; - - let hash_1 = cumulative_hash::(dataset_1); - let hash_2 = cumulative_hash::(dataset_2); - let hash_3 = cumulative_hash::(dataset_3); - - assert_eq!(hash_1, hash_2); - assert_ne!(hash_1, hash_3); - assert_ne!(hash_2, hash_3); - } - - #[test] - fn test_cumulative_hash_order_sensitive() { - let dataset_forward = sp_std::vec![sp_std::vec![1, 1, 1], sp_std::vec![2, 2, 2]]; - let dataset_reversed = sp_std::vec![sp_std::vec![2, 2, 2], sp_std::vec![1, 1, 1]]; - - let hash_forward = cumulative_hash::(dataset_forward); - let hash_reversed = cumulative_hash::(dataset_reversed); - - assert_ne!(hash_forward, hash_reversed); - } - - #[test] - fn test_cumulative_hash_with_slices() { - let slice_data: &[&[u8]] = &[&[1, 2, 3], &[4, 5, 6]]; - let hash_from_slice = cumulative_hash::(slice_data.iter()); - assert_ne!(hash_from_slice, H256::zero()); - } - - #[test] - fn test_sequential_hash_empty() { - let empty_list: Vec> = sp_std::vec![]; - let result = sequential_hash::(empty_list); - assert_eq!(H256::zero(), result); - } - - #[test] - fn test_sequential_hash_single_element() { - let single_item = sp_std::vec![sp_std::vec![1, 2, 3]]; - let result = sequential_hash::(single_item); - let expected = TestBlake2Hasher::hash(&[1, 2, 3]); - assert_eq!(result, expected); - } - - #[test] - fn test_sequential_hash_determinism_and_order() { - let data_1 = sp_std::vec![sp_std::vec![1], sp_std::vec![2], sp_std::vec![3]]; - let data_2 = sp_std::vec![sp_std::vec![1], sp_std::vec![2], sp_std::vec![3]]; - let data_reversed = sp_std::vec![sp_std::vec![3], sp_std::vec![2], sp_std::vec![1]]; - - let hash_1 = sequential_hash::(data_1); - let hash_2 = sequential_hash::(data_2); - let hash_reversed = sequential_hash::(data_reversed); - - assert_eq!(hash_1, hash_2); - assert_ne!(hash_1, hash_reversed); - } - - #[test] - fn test_sequential_vs_cumulative_hash() { - let dataset = sp_std::vec![sp_std::vec![1, 2, 3], sp_std::vec![4, 5, 6]]; - let seq_hash = sequential_hash::(dataset.clone()); - let cum_hash = cumulative_hash::(dataset); - assert_ne!(seq_hash, cum_hash); - } - - #[test] - fn test_sequential_hash_with_slices() { - let slice_data: &[&[u8]] = &[&[10, 20], &[30, 40]]; - let result = sequential_hash::(slice_data.iter()); - assert_ne!(result, H256::zero()); - } + run_hasher_tests!(SubstrateBlake2Hasher, blake2_tests); + run_hasher_tests!(SubstrateKeccakHasher, keccak_tests); + run_hasher_tests!(UtxoSha2Hasher, sha2_tests); #[test] fn test_verify_in_current_block_with_empty_ancestry() { @@ -234,7 +201,7 @@ mod tests { trusted_bytes.reverse(); let trusted_top_block_hash = H256::from(trusted_bytes); - let result = verify_hash_ancestry::( + let result = verify_hash_ancestry::( &tx_header, &[], trusted_top_block_hash, @@ -256,7 +223,7 @@ mod tests { let trusted_top_block_hash = H256::from(trusted_bytes); let ancestry = [header_101]; - let result = verify_hash_ancestry::( + let result = verify_hash_ancestry::( &tx_header_100, &ancestry, trusted_top_block_hash, @@ -284,7 +251,7 @@ mod tests { let trusted_top_block_hash = H256::from(trusted_bytes); let ancestry = [header_101, header_102, header_103]; - let result = verify_hash_ancestry::( + let result = verify_hash_ancestry::( &header_100, &ancestry, trusted_top_block_hash, @@ -305,7 +272,7 @@ mod tests { let trusted_top_block_hash = H256::from(trusted_bytes); let ancestry = [broken_header_101]; - let result = verify_hash_ancestry::( + let result = verify_hash_ancestry::( &header_100, &ancestry, trusted_top_block_hash, diff --git a/pallets/helpers/src/lib.rs b/pallets/helpers/src/lib.rs index c13576b..f871d87 100644 --- a/pallets/helpers/src/lib.rs +++ b/pallets/helpers/src/lib.rs @@ -48,53 +48,66 @@ where value - f } -pub struct SubstrateBlake2Hasher; -impl GhostHasher for SubstrateBlake2Hasher { - type Hash = H256; - type HashBytes = [u8; 32]; - fn hash(data: &[u8]) -> Self::Hash { - H256::from(blake2_256(data)) - } - fn hash_len() -> usize { - H256::len_bytes() - } - fn empty() -> Self::Hash { - H256::zero() - } +macro_rules! impl_ghost_hasher { + ( + struct $name:ident; + hash_type: $hash_type:ty; + hash_bytes_len: $hash_bytes_len:expr; + fn hash($data:ident) -> $hash_res:expr + ) => { + pub struct $name; + + impl GhostHasher for $name { + type Hash = $hash_type; + type HashBytes = [u8; $hash_bytes_len]; + + fn hash($data: &[u8]) -> Self::Hash { + $hash_res + } + + fn hash_len() -> usize { + $hash_bytes_len + } + + fn empty() -> Self::Hash { + <$hash_type>::zero() + } + + fn combine_hashes(left: Self::Hash, right: Self::Hash) -> Self::Hash { + let mut combined = [0u8; $hash_bytes_len * 2]; + combined[..$hash_bytes_len].copy_from_slice(left.as_ref()); + combined[$hash_bytes_len..].copy_from_slice(right.as_ref()); + Self::hash(&combined) + } + } + }; } -pub struct SubstrateKeccakHasher; -impl GhostHasher for SubstrateKeccakHasher { - type Hash = H256; - type HashBytes = [u8; 32]; - fn hash(data: &[u8]) -> Self::Hash { - H256::from(keccak_256(data)) - } - fn hash_len() -> usize { - H256::len_bytes() - } - fn empty() -> Self::Hash { - H256::zero() - } -} +impl_ghost_hasher!( + struct SubstrateBlake2Hasher; + hash_type: H256; + hash_bytes_len: 32; + fn hash(data) -> H256::from(blake2_256(data)) +); -pub struct UtxoSha2Hasher; -impl GhostHasher for UtxoSha2Hasher { - type Hash = H256; - type HashBytes = [u8; 32]; - fn hash(data: &[u8]) -> Self::Hash { +impl_ghost_hasher!( + struct SubstrateKeccakHasher; + hash_type: H256; + hash_bytes_len: 32; + fn hash(data) -> H256::from(keccak_256(data)) +); + +impl_ghost_hasher!( + struct UtxoSha2Hasher; + hash_type: H256; + hash_bytes_len: 32; + fn hash(data) -> { let first_pass: [u8; 32] = sha2_256(data); let second_pass: [u8; 32] = sha2_256(&first_pass); H256::from(second_pass) } - fn hash_len() -> usize { - H256::len_bytes() - } - fn empty() -> Self::Hash { - H256::zero() - } -} +); #[cfg(test)] mod tests { diff --git a/pallets/helpers/src/merkle_tree.rs b/pallets/helpers/src/merkle_tree.rs index b482cf0..cb109ff 100644 --- a/pallets/helpers/src/merkle_tree.rs +++ b/pallets/helpers/src/merkle_tree.rs @@ -139,23 +139,8 @@ where mod tests { use super::*; use sp_core::H256; - use sp_io::hashing::blake2_256; - pub struct TestBlake2Hasher; - impl GhostHasher for TestBlake2Hasher { - type Hash = H256; - type HashBytes = [u8; 32]; - - fn hash(data: &[u8]) -> Self::Hash { - H256::from(blake2_256(data)) - } - fn empty() -> Self::Hash { - H256::zero() - } - fn hash_len() -> usize { - H256::len_bytes() - } - } + use crate::SubstrateBlake2Hasher; #[test] fn test_generate_tree_perfect_power_of_two() { @@ -167,7 +152,7 @@ mod tests { (3, sp_std::vec![4]), ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -176,28 +161,28 @@ mod tests { assert_eq!(tree.len(), 7); - let h0 = TestBlake2Hasher::hash(&[ &[0u8], [1].as_slice() ].concat()); - let h1 = TestBlake2Hasher::hash(&[ &[0u8], [2].as_slice() ].concat()); - let h2 = TestBlake2Hasher::hash(&[ &[0u8], [3].as_slice() ].concat()); - let h3 = TestBlake2Hasher::hash(&[ &[0u8], [4].as_slice() ].concat()); + let h0 = SubstrateBlake2Hasher::hash(&[ &[0u8], [1].as_slice() ].concat()); + let h1 = SubstrateBlake2Hasher::hash(&[ &[0u8], [2].as_slice() ].concat()); + let h2 = SubstrateBlake2Hasher::hash(&[ &[0u8], [3].as_slice() ].concat()); + let h3 = SubstrateBlake2Hasher::hash(&[ &[0u8], [4].as_slice() ].concat()); let mut c1 = [0u8; 65]; c1[0] = NODE_PREFIX; c1[1..33].copy_from_slice(h0.as_ref()); c1[33..].copy_from_slice(h1.as_ref()); - let parent_left = TestBlake2Hasher::hash(&c1); + let parent_left = SubstrateBlake2Hasher::hash(&c1); let mut c2 = [0u8; 65]; c2[0] = NODE_PREFIX; c2[1..33].copy_from_slice(h2.as_ref()); c2[33..].copy_from_slice(h3.as_ref()); - let parent_right = TestBlake2Hasher::hash(&c2); + let parent_right = SubstrateBlake2Hasher::hash(&c2); let mut c_root = [0u8; 65]; c_root[0] = NODE_PREFIX; c_root[1..33].copy_from_slice(parent_left.as_ref()); c_root[33..].copy_from_slice(parent_right.as_ref()); - let expected_root = TestBlake2Hasher::hash(&c_root); + let expected_root = SubstrateBlake2Hasher::hash(&c_root); assert_eq!(tree.last().unwrap(), &expected_root); } @@ -211,7 +196,7 @@ mod tests { (2, sp_std::vec![3]), ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -220,21 +205,21 @@ mod tests { let mut empty_data = sp_std::vec![LEAF_PREFIX]; empty_data.extend_from_slice(&H256::zero().to_fixed_bytes()); - let empty_hash = TestBlake2Hasher::hash(&empty_data); + let empty_hash = SubstrateBlake2Hasher::hash(&empty_data); assert_eq!(tree.len(), 7); assert_eq!(tree[3], empty_hash); let mut leaf2_data = sp_std::vec![LEAF_PREFIX]; leaf2_data.extend_from_slice(&[3]); - let h2 = TestBlake2Hasher::hash(&leaf2_data); + let h2 = SubstrateBlake2Hasher::hash(&leaf2_data); let mut combined_right = [0u8; 65]; combined_right[0] = NODE_PREFIX; combined_right[1..33].copy_from_slice(h2.as_ref()); combined_right[33..].copy_from_slice(empty_hash.as_ref()); - let expected_parent_right = TestBlake2Hasher::hash(&combined_right); + let expected_parent_right = SubstrateBlake2Hasher::hash(&combined_right); assert_eq!(tree[5], expected_parent_right); } @@ -247,17 +232,17 @@ mod tests { let data_3 = sp_std::vec![(0, sp_std::vec![101]), (1, sp_std::vec![200])]; let tree_1 = - generate_tree::(max_index, data_1, |(i, b)| { + generate_tree::(max_index, data_1, |(i, b)| { Ok((i, b)) }) .unwrap(); let tree_2 = - generate_tree::(max_index, data_2, |(i, b)| { + generate_tree::(max_index, data_2, |(i, b)| { Ok((i, b)) }) .unwrap(); let tree_3 = - generate_tree::(max_index, data_3, |(i, b)| { + generate_tree::(max_index, data_3, |(i, b)| { Ok((i, b)) }) .unwrap(); @@ -271,7 +256,7 @@ mod tests { let max_index = 0u32; let raw_data = sp_std::vec![(0, sp_std::vec![42])]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -279,7 +264,7 @@ mod tests { .unwrap(); assert_eq!(tree.len(), 1); - assert_eq!(tree[0], TestBlake2Hasher::hash(&vec![LEAF_PREFIX, 42])); + assert_eq!(tree[0], SubstrateBlake2Hasher::hash(&vec![LEAF_PREFIX, 42])); } #[test] @@ -292,7 +277,7 @@ mod tests { (3, sp_std::vec![4]), ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -302,13 +287,13 @@ mod tests { let root = *tree.last().unwrap(); let target_index = 2u32; - let proof = generate_proof::(&tree, max_index, target_index); + let proof = generate_proof::(&tree, max_index, target_index); assert_eq!(proof.len(), 2); let preimage = sp_std::vec![3]; let is_valid = - verify_tree_proof::(&preimage, &proof, root, target_index); + verify_tree_proof::(&preimage, &proof, root, target_index); assert!(is_valid); } @@ -323,7 +308,7 @@ mod tests { (3, sp_std::vec![4]), ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -333,13 +318,13 @@ mod tests { let root = *tree.last().unwrap(); let target_index = 2u32; - let proof = generate_proof::(&tree, max_index, target_index); + let proof = generate_proof::(&tree, max_index, target_index); assert_eq!(proof.len(), 2); let preimage = sp_std::vec![3]; let is_valid = - verify_tree_proof::(&preimage, &proof, root, target_index + 1); + verify_tree_proof::(&preimage, &proof, root, target_index + 1); assert!(!is_valid); } @@ -354,7 +339,7 @@ mod tests { (3, sp_std::vec![40]), ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -369,19 +354,19 @@ mod tests { let parent_left = tree[4]; // hash(h0 + h1) let parent_right = tree[5]; // hash(h2 + h3) - let proof_for_0 = generate_proof::(&tree, max_index, 0); + let proof_for_0 = generate_proof::(&tree, max_index, 0); assert_eq!(proof_for_0[0], h1); assert_eq!(proof_for_0[1], parent_right); - let proof_for_1 = generate_proof::(&tree, max_index, 1); + let proof_for_1 = generate_proof::(&tree, max_index, 1); assert_eq!(proof_for_1[0], h0); assert_eq!(proof_for_1[1], parent_right); - let proof_for_2 = generate_proof::(&tree, max_index, 2); + let proof_for_2 = generate_proof::(&tree, max_index, 2); assert_eq!(proof_for_2[0], h3); assert_eq!(proof_for_2[1], parent_left); - let proof_for_3 = generate_proof::(&tree, max_index, 3); + let proof_for_3 = generate_proof::(&tree, max_index, 3); assert_eq!(proof_for_3[0], h2); assert_eq!(proof_for_3[1], parent_left); } @@ -395,23 +380,23 @@ mod tests { (2, sp_std::vec![3]), ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), ) .unwrap(); - let proof = generate_proof::(&tree, max_index, 2); + let proof = generate_proof::(&tree, max_index, 2); let mut empty_data = sp_std::vec![LEAF_PREFIX]; empty_data.extend_from_slice(&H256::zero().to_fixed_bytes()); - let empty_hash = TestBlake2Hasher::hash(&empty_data); + let empty_hash = SubstrateBlake2Hasher::hash(&empty_data); assert_eq!(proof[0], empty_hash); let root = *tree.last().unwrap(); let is_valid = - verify_tree_proof::(&sp_std::vec![3], &proof, root, 2); + verify_tree_proof::(&sp_std::vec![3], &proof, root, 2); assert!(is_valid); } @@ -420,14 +405,14 @@ mod tests { let max_index = 0u32; let raw_data = sp_std::vec![(0, sp_std::vec![99])]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), ) .unwrap(); - let proof = generate_proof::(&tree, max_index, 0); + let proof = generate_proof::(&tree, max_index, 0); assert!(proof.is_empty()); } @@ -446,7 +431,7 @@ mod tests { (3, leaf_3.clone()) ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -460,30 +445,30 @@ mod tests { let h2 = tree[2]; let h3 = tree[3]; - let proof_for_1 = generate_proof::(&tree, max_index, 1); + let proof_for_1 = generate_proof::(&tree, max_index, 1); assert_eq!(proof_for_1[0], h0); - let is_valid_1 = verify_tree_proof::(&leaf_1, &proof_for_1, root, 1); + let is_valid_1 = verify_tree_proof::(&leaf_1, &proof_for_1, root, 1); assert!(is_valid_1); - let proof_for_2 = generate_proof::(&tree, max_index, 2); + let proof_for_2 = generate_proof::(&tree, max_index, 2); assert_eq!(proof_for_2[0], h3); - let is_valid_2 = verify_tree_proof::(&leaf_2, &proof_for_2, root, 2); + let is_valid_2 = verify_tree_proof::(&leaf_2, &proof_for_2, root, 2); assert!(is_valid_2); - let proof_for_0 = generate_proof::(&tree, max_index, 0); + let proof_for_0 = generate_proof::(&tree, max_index, 0); assert_eq!(proof_for_0[0], h1); - assert!(verify_tree_proof::( + assert!(verify_tree_proof::( &leaf_0, &proof_for_0, root, 0 )); - let proof_for_3 = generate_proof::(&tree, max_index, 3); + let proof_for_3 = generate_proof::(&tree, max_index, 3); assert_eq!(proof_for_3[0], h2); - assert!(verify_tree_proof::( + assert!(verify_tree_proof::( &leaf_3, &proof_for_3, root, @@ -493,12 +478,12 @@ mod tests { let mut bad_proof = proof_for_1.clone(); bad_proof[0] = H256::random(); let is_valid_bad_proof = - verify_tree_proof::(&leaf_1, &bad_proof, root, 1); + verify_tree_proof::(&leaf_1, &bad_proof, root, 1); assert!(!is_valid_bad_proof); let bad_preimage = vec![99u8]; let is_valid_bad_preimage = - verify_tree_proof::(&bad_preimage, &proof_for_1, root, 1); + verify_tree_proof::(&bad_preimage, &proof_for_1, root, 1); assert!(!is_valid_bad_preimage); } @@ -511,7 +496,7 @@ mod tests { raw_data.push((i, sp_std::vec![i as u8])); } - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -525,18 +510,18 @@ mod tests { let target_index = 11u32; let preimage = vec![target_index as u8]; - let proof = generate_proof::(&tree, max_index, target_index); + let proof = generate_proof::(&tree, max_index, target_index); assert_eq!(proof.len(), 4); let h10 = tree[10]; assert_eq!(proof[0], h10); let is_valid = - verify_tree_proof::(&preimage, &proof, root, target_index); + verify_tree_proof::(&preimage, &proof, root, target_index); assert!(is_valid); let is_valid_wrong_index = - verify_tree_proof::(&preimage, &proof, root, 4); + verify_tree_proof::(&preimage, &proof, root, 4); assert!(!is_valid_wrong_index); } @@ -550,7 +535,7 @@ mod tests { (3, sp_std::vec![4]), ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -560,13 +545,13 @@ mod tests { let root = *tree.last().unwrap(); let target_index = 3u32; - let proof = generate_proof::(&tree, max_index, target_index); + let proof = generate_proof::(&tree, max_index, target_index); assert_eq!(proof.len(), 2); let preimage = sp_std::vec![4]; let is_valid = - verify_tree_proof::(&preimage, &proof, root, target_index); + verify_tree_proof::(&preimage, &proof, root, target_index); assert!(is_valid); } @@ -581,7 +566,7 @@ mod tests { (3, sp_std::vec![4]), ]; - let tree = generate_tree::( + let tree = generate_tree::( max_index, raw_data, |(index, bytes)| Ok((index, bytes)), @@ -590,13 +575,13 @@ mod tests { let root = *tree.last().unwrap(); - let proof = generate_proof::(&tree, max_index, 3u32); + let proof = generate_proof::(&tree, max_index, 3u32); let target_index = 4u32; let preimage = sp_std::vec![4]; let is_valid = - verify_tree_proof::(&preimage, &proof, root, target_index); + verify_tree_proof::(&preimage, &proof, root, target_index); assert!(!is_valid); } diff --git a/pallets/traits/Cargo.toml b/pallets/traits/Cargo.toml index e243aa3..373c90d 100644 --- a/pallets/traits/Cargo.toml +++ b/pallets/traits/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ghost-traits" -version = "0.4.6" +version = "0.4.7" description = "Shared traits including `GhostHasher`, `NetworkDataBasicHandler`, `BoundedBTreeMap`, `MerkleTree` and more." license.workspace = true authors.workspace = true diff --git a/pallets/traits/src/hashing.rs b/pallets/traits/src/hashing.rs index 0816949..f115b76 100644 --- a/pallets/traits/src/hashing.rs +++ b/pallets/traits/src/hashing.rs @@ -21,6 +21,7 @@ pub trait GhostHasher { bytes } + fn combine_hashes(left: Self::Hash, right: Self::Hash) -> Self::Hash; fn hash(data: &[u8]) -> Self::Hash; fn empty() -> Self::Hash; fn hash_len() -> usize;