Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync with upstream PSE #7

Merged
merged 8 commits into from
Sep 23, 2023
21 changes: 19 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ criterion = { version = "0.3", features = ["html_reports"] }
rand_xorshift = "0.3"
ark-std = { version = "0.3" }
bincode = "1.3.3"
serde_json = "1.0.105"

[dependencies]
subtle = "2.4"
Expand All @@ -30,14 +31,17 @@ num-traits = "0.2"
paste = "1.0.11"
serde = { version = "1.0", default-features = false, optional = true }
serde_arrays = { version = "0.1.0", optional = true }
hex = { version = "0.4", optional = true, default-features = false, features = ["alloc", "serde"] }
blake2b_simd = "1"
maybe-rayon = { version = "0.1.0", default-features = false }

[features]
default = ["reexport", "bits", "bn256-table", "derive_serde"]
default = ["reexport", "bits", "multicore", "bn256-table", "derive_serde"]
multicore = ["maybe-rayon/threads"]
asm = []
bits = ["ff/bits"]
bn256-table = []
derive_serde = ["serde/derive", "serde_arrays"]
derive_serde = ["serde/derive", "serde_arrays", "hex"]
prefetch = []
print-trace = ["ark-std/print-trace"]
reexport = []
Expand All @@ -63,3 +67,16 @@ required-features = ["reexport"]
[[bench]]
name = "group"
harness = false

[[bench]]
name = "hash_to_curve"
harness = false

[[bench]]
name = "fft"
harness = false

[[bench]]
name = "msm"
harness = false
required-features = ["multicore"]
57 changes: 57 additions & 0 deletions benches/fft.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! This benchmarks Fast-Fourier Transform (FFT).
//! Since it is over a finite field, it is actually the Number Theoretical
//! Transform (NNT). It uses the `Fr` scalar field from the BN256 curve.
//!
//! To run this benchmark:
//!
//! cargo bench -- fft
//!
//! Caveat: The multicore benchmark assumes:
//! 1. a multi-core system
//! 2. that the `multicore` feature is enabled. It is by default.

#[macro_use]
extern crate criterion;

use criterion::{BenchmarkId, Criterion};
use group::ff::Field;
use halo2curves::bn256::Fr as Scalar;
use halo2curves::fft::best_fft;
use rand_core::OsRng;
use std::ops::Range;
use std::time::SystemTime;

const RANGE: Range<u32> = 3..19;

fn generate_data(k: u32) -> Vec<Scalar> {
let n = 1 << k;
let timer = SystemTime::now();
println!("\n\nGenerating 2^{k} = {n} values..",);
let data: Vec<Scalar> = (0..n).map(|_| Scalar::random(OsRng)).collect();
let end = timer.elapsed().unwrap();
println!(
"Generating 2^{k} = {n} values took: {} sec.\n\n",
end.as_secs()
);
data
}

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 group = c.benchmark_group("fft");
for k in RANGE {
group.bench_function(BenchmarkId::new("k", k), |b| {
let n = 1 << k;
assert!(n <= data.len());
b.iter(|| {
best_fft(&mut data[..n], omega, k);
});
});
}
group.finish();
}

