From dcdeb8aefa12712ac0278c592cd50f7498d067b9 Mon Sep 17 00:00:00 2001 From: Irfan Bozkurt Date: Thu, 4 Apr 2024 02:09:35 +0300 Subject: [PATCH 1/5] functional wnaf for EC points --- math/src/elliptic_curve/mod.rs | 1 + math/src/elliptic_curve/wnaf.rs | 163 ++++++++++++++++++++++++++++++++ provers/groth16/src/setup.rs | 14 +-- 3 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 math/src/elliptic_curve/wnaf.rs diff --git a/math/src/elliptic_curve/mod.rs b/math/src/elliptic_curve/mod.rs index c34d69e98..7539f1f71 100644 --- a/math/src/elliptic_curve/mod.rs +++ b/math/src/elliptic_curve/mod.rs @@ -4,3 +4,4 @@ pub mod montgomery; pub mod point; pub mod short_weierstrass; pub mod traits; +pub mod wnaf; diff --git a/math/src/elliptic_curve/wnaf.rs b/math/src/elliptic_curve/wnaf.rs new file mode 100644 index 000000000..33bca2919 --- /dev/null +++ b/math/src/elliptic_curve/wnaf.rs @@ -0,0 +1,163 @@ +use core::marker::PhantomData; + +use crate::{ + cyclic_group::IsGroup, + elliptic_curve::short_weierstrass::{ + point::ShortWeierstrassProjectivePoint, traits::IsShortWeierstrass, + }, + field::traits::IsPrimeField, + traits::ByteConversion, + unsigned_integer::traits::IsUnsignedInteger, +}; + +use rayon::iter::IntoParallelRefIterator; +#[cfg(feature = "parallel")] +use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator}; + +pub struct Wnaf +where + EC: IsShortWeierstrass>, + EC::PointRepresentation: Send + Sync, + ScalarField: IsPrimeField, +{ + table: Vec>>, + window_size: usize, + phantom: PhantomData, +} + +impl Wnaf +where + EC: IsShortWeierstrass>, + EC::PointRepresentation: Send + Sync, + ScalarField: IsPrimeField + Sync, +{ + pub fn new(base: ShortWeierstrassProjectivePoint) -> Self { + let scalar_field_bit_size = ScalarField::field_bit_size(); + + let window = Self::get_mul_window_size(); + let in_window = 1 << window; + let outerc = (scalar_field_bit_size + window - 1) / window; + let last_in_window = 1 << (scalar_field_bit_size - (outerc - 1) * window); + + let mut g_outer = base; + let mut g_outers = Vec::with_capacity(outerc); + for _ in 0..outerc { + g_outers.push(g_outer.clone()); // performance? + for _ in 0..window { + g_outer = g_outer.double(); + } + } + + let mut table = + vec![vec![ShortWeierstrassProjectivePoint::::neutral_element(); in_window]; outerc]; + + #[cfg(feature = "parallel")] + let iter = table.par_iter_mut(); + #[cfg(not(feature = "parallel"))] + let iter = table.iter_mut(); + + iter.enumerate().take(outerc).zip(g_outers).for_each( + |((outer, multiples_of_g), g_outer)| { + let curr_in_window = if outer == outerc - 1 { + last_in_window + } else { + in_window + }; + + let mut g_inner = ShortWeierstrassProjectivePoint::::neutral_element(); + for inner in multiples_of_g.iter_mut().take(curr_in_window) { + *inner = g_inner.clone(); // performance? + g_inner = g_inner.operate_with(&g_outer); + } + }, + ); + + Self { + table, + window_size: window, + phantom: PhantomData, + } + } + + pub fn multi_scalar_mul(&self, v: &[T]) -> Vec> + where + T: IsUnsignedInteger + ByteConversion + Sync, + { + v.par_iter().map(|e| self.windowed_mul(e.clone())).collect() + } + + fn windowed_mul(&self, scalar: T) -> ShortWeierstrassProjectivePoint + where + T: IsUnsignedInteger + ByteConversion, + { + let mut res = self.table[0][0].clone(); + + let modulus_size = ScalarField::field_bit_size(); + let outerc = (modulus_size + self.window_size - 1) / self.window_size; + let scalar_bits_le: Vec = scalar + .to_bytes_le() + .iter() + .map(|byte| (0..8).map(|i| (byte >> i) & 1 == 1).collect::>()) + .flatten() + .collect(); + + for outer in 0..outerc { + let mut inner = 0usize; + for i in 0..self.window_size { + if outer * self.window_size + i < modulus_size + && scalar_bits_le[outer * self.window_size + i] + { + inner |= 1 << i; + } + } + res = res.operate_with(&self.table[outer][inner]); + } + + res.to_affine() + } + + fn get_mul_window_size() -> usize { + let scalar_field_bit_size = ScalarField::field_bit_size(); + if scalar_field_bit_size < 32 { + 3 + } else { + (scalar_field_bit_size as f64).ln().ceil() as usize + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + elliptic_curve::{ + short_weierstrass::curves::bls12_381::{curve::BLS12381Curve, default_types::FrField}, + traits::IsEllipticCurve, + }, + unsigned_integer::element::U256, + }; + use rand::*; + + #[test] + fn anal() { + let g1 = BLS12381Curve::generator(); + let wnaf = Wnaf::::new(g1.clone()); + + let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9001); + let mut scalars = Vec::new(); + for _i in 0..100 { + scalars.push(U256::from(rng.gen::())); + } + + let res1: Vec> = scalars + .iter() + .map(|scalar| g1.operate_with_self(scalar.clone()).to_affine()) + .collect(); + + let res2 = wnaf.multi_scalar_mul(&scalars); + + for i in 0..100 { + assert_eq!(res1[i], res2[i]); + } + } +} diff --git a/provers/groth16/src/setup.rs b/provers/groth16/src/setup.rs index 4e941d68b..897e6f712 100644 --- a/provers/groth16/src/setup.rs +++ b/provers/groth16/src/setup.rs @@ -99,11 +99,11 @@ pub fn setup(qap: &QuadraticArithmeticProgram) -> (ProvingKey, VerifyingKey) { beta_g2, delta_g1: g1.operate_with_self(tw.delta.representative()), delta_g2: delta_g2.clone(), - l_tau_g1: batch_operate(&l_tau, &g1), - r_tau_g1: batch_operate(&r_tau, &g1), - r_tau_g2: batch_operate(&r_tau, &g2), - prover_k_tau_g1: batch_operate(&k_tau[qap.num_of_public_inputs..], &g1), - z_powers_of_tau_g1: batch_operate( + l_tau_g1: batch_operate_with_self(&l_tau, &g1), + r_tau_g1: batch_operate_with_self(&r_tau, &g1), + r_tau_g2: batch_operate_with_self(&r_tau, &g2), + prover_k_tau_g1: batch_operate_with_self(&k_tau[qap.num_of_public_inputs..], &g1), + z_powers_of_tau_g1: batch_operate_with_self( &core::iter::successors( // Start from delta^{-1} * t(τ) // Note that t(τ) = (τ^N - 1) because our domain is roots of unity @@ -119,12 +119,12 @@ pub fn setup(qap: &QuadraticArithmeticProgram) -> (ProvingKey, VerifyingKey) { alpha_g1_times_beta_g2, delta_g2, gamma_g2: g2.operate_with_self(tw.gamma.representative()), - verifier_k_tau_g1: batch_operate(&k_tau[..qap.num_of_public_inputs], &g1), + verifier_k_tau_g1: batch_operate_with_self(&k_tau[..qap.num_of_public_inputs], &g1), }, ) } -fn batch_operate( +fn batch_operate_with_self( elems: &[FrElement], point: &ShortWeierstrassProjectivePoint, ) -> Vec> { From 3839fb7d1b03b54d04027c45fa0b5476be567437 Mon Sep 17 00:00:00 2001 From: Irfan Bozkurt Date: Fri, 5 Apr 2024 03:30:11 +0300 Subject: [PATCH 2/5] finalize --- math/benches/criterion_elliptic_curve.rs | 5 +- .../{ => bls12_381}/bls12_381.rs | 0 math/benches/elliptic_curves/bls12_381/mod.rs | 2 + .../benches/elliptic_curves/bls12_381/wnaf.rs | 67 ++++++++++++ math/src/elliptic_curve/wnaf.rs | 103 +++++++++++------- provers/groth16/src/setup.rs | 60 +++++----- 6 files changed, 170 insertions(+), 67 deletions(-) rename math/benches/elliptic_curves/{ => bls12_381}/bls12_381.rs (100%) create mode 100644 math/benches/elliptic_curves/bls12_381/mod.rs create mode 100644 math/benches/elliptic_curves/bls12_381/wnaf.rs diff --git a/math/benches/criterion_elliptic_curve.rs b/math/benches/criterion_elliptic_curve.rs index 53c73aaa0..179bb9704 100644 --- a/math/benches/criterion_elliptic_curve.rs +++ b/math/benches/criterion_elliptic_curve.rs @@ -3,12 +3,13 @@ use pprof::criterion::{Output, PProfProfiler}; mod elliptic_curves; use elliptic_curves::{ - bls12_377::bls12_377_elliptic_curve_benchmarks, bls12_381::bls12_381_elliptic_curve_benchmarks, + bls12_377::bls12_377_elliptic_curve_benchmarks, + bls12_381::{bls12_381::bls12_381_elliptic_curve_benchmarks, wnaf::wnaf_bls12_381_benchmarks}, }; criterion_group!( name = elliptic_curve_benches; config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); - targets = bls12_381_elliptic_curve_benchmarks, bls12_377_elliptic_curve_benchmarks + targets = bls12_381_elliptic_curve_benchmarks, bls12_377_elliptic_curve_benchmarks, wnaf_bls12_381_benchmarks ); criterion_main!(elliptic_curve_benches); diff --git a/math/benches/elliptic_curves/bls12_381.rs b/math/benches/elliptic_curves/bls12_381/bls12_381.rs similarity index 100% rename from math/benches/elliptic_curves/bls12_381.rs rename to math/benches/elliptic_curves/bls12_381/bls12_381.rs diff --git a/math/benches/elliptic_curves/bls12_381/mod.rs b/math/benches/elliptic_curves/bls12_381/mod.rs new file mode 100644 index 000000000..8b1e7e74f --- /dev/null +++ b/math/benches/elliptic_curves/bls12_381/mod.rs @@ -0,0 +1,2 @@ +pub mod bls12_381; +pub mod wnaf; diff --git a/math/benches/elliptic_curves/bls12_381/wnaf.rs b/math/benches/elliptic_curves/bls12_381/wnaf.rs new file mode 100644 index 000000000..b0af54cc9 --- /dev/null +++ b/math/benches/elliptic_curves/bls12_381/wnaf.rs @@ -0,0 +1,67 @@ +use criterion::{black_box, Criterion}; +use lambdaworks_math::{ + cyclic_group::IsGroup, + elliptic_curve::{ + short_weierstrass::curves::bls12_381::{ + curve::BLS12381Curve, + default_types::{FrElement, FrField}, + }, + traits::IsEllipticCurve, + wnaf::WnafTable, + }, + unsigned_integer::element::U256, +}; +use rand::{Rng, SeedableRng}; + +#[allow(dead_code)] +pub fn wnaf_bls12_381_benchmarks(c: &mut Criterion) { + let scalar_size = 10000; + + let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9001); + let mut scalars = Vec::new(); + for _i in 0..scalar_size { + scalars.push(FrElement::new(U256::from(rng.gen::()))); + } + + let g = BLS12381Curve::generator(); + + let mut group = c.benchmark_group("BLS12-381 WNAF"); + group.significance_level(0.1).sample_size(10000); + group.throughput(criterion::Throughput::Elements(1)); + + group.bench_function( + format!("Naive BLS12-381 MSM with size {}", scalar_size), + |bencher| { + bencher.iter(|| { + black_box( + scalars + .clone() + .iter() + .map(|scalar| { + black_box( + black_box(g.clone()) + .operate_with_self(black_box(scalar.clone().representative())) + .to_affine(), + ) + }) + .collect::>(), + ) + }); + }, + ); + + group.bench_function( + format!("WNAF BLS12-381 MSM with size {}", scalar_size), + |bencher| { + bencher.iter(|| { + black_box( + black_box(WnafTable::::new( + black_box(&g.clone()), + scalar_size, + )) + .multi_scalar_mul(&black_box(scalars.clone())), + ) + }); + }, + ); +} diff --git a/math/src/elliptic_curve/wnaf.rs b/math/src/elliptic_curve/wnaf.rs index 33bca2919..c166d7f77 100644 --- a/math/src/elliptic_curve/wnaf.rs +++ b/math/src/elliptic_curve/wnaf.rs @@ -1,48 +1,51 @@ -use core::marker::PhantomData; - use crate::{ cyclic_group::IsGroup, elliptic_curve::short_weierstrass::{ point::ShortWeierstrassProjectivePoint, traits::IsShortWeierstrass, }, - field::traits::IsPrimeField, + field::{element::FieldElement, traits::IsPrimeField}, traits::ByteConversion, - unsigned_integer::traits::IsUnsignedInteger, }; +use alloc::{vec, vec::Vec}; +use core::marker::PhantomData; -use rayon::iter::IntoParallelRefIterator; #[cfg(feature = "parallel")] -use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator}; +use rayon::iter::{ + IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, +}; -pub struct Wnaf +extern crate std; // To be able to use f64::ln() + +pub struct WnafTable where EC: IsShortWeierstrass>, EC::PointRepresentation: Send + Sync, - ScalarField: IsPrimeField, + ScalarField: IsPrimeField + Sync, + FieldElement: ByteConversion + Send + Sync, { table: Vec>>, window_size: usize, phantom: PhantomData, } -impl Wnaf +impl WnafTable where EC: IsShortWeierstrass>, EC::PointRepresentation: Send + Sync, ScalarField: IsPrimeField + Sync, + FieldElement: ByteConversion + Send + Sync, { - pub fn new(base: ShortWeierstrassProjectivePoint) -> Self { + pub fn new(base: &ShortWeierstrassProjectivePoint, max_num_of_scalars: usize) -> Self { let scalar_field_bit_size = ScalarField::field_bit_size(); - - let window = Self::get_mul_window_size(); + let window = Self::get_mul_window_size(max_num_of_scalars); let in_window = 1 << window; let outerc = (scalar_field_bit_size + window - 1) / window; let last_in_window = 1 << (scalar_field_bit_size - (outerc - 1) * window); - let mut g_outer = base; + let mut g_outer = base.clone(); let mut g_outers = Vec::with_capacity(outerc); for _ in 0..outerc { - g_outers.push(g_outer.clone()); // performance? + g_outers.push(g_outer.clone()); for _ in 0..window { g_outer = g_outer.double(); } @@ -66,7 +69,7 @@ where let mut g_inner = ShortWeierstrassProjectivePoint::::neutral_element(); for inner in multiples_of_g.iter_mut().take(curr_in_window) { - *inner = g_inner.clone(); // performance? + *inner = g_inner.clone(); g_inner = g_inner.operate_with(&g_outer); } }, @@ -79,17 +82,22 @@ where } } - pub fn multi_scalar_mul(&self, v: &[T]) -> Vec> - where - T: IsUnsignedInteger + ByteConversion + Sync, - { - v.par_iter().map(|e| self.windowed_mul(e.clone())).collect() + pub fn multi_scalar_mul( + &self, + v: &[FieldElement], + ) -> Vec> { + #[cfg(feature = "parallel")] + let iter = v.par_iter(); + #[cfg(not(feature = "parallel"))] + let iter = v.iter(); + + iter.map(|e| self.windowed_mul(e.clone())).collect() } - fn windowed_mul(&self, scalar: T) -> ShortWeierstrassProjectivePoint - where - T: IsUnsignedInteger + ByteConversion, - { + fn windowed_mul( + &self, + scalar: FieldElement, + ) -> ShortWeierstrassProjectivePoint { let mut res = self.table[0][0].clone(); let modulus_size = ScalarField::field_bit_size(); @@ -116,12 +124,11 @@ where res.to_affine() } - fn get_mul_window_size() -> usize { - let scalar_field_bit_size = ScalarField::field_bit_size(); - if scalar_field_bit_size < 32 { + fn get_mul_window_size(max_num_of_scalars: usize) -> usize { + if max_num_of_scalars < 32 { 3 } else { - (scalar_field_bit_size as f64).ln().ceil() as usize + f64::ln(max_num_of_scalars as f64).ceil() as usize } } } @@ -131,33 +138,53 @@ mod tests { use super::*; use crate::{ elliptic_curve::{ - short_weierstrass::curves::bls12_381::{curve::BLS12381Curve, default_types::FrField}, + short_weierstrass::curves::bls12_381::{ + curve::BLS12381Curve, + default_types::{FrElement, FrField}, + }, traits::IsEllipticCurve, }, unsigned_integer::element::U256, }; use rand::*; + use std::time::Instant; #[test] - fn anal() { + fn wnaf_works() { + let point_count = 100; let g1 = BLS12381Curve::generator(); - let wnaf = Wnaf::::new(g1.clone()); let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9001); let mut scalars = Vec::new(); - for _i in 0..100 { - scalars.push(U256::from(rng.gen::())); + for _i in 0..point_count { + scalars.push(FrElement::new(U256::from(rng.gen::()))); } - let res1: Vec> = scalars + let start1 = Instant::now(); + let naive_result: Vec<_> = scalars .iter() - .map(|scalar| g1.operate_with_self(scalar.clone()).to_affine()) + .map(|scalar| { + g1.operate_with_self(scalar.clone().representative()) + .to_affine() + }) .collect(); + let duration1 = start1.elapsed(); + println!( + "Time taken for naive ksk with {} scalars: {:?}", + point_count, duration1 + ); - let res2 = wnaf.multi_scalar_mul(&scalars); + let start2 = Instant::now(); + let wnaf_result = + WnafTable::::new(&g1, point_count).multi_scalar_mul(&scalars); + let duration2 = start2.elapsed(); + println!( + "Time taken for wnaf msm including table generation with {} scalars: {:?}", + point_count, duration2 + ); - for i in 0..100 { - assert_eq!(res1[i], res2[i]); + for i in 0..point_count { + assert_eq!(naive_result[i], wnaf_result[i]); } } } diff --git a/provers/groth16/src/setup.rs b/provers/groth16/src/setup.rs index 897e6f712..6d8084d5b 100644 --- a/provers/groth16/src/setup.rs +++ b/provers/groth16/src/setup.rs @@ -2,8 +2,9 @@ use crate::{common::*, QuadraticArithmeticProgram}; use lambdaworks_math::{ cyclic_group::IsGroup, elliptic_curve::{ - short_weierstrass::{point::ShortWeierstrassProjectivePoint, traits::IsShortWeierstrass}, + short_weierstrass::curves::bls12_381::{curve::BLS12381Curve, twist::BLS12381TwistCurve}, traits::{IsEllipticCurve, IsPairing}, + wnaf::WnafTable, }, }; @@ -92,6 +93,30 @@ pub fn setup(qap: &QuadraticArithmeticProgram) -> (ProvingKey, VerifyingKey) { let delta_g2 = g2.operate_with_self(tw.delta.representative()); + let z_powers_of_tau = &core::iter::successors( + // Start from delta^{-1} * t(τ) + // Note that t(τ) = (τ^N - 1) because our domain is roots of unity + Some(&delta_inv * (&tw.tau.pow(qap.num_of_gates) - FrElement::one())), + |prev| Some(prev * &tw.tau), + ) + .take(qap.num_of_gates * 2) + .collect::>(); + + let g1_wnaf = WnafTable::::new( + &g1, + [ + qap.num_of_public_inputs, + r_tau.len(), + l_tau.len(), + k_tau.len() - qap.num_of_public_inputs, + z_powers_of_tau.len(), + ] + .iter() + .max() + .unwrap() + .clone(), + ); + ( ProvingKey { alpha_g1, @@ -99,37 +124,18 @@ pub fn setup(qap: &QuadraticArithmeticProgram) -> (ProvingKey, VerifyingKey) { beta_g2, delta_g1: g1.operate_with_self(tw.delta.representative()), delta_g2: delta_g2.clone(), - l_tau_g1: batch_operate_with_self(&l_tau, &g1), - r_tau_g1: batch_operate_with_self(&r_tau, &g1), - r_tau_g2: batch_operate_with_self(&r_tau, &g2), - prover_k_tau_g1: batch_operate_with_self(&k_tau[qap.num_of_public_inputs..], &g1), - z_powers_of_tau_g1: batch_operate_with_self( - &core::iter::successors( - // Start from delta^{-1} * t(τ) - // Note that t(τ) = (τ^N - 1) because our domain is roots of unity - Some(&delta_inv * (&tw.tau.pow(qap.num_of_gates) - FrElement::one())), - |prev| Some(prev * &tw.tau), - ) - .take(qap.num_of_gates * 2) - .collect::>(), - &g1, - ), + l_tau_g1: g1_wnaf.multi_scalar_mul(&l_tau), + r_tau_g1: g1_wnaf.multi_scalar_mul(&r_tau), + r_tau_g2: WnafTable::::new(&g2, r_tau.len()) + .multi_scalar_mul(&r_tau), + prover_k_tau_g1: g1_wnaf.multi_scalar_mul(&k_tau[qap.num_of_public_inputs..]), + z_powers_of_tau_g1: g1_wnaf.multi_scalar_mul(&z_powers_of_tau), }, VerifyingKey { alpha_g1_times_beta_g2, delta_g2, gamma_g2: g2.operate_with_self(tw.gamma.representative()), - verifier_k_tau_g1: batch_operate_with_self(&k_tau[..qap.num_of_public_inputs], &g1), + verifier_k_tau_g1: g1_wnaf.multi_scalar_mul(&k_tau[..qap.num_of_public_inputs]), }, ) } - -fn batch_operate_with_self( - elems: &[FrElement], - point: &ShortWeierstrassProjectivePoint, -) -> Vec> { - elems - .iter() - .map(|elem| point.operate_with_self(elem.representative())) - .collect() -} From cf9c9e1f8501a72cc88e7315fd6b096fcaa60973 Mon Sep 17 00:00:00 2001 From: Irfan Bozkurt Date: Fri, 5 Apr 2024 04:07:10 +0300 Subject: [PATCH 3/5] hopefully clippy shuts up now --- math/src/elliptic_curve/wnaf.rs | 3 +-- provers/groth16/src/setup.rs | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/math/src/elliptic_curve/wnaf.rs b/math/src/elliptic_curve/wnaf.rs index c166d7f77..fb03b405a 100644 --- a/math/src/elliptic_curve/wnaf.rs +++ b/math/src/elliptic_curve/wnaf.rs @@ -105,8 +105,7 @@ where let scalar_bits_le: Vec = scalar .to_bytes_le() .iter() - .map(|byte| (0..8).map(|i| (byte >> i) & 1 == 1).collect::>()) - .flatten() + .flat_map(|byte| (0..8).map(|i| (byte >> i) & 1 == 1).collect::>()) .collect(); for outer in 0..outerc { diff --git a/provers/groth16/src/setup.rs b/provers/groth16/src/setup.rs index 6d8084d5b..a6ae54b2a 100644 --- a/provers/groth16/src/setup.rs +++ b/provers/groth16/src/setup.rs @@ -104,7 +104,7 @@ pub fn setup(qap: &QuadraticArithmeticProgram) -> (ProvingKey, VerifyingKey) { let g1_wnaf = WnafTable::::new( &g1, - [ + *[ qap.num_of_public_inputs, r_tau.len(), l_tau.len(), @@ -113,8 +113,7 @@ pub fn setup(qap: &QuadraticArithmeticProgram) -> (ProvingKey, VerifyingKey) { ] .iter() .max() - .unwrap() - .clone(), + .unwrap(), ); ( @@ -129,7 +128,7 @@ pub fn setup(qap: &QuadraticArithmeticProgram) -> (ProvingKey, VerifyingKey) { r_tau_g2: WnafTable::::new(&g2, r_tau.len()) .multi_scalar_mul(&r_tau), prover_k_tau_g1: g1_wnaf.multi_scalar_mul(&k_tau[qap.num_of_public_inputs..]), - z_powers_of_tau_g1: g1_wnaf.multi_scalar_mul(&z_powers_of_tau), + z_powers_of_tau_g1: g1_wnaf.multi_scalar_mul(z_powers_of_tau), }, VerifyingKey { alpha_g1_times_beta_g2, From 33c52eb3fd2e14962a2692ee6ac3a303da450205 Mon Sep 17 00:00:00 2001 From: Irfan Bozkurt Date: Wed, 10 Apr 2024 23:31:41 +0300 Subject: [PATCH 4/5] move bls12_381.rs to bls12_381/mod.rs --- .../elliptic_curves/bls12_381/bls12_381.rs | 96 ------------------ math/benches/elliptic_curves/bls12_381/mod.rs | 98 ++++++++++++++++++- 2 files changed, 97 insertions(+), 97 deletions(-) delete mode 100644 math/benches/elliptic_curves/bls12_381/bls12_381.rs diff --git a/math/benches/elliptic_curves/bls12_381/bls12_381.rs b/math/benches/elliptic_curves/bls12_381/bls12_381.rs deleted file mode 100644 index 44613e5b1..000000000 --- a/math/benches/elliptic_curves/bls12_381/bls12_381.rs +++ /dev/null @@ -1,96 +0,0 @@ -use criterion::{black_box, Criterion}; -use lambdaworks_math::{ - cyclic_group::IsGroup, - elliptic_curve::{ - short_weierstrass::curves::bls12_381::{ - compression::{compress_g1_point, decompress_g1_point}, - curve::BLS12381Curve, - pairing::BLS12381AtePairing, - twist::BLS12381TwistCurve, - }, - traits::{IsEllipticCurve, IsPairing}, - }, -}; -use rand::{rngs::StdRng, Rng, SeedableRng}; - -#[allow(dead_code)] -pub fn bls12_381_elliptic_curve_benchmarks(c: &mut Criterion) { - let mut rng = StdRng::seed_from_u64(42); - let a_val: u128 = rng.gen(); - let b_val: u128 = rng.gen(); - let a_g1 = BLS12381Curve::generator().operate_with_self(a_val); - let b_g1 = BLS12381Curve::generator().operate_with_self(b_val); - - let a_g2 = BLS12381TwistCurve::generator(); - let b_g2 = BLS12381TwistCurve::generator(); - - let mut group = c.benchmark_group("BLS12-381 Ops"); - group.significance_level(0.1).sample_size(10000); - group.throughput(criterion::Throughput::Elements(1)); - - // Operate_with G1 - group.bench_function("Operate_with_G1", |bencher| { - bencher.iter(|| black_box(black_box(&a_g1).operate_with(black_box(&b_g1)))); - }); - - // Operate_with G2 - group.bench_function("Operate_with_G2 {:?}", |bencher| { - bencher.iter(|| black_box(black_box(&a_g2).operate_with(black_box(&b_g2)))); - }); - - // Operate_with_self G1 - group.bench_function("Operate_with_self_G1", |bencher| { - bencher.iter(|| black_box(black_box(&a_g1).operate_with_self(black_box(b_val)))); - }); - - // Operate_with_self G2 - group.bench_function("Operate_with_self_G2", |bencher| { - bencher.iter(|| black_box(black_box(&a_g2).operate_with_self(black_box(b_val)))); - }); - - // Double G1 - group.bench_function("Double G1", |bencher| { - bencher.iter(|| black_box(black_box(&a_g1).operate_with_self(black_box(2u64)))); - }); - - // Double G2 - group.bench_function("Double G2 {:?}", |bencher| { - bencher.iter(|| black_box(black_box(&a_g2).operate_with_self(black_box(2u64)))); - }); - - // Neg G1 - group.bench_function("Neg G1", |bencher| { - bencher.iter(|| black_box(black_box(&a_g1).neg())); - }); - - // Neg G2 - group.bench_function("Neg G2", |bencher| { - bencher.iter(|| black_box(black_box(&a_g2).neg())); - }); - - // Compress_G1_point - group.bench_function("Compress G1 point", |bencher| { - bencher.iter(|| black_box(compress_g1_point(black_box(&a_g1)))); - }); - - // Decompress_G1_point - group.bench_function("Decompress G1 Point", |bencher| { - let a: [u8; 48] = compress_g1_point(&a_g1).try_into().unwrap(); - bencher.iter(|| black_box(decompress_g1_point(&mut black_box(a))).unwrap()); - }); - - // Subgroup Check G1 - group.bench_function("Subgroup Check G1", |bencher| { - bencher.iter(|| (black_box(a_g1.is_in_subgroup()))); - }); - - // Ate Pairing - group.bench_function("Ate Pairing", |bencher| { - bencher.iter(|| { - black_box(BLS12381AtePairing::compute( - black_box(&a_g1), - black_box(&a_g2), - )) - }); - }); -} diff --git a/math/benches/elliptic_curves/bls12_381/mod.rs b/math/benches/elliptic_curves/bls12_381/mod.rs index 8b1e7e74f..467fec83a 100644 --- a/math/benches/elliptic_curves/bls12_381/mod.rs +++ b/math/benches/elliptic_curves/bls12_381/mod.rs @@ -1,2 +1,98 @@ -pub mod bls12_381; pub mod wnaf; + +use criterion::{black_box, Criterion}; +use lambdaworks_math::{ + cyclic_group::IsGroup, + elliptic_curve::{ + short_weierstrass::curves::bls12_381::{ + compression::{compress_g1_point, decompress_g1_point}, + curve::BLS12381Curve, + pairing::BLS12381AtePairing, + twist::BLS12381TwistCurve, + }, + traits::{IsEllipticCurve, IsPairing}, + }, +}; +use rand::{rngs::StdRng, Rng, SeedableRng}; + +#[allow(dead_code)] +pub fn bls12_381_elliptic_curve_benchmarks(c: &mut Criterion) { + let mut rng = StdRng::seed_from_u64(42); + let a_val: u128 = rng.gen(); + let b_val: u128 = rng.gen(); + let a_g1 = BLS12381Curve::generator().operate_with_self(a_val); + let b_g1 = BLS12381Curve::generator().operate_with_self(b_val); + + let a_g2 = BLS12381TwistCurve::generator(); + let b_g2 = BLS12381TwistCurve::generator(); + + let mut group = c.benchmark_group("BLS12-381 Ops"); + group.significance_level(0.1).sample_size(10000); + group.throughput(criterion::Throughput::Elements(1)); + + // Operate_with G1 + group.bench_function("Operate_with_G1", |bencher| { + bencher.iter(|| black_box(black_box(&a_g1).operate_with(black_box(&b_g1)))); + }); + + // Operate_with G2 + group.bench_function("Operate_with_G2 {:?}", |bencher| { + bencher.iter(|| black_box(black_box(&a_g2).operate_with(black_box(&b_g2)))); + }); + + // Operate_with_self G1 + group.bench_function("Operate_with_self_G1", |bencher| { + bencher.iter(|| black_box(black_box(&a_g1).operate_with_self(black_box(b_val)))); + }); + + // Operate_with_self G2 + group.bench_function("Operate_with_self_G2", |bencher| { + bencher.iter(|| black_box(black_box(&a_g2).operate_with_self(black_box(b_val)))); + }); + + // Double G1 + group.bench_function("Double G1", |bencher| { + bencher.iter(|| black_box(black_box(&a_g1).operate_with_self(black_box(2u64)))); + }); + + // Double G2 + group.bench_function("Double G2 {:?}", |bencher| { + bencher.iter(|| black_box(black_box(&a_g2).operate_with_self(black_box(2u64)))); + }); + + // Neg G1 + group.bench_function("Neg G1", |bencher| { + bencher.iter(|| black_box(black_box(&a_g1).neg())); + }); + + // Neg G2 + group.bench_function("Neg G2", |bencher| { + bencher.iter(|| black_box(black_box(&a_g2).neg())); + }); + + // Compress_G1_point + group.bench_function("Compress G1 point", |bencher| { + bencher.iter(|| black_box(compress_g1_point(black_box(&a_g1)))); + }); + + // Decompress_G1_point + group.bench_function("Decompress G1 Point", |bencher| { + let a: [u8; 48] = compress_g1_point(&a_g1).try_into().unwrap(); + bencher.iter(|| black_box(decompress_g1_point(&mut black_box(a))).unwrap()); + }); + + // Subgroup Check G1 + group.bench_function("Subgroup Check G1", |bencher| { + bencher.iter(|| (black_box(a_g1.is_in_subgroup()))); + }); + + // Ate Pairing + group.bench_function("Ate Pairing", |bencher| { + bencher.iter(|| { + black_box(BLS12381AtePairing::compute( + black_box(&a_g1), + black_box(&a_g2), + )) + }); + }); +} From 7d26db78f9820dac1cf47401bf523cb240af47cc Mon Sep 17 00:00:00 2001 From: Irfan Bozkurt Date: Mon, 29 Apr 2024 20:00:55 +0300 Subject: [PATCH 5/5] run benches + small fix --- math/benches/criterion_elliptic_curve.rs | 2 +- math/benches/elliptic_curves/bls12_381/wnaf.rs | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/math/benches/criterion_elliptic_curve.rs b/math/benches/criterion_elliptic_curve.rs index 179bb9704..dc5f99013 100644 --- a/math/benches/criterion_elliptic_curve.rs +++ b/math/benches/criterion_elliptic_curve.rs @@ -4,7 +4,7 @@ use pprof::criterion::{Output, PProfProfiler}; mod elliptic_curves; use elliptic_curves::{ bls12_377::bls12_377_elliptic_curve_benchmarks, - bls12_381::{bls12_381::bls12_381_elliptic_curve_benchmarks, wnaf::wnaf_bls12_381_benchmarks}, + bls12_381::{bls12_381_elliptic_curve_benchmarks, wnaf::wnaf_bls12_381_benchmarks}, }; criterion_group!( diff --git a/math/benches/elliptic_curves/bls12_381/wnaf.rs b/math/benches/elliptic_curves/bls12_381/wnaf.rs index b0af54cc9..54eb7d48f 100644 --- a/math/benches/elliptic_curves/bls12_381/wnaf.rs +++ b/math/benches/elliptic_curves/bls12_381/wnaf.rs @@ -15,7 +15,7 @@ use rand::{Rng, SeedableRng}; #[allow(dead_code)] pub fn wnaf_bls12_381_benchmarks(c: &mut Criterion) { - let scalar_size = 10000; + let scalar_size = 1000; let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9001); let mut scalars = Vec::new(); @@ -26,11 +26,14 @@ pub fn wnaf_bls12_381_benchmarks(c: &mut Criterion) { let g = BLS12381Curve::generator(); let mut group = c.benchmark_group("BLS12-381 WNAF"); - group.significance_level(0.1).sample_size(10000); + group.significance_level(0.1).sample_size(100); group.throughput(criterion::Throughput::Elements(1)); group.bench_function( - format!("Naive BLS12-381 MSM with size {}", scalar_size), + format!( + "Naive BLS12-381 vector multiplication with size {}", + scalar_size + ), |bencher| { bencher.iter(|| { black_box( @@ -51,7 +54,10 @@ pub fn wnaf_bls12_381_benchmarks(c: &mut Criterion) { ); group.bench_function( - format!("WNAF BLS12-381 MSM with size {}", scalar_size), + format!( + "WNAF BLS12-381 vector multiplication with size {}", + scalar_size + ), |bencher| { bencher.iter(|| { black_box(