Skip to content

Commit

Permalink
Merge pull request #531 from input-output-hk/batch_verify
Browse files Browse the repository at this point in the history
Batch verify of StmAggregateSignatures
  • Loading branch information
iquerejeta authored Jan 4, 2023
2 parents a43b1b8 + 2ff2039 commit cab17fa
Show file tree
Hide file tree
Showing 9 changed files with 570 additions and 115 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions mithril-stm/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.2.1 (04-01-2022)
### Added
- Batch verification for `StmAggrSig`.

## 0.2.0 (16-12-2022)
### Changed
- Addapted the `Signature` struct, so that it does not contain the verification key and
the stake, as these values are not required.

## 0.1.0 (05-12-2022)
Initial release.
10 changes: 8 additions & 2 deletions mithril-stm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-stm"
version = "0.2.0"
version = "0.2.1"
edition = { workspace = true }
authors = { workspace = true }
documentation = { workspace = true }
Expand All @@ -27,6 +27,7 @@ num-bigint = { version = "0.4.0", optional = true }
num-rational = { version = "0.4.0", optional = true }
num-traits = { version = "0.2.14", optional = true }
rand_core = "0.6.3"
rayon = "1.5.1"
rug = { version = "1.14", optional = true }
serde = { version = "1", features = ["rc", "derive"] }
thiserror = "1.0"
Expand All @@ -39,7 +40,11 @@ num-bigint = "0.4.0"
num-rational = "0.4.0"
proptest = "1.0.0"
rand_chacha = "0.3.1"
rayon = "1.5.1"

[[bench]]
name = "multi_sig"
harness = false
required-features = ["benchmark-internals"]

[[bench]]
name = "stm"
Expand All @@ -54,3 +59,4 @@ default = ["rug-backend"]
rug-backend = ["rug/default"]
num-integer-backend = ["num-bigint", "num-rational", "num-traits"]
portable = ["blst/portable"]
benchmark-internals = [] # For benchmarking multi_sig
93 changes: 93 additions & 0 deletions mithril-stm/benches/multi_sig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use blake2::{digest::consts::U64, Blake2b, Digest};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use mithril_stm::multi_sig::{Signature, SigningKey, VerificationKey};
use rand_chacha::ChaCha20Rng;
use rand_core::{RngCore, SeedableRng};

fn batch_benches(c: &mut Criterion, array_batches: &[usize], nr_sigs: usize) {
let mut group = c.benchmark_group("MultiSig".to_string());
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
let mut batch_msgs = Vec::new();
let mut batch_vk = Vec::new();
let mut batch_sig = Vec::new();

for &nr_batches in array_batches {
let batch_string = format!("Batch size: {}", nr_batches);

for _ in 0..nr_batches {
let mut msg = [0u8; 32];
rng.fill_bytes(&mut msg);
let mut mvks = Vec::new();
let mut sigs = Vec::new();
for _ in 0..nr_sigs {
let sk = SigningKey::gen(&mut rng);
let vk = VerificationKey::from(&sk);
let sig = sk.sign(&msg);
sigs.push(sig);
mvks.push(vk);
}
let (agg_vk, agg_sig) = Signature::aggregate(&mvks, &sigs).unwrap();
batch_msgs.push(msg.to_vec());
batch_vk.push(agg_vk);
batch_sig.push(agg_sig);
}

group.bench_function(BenchmarkId::new("Batch Verification", batch_string), |b| {
b.iter(|| {
Signature::batch_verify_aggregates(&batch_msgs, &batch_vk, &batch_sig).is_ok()
})
});
}
}

fn aggregate_and_verify(c: &mut Criterion, nr_sigs: usize) {
let mut group = c.benchmark_group("BLS".to_string());
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);

let mut msg = [0u8; 32];
rng.fill_bytes(&mut msg);
let mut mvks = Vec::new();
let mut sigs = Vec::new();
for _ in 0..nr_sigs {
let sk = SigningKey::gen(&mut rng);
let vk = VerificationKey::from(&sk);
let sig = sk.sign(&msg);
sigs.push(sig);
mvks.push(vk);
}

group.bench_function(BenchmarkId::new("Individual verif", nr_sigs), |b| {
b.iter(|| {
for (vk, sig) in mvks.iter().zip(sigs.iter()) {
assert!(sig.verify(&msg, vk).is_ok());
}
})
});

group.bench_function(BenchmarkId::new("Batch Verification", nr_sigs), |b| {
b.iter(|| {
for sig in sigs.iter() {
let mut hasher = Blake2b::<U64>::new();
hasher.update(sig.to_bytes());
hasher.finalize();
}
let (agg_vk, agg_sig) = Signature::aggregate(&mvks, &sigs).unwrap();
assert!(agg_sig.verify(&msg, &agg_vk).is_ok())
})
});
}

