diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..c2ea78b --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,21 @@ +name: Rust Tests + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + +jobs: + test: + if: github.event.pull_request.draft == false + name: Rust tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: Run tests + run: cargo test diff --git a/book/src/merkletree.md b/book/src/merkletree.md index cf5f10e..b58d766 100644 --- a/book/src/merkletree.md +++ b/book/src/merkletree.md @@ -145,28 +145,30 @@ For the current use cases, we don't need to prove that the key exists but the va ```rust impl MerkleTree { - /// builds a new `MerkleTree` where the leaves contain the given key-values - fn new(kvs: HashMap) -> Self; - /// returns the root of the tree - fn root(&self) -> Result; + fn root(&self) -> Hash; + + /// returns the value at the given key + fn get(&self, key: &Value) -> Result; + /// returns a boolean indicating whether the key exists in the tree + fn contains(&self, key: &Value) -> bool; + /// returns a proof of existence, which proves that the given key exists in - /// the tree. It returns the `value` of the leaf at the given `key`, and - /// the `MerkleProof`. - fn prove(&self, key: &Value) -> Result<(Value, MerkleProof)>; - + /// the tree. It returns the `MerkleProof`. + fn prove(&self, key: &Value) -> Result; + /// returns a proof of non-existence, which proves that the given `key` /// does not exist in the tree fn prove_nonexistence(&self, key: &Value) -> Result; - + /// verifies an inclusion proof for the given `key` and `value` fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()>; - + /// verifies a non-inclusion proof for the given `key`, that is, the given /// `key` does not exist in the tree fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Value) -> Result<()>; - + /// returns an iterator over the leaves of the tree fn iter(&self) -> std::collections::hash_map::Iter; } diff --git a/book/src/values.md b/book/src/values.md index 875f1cf..f4e2f5d 100644 --- a/book/src/values.md +++ b/book/src/values.md @@ -51,14 +51,15 @@ The array, set and dictionary types are similar types. While all of them use [a - `leaf.key=hash(original_key)` - `leaf.value=hash(original_value)` - **array**: the elements are placed at the value field of each leaf, and the key field is just the array index (integer) - - `leaf.value=original_value` - `leaf.key=i` + - `leaf.value=original_value` - **set**: the value field of the leaf is unused, and the key contains the hash of the element - `leaf.key=hash(original_value)` - `leaf.value=0` In the three types, the merkletree under the hood allows to prove inclusion & non-inclusion of the particular entry of the {dictionary/array/set} element. +A concrete implementation of dictionary, array, set can be found at [pod2/src/middleware/containers.rs](https://github.com/0xPARC/pod2/blob/main/src/middleware/containers.rs).

