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    /// Run the construction benchmark
 24    #[clap(short = 'c', long = "construction")]
 25    construction: bool,
 26
 27    /// Run the insertion benchmark
 28    #[clap(short = 'i', long = "insertion")]
 29    insertion: bool,
 30
 31    /// Run the proof generation benchmark
 32    #[clap(short = 'p', long = "proof-generation")]
 33    proof_generation: bool,
 34}
 35
 36fn main() {
 37    benchmark_tsmt();
 38}
 39
 40/// Run a benchmark for the Tiered SMT.
 41pub fn benchmark_tsmt() {
 42    let args = BenchmarkCmd::parse();
 43    let tree_size = args.size;
 44
 45    // prepare the `leaves` vector for tree creation
 46    let mut leaves = Vec::new();
 47    for i in 0..tree_size {
 48        let key = rand_value::<RpoDigest>();
 49        let value = [ONE, ONE, ONE, Felt::new(i)];
 50        leaves.push((key, value));
 51    }
 52
 53    let mut tree: Option<TieredSmt> = None;
 54
 55    // if the `-c` argument was specified
 56    if args.construction {
 57        tree = Some(construction(leaves.clone(), tree_size).unwrap());
 58    }
 59
 60    // if the `-i` argument was specified
 61    if args.insertion {
 62        if let Some(inner_tree) = tree {
 63            tree = Some(insertion(inner_tree, tree_size).unwrap());
 64        } else {
 65            let inner_tree = TieredSmt::with_leaves(leaves.clone()).unwrap();
 66            tree = Some(insertion(inner_tree, tree_size).unwrap());
 67        }
 68    }
 69
 70    // if the `-p` argument was specified
 71    if args.proof_generation {
 72        if let Some(inner_tree) = tree {
 73            proof_generation(inner_tree, tree_size).unwrap();
 74        } else {
 75            let inner_tree = TieredSmt::with_leaves(leaves).unwrap();
 76            proof_generation(inner_tree, tree_size).unwrap();
 77        }
 78    }
 79}
 80
 81/// Run the construction benchmark for the Tiered SMT.
 82pub fn construction(leaves: Vec<(RpoDigest, Word)>, size: u64) -> Result<TieredSmt, MerkleError> {
 83    println!("Running a construction benchmark:");
 84    let now = Instant::now();
 85    let tree = TieredSmt::with_leaves(leaves)?;
 86    let elapsed = now.elapsed();
 87    println!(
 88        "Constructed a TSMT with {} key-value pairs in {:.3} seconds",
 89        size,
 90        elapsed.as_secs_f32(),
 91    );
 92
 93    // Count how many nodes end up at each tier
 94    let mut nodes_num_16_32_48 = (0, 0, 0);
 95
 96    tree.upper_leaf_nodes().for_each(|(index, _)| match index.depth() {
 97        16 => nodes_num_16_32_48.0 += 1,
 98        32 => nodes_num_16_32_48.1 += 1,
 99        48 => nodes_num_16_32_48.2 += 1,
100        _ => unreachable!(),
101    });
102
103    println!("Number of nodes on depth 16: {}", nodes_num_16_32_48.0);
104    println!("Number of nodes on depth 32: {}", nodes_num_16_32_48.1);
105    println!("Number of nodes on depth 48: {}", nodes_num_16_32_48.2);
106    println!("Number of nodes on depth 64: {}\n", tree.bottom_leaves().count());
107
108    Ok(tree)
109}
110
111/// Run the insertion benchmark for the Tiered SMT.
112pub fn insertion(mut tree: TieredSmt, size: u64) -> Result<TieredSmt, MerkleError> {
113    println!("Running an insertion benchmark:");
114
115    let mut insertion_times = Vec::new();
116
117    for i in 0..20 {
118        let test_key = Rpo256::hash(&rand_value::<u64>().to_be_bytes());
119        let test_value = [ONE, ONE, ONE, Felt::new(size + i)];
120
121        let now = Instant::now();
122        tree.insert(test_key, test_value);
123        let elapsed = now.elapsed();
124        insertion_times.push(elapsed.as_secs_f32());
125    }
126
127    println!(
128        "An average insertion time measured by 20 inserts into a TSMT with {} key-value pairs is {:.3} milliseconds\n",
129        size,
130        // calculate the average by dividing by 20 and convert to milliseconds by multiplying by 
131        // 1000. As a result, we can only multiply by 50
132        insertion_times.iter().sum::<f32>() * 50f32,
133    );
134
135    Ok(tree)
136}
137
138/// Run the proof generation benchmark for the Tiered SMT.
139pub fn proof_generation(mut tree: TieredSmt, size: u64) -> Result<(), MerkleError> {
140    println!("Running a proof generation benchmark:");
141
142    let mut insertion_times = Vec::new();
143
144    for i in 0..20 {
145        let test_key = Rpo256::hash(&rand_value::<u64>().to_be_bytes());
146        let test_value = [ONE, ONE, ONE, Felt::new(size + i)];
147        tree.insert(test_key, test_value);
148
149        let now = Instant::now();
150        let _proof = tree.prove(test_key);
151        let elapsed = now.elapsed();
152        insertion_times.push(elapsed.as_secs_f32());
153    }
154
155    println!(
156        "An average proving time measured by 20 value proofs in a TSMT with {} key-value pairs in {:.3} microseconds",
157        size,
158        // calculate the average by dividing by 20 and convert to microseconds by multiplying by
159        // 1000000. As a result, we can only multiply by 50000
160        insertion_times.iter().sum::<f32>() * 50000f32,
161    );
162
163    Ok(())
164}