From fff19b56e751ac801f63236b0cd792d0e5a3f28a Mon Sep 17 00:00:00 2001 From: David Nevado Date: Wed, 19 Jun 2024 14:22:49 +0200 Subject: [PATCH] feat: update & clean benchmarks --- Cargo.toml | 8 +--- benches/bn256_field.rs | 51 -------------------- benches/curve.rs | 73 ++++++++++++++++++++++++++++ benches/fft.rs | 17 ++++--- benches/field_arith.rs | 70 +++++++++++++++++++++++++++ benches/group.rs | 52 -------------------- benches/hash_to_curve.rs | 60 ++++++++--------------- benches/less_than.rs | 101 --------------------------------------- benches/msm.rs | 2 +- benches/pairing.rs | 48 +++++++++++++++++++ 10 files changed, 225 insertions(+), 257 deletions(-) delete mode 100644 benches/bn256_field.rs create mode 100644 benches/curve.rs create mode 100644 benches/field_arith.rs delete mode 100644 benches/group.rs delete mode 100644 benches/less_than.rs create mode 100644 benches/pairing.rs diff --git a/Cargo.toml b/Cargo.toml index 64c178ff..a1183cbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,15 +66,11 @@ incremental = false codegen-units = 1 [[bench]] -name = "less_than" +name = "field_arith" harness = false [[bench]] -name = "bn256_field" -harness = false - -[[bench]] -name = "group" +name = "curve" harness = false [[bench]] diff --git a/benches/bn256_field.rs b/benches/bn256_field.rs deleted file mode 100644 index d3495dfe..00000000 --- a/benches/bn256_field.rs +++ /dev/null @@ -1,51 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; -use halo2curves::{bn256::*, ff::Field, ff_ext::Legendre}; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; - -pub fn bench_bn256_field(c: &mut Criterion) { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let a = Fq::random(&mut rng); - let b = Fq::random(&mut rng); - - #[cfg(not(feature = "asm"))] - let mut group = c.benchmark_group("BN256 Field Arithmetic (no assembly)"); - - #[cfg(feature = "asm")] - let mut group = c.benchmark_group("BN256 Field Arithmetic (with assembly)"); - - group.significance_level(0.1).sample_size(10000); - group.throughput(Throughput::Elements(1)); - - group.bench_function("bn256_fq_add", |bencher| { - bencher.iter(|| black_box(&a).add(black_box(&b))) - }); - group.bench_function("bn256_fq_double", |bencher| { - bencher.iter(|| black_box(&a).double()) - }); - group.bench_function("bn256_fq_sub", |bencher| { - bencher.iter(|| black_box(&a).sub(black_box(&b))) - }); - group.bench_function("bn256_fq_neg", |bencher| { - bencher.iter(|| black_box(&a).neg()) - }); - group.bench_function("bn256_fq_mul", |bencher| { - bencher.iter(|| black_box(&a).mul(black_box(&b))) - }); - group.bench_function("bn256_fq_square", |bencher| { - bencher.iter(|| black_box(&a).square()) - }); - group.bench_function("bn256_fq_invert", |bencher| { - bencher.iter(|| black_box(&a).invert()) - }); - group.bench_function("bn256_fq_legendre", |bencher| { - bencher.iter(|| black_box(&a).legendre()) - }); -} - -criterion_group!(benches, bench_bn256_field); -criterion_main!(benches); diff --git a/benches/curve.rs b/benches/curve.rs new file mode 100644 index 00000000..f1b3f1de --- /dev/null +++ b/benches/curve.rs @@ -0,0 +1,73 @@ +//! This benchmarks the basic EC operations. +//! It measures `G1` from the BN256 curve. +//! +//! To run this benchmark: +//! +//! cargo bench --bench curve + +use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; +use ff::Field; +use group::prime::PrimeCurveAffine; +use halo2curves::bn256::G1; +use pasta_curves::arithmetic::CurveExt; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; + +fn bench_curve_ops(c: &mut Criterion, name: &'static str) { + { + let mut rng = XorShiftRng::seed_from_u64(3141519u64); + + // Generate 2 random points. + let mut p1 = G::random(&mut rng); + let p2 = G::random(&mut rng); + p1 += p2; + + let p1_affine = G::AffineExt::from(p1); + + let s = G::ScalarExt::random(&mut rng); + + const N: usize = 1000; + let v: Vec = (0..N).map(|_| p1 + G::random(&mut rng)).collect(); + + let mut q = vec![G::AffineExt::identity(); N]; + + let mut group = c.benchmark_group(format!("{} arithmetic", name)); + + group.significance_level(0.1).sample_size(1000); + group.throughput(Throughput::Elements(1)); + + group.bench_function(&format!("{name} check on curve"), move |b| { + b.iter(|| black_box(p1).is_on_curve()) + }); + group.bench_function(&format!("{name} check equality"), move |b| { + b.iter(|| black_box(p1) == black_box(p1)) + }); + group.bench_function(&format!("{name} to affine"), move |b| { + b.iter(|| G::AffineExt::from(black_box(p1))) + }); + group.bench_function(&format!("{name} doubling"), move |b| { + b.iter(|| black_box(p1).double()) + }); + group.bench_function(&format!("{name} addition"), move |b| { + b.iter(|| black_box(p1).add(&p2)) + }); + group.bench_function(&format!("{name} mixed addition"), move |b| { + b.iter(|| black_box(p2).add(&p1_affine)) + }); + group.bench_function(&format!("{name} scalar multiplication"), move |b| { + b.iter(|| black_box(p1) * black_box(s)) + }); + group.bench_function(&format!("{name} batch to affine n={N}"), move |b| { + b.iter(|| { + G::batch_normalize(black_box(&v), black_box(&mut q)); + }) + }); + } +} + +fn bench_bn256_ops(c: &mut Criterion) { + bench_curve_ops::(c, "BN256") +} + +criterion_group!(benches, bench_bn256_ops); +criterion_main!(benches); diff --git a/benches/fft.rs b/benches/fft.rs index a250308d..a9eda9ce 100644 --- a/benches/fft.rs +++ b/benches/fft.rs @@ -4,7 +4,7 @@ //! //! To run this benchmark: //! -//! cargo bench -- fft +//! cargo bench --bench fft //! //! Caveat: The multicore benchmark assumes: //! 1. a multi-core system @@ -17,17 +17,21 @@ use criterion::{BenchmarkId, Criterion}; use group::ff::Field; use halo2curves::bn256::Fr as Scalar; use halo2curves::fft::best_fft; -use rand_core::OsRng; +use rand::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; use std::ops::Range; use std::time::SystemTime; const RANGE: Range = 3..19; +const SEED: [u8; 16] = [ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, +]; -fn generate_data(k: u32) -> Vec { +fn generate_data(k: u32, mut rng: impl RngCore) -> Vec { let n = 1 << k; let timer = SystemTime::now(); println!("\n\nGenerating 2^{k} = {n} values..",); - let data: Vec = (0..n).map(|_| Scalar::random(OsRng)).collect(); + let data: Vec = (0..n).map(|_| Scalar::random(&mut rng)).collect(); let end = timer.elapsed().unwrap(); println!( "Generating 2^{k} = {n} values took: {} sec.\n\n", @@ -38,8 +42,9 @@ fn generate_data(k: u32) -> Vec { fn fft(c: &mut Criterion) { let max_k = RANGE.max().unwrap_or(16); - let mut data = generate_data(max_k); - let omega = Scalar::random(OsRng); + let mut rng = XorShiftRng::from_seed(SEED); + let mut data = generate_data(max_k, &mut rng); + let omega = Scalar::random(&mut rng); let mut group = c.benchmark_group("fft"); for k in RANGE { group.bench_function(BenchmarkId::new("k", k), |b| { diff --git a/benches/field_arith.rs b/benches/field_arith.rs new file mode 100644 index 00000000..2edcaef2 --- /dev/null +++ b/benches/field_arith.rs @@ -0,0 +1,70 @@ +//! This benchmarks the basic FF operations. +//! It measures the base field `Fq` and scalar field `Fr` from the BN256 curve. +//! +//! To run this benchmark: +//! +//! cargo bench --bench field_arith + +use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; +use halo2curves::{ + bn256::{Fq, Fr}, + ff::Field, + ff_ext::Legendre, +}; +use rand::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; + +const SEED: [u8; 16] = [ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, +]; +fn bench_field_arithmetic(c: &mut Criterion, name: &'static str) { + let mut rng = XorShiftRng::from_seed(SEED); + + let a = ::random(&mut rng); + let b = ::random(&mut rng); + let exp = rng.next_u64(); + + let mut group = c.benchmark_group(format!("{} arithmetic", name)); + + group.significance_level(0.1).sample_size(1000); + group.throughput(Throughput::Elements(1)); + + group.bench_function(format!("{}_add", name), |bencher| { + bencher.iter(|| black_box(&a).add(black_box(&b))) + }); + group.bench_function(format!("{}_double", name), |bencher| { + bencher.iter(|| black_box(&a).double()) + }); + group.bench_function(format!("{}_sub", name), |bencher| { + bencher.iter(|| black_box(&a).sub(black_box(&b))) + }); + group.bench_function(format!("{}_neg", name), |bencher| { + bencher.iter(|| black_box(&a).neg()) + }); + group.bench_function(format!("{}_mul", name), |bencher| { + bencher.iter(|| black_box(&a).mul(black_box(&b))) + }); + group.bench_function(format!("{}_square", name), |bencher| { + bencher.iter(|| black_box(&a).square()) + }); + group.bench_function(format!("{}_pow_vartime", name), |bencher| { + bencher.iter(|| black_box(&a).pow_vartime(black_box(&[exp]))) + }); + group.bench_function(format!("{}_invert", name), |bencher| { + bencher.iter(|| black_box(&a).invert()) + }); + group.bench_function(format!("{}_legendre", name), |bencher| { + bencher.iter(|| black_box(&a).legendre()) + }); + group.finish() +} + +fn bench_bn256_base_field(c: &mut Criterion) { + bench_field_arithmetic::(c, "Fq") +} +fn bench_bn256_scalar_field(c: &mut Criterion) { + bench_field_arithmetic::(c, "Fr") +} + +criterion_group!(benches, bench_bn256_base_field, bench_bn256_scalar_field); +criterion_main!(benches); diff --git a/benches/group.rs b/benches/group.rs deleted file mode 100644 index b1936e68..00000000 --- a/benches/group.rs +++ /dev/null @@ -1,52 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use ff::Field; -use group::prime::PrimeCurveAffine; -use halo2curves::secp256k1::Secp256k1; -use pasta_curves::arithmetic::CurveExt; -use rand_core::OsRng; - -fn criterion_benchmark(c: &mut Criterion) { - // G1Projective - { - let name = "GProjective"; - let p1 = G::random(OsRng); - let p2 = G::random(OsRng); - let p1_affine = G::AffineExt::from(p1); - let s = G::ScalarExt::random(OsRng); - - const N: usize = 1000; - let v = vec![G::generator(); N]; - let mut q = vec![G::AffineExt::identity(); N]; - - c.bench_function(&format!("{name} check on curve"), move |b| { - b.iter(|| black_box(p1).is_on_curve()) - }); - c.bench_function(&format!("{name} check equality"), move |b| { - b.iter(|| black_box(p1) == black_box(p1)) - }); - c.bench_function(&format!("{name} to affine"), move |b| { - b.iter(|| G::AffineExt::from(black_box(p1))) - }); - c.bench_function(&format!("{name} doubling"), move |b| { - b.iter(|| black_box(p1).double()) - }); - c.bench_function(&format!("{name} addition"), move |b| { - b.iter(|| black_box(p1).add(&p2)) - }); - c.bench_function(&format!("{name} mixed addition"), move |b| { - b.iter(|| black_box(p2).add(&p1_affine)) - }); - c.bench_function(&format!("{name} scalar multiplication"), move |b| { - b.iter(|| black_box(p1) * black_box(s)) - }); - c.bench_function(&format!("{name} batch to affine n={N}"), move |b| { - b.iter(|| { - G::batch_normalize(black_box(&v), black_box(&mut q)); - black_box(&q)[0] - }) - }); - } -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/benches/hash_to_curve.rs b/benches/hash_to_curve.rs index bda1c1d3..a480d853 100644 --- a/benches/hash_to_curve.rs +++ b/benches/hash_to_curve.rs @@ -1,40 +1,25 @@ +//! This benchmarks basic the hash-to-curve algorithm. +//! It measures `G1` from the BN256 curve. +//! +//! To run this benchmark: +//! +//! cargo bench --bench hash_to_curve + use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use halo2curves::bn256::G1; use pasta_curves::arithmetic::CurveExt; -use rand_core::{OsRng, RngCore}; +use rand::SeedableRng; +use rand_core::RngCore; +use rand_xorshift::XorShiftRng; use std::iter; -fn hash_to_secp256k1(c: &mut Criterion) { - hash_to_curve::(c, "Secp256k1"); -} - -fn hash_to_secq256k1(c: &mut Criterion) { - hash_to_curve::(c, "Secq256k1"); -} - -fn hash_to_secp256r1(c: &mut Criterion) { - hash_to_curve::(c, "Secp256r1"); -} - -fn hash_to_pallas(c: &mut Criterion) { - hash_to_curve::(c, "Pallas"); -} - -fn hash_to_vesta(c: &mut Criterion) { - hash_to_curve::(c, "Vesta"); -} - -fn hash_to_bn256(c: &mut Criterion) { - hash_to_curve::(c, "Bn256"); -} - -fn hash_to_grumpkin(c: &mut Criterion) { - hash_to_curve::(c, "Grumpkin"); -} - +const SEED: [u8; 16] = [ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, +]; fn hash_to_curve(c: &mut Criterion, name: &'static str) { { let hasher = G::hash_to_curve("test"); - let mut rng = OsRng; + let mut rng = XorShiftRng::from_seed(SEED); let message = iter::repeat_with(|| rng.next_u32().to_be_bytes()) .take(1024) .flatten() @@ -46,14 +31,9 @@ fn hash_to_curve(c: &mut Criterion, name: &'static str) { } } -criterion_group!( - benches, - hash_to_secp256k1, - hash_to_secq256k1, - hash_to_secp256r1, - hash_to_pallas, - hash_to_vesta, - hash_to_bn256, - hash_to_grumpkin, -); +fn hash_to_bn256(c: &mut Criterion) { + hash_to_curve::(c, "BN256"); +} + +criterion_group!(benches, hash_to_bn256,); criterion_main!(benches); diff --git a/benches/less_than.rs b/benches/less_than.rs deleted file mode 100644 index 9c364fb4..00000000 --- a/benches/less_than.rs +++ /dev/null @@ -1,101 +0,0 @@ -#![allow(unused)] - -use criterion::BenchmarkId; - -/// Compute a - (b + borrow), returning the result and the new borrow. -#[inline(always)] -const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) { - let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128)); - (ret as u64, (ret >> 64) as u64) -} - -#[inline(always)] -fn is_less_than(x: &[u64; 4], y: &[u64; 4]) -> bool { - match x[3].cmp(&y[3]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[2].cmp(&y[2]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[1].cmp(&y[1]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - x[0].lt(&y[0]) -} - -#[inline(always)] -fn check_underflow(x: &[u64; 4], y: &[u64; 4]) -> bool { - let (_, borrow) = sbb(x[0], y[0], 0); - let (_, borrow) = sbb(x[1], y[1], borrow); - let (_, borrow) = sbb(x[2], y[2], borrow); - let (_, borrow) = sbb(x[3], y[3], borrow); - borrow >> 63 == 1 -} - -use criterion::{criterion_group, criterion_main, Criterion}; -use group::Group; -use halo2curves::bn256::G1; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; - -pub fn criterion_benchmark(c: &mut Criterion) { - let x: [u64; 4] = [(); 4].map(|_| rand::random()); - let y: [u64; 4] = [(); 4].map(|_| rand::random()); - - let mut group = c.benchmark_group("Big less than methods"); - - group.bench_with_input( - BenchmarkId::new("is_less_than", ""), - &(x, y), - |b, (x, y)| b.iter(|| is_less_than(x, y)), - ); - - group.bench_with_input( - BenchmarkId::new("check_underflow", ""), - &(x, y), - |b, (x, y)| b.iter(|| check_underflow(x, y)), - ); - group.finish(); -} - -pub fn arithmetics(c: &mut Criterion) { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - let iteration = 1000; - - let x_vec: Vec = (0..iteration).map(|_| G1::random(&mut rng)).collect(); - let y_vec: Vec = (0..iteration).map(|_| G1::random(&mut rng)).collect(); - - let mut group = c.benchmark_group("Group operations"); - - group.bench_with_input(BenchmarkId::new("double", ""), &x_vec, |b, x_vec| { - b.iter(|| x_vec.iter().map(|x| x.double()).collect::>()) - }); - - group.bench_with_input( - BenchmarkId::new("add", ""), - &(x_vec, y_vec), - |b, (x_vec, y_vec)| { - b.iter(|| { - x_vec - .iter() - .zip(y_vec.iter()) - .map(|(x, y)| x + y) - .collect::>() - }) - }, - ); - - group.finish(); -} - -criterion_group!(benches, criterion_benchmark, arithmetics); -criterion_main!(benches); diff --git a/benches/msm.rs b/benches/msm.rs index 30afc8bf..496e2780 100644 --- a/benches/msm.rs +++ b/benches/msm.rs @@ -3,7 +3,7 @@ //! //! To run this benchmark: //! -//! cargo bench -- msm +//! cargo bench --bench msm //! //! Caveat: The multicore benchmark assumes: //! 1. a multi-core system diff --git a/benches/pairing.rs b/benches/pairing.rs new file mode 100644 index 00000000..1dca2606 --- /dev/null +++ b/benches/pairing.rs @@ -0,0 +1,48 @@ +//! Benchmark pairing. +//! It measures the pairing of the BN256 curve. +//! +//! To run this benchmark: +//! +//! cargo bench --bench pairing + +use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; +use ff::Field; +use group::prime::PrimeCurveAffine; +use halo2curves::bn256::Bn256; +use pairing::Engine; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; + +const SEED: [u8; 16] = [ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, +]; + +fn bench_pairing(c: &mut Criterion, name: &'static str) { + { + let mut rng = XorShiftRng::from_seed(SEED); + let mut group = c.benchmark_group(format!("{} Pairing", name)); + + group.significance_level(0.1).sample_size(100); + group.throughput(Throughput::Elements(1)); + + let a = E::Fr::random(&mut rng); + let b = E::Fr::random(&mut rng); + + let g1 = E::G1Affine::generator(); + let g1_affine = (g1 * a).into(); + + let g2 = E::G2Affine::generator(); + let g2_affine = (g2 * b).into(); + + group.bench_function(&format!("{} pairing", name), move |b| { + b.iter(|| E::pairing(&black_box(g1_affine), &black_box(g2_affine))) + }); + } +} + +fn bench_bn256_pairing(c: &mut Criterion) { + bench_pairing::(c, "BN256"); +} + +criterion_group!(benches, bench_bn256_pairing); +criterion_main!(benches);