Skip to content

Commit c101d94

Browse files
arnaucubeed255ax0
authored
implement the specified sparse merkletree (#82)
* wip * prototype custom predicates 1b * feat: implement custom pred recursion * files reorg, add github CI for rustfmt checks * start sparsemerkletree. impl add_leaf method, initial Leaf & Intermediate types with methods * mt: add hash computation of all the nodes in the tree, add method to print the tree to visualize it as a graphviz * mt: add (till the leaf) method which is used by get,contains,prove methods * mt: add verify (of inclusion) method * mt: update 'down' method to reuse siblings, update get,contains,prove methods (the three use 'down' under the hood) * Add nonexistence proofs and iterator * Add iterator test * migrate usage of old merkletree to the new merkletree impl in POD2 code --------- Co-authored-by: Eduard S. <eduardsanou@posteo.net> Co-authored-by: Ahmad <root@ahmadafuni.com>
1 parent 2e9719a commit c101d94

File tree

9 files changed

+649
-198
lines changed

9 files changed

+649
-198
lines changed

src/backends/mock_main/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ pub mod tests {
485485
pk: "ZooDeel".into(),
486486
};
487487
let pay_stub_pod = pay_stub_builder.sign(&mut signer)?;
488-
let kyc_builder = zu_kyc_pod_builder(&params, &gov_id_pod, &pay_stub_pod);
488+
let kyc_builder = zu_kyc_pod_builder(&params, &gov_id_pod, &pay_stub_pod)?;
489489

490490
let mut prover = MockProver {};
491491
let kyc_pod = kyc_builder.prove(&mut prover)?;
@@ -501,7 +501,7 @@ pub mod tests {
501501

502502
#[test]
503503
fn test_mock_main_great_boy() -> Result<()> {
504-
let great_boy_builder = great_boy_pod_full_flow();
504+
let great_boy_builder = great_boy_pod_full_flow()?;
505505

506506
let mut prover = MockProver {};
507507
let great_boy_pod = great_boy_builder.prove(&mut prover)?;
@@ -520,7 +520,7 @@ pub mod tests {
520520

521521
#[test]
522522
fn test_mock_main_tickets() -> Result<()> {
523-
let tickets_builder = tickets_pod_full_flow();
523+
let tickets_builder = tickets_pod_full_flow()?;
524524
let mut prover = MockProver {};
525525
let proof_pod = tickets_builder.prove(&mut prover)?;
526526
let pod = proof_pod.pod.into_any().downcast::<MockMainPod>().unwrap();

src/backends/mock_signed.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use anyhow::Result;
22
use std::any::Any;
33
use std::collections::HashMap;
44

5+
use crate::constants::MAX_DEPTH;
56
use crate::middleware::{
67
containers::Dictionary, hash_str, AnchoredKey, Hash, Params, Pod, PodId, PodSigner, PodType,
78
Statement, Value, KEY_SIGNER, KEY_TYPE,
@@ -19,7 +20,7 @@ impl PodSigner for MockSigner {
1920
kvs.insert(hash_str(&KEY_SIGNER), Value(pk_hash.0));
2021
kvs.insert(hash_str(&KEY_TYPE), Value::from(PodType::MockSigned));
2122

22-
let dict = Dictionary::new(&kvs);
23+
let dict = Dictionary::new(&kvs)?;
2324
let id = PodId(dict.commitment());
2425
let signature = format!("{}_signed_by_{}", id, pk_hash);
2526
Ok(Box::new(MockSignedPod {
@@ -49,13 +50,17 @@ impl Pod for MockSignedPod {
4950
}
5051

5152
// Verify id
52-
let mt = MerkleTree::new(
53+
let mt = match MerkleTree::new(
54+
MAX_DEPTH,
5355
&self
5456
.dict
5557
.iter()
5658
.map(|(&k, &v)| (k, v))
5759
.collect::<HashMap<Value, Value>>(),
58-
);
60+
) {
61+
Ok(mt) => mt,
62+
Err(_) => return false,
63+
};
5964
let id = PodId(mt.root());
6065
if id != self.id {
6166
return false;
@@ -93,14 +98,16 @@ impl Pod for MockSignedPod {
9398

9499
#[cfg(test)]
95100
pub mod tests {
101+
use plonky2::field::types::Field;
102+
use std::iter;
103+
96104
use super::*;
105+
use crate::constants::MAX_DEPTH;
97106
use crate::frontend;
98107
use crate::middleware::{self, F, NULL};
99-
use plonky2::field::types::Field;
100-
use std::iter;
101108

102109
#[test]
103-
fn test_mock_signed_0() {
110+
fn test_mock_signed_0() -> Result<()> {
104111
let params = middleware::Params::default();
105112
let mut pod = frontend::SignedPodBuilder::new(&params);
106113
pod.insert("idNumber", "4242424242");
@@ -131,7 +138,7 @@ pub mod tests {
131138
.map(|(AnchoredKey(_, k), v)| (Value(k.0), v))
132139
.chain(iter::once(bad_kv))
133140
.collect::<HashMap<Value, Value>>();
134-
let bad_mt = MerkleTree::new(&bad_kvs_mt);
141+
let bad_mt = MerkleTree::new(MAX_DEPTH, &bad_kvs_mt)?;
135142
bad_pod.dict.mt = bad_mt;
136143
assert_eq!(bad_pod.verify(), false);
137144

@@ -143,8 +150,10 @@ pub mod tests {
143150
.map(|(AnchoredKey(_, k), v)| (Value(k.0), v))
144151
.chain(iter::once(bad_kv))
145152
.collect::<HashMap<Value, Value>>();
146-
let bad_mt = MerkleTree::new(&bad_kvs_mt);
153+
let bad_mt = MerkleTree::new(MAX_DEPTH, &bad_kvs_mt)?;
147154
bad_pod.dict.mt = bad_mt;
148155
assert_eq!(bad_pod.verify(), false);
156+
157+
Ok(())
149158
}
150159
}

src/constants.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub const MAX_DEPTH: usize = 32;

src/examples.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use anyhow::Result;
12
use std::collections::HashMap;
23

34
use crate::backends::mock_signed::MockSigner;
@@ -24,8 +25,8 @@ pub fn zu_kyc_pod_builder(
2425
params: &Params,
2526
gov_id: &SignedPod,
2627
pay_stub: &SignedPod,
27-
) -> MainPodBuilder {
28-
let sanction_list = Value::Dictionary(Dictionary::new(&HashMap::new())); // empty dictionary
28+
) -> Result<MainPodBuilder> {
29+
let sanction_list = Value::Dictionary(Dictionary::new(&HashMap::new())?); // empty dictionary
2930
let now_minus_18y: i64 = 1169909388;
3031
let now_minus_1y: i64 = 1706367566;
3132

@@ -41,7 +42,7 @@ pub fn zu_kyc_pod_builder(
4142
));
4243
kyc.pub_op(op!(eq, (pay_stub, "startDate"), now_minus_1y));
4344

44-
kyc
45+
Ok(kyc)
4546
}
4647

4748
// GreatBoy
@@ -130,7 +131,7 @@ pub fn great_boy_pod_builder(
130131
great_boy
131132
}
132133

133-
pub fn great_boy_pod_full_flow() -> MainPodBuilder {
134+
pub fn great_boy_pod_full_flow() -> Result<MainPodBuilder> {
134135
let params = Params {
135136
max_input_signed_pods: 6,
136137
max_statements: 100,
@@ -179,8 +180,8 @@ pub fn great_boy_pod_full_flow() -> MainPodBuilder {
179180
alice_friend_pods.push(friend.sign(&mut bob_signer).unwrap());
180181
alice_friend_pods.push(friend.sign(&mut charlie_signer).unwrap());
181182

182-
let good_boy_issuers_dict = Value::Dictionary(Dictionary::new(&HashMap::new())); // empty
183-
great_boy_pod_builder(
183+
let good_boy_issuers_dict = Value::Dictionary(Dictionary::new(&HashMap::new())?); // empty
184+
Ok(great_boy_pod_builder(
184185
&params,
185186
[
186187
&bob_good_boys[0],
@@ -191,7 +192,7 @@ pub fn great_boy_pod_full_flow() -> MainPodBuilder {
191192
[&alice_friend_pods[0], &alice_friend_pods[1]],
192193
&good_boy_issuers_dict,
193194
alice,
194-
)
195+
))
195196
}
196197

197198
// Tickets
@@ -229,15 +230,15 @@ pub fn tickets_pod_builder(
229230
builder
230231
}
231232

232-
pub fn tickets_pod_full_flow() -> MainPodBuilder {
233+
pub fn tickets_pod_full_flow() -> Result<MainPodBuilder> {
233234
let params = Params::default();
234235
let builder = tickets_sign_pod_builder(&params);
235236
let signed_pod = builder.sign(&mut MockSigner { pk: "test".into() }).unwrap();
236-
tickets_pod_builder(
237+
Ok(tickets_pod_builder(
237238
&params,
238239
&signed_pod,
239240
123,
240241
true,
241-
&Value::Dictionary(Dictionary::new(&HashMap::new())),
242-
)
242+
&Value::Dictionary(Dictionary::new(&HashMap::new())?),
243+
))
243244
}

src/frontend/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ pub mod tests {
510510
let pay_stub = pay_stub.sign(&mut signer).unwrap();
511511
println!("{}", pay_stub);
512512

513-
let kyc = zu_kyc_pod_builder(&params, &gov_id, &pay_stub);
513+
let kyc = zu_kyc_pod_builder(&params, &gov_id, &pay_stub)?;
514514
println!("{}", kyc);
515515

516516
// TODO: prove kyc with MockProver and print it
@@ -520,7 +520,7 @@ pub mod tests {
520520

521521
#[test]
522522
fn test_front_great_boy() -> Result<()> {
523-
let great_boy = great_boy_pod_full_flow();
523+
let great_boy = great_boy_pod_full_flow()?;
524524
println!("{}", great_boy);
525525

526526
// TODO: prove kyc with MockProver and print it
@@ -530,7 +530,7 @@ pub mod tests {
530530

531531
#[test]
532532
fn test_front_tickets() -> Result<()> {
533-
let builder = tickets_pod_full_flow();
533+
let builder = tickets_pod_full_flow()?;
534534
println!("{}", builder);
535535

536536
Ok(())

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod backends;
2+
pub mod constants;
23
pub mod frontend;
34
pub mod middleware;
45
pub mod primitives;

src/middleware/containers.rs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use plonky2::plonk::config::Hasher;
66
use std::collections::HashMap;
77

88
use super::{Hash, Value, EMPTY};
9+
use crate::constants::MAX_DEPTH;
910
use crate::primitives::merkletree::{MerkleProof, MerkleTree};
1011

1112
/// Dictionary: the user original keys and values are hashed to be used in the leaf.
@@ -18,37 +19,37 @@ pub struct Dictionary {
1819
}
1920

2021
impl Dictionary {
21-
pub fn new(kvs: &HashMap<Hash, Value>) -> Self {
22+
pub fn new(kvs: &HashMap<Hash, Value>) -> Result<Self> {
2223
let kvs: HashMap<Value, Value> = kvs.into_iter().map(|(&k, &v)| (Value(k.0), v)).collect();
23-
Self {
24-
mt: MerkleTree::new(&kvs),
25-
}
24+
Ok(Self {
25+
mt: MerkleTree::new(MAX_DEPTH, &kvs)?,
26+
})
2627
}
2728
pub fn commitment(&self) -> Hash {
2829
self.mt.root()
2930
}
3031
pub fn get(&self, key: &Value) -> Result<Value> {
3132
self.mt.get(key)
3233
}
33-
pub fn prove(&self, key: &Value) -> Result<MerkleProof> {
34+
pub fn prove(&self, key: &Value) -> Result<(Value, MerkleProof)> {
3435
self.mt.prove(key)
3536
}
3637
pub fn prove_nonexistence(&self, key: &Value) -> Result<MerkleProof> {
3738
self.mt.prove_nonexistence(key)
3839
}
3940
pub fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()> {
40-
MerkleTree::verify(root, proof, key, value)
41+
MerkleTree::verify(MAX_DEPTH, root, proof, key, value)
4142
}
4243
pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Value) -> Result<()> {
43-
MerkleTree::verify_nonexistence(root, proof, key)
44+
MerkleTree::verify_nonexistence(MAX_DEPTH, root, proof, key)
4445
}
45-
pub fn iter(&self) -> std::collections::hash_map::Iter<Value, Value> {
46+
pub fn iter(&self) -> crate::primitives::merkletree::Iter {
4647
self.mt.iter()
4748
}
4849
}
4950
impl<'a> IntoIterator for &'a Dictionary {
5051
type Item = (&'a Value, &'a Value);
51-
type IntoIter = std::collections::hash_map::Iter<'a, Value, Value>;
52+
type IntoIter = crate::primitives::merkletree::Iter<'a>;
5253

5354
fn into_iter(self) -> Self::IntoIter {
5455
self.mt.iter()
@@ -71,37 +72,38 @@ pub struct Set {
7172
}
7273

7374
impl Set {
74-
pub fn new(set: &Vec<Value>) -> Self {
75+
pub fn new(set: &Vec<Value>) -> Result<Self> {
7576
let kvs: HashMap<Value, Value> = set
7677
.into_iter()
7778
.map(|e| {
7879
let h = PoseidonHash::hash_no_pad(&e.0).elements;
7980
(Value(h), EMPTY)
8081
})
8182
.collect();
82-
Self {
83-
mt: MerkleTree::new(&kvs),
84-
}
83+
Ok(Self {
84+
mt: MerkleTree::new(MAX_DEPTH, &kvs)?,
85+
})
8586
}
8687
pub fn commitment(&self) -> Hash {
8788
self.mt.root()
8889
}
89-
pub fn contains(&self, value: &Value) -> bool {
90+
pub fn contains(&self, value: &Value) -> Result<bool> {
9091
self.mt.contains(value)
9192
}
9293
pub fn prove(&self, value: &Value) -> Result<MerkleProof> {
93-
self.mt.prove(value)
94+
let (_, proof) = self.mt.prove(value)?;
95+
Ok(proof)
9496
}
9597
pub fn prove_nonexistence(&self, value: &Value) -> Result<MerkleProof> {
9698
self.mt.prove_nonexistence(value)
9799
}
98100
pub fn verify(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> {
99-
MerkleTree::verify(root, proof, value, &EMPTY)
101+
MerkleTree::verify(MAX_DEPTH, root, proof, value, &EMPTY)
100102
}
101103
pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> {
102-
MerkleTree::verify_nonexistence(root, proof, value)
104+
MerkleTree::verify_nonexistence(MAX_DEPTH, root, proof, value)
103105
}
104-
pub fn iter(&self) -> std::collections::hash_map::Iter<Value, Value> {
106+
pub fn iter(&self) -> crate::primitives::merkletree::Iter {
105107
self.mt.iter()
106108
}
107109
}
@@ -123,30 +125,30 @@ pub struct Array {
123125
}
124126

125127
impl Array {
126-
pub fn new(array: &Vec<Value>) -> Self {
128+
pub fn new(array: &Vec<Value>) -> Result<Self> {
127129
let kvs: HashMap<Value, Value> = array
128130
.into_iter()
129131
.enumerate()
130132
.map(|(i, &e)| (Value::from(i as i64), e))
131133
.collect();
132134

133-
Self {
134-
mt: MerkleTree::new(&kvs),
135-
}
135+
Ok(Self {
136+
mt: MerkleTree::new(MAX_DEPTH, &kvs)?,
137+
})
136138
}
137139
pub fn commitment(&self) -> Hash {
138140
self.mt.root()
139141
}
140142
pub fn get(&self, i: usize) -> Result<Value> {
141143
self.mt.get(&Value::from(i as i64))
142144
}
143-
pub fn prove(&self, i: usize) -> Result<MerkleProof> {
145+
pub fn prove(&self, i: usize) -> Result<(Value, MerkleProof)> {
144146
self.mt.prove(&Value::from(i as i64))
145147
}
146148
pub fn verify(root: Hash, proof: &MerkleProof, i: usize, value: &Value) -> Result<()> {
147-
MerkleTree::verify(root, proof, &Value::from(i as i64), value)
149+
MerkleTree::verify(MAX_DEPTH, root, proof, &Value::from(i as i64), value)
148150
}
149-
pub fn iter(&self) -> std::collections::hash_map::Iter<Value, Value> {
151+
pub fn iter(&self) -> crate::primitives::merkletree::Iter {
150152
self.mt.iter()
151153
}
152154
}

src/middleware/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ pub type Entry = (String, Value);
4848
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
4949
pub struct Value(pub [F; 4]);
5050

51+
impl Value {
52+
pub fn to_bytes(self) -> Vec<u8> {
53+
self.0
54+
.iter()
55+
.flat_map(|e| e.to_canonical_u64().to_le_bytes())
56+
.collect()
57+
}
58+
}
59+
5160
impl Ord for Value {
5261
fn cmp(&self, other: &Self) -> Ordering {
5362
for (lhs, rhs) in self.0.iter().zip(other.0.iter()).rev() {

0 commit comments

Comments
 (0)