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 }