Skip to content

Commit

Permalink
refactor: move benches to criterion and expand benchmarks
Browse files Browse the repository at this point in the history
* bench: switch to criterion

* update message benchmarks

* cleanup

* perf: avoid allocations in s2k iterated

* expand encryption and decryption benchmarks

* fixup

* happy clippy

* ci: update bench check

* fixup
  • Loading branch information
dignifiedquire committed Mar 24, 2024
1 parent f42e7c3 commit 8e87774
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 267 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
push:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
RUST_BACKTRACE: 1
Expand Down Expand Up @@ -58,7 +61,6 @@ jobs:

- name: check bench
uses: actions-rs/cargo@v1
if: ${{ matrix.rust == env.RUST_NIGHTLY }}
with:
command: check
args: --benches
Expand Down
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ rand_xorshift = "0.3"
regex = "^1.7"
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
criterion = { version = "0.4", features = ["html_reports"] }

[features]
default = []
Expand All @@ -118,3 +119,10 @@ wasm = ["chrono/wasmbind", "getrandom", "getrandom/js"]

[profile.bench]
debug = true

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

[lib]
bench = false
5 changes: 5 additions & 0 deletions benches/benches_main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use criterion::criterion_main;

mod benchmarks;

criterion_main!(benchmarks::key::benches, benchmarks::message::benches,);
81 changes: 81 additions & 0 deletions benches/benchmarks/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use std::fs::File;
use std::io::Cursor;

use criterion::{black_box, criterion_group, Criterion};
use pgp::composed::{Deserializable, KeyType, SignedSecretKey};
use pgp::ser::Serialize;

use super::build_key;

fn bench_key(c: &mut Criterion) {
let mut g = c.benchmark_group("secret_key");

g.bench_function("rsa_parse", |b| {
let p = "./tests/opengpg-interop/testcases/messages/gnupg-v1-001-decrypt.asc";
b.iter(|| {
let mut decrypt_key_file = File::open(p).unwrap();
black_box(SignedSecretKey::from_armor_single(&mut decrypt_key_file).unwrap())
});
});

g.bench_function("rsa_parse_raw", |b| {
let key = build_key(KeyType::Rsa(2048), KeyType::Rsa(2048))
.sign(|| "".into())
.unwrap();
let bytes = key.to_bytes().unwrap();

b.iter(|| black_box(SignedSecretKey::from_bytes(Cursor::new(&bytes)).unwrap()))
});

g.bench_function("parse_armored_rsa", |b| {
let key = build_key(KeyType::Rsa(2048), KeyType::Rsa(2048))
.sign(|| "".into())
.unwrap();
let bytes = key.to_armored_bytes(None).unwrap();

b.iter(|| black_box(SignedSecretKey::from_armor_single(Cursor::new(&bytes)).unwrap()));
});

g.bench_function("x25519_parse_armored", |b| {
let key = build_key(KeyType::EdDSA, KeyType::ECDH)
.sign(|| "".into())
.unwrap();
let bytes = key.to_armored_bytes(None).unwrap();

b.iter(|| black_box(SignedSecretKey::from_armor_single(Cursor::new(&bytes)).unwrap()));
});

g.bench_function("x25519_generate", |b| {
b.iter(|| black_box(build_key(KeyType::EdDSA, KeyType::ECDH)))
});

g.bench_function("x25519_self_sign", |b| {
let key = build_key(KeyType::EdDSA, KeyType::ECDH);

b.iter(|| black_box(key.clone().sign(|| "".into()).unwrap()))
});

g.bench_function("rsa_2048_self_sign", |b| {
let key = build_key(KeyType::Rsa(2048), KeyType::Rsa(2048));

b.iter(|| black_box(key.clone().sign(|| "".into()).unwrap()))
});

g.finish();
}

#[cfg(feature = "profile")]
fn profiled() -> Criterion {
Criterion::default().with_profiler(super::profiler::GProfiler)
}

#[cfg(not(feature = "profile"))]
fn profiled() -> Criterion {
Criterion::default()
}

criterion_group!(
name = benches;
config = profiled();
targets = bench_key
);
202 changes: 202 additions & 0 deletions benches/benchmarks/message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
use std::fs::{self, File};
use std::io::Cursor;
use std::io::Read;

use criterion::{black_box, criterion_group, BenchmarkId, Criterion, Throughput};

use pgp::composed::{Deserializable, Message, SignedSecretKey};
use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::types::{SecretKeyTrait, StringToKey};
use pgp::KeyType;
use rand::RngCore;

use super::build_key;