fn batch_multi_sig_benches(c: &mut Criterion) {
batch_benches(c, &[1, 10, 20, 50, 100], 300);
}
fn batch_bls_benches(c: &mut Criterion) {
aggregate_and_verify(c, 856);
}

criterion_group!(name = benches;
config = Criterion::default().nresamples(1000);
targets =
batch_multi_sig_benches,
batch_bls_benches
);
criterion_main!(benches);
116 changes: 107 additions & 9 deletions mithril-stm/benches/stm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@ use blake2::digest::{Digest, FixedOutput};
use blake2::{digest::consts::U32, Blake2b};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use mithril_stm::key_reg::KeyReg;
use mithril_stm::stm::{StmClerk, StmInitializer, StmParameters, StmSigner};
use mithril_stm::stm::{StmAggrSig, StmClerk, StmInitializer, StmParameters, StmSigner};
use rand_chacha::ChaCha20Rng;
use rand_core::{RngCore, SeedableRng};
use rayon::prelude::*;
use std::fmt::Debug;

///
/// This benchmark framework is not ideal. We really have to think what is the best mechanism for
/// benchmarking these signatures, over which parameters, how many times to run them, etc:
/// * Registration depends on the number of parties (should be constant, as it is a lookup table)
/// * Signing depends on the parameter `m`, as it defines the number of lotteries a user can play
/// * Aggregation depends on `k`.
/// * Verification is independent from the parameters.

fn stm_benches<H>(c: &mut Criterion, nr_parties: usize, params: StmParameters, hashing_alg: &str)
where
H: Clone + Debug + Digest + Send + Sync + FixedOutput + Default,
Expand Down Expand Up @@ -70,15 +67,97 @@ where
.collect::<Vec<_>>();

let clerk = StmClerk::from_signer(&signers[0]);
let msig = clerk.aggregate(&sigs, &msg).unwrap();

group.bench_function(BenchmarkId::new("Aggregation", &param_string), |b| {
b.iter(|| clerk.aggregate(&sigs, &msg))
});
}

group.bench_function(BenchmarkId::new("Verification", &param_string), |b| {
b.iter(|| msig.verify(&msg, &clerk.compute_avk(), &params).is_ok())
});
fn batch_benches<H>(
c: &mut Criterion,
array_batches: &[usize],
nr_parties: usize,
params: StmParameters,
hashing_alg: &str,
) where
H: Clone + Debug + Digest + FixedOutput + Send + Sync,
{
let mut group = c.benchmark_group(format!("STM/{}", hashing_alg));
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);

let param_string = format!(
"k: {}, m: {}, nr_parties: {}",
params.k, params.m, nr_parties
);

for &nr_batches in array_batches {
let batch_string = format!("{}/batch size: {}", param_string, nr_batches);

let mut batch_msgs = Vec::with_capacity(nr_batches);
let mut batch_params = Vec::with_capacity(nr_batches);
let mut batch_stms = Vec::with_capacity(nr_batches);
let mut batch_avks = Vec::with_capacity(nr_batches);

for _ in 0..nr_batches {
let mut msg = [0u8; 32];
rng.fill_bytes(&mut msg);
batch_msgs.push(msg.to_vec());
batch_params.push(params);

let stakes = (0..nr_parties)
.into_iter()
.map(|_| 1 + (rng.next_u64() % 9999))
.collect::<Vec<_>>();

let mut initializers: Vec<StmInitializer> = Vec::with_capacity(nr_parties);
for stake in stakes {
initializers.push(StmInitializer::setup(params, stake, &mut rng));
}
let mut key_reg = KeyReg::init();
for p in initializers.iter() {
key_reg.register(p.stake, p.verification_key()).unwrap();
}

let closed_reg = key_reg.close();

let signers = initializers
.into_par_iter()
.map(|p| p.new_signer(closed_reg.clone()).unwrap())
.collect::<Vec<StmSigner<H>>>();

let sigs = signers
.par_iter()
.filter_map(|p| p.sign(&msg))
.collect::<Vec<_>>();

let clerk = StmClerk::from_signer(&signers[0]);
let msig = clerk.aggregate(&sigs, &msg).unwrap();

batch_avks.push(clerk.compute_avk());
batch_stms.push(msig);
}

group.bench_function(BenchmarkId::new("Batch Verification", batch_string), |b| {
b.iter(|| {
StmAggrSig::batch_verify(&batch_stms, &batch_msgs, &batch_avks, &batch_params)
.is_ok()
})
});
}
}

