Skip to content

Commit ce72bdf

Browse files
authored
Merge pull request #3008 from ProvableHQ/update/kary-bench
Improves kary Merkle tree benchmarking
2 parents fbd9960 + 92a2ae3 commit ce72bdf

File tree

1 file changed

+80
-39
lines changed

1 file changed

+80
-39
lines changed

synthesizer/benches/kary_merkle_tree.rs

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ extern crate criterion;
1919
use snarkvm_algorithms::snark::varuna::VarunaVersion;
2020
use snarkvm_circuit::{AleoV0, Eject, Environment, Inject, Mode, collections::kary_merkle_tree::*};
2121
use snarkvm_console::{
22-
algorithms::Sha3_256,
22+
algorithms::Poseidon8,
2323
collections::kary_merkle_tree::KaryMerkleTree,
2424
network::{
2525
MainnetV0,
26-
prelude::{TestRng, ToBits, Uniform},
26+
prelude::{Rng, TestRng, Uniform},
2727
},
2828
types::Field,
2929
};
@@ -34,78 +34,119 @@ use criterion::Criterion;
3434
type CurrentNetwork = MainnetV0;
3535
type CurrentAleo = AleoV0;
3636

37-
type NativePathHasher = Sha3_256;
38-
type NativeLeafHasher = Sha3_256;
39-
type CircuitPathHasher = snarkvm_circuit::Sha3_256<AleoV0>;
40-
type CircuitLeafHasher = snarkvm_circuit::Sha3_256<AleoV0>;
37+
type NativePathHasher = Poseidon8<CurrentNetwork>;
38+
type NativeLeafHasher = Poseidon8<CurrentNetwork>;
39+
type CircuitPathHasher = snarkvm_circuit::Poseidon8<AleoV0>;
40+
type CircuitLeafHasher = snarkvm_circuit::Poseidon8<AleoV0>;
4141

42-
const DEPTH: u8 = 8;
42+
const DEPTH: u8 = 7;
4343
const ARITY: u8 = 8;
4444

4545
/// Generates the specified number of random Merkle tree leaves.
4646
macro_rules! generate_leaves {
47-
($num_leaves:expr, $rng:expr) => {{ (0..$num_leaves).map(|_| Field::<MainnetV0>::rand($rng).to_bits_le()).collect::<Vec<_>>() }};
47+
("bits", $num_leaves:expr, $rng:expr) => {{
48+
use snarkvm_console::network::prelude::ToBits;
49+
// Generate leaf bits.
50+
(0..$num_leaves).map(|_| Field::<CurrentNetwork>::rand($rng).to_bits_le()).collect::<Vec<_>>()
51+
}};
52+
("fields", $num_leaves:expr, $rng:expr) => {{
53+
use rand::SeedableRng;
54+
use rayon::prelude::*;
55+
// Generate leaf fields in parallel.
56+
(0..$num_leaves)
57+
.map(|_| u64::rand($rng))
58+
.collect::<Vec<u64>>()
59+
.into_par_iter()
60+
.map(|seed| vec![Field::<CurrentNetwork>::rand(&mut rand::rngs::StdRng::seed_from_u64(seed))])
61+
.collect::<Vec<_>>()
62+
}};
4863
}
4964