fn bench_message(c: &mut Criterion) {
let mut g = c.benchmark_group("message");

g.bench_function("parse_armored_rsa", |b| {
let message_file_path = "./tests/opengpg-interop/testcases/messages/gnupg-v1-001.asc";
let mut message_file = File::open(message_file_path).unwrap();
let mut bytes = Vec::new();
message_file.read_to_end(&mut bytes).unwrap();

b.iter(|| {
let c = Cursor::new(bytes.clone());
black_box(Message::from_armor_single(c).unwrap())
});
});

g.bench_function("parse_armored_x25519", |b| {
let message_file_path = "./tests/openpgpjs/x25519.asc";
let mut message_file = File::open(message_file_path).unwrap();
let mut bytes = Vec::new();
message_file.read_to_end(&mut bytes).unwrap();

b.iter(|| {
let c = Cursor::new(bytes.clone());
black_box(Message::from_armor_single(c).unwrap())
});
});

g.bench_function("rsa_decrypt", |b| {
let mut decrypt_key_file =
File::open("./tests/opengpg-interop/testcases/messages/gnupg-v1-001-decrypt.asc")
.unwrap();
let (decrypt_key, _headers) =
SignedSecretKey::from_armor_single(&mut decrypt_key_file).unwrap();
let message_file_path = "./tests/opengpg-interop/testcases/messages/gnupg-v1-001.asc";
let message_file = fs::read(message_file_path).unwrap();

b.iter(|| {
let (message, _headers) =
Message::from_armor_single(Cursor::new(message_file.clone())).unwrap();

black_box(
message
.decrypt(|| "test".to_string(), &[&decrypt_key][..])
.unwrap(),
);
});
});

const KB: usize = 1000;
let sizes = [KB, 10 * KB, 100 * KB, 1000 * KB];

for size in &sizes {
g.throughput(Throughput::BytesDecimal(*size as u64));
g.bench_with_input(
BenchmarkId::new("encrypt_password_s2k_iter_aes128", size),
size,
|b, &size| {
let mut bytes = vec![0u8; size];
let mut rng = rand::thread_rng();
rng.fill_bytes(&mut bytes);

let s2k = StringToKey::new_default(&mut rng);
let message = Message::new_literal_bytes("test", &bytes);

b.iter(|| {
let res = message
.encrypt_with_password(
&mut rng,
s2k.clone(),
SymmetricKeyAlgorithm::default(),
|| "pw".into(),
)
.unwrap();

black_box(res);
});
},
);
}

for size in &sizes {
g.throughput(Throughput::BytesDecimal(*size as u64));
g.bench_with_input(
BenchmarkId::new("decrypt_password_s2k_iter_aes128", size),
size,
|b, &size| {
let mut bytes = vec![0u8; size];
let mut rng = rand::thread_rng();
rng.fill_bytes(&mut bytes);

let s2k = StringToKey::new_default(&mut rng);
let message = Message::new_literal_bytes("test", &bytes)
.encrypt_with_password(&mut rng, s2k, SymmetricKeyAlgorithm::default(), || {
"pw".into()
})
.unwrap();

// sanity check
let res = message.decrypt_with_password(|| "pw".into()).unwrap();
assert_eq!(res.get_content().unwrap().unwrap(), bytes);

b.iter(|| {
let res = message.decrypt_with_password(|| "pw".into()).unwrap();
black_box(res);
});
},
);
}

for size in &sizes {
g.throughput(Throughput::BytesDecimal(*size as u64));
g.bench_with_input(
BenchmarkId::new("x25519_encrypt_key_aes128", size),
size,
|b, &size| {
let mut bytes = vec![0u8; size];
let mut rng = rand::thread_rng();
rng.fill_bytes(&mut bytes);

let key = build_key(KeyType::EdDSA, KeyType::ECDH);
let signed_key = key.sign(|| "".into()).unwrap();

let message = Message::new_literal_bytes("test", &bytes);

b.iter(|| {
let res = message
.encrypt_to_keys(
&mut rng,
SymmetricKeyAlgorithm::AES128,
&[&signed_key.secret_subkeys[0].public_key()],
)
.unwrap();

black_box(res);
});
},
);
}

for size in &sizes {
g.throughput(Throughput::BytesDecimal(*size as u64));
g.bench_with_input(
BenchmarkId::new("x25519_decrypt_key_aes128", size),
size,
|b, &size| {
let mut bytes = vec![0u8; size];
let mut rng = rand::thread_rng();
rng.fill_bytes(&mut bytes);

let key = build_key(KeyType::EdDSA, KeyType::ECDH);
let signed_key = key.sign(|| "".into()).unwrap();

let message = Message::new_literal_bytes("test", &bytes)
.encrypt_to_keys(
&mut rng,
SymmetricKeyAlgorithm::AES128,
&[&signed_key.secret_subkeys[0].public_key()],
)
.unwrap();

// sanity check
let (res, _) = message.decrypt(|| "".into(), &[&signed_key]).unwrap();
assert_eq!(res.get_content().unwrap().unwrap(), bytes);

b.iter(|| {
let res = message.decrypt(|| "".into(), &[&signed_key]).unwrap();
black_box(res);
});
},
);
}
}

#[cfg(feature = "profile")]
fn profiled() -> Criterion {
Criterion::default().with_profiler(super::profiler::GProfiler)
}

#[cfg(not(feature = "profile"))]
fn profiled() -> Criterion {
Criterion::default()
}

criterion_group!(
name = benches;
config = profiled();
targets = bench_message
);
Loading

0 comments on commit 8e87774

Please sign in to comment.