diff --git a/src/backends/mock_main.rs b/src/backends/mock_main.rs index cdbab22..371871e 100644 --- a/src/backends/mock_main.rs +++ b/src/backends/mock_main.rs @@ -9,7 +9,6 @@ use plonky2::hash::poseidon::PoseidonHash; use plonky2::plonk::config::Hasher; use std::any::Any; use std::fmt; -use std::io::{self, Write}; pub struct MockProver {} diff --git a/src/backends/mock_signed.rs b/src/backends/mock_signed.rs index 4080025..3c5041f 100644 --- a/src/backends/mock_signed.rs +++ b/src/backends/mock_signed.rs @@ -1,7 +1,8 @@ -use crate::merkletree::MerkleTree; use crate::middleware::{ - hash_str, Hash, Params, PodId, PodSigner, PodType, SignedPod, Value, KEY_SIGNER, KEY_TYPE, + containers::Dictionary, hash_str, Hash, Params, PodId, PodSigner, PodType, SignedPod, Value, + KEY_SIGNER, KEY_TYPE, }; +use crate::primitives::merkletree::MerkleTree; use anyhow::Result; use std::any::Any; use std::collections::HashMap; @@ -17,10 +18,14 @@ impl PodSigner for MockSigner { kvs.insert(hash_str(&KEY_SIGNER), Value(pk_hash.0)); kvs.insert(hash_str(&KEY_TYPE), Value::from(PodType::MockSigned)); - let mt = MerkleTree::new(&kvs); - let id = PodId(mt.root()?); + let dict = Dictionary::new(&kvs); + let id = PodId(dict.commitment()); let signature = format!("{}_signed_by_{}", id, pk_hash); - Ok(Box::new(MockSignedPod { mt, id, signature })) + Ok(Box::new(MockSignedPod { + dict, + id, + signature, + })) } } @@ -28,30 +33,37 @@ impl PodSigner for MockSigner { pub struct MockSignedPod { id: PodId, signature: String, - mt: MerkleTree, + dict: Dictionary, } impl SignedPod for MockSignedPod { fn verify(&self) -> bool { // Verify type - if Some(&Value::from(PodType::MockSigned)) != self.mt.kvs().get(&hash_str(&KEY_TYPE)) { + let value_at_type = match self.dict.get(&hash_str(&KEY_TYPE).into()) { + Ok(v) => v, + Err(_) => return false, + }; + if Value::from(PodType::MockSigned) != value_at_type { return false; } // Verify id - let mt = MerkleTree::new(&self.mt.kvs()); - let id = match mt.root() { - Ok(id) => PodId(id), - Err(_) => return false, - }; + let mt = MerkleTree::new( + &self + .dict + .iter() + .map(|(&k, &v)| (k, v)) + .collect::>(), + ); + let id = PodId(mt.root()); if id != self.id { return false; } // Verify signature - let pk_hash = match self.mt.kvs().get(&hash_str(&KEY_SIGNER)) { - Some(v) => v, - None => return false, + let pk_hash = match self.dict.get(&hash_str(&KEY_SIGNER).into()) { + Ok(v) => v, + Err(_) => return false, }; let signature = format!("{}_signed_by_{}", id, pk_hash); if signature != self.signature { @@ -66,7 +78,10 @@ impl SignedPod for MockSignedPod { } fn kvs(&self) -> HashMap { - self.mt.kvs().clone() + self.dict + .into_iter() + .map(|(&k, &v)| (Hash(k.0), v)) + .collect() } fn into_any(self: Box) -> Box { @@ -108,15 +123,23 @@ pub mod tests { let mut bad_pod = pod.clone(); let mut bad_kvs = bad_pod.kvs(); bad_kvs.insert(hash_str(KEY_SIGNER), Value(PodId(NULL).0 .0)); - let bad_mt = MerkleTree::new(&bad_kvs); - bad_pod.mt = bad_mt; + let bad_kvs_mt = &bad_kvs + .into_iter() + .map(|(k, v)| (Value(k.0), v)) + .collect::>(); + let bad_mt = MerkleTree::new(&bad_kvs_mt); + bad_pod.dict.mt = bad_mt; assert_eq!(bad_pod.verify(), false); let mut bad_pod = pod.clone(); let mut bad_kvs = bad_pod.kvs(); bad_kvs.insert(hash_str(KEY_TYPE), Value::from(0)); - let bad_mt = MerkleTree::new(&bad_kvs); - bad_pod.mt = bad_mt; + let bad_kvs_mt = &bad_kvs + .into_iter() + .map(|(k, v)| (Value(k.0), v)) + .collect::>(); + let bad_mt = MerkleTree::new(&bad_kvs_mt); + bad_pod.dict.mt = bad_mt; assert_eq!(bad_pod.verify(), false); } } diff --git a/src/backends.rs b/src/backends/mod.rs similarity index 100% rename from src/backends.rs rename to src/backends/mod.rs diff --git a/src/examples.rs b/src/examples.rs index 0105ae3..52e0a68 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -1,5 +1,7 @@ -use crate::frontend::{MainPodBuilder, MerkleTree, SignedPod, SignedPodBuilder, Value}; -use crate::middleware::{Params, PodType, KEY_SIGNER, KEY_TYPE}; +use std::collections::HashMap; + +use crate::frontend::{MainPodBuilder, SignedPod, SignedPodBuilder, Value}; +use crate::middleware::{containers::Dictionary, Params, PodType, KEY_SIGNER, KEY_TYPE}; use crate::op; // ZuKYC @@ -22,7 +24,7 @@ pub fn zu_kyc_pod_builder( gov_id: &SignedPod, pay_stub: &SignedPod, ) -> MainPodBuilder { - let sanction_list = Value::MerkleTree(MerkleTree { root: 1 }); + let sanction_list = Value::Dictionary(Dictionary::new(&HashMap::new())); // empty dictionary let now_minus_18y: i64 = 1169909388; let now_minus_1y: i64 = 1706367566; @@ -178,7 +180,7 @@ pub fn great_boy_pod_full_flow() -> MainPodBuilder { alice_friend_pods.push(friend.sign(&mut bob_signer).unwrap()); alice_friend_pods.push(friend.sign(&mut charlie_signer).unwrap()); - let good_boy_issuers_mt = Value::MerkleTree(MerkleTree { root: 33 }); + let good_boy_issuers_dict = Value::Dictionary(Dictionary::new(&HashMap::new())); // empty great_boy_pod_builder( ¶ms, [ @@ -188,7 +190,7 @@ pub fn great_boy_pod_full_flow() -> MainPodBuilder { &charlie_good_boys[1], ], [&alice_friend_pods[0], &alice_friend_pods[1]], - &good_boy_issuers_mt, + &good_boy_issuers_dict, alice, ) } diff --git a/src/frontend.rs b/src/frontend.rs index cae15df..bd32684 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -3,14 +3,15 @@ use anyhow::Result; use itertools::Itertools; -use plonky2::field::types::Field; use std::collections::HashMap; use std::convert::From; use std::fmt; use crate::middleware::{ - self, hash_str, Hash, MainPodInputs, NativeOperation, NativeStatement, Params, PodId, - PodProver, PodSigner, F, SELF, + self, + containers::{Array, Dictionary, Set}, + hash_str, Hash, MainPodInputs, NativeOperation, NativeStatement, Params, PodId, PodProver, + PodSigner, SELF, }; /// This type is just for presentation purposes. @@ -25,16 +26,13 @@ pub enum PodClass { #[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] pub struct Origin(pub PodClass, pub PodId); -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleTree { - pub root: u8, // TODO -} - #[derive(Clone, Debug, PartialEq, Eq)] pub enum Value { String(String), Int(i64), - MerkleTree(MerkleTree), + Dictionary(Dictionary), + Set(Set), + Array(Array), } impl From<&str> for Value { @@ -54,13 +52,9 @@ impl From<&Value> for middleware::Value { match v { Value::String(s) => middleware::Value(hash_str(s).0), Value::Int(v) => middleware::Value::from(*v), - // TODO - Value::MerkleTree(mt) => middleware::Value([ - F::from_canonical_u64(mt.root as u64), - F::ZERO, - F::ZERO, - F::ZERO, - ]), + Value::Dictionary(d) => middleware::Value(d.commitment().0), + Value::Set(s) => middleware::Value(s.commitment().0), + Value::Array(a) => middleware::Value(a.commitment().0), } } } @@ -70,7 +64,9 @@ impl fmt::Display for Value { match self { Value::String(s) => write!(f, "\"{}\"", s), Value::Int(v) => write!(f, "{}", v), - Value::MerkleTree(mt) => write!(f, "mt:{}", mt.root), + Value::Dictionary(d) => write!(f, "dict:{}", d.commitment()), + Value::Set(s) => write!(f, "set:{}", s.commitment()), + Value::Array(a) => write!(f, "arr:{}", a.commitment()), } } } diff --git a/src/lib.rs b/src/lib.rs index 4bad04e..95245d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ pub mod backends; pub mod frontend; -pub mod merkletree; pub mod middleware; +pub mod primitives; #[cfg(test)] pub mod examples; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/src/middleware/containers.rs b/src/middleware/containers.rs new file mode 100644 index 0000000..43204b4 --- /dev/null +++ b/src/middleware/containers.rs @@ -0,0 +1,159 @@ +/// This file implements the types defined at +/// https://0xparc.github.io/pod2/values.html#dictionary-array-set . +use anyhow::Result; +use plonky2::hash::poseidon::PoseidonHash; +use plonky2::plonk::config::Hasher; +use std::collections::HashMap; + +use super::{Hash, Value, EMPTY}; +use crate::primitives::merkletree::{MerkleProof, MerkleTree}; + +/// Dictionary: the user original keys and values are hashed to be used in the leaf. +/// leaf.key=hash(original_key) +/// leaf.value=hash(original_value) +#[derive(Clone, Debug)] +pub struct Dictionary { + // exposed with pub(crate) so that it can be modified at tests + pub(crate) mt: MerkleTree, +} + +impl Dictionary { + pub fn new(kvs: &HashMap) -> Self { + let kvs: HashMap = kvs.into_iter().map(|(&k, &v)| (Value(k.0), v)).collect(); + Self { + mt: MerkleTree::new(&kvs), + } + } + pub fn commitment(&self) -> Hash { + self.mt.root() + } + pub fn get(&self, key: &Value) -> Result { + self.mt.get(key) + } + pub fn prove(&self, key: &Value) -> Result { + self.mt.prove(key) + } + pub fn prove_nonexistence(&self, key: &Value) -> Result { + self.mt.prove_nonexistence(key) + } + pub fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()> { + MerkleTree::verify(root, proof, key, value) + } + pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Value) -> Result<()> { + MerkleTree::verify_nonexistence(root, proof, key) + } + pub fn iter(&self) -> std::collections::hash_map::Iter { + self.mt.iter() + } +} +impl<'a> IntoIterator for &'a Dictionary { + type Item = (&'a Value, &'a Value); + type IntoIter = std::collections::hash_map::Iter<'a, Value, Value>; + + fn into_iter(self) -> Self::IntoIter { + self.mt.iter() + } +} + +impl PartialEq for Dictionary { + fn eq(&self, other: &Self) -> bool { + self.mt.root() == other.mt.root() + } +} +impl Eq for Dictionary {} + +/// Set: the value field of the leaf is unused, and the key contains the hash of the element. +/// leaf.key=hash(original_value) +/// leaf.value=0 +#[derive(Clone, Debug)] +pub struct Set { + mt: MerkleTree, +} + +impl Set { + pub fn new(set: &Vec) -> Self { + let kvs: HashMap = set + .into_iter() + .map(|e| { + let h = PoseidonHash::hash_no_pad(&e.0).elements; + (Value(h), EMPTY) + }) + .collect(); + Self { + mt: MerkleTree::new(&kvs), + } + } + pub fn commitment(&self) -> Hash { + self.mt.root() + } + pub fn contains(&self, value: &Value) -> bool { + self.mt.contains(value) + } + pub fn prove(&self, value: &Value) -> Result { + self.mt.prove(value) + } + pub fn prove_nonexistence(&self, value: &Value) -> Result { + self.mt.prove_nonexistence(value) + } + pub fn verify(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> { + MerkleTree::verify(root, proof, value, &EMPTY) + } + pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> { + MerkleTree::verify_nonexistence(root, proof, value) + } + pub fn iter(&self) -> std::collections::hash_map::Iter { + self.mt.iter() + } +} + +impl PartialEq for Set { + fn eq(&self, other: &Self) -> bool { + self.mt.root() == other.mt.root() + } +} +impl Eq for Set {} + +/// Array: the elements are placed at the value field of each leaf, and the key field is just the +/// array index (integer). +/// leaf.key=i +/// leaf.value=original_value +#[derive(Clone, Debug)] +pub struct Array { + mt: MerkleTree, +} + +impl Array { + pub fn new(array: &Vec) -> Self { + let kvs: HashMap = array + .into_iter() + .enumerate() + .map(|(i, &e)| (Value::from(i as i64), e)) + .collect(); + + Self { + mt: MerkleTree::new(&kvs), + } + } + pub fn commitment(&self) -> Hash { + self.mt.root() + } + pub fn get(&self, i: usize) -> Result { + self.mt.get(&Value::from(i as i64)) + } + pub fn prove(&self, i: usize) -> Result { + self.mt.prove(&Value::from(i as i64)) + } + pub fn verify(root: Hash, proof: &MerkleProof, i: usize, value: &Value) -> Result<()> { + MerkleTree::verify(root, proof, &Value::from(i as i64), value) + } + pub fn iter(&self) -> std::collections::hash_map::Iter { + self.mt.iter() + } +} + +impl PartialEq for Array { + fn eq(&self, other: &Self) -> bool { + self.mt.root() == other.mt.root() + } +} +impl Eq for Array {} diff --git a/src/middleware.rs b/src/middleware/mod.rs similarity index 99% rename from src/middleware.rs rename to src/middleware/mod.rs index 809d5df..eb2cb46 100644 --- a/src/middleware.rs +++ b/src/middleware/mod.rs @@ -12,9 +12,11 @@ use plonky2::plonk::config::{Hasher, PoseidonGoldilocksConfig}; use std::any::Any; use std::cmp::{Ord, Ordering}; use std::collections::HashMap; -use std::{array, fmt}; +use std::fmt; use strum_macros::FromRepr; +pub mod containers; + pub const KEY_SIGNER: &str = "_signer"; pub const KEY_TYPE: &str = "_type"; pub const STATEMENT_ARG_F_LEN: usize = 8; @@ -57,6 +59,12 @@ impl From for Value { } } +impl From for Value { + fn from(h: Hash) -> Self { + Value(h.0) + } +} + impl TryInto for Value { type Error = Error; fn try_into(self) -> std::result::Result { @@ -109,6 +117,7 @@ impl PartialOrd for Hash { } } +pub const EMPTY: Value = Value([F::ZERO, F::ZERO, F::ZERO, F::ZERO]); pub const NULL: Hash = Hash([F::ZERO, F::ZERO, F::ZERO, F::ZERO]); impl fmt::Display for Hash { diff --git a/src/merkletree.rs b/src/primitives/merkletree.rs similarity index 59% rename from src/merkletree.rs rename to src/primitives/merkletree.rs index 8d6f87e..8a393af 100644 --- a/src/merkletree.rs +++ b/src/primitives/merkletree.rs @@ -20,19 +20,22 @@ use crate::middleware::{Hash, Value, C, D, F}; const CAP_HEIGHT: usize = 0; -/// MerkleTree currently implements the MerkleTree interface with a wrapper on top of Plonky2's -/// MerkleTree. A future iteration will replace it by the MerkleTree specified at -/// https://0xparc.github.io/pod2/merkletree.html . +/// MerkleTree currently is a wrapper on top of Plonky2's MerkleTree. A future iteration will +/// replace it by the MerkleTree specified at https://0xparc.github.io/pod2/merkletree.html . #[derive(Clone, Debug)] pub struct MerkleTree { tree: PlonkyMerkleTree>::Hasher>, // keyindex: key -> index mapping. This is just for the current plonky-tree wrapper - keyindex: HashMap, + keyindex: HashMap, // kvs are a field in the MerkleTree in order to be able to iterate over the keyvalues. This is // specific of the current implementation (Plonky2's tree wrapper), in the next iteration this // will not be needed since the tree implementation itself will offer the hashmap // functionality. - kvs: HashMap, + pub kvs: HashMap, + // leaves_map is a map between the leaf (leaf=Hash(key,value)) and the actual (key, value). It + // is used to get the actual value from a leaf for a given key (through the method + // `MerkleTree.get`. + leaves_map: HashMap, } pub struct MerkleProof { @@ -42,9 +45,11 @@ pub struct MerkleProof { } impl MerkleTree { - pub fn new(kvs: &HashMap) -> Self { - let mut keyindex: HashMap = HashMap::new(); + /// builds a new `MerkleTree` where the leaves contain the given key-values + pub fn new(kvs: &HashMap) -> Self { + let mut keyindex: HashMap = HashMap::new(); let mut leaves: Vec> = Vec::new(); + let mut leaves_map: HashMap = HashMap::new(); // Note: current version iterates sorting by keys of the kvs, but the merkletree defined at // https://0xparc.github.io/pod2/merkletree.html will not need it since it will be // deterministic based on the keys values not on the order of the keys when added into the @@ -54,6 +59,7 @@ impl MerkleTree { let leaf = PoseidonHash::hash_no_pad(&input).elements; leaves.push(leaf.into()); keyindex.insert(*k, i); + leaves_map.insert(Hash(leaf), (*k, *v)); } // pad to a power of two if needed @@ -67,17 +73,40 @@ impl MerkleTree { tree, keyindex, kvs: kvs.clone(), + leaves_map, } } +} - pub fn root(&self) -> Result { +impl MerkleTree { + /// returns the root of the tree + pub fn root(&self) -> Hash { if self.tree.cap.is_empty() { - return Err(anyhow!("empty tree")); + return crate::middleware::NULL; } - Ok(Hash(self.tree.cap.0[0].elements)) + Hash(self.tree.cap.0[0].elements) } - pub fn prove(&self, key: &Hash) -> Result { + /// returns the value at the given key + pub fn get(&self, key: &Value) -> Result { + let i = self.keyindex.get(&key).ok_or(anyhow!("key not in tree"))?; + let leaf_hash_raw = self.tree.get(*i); + let leaf_hash_f: [F; 4] = leaf_hash_raw + .try_into() + .map_err(|_| anyhow!("unexpected length (len!=4)"))?; + let leaf_hash: Hash = Hash(leaf_hash_f); + let (_, value) = self.leaves_map.get(&leaf_hash).unwrap(); + Ok(*value) + } + + /// returns a boolean indicating whether the key exists in the tree + pub fn contains(&self, key: &Value) -> bool { + self.keyindex.get(&key).is_some() + } + + /// returns a proof of existence, which proves that the given key exists in + /// the tree. It returns the `MerkleProof`. + pub fn prove(&self, key: &Value) -> Result { let i = self.keyindex.get(&key).ok_or(anyhow!("key not in tree"))?; let proof = self.tree.prove(*i); Ok(MerkleProof { @@ -87,7 +116,9 @@ impl MerkleTree { }) } - pub fn prove_nonexistence(&self, _key: &Hash) -> Result { + /// returns a proof of non-existence, which proves that the given `key` + /// does not exist in the tree + pub fn prove_nonexistence(&self, _key: &Value) -> Result { // mock method println!("WARNING: MerkleTree::verify_nonexistence is currently a mock"); Ok(MerkleProof { @@ -97,7 +128,8 @@ impl MerkleTree { }) } - pub fn verify(root: Hash, proof: &MerkleProof, key: &Hash, value: &Value) -> Result<()> { + /// verifies an inclusion proof for the given `key` and `value` + pub fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()> { if !proof.existence { return Err(anyhow!( "expected proof of existence, found proof of non-existence" @@ -108,12 +140,9 @@ impl MerkleTree { verify_merkle_proof(leaf.into(), proof.index, root, &proof.proof) } - pub fn verify_nonexistence( - _root: Hash, - proof: &MerkleProof, - _key: &Hash, - _value: &Value, - ) -> Result<()> { + /// verifies a non-inclusion proof for the given `key`, that is, the given + /// `key` does not exist in the tree + pub fn verify_nonexistence(_root: Hash, proof: &MerkleProof, _key: &Value) -> Result<()> { // mock method if proof.existence { return Err(anyhow!( @@ -124,18 +153,15 @@ impl MerkleTree { Ok(()) } - pub fn iter(&self) -> std::collections::hash_map::Iter { + /// returns an iterator over the leaves of the tree + pub fn iter(&self) -> std::collections::hash_map::Iter { self.kvs.iter() } - - pub fn kvs(&self) -> &HashMap { - &self.kvs - } } impl<'a> IntoIterator for &'a MerkleTree { - type Item = (&'a Hash, &'a Value); - type IntoIter = std::collections::hash_map::Iter<'a, Hash, Value>; + type Item = (&'a Value, &'a Value); + type IntoIter = std::collections::hash_map::Iter<'a, Value, Value>; fn into_iter(self) -> Self::IntoIter { self.kvs.iter() @@ -151,15 +177,15 @@ pub mod tests { #[test] fn test_merkletree() -> Result<()> { let (k0, v0) = ( - hash_str("key_0".into()), + Value(hash_str("key_0".into()).0), Value(hash_str("value_0".into()).0), ); let (k1, v1) = ( - hash_str("key_1".into()), + Value(hash_str("key_1".into()).0), Value(hash_str("value_1".into()).0), ); let (k2, v2) = ( - hash_str("key_2".into()), + Value(hash_str("key_2".into()).0), Value(hash_str("value_2".into()).0), ); @@ -171,18 +197,18 @@ pub mod tests { let tree = MerkleTree::new(&kvs); let proof = tree.prove(&k2)?; - MerkleTree::verify(tree.root()?, &proof, &k2, &v2)?; + MerkleTree::verify(tree.root(), &proof, &k2, &v2)?; // expect verification to fail with different key / value - assert!(MerkleTree::verify(tree.root()?, &proof, &k2, &v0).is_err()); - assert!(MerkleTree::verify(tree.root()?, &proof, &k0, &v2).is_err()); + assert!(MerkleTree::verify(tree.root(), &proof, &k2, &v0).is_err()); + assert!(MerkleTree::verify(tree.root(), &proof, &k0, &v2).is_err()); // non-existence proofs let proof_ne = tree.prove_nonexistence(&k2)?; - let _ = MerkleTree::verify_nonexistence(tree.root()?, &proof_ne, &k2, &v2)?; + let _ = MerkleTree::verify_nonexistence(tree.root(), &proof_ne, &k2)?; // expect verification of existence fail for nonexistence proof - let _ = MerkleTree::verify(tree.root()?, &proof_ne, &k2, &v2).is_err(); + let _ = MerkleTree::verify(tree.root(), &proof_ne, &k2, &v2).is_err(); Ok(()) } diff --git a/src/primitives/mod.rs b/src/primitives/mod.rs new file mode 100644 index 0000000..ad3ec6a --- /dev/null +++ b/src/primitives/mod.rs @@ -0,0 +1 @@ +pub mod merkletree;