5065
fn batch_prove(c: &mut Criterion) {
5166
let mut rng = TestRng::default();
5267

68+
// Start the timer.
69+
let timer = std::time::Instant::now();
70+
5371
// Initialize the hashers.
54-
let native_path_hasher = NativePathHasher::default();
55-
let native_leaf_hasher = NativeLeafHasher::default();
56-
let circuit_path_hasher = CircuitPathHasher::new();
57-
let circuit_leaf_hasher = CircuitLeafHasher::new();
72+
let native_path_hasher = NativePathHasher::setup("test").unwrap();
73+
let native_leaf_hasher = NativeLeafHasher::setup("test").unwrap();
74+
let circuit_path_hasher = CircuitPathHasher::new(Mode::Private, native_path_hasher.clone());
75+
let circuit_leaf_hasher = CircuitLeafHasher::new(Mode::Private, native_leaf_hasher.clone());
5876

5977
// Determine the maximum number of leaves.
60-
let max_num_leaves = (ARITY as u32).pow(DEPTH as u32);
78+
let max_num_leaves = (ARITY as u64).pow(DEPTH as u32);
6179
// Initialize the leaves.
62-
let leaves = generate_leaves!(max_num_leaves, &mut rng);
63-
80+
let leaves = generate_leaves!("fields", max_num_leaves, &mut rng);
6481
// Initialize the tree.
6582
let merkle_tree =
6683
KaryMerkleTree::<_, _, DEPTH, ARITY>::new(&native_leaf_hasher, &native_path_hasher, &leaves).unwrap();
67-
// Initialize the leaf.
68-
let merkle_leaf = leaves[0].clone();
69-
// Initialize the Merkle path.
70-
let merkle_path = merkle_tree.prove(0, &merkle_leaf).unwrap();
7184

72-
// Start the timer.
85+
// Log the current time elapsed.
86+
println!(" • Synthesized the Merkle tree in: {} secs", timer.elapsed().as_secs());
7387
let timer = std::time::Instant::now();
7488

75-
// Construct the circuit.
76-
CurrentAleo::reset();
89+
// Construct the assignment closure.
90+
let generate_assignment = |rng: &mut TestRng| {
91+
// Construct the circuit.
92+
CurrentAleo::reset();
93+
94+
// Select the leaf index to prove.
95+
let leaf_index = rng.gen_range(0..max_num_leaves as usize);
96+
// Initialize the leaf.
97+
let merkle_leaf = leaves[leaf_index].clone();
98+
// Initialize the Merkle path.
99+
let merkle_path = merkle_tree.prove(leaf_index, &merkle_leaf).unwrap();
77100

78-
// Initialize the Merkle path circuit.
79-
let path = KaryMerklePath::<CurrentAleo, snarkvm_circuit::Sha3_256<CurrentAleo>, DEPTH, ARITY>::new(
80-
Mode::Private,
81-
merkle_path,
82-
);
83-
// Initialize the Merkle root.
84-
let root = <CircuitPathHasher as PathHash<CurrentAleo>>::Hash::new(Mode::Private, *merkle_tree.root());
85-
// Initialize the Merkle leaf.
86-
let leaf: Vec<_> = Inject::new(Mode::Private, merkle_leaf);
101+
// Uncomment me to enable logging.
102+
// println!("\t• Proving leaf index: {leaf_index}");
87103

88-
// Verify the merkle path.
89-
let candidate = path.verify(&circuit_leaf_hasher, &circuit_path_hasher, &root, &leaf);
90-
assert!(candidate.eject_value());
104+
// Initialize the Merkle path circuit.
105+
let path = KaryMerklePath::<CurrentAleo, CircuitPathHasher, DEPTH, ARITY>::new(Mode::Private, merkle_path);
106+
// Initialize the Merkle leaf circuit.
107+
let leaf: Vec<_> = Inject::new(Mode::Private, merkle_leaf);
108+
// Initialize the Merkle root circuit.
109+
let root = <CircuitPathHasher as PathHash<CurrentAleo>>::Hash::new(Mode::Private, *merkle_tree.root());
91110

92-
// Construct the assignment.
93-
let assignment = CurrentAleo::eject_assignment_and_reset();
111+
// Verify the Merkle path circuit.
112+
let candidate = path.verify(&circuit_leaf_hasher, &circuit_path_hasher, &root, &leaf);
113+
assert!(candidate.eject_value());
94114

115+
// Eject the assignment.
116+
CurrentAleo::eject_assignment_and_reset()
117+
};
118+
119+
// Synthesize a single assignment.
120+
let assignment = generate_assignment(&mut rng);
121+
122+
// Log the current time elapsed.
95123
println!(" • Synthesized the circuit in: {} ms", timer.elapsed().as_millis());
124+
let timer = std::time::Instant::now();
96125

97126
// Load the universal srs.
98127
let universal_srs = UniversalSRS::<CurrentNetwork>::load().unwrap();
99128
// Construct the proving key.
100129
let (proving_key, _) = universal_srs.to_circuit_key("KaryMerklePathVerification", &assignment).unwrap();
101130

131+
// Log the current time elapsed.
132+
println!(" • Generated the proving key in: {} ms", timer.elapsed().as_millis());
133+
println!("\t• Number of public & private variables: {:?}", (assignment.num_public(), assignment.num_private()));
134+
println!("\t• Number of constraints: {}", assignment.num_constraints());
135+
println!("\t• Number of nonzeros: {:?}", assignment.num_nonzeros());
136+
102137
// Bench the proof construction.
103-
for num_assignments in &[1, 2, 4, 8] {
138+
for num_assignments in &[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] {
139+
// Reset the timer.
140+
let timer = std::time::Instant::now();
141+
104142
// Construct the assignments.
105143
let assignments =
106-
[(proving_key.clone(), (0..*num_assignments).map(|_| assignment.clone()).collect::<Vec<_>>())];
144+
[(proving_key.clone(), (0..*num_assignments).map(|_| generate_assignment(&mut rng)).collect::<Vec<_>>())];
145+
146+
// Log the current time elapsed.
147+
println!(" • Generated {num_assignments} assignments in: {} ms", timer.elapsed().as_millis());
107148

108-
let varuna_version = VarunaVersion::V1;
149+
let varuna_version = VarunaVersion::V2;
109150
c.bench_function(&format!("KaryMerkleTree batch prove {num_assignments} assignments"), |b| {
110151
b.iter(|| {
111152
let _proof =

0 commit comments

Comments
 (0)