feat: Phase 9 — developer experience, extensibility, and community growth
New crates: - quicproquo-bot: Bot SDK with polling API + JSON pipe mode - quicproquo-kt: Key Transparency Merkle log (RFC 9162 subset) - quicproquo-plugin-api: no_std C-compatible plugin vtable API - quicproquo-gen: scaffolding tool (qpq-gen plugin/bot/rpc/hook) Server features: - ServerHooks trait wired into all RPC handlers (enqueue, fetch, auth, channel, registration) with plugin rejection support - Dynamic plugin loader (libloading) with --plugin-dir config - Delivery proof canary tokens (Ed25519 server signatures on enqueue) - Key Transparency Merkle log with inclusion proofs on resolveUser Core library: - Safety numbers (60-digit HMAC-SHA256 key verification codes) - Verifiable transcript archive (CBOR + ChaCha20-Poly1305 + hash chain) - Delivery proof verification utility - Criterion benchmarks (hybrid KEM, MLS, identity, sealed sender, padding) Client: - /verify REPL command for out-of-band key verification - Full-screen TUI via Ratatui (feature-gated --features tui) - qpq export / qpq export-verify CLI subcommands - KT inclusion proof verification on user resolution Also: ROADMAP Phase 9 added, bot SDK docs, server hooks docs, crate-responsibilities updated, example plugins (rate_limit, logging).
This commit is contained in:
139
crates/quicproquo-core/benches/crypto_benchmarks.rs
Normal file
139
crates/quicproquo-core/benches/crypto_benchmarks.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
//! Benchmark: Identity keypair operations, sealed sender, and message padding.
|
||||
//!
|
||||
//! Covers:
|
||||
//! - [`IdentityKeypair`] generation, signing, and signature verification
|
||||
//! - Sealed sender `seal` / `unseal` (Ed25519 sign + verify overhead)
|
||||
//! - Message padding `pad` / `unpad` at various payload sizes
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
|
||||
use quicproquo_core::{IdentityKeypair, padding};
|
||||
|
||||
// ── Identity keypair benchmarks ──────────────────────────────────────────────
|
||||
|
||||
fn bench_identity_keygen(c: &mut Criterion) {
|
||||
c.bench_function("identity_keygen", |b| {
|
||||
b.iter(|| black_box(IdentityKeypair::generate()));
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_identity_sign(c: &mut Criterion) {
|
||||
let identity = IdentityKeypair::generate();
|
||||
let payload = b"benchmark signing payload -- 32+ bytes of realistic data here";
|
||||
|
||||
c.bench_function("identity_sign", |b| {
|
||||
b.iter(|| black_box(identity.sign_raw(black_box(payload))));
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_identity_verify(c: &mut Criterion) {
|
||||
let identity = IdentityKeypair::generate();
|
||||
let payload = b"benchmark signing payload -- 32+ bytes of realistic data here";
|
||||
let sig = identity.sign_raw(payload);
|
||||
let pk = identity.public_key_bytes();
|
||||
|
||||
c.bench_function("identity_verify", |b| {
|
||||
b.iter(|| {
|
||||
black_box(
|
||||
IdentityKeypair::verify_raw(
|
||||
black_box(&pk),
|
||||
black_box(payload),
|
||||
black_box(&sig),
|
||||
)
|
||||
.unwrap()
|
||||
)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ── Sealed sender benchmarks ─────────────────────────────────────────────────
|
||||
|
||||
fn bench_sealed_sender(c: &mut Criterion) {
|
||||
use quicproquo_core::sealed_sender::{seal, unseal};
|
||||
|
||||
let sizes: &[(&str, usize)] = &[
|
||||
("32B", 32),
|
||||
("256B", 256),
|
||||
("1KB", 1024),
|
||||
("4KB", 4096),
|
||||
];
|
||||
|
||||
let identity = IdentityKeypair::generate();
|
||||
|
||||
let mut group = c.benchmark_group("sealed_sender_seal");
|
||||
for (label, size) in sizes {
|
||||
let payload = vec![0xABu8; *size];
|
||||
group.bench_with_input(
|
||||
BenchmarkId::from_parameter(label),
|
||||
&payload,
|
||||
|b, payload| {
|
||||
b.iter(|| black_box(seal(black_box(&identity), black_box(payload))));
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("sealed_sender_unseal");
|
||||
for (label, size) in sizes {
|
||||
let payload = vec![0xABu8; *size];
|
||||
let sealed = seal(&identity, &payload);
|
||||
group.bench_with_input(
|
||||
BenchmarkId::from_parameter(label),
|
||||
&sealed,
|
||||
|b, sealed| {
|
||||
b.iter(|| black_box(unseal(black_box(sealed)).unwrap()));
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
// ── Message padding benchmarks ────────────────────────────────────────────────
|
||||
|
||||
fn bench_padding(c: &mut Criterion) {
|
||||
// Representative sizes: one per bucket + oversized
|
||||
let sizes: &[(&str, usize)] = &[
|
||||
("50B", 50), // → 256 bucket
|
||||
("512B", 512), // → 1024 bucket
|
||||
("2KB", 2048), // → 4096 bucket
|
||||
("8KB", 8192), // → 16384 bucket
|
||||
("20KB", 20480), // → 32768 (oversized)
|
||||
];
|
||||
|
||||
let mut group = c.benchmark_group("padding_pad");
|
||||
for (label, size) in sizes {
|
||||
let payload = vec![0xABu8; *size];
|
||||
group.bench_with_input(
|
||||
BenchmarkId::from_parameter(label),
|
||||
&payload,
|
||||
|b, payload| {
|
||||
b.iter(|| black_box(padding::pad(black_box(payload))));
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("padding_unpad");
|
||||
for (label, size) in sizes {
|
||||
let payload = vec![0xABu8; *size];
|
||||
let padded = padding::pad(&payload);
|
||||
group.bench_with_input(
|
||||
BenchmarkId::from_parameter(label),
|
||||
&padded,
|
||||
|b, padded| {
|
||||
b.iter(|| black_box(padding::unpad(black_box(padded)).unwrap()));
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
bench_identity_keygen,
|
||||
bench_identity_sign,
|
||||
bench_identity_verify,
|
||||
bench_sealed_sender,
|
||||
bench_padding,
|
||||
);
|
||||
criterion_main!(benches);
|
||||
Reference in New Issue
Block a user