core/crypto/nip98.rs:
- verify_nip98 (login-grade): binds url+method+freshness
- verify_signed_action (state-change): adds single-use nonce + purpose +
canonical request-descriptor hash + optional target-id/instance-id, each an
exactly-one tag, constant-time compared, all checked on the signature-
authenticated event (id recomputed + schnorr-verified before any tag trusted)
- hardening from adversarial review: length-guard pubkey/id/sig before k256
construction (no panic on short input), saturating freshness window (no
overflow wrap); regressions for all three
core/crypto/signatures.rs: BIP-137 ECDSA + Ed25519 verification returning
Result<(),AppError> (Ok only on valid; malformed->400, mismatch->401) — closes
the Ok(false) fail-open.
Cargo.toml: overflow-checks=true in release (defense-in-depth for auth paths).
- minimal Axum server exposing GET /health
- OpenAPI contract generated from handlers (gen_openapi -> openapi.json),
drift-gated in CI so the spec can never silently diverge from the code
- CI: secret-scan + gitleaks, openapi drift gate, fmt/clippy/build/test/doc-test, cargo-deny
- Cargo.lock tracked for reproducible builds; publish=false; pinned toolchain
- README, SECURITY.md, deny.toml, .env.example