add benchmarks (#205)
* add benchmarks * Apply suggestions from code review Co-authored-by: Marek <mail@marek.onl> * cargo fmt --------- Co-authored-by: Marek <mail@marek.onl>
This commit is contained in:
parent
084ed95f46
commit
956d8d3c7f
|
@ -30,6 +30,7 @@ zeroize = { version = "1.5.4", default-features = false, features = ["derive"] }
|
|||
proptest = { version = "1.0", optional = true }
|
||||
proptest-derive = { version = "0.3", optional = true }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
criterion = { version = "0.4", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
curve25519-dalek = { version = "=4.0.0-pre.1", features = ["serde"] }
|
||||
|
@ -43,6 +44,9 @@ sha2 = "0.10.2"
|
|||
[features]
|
||||
nightly = []
|
||||
default = []
|
||||
# Exposes ciphersuite-generic tests for other crates to use
|
||||
test-impl = ["proptest", "proptest-derive", "serde_json"]
|
||||
internals = []
|
||||
# Exposes ciphersuite-generic tests for other crates to use
|
||||
test-impl = ["proptest", "proptest-derive", "serde_json", "criterion"]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
//! Ciphersuite-generic benchmark functions.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use criterion::{BenchmarkId, Criterion, Throughput};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use crate::{batch, frost, Ciphersuite, Signature, SigningKey, VerifyingKey};
|
||||
|
||||
struct Item<C: Ciphersuite> {
|
||||
vk: VerifyingKey<C>,
|
||||
sig: Signature<C>,
|
||||
}
|
||||
|
||||
fn sigs_with_distinct_keys<C: Ciphersuite, R: RngCore + CryptoRng + Clone>(
|
||||
rng: &mut R,
|
||||
) -> impl Iterator<Item = Item<C>> {
|
||||
let mut rng = rng.clone();
|
||||
std::iter::repeat_with(move || {
|
||||
let msg = b"Bench";
|
||||
let sk = SigningKey::new(&mut rng);
|
||||
let vk = VerifyingKey::from(&sk);
|
||||
let sig = sk.sign(&mut rng, &msg[..]);
|
||||
Item { vk, sig }
|
||||
})
|
||||
}
|
||||
|
||||
/// Benchmark batched signature verification with the specified ciphersuite.
|
||||
pub fn bench_batch_verify<C: Ciphersuite, R: RngCore + CryptoRng + Clone>(
|
||||
c: &mut Criterion,
|
||||
name: &str,
|
||||
rng: &mut R,
|
||||
) {
|
||||
let mut group = c.benchmark_group(format!("Batch Verification {}", name));
|
||||
for &n in [8usize, 16, 24, 32, 40, 48, 56, 64].iter() {
|
||||
group.throughput(Throughput::Elements(n as u64));
|
||||
|
||||
let sigs = sigs_with_distinct_keys::<C, R>(rng)
|
||||
.take(n)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("Unbatched verification", n),
|
||||
&sigs,
|
||||
|b, sigs| {
|
||||
b.iter(|| {
|
||||
for item in sigs.iter() {
|
||||
let msg = b"Bench";
|
||||
|
||||
let Item { vk, sig } = item;
|
||||
let _ = vk.verify(msg, sig);
|
||||
}
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("Batched verification", n),
|
||||
&sigs,
|
||||
|b, sigs| {
|
||||
let mut rng = rng.clone();
|
||||
b.iter(|| {
|
||||
let mut batch = batch::Verifier::new();
|
||||
for item in sigs.iter() {
|
||||
let msg = b"Bench";
|
||||
|
||||
let Item { vk, sig } = item;
|
||||
batch.queue((*vk, *sig, msg));
|
||||
}
|
||||
batch.verify(&mut rng)
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
/// Benchmark FROST signing with the specified ciphersuite.
|
||||
pub fn bench_sign<C: Ciphersuite, R: RngCore + CryptoRng + Clone>(
|
||||
c: &mut Criterion,
|
||||
name: &str,
|
||||
rng: &mut R,
|
||||
) {
|
||||
let mut group = c.benchmark_group(format!("FROST Signing {}", name));
|
||||
for &n in [3u16, 10, 100, 1000].iter() {
|
||||
let max_signers = n;
|
||||
let min_signers = (n * 2 + 2) / 3;
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("Key Generation with Dealer", max_signers),
|
||||
&(max_signers, min_signers),
|
||||
|b, (max_signers, min_signers)| {
|
||||
let mut rng = rng.clone();
|
||||
b.iter(|| {
|
||||
frost::keys::keygen_with_dealer::<C, R>(*max_signers, *min_signers, &mut rng)
|
||||
.unwrap();
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let (shares, pubkeys) =
|
||||
frost::keys::keygen_with_dealer::<C, R>(max_signers, min_signers, rng).unwrap();
|
||||
|
||||
// Verifies the secret shares from the dealer
|
||||
let key_packages: HashMap<_, _> = shares
|
||||
.into_iter()
|
||||
.map(|share| {
|
||||
(
|
||||
share.identifier,
|
||||
frost::keys::KeyPackage::try_from(share).unwrap(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("Round 1", min_signers),
|
||||
&key_packages,
|
||||
|b, key_packages| {
|
||||
b.iter(|| {
|
||||
let participant_identifier = 1u16.try_into().expect("should be nonzero");
|
||||
frost::round1::commit(
|
||||
participant_identifier,
|
||||
key_packages
|
||||
.get(&participant_identifier)
|
||||
.unwrap()
|
||||
.secret_share(),
|
||||
rng,
|
||||
);
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let mut nonces: HashMap<_, _> = HashMap::new();
|
||||
let mut commitments: HashMap<_, _> = HashMap::new();
|
||||
|
||||
for participant_index in 1..=min_signers {
|
||||
let participant_identifier = participant_index.try_into().expect("should be nonzero");
|
||||
let (nonce, commitment) = frost::round1::commit(
|
||||
participant_identifier,
|
||||
key_packages
|
||||
.get(&participant_identifier)
|
||||
.unwrap()
|
||||
.secret_share(),
|
||||
rng,
|
||||
);
|
||||
nonces.insert(participant_identifier, nonce);
|
||||
commitments.insert(participant_identifier, commitment);
|
||||
}
|
||||
|
||||
let message = "message to sign".as_bytes();
|
||||
let comms = commitments.clone().into_values().collect();
|
||||
let signing_package = frost::SigningPackage::new(comms, message.to_vec());
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("Round 2", min_signers),
|
||||
&(
|
||||
key_packages.clone(),
|
||||
nonces.clone(),
|
||||
signing_package.clone(),
|
||||
),
|
||||
|b, (key_packages, nonces, signing_package)| {
|
||||
b.iter(|| {
|
||||
let participant_identifier = 1u16.try_into().expect("should be nonzero");
|
||||
let key_package = key_packages.get(&participant_identifier).unwrap();
|
||||
let nonces_to_use = &nonces.get(&participant_identifier).unwrap();
|
||||
frost::round2::sign(signing_package, nonces_to_use, key_package).unwrap();
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let mut signature_shares = Vec::new();
|
||||
for participant_identifier in nonces.keys() {
|
||||
let key_package = key_packages.get(participant_identifier).unwrap();
|
||||
let nonces_to_use = &nonces.get(participant_identifier).unwrap();
|
||||
let signature_share =
|
||||
frost::round2::sign(&signing_package, nonces_to_use, key_package).unwrap();
|
||||
signature_shares.push(signature_share);
|
||||
}
|
||||
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("Aggregate", min_signers),
|
||||
&(signing_package.clone(), signature_shares.clone(), pubkeys),
|
||||
|b, (signing_package, signature_shares, pubkeys)| {
|
||||
b.iter(|| {
|
||||
frost::aggregate(signing_package, &signature_shares[..], pubkeys).unwrap();
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
}
|
|
@ -181,6 +181,7 @@ fn derive_lagrange_coeff<C: Ciphersuite>(
|
|||
|
||||
/// Generated by the coordinator of the signing operation and distributed to
|
||||
/// each signing party
|
||||
#[derive(Clone)]
|
||||
pub struct SigningPackage<C: Ciphersuite> {
|
||||
/// The set of commitments participants published in the first round of the
|
||||
/// protocol.
|
||||
|
|
|
@ -60,11 +60,11 @@ where
|
|||
|
||||
/// Generates a new uniformly random secret value using the provided RNG.
|
||||
// TODO: should this only be behind test?
|
||||
pub fn random<R>(mut rng: R) -> Self
|
||||
pub fn random<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: CryptoRng + RngCore,
|
||||
{
|
||||
Self(random_nonzero::<C, R>(&mut rng))
|
||||
Self(random_nonzero::<C, R>(rng))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,15 +322,15 @@ where
|
|||
pub fn keygen_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
|
||||
max_signers: u16,
|
||||
min_signers: u16,
|
||||
mut rng: R,
|
||||
rng: &mut R,
|
||||
) -> Result<(Vec<SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
|
||||
let mut bytes = [0; 64];
|
||||
rng.fill_bytes(&mut bytes);
|
||||
|
||||
let secret = SharedSecret::random(&mut rng);
|
||||
let secret = SharedSecret::random(rng);
|
||||
let group_public = VerifyingKey::from(&secret);
|
||||
|
||||
let coefficients = generate_coefficients::<C, R>(min_signers as usize - 1, &mut rng);
|
||||
let coefficients = generate_coefficients::<C, R>(min_signers as usize - 1, rng);
|
||||
|
||||
let secret_shares = generate_secret_shares(&secret, max_signers, min_signers, coefficients)?;
|
||||
let mut signer_pubkeys: HashMap<Identifier<C>, VerifyingShare<C>> =
|
||||
|
|
|
@ -14,6 +14,8 @@ use std::{
|
|||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
pub mod batch;
|
||||
#[cfg(any(test, feature = "test-impl"))]
|
||||
pub mod benches;
|
||||
mod error;
|
||||
pub mod frost;
|
||||
mod scalar_mul;
|
||||
|
|
|
@ -44,3 +44,12 @@ serde_json = "1.0"
|
|||
[features]
|
||||
nightly = []
|
||||
default = []
|
||||
|
||||
[lib]
|
||||
# Disables non-criterion benchmark which is not used; prevents errors
|
||||
# when using criterion-specific flags
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use rand::thread_rng;
|
||||
|
||||
use frost_ed25519::*;
|
||||
|
||||
fn bench_ed25519_batch_verify(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
frost_core::benches::bench_batch_verify::<Ed25519Sha512, _>(c, "ed25519", &mut rng);
|
||||
}
|
||||
|
||||
fn bench_ed25519_sign(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
frost_core::benches::bench_sign::<Ed25519Sha512, _>(c, "ed25519", &mut rng);
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_ed25519_batch_verify, bench_ed25519_sign);
|
||||
criterion_main!(benches);
|
|
@ -42,3 +42,12 @@ serde_json = "1.0"
|
|||
[features]
|
||||
nightly = []
|
||||
default = []
|
||||
|
||||
[lib]
|
||||
# Disables non-criterion benchmark which is not used; prevents errors
|
||||
# when using criterion-specific flags
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use rand::thread_rng;
|
||||
|
||||
use frost_ed448::*;
|
||||
|
||||
// bench_ed448_batch_verify not included until batch verification is fixed for Ed448
|
||||
#[allow(unused)]
|
||||
fn bench_ed448_batch_verify(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
frost_core::benches::bench_batch_verify::<Ed448Shake256, _>(c, "ed448", &mut rng);
|
||||
}
|
||||
|
||||
fn bench_ed448_sign(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
frost_core::benches::bench_sign::<Ed448Shake256, _>(c, "ed448", &mut rng);
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_ed448_sign);
|
||||
criterion_main!(benches);
|
|
@ -44,6 +44,11 @@ serde_json = "1.0"
|
|||
nightly = []
|
||||
default = []
|
||||
|
||||
# [[bench]]
|
||||
# name = "bench"
|
||||
# harness = false
|
||||
[lib]
|
||||
# Disables non-criterion benchmark which is not used; prevents errors
|
||||
# when using criterion-specific flags
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use rand::thread_rng;
|
||||
|
||||
use frost_p256::*;
|
||||
|
||||
fn bench_p256_batch_verify(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
frost_core::benches::bench_batch_verify::<P256Sha256, _>(c, "p256", &mut rng);
|
||||
}
|
||||
|
||||
fn bench_p256_sign(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
frost_core::benches::bench_sign::<P256Sha256, _>(c, "p256", &mut rng);
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_p256_batch_verify, bench_p256_sign);
|
||||
criterion_main!(benches);
|
|
@ -25,7 +25,7 @@ sha2 = "0.10.2"
|
|||
|
||||
[dev-dependencies]
|
||||
bincode = "1"
|
||||
criterion = "0.4"
|
||||
criterion = { version = "0.4", features = ["html_reports"] }
|
||||
ed25519-dalek = "1.0.1"
|
||||
ed25519-zebra = "3.0.0"
|
||||
lazy_static = "1.4"
|
||||
|
@ -39,6 +39,11 @@ serde_json = "1.0"
|
|||
nightly = []
|
||||
default = []
|
||||
|
||||
[lib]
|
||||
# Disables non-criterion benchmark which is not used; prevents errors
|
||||
# when using criterion-specific flags
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
|
|
|
@ -1,72 +1,23 @@
|
|||
// use std::convert::TryFrom;
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use rand::thread_rng;
|
||||
|
||||
// use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||
// use rand::thread_rng;
|
||||
use frost_ristretto255::*;
|
||||
|
||||
// use frost_ristretto255::*;
|
||||
fn bench_ristretto255_batch_verify(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// struct Item {
|
||||
// vk: VerifyingKey,
|
||||
// sig: Signature,
|
||||
// }
|
||||
frost_core::benches::bench_batch_verify::<Ristretto255Sha512, _>(c, "ristretto255", &mut rng);
|
||||
}
|
||||
|
||||
// fn sigs_with_distinct_keys() -> impl Iterator<Item = Item> {
|
||||
// std::iter::repeat_with(|| {
|
||||
// let msg = b"Bench";
|
||||
// let sk = SigningKey::new(thread_rng());
|
||||
// let vk = VerifyingKey::from(&sk).into();
|
||||
// let sig = sk.sign(thread_rng(), &msg[..]);
|
||||
// Item { vk, sig }
|
||||
// })
|
||||
// }
|
||||
fn bench_ristretto255_sign(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// fn bench_batch_verify(c: &mut Criterion) {
|
||||
// let mut group = c.benchmark_group("Batch Verification");
|
||||
// for &n in [8usize, 16, 24, 32, 40, 48, 56, 64].iter() {
|
||||
// group.throughput(Throughput::Elements(n as u64));
|
||||
frost_core::benches::bench_sign::<Ristretto255Sha512, _>(c, "ristretto255", &mut rng);
|
||||
}
|
||||
|
||||
// let sigs = sigs_with_distinct_keys().take(n).collect::<Vec<_>>();
|
||||
|
||||
// group.bench_with_input(
|
||||
// BenchmarkId::new("Unbatched verification", n),
|
||||
// &sigs,
|
||||
// |b, sigs| {
|
||||
// b.iter(|| {
|
||||
// for item in sigs.iter() {
|
||||
// let msg = b"Bench";
|
||||
|
||||
// let Item { vk, sig } = item;
|
||||
// {
|
||||
// vk.verify(msg, sig);
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
// );
|
||||
|
||||
// group.bench_with_input(
|
||||
// BenchmarkId::new("Batched verification", n),
|
||||
// &sigs,
|
||||
// |b, sigs| {
|
||||
// b.iter(|| {
|
||||
// let mut batch = batch::Verifier::new();
|
||||
// for item in sigs.iter() {
|
||||
// let msg = b"Bench";
|
||||
|
||||
// let Item { vk, sig } = item;
|
||||
// {
|
||||
// batch.queue((*vk, *sig, msg));
|
||||
// }
|
||||
// }
|
||||
// batch.verify(thread_rng())
|
||||
// })
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// group.finish();
|
||||
// }
|
||||
|
||||
// criterion_group!(benches, bench_batch_verify);
|
||||
// criterion_main!(benches);
|
||||
|
||||
fn main() {}
|
||||
criterion_group!(
|
||||
benches,
|
||||
bench_ristretto255_batch_verify,
|
||||
bench_ristretto255_sign
|
||||
);
|
||||
criterion_main!(benches);
|
||||
|
|
|
@ -44,3 +44,12 @@ serde_json = "1.0"
|
|||
[features]
|
||||
nightly = []
|
||||
default = []
|
||||
|
||||
[lib]
|
||||
# Disables non-criterion benchmark which is not used; prevents errors
|
||||
# when using criterion-specific flags
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use rand::thread_rng;
|
||||
|
||||
use frost_secp256k1::*;
|
||||
|
||||
fn bench_secp256k1_batch_verify(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
frost_core::benches::bench_batch_verify::<Secp256K1Sha256, _>(c, "secp256k1", &mut rng);
|
||||
}
|
||||
|
||||
fn bench_secp256k1_sign(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
frost_core::benches::bench_sign::<Secp256K1Sha256, _>(c, "secp256k1", &mut rng);
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_secp256k1_batch_verify, bench_secp256k1_sign);
|
||||
criterion_main!(benches);
|
|
@ -7,3 +7,10 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
regex = "1.6.0"
|
||||
|
||||
[[bin]]
|
||||
name = "gendoc"
|
||||
path = "src/main.rs"
|
||||
# Disables non-criterion benchmark which is not used; prevents errors
|
||||
# when using criterion-specific flags
|
||||
bench = false
|
||||
|
|
Loading…
Reference in New Issue