Skip to content

perf(kdf): benchmark and calibrate default parameters - #23

Merged
ericliswan merged 3 commits into
mainfrom
perf/kdf-calibration
Oct 27, 2026
Merged

ericliswan merged 3 commits into
mainfrom
perf/kdf-calibration

Conversation

@ericliswan

Copy link
Copy Markdown
Owner

Summary

Adds cargo run --release --example kdf_bench, runs it on the owner's Apple M1, and raises the production Argon2id default from 64 MiB to 256 MiB (t=3, p=4). That takes unlock from ~0.14 s to ~0.6 s, inside the 0.5–1 s target. ADR 0002 records the reasoning, including why argon2's parallel feature stays off.

Closes #22

Type of change

  • feat - [ ] fix - [x] docs - [ ] test - [ ] refactor - [x] ci/chore - [ ] security

perf: KDF calibration.

How was this tested?

  • cargo run --release --example kdf_bench three times on the M1. DESIGN.md quotes the final run, made with the committed code.
  • cargo fmt --check, cargo clippy -D warnings (with and without --all-features), cargo test --workspace in both modes, cargo deny check.
  • production_default_meets_production_floor still passes in the featureless run. No test runs Argon2 with the production default (the crypto tests use a fixed key, and the storage and integration tests are gated on insecure-test-kdf), so CI time is unchanged.

Security checklist

  • No secret in args, env vars, logs, Debug output, errors or panics (the benchmark password is a fixed, non-secret literal)
  • Crypto is called only from pwv-core::kdf / pwv-core::crypto (the example calls kdf::derive_key)
  • Any new header/file-format field is inside the AAD and validated on load (no format change)
  • Failure paths have tests (unchanged; out-of-range params are already covered)
  • Docs (README / DESIGN / THREAT_MODEL) updated if behaviour changed

Notes for the reviewer

  • AGENTS.md §12 requires a 🛑 checkpoint and an ADR for KDF-parameter changes. The owner chose 256 MiB / t=3 / p=4, single-threaded, from the benchmark table during this session; ADR 0002 is the record.
  • This is not a format change. Parameters live in each vault's header, so vaults made with 64 MiB still open. No vaults exist in the wild yet anyway.
  • RFC 9106's first option (2 GiB, t=1) is rejected by our floor's t ≥ 2, which is why the benchmark doesn't list it.

Times derive_key for the floor, the current default and larger
profiles so the production default can be chosen from measurements
on real hardware rather than assumed.

Refs #22
RFC 9106's second option (64 MiB, t=3, p=4) unlocks in ~0.14 s on an
Apple M1, well under the 0.5-1 s target. 256 MiB with the same passes
and lanes takes ~0.6 s and makes each offline guess cost four times
the memory. Existing vaults keep the parameters in their header.

Refs #22
Adds the M1 timings to DESIGN.md and ADR 0002 explaining the 256 MiB
default and why argon2's parallel feature stays off. Updates the
default in the threat model and AGENTS.md to match.

Refs #22
@ericliswan

Copy link
Copy Markdown
Owner Author

Self-review: I read the full gh pr diff.

  • Benchmark: it only calls pwv_core::kdf::derive_key with a fixed, non-secret password and a zero salt. It warns on debug builds, and black_box keeps the derivation from being optimised away. It returns Result, so there's no unwrap. A below-floor profile fails with ParamsOutOfRange instead of being timed, which is how the RFC 9106 2 GiB / t=1 row was caught and dropped.
  • Constant change: only KdfParams::PRODUCTION changes. The floor, ceiling and test profile are untouched. No test derives with the production default, so CI time stays the same; this run was 35 s to 1 min per OS. production_default_meets_production_floor still guards the featureless build.
  • Docs: the DESIGN.md table quotes only the final benchmark run, which used the committed code. The THREAT_MODEL and AGENTS.md defaults match. ADR 0002 links to DESIGN.md#calibration.
  • Minor: ADR 0002 says four lanes cost "the same time" as one, while DESIGN.md says "about as long as"; the measurements support the latter. I left it to avoid a wording-only commit. It can be fixed in PR perf(kdf): benchmark and calibrate default parameters #23's README/threat-model pass.
  • 🛑 §12 checkpoint: the owner picked 256 MiB / t=3 / p=4, single-threaded, from the benchmark table in this session.

@ericliswan
ericliswan merged commit 3c5e7d8 into main Oct 27, 2026
4 checks passed
@ericliswan
ericliswan deleted the perf/kdf-calibration branch October 27, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(kdf): benchmark and calibrate default parameters

1 participant