criterion_group!(benches, fft);
criterion_main!(benches);
16 changes: 8 additions & 8 deletions benches/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,28 @@ fn criterion_benchmark<G: CurveExt>(c: &mut Criterion) {
let v = vec![G::generator(); N];
let mut q = vec![G::AffineExt::identity(); N];

c.bench_function(&format!("{} check on curve", name), move |b| {
c.bench_function(&format!("{name} check on curve"), move |b| {
b.iter(|| black_box(p1).is_on_curve())
});
c.bench_function(&format!("{} check equality", name), move |b| {
c.bench_function(&format!("{name} check equality"), move |b| {
b.iter(|| black_box(p1) == black_box(p1))
});
c.bench_function(&format!("{} to affine", name), move |b| {
c.bench_function(&format!("{name} to affine"), move |b| {
b.iter(|| G::AffineExt::from(black_box(p1)))
});
c.bench_function(&format!("{} doubling", name), move |b| {
c.bench_function(&format!("{name} doubling"), move |b| {
b.iter(|| black_box(p1).double())
});
c.bench_function(&format!("{} addition", name), move |b| {
c.bench_function(&format!("{name} addition"), move |b| {
b.iter(|| black_box(p1).add(&p2))
});
c.bench_function(&format!("{} mixed addition", name), move |b| {
c.bench_function(&format!("{name} mixed addition"), move |b| {
b.iter(|| black_box(p2).add(&p1_affine))
});
c.bench_function(&format!("{} scalar multiplication", name), move |b| {
c.bench_function(&format!("{name} scalar multiplication"), move |b| {
b.iter(|| black_box(p1) * black_box(s))
});
c.bench_function(&format!("{} batch to affine n={}", name, N), move |b| {
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]
Expand Down
59 changes: 59 additions & 0 deletions benches/hash_to_curve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use pasta_curves::arithmetic::CurveExt;
use rand_core::{OsRng, RngCore};
use std::iter;

fn hash_to_secp256k1(c: &mut Criterion) {
hash_to_curve::<halo2curves::secp256k1::Secp256k1>(c, "Secp256k1");
}

fn hash_to_secq256k1(c: &mut Criterion) {
hash_to_curve::<halo2curves::secq256k1::Secq256k1>(c, "Secq256k1");
}

fn hash_to_secp256r1(c: &mut Criterion) {
hash_to_curve::<halo2curves::secp256r1::Secp256r1>(c, "Secp256r1");
}

fn hash_to_pallas(c: &mut Criterion) {
hash_to_curve::<halo2curves::pasta::Ep>(c, "Pallas");
}

fn hash_to_vesta(c: &mut Criterion) {
hash_to_curve::<halo2curves::pasta::Eq>(c, "Vesta");
}

fn hash_to_bn256(c: &mut Criterion) {
hash_to_curve::<halo2curves::bn256::G1>(c, "Bn256");
}

fn hash_to_grumpkin(c: &mut Criterion) {
hash_to_curve::<halo2curves::grumpkin::G1>(c, "Grumpkin");
}

fn hash_to_curve<G: CurveExt>(c: &mut Criterion, name: &'static str) {
{
let hasher = G::hash_to_curve("test");
let mut rng = OsRng;
let message = iter::repeat_with(|| rng.next_u32().to_be_bytes())
.take(1024)
.flatten()
.collect::<Vec<_>>();

c.bench_function(&format!("Hash to {name}"), move |b| {
b.iter(|| hasher(black_box(&message)))
});
}
}

criterion_group!(
benches,
hash_to_secp256k1,
hash_to_secq256k1,
hash_to_secp256r1,
hash_to_pallas,
hash_to_vesta,
hash_to_bn256,
hash_to_grumpkin,
);
criterion_main!(benches);
116 changes: 116 additions & 0 deletions benches/msm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//! This benchmarks Multi Scalar Multiplication (MSM).
//! It measures `G1` from the BN256 curve.
//!
//! To run this benchmark:
//!
//! cargo bench -- msm
//!
//! Caveat: The multicore benchmark assumes:
//! 1. a multi-core system
//! 2. that the `multicore` feature is enabled. It is by default.

#[macro_use]
extern crate criterion;

use criterion::{BenchmarkId, Criterion};
use ff::Field;
use group::prime::PrimeCurveAffine;
use halo2curves::bn256::{Fr as Scalar, G1Affine as Point};
use halo2curves::msm::{best_multiexp, multiexp_serial};
use maybe_rayon::current_thread_index;
use maybe_rayon::prelude::{IntoParallelIterator, ParallelIterator};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::time::SystemTime;

const SAMPLE_SIZE: usize = 10;
const SINGLECORE_RANGE: [u8; 6] = [3, 8, 10, 12, 14, 16];
const MULTICORE_RANGE: [u8; 9] = [3, 8, 10, 12, 14, 16, 18, 20, 22];
const SEED: [u8; 16] = [
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5,
];

fn generate_coefficients_and_curvepoints(k: u8) -> (Vec<Scalar>, Vec<Point>) {
let n: u64 = {
assert!(k < 64);
1 << k
};

println!("\n\nGenerating 2^{k} = {n} coefficients and curve points..",);
let timer = SystemTime::now();
let coeffs = (0..n)
.into_par_iter()
.map_init(
|| {
let mut thread_seed = SEED;
let uniq = current_thread_index().unwrap().to_ne_bytes();
assert!(std::mem::size_of::<usize>() == 8);
for i in 0..uniq.len() {
thread_seed[i] += uniq[i];
thread_seed[i + 8] += uniq[i];
}
XorShiftRng::from_seed(thread_seed)
},
|rng, _| Scalar::random(rng),
)
.collect();
let bases = (0..n)
.into_par_iter()
.map_init(
|| {
let mut thread_seed = SEED;
let uniq = current_thread_index().unwrap().to_ne_bytes();
assert!(std::mem::size_of::<usize>() == 8);
for i in 0..uniq.len() {
thread_seed[i] += uniq[i];
thread_seed[i + 8] += uniq[i];
}
XorShiftRng::from_seed(thread_seed)
},
|rng, _| Point::random(rng),
)
.collect();
let end = timer.elapsed().unwrap();
println!(
"Generating 2^{k} = {n} coefficients and curve points took: {} sec.\n\n",
end.as_secs()
);

(coeffs, bases)
}

fn msm(c: &mut Criterion) {
let mut group = c.benchmark_group("msm");
let max_k = *SINGLECORE_RANGE
.iter()
.chain(MULTICORE_RANGE.iter())
.max()
.unwrap_or(&16);
let (coeffs, bases) = generate_coefficients_and_curvepoints(max_k);

for k in SINGLECORE_RANGE {
group
.bench_function(BenchmarkId::new("singlecore", k), |b| {
assert!(k < 64);
let n: usize = 1 << k;
let mut acc = Point::identity().into();
b.iter(|| multiexp_serial(&coeffs[..n], &bases[..n], &mut acc));
})
.sample_size(10);
}
for k in MULTICORE_RANGE {
group
.bench_function(BenchmarkId::new("multicore", k), |b| {
assert!(k < 64);
let n: usize = 1 << k;
b.iter(|| {
best_multiexp(&coeffs[..n], &bases[..n]);
})
})
.sample_size(SAMPLE_SIZE);
}
group.finish();
}

criterion_group!(benches, msm);
criterion_main!(benches);
Loading
Loading