use std::hint::black_box;
use std::net::IpAddr;
use criterion::{criterion_group, criterion_main, Criterion};
use serde_json::{json, Value};
use acdp::crypto::hash::compute_content_hash;
use acdp::crypto::jcs::try_canonicalize_value;
use acdp::crypto::sign::{P256SigningKey, SigningKey};
use acdp::crypto::verify::{verify_ecdsa_p256, verify_ed25519};
use acdp::safe_http::SsrfPolicy;
use acdp::types::ContentHash;
const GOLDEN_HASH: &str = "sha256:f170150ddbf59d99794e7797824591b374d459782084597b644ecc57a41031b5";
fn small_body() -> Value {
json!({
"acdp_version": "0.1.0",
"schema": "acdp.software.release.v1",
"context_type": "software_release",
"producer": "did:web:registry.example.com:agents:release-bot",
"summary": "Release 4.2.1 of the payments service. \
Fixes a race in the ledger reconciliation job, upgrades \
the TLS stack, and adds idempotency keys to the refund \
endpoint. Rollback window is 48 hours from deploy.",
"data": {
"type": "embedded",
"content": {
"version": "4.2.1",
"artifact": "registry.example.com/payments@sha256:9f2c1a7e",
"changes": [
"fix: ledger reconciliation race under concurrent settle",
"chore: bump rustls to 0.23, prune legacy cipher suites",
"feat: idempotency keys on POST /refunds"
],
"rollback": {"supported": true, "window_hours": 48},
"environments": ["staging", "prod-eu", "prod-us"]
}
},
"tags": ["payments", "release", "backend", "rust"],
"visibility": "public",
"version": 1,
"timestamp": "2026-07-01T12:00:00.000Z",
"expires_at": "2027-07-01T12:00:00.000Z",
"metadata": {
"build_id": "b-20260701-1200-4f9a",
"ci_run": "https://ci.example.com/runs/188422",
"commit": "d543c0a1b2c3d4e5f60718293a4b5c6d7e8f9012"
}
})
}
fn nested_object(depth: usize, fanout: usize, leaf_len: usize) -> Value {
if depth == 0 {
return Value::String("v".repeat(leaf_len));
}
let mut map = serde_json::Map::new();
for i in 0..fanout {
map.insert(
format!("k{depth}_{i:03}"),
nested_object(depth - 1, fanout, leaf_len),
);
}
Value::Object(map)
}
fn large_body() -> Value {
let mut body = small_body();
body["metadata"] = nested_object(6, 3, 70);
body
}
fn ssrf_batch() -> Vec<IpAddr> {
[
"127.0.0.1", "10.0.0.1", "172.16.5.5", "192.168.1.1", "169.254.169.254", "100.64.0.1", "8.8.8.8", "93.184.216.34", "::1", "fe80::1", "fc00::1", "::ffff:10.0.0.1", "::ffff:8.8.8.8", "64:ff9b::808:808", "2606:4700:4700::1111", "ff02::1", ]
.iter()
.map(|s| s.parse().expect("static IP literal"))
.collect()
}
fn bench_signing(c: &mut Criterion) {
let mut group = c.benchmark_group("signing");
let hash = ContentHash(GOLDEN_HASH.to_owned());
let ed_key = SigningKey::from_bytes(&[7u8; 32]);
let ed_pub = ed_key.verifying_key_bytes();
let ed_sig = ed_key.sign_content_hash(&hash);
group.bench_function("ed25519_sign", |b| {
b.iter(|| ed_key.sign_content_hash(black_box(&hash)))
});
group.bench_function("ed25519_verify", |b| {
b.iter(|| {
verify_ed25519(
black_box(&ed_pub),
black_box(&ed_sig),
black_box(GOLDEN_HASH),
)
.expect("valid signature")
})
});
let p256_key = P256SigningKey::from_bytes(&[7u8; 32]).expect("valid P-256 seed");
let p256_pub = p256_key.verifying_key_sec1();
let p256_sig = p256_key.sign_content_hash(&hash);
group.bench_function("ecdsa_p256_sign", |b| {
b.iter(|| p256_key.sign_content_hash(black_box(&hash)))
});
group.bench_function("ecdsa_p256_verify", |b| {
b.iter(|| {
verify_ecdsa_p256(
black_box(&p256_pub),
black_box(&p256_sig),
black_box(GOLDEN_HASH),
)
.expect("valid signature")
})
});
group.finish();
}
fn bench_jcs(c: &mut Criterion) {
let mut group = c.benchmark_group("jcs");
let small = small_body();
let large = large_body();
group.bench_function("canonicalize_small_1kb", |b| {
b.iter(|| try_canonicalize_value(black_box(&small)).expect("canonicalizable"))
});
group.bench_function("canonicalize_large_64kb", |b| {
b.iter(|| try_canonicalize_value(black_box(&large)).expect("canonicalizable"))
});
group.finish();
}
fn bench_content_hash(c: &mut Criterion) {
let mut group = c.benchmark_group("content_hash");
let small = small_body();
let large = large_body();
group.bench_function("compute_small_1kb", |b| {
b.iter(|| compute_content_hash(black_box(&small)).expect("hashable"))
});
group.bench_function("compute_large_64kb", |b| {
b.iter(|| compute_content_hash(black_box(&large)).expect("hashable"))
});
group.finish();
}
fn bench_ssrf(c: &mut Criterion) {
let mut group = c.benchmark_group("ssrf");
let policy = SsrfPolicy::default();
let batch = ssrf_batch();
group.bench_function("classify_ip_batch_16", |b| {
b.iter(|| {
let mut rejected = 0usize;
for ip in &batch {
if policy.classify_ip(black_box(*ip)).is_err() {
rejected += 1;
}
}
black_box(rejected)
})
});
group.finish();
}
criterion_group!(
benches,
bench_signing,
bench_jcs,
bench_content_hash,
bench_ssrf
);
criterion_main!(benches);