fn batch_stm_benches_blake_300(c: &mut Criterion) {
batch_benches::<Blake2b<U32>>(
c,
&[1, 10, 20, 100],
300,
StmParameters {
m: 150,
k: 25,
phi_f: 0.4,
},
"Blake2b",
);
}

fn stm_benches_blake_300(c: &mut Criterion) {
Expand All @@ -94,6 +173,20 @@ fn stm_benches_blake_300(c: &mut Criterion) {
);
}

fn batch_stm_benches_blake_2000(c: &mut Criterion) {
batch_benches::<Blake2b<U32>>(
c,
&[1, 10, 20, 100],
2000,
StmParameters {
m: 1523,
k: 250,
phi_f: 0.4,
},
"Blake2b",
);
}

fn stm_benches_blake_2000(c: &mut Criterion) {
stm_benches::<Blake2b<U32>>(
c,
Expand All @@ -109,5 +202,10 @@ fn stm_benches_blake_2000(c: &mut Criterion) {

criterion_group!(name = benches;
config = Criterion::default().nresamples(1000);
targets = stm_benches_blake_300, stm_benches_blake_2000);
targets =
stm_benches_blake_300,
stm_benches_blake_2000,
batch_stm_benches_blake_300,
batch_stm_benches_blake_2000,
);
criterion_main!(benches);
17 changes: 16 additions & 1 deletion mithril-stm/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ pub enum MultiSignatureError {
/// Incorrect proof of possession
#[error("Key with invalid PoP")]
KeyInvalid(Box<VerificationKeyPoP>),

/// At least one signature in the batch is invalid
#[error("One signature in the batch is invalid")]
BatchInvalid,
}

/// Errors which can be output by Mithril single signature verification.
Expand All @@ -46,6 +50,10 @@ pub enum StmSignatureError {
#[error("A provided signature is invalid")]
SignatureInvalid(Signature),

/// Batch verification of STM signatures failed
#[error("Batch verification of STM signatures failed")]
BatchInvalid,

/// This error occurs when the the serialization of the raw bytes failed
#[error("Invalid bytes")]
SerializationError,
Expand Down Expand Up @@ -81,6 +89,10 @@ pub enum StmAggregateSignatureError<D: Digest + FixedOutput> {
/// Invalid merkle batch path
#[error("Batch path does not verify against root")]
PathInvalid(BatchPath<D>),

/// Batch verification of STM aggregate signatures failed
#[error("Batch verification of STM aggregate signatures failed")]
BatchInvalid,
}

/// Error types for aggregation.
Expand Down Expand Up @@ -146,6 +158,7 @@ impl From<MultiSignatureError> for StmSignatureError {
match e {
MultiSignatureError::SerializationError => Self::SerializationError,
MultiSignatureError::SignatureInvalid(e) => Self::SignatureInvalid(e),
MultiSignatureError::BatchInvalid => unreachable!(),
MultiSignatureError::KeyInvalid(_) => unreachable!(),
MultiSignatureError::AggregateSignatureInvalid => unreachable!(),
}
Expand All @@ -156,6 +169,7 @@ impl<D: Digest + FixedOutput> From<MultiSignatureError> for StmAggregateSignatur
fn from(e: MultiSignatureError) -> Self {
match e {
MultiSignatureError::AggregateSignatureInvalid => Self::AggregateSignatureInvalid,
MultiSignatureError::BatchInvalid => Self::BatchInvalid,
MultiSignatureError::SerializationError => unreachable!(),
MultiSignatureError::KeyInvalid(_) => unreachable!(),
MultiSignatureError::SignatureInvalid(_e) => unreachable!(),
Expand All @@ -176,13 +190,14 @@ impl From<MultiSignatureError> for RegisterError {
MultiSignatureError::KeyInvalid(e) => Self::KeyInvalid(e),
MultiSignatureError::SignatureInvalid(_) => unreachable!(),
MultiSignatureError::AggregateSignatureInvalid => unreachable!(),
MultiSignatureError::BatchInvalid => unreachable!(),
}
}
}

/// If verifying a single signature, the signature should be provided. If verifying a multi-sig,
/// no need to provide the signature
pub(crate) fn blst_err_to_atms(
pub(crate) fn blst_err_to_mithril(
e: BLST_ERROR,
sig: Option<Signature>,
) -> Result<(), MultiSignatureError> {
Expand Down
8 changes: 6 additions & 2 deletions mithril-stm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ pub mod key_reg;
mod merkle_tree;
pub mod stm;

mod multi_sig;

pub use crate::error::{AggregationError, RegisterError};

#[cfg(feature = "benchmark-internals")]
pub mod multi_sig;

#[cfg(not(feature = "benchmark-internals"))]
mod multi_sig;
Loading

0 comments on commit cab17fa

Please sign in to comment.