Skip to content

Commit 0782da0

Browse files
committed
Implement Containers (Dictionary,Set,Array) on top of MerkleTree. And restructure the code.
- Reorganize the code grouping backends, middleware, frontend, (crypto) primitives. - Add containers (Dictionary,Set,Array) at the middleware layer, so that it can be used both by the backend and frontend. The Dictionary, Set, Array use the merkletree differently as specified at https://github.com/0xPARC/pod2/blob/f2575d1524c9e15a5b688eb444ee3c39df242c81/book/src/values.md#dictionary-array-set - The containers introduce the trait Container, which has the method 'cm()'. At the current version this uses a merkletree under the hood, and the method 'cm' returns the merkle root. - Ideally neither frontend nor backend use the MerkleTree type, and they use the wrappers {Dictionary,Set,Array}. Note that the current commit the MerkleTree is used at the mock-backend to check internal values, but not at the struct types. - updated the spec's merkletree section updating the defined interface
1 parent f2575d1 commit 0782da0

File tree

13 files changed

+237
-76
lines changed

13 files changed

+237
-76
lines changed

book/src/merkletree.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,15 @@ impl MerkleTree {
149149
fn new(kvs: HashMap<Value, Value>) -> Self;
150150

151151
/// returns the root of the tree
152-
fn root(&self) -> Result<Hash>;
152+
fn root(&self) -> Hash;
153+
154+
/// returns the value at the given key
155+
pub fn get(&self, key: &Value) -> Value;
153156

154157
/// returns a proof of existence, which proves that the given key exists in
155158
/// the tree. It returns the `value` of the leaf at the given `key`, and
156159
/// the `MerkleProof`.
157-
fn prove(&self, key: &Value) -> Result<(Value, MerkleProof)>;
160+
fn prove(&self, key: &Value) -> Result<MerkleProof>;
158161

159162
/// returns a proof of non-existence, which proves that the given `key`
160163
/// does not exist in the tree

book/src/values.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ The array, set and dictionary types are similar types. While all of them use [a
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-
6362
<br><br>
6463

6564
---

src/backends/mock_main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use plonky2::hash::poseidon::PoseidonHash;
99
use plonky2::plonk::config::Hasher;
1010
use std::any::Any;
1111
use std::fmt;
12-
use std::io::{self, Write};
1312

1413
pub struct MockProver {}
1514

src/backends/mock_signed.rs

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::merkletree::MerkleTree;
21
use crate::middleware::{
2+
containers::{Container, Dictionary},
33
hash_str, Hash, Params, PodId, PodSigner, PodType, SignedPod, Value, KEY_SIGNER, KEY_TYPE,
44
};
5+
use crate::primitives::merkletree::MerkleTree;
56
use anyhow::Result;
67
use std::any::Any;
78
use std::collections::HashMap;
@@ -17,41 +18,46 @@ impl PodSigner for MockSigner {
1718
kvs.insert(hash_str(&KEY_SIGNER), Value(pk_hash.0));
1819
kvs.insert(hash_str(&KEY_TYPE), Value::from(PodType::MockSigned));
1920

20-
let mt = MerkleTree::new(&kvs);
21-
let id = PodId(mt.root()?);
21+
let dict = Dictionary::new(&kvs);
22+
let id = PodId(dict.cm());
2223
let signature = format!("{}_signed_by_{}", id, pk_hash);
23-
Ok(Box::new(MockSignedPod { mt, id, signature }))
24+
Ok(Box::new(MockSignedPod {
25+
dict,
26+
id,
27+
signature,
28+
}))
2429
}
2530
}
2631

2732
#[derive(Clone, Debug)]
2833
pub struct MockSignedPod {
2934
id: PodId,
3035
signature: String,
31-
mt: MerkleTree,
36+
dict: Dictionary,
3237
}
3338

3439
impl SignedPod for MockSignedPod {
3540
fn verify(&self) -> bool {
3641
// Verify type
37-
if Some(&Value::from(PodType::MockSigned)) != self.mt.kvs().get(&hash_str(&KEY_TYPE)) {
42+
let value_at_type = match self.dict.mt.get(&hash_str(&KEY_TYPE).into()) {
43+
Ok(v) => v,
44+
Err(_) => return false,
45+
};
46+
if Value::from(PodType::MockSigned) != value_at_type {
3847
return false;
3948
}
4049

4150
// Verify id
42-
let mt = MerkleTree::new(&self.mt.kvs());
43-
let id = match mt.root() {
44-
Ok(id) => PodId(id),
45-
Err(_) => return false,
46-
};
51+
let mt = MerkleTree::new(&self.dict.mt.kvs);
52+
let id = PodId(mt.root());
4753
if id != self.id {
4854
return false;
4955
}
5056

5157
// Verify signature
52-
let pk_hash = match self.mt.kvs().get(&hash_str(&KEY_SIGNER)) {
53-
Some(v) => v,
54-
None => return false,
58+
let pk_hash = match self.dict.mt.get(&hash_str(&KEY_SIGNER).into()) {
59+
Ok(v) => v,
60+
Err(_) => return false,
5561
};
5662
let signature = format!("{}_signed_by_{}", id, pk_hash);
5763
if signature != self.signature {
@@ -66,7 +72,11 @@ impl SignedPod for MockSignedPod {
6672
}
6773

6874
fn kvs(&self) -> HashMap<Hash, Value> {
69-
self.mt.kvs().clone()
75+
self.dict
76+
.mt
77+
.into_iter()
78+
.map(|(&k, &v)| (Hash(k.0), v))
79+
.collect()
7080
}
7181

7282
fn into_any(self: Box<Self>) -> Box<dyn Any> {
@@ -108,15 +118,23 @@ pub mod tests {
108118
let mut bad_pod = pod.clone();
109119
let mut bad_kvs = bad_pod.kvs();
110120
bad_kvs.insert(hash_str(KEY_SIGNER), Value(PodId(NULL).0 .0));
111-
let bad_mt = MerkleTree::new(&bad_kvs);
112-
bad_pod.mt = bad_mt;
121+
let bad_kvs_mt = &bad_kvs
122+
.into_iter()
123+
.map(|(k, v)| (Value(k.0), v))
124+
.collect::<HashMap<Value, Value>>();
125+
let bad_mt = MerkleTree::new(&bad_kvs_mt);
126+
bad_pod.dict.mt = bad_mt;
113127
assert_eq!(bad_pod.verify(), false);
114128

115129
let mut bad_pod = pod.clone();
116130
let mut bad_kvs = bad_pod.kvs();
117131
bad_kvs.insert(hash_str(KEY_TYPE), Value::from(0));
118-
let bad_mt = MerkleTree::new(&bad_kvs);
119-
bad_pod.mt = bad_mt;
132+
let bad_kvs_mt = &bad_kvs
133+
.into_iter()
134+
.map(|(k, v)| (Value(k.0), v))
135+
.collect::<HashMap<Value, Value>>();
136+
let bad_mt = MerkleTree::new(&bad_kvs_mt);
137+
bad_pod.dict.mt = bad_mt;
120138
assert_eq!(bad_pod.verify(), false);
121139
}
122140
}
File renamed without changes.

src/examples.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
use crate::frontend::{MainPodBuilder, MerkleTree, SignedPod, SignedPodBuilder, Value};
2-
use crate::middleware::{Params, PodType, KEY_SIGNER, KEY_TYPE};
1+
use std::collections::HashMap;
2+
3+
use crate::frontend::{MainPodBuilder, SignedPod, SignedPodBuilder, Value};
4+
use crate::middleware::{
5+
containers::{Container, Dictionary},
6+
Params, PodType, KEY_SIGNER, KEY_TYPE,
7+
};
38
use crate::op;
49

510
// ZuKYC
@@ -22,7 +27,7 @@ pub fn zu_kyc_pod_builder(
2227
gov_id: &SignedPod,
2328
pay_stub: &SignedPod,
2429
) -> MainPodBuilder {
25-
let sanction_list = Value::MerkleTree(MerkleTree { root: 1 });
30+
let sanction_list = Value::Dictionary(Dictionary::new(&HashMap::new())); // empty dictionary
2631
let now_minus_18y: i64 = 1169909388;
2732
let now_minus_1y: i64 = 1706367566;
2833

@@ -178,7 +183,7 @@ pub fn great_boy_pod_full_flow() -> MainPodBuilder {
178183
alice_friend_pods.push(friend.sign(&mut bob_signer).unwrap());
179184
alice_friend_pods.push(friend.sign(&mut charlie_signer).unwrap());
180185

181-
let good_boy_issuers_mt = Value::MerkleTree(MerkleTree { root: 33 });
186+
let good_boy_issuers_dict = Value::Dictionary(Dictionary::new(&HashMap::new())); // empty
182187
great_boy_pod_builder(
183188
&params,
184189
[
@@ -188,7 +193,7 @@ pub fn great_boy_pod_full_flow() -> MainPodBuilder {
188193
&charlie_good_boys[1],
189194
],
190195
[&alice_friend_pods[0], &alice_friend_pods[1]],
191-
&good_boy_issuers_mt,
196+
&good_boy_issuers_dict,
192197
alice,
193198
)
194199
}

src/frontend.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
44
use anyhow::Result;
55
use itertools::Itertools;
6-
use plonky2::field::types::Field;
76
use std::collections::HashMap;
87
use std::convert::From;
98
use std::fmt;
109

1110
use crate::middleware::{
12-
self, hash_str, Hash, MainPodInputs, NativeOperation, NativeStatement, Params, PodId,
13-
PodProver, PodSigner, F, SELF,
11+
self,
12+
containers::{Array, Container, Dictionary, Set},
13+
hash_str, Hash, MainPodInputs, NativeOperation, NativeStatement, Params, PodId, PodProver,
14+
PodSigner, SELF,
1415
};
1516

1617
/// This type is just for presentation purposes.
@@ -25,16 +26,13 @@ pub enum PodClass {
2526
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
2627
pub struct Origin(pub PodClass, pub PodId);
2728

28-
#[derive(Clone, Debug, PartialEq, Eq)]
29-
pub struct MerkleTree {
30-
pub root: u8, // TODO
31-
}
32-
3329
#[derive(Clone, Debug, PartialEq, Eq)]
3430
pub enum Value {
3531
String(String),
3632
Int(i64),
37-
MerkleTree(MerkleTree),
33+
Dictionary(Dictionary),
34+
Set(Set),
35+
Array(Array),
3836
}
3937

4038
impl From<&str> for Value {
@@ -54,13 +52,9 @@ impl From<&Value> for middleware::Value {
5452
match v {
5553
Value::String(s) => middleware::Value(hash_str(s).0),
5654
Value::Int(v) => middleware::Value::from(*v),
57-
// TODO
58-
Value::MerkleTree(mt) => middleware::Value([
59-
F::from_canonical_u64(mt.root as u64),
60-
F::ZERO,
61-
F::ZERO,
62-
F::ZERO,
63-
]),
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),
6458
}
6559
}
6660
}
@@ -70,7 +64,9 @@ impl fmt::Display for Value {
7064
match self {
7165
Value::String(s) => write!(f, "\"{}\"", s),
7266
Value::Int(v) => write!(f, "{}", v),
73-
Value::MerkleTree(mt) => write!(f, "mt:{}", mt.root),
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()),
7470
}
7571
}
7672
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub mod backends;
22
pub mod frontend;
3-
pub mod merkletree;
43
pub mod middleware;
4+
pub mod primitives;
55

66
#[cfg(test)]
77
pub mod examples;

src/main.rs

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/middleware/containers.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/// This file implements the types defined at
2+
/// https://0xparc.github.io/pod2/values.html#dictionary-array-set .
3+
use plonky2::hash::poseidon::PoseidonHash;
4+
use plonky2::plonk::config::Hasher;
5+
use std::collections::HashMap;
6+
7+
use super::{Hash, Value, EMPTY};
8+
use crate::primitives::merkletree::MerkleTree;
9+
10+
/// Contaiter is a wrapper of a MerkleTree, used to achieve Dictionary, Set, Array frontend types.
11+
pub trait Container {
12+
type Raw: Clone;
13+
14+
fn new(raw: &Self::Raw) -> Self;
15+
16+
/// returns the commitment to the container
17+
fn cm(&self) -> Hash;
18+
}
19+
20+
/// Dictionary: the user original keys and values are hashed to be used in the leaf.
21+
/// leaf.key=hash(original_key)
22+
/// leaf.value=hash(original_value)
23+
#[derive(Clone, Debug)]
24+
pub struct Dictionary {
25+
pub mt: MerkleTree,
26+
}
27+
28+
impl Container for Dictionary {
29+
type Raw = HashMap<Hash, Value>;
30+
31+
fn new(raw: &Self::Raw) -> Self {
32+
let kvs: HashMap<Value, Value> = raw.into_iter().map(|(&k, &v)| (Value(k.0), v)).collect();
33+
Self {
34+
mt: MerkleTree::new(&kvs),
35+
}
36+
}
37+
38+
fn cm(&self) -> Hash {
39+
self.mt.root()
40+
}
41+
}
42+
43+
impl PartialEq for Dictionary {
44+
fn eq(&self, other: &Self) -> bool {
45+
self.mt.root() == other.mt.root() && self.mt.root() == other.mt.root()
46+
}
47+
}
48+
impl Eq for Dictionary {}
49+
50+
/// Set: the value field of the leaf is unused, and the key contains the hash of the element.
51+
/// leaf.key=hash(original_value)
52+
/// leaf.value=0
53+
#[derive(Clone, Debug)]
54+
pub struct Set {
55+
mt: MerkleTree,
56+
}
57+
58+
impl Container for Set {
59+
type Raw = Vec<Value>;
60+
61+
fn new(raw: &Self::Raw) -> Self {
62+
let kvs: HashMap<Value, Value> = raw
63+
.into_iter()
64+
.map(|e| {
65+
let h = PoseidonHash::hash_no_pad(&e.0).elements;
66+
(Value(h), EMPTY)
67+
})
68+
.collect();
69+
Self {
70+
mt: MerkleTree::new(&kvs),
71+
}
72+
}
73+
74+
fn cm(&self) -> Hash {
75+
self.mt.root()
76+
}
77+
}
78+
79+
impl PartialEq for Set {
80+
fn eq(&self, other: &Self) -> bool {
81+
self.mt.root() == other.mt.root() && self.mt.root() == other.mt.root()
82+
}
83+
}
84+
impl Eq for Set {}
85+
86+
/// Array: the elements are placed at the value field of each leaf, and the key field is just the
87+
/// array index (integer).
88+
/// leaf.key=i
89+
/// leaf.value=original_value
90+
#[derive(Clone, Debug)]
91+
pub struct Array {
92+
mt: MerkleTree,
93+
}
94+
95+
impl Container for Array {
96+
type Raw = Vec<Value>;
97+
98+
fn new(raw: &Self::Raw) -> Self {
99+
let kvs: HashMap<Value, Value> = raw
100+
.into_iter()
101+
.enumerate()
102+
.map(|(i, &e)| (Value::from(i as i64), e))
103+
.collect();
104+
105+
Self {
106+
mt: MerkleTree::new(&kvs),
107+
}
108+
}
109+
110+
fn cm(&self) -> Hash {
111+
self.mt.root()
112+
}
113+
}
114+
115+
impl PartialEq for Array {
116+
fn eq(&self, other: &Self) -> bool {
117+
self.mt.root() == other.mt.root() && self.mt.root() == other.mt.root()
118+
}
119+
}
120+
impl Eq for Array {}

0 commit comments

Comments
 (0)