// This file is part of Bizinikiwi. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Provides functionality for verifying proofs. use alloc::vec::Vec; use codec::{Decode, Encode}; use pezsp_core::Hasher; use pezsp_runtime::DispatchError; // Re-export the `proving_trie` types and traits. pub use pezsp_runtime::proving_trie::*; /// Something that can verify the existence of some data in a given proof. pub trait VerifyExistenceProof { /// The proof type. type Proof; /// The hash type. type Hash; /// Verify the given `proof`. /// /// Ensures that the `proof` was build for `root` and returns the proved data. fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, DispatchError>; } /// Implements [`VerifyExistenceProof`] using a binary merkle tree. pub struct BinaryMerkleTreeProver(core::marker::PhantomData); impl VerifyExistenceProof for BinaryMerkleTreeProver where H::Out: Decode + Encode, { type Proof = binary_merkle_tree::MerkleProof>; type Hash = H::Out; fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, DispatchError> { if proof.root != *root { return Err(TrieError::RootMismatch.into()); } if binary_merkle_tree::verify_proof::( &proof.root, proof.proof, proof.number_of_leaves, proof.leaf_index, &proof.leaf, ) { Ok(proof.leaf) } else { Err(TrieError::IncompleteProof.into()) } } } impl ProofToHashes for BinaryMerkleTreeProver { type Proof = binary_merkle_tree::MerkleProof>; // This base 2 merkle trie includes a `proof` field which is a `Vec`. // The length of this vector tells us the depth of the proof, and how many // hashes we need to calculate. fn proof_to_hashes(proof: &Self::Proof) -> Result { let depth = proof.proof.len(); Ok(depth as u32) } } /// Proof used by [`SixteenPatriciaMerkleTreeProver`] for [`VerifyExistenceProof`]. #[derive(Encode, Decode, Clone)] pub struct SixteenPatriciaMerkleTreeExistenceProof { /// The key of the value to prove. pub key: Vec, /// The value for that the existence is proved. pub value: Vec, /// The encoded nodes to prove the existence of the data under `key`. pub proof: Vec>, } /// Implements [`VerifyExistenceProof`] using a 16-patricia merkle tree. pub struct SixteenPatriciaMerkleTreeProver(core::marker::PhantomData); impl VerifyExistenceProof for SixteenPatriciaMerkleTreeProver { type Proof = SixteenPatriciaMerkleTreeExistenceProof; type Hash = H::Out; fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, DispatchError> { pezsp_trie::verify_trie_proof::, _, _, _>( &root, &proof.proof, [&(&proof.key, Some(&proof.value))], ) .map_err(|err| TrieError::from(err).into()) .map(|_| proof.value) } } impl ProofToHashes for SixteenPatriciaMerkleTreeProver { type Proof = SixteenPatriciaMerkleTreeExistenceProof; // This base 16 trie uses a raw proof of `Vec`, where the length of the first `Vec` // is the depth of the trie. We can use this to predict the number of hashes. fn proof_to_hashes(proof: &Self::Proof) -> Result { let depth = proof.proof.len(); Ok(depth as u32) } } #[cfg(test)] mod tests { use super::*; use pezsp_runtime::{ proving_trie::{base16::BasicProvingTrie, ProvingTrie}, traits::BlakeTwo256, }; #[test] fn verify_binary_merkle_tree_prover_works() { let proof = binary_merkle_tree::merkle_proof::( vec![b"hey".encode(), b"yes".encode()], 1, ); let root = proof.root; assert_eq!( BinaryMerkleTreeProver::::verify_proof(proof, &root).unwrap(), b"yes".encode() ); } #[test] fn verify_sixteen_patricia_merkle_tree_prover_works() { let trie = BasicProvingTrie::::generate_for(vec![ (0u32, String::from("hey")), (1u32, String::from("yes")), ]) .unwrap(); let proof = trie.create_proof(&1u32).unwrap(); let structured_proof: Vec> = Decode::decode(&mut &proof[..]).unwrap(); let root = *trie.root(); let proof = SixteenPatriciaMerkleTreeExistenceProof { key: 1u32.encode(), value: String::from("yes").encode(), proof: structured_proof, }; assert_eq!( SixteenPatriciaMerkleTreeProver::::verify_proof(proof, &root).unwrap(), String::from("yes").encode() ); } #[test] fn proof_to_hashes_sixteen() { let mut i: u32 = 1; // Compute log base 16 and round up let log16 = |x: u32| -> u32 { let x_f64 = x as f64; let log16_x = (x_f64.ln() / 16_f64.ln()).ceil(); log16_x as u32 }; while i < 10_000_000 { let trie = BasicProvingTrie::::generate_for( (0..i).map(|i| (i, u128::from(i))), ) .unwrap(); let proof = trie.create_proof(&0).unwrap(); let structured_proof: Vec> = Decode::decode(&mut &proof[..]).unwrap(); let root = *trie.root(); let proof = SixteenPatriciaMerkleTreeExistenceProof { key: 0u32.encode(), value: 0u128.encode(), proof: structured_proof, }; let hashes = SixteenPatriciaMerkleTreeProver::::proof_to_hashes(&proof).unwrap(); let log16 = log16(i).max(1); assert_eq!(hashes, log16); assert_eq!( SixteenPatriciaMerkleTreeProver::::verify_proof(proof.clone(), &root) .unwrap(), proof.value ); i = i * 10; } } #[test] fn proof_to_hashes_binary() { let mut i: u32 = 1; while i < 10_000_000 { let proof = binary_merkle_tree::merkle_proof::( (0..i).map(|i| u128::from(i).encode()), 0, ); let root = proof.root; let hashes = BinaryMerkleTreeProver::::proof_to_hashes(&proof).unwrap(); let log2 = (i as f64).log2().ceil() as u32; assert_eq!(hashes, log2); assert_eq!( BinaryMerkleTreeProver::::verify_proof(proof, &root).unwrap(), 0u128.encode() ); i = i * 10; } } }