From 66cafab0411c866baa476303a720c908e5fcd97e Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Fri, 6 Sep 2024 13:36:46 +0100 Subject: [PATCH 1/7] initial impl of blst method --- .../bls12_381/src/fixed_base_msm_blst.rs | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 cryptography/bls12_381/src/fixed_base_msm_blst.rs diff --git a/cryptography/bls12_381/src/fixed_base_msm_blst.rs b/cryptography/bls12_381/src/fixed_base_msm_blst.rs new file mode 100644 index 00000000..7ea9e653 --- /dev/null +++ b/cryptography/bls12_381/src/fixed_base_msm_blst.rs @@ -0,0 +1,153 @@ +use std::time::{Duration, Instant}; + +use crate::{ + batch_add::{batch_addition, multi_batch_addition}, + booth_encoding::{self, get_booth_index}, + fixed_base_msm_pippenger::FixedBaseMSMPippenger, + g1_batch_normalize, G1Projective, Scalar, +}; +use blstrs::{Fp, G1Affine}; +use ff::PrimeField; +use group::prime::PrimeCurveAffine; +use group::Group; + +// FixedBasePrecomp blst way with some changes +#[derive(Debug)] +pub struct FixedBaseMSMPrecompBLST { + table: Vec>, // TODO: Make this a Vec<> and then just do the maths in msm function for offsetting + // table: Vec, + wbits: usize, +} + +impl FixedBaseMSMPrecompBLST { + pub fn new(points: &[G1Affine], wbits: usize) -> Self { + // For every point `P`, wbits indicates that we should compute + // 0 * P, 1 * P, ..., (2^{wbits} - 1) * P + // + // The total amount of memory is roughly (numPoints * 2^{wbits} - 1) + // where each point is 64 bytes. + // + // TODO: I say roughly because we do not need to store 0 * P, update description with that + // + let mut precomputed_points: Vec<_> = points + .into_iter() + .map(|point| Self::precompute_points(wbits, *point)) + .collect(); + + Self { + table: precomputed_points, + wbits, + } + } + + fn precompute_points(wbits: usize, point: G1Affine) -> Vec { + let mut lookup_table = Vec::with_capacity(1 << wbits); + + // Convert to projective for faster operations + let mut current = G1Projective::from(point); + + // Compute and store multiples + for _ in 0..(1 << wbits) { + lookup_table.push(current); + current += point; + } + + g1_batch_normalize(&lookup_table) + } + + pub fn msm(&self, scalars: &[Scalar]) -> G1Projective { + let scalars_bytes: Vec<_> = scalars.iter().map(|a| a.to_bytes_le()).collect(); + let number_of_windows = Scalar::NUM_BITS as usize / self.wbits + 1; + + let mut windows_of_points = vec![Vec::with_capacity(scalars.len()); number_of_windows]; + + for window_idx in 0..number_of_windows { + for (scalar_idx, scalar_bytes) in scalars_bytes.iter().enumerate() { + let sub_table = &self.table[scalar_idx]; + let point_idx = get_booth_index(window_idx, self.wbits, scalar_bytes.as_ref()); + + if point_idx == 0 { + continue; + } + + let sign = point_idx.is_positive(); + let point_idx = point_idx.unsigned_abs() as usize - 1; + let mut point = sub_table[point_idx]; + // let mut point = self.table[(scalar_idx * 1 << self.wbits) + point_idx]; + if !sign { + point = -point; + } + + // Time pushing to windows_of_points + windows_of_points[window_idx].push(point); + } + } + + // For each window, lets add all of the points together. + // let accumulated_points: Vec<_> = windows_of_points + // .into_iter() + // .map(|wp| batch_addition(wp)) + // .collect(); + let accumulated_points = multi_batch_addition(windows_of_points); + + // Now accumulate the windows by doubling wbits times + let mut result = G1Projective::identity(); + for point in accumulated_points.into_iter().rev() { + // Double the result 'wbits' times + for _ in 0..self.wbits { + result = result.double(); + } + // Add the accumulated point for this window + result += point; + } + + result + } +} + +#[test] +fn precomp_lookup_table() { + use group::Group; + let lookup_table = FixedBaseMSMPrecompBLST::precompute_points(7, G1Affine::generator()); + + for i in 1..lookup_table.len() { + let expected = G1Projective::generator() * Scalar::from((i + 1) as u64); + assert_eq!(lookup_table[i], expected.into(),) + } +} +use ff::Field; + +#[test] +fn msm_blst_precomp() { + let length = 64; + let generators: Vec<_> = (0..length) + .map(|_| G1Projective::random(&mut rand::thread_rng()).into()) + .collect(); + let scalars: Vec<_> = (0..length) + .map(|_| Scalar::random(&mut rand::thread_rng())) + .collect(); + + let res = crate::lincomb::g1_lincomb(&generators, &scalars) + .expect("number of generators and number of scalars is equal"); + + let fbm = FixedBaseMSMPrecompBLST::new(&generators, 7); + let result = fbm.msm(&scalars); + + assert_eq!(res, result); +} + +#[test] +fn bench_window_sizes_msm() { + let length = 64; + let generators: Vec<_> = (0..length) + .map(|_| G1Projective::random(&mut rand::thread_rng()).into()) + .collect(); + let scalars: Vec<_> = (0..length) + .map(|_| Scalar::random(&mut rand::thread_rng())) + .collect(); + + for i in 2..=14 { + let fbm = FixedBaseMSMPrecompBLST::new( &generators, i); + fbm.msm(&scalars); + } +} From 18050fb2802bf388d2b79b33cf1f701b7b08e79a Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Fri, 6 Sep 2024 13:37:08 +0100 Subject: [PATCH 2/7] replace blst call with our method --- cryptography/bls12_381/src/fixed_base_msm.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cryptography/bls12_381/src/fixed_base_msm.rs b/cryptography/bls12_381/src/fixed_base_msm.rs index e3e77150..70bf6629 100644 --- a/cryptography/bls12_381/src/fixed_base_msm.rs +++ b/cryptography/bls12_381/src/fixed_base_msm.rs @@ -1,4 +1,7 @@ -use crate::{fixed_base_msm_pippenger::FixedBaseMSMPippenger, G1Projective, Scalar}; +use crate::{ + fixed_base_msm_blst::FixedBaseMSMPrecompBLST, fixed_base_msm_pippenger::FixedBaseMSMPippenger, + G1Projective, Scalar, +}; use blstrs::{Fp, G1Affine}; /// FixedBaseMSMPrecomp computes a multi scalar multiplication using pre-computations. @@ -27,7 +30,7 @@ pub enum UsePrecomp { /// of memory. #[derive(Debug)] pub enum FixedBaseMSM { - Precomp(FixedBaseMSMPrecomp), + Precomp(FixedBaseMSMPrecompBLST), // TODO: We are hijacking the NoPrecomp variant to store the // TODO: new pippenger algorithm. NoPrecomp(FixedBaseMSMPippenger), @@ -37,7 +40,7 @@ impl FixedBaseMSM { pub fn new(generators: Vec, use_precomp: UsePrecomp) -> Self { match use_precomp { UsePrecomp::Yes { width } => { - FixedBaseMSM::Precomp(FixedBaseMSMPrecomp::new(generators, width)) + FixedBaseMSM::Precomp(FixedBaseMSMPrecompBLST::new(&generators, width)) } UsePrecomp::No => FixedBaseMSM::NoPrecomp(FixedBaseMSMPippenger::new(&generators)), } @@ -45,7 +48,7 @@ impl FixedBaseMSM { pub fn msm(&self, scalars: Vec) -> G1Projective { match self { - FixedBaseMSM::Precomp(precomp) => precomp.msm(scalars), + FixedBaseMSM::Precomp(precomp) => precomp.msm(&scalars), FixedBaseMSM::NoPrecomp(precomp) => precomp.msm(&scalars), } } From bb9fe6131fa3b07f47d467b0333476a52ea96487 Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Fri, 6 Sep 2024 13:37:33 +0100 Subject: [PATCH 3/7] cargo --- cryptography/bls12_381/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cryptography/bls12_381/src/lib.rs b/cryptography/bls12_381/src/lib.rs index 7d349584..49177361 100644 --- a/cryptography/bls12_381/src/lib.rs +++ b/cryptography/bls12_381/src/lib.rs @@ -1,7 +1,8 @@ -mod batch_add; +pub mod batch_add; pub mod batch_inversion; mod booth_encoding; pub mod fixed_base_msm; +pub mod fixed_base_msm_blst; pub mod fixed_base_msm_pippenger; pub mod lincomb; From 55263576be60f9b6be0d03cb2118207f5579d740 Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Fri, 6 Sep 2024 13:37:44 +0100 Subject: [PATCH 4/7] benchmark --- cryptography/bls12_381/benches/benchmark.rs | 42 ++++++++++++++------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/cryptography/bls12_381/benches/benchmark.rs b/cryptography/bls12_381/benches/benchmark.rs index 25803359..1a248859 100644 --- a/cryptography/bls12_381/benches/benchmark.rs +++ b/cryptography/bls12_381/benches/benchmark.rs @@ -3,13 +3,14 @@ use crate_crypto_internal_eth_kzg_bls12_381::{ batch_inversion, ff::Field, fixed_base_msm::{FixedBaseMSM, UsePrecomp}, + fixed_base_msm_blst::FixedBaseMSMPrecompBLST, fixed_base_msm_pippenger::FixedBaseMSMPippenger, g1_batch_normalize, g2_batch_normalize, group::Group, lincomb::{g1_lincomb, g1_lincomb_unsafe, g2_lincomb, g2_lincomb_unsafe}, - G1Projective, G2Projective, + G1Point, G1Projective, G2Projective, }; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; pub fn batch_inversion(c: &mut Criterion) { const NUM_ELEMENTS: usize = 8192; @@ -30,18 +31,33 @@ pub fn fixed_base_msm(c: &mut Criterion) { .into_iter() .map(|p| p.into()) .collect(); - let fbm = FixedBaseMSM::new(generators.clone(), UsePrecomp::Yes { width: 8 }); let scalars: Vec<_> = random_scalars(length); + // let fbm = FixedBaseMSM::new(generators.clone(), UsePrecomp::Yes { width: 8 }); - c.bench_function("bls12_381 fixed_base_msm length=64 width=8", |b| { - b.iter(|| fbm.msm(scalars.clone())) - }); + // c.bench_function("bls12_381 fixed_base_msm length=64 width=8", |b| { + // b.iter(|| fbm.msm(scalars.clone())) + // }); - let fixed_base_pip = FixedBaseMSMPippenger::new(&generators); + // let fixed_base_pip = FixedBaseMSMPippenger::new(&generators); - c.bench_function("bls12_381 fixed based pippenger algorithm", |b| { - b.iter(|| fixed_base_pip.msm(&scalars)) - }); + // c.bench_function("bls12_381 fixed based pippenger algorithm", |b| { + // b.iter(|| fixed_base_pip.msm(&scalars)) + // }); + + let mut group = c.benchmark_group("bls12_381 fixed base windowed algorithm"); + + for window_size in 2..=14 { + // Test window sizes from 2 to 10 + // Create the FixedBaseMSMPrecompBLST instance outside the benchmarked portion + let fixed_base = FixedBaseMSMPrecompBLST::new(&generators, window_size); + + group.bench_with_input( + BenchmarkId::new("window_size", window_size), + &window_size, + |b, &_| b.iter(|| black_box(fixed_base.msm(black_box(&scalars)))), + ); + } + group.finish(); } pub fn bench_msm(c: &mut Criterion) { @@ -97,9 +113,9 @@ fn random_g2_points(size: usize) -> Vec { criterion_group!( benches, - batch_inversion, - fixed_base_msm, - bench_msm, + // batch_inversion, + // fixed_base_msm, + // bench_msm, fixed_base_msm ); criterion_main!(benches); From eb14e851f8f5f4d4f8b427ff49f946007d262fa2 Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Fri, 6 Sep 2024 13:41:24 +0100 Subject: [PATCH 5/7] fix outdated comment --- cryptography/bls12_381/src/fixed_base_msm_blst.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cryptography/bls12_381/src/fixed_base_msm_blst.rs b/cryptography/bls12_381/src/fixed_base_msm_blst.rs index 7ea9e653..d9d6e032 100644 --- a/cryptography/bls12_381/src/fixed_base_msm_blst.rs +++ b/cryptography/bls12_381/src/fixed_base_msm_blst.rs @@ -22,12 +22,11 @@ pub struct FixedBaseMSMPrecompBLST { impl FixedBaseMSMPrecompBLST { pub fn new(points: &[G1Affine], wbits: usize) -> Self { // For every point `P`, wbits indicates that we should compute - // 0 * P, 1 * P, ..., (2^{wbits} - 1) * P + // 1 * P, ..., (2^{wbits} - 1) * P // // The total amount of memory is roughly (numPoints * 2^{wbits} - 1) // where each point is 64 bytes. // - // TODO: I say roughly because we do not need to store 0 * P, update description with that // let mut precomputed_points: Vec<_> = points .into_iter() @@ -147,7 +146,7 @@ fn bench_window_sizes_msm() { .collect(); for i in 2..=14 { - let fbm = FixedBaseMSMPrecompBLST::new( &generators, i); + let fbm = FixedBaseMSMPrecompBLST::new(&generators, i); fbm.msm(&scalars); } } From e8144ae144b1ef71357a6abf027dae6e965948d6 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Fri, 6 Sep 2024 13:43:01 +0100 Subject: [PATCH 6/7] Update cryptography/bls12_381/src/fixed_base_msm_blst.rs --- cryptography/bls12_381/src/fixed_base_msm_blst.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/cryptography/bls12_381/src/fixed_base_msm_blst.rs b/cryptography/bls12_381/src/fixed_base_msm_blst.rs index d9d6e032..61828c3b 100644 --- a/cryptography/bls12_381/src/fixed_base_msm_blst.rs +++ b/cryptography/bls12_381/src/fixed_base_msm_blst.rs @@ -77,7 +77,6 @@ impl FixedBaseMSMPrecompBLST { point = -point; } - // Time pushing to windows_of_points windows_of_points[window_idx].push(point); } } From 1519984dbc31c134745dbb1b902d9635abee74a9 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Fri, 6 Sep 2024 13:43:31 +0100 Subject: [PATCH 7/7] Update cryptography/bls12_381/src/lib.rs --- cryptography/bls12_381/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptography/bls12_381/src/lib.rs b/cryptography/bls12_381/src/lib.rs index 49177361..0b7f42b7 100644 --- a/cryptography/bls12_381/src/lib.rs +++ b/cryptography/bls12_381/src/lib.rs @@ -1,4 +1,4 @@ -pub mod batch_add; +mod batch_add; pub mod batch_inversion; mod booth_encoding; pub mod fixed_base_msm;