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

Add benchmarks for the whole PRE scenario and some internals #54

Merged
merged 5 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/umbral-pre.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ jobs:
#- run: cp ../../Cargo.lock .. # Use same Cargo.lock resolution that's checked in
- run: cargo build --release --target ${{ matrix.target }} --no-default-features

build-benchmarks:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- 1.51.0 # MSRV
- stable
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
- run: cargo build --all-features --benches

test:
runs-on: ubuntu-latest
strategy:
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added separate entry points for Webpack and Node.JS in the WASM bindings, and added examples for both of these scenarios ([#60])
- `SecretBox` struct, a wrapper making operations with secret data explicit and ensuring zeroization on drop ([#53])
- Feature `default-rng` (enabled by default). When disabled, the library can be compiled on targets not supported by `getrandom` (e.g., ARM), but only the functions taking an explicit RNG as a parameter will be available. ([#55])
- Added benchmarks for the main usage scenario and a feature `bench-internals` to expose some internals for benchmarking ([#54])


### Fixed
Expand All @@ -27,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0


[#53]: https://github.com/nucypher/rust-umbral/pull/53
[#54]: https://github.com/nucypher/rust-umbral/pull/54
[#55]: https://github.com/nucypher/rust-umbral/pull/55
[#56]: https://github.com/nucypher/rust-umbral/pull/56
[#60]: https://github.com/nucypher/rust-umbral/pull/60
Expand Down
3 changes: 2 additions & 1 deletion umbral-pre/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ subtle = { version = "2.4", default-features = false }
zeroize = "1.3"

[dev-dependencies]
criterion = "0.3"
criterion = { version = "0.3", features = ["html_reports"] }

[features]
default = ["default-rng"]
bench-internals = ["default-rng"]
default-rng = ["getrandom", "rand_core/getrandom"]

[[bench]]
Expand Down
171 changes: 168 additions & 3 deletions umbral-pre/bench/bench.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
use criterion::measurement::Measurement;
use criterion::{criterion_group, criterion_main, BenchmarkGroup, Criterion};

use umbral_pre::bench::unsafe_hash_to_point;
#[cfg(feature = "bench-internals")]
use umbral_pre::bench::{
capsule_from_public_key, capsule_open_original, capsule_open_reencrypted, get_cfrag,
unsafe_hash_to_point,
};

use umbral_pre::{
decrypt_original, decrypt_reencrypted, encrypt, generate_kfrags, reencrypt, SecretKey, Signer,
VerifiedCapsuleFrag,
};

#[cfg(feature = "bench-internals")]
fn bench_unsafe_hash_to_point<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) {
let data = b"abcdefg";
let label = b"sdasdasd";
Expand All @@ -11,11 +21,166 @@ fn bench_unsafe_hash_to_point<'a, M: Measurement>(group: &mut BenchmarkGroup<'a,
});
}

fn bench_all(c: &mut Criterion) {
#[cfg(feature = "bench-internals")]
fn bench_capsule_from_public_key<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) {
let delegating_sk = SecretKey::random();
let delegating_pk = delegating_sk.public_key();
group.bench_function("Capsule::from_public_key", |b| {
b.iter(|| capsule_from_public_key(&delegating_pk))
});
}

#[cfg(feature = "bench-internals")]
fn bench_capsule_open_original<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) {
let delegating_sk = SecretKey::random();
let delegating_pk = delegating_sk.public_key();
let plaintext = b"peace at dawn";
let (capsule, _ciphertext) = encrypt(&delegating_pk, plaintext).unwrap();
group.bench_function("Capsule::open_original", |b| {
b.iter(|| capsule_open_original(&capsule, &delegating_sk))
});
}

#[cfg(feature = "bench-internals")]
fn bench_capsule_open_reencrypted<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) {
let delegating_sk = SecretKey::random();
let delegating_pk = delegating_sk.public_key();

let signing_sk = SecretKey::random();
let signer = Signer::new(&signing_sk);

let receiving_sk = SecretKey::random();
let receiving_pk = receiving_sk.public_key();

let (capsule, _key_seed) = capsule_from_public_key(&delegating_pk);

let threshold: usize = 2;
let num_frags: usize = threshold + 1;

let kfrags = generate_kfrags(
&delegating_sk,
&receiving_pk,
&signer,
threshold,
num_frags,
true,
true,
);

let vcfrags: Vec<_> = kfrags
.iter()
.map(|kfrag| reencrypt(&capsule, &kfrag))
.collect();

let cfrags: Vec<_> = vcfrags[0..threshold]
.iter()
.map(|vcfrag| get_cfrag(&vcfrag).clone())
.collect();

group.bench_function("Capsule::open_reencrypted", |b| {
b.iter(|| capsule_open_reencrypted(&capsule, &receiving_sk, &delegating_pk, &cfrags))
});
}

fn bench_pre<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) {
let delegating_sk = SecretKey::random();
let delegating_pk = delegating_sk.public_key();
let plaintext = b"peace at dawn";

// Encryption

group.bench_function("encrypt", |b| {
b.iter(|| encrypt(&delegating_pk, &plaintext[..]))
});

// Decryption with the original key

let (capsule, ciphertext) = encrypt(&delegating_pk, plaintext).unwrap();
group.bench_function("decrypt_original", |b| {
b.iter(|| decrypt_original(&delegating_sk, &capsule, &ciphertext[..]))
});

// Kfrag generation

let threshold: usize = 2;
let num_frags: usize = threshold + 1;

let signing_sk = SecretKey::random();
let signer = Signer::new(&signing_sk);

let receiving_sk = SecretKey::random();
let receiving_pk = receiving_sk.public_key();

group.bench_function("generate_kfrags", |b| {
b.iter(|| {
generate_kfrags(
&delegating_sk,
&receiving_pk,
&signer,
threshold,
num_frags,
true,
true,
)
})
});

// Reencryption

let verified_kfrags = generate_kfrags(
&delegating_sk,
&receiving_pk,
&signer,
threshold,
num_frags,
true,
true,
);

let vkfrag = verified_kfrags[0].clone();

group.bench_function("reencrypt", |b| b.iter(|| reencrypt(&capsule, &vkfrag)));

// Decryption of the reencrypted data

let verified_cfrags: Vec<VerifiedCapsuleFrag> = verified_kfrags[0..threshold]
.iter()
.map(|vkfrag| reencrypt(&capsule, &vkfrag))
.collect();

group.bench_function("decrypt_reencrypted", |b| {
b.iter(|| {
decrypt_reencrypted(
&receiving_sk,
&delegating_pk,
&capsule,
&verified_cfrags,
&ciphertext,
)
})
});
}

#[cfg(feature = "bench-internals")]
fn group_internals(c: &mut Criterion) {
let mut group = c.benchmark_group("internals");
bench_unsafe_hash_to_point(&mut group);
bench_capsule_from_public_key(&mut group);
bench_capsule_open_original(&mut group);
bench_capsule_open_reencrypted(&mut group);
group.finish();
}

criterion_group!(benches, bench_all);
fn group_pre(c: &mut Criterion) {
let mut group = c.benchmark_group("PRE API");
bench_pre(&mut group);
group.finish();
}

#[cfg(feature = "bench-internals")]
criterion_group!(benches, group_internals, group_pre);

#[cfg(not(feature = "bench-internals"))]
criterion_group!(benches, group_pre);

criterion_main!(benches);
32 changes: 32 additions & 0 deletions umbral-pre/src/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,36 @@
//! This module re-exports some internals for the purposes of benchmarking.
//! Should not be used by regular users.

use rand_core::OsRng;

use crate::capsule::{Capsule, KeySeed, OpenReencryptedError};
use crate::capsule_frag::{CapsuleFrag, VerifiedCapsuleFrag};
use crate::keys::{PublicKey, SecretKey};
use crate::secret_box::SecretBox;

pub use crate::hashing::unsafe_hash_to_point;

/// Exported `Capsule::from_public_key()` for benchmark purposes.
pub fn capsule_from_public_key(delegating_pk: &PublicKey) -> (Capsule, SecretBox<KeySeed>) {
Capsule::from_public_key(&mut OsRng, delegating_pk)
}

/// Exported `Capsule::open_original()` for benchmark purposes.
pub fn capsule_open_original(capsule: &Capsule, delegating_sk: &SecretKey) -> SecretBox<KeySeed> {
capsule.open_original(delegating_sk)
}

/// Exported `Capsule::open_reencrypted()` for benchmark purposes.
pub fn capsule_open_reencrypted(
capsule: &Capsule,
receiving_sk: &SecretKey,
delegating_pk: &PublicKey,
cfrags: &[CapsuleFrag],
) -> Result<SecretBox<KeySeed>, OpenReencryptedError> {
capsule.open_reencrypted(receiving_sk, delegating_pk, cfrags)
}

/// Extracts the internal [`CapsuleFrag`] from a [`VerifiedCapsuleFrag`].
pub fn get_cfrag(verified_cfrag: &VerifiedCapsuleFrag) -> &CapsuleFrag {
&verified_cfrag.cfrag
}
2 changes: 1 addition & 1 deletion umbral-pre/src/capsule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl fmt::Display for Capsule {
}
}

type KeySeed = GenericArray<u8, <CurvePoint as RepresentableAsArray>::Size>;
pub(crate) type KeySeed = GenericArray<u8, <CurvePoint as RepresentableAsArray>::Size>;

impl Capsule {
fn new(point_e: CurvePoint, point_v: CurvePoint, signature: CurveScalar) -> Self {
Expand Down
2 changes: 2 additions & 0 deletions umbral-pre/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@

extern crate alloc;

#[cfg(feature = "bench-internals")]
pub mod bench; // Re-export some internals for benchmarks.

mod capsule;
mod capsule_frag;
mod curve;
Expand Down