diff --git a/Cargo.toml b/Cargo.toml index fabf37a..bd3f217 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ borsh = { version = "1" } serde_json = "1.0.96" postcard = { version = "1.0.4", features = ["use-std"] } tendermint = { version = "0.35.0" } +hex = "0.4.3" [features] default = ["std"] diff --git a/src/simple_merkle/db.rs b/src/simple_merkle/db.rs index 7b94438..b5b267e 100644 --- a/src/simple_merkle/db.rs +++ b/src/simple_merkle/db.rs @@ -123,3 +123,19 @@ impl PreimageWriter for NoopDb { } impl PreimageDb for NoopDb {} + +#[cfg(test)] +mod test { + #[test] + fn test_mem_db() { + use super::*; + let mut db = MemDb::::default(); + let leaf = Node::Leaf(vec![1, 2, 3]); + db.put(1, leaf.clone()); + assert_eq!(db.get(&1), Some(&leaf)); + + let node = Node::Inner(1, 2); + db.put(2, node.clone()); + assert_eq!(db.get(&2), Some(&node)); + } +} diff --git a/src/simple_merkle/proof.rs b/src/simple_merkle/proof.rs index 137c048..41ee981 100644 --- a/src/simple_merkle/proof.rs +++ b/src/simple_merkle/proof.rs @@ -3,7 +3,7 @@ use core::{cmp::Ordering, ops::Range}; use super::{ db::NoopDb, error::RangeProofError, - tree::{MerkleHash, MerkleTree}, + tree::{MerkleHash, MerkleTree, next_smaller_po2}, utils::compute_num_left_siblings, }; use crate::maybestd::vec::Vec; @@ -56,12 +56,87 @@ where self.start_idx() as usize, ) } + + /// verify range with leaves data + pub fn verify_with_leaves_data( + &self, + root: &M::Output, + leaves_data: &[&[u8]], + ) -> Result<(), RangeProofError> { + if leaves_data.len() != self.range_len() { + return Err(RangeProofError::WrongAmountOfLeavesProvided); + } + + let hasher = M::default(); + let mut leaves_hash = vec![]; + leaves_data.iter().for_each(|x| { leaves_hash.push( hasher.hash_leaf(x))}); + self.verify_range(root, &leaves_hash) + } } impl Proof where M: MerkleHash, { + /// Create a new proof from a merkle path which generate by celestia + pub fn from_celestia_merkle_path( + merkle_path: &[M::Output], + index: u32, + total: u32, + ) -> Self { + let mut new_proof = vec![]; + Self::covert_merkle_path(merkle_path, &mut new_proof, index as usize, total as usize); + let end = if total == 0{ + 0 + }else { + index+1 + }; + Self{ + siblings: new_proof, + range:index..end, + } + } + + fn covert_merkle_path( + merkle_path: &[M::Output], + new_proof: &mut Vec, + index: usize, + total: usize, + ) { + // 只有一个Leaf的树merkle path为null + if merkle_path.len() == 0{ + return; + } + // 基本案例:如果仅剩一个哈希,则返回 + if merkle_path.len() == 1 { + new_proof.push(merkle_path[0].clone()); + return + } + + // 计算拆分点 + let split_point = next_smaller_po2(total); + // 递归处理左子树 + if index < split_point { + Self::covert_merkle_path( + &merkle_path[..merkle_path.len() - 1], + new_proof, + index, + split_point, + ); + // 在左子树之后添加当前节点 + new_proof.push(merkle_path[merkle_path.len() - 1].clone()); + } else { + // 递归处理右子树 + new_proof.push(merkle_path[merkle_path.len() - 1].clone()); + Self::covert_merkle_path( + &merkle_path[..merkle_path.len() - 1], + new_proof, + index - split_point, + total - split_point, + ); + } + } + /// Verify a range proof pub fn verify_range_with_hasher( &self, @@ -169,3 +244,509 @@ where None } } + +#[cfg(test)] +mod test { + use super::*; + use crate::TmSha2Hasher; + use hex; + + /** + * TEST VECTORS + * + * 0x01 + * 0x02 + * 0x03 + * 0x04 + * 0x05 + * 0x06 + * 0x07 + * 0x08 + * + * + * 0xb413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2 + * 0xfcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f + * 0x583c7dfb7b3055d99465544032a571e10a134b1b6f769422bbb71fd7fa167a5d + * 0x4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4 + * 0x9f1afa4dc124cba73134e82ff50f17c8f7164257c79fed9a13f5943a6acb8e3d + * 0x40d88127d4d31a3891f41598eeed41174e5bc89b1eb9bbd66a8cbfc09956a3fd + * 0x2ecd8a6b7d2845546659ad4cf443533cf921b19dc81fa83934e83821b4dfdcb7 + * 0xb4c43b50bf245bd727623e3c775a8fcfb8d823d00b57dd65f7f79dd33f126315 + * + * 0x6bcf0e2e93e0a18e22789aee965e6553f4fbe93f0acfc4a705d691c8311c4965 + * 0x78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d + * 0x90eeb2c4a04ec33ee4dd2677593331910e4203db4fcc120a6cdb95b13cfe83f0 + * 0x28c01722dd8dd05b63bcdeb6878bc2c083118cc2b170646d6b842d0bdbdc9d29 + * + * 0xfa02d31a63cc11cc624881e52af14af7a1c6ab745efa71021cb24086b9b1793f + * 0x4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09 + * + * 0xc1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071 + * + */ + #[test] + fn test_verify_none() { + let root= TmSha2Hasher::EMPTY_ROOT; + let siblings: Vec<[u8; 32]> = vec![]; + let proof = Proof::::from_celestia_merkle_path(&siblings, 0, 0); + let result = proof.verify_with_leaves_data(&root, &vec![]); + assert!(result.is_ok()); + + // let root = TmSha2Hasher::EMPTY_ROOT; + // let proof = Proof:: { + // siblings: vec![], + // range: 0..0, + // }; + // let result = proof.verify_with_leaves_data(&root, &[]); + // assert!(result.is_err()); + } + + #[test] + fn test_verify_one_leaf_empty() { + let root:[u8;32]= hex::decode("6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d").unwrap().try_into().unwrap(); + let siblings: Vec<[u8; 32]> = vec![]; + let proof = Proof::::from_celestia_merkle_path(&siblings, 0, 1); + let result = + proof.verify_with_leaves_data(&root, &vec!["".as_bytes()]); + assert!(result.is_ok()); + } + + #[test] + fn test_verify_one_leaf_some() { + let root:[u8;32]= hex::decode("48c90c8ae24688d6bef5d48a30c2cc8b6754335a8db21793cc0a8e3bed321729").unwrap().try_into().unwrap(); + let siblings: Vec<[u8; 32]> = vec![]; + let proof = Proof::::from_celestia_merkle_path(&siblings, 0, 1); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("deadbeef").unwrap().as_slice()]); + assert!(result.is_ok()); + } + + #[test] + fn test_verify_one_leaf_01() { + let root:[u8;32]= hex::decode("b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2").unwrap().try_into().unwrap(); + let siblings: Vec<[u8; 32]> = vec![]; + let proof = Proof::::from_celestia_merkle_path(&siblings, 0, 1); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("01").unwrap().as_slice()]); + assert!(result.is_ok()); + } + + #[test] + fn test_verify_leaf_one_of_eight() { + let root:[u8;32]= hex::decode("c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "fcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f", + "78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 0, 8); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("01").unwrap().as_slice()]); + assert!(result.is_ok()); + } + + #[test] + fn test_verify_leaf_two_of_eight() { + let root:[u8;32]= hex::decode("c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2", + "78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 1, 8); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("02").unwrap().as_slice()]); + assert!(result.is_ok()); + } + + #[test] + fn test_verify_leaf_three_of_eight() { + let root:[u8;32]= hex::decode("c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + "6bcf0e2e93e0a18e22789aee965e6553f4fbe93f0acfc4a705d691c8311c4965", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 2, 8); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("03").unwrap().as_slice()]); + assert!(result.is_ok()); + } + + #[test] + fn test_verify_leaf_seven_of_eight() { + let root:[u8;32]= hex::decode("c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "b4c43b50bf245bd727623e3c775a8fcfb8d823d00b57dd65f7f79dd33f126315", + "90eeb2c4a04ec33ee4dd2677593331910e4203db4fcc120a6cdb95b13cfe83f0", + "fa02d31a63cc11cc624881e52af14af7a1c6ab745efa71021cb24086b9b1793f", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 6, 8); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("07").unwrap().as_slice()]); + assert!(result.is_ok()); + } + + #[test] + fn test_verify_leaf_eight_of_eight() { + let root:[u8;32]= hex::decode("c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "2ecd8a6b7d2845546659ad4cf443533cf921b19dc81fa83934e83821b4dfdcb7", + "90eeb2c4a04ec33ee4dd2677593331910e4203db4fcc120a6cdb95b13cfe83f0", + "fa02d31a63cc11cc624881e52af14af7a1c6ab745efa71021cb24086b9b1793f", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 7, 8); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("08").unwrap().as_slice()]); + assert!(result.is_ok()); + } + + // Test vectors: + // 0x00 + // 0x01 + // 0x02 + // 0x03 + // 0x04 + #[test] + fn test_verify_proof_of_five_leaves() { + let root:[u8;32]= hex::decode("b855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", + "52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825", + "4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 1, 5); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("01").unwrap().as_slice()]); + assert!(result.is_ok()) + } + + #[test] + fn test_verify_invalid_proof_root() { + let root:[u8;32]= hex::decode("c855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", + "52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825", + "4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 1, 5); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("01").unwrap().as_slice()]); + assert!(result.is_err()); + } + + #[test] + fn test_verify_invalid_proof_key() { + let root:[u8;32]= hex::decode("b855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", + "52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825", + "4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let mut proof = Proof::::from_celestia_merkle_path(&siblings, 1, 5); + proof.range = 2..3; + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("01").unwrap().as_slice()]); + assert!(result.is_err()); + } + + #[test] + fn test_verify_invalid_proof_side_nodes() { + let root:[u8;32]= hex::decode("b855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", + "52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825", + // correct side node:"4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + "5f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 1, 5); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("01").unwrap().as_slice()]); + assert!(result.is_err()); + } + + #[test] + fn test_verify_invalid_proof_data() { + let root:[u8;32]= hex::decode("b855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", + "52c56b473e5246933e7852989cd9feba3b38f078742b93afff1e65ed46797825", + "4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + let proof = Proof::::from_celestia_merkle_path(&siblings, 1, 5); + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("012345").unwrap().as_slice()]); + assert!(result.is_err()); + } + + #[test] + fn test_same_key_and_leaves_number() { + let root: [u8; 32] = + hex::decode("b855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f") + .unwrap() + .try_into() + .unwrap(); + let proof = Proof:: { + siblings: vec![], + range: 3..4, + }; + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("01").unwrap().as_slice()]); + assert!(result.is_err()) + } + + #[test] + fn test_consecutive_key_and_number_of_leaves() { + let root: [u8; 32] = + hex::decode("b855b42d6c30f5b087e05266783fbd6e394f7b926013ccaa67700a8b0c5a596f") + .unwrap() + .try_into() + .unwrap(); + let proof = Proof:: { + siblings: vec![], + range: 6..7, + }; + let result = + proof.verify_with_leaves_data(&root, &vec![hex::decode("01").unwrap().as_slice()]); + assert!(result.is_err()) + } + + // ================================================================ + // Test for covert merkle path from celestia + // ================================================================ + // merkle_path is generate from celestia. + // Example code with golang: + // ```go + // import ( + // "github.com/tendermint/tendermint/crypto/merkle" + // "fmt" + // "hex" + // ) + // func main() { + // var leaves [][]byte + // for i := 1; i < 17; i++ { + // leaves = append(leaves, []byte{byte(i)}) + // } + // root, proofs := merkle.ProofsFromByteSlices(leaves) + // fmt.Println("root hash: ", hex.EncodeToString(root)) + // + // fmt.Println("index 2 leaf for proof: ", hex.EncodeToString(proofs[2].LeafHash)) + // for i, v := range proofs[2].Aunts { + // fmt.Printf("{%d} ==> %s\n", i, hex.EncodeToString(v)) + // } + // ``` + // Note: replace github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.32.0-tm-v0.34.29 in go.mod. + + #[test] + fn test_covert_8of16_celestia() { + let root:[u8;32]= hex::decode("451f071b539a1b912ead47ff3ba769147903a3a23a1d466f93656f4933934ca8").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "67ebbd370daa02ba9aadd05d8e091e862d0d8bcadafdf2a22360240a42fe922e", + "4e0da3c379521af1f85d7eef03a7860cfe2dcb3efd8dd32194f0981f0f0af7d5", + "0ed2ebf596a4de07fa95b19774c506b178cac53df3292bfd3908f85c2433995a", + "c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + + let proof = Proof::::from_celestia_merkle_path(&siblings, 8, 16); + let mut nmt_proof = Vec::new(); + proof.siblings + .iter() + .for_each(|h| nmt_proof.push(hex::encode(h))); + let expect_proof = vec![ + "c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071", + "67ebbd370daa02ba9aadd05d8e091e862d0d8bcadafdf2a22360240a42fe922e", + "4e0da3c379521af1f85d7eef03a7860cfe2dcb3efd8dd32194f0981f0f0af7d5", + "0ed2ebf596a4de07fa95b19774c506b178cac53df3292bfd3908f85c2433995a", + ]; + assert_eq!(expect_proof, nmt_proof); + assert!(proof.verify_with_leaves_data(&root,&[&[9]]).is_ok()) + } + #[test] + fn test_covert_9of16_celestia() { + let root:[u8;32]= hex::decode("451f071b539a1b912ead47ff3ba769147903a3a23a1d466f93656f4933934ca8").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "c87479cd656e7e3ad6bd8db402e8027df454b2b0c42ff29e093458beb98a23d4", + "4e0da3c379521af1f85d7eef03a7860cfe2dcb3efd8dd32194f0981f0f0af7d5", + "0ed2ebf596a4de07fa95b19774c506b178cac53df3292bfd3908f85c2433995a", + "c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + + let proof = Proof::::from_celestia_merkle_path(&siblings, 9, 16); + let mut nmt_proof = Vec::new(); + proof.siblings + .iter() + .for_each(|h| nmt_proof.push(hex::encode(h))); + let expect_proof = vec![ + "c1ad6548cb4c7663110df219ec8b36ca63b01158956f4be31a38a88d0c7f7071", + "c87479cd656e7e3ad6bd8db402e8027df454b2b0c42ff29e093458beb98a23d4", + "4e0da3c379521af1f85d7eef03a7860cfe2dcb3efd8dd32194f0981f0f0af7d5", + "0ed2ebf596a4de07fa95b19774c506b178cac53df3292bfd3908f85c2433995a", + ]; + assert_eq!(expect_proof, nmt_proof); + assert!(proof.verify_with_leaves_data(&root,&[&[10]]).is_ok()) + } + #[test] + fn test_covert_1of16_celestia() { + let root:[u8;32]= hex::decode("451f071b539a1b912ead47ff3ba769147903a3a23a1d466f93656f4933934ca8").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2", + "78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + "199fb6d33ec49c0d2ed928ed550d7efe5caa9b3e6298fb1e1f239d18fa6ca5cd", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + + let proof = Proof::::from_celestia_merkle_path(&siblings, 1, 16); + let mut nmt_proof = Vec::new(); + proof.siblings + .iter() + .for_each(|h| nmt_proof.push(hex::encode(h))); + let expect_proof = vec![ + "b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2", + "78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + "199fb6d33ec49c0d2ed928ed550d7efe5caa9b3e6298fb1e1f239d18fa6ca5cd", + ]; + assert_eq!(expect_proof, nmt_proof); + assert!(proof.verify_with_leaves_data(&root,&[&[2]]).is_ok()) + } + + #[test] + fn test_covert_0of16_celestia() { + let root:[u8;32]= hex::decode("451f071b539a1b912ead47ff3ba769147903a3a23a1d466f93656f4933934ca8").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "fcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f", + "78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + "199fb6d33ec49c0d2ed928ed550d7efe5caa9b3e6298fb1e1f239d18fa6ca5cd", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + + let proof = Proof::::from_celestia_merkle_path(&siblings, 0, 16); + let mut nmt_proof = Vec::new(); + + proof.siblings + .iter() + .for_each(|h| nmt_proof.push(hex::encode(h))); + let expect_proof = vec![ + "fcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f", + "78850a5ab36238b076dd99fd258c70d523168704247988a94caa8c9ccd056b8d", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + "199fb6d33ec49c0d2ed928ed550d7efe5caa9b3e6298fb1e1f239d18fa6ca5cd", + ]; + assert_eq!(expect_proof, nmt_proof); + assert!(proof.verify_with_leaves_data(&root,&[&[1]]).is_ok()) + } + + #[test] + fn test_covert_2of16_celestia() { + let root:[u8;32]= hex::decode("451f071b539a1b912ead47ff3ba769147903a3a23a1d466f93656f4933934ca8").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + "6bcf0e2e93e0a18e22789aee965e6553f4fbe93f0acfc4a705d691c8311c4965", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + "199fb6d33ec49c0d2ed928ed550d7efe5caa9b3e6298fb1e1f239d18fa6ca5cd", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + + let proof = Proof::::from_celestia_merkle_path(&siblings, 2, 16); + let mut nmt_proof = Vec::new(); + proof.siblings + .iter() + .for_each(|h| nmt_proof.push(hex::encode(h))); + let expect_proof = vec![ + "6bcf0e2e93e0a18e22789aee965e6553f4fbe93f0acfc4a705d691c8311c4965", + "4f35212d12f9ad2036492c95f1fe79baf4ec7bd9bef3dffa7579f2293ff546a4", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + "199fb6d33ec49c0d2ed928ed550d7efe5caa9b3e6298fb1e1f239d18fa6ca5cd", + ]; + assert_eq!(expect_proof, nmt_proof); + assert!(proof.verify_with_leaves_data(&root,&[&[3]]).is_ok()) + } + + #[test] + fn test_covert_3of16_celestia() { + let root:[u8;32]= hex::decode("451f071b539a1b912ead47ff3ba769147903a3a23a1d466f93656f4933934ca8").unwrap().try_into().unwrap(); + let mut siblings: Vec<[u8; 32]> = vec![]; + let merkle_path = vec![ + "583c7dfb7b3055d99465544032a571e10a134b1b6f769422bbb71fd7fa167a5d", + "6bcf0e2e93e0a18e22789aee965e6553f4fbe93f0acfc4a705d691c8311c4965", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + "199fb6d33ec49c0d2ed928ed550d7efe5caa9b3e6298fb1e1f239d18fa6ca5cd", + ]; + merkle_path.iter().for_each(|h| { + siblings.push(hex::decode(h).unwrap().try_into().unwrap()); + }); + + let proof = Proof::::from_celestia_merkle_path(&siblings, 3, 16); + let mut nmt_proof = Vec::new(); + proof.siblings + .iter() + .for_each(|h| nmt_proof.push(hex::encode(h))); + let expect_proof = vec![ + "6bcf0e2e93e0a18e22789aee965e6553f4fbe93f0acfc4a705d691c8311c4965", + "583c7dfb7b3055d99465544032a571e10a134b1b6f769422bbb71fd7fa167a5d", + "4301a067262bbb18b4919742326f6f6d706099f9c0e8b0f2db7b88f204b2cf09", + "199fb6d33ec49c0d2ed928ed550d7efe5caa9b3e6298fb1e1f239d18fa6ca5cd", + ]; + assert_eq!(expect_proof, nmt_proof); + assert!(proof.verify_with_leaves_data(&root,&[&[4]]).is_ok()) + } +} diff --git a/src/simple_merkle/tree.rs b/src/simple_merkle/tree.rs index f3e8cc8..c646c7d 100644 --- a/src/simple_merkle/tree.rs +++ b/src/simple_merkle/tree.rs @@ -760,7 +760,38 @@ where } /// Calculates the largest power of two which is strictly less than the argument -fn next_smaller_po2(int: usize) -> usize { +pub fn next_smaller_po2(int: usize) -> usize { // Calculate the first power of two which is greater than or equal to the argument, then divide by two. int.next_power_of_two() >> 1 } + +#[cfg(test)] +mod tests { + use super::*; + use crate::simple_merkle::db::{MemDb}; + use crate::TmSha2Hasher; + use hex; + + #[test] + fn test_tree() { + let mut tree: MerkleTree, TmSha2Hasher> = MerkleTree::new(); + tree.visitor = Box::new(|h| println!("{:?}", hex::encode(h))); + for i in 1..17 { + tree.push_raw_leaf(&[i as u8]); + } + let root = tree.root(); + assert_eq!( + hex::encode(root), + "451f071b539a1b912ead47ff3ba769147903a3a23a1d466f93656f4933934ca8" + ); + println!(" ============ \n"); + println!("merkle root: {:?}", hex::encode(root)); + let proof = tree.get_index_with_proof(2); + println!("index: {} merkle path ============ ", proof.1.range.start); + proof + .1 + .siblings + .iter() + .for_each(|h| println!("{:?}", hex::encode(h))); + } +} diff --git a/src/simple_merkle/utils.rs b/src/simple_merkle/utils.rs index cd4dd9e..ae58766 100644 --- a/src/simple_merkle/utils.rs +++ b/src/simple_merkle/utils.rs @@ -40,3 +40,23 @@ pub fn compute_tree_size( } Ok(index_of_final_node + 1) } + +#[cfg(test)] +mod test { + use crate::simple_merkle::utils::*; + + #[test] + fn test_compute_num_left_siblings() { + let num = compute_num_left_siblings(4); + assert_eq!(num, 1); + + let num = compute_num_left_siblings(5); + assert_eq!(num, 2); + } + + #[test] + fn test_compute_tree_size() { + let size = compute_tree_size(2, 4).unwrap(); + assert_eq!(size, 8); + } +} diff --git a/src/tendermint_hash.rs b/src/tendermint_hash.rs index 9657080..caaf4c0 100644 --- a/src/tendermint_hash.rs +++ b/src/tendermint_hash.rs @@ -22,6 +22,7 @@ fn inner_hash(left: &[u8], right: &[u8]) -> [u8; 32] { } /// A sha256 hasher, compatible with [Tendermint merkle hash](https://github.com/informalsystems/tendermint-rs/blob/979456c9f33463944f97f7ea3900640e59f7ea6d/tendermint/src/merkle.rs) +#[derive(Debug)] pub struct TmSha2Hasher; impl Default for TmSha2Hasher { @@ -57,7 +58,9 @@ impl MerkleHash for TmSha2Hasher { mod tests { use super::*; use crate::{MemDb, MerkleTree}; + use hex; use tendermint::merkle::simple_hash_from_byte_vectors; + #[test] fn test_tm_hash_matches_upstream() { let leaves: Vec<&[u8]> = vec![b"leaf_1", b"leaf_2", b"leaf_3", b"leaf_4"]; @@ -69,4 +72,75 @@ mod tests { let hash_from_byte_slices = simple_hash_from_byte_vectors::(leaves.as_slice()); assert_eq!(tree.root().as_ref(), &hash_from_byte_slices); } + + // --------------------------------------------------------- + // These test copy from solidity implementation + // https://github.com/celestiaorg/blobstream-contracts/blob/dc02821/src/lib/tree/binary/test/TreeHasher.t.sol + // --------------------------------------------------------- + + #[test] + fn test_leaf_digest_empty() { + let hasher = TmSha2Hasher {}; + let expected: [u8; 32] = + hex::decode("6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d") + .unwrap() + .try_into() + .unwrap(); + let digest = hasher.hash_leaf(&vec![]); + assert_eq!(digest, expected); + } + + #[test] + fn test_leaf_digest_some() { + let hasher = TmSha2Hasher {}; + let expected: [u8; 32] = + hex::decode("48c90c8ae24688d6bef5d48a30c2cc8b6754335a8db21793cc0a8e3bed321729") + .unwrap() + .try_into() + .unwrap(); + let digest = hasher.hash_leaf(hex::decode("deadbeef").unwrap().as_slice()); + assert_eq!(digest, expected); + } + + #[test] + fn test_node_digest_empty_children() { + let hasher = TmSha2Hasher {}; + let expected: [u8; 32] = + hex::decode("fe43d66afa4a9a5c4f9c9da89f4ffb52635c8f342e7ffb731d68e36c5982072a") + .unwrap() + .try_into() + .unwrap(); + let digest = hasher.hash_nodes( + &hex::decode("6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d") + .unwrap() + .try_into() + .unwrap(), + &hex::decode("6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d") + .unwrap() + .try_into() + .unwrap(), + ); + assert_eq!(digest, expected); + } + + #[test] + fn test_node_digest_some_children() { + let hasher = TmSha2Hasher {}; + let expected: [u8; 32] = + hex::decode("62343bba7c4d6259f0d4863cdf476f1c0ac1b9fbe9244723a9b8b5c8aae72c38") + .unwrap() + .try_into() + .unwrap(); + let digest = hasher.hash_nodes( + &hex::decode("db55da3fc3098e9c42311c6013304ff36b19ef73d12ea932054b5ad51df4f49d") + .unwrap() + .try_into() + .unwrap(), + &hex::decode("c75cb66ae28d8ebc6eded002c28a8ba0d06d3a78c6b5cbf9b2ade051f0775ac4") + .unwrap() + .try_into() + .unwrap(), + ); + assert_eq!(digest, expected); + } }