Skip to content

Commit 89ffd52

Browse files
authored
Merge branch 'master' into add-rust-overlay
2 parents 7b34629 + 7023e85 commit 89ffd52

13 files changed

Lines changed: 644 additions & 452 deletions

File tree

Cargo.lock

Lines changed: 99 additions & 122 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rln-cli/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ path = "src/examples/stateless.rs"
1313
required-features = ["stateless"]
1414

1515
[dependencies]
16-
rln = { path = "../rln", default-features = false }
16+
rln = { path = "../rln", default-features = true }
1717
zerokit_utils = { path = "../utils" }
18-
clap = { version = "4.5.35", features = ["cargo", "derive", "env"] }
18+
clap = { version = "4.5.38", features = ["cargo", "derive", "env"] }
1919
clap_derive = { version = "4.5.32" }
20-
color-eyre = "0.6.3"
20+
color-eyre = "0.6.4"
2121
serde_json = "1.0"
2222
serde = { version = "1.0", features = ["derive"] }
2323

rln-wasm/Cargo.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ required-features = ["stateless"]
1010

1111
[dependencies]
1212
rln = { path = "../rln", default-features = false }
13-
num-bigint = { version = "0.4.6", default-features = false, features = [
14-
"rand",
15-
"serde",
16-
] }
13+
num-bigint = { version = "0.4.6", default-features = false }
1714
js-sys = "0.3.77"
1815
wasm-bindgen = "0.2.100"
1916
serde-wasm-bindgen = "0.6.5"
@@ -27,7 +24,7 @@ console_error_panic_hook = { version = "0.1.7", optional = true }
2724
zerokit_utils = { path = "../utils" }
2825

2926
[target.'cfg(target_arch = "wasm32")'.dependencies]
30-
getrandom = { version = "0.2.15", features = ["js"] }
27+
getrandom = { version = "0.2.16", features = ["js"] }
3128

3229
[dev-dependencies]
3330
serde_json = "1.0"

rln/Cargo.toml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,13 @@ ark-serialize = { version = "0.5.0", default-features = false, features = [
4040
] }
4141

4242
# error handling
43-
color-eyre = "0.6.3"
43+
color-eyre = "0.6.4"
4444
thiserror = "2.0.12"
4545

4646
# utilities
4747
byteorder = "1.5.0"
4848
cfg-if = "1.0"
49-
num-bigint = { version = "0.4.6", default-features = false, features = [
50-
"rand",
51-
"std",
52-
] }
49+
num-bigint = { version = "0.4.6", default-features = false, features = ["std"] }
5350
num-traits = "0.2.19"
5451
once_cell = "1.21.3"
5552
lazy_static = "1.5.0"
@@ -67,7 +64,6 @@ serde = { version = "1.0", features = ["derive"] }
6764
document-features = { version = "0.2.11", optional = true }
6865

6966
[dev-dependencies]
70-
sled = "0.34.7"
7167
criterion = { version = "0.4.0", features = ["html_reports"] }
7268

7369
[features]

rln/benches/pmtree_benchmark.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,6 @@ pub fn pmtree_benchmark(c: &mut Criterion) {
2626
})
2727
});
2828

