arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/main.rs
src/main.rsRaw
  1use clap::Parser;
  2use miden_crypto::{
  3    hash::rpo::RpoDigest,
  4    merkle::MerkleError,
  5    Felt, Word, ONE,
  6    {hash::rpo::Rpo256, merkle::TieredSmt},
  7};
  8use rand_utils::rand_value;
  9use std::time::Instant;
 10
 11#[derive(Parser, Debug)]
 12#[clap(
 13    name = "Benchmark",
 14    about = "Tiered SMT benchmark",
 15    version,
 16    rename_all = "kebab-case"
 17)]
 18pub struct BenchmarkCmd {
 19    /// Size of the tree
 20    #[clap(short = 's', long = "size")]
 21    size: u64,
 22}
 23
 24fn main() {
 25    benchmark_tsmt();
 26}
 27
 28/// Run a benchmark for the Tiered SMT.
 29pub fn benchmark_tsmt() {
 30    let args = BenchmarkCmd::parse();
 31    let tree_size = args.size;
 32
 33    // prepare the `leaves` vector for tree creation
 34    let mut entries = Vec::new();
 35    for i in 0..tree_size {
 36        let key = rand_value::<RpoDigest>();
 37        let value = [ONE, ONE, ONE, Felt::new(i)];
 38        entries.push((key, value));
 39    }
 40
 41    let mut tree = construction(entries, tree_size).unwrap();
 42    insertion(&mut tree, tree_size).unwrap();
 43    proof_generation(&mut tree, tree_size).unwrap();
 44}
 45
 46/// Runs the construction benchmark for the Tiered SMT, returning the constructed tree.
 47pub fn construction(entries: Vec<(RpoDigest, Word)>, size: u64) -> Result<TieredSmt, MerkleError> {
 48    println!("Running a construction benchmark:");
 49    let now = Instant::now();
 50    let tree = TieredSmt::with_entries(entries)?;
 51    let elapsed = now.elapsed();
 52    println!(
 53        "Constructed a TSMT with {} key-value pairs in {:.3} seconds",
 54        size,
 55        elapsed.as_secs_f32(),
 56    );
 57
 58    // Count how many nodes end up at each tier
 59    let mut nodes_num_16_32_48 = (0, 0, 0);
 60
 61    tree.upper_leaf_nodes().for_each(|(index, _)| match index.depth() {
 62        16 => nodes_num_16_32_48.0 += 1,
 63        32 => nodes_num_16_32_48.1 += 1,
 64        48 => nodes_num_16_32_48.2 += 1,
 65        _ => unreachable!(),
 66    });
 67
 68    println!("Number of nodes on depth 16: {}", nodes_num_16_32_48.0);
 69    println!("Number of nodes on depth 32: {}", nodes_num_16_32_48.1);
 70    println!("Number of nodes on depth 48: {}", nodes_num_16_32_48.2);
 71    println!("Number of nodes on depth 64: {}\n", tree.bottom_leaves().count());
 72
 73    Ok(tree)
 74}
 75
 76/// Runs the insertion benchmark for the Tiered SMT.
 77pub fn insertion(tree: &mut TieredSmt, size: u64) -> Result<(), MerkleError> {
 78    println!("Running an insertion benchmark:");
 79
 80    let mut insertion_times = Vec::new();
 81
 82    for i in 0..20 {
 83        let test_key = Rpo256::hash(&rand_value::<u64>().to_be_bytes());
 84        let test_value = [ONE, ONE, ONE, Felt::new(size + i)];
 85
 86        let now = Instant::now();
 87        tree.insert(test_key, test_value);
 88        let elapsed = now.elapsed();
 89        insertion_times.push(elapsed.as_secs_f32());
 90    }
 91
 92    println!(
 93        "An average insertion time measured by 20 inserts into a TSMT with {} key-value pairs is {:.3} milliseconds\n",
 94        size,
 95        // calculate the average by dividing by 20 and convert to milliseconds by multiplying by 
 96        // 1000. As a result, we can only multiply by 50
 97        insertion_times.iter().sum::<f32>() * 50f32,
 98    );
 99
100    Ok(())
101}
102
103/// Runs the proof generation benchmark for the Tiered SMT.
104pub fn proof_generation(tree: &mut TieredSmt, size: u64) -> Result<(), MerkleError> {
105    println!("Running a proof generation benchmark:");
106
107    let mut insertion_times = Vec::new();
108
109    for i in 0..20 {
110        let test_key = Rpo256::hash(&rand_value::<u64>().to_be_bytes());
111        let test_value = [ONE, ONE, ONE, Felt::new(size + i)];
112        tree.insert(test_key, test_value);
113
114        let now = Instant::now();
115        let _proof = tree.prove(test_key);
116        let elapsed = now.elapsed();
117        insertion_times.push(elapsed.as_secs_f32());
118    }
119
120    println!(
121        "An average proving time measured by 20 value proofs in a TSMT with {} key-value pairs in {:.3} microseconds",
122        size,
123        // calculate the average by dividing by 20 and convert to microseconds by multiplying by
124        // 1000000. As a result, we can only multiply by 50000
125        insertion_times.iter().sum::<f32>() * 50000f32,
126    );
127
128    Ok(())
129}