mod support;
use support::{Fixture, Spec, specs};
#[cfg(feature = "benchmark-alloc")]
#[global_allocator]
static ALLOCATOR: divan::AllocProfiler = divan::AllocProfiler::system();
fn main() {
divan::main();
}
macro_rules! operation {
($name:ident) => {
#[divan::bench(args = specs())]
fn $name(bencher: divan::Bencher, spec: Spec) {
debug_assert!(support::OPERATIONS.contains(&stringify!($name)));
let fixture = Fixture::new(spec);
bencher
.counter(divan::counter::BytesCount::new(
fixture.input_bytes(stringify!($name)),
))
.bench_local(|| fixture.run(stringify!($name)));
}
};
}
operation!(parse);
operation!(c14n);
operation!(sign);
operation!(verify);
operation!(verify_retained);
operation!(verify_reject);
operation!(encrypt);
operation!(decrypt);
fn large_reference(units: usize) -> Fixture {
reference_fixture(support::BULK, units)
}
fn reference_fixture(shape: usize, units: usize) -> Fixture {
Fixture::new(Spec {
shape,
units,
backend: xml_sec::XmlBackend::default(),
engine: support::Engine::RustCrypto,
})
}
#[divan::bench]
fn attribute_reference_verify(bencher: divan::Bencher) {
let shape = support::SHAPES
.iter()
.position(|shape| *shape == "attributes")
.expect("attributes shape");
let fixture = reference_fixture(shape, 2_048);
bencher
.counter(divan::counter::BytesCount::new(
fixture.input_bytes("verify_retained"),
))
.bench_local(|| fixture.run("verify_retained"));
}
#[divan::bench(args = [256, 4_096])]
fn large_reference_verify(bencher: divan::Bencher, units: usize) {
let fixture = large_reference(units);
bencher
.counter(divan::counter::BytesCount::new(
fixture.input_bytes("verify_retained"),
))
.bench_local(|| fixture.run("verify_retained"));
}
#[divan::bench(args = [256, 4_096])]
fn large_reference_sign(bencher: divan::Bencher, units: usize) {
let fixture = large_reference(units);
bencher
.counter(divan::counter::BytesCount::new(fixture.input_bytes("sign")))
.bench_local(|| fixture.run("sign"));
}
#[divan::bench(args = specs().filter(|spec| spec.backend != xml_sec::XmlBackend::Differential))]
fn projection(bencher: divan::Bencher, spec: Spec) {
let fixture = Fixture::new(spec);
let projection = xml_sec::benchmark_support::Projection::new(&fixture.unsigned, spec.backend)
.expect("prepared backend");
bencher
.counter(divan::counter::BytesCount::new(fixture.unsigned.len()))
.bench_local(|| {
std::hint::black_box(projection.project().expect("project"));
});
}
fn node_set_document(elements: usize) -> String {
let body = (0..elements)
.map(|index| format!("<p:e id='e{index}' a:k='{index}'>text {index}</p:e>"))
.collect::<String>();
format!("<p:root xmlns:p='urn:p' xmlns:a='urn:a'>{body}<p:Signature/></p:root>")
}
#[divan::bench(args = [1_024, 16_384])]
fn node_set_enveloped(bencher: divan::Bencher, elements: usize) {
let xml = node_set_document(elements);
let sets = xml_sec::benchmark_support::NodeSets::new(&xml).expect("node-set document");
bencher.bench_local(|| std::hint::black_box(sets.enveloped()));
}
const NODE_SET_STRIDES: [usize; 7] = [2, 8, 32, 128, 512, 2_048, 8_192];
#[divan::bench(args = NODE_SET_STRIDES)]
fn node_set_sparse(bencher: divan::Bencher, stride: usize) {
let xml = node_set_document(16_384);
let sets = xml_sec::benchmark_support::NodeSets::new(&xml).expect("node-set document");
bencher.bench_local(|| std::hint::black_box(sets.selection(stride, false)));
}
#[divan::bench(args = NODE_SET_STRIDES)]
fn node_set_dense(bencher: divan::Bencher, stride: usize) {
let xml = node_set_document(16_384);
let sets = xml_sec::benchmark_support::NodeSets::new(&xml).expect("node-set document");
bencher.bench_local(|| std::hint::black_box(sets.selection(stride, true)));
}
#[divan::bench(args = [1, 8, 32, 64])]
fn plan_compile(bencher: divan::Bencher, references: usize) {
bencher
.with_inputs(|| xml_sec::benchmark_support::Plan::new(references))
.bench_values(|mut plan| {
plan.compile();
plan
});
}
#[divan::bench(args = [1, 8, 32, 64])]
fn plan_execute(bencher: divan::Bencher, references: usize) {
bencher
.with_inputs(|| {
let mut plan = xml_sec::benchmark_support::Plan::new(references);
plan.compile();
plan
})
.bench_values(|plan| plan.execute());
}
#[divan::bench(args = [1, 8, 32, 64])]
fn policy_validate(bencher: divan::Bencher, algorithms: usize) {
use xml_sec::xmldsig::SignatureAlgorithm;
let policy = xml_sec::policy::VerificationPolicy {
signature_algorithms: Some([SignatureAlgorithm::RsaSha256].into_iter().collect()),
..Default::default()
};
bencher.bench(|| {
for _ in 0..algorithms {
let policy = std::hint::black_box(&policy);
policy.validate().expect("policy");
policy
.check_signature_algorithm(SignatureAlgorithm::RsaSha256)
.expect("permitted");
}
});
}
#[divan::bench(args = xml_sec::XmlBackend::available())]
fn reject_xml(bencher: divan::Bencher, backend: xml_sec::XmlBackend) {
bencher.bench_local(|| {
for input in ["<root><unclosed></root>", "<p:root/>", "<root/><extra/>"] {
assert!(xml_sec::XmlDocument::parse_with_backend(input, backend).is_err());
}
});
}