/ algorithms / examples / msm.rs
msm.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use alphavm_algorithms::msm::*;
 20  use alphavm_curves::{
 21      bls12_377::{Fr, G1Projective},
 22      traits::ProjectiveCurve,
 23  };
 24  use alphavm_fields::PrimeField;
 25  use alphavm_utilities::{
 26      cfg_into_iter,
 27      rand::{TestRng, Uniform},
 28  };
 29  
 30  use anyhow::Result;
 31  #[cfg(not(feature = "serial"))]
 32  use rayon::prelude::*;
 33  
 34  const DEFAULT_POWER_OF_TWO: usize = 20;
 35  
 36  /// Run the following command to perform the MSM(s).
 37  /// `cargo run --release --example msm [variant] [power of 2] [number of MSM
 38  /// iterations]`
 39  pub fn main() -> Result<()> {
 40      let args: Vec<String> = std::env::args().collect();
 41      if args.len() < 4 {
 42          eprintln!("Invalid number of arguments. Given: {} - Required: 3", args.len() - 1);
 43          return Ok(());
 44      }
 45  
 46      // Parse the power of two to sample.
 47      let power_of_two = match args[2].as_str().parse::<usize>() {
 48          Ok(power_of_two) => power_of_two,
 49          Err(_) => {
 50              eprintln!("Failed to parse the power of 2, using the default: 1 << {DEFAULT_POWER_OF_TWO}");
 51              DEFAULT_POWER_OF_TWO
 52          }
 53      };
 54  
 55      println!("\nSampling 1 << {power_of_two} pairs for the vMSM...");
 56  
 57      // Sample the bases and scalars.
 58      let samples = 1 << power_of_two;
 59  
 60      let scalars = cfg_into_iter!(0..samples)
 61          .step_by(1 << 16)
 62          .flat_map(|_| {
 63              let rng = &mut TestRng::fixed(123456789);
 64              (0..(1 << 16)).map(|_| Fr::rand(rng).to_bigint()).collect::<Vec<_>>()
 65          })
 66          .collect::<Vec<_>>();
 67  
 68      println!("Sampled 1 << {power_of_two} scalars.");
 69  
 70      let bases = G1Projective::batch_normalization_into_affine(
 71          cfg_into_iter!(0..samples)
 72              .step_by(1 << 16)
 73              .flat_map(|_| {
 74                  let rng = &mut TestRng::fixed(123456789);
 75                  (0..(1 << 16)).map(|_| G1Projective::rand(rng)).collect::<Vec<_>>()
 76              })
 77              .collect::<Vec<_>>(),
 78      );
 79  
 80      println!("Sampled 1 << {power_of_two} bases.");
 81  
 82      // Parse the number of MSM iterations.
 83      let num_iterations = match args[3].as_str().parse::<usize>() {
 84          Ok(num_iterations) => num_iterations,
 85          Err(_) => {
 86              eprintln!("\nFailed to parse the number of iterations, using the default: 1");
 87              1
 88          }
 89      };
 90  
 91      println!("\nPerforming the vMSM...");
 92  
 93      for i in 0..num_iterations {
 94          let timer = std::time::Instant::now();
 95  
 96          // Parse the variant.
 97          match args[1].as_str() {
 98              "batched" => batched::msm(bases.as_slice(), scalars.as_slice()),
 99              "standard" => standard::msm(bases.as_slice(), scalars.as_slice()),
100              _ => panic!("Invalid variant: use 'batched' or 'standard'"),
101          };
102  
103          println!("{i} - Performed the vMSM in {} milliseconds.", timer.elapsed().as_millis());
104      }
105  
106      Ok(())
107  }