Skip to content

Commit 86cb2b2

Browse files
committed
traitify the MerkleTree to make it extendable by Containers, so that the tree methods are exposed at Dictionary,Set,Array types
1 parent cce08a6 commit 86cb2b2

File tree

6 files changed

+143
-52
lines changed

6 files changed

+143
-52
lines changed

book/src/merkletree.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -144,31 +144,28 @@ For the current use cases, we don't need to prove that the key exists but the va
144144
## Interface
145145

146146
```rust
147-
impl MerkleTree {
148-
/// builds a new `MerkleTree` where the leaves contain the given key-values
149-
fn new(kvs: HashMap<Value, Value>) -> Self;
150-
147+
trait MerkleTreeTrait {
151148
/// returns the root of the tree
152149
fn root(&self) -> Hash;
153-
150+
154151
/// returns the value at the given key
155-
pub fn get(&self, key: &Value) -> Value;
156-
152+
fn get(&self, key: &Value) -> Result<Value>;
153+
157154
/// returns a proof of existence, which proves that the given key exists in
158155
/// the tree. It returns the `MerkleProof`.
159156
fn prove(&self, key: &Value) -> Result<MerkleProof>;
160-
157+
161158
/// returns a proof of non-existence, which proves that the given `key`
162159
/// does not exist in the tree
163160
fn prove_nonexistence(&self, key: &Value) -> Result<MerkleProof>;
164-
161+
165162
/// verifies an inclusion proof for the given `key` and `value`
166163
fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()>;
167-
164+
168165
/// verifies a non-inclusion proof for the given `key`, that is, the given
169166
/// `key` does not exist in the tree
170167
fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Value) -> Result<()>;
171-
168+
172169
/// returns an iterator over the leaves of the tree
173170
fn iter(&self) -> std::collections::hash_map::Iter<Value, Value>;
174171
}

book/src/values.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,16 @@ The array, set and dictionary types are similar types. While all of them use [a
5151
- `leaf.key=hash(original_key)`
5252
- `leaf.value=hash(original_value)`
5353
- **array**: the elements are placed at the value field of each leaf, and the key field is just the array index (integer)
54-
- `leaf.value=original_value`
5554
- `leaf.key=i`
55+
- `leaf.value=original_value`
5656
- **set**: the value field of the leaf is unused, and the key contains the hash of the element
5757
- `leaf.key=hash(original_value)`
5858
- `leaf.value=0`
5959

6060
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.
6161

62+
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).
63+
6264
<br><br>
6365

6466
---

src/backends/mock_signed.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::middleware::{
22
containers::{Container, Dictionary},
33
hash_str, Hash, Params, PodId, PodSigner, PodType, SignedPod, Value, KEY_SIGNER, KEY_TYPE,
44
};
5-
use crate::primitives::merkletree::MerkleTree;
5+
use crate::primitives::merkletree::{MerkleTree, MerkleTreeTrait};
66
use anyhow::Result;
77
use std::any::Any;
88
use std::collections::HashMap;
@@ -19,7 +19,7 @@ impl PodSigner for MockSigner {
1919
kvs.insert(hash_str(&KEY_TYPE), Value::from(PodType::MockSigned));
2020

2121
let dict = Dictionary::new(&kvs);
22-
let id = PodId(dict.cm());
22+
let id = PodId(dict.root());
2323
let signature = format!("{}_signed_by_{}", id, pk_hash);
2424
Ok(Box::new(MockSignedPod {
2525
dict,
@@ -48,7 +48,7 @@ impl SignedPod for MockSignedPod {
4848
}
4949

5050
// Verify id
51-
let mt = MerkleTree::new(&self.dict.mt.kvs);
51+
let mt = MerkleTree::construct(&self.dict.mt.kvs);
5252
let id = PodId(mt.root());
5353
if id != self.id {
5454
return false;
@@ -122,7 +122,7 @@ pub mod tests {
122122
.into_iter()
123123
.map(|(k, v)| (Value(k.0), v))
124124
.collect::<HashMap<Value, Value>>();
125-
let bad_mt = MerkleTree::new(&bad_kvs_mt);
125+
let bad_mt = MerkleTree::construct(&bad_kvs_mt);
126126
bad_pod.dict.mt = bad_mt;
127127
assert_eq!(bad_pod.verify(), false);
128128

@@ -133,7 +133,7 @@ pub mod tests {
133133
.into_iter()
134134
.map(|(k, v)| (Value(k.0), v))
135135
.collect::<HashMap<Value, Value>>();
136-
let bad_mt = MerkleTree::new(&bad_kvs_mt);
136+
let bad_mt = MerkleTree::construct(&bad_kvs_mt);
137137
bad_pod.dict.mt = bad_mt;
138138
assert_eq!(bad_pod.verify(), false);
139139
}

src/frontend.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ use std::fmt;
99

1010
use crate::middleware::{
1111
self,
12-
containers::{Array, Container, Dictionary, Set},
12+
containers::{Array, Dictionary, Set},
1313
hash_str, Hash, MainPodInputs, NativeOperation, NativeStatement, Params, PodId, PodProver,
1414
PodSigner, SELF,
1515
};
16+
use crate::primitives::merkletree::MerkleTreeTrait;
1617

1718
/// This type is just for presentation purposes.
1819
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
@@ -52,9 +53,9 @@ impl From<&Value> for middleware::Value {
5253
match v {
5354
Value::String(s) => middleware::Value(hash_str(s).0),
5455
Value::Int(v) => middleware::Value::from(*v),
55-
Value::Dictionary(d) => middleware::Value(d.cm().0),
56-
Value::Set(s) => middleware::Value(s.cm().0),
57-
Value::Array(a) => middleware::Value(a.cm().0),
56+
Value::Dictionary(d) => middleware::Value(d.root().0),
57+
Value::Set(s) => middleware::Value(s.root().0),
58+
Value::Array(a) => middleware::Value(a.root().0),
5859
}
5960
}
6061
}
@@ -64,9 +65,9 @@ impl fmt::Display for Value {
6465
match self {
6566
Value::String(s) => write!(f, "\"{}\"", s),
6667
Value::Int(v) => write!(f, "{}", v),
67-
Value::Dictionary(d) => write!(f, "dict:{}", d.cm()),
68-
Value::Set(s) => write!(f, "set:{}", s.cm()),
69-
Value::Array(a) => write!(f, "arr:{}", a.cm()),
68+
Value::Dictionary(d) => write!(f, "dict:{}", d.root()),
69+
Value::Set(s) => write!(f, "set:{}", s.root()),
70+
Value::Array(a) => write!(f, "arr:{}", a.root()),
7071
}
7172
}
7273
}

src/middleware/containers.rs

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
/// This file implements the types defined at
22
/// https://0xparc.github.io/pod2/values.html#dictionary-array-set .
3+
use anyhow::Result;
34
use plonky2::hash::poseidon::PoseidonHash;
45
use plonky2::plonk::config::Hasher;
56
use std::collections::HashMap;
67

78
use super::{Hash, Value, EMPTY};
8-
use crate::primitives::merkletree::MerkleTree;
9+
use crate::primitives::merkletree::{MerkleProof, MerkleTree, MerkleTreeTrait};
910

1011
/// Container is a wrapper of a MerkleTree, used to achieve Dictionary, Set, Array frontend types.
11-
pub trait Container {
12+
/// It offers all the methods of the trait `MerkleTreeTrait`, with an additional constructor `new`
13+
/// that allows each specific type (ie. Dictionary, Set, Array) to define how each type is
14+
/// constructed (for example a Dictionary is built from HashMap<Hash,Value>, whereas a set is built
15+
/// from Vec<Value>).
16+
pub trait Container: MerkleTreeTrait {
1217
type Raw: Clone;
1318

1419
fn new(raw: &Self::Raw) -> Self;
15-
16-
/// returns the commitment to the container
17-
fn cm(&self) -> Hash;
1820
}
1921

2022
/// Dictionary: the user original keys and values are hashed to be used in the leaf.
2123
/// leaf.key=hash(original_key)
2224
/// leaf.value=hash(original_value)
2325
#[derive(Clone, Debug)]
2426
pub struct Dictionary {
25-
pub mt: MerkleTree,
27+
mt: MerkleTree,
2628
}
2729

2830
impl Container for Dictionary {
@@ -31,13 +33,33 @@ impl Container for Dictionary {
3133
fn new(raw: &Self::Raw) -> Self {
3234
let kvs: HashMap<Value, Value> = raw.into_iter().map(|(&k, &v)| (Value(k.0), v)).collect();
3335
Self {
34-
mt: MerkleTree::new(&kvs),
36+
mt: MerkleTree::construct(&kvs),
3537
}
3638
}
39+
}
3740

38-
fn cm(&self) -> Hash {
41+
impl MerkleTreeTrait for Dictionary {
42+
fn root(&self) -> Hash {
3943
self.mt.root()
4044
}
45+
fn get(&self, key: &Value) -> Result<Value> {
46+
self.mt.get(key)
47+
}
48+
fn prove(&self, key: &Value) -> Result<MerkleProof> {
49+
self.mt.prove(key)
50+
}
51+
fn prove_nonexistence(&self, key: &Value) -> Result<MerkleProof> {
52+
self.mt.prove_nonexistence(key)
53+
}
54+
fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()> {
55+
MerkleTree::verify(root, proof, key, value)
56+
}
57+
fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Value) -> Result<()> {
58+
MerkleTree::verify_nonexistence(root, proof, key)
59+
}
60+
fn iter(&self) -> std::collections::hash_map::Iter<Value, Value> {
61+
self.mt.iter()
62+
}
4163
}
4264

4365
impl PartialEq for Dictionary {
@@ -67,13 +89,33 @@ impl Container for Set {
6789
})
6890
.collect();
6991
Self {
70-
mt: MerkleTree::new(&kvs),
92+
mt: MerkleTree::construct(&kvs),
7193
}
7294
}
95+
}
7396

74-
fn cm(&self) -> Hash {
97+
impl MerkleTreeTrait for Set {
98+
fn root(&self) -> Hash {
7599
self.mt.root()
76100
}
101+
fn get(&self, key: &Value) -> Result<Value> {
102+
self.mt.get(key)
103+
}
104+
fn prove(&self, key: &Value) -> Result<MerkleProof> {
105+
self.mt.prove(key)
106+
}
107+
fn prove_nonexistence(&self, key: &Value) -> Result<MerkleProof> {
108+
self.mt.prove_nonexistence(key)
109+
}
110+
fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()> {
111+
MerkleTree::verify(root, proof, key, value)
112+
}
113+
fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Value) -> Result<()> {
114+
MerkleTree::verify_nonexistence(root, proof, key)
115+
}
116+
fn iter(&self) -> std::collections::hash_map::Iter<Value, Value> {
117+
self.mt.iter()
118+
}
77119
}
78120

79121
impl PartialEq for Set {
@@ -103,13 +145,33 @@ impl Container for Array {
103145
.collect();
104146

105147
Self {
106-
mt: MerkleTree::new(&kvs),
148+
mt: MerkleTree::construct(&kvs),
107149
}
108150
}
151+
}
109152

110-
fn cm(&self) -> Hash {
153+
impl MerkleTreeTrait for Array {
154+
fn root(&self) -> Hash {
111155
self.mt.root()
112156
}
157+
fn get(&self, key: &Value) -> Result<Value> {
158+
self.mt.get(key)
159+
}
160+
fn prove(&self, key: &Value) -> Result<MerkleProof> {
161+
self.mt.prove(key)
162+
}
163+
fn prove_nonexistence(&self, key: &Value) -> Result<MerkleProof> {
164+
self.mt.prove_nonexistence(key)
165+
}
166+
fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()> {
167+
MerkleTree::verify(root, proof, key, value)
168+
}
169+
fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Value) -> Result<()> {
170+
MerkleTree::verify_nonexistence(root, proof, key)
171+
}
172+
fn iter(&self) -> std::collections::hash_map::Iter<Value, Value> {
173+
self.mt.iter()
174+
}
113175
}
114176

115177
impl PartialEq for Array {

0 commit comments

Comments
 (0)