29-
c.bench_function("Pmtree::compute_root", |b| {
30-
b.iter(|| {
31-
tree.compute_root().unwrap();
32-
})
33-
});
34-
3529
c.bench_function("Pmtree::get", |b| {
3630
b.iter(|| {
3731
tree.get(0).unwrap();

rln/src/pm_tree_adapter.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,6 @@ impl ZerokitMerkleTree for PmTree {
168168
self.tree.root()
169169
}
170170

171-
fn compute_root(&mut self) -> Result<FrOf<Self::Hasher>> {
172-
Ok(self.tree.root())
173-
}
174-
175171
fn set(&mut self, index: usize, leaf: FrOf<Self::Hasher>) -> Result<()> {
176172
self.tree
177173
.set(index, leaf)

utils/Cargo.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@ bench = false
1515
ark-ff = { version = "0.5.0", default-features = false, features = [
1616
"parallel",
1717
] }
18-
num-bigint = { version = "0.4.6", default-features = false, features = [
19-
"rand",
20-
] }
21-
color-eyre = "0.6.3"
18+
num-bigint = { version = "0.4.6", default-features = false }
19+
color-eyre = "0.6.4"
2220
pmtree = { package = "vacp2p_pmtree", version = "2.0.2", optional = true }
2321
sled = "0.34.7"
2422
serde = "1.0"
2523
lazy_static = "1.5.0"
26-
hex = "0.4"
24+
hex = "0.4.3"
25+
rayon = "1.7.0"
2726

2827
[dev-dependencies]
2928
ark-bn254 = { version = "0.5.0", features = ["std"] }

utils/README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,23 @@ The crate supports two interchangeable Merkle tree implementations:
2020
- **OptimalMerkleTree**
2121
- Only stores nodes used to prove accumulation of set leaves
2222

23+
Both OptimalMerkleTree and FullMerkleTree use [Rayon](https://crates.io/crates/rayon) internally to speed up computation through data parallelism. This provides significant performance improvements, especially during large Merkle tree updates.
24+
2325
### Implementation notes
2426

2527
Glossary:
2628

27-
* depth: level of leaves if we count from levels from 0
28-
* number of levels: depth + 1
29-
* capacity (== number of leaves) -- 1 << depth
30-
* total number of nodes: 1 << (depth + 1)) - 1
29+
- depth: level of leaves if we count from levels from 0
30+
- number of levels: depth + 1
31+
- capacity (number of leaves): 1 << depth
32+
- total number of nodes: 1 << (depth + 1) - 1
3133

3234
So for instance:
33-
* depth: 3
34-
* number of levels: 4
35-
* capacity (number of leaves): 8
36-
* total number of nodes: 15
35+
36+
- depth: 3
37+
- number of levels: 4
38+
- capacity (number of leaves): 8
39+
- total number of nodes: 15
3740

3841
```mermaid
3942
flowchart TD
@@ -53,7 +56,6 @@ flowchart TD
5356
N6 -->|Leaf| L8
5457
```
5558

56-
5759
## Poseidon Hash Implementation
5860

5961
This crate provides an implementation to compute the Poseidon hash round constants and MDS matrices:

utils/benches/merkle_tree_benchmark.rs

Lines changed: 76 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use criterion::{criterion_group, criterion_main, Criterion};
2-
use hex_literal::hex;
32
use lazy_static::lazy_static;
43
use std::{fmt::Display, str::FromStr};
54
use tiny_keccak::{Hasher as _, Keccak};
@@ -47,55 +46,78 @@ impl FromStr for TestFr {
4746
}
4847

4948
lazy_static! {
50-
static ref LEAVES: [TestFr; 4] = [
51-
hex!("0000000000000000000000000000000000000000000000000000000000000001"),
52-
hex!("0000000000000000000000000000000000000000000000000000000000000002"),
53-
hex!("0000000000000000000000000000000000000000000000000000000000000003"),
54-
hex!("0000000000000000000000000000000000000000000000000000000000000004"),
55-
]
56-
.map(TestFr);
49+
static ref LEAVES: Vec<TestFr> = {
50+
let mut leaves = Vec::with_capacity(1 << 20);
51+
for i in 0..(1 << 20) {
52+
let mut bytes = [0u8; 32];
53+
bytes[28..].copy_from_slice(&(i as u32).to_be_bytes());
54+
leaves.push(TestFr(bytes));
55+
}
56+
leaves
57+
};
58+
static ref INDICES: Vec<usize> = (0..(1 << 20)).collect();
5759
}
5860

61+
const NOF_LEAVES: usize = 8192;
62+
5963
pub fn optimal_merkle_tree_benchmark(c: &mut Criterion) {
6064
let mut tree =
61-
OptimalMerkleTree::<Keccak256>::new(2, TestFr([0; 32]), OptimalMerkleConfig::default())
65+
OptimalMerkleTree::<Keccak256>::new(20, TestFr([0; 32]), OptimalMerkleConfig::default())
6266
.unwrap();
6367

68+
for i in 0..NOF_LEAVES {
69+
tree.set(i, LEAVES[i % LEAVES.len()]).unwrap();
70+
}
71+
6472
c.bench_function("OptimalMerkleTree::set", |b| {
73+
let mut index = NOF_LEAVES;
6574
b.iter(|| {
66-
tree.set(0, LEAVES[0]).unwrap();
75+
tree.set(index % (1 << 20), LEAVES[index % LEAVES.len()])
76+
.unwrap();
77+
index = (index + 1) % (1 << 20);
6778
})
6879
});
6980

7081
c.bench_function("OptimalMerkleTree::delete", |b| {
82+
let mut index = 0;
7183
b.iter(|| {
72-
tree.delete(0).unwrap();
73-
})
74-
});
75-
76-
c.bench_function("OptimalMerkleTree::override_range", |b| {
77-
b.iter(|| {
78-
tree.override_range(0, LEAVES.into_iter(), [0, 1, 2, 3].into_iter())
84+
tree.delete(index % NOF_LEAVES).unwrap();
85+
tree.set(index % NOF_LEAVES, LEAVES[index % LEAVES.len()])
7986
.unwrap();
87+
index = (index + 1) % NOF_LEAVES;
8088
})
8189
});
8290

83-
c.bench_function("OptimalMerkleTree::compute_root", |b| {
91+
c.bench_function("OptimalMerkleTree::override_range", |b| {
92+
let mut offset = 0;
8493
b.iter(|| {
85-
tree.compute_root().unwrap();
94+
let range = offset..offset + NOF_LEAVES;
95+
tree.override_range(
96+
offset,
97+
LEAVES[range.clone()].iter().cloned(),
98+
INDICES[range.clone()].iter().cloned(),
99+
)
100+
.unwrap();
101+
offset = (offset + NOF_LEAVES) % (1 << 20);
86102
})
87103
});
88104

89105
c.bench_function("OptimalMerkleTree::get", |b| {
106+
let mut index = 0;
90107
b.iter(|| {
91-
tree.get(0).unwrap();
108+
tree.get(index % NOF_LEAVES).unwrap();
109+
index = (index + 1) % NOF_LEAVES;
92110
})
93111
});
94112

95-
// check intermediate node getter which required additional computation of sub root index
96113
c.bench_function("OptimalMerkleTree::get_subtree_root", |b| {
114+
let mut level = 1;
115+
let mut index = 0;
97116
b.iter(|| {
98-
tree.get_subtree_root(1, 0).unwrap();
117+
tree.get_subtree_root(level % 20, index % (1 << (20 - (level % 20))))
118+
.unwrap();
119+
index = (index + 1) % (1 << (20 - (level % 20)));
120+
level = 1 + (level % 20);
99121
})
100122
});
101123

@@ -108,43 +130,61 @@ pub fn optimal_merkle_tree_benchmark(c: &mut Criterion) {
108130

109131
pub fn full_merkle_tree_benchmark(c: &mut Criterion) {
110132
let mut tree =
111-
FullMerkleTree::<Keccak256>::new(2, TestFr([0; 32]), FullMerkleConfig::default()).unwrap();
133+
FullMerkleTree::<Keccak256>::new(20, TestFr([0; 32]), FullMerkleConfig::default()).unwrap();
134+
135+
for i in 0..NOF_LEAVES {
136+
tree.set(i, LEAVES[i % LEAVES.len()]).unwrap();
137+
}
112138

113139
c.bench_function("FullMerkleTree::set", |b| {
140+
let mut index = NOF_LEAVES;
114141
b.iter(|| {
115-
tree.set(0, LEAVES[0]).unwrap();
142+
tree.set(index % (1 << 20), LEAVES[index % LEAVES.len()])
143+
.unwrap();
144+
index = (index + 1) % (1 << 20);
116145
})
117146
});
118147

119148
c.bench_function("FullMerkleTree::delete", |b| {
149+
let mut index = 0;
120150
b.iter(|| {
121-
tree.delete(0).unwrap();
122-
})
123-
});
124-
125-
c.bench_function("FullMerkleTree::override_range", |b| {
126-
b.iter(|| {
127-
tree.override_range(0, LEAVES.into_iter(), [0, 1, 2, 3].into_iter())
151+
tree.delete(index % NOF_LEAVES).unwrap();
152+
tree.set(index % NOF_LEAVES, LEAVES[index % LEAVES.len()])
128153
.unwrap();
154+
index = (index + 1) % NOF_LEAVES;
129155
})
130156
});
131157

132-
c.bench_function("FullMerkleTree::compute_root", |b| {
158+
c.bench_function("FullMerkleTree::override_range", |b| {
159+
let mut offset = 0;
133160
b.iter(|| {
134-
tree.compute_root().unwrap();
161+
let range = offset..offset + NOF_LEAVES;
162+
tree.override_range(
163+
offset,
164+
LEAVES[range.clone()].iter().cloned(),
165+
INDICES[range.clone()].iter().cloned(),
166+
)
167+
.unwrap();
168+
offset = (offset + NOF_LEAVES) % (1 << 20);
135169
})
136170
});
137171

138172
c.bench_function("FullMerkleTree::get", |b| {
173+
let mut index = 0;
139174
b.iter(|| {
140-
tree.get(0).unwrap();
175+
tree.get(index % NOF_LEAVES).unwrap();
176+
index = (index + 1) % NOF_LEAVES;
141177
})
142178
});
143179

144-
// check intermediate node getter which required additional computation of sub root index
145180
c.bench_function("FullMerkleTree::get_subtree_root", |b| {
181+
let mut level = 1;
182+
let mut index = 0;
146183
b.iter(|| {
147-
tree.get_subtree_root(1, 0).unwrap();
184+
tree.get_subtree_root(level % 20, index % (1 << (20 - (level % 20))))
185+
.unwrap();
186+
index = (index + 1) % (1 << (20 - (level % 20)));
187+
level = 1 + (level % 20);
148188
})
149189
});
150190

0 commit comments

Comments
 (0)