# v0.2.0 — Foundation Types, KeyHandle, TEE Detection

**Release date:** 2026-05-20
**Phase:** 0.2.0 — Foundation types + KeyHandle + TEE detection
**Status:** development (pre-1.0; public API subject to change without notice)

---

## What is `key-vault`?

`key-vault` is an enterprise-grade in-memory key management vault for Rust.
It implements **9 layers of defense-in-depth** plus a bonus 10th to keep
cryptographic key material hard to extract from a running process:

1. Secure Acquisition (`KeyFetch`)
2. Memory Page Locking (mlock / VirtualLock)
3. Fragmentation (variable chunks, shuffled, non-contiguous)
4. Decoy Bytes (self-referential filler)
5. Codex Transformation (involution-based byte swap)
6. Constant-Time Operations (`subtle::ConstantTimeEq`)
7. Zero-On-Drop (`zeroize`)
8. Security Monitor (failure detection + threshold lockout)
9. Audit Logging
10. (Bonus) Page Protection Toggling

See [`docs/SECURITY.md`](../SECURITY.md) for the full architecture and
[`docs/TRANSFORMATION.md`](../TRANSFORMATION.md) for a step-by-step visual
walkthrough.

This release establishes the public type system — Layers 1, 3, 4, 5, 8 are
defined as traits; Layer 5 ships its first real implementation
(`IdentityCodex`). Real storage (mlock + fragmentation + zeroize) lands in
Phase 0.3.

---

## What's in 0.2.0

### Core types

- **`Error`** — redaction-clean error enum with 10 variants covering every
  failure mode the vault surfaces. Marked `#[non_exhaustive]` so future
  variants are additive. No variant ever carries key bytes.
- **`Result<T>`** — `core::result::Result<T, Error>` shorthand.
- **`KeyHandle`** / **`KeyId`** — opaque reference types. Both implement
  `Debug` as `KeyHandle(<redacted>)` / `KeyId(<redacted>)`; no path through
  the public API exposes the underlying numeric id or the key bytes.
- **`KeyMetadata`** + **`AlgorithmHint`** — non-secret per-key information
  (registration time, raw key length, optional algorithm hint).
- **`RawKey`** + **`FetchContext`** — value types for the acquisition path.
  `RawKey` redacts its bytes in `Debug` and only exposes length to public
  callers; the byte view is `pub(crate)` for the fragmentation pipeline.

### Pluggable trait surface

- **`KeyFetch`** (Layer 1) — pluggable acquisition source. Required
  contract: no retries, no caching, sanitized errors, `Send + Sync`.
- **`FragmentStrategy`** (Layer 3) — splits and reassembles a `RawKey`.
  Required contract: round-trip equality, variable layout per call.
- **`DecoyStrategy`** (Layer 4) — generates filler bytes. Required
  contract: no accidental key recovery; per-vault seeded.
- **`Codex`** (Layer 5) — byte-wise involution. Required contract:
  `decode(encode(x)) == x` for every byte.
- **`SecurityMonitor`** (Layer 8) — anomaly event sink. Required contract:
  non-blocking, panic-free, no key material in calls.

### Layer 5 — Codex implementations

- **`IdentityCodex`** — no-op default. Trivially satisfies the involution
  property and costs zero at runtime.
- **`FnCodex<F>`** — wraps a user-provided closure. Documented as an
  involution-only escape hatch.

### Vault skeleton

- **`KeyVault`** — `Arc`-backed, `Clone`-able, `Send + Sync`. Today it holds
  configuration and an atomic lock-out flag (driven by the monitor in 0.8).
- **`KeyVaultBuilder`** — fluent builder. Today: only the BLAKE3
  normalization toggle. Key registration and access methods arrive in 0.3.
- **`VaultConfig`** — `#[non_exhaustive]` configuration struct.

### TEE detection (`tee::detect_tee_capabilities`)

`detect_tee_capabilities()` returns a `TeeCapabilities` snapshot covering
seven TEE families. Each capability reports one of three values: `Detected`,
`NotDetected`, or `Unknown` (distinct from `NotDetected` — `Unknown` means
"this platform can't be probed from userspace").

| Capability      | x86_64 host        | aarch64 / macOS    | Other           |
|-----------------|--------------------|--------------------|-----------------|
| Intel SGX       | CPUID.07H EBX[2]   | `Unknown`          | `Unknown`       |
| Intel TDX       | CPUID.21H signature| `Unknown`          | `Unknown`       |
| AMD SEV         | CPUID 0x8000001F EAX[1] | `Unknown`     | `Unknown`       |
| AMD SEV-SNP     | CPUID 0x8000001F EAX[4] | `Unknown`     | `Unknown`       |
| ARM TrustZone   | `Unknown`          | `Unknown` (1.0)    | `Unknown`       |
| Apple SE        | `Unknown`          | `Detected` on Apple Silicon, `NotDetected` on Intel macOS | `Unknown` |
| AWS Nitro       | Linux DMI vendor   | DMI vendor on Linux| `Unknown`       |

x86_64 detection uses the safe `core::arch::x86_64::__cpuid_count`
intrinsic. AWS Nitro inference reads `/sys/devices/virtual/dmi/id/sys_vendor`
on Linux only. No probe opens privileged files, loads drivers, or makes
network calls.

### Test surface

- 27 unit tests (handle opacity, error display, codex involution, vault
  builder, TEE structure)
- 4 integration tests (`tests/smoke.rs`, `tests/tee_detection.rs`)
- 5 doctests (codex, vault, handle, TEE)
- All run on `cargo test --all-features`

---

## Breaking changes

This is a pre-1.0 release; the public API is not yet stable. That said, the
0.2.0 cut is purely additive on top of the 0.1.0 scaffold:

- 0.1.0 exposed exactly one item — `key_vault::VERSION`. That item is
  preserved unchanged.
- Everything new in 0.2.0 lives behind names that did not exist in 0.1.0.

One **build-environment** change is worth calling out:

- **MSRV raised from 1.75 → 1.85.** The previous `Cargo.toml` declared
  `edition = "2024"` together with `rust-version = "1.75"`. Edition 2024
  stabilized in Rust 1.85; Cargo ≥1.84 refuses to parse the previous
  combination. The MSRV bump resolves the conflict and aligns CI with the
  declared edition. CI matrix entry `1.75.0` → `1.85.0` updated to match.

---

## Verification

Verified locally before tagging:

```text
cargo fmt --all -- --check        clean
cargo clippy --all-targets --all-features -- -D warnings     clean
cargo test --all-features         27 + 4 + 5 = 36 tests; all pass
RUSTDOCFLAGS=-D warnings cargo doc --no-deps --all-features   clean
```

No `unsafe` blocks in this release — `__cpuid_count` is a safe intrinsic on
modern Rust, so the CPUID wrapper is plain safe code.

`clippy.toml` gained a `doc-valid-idents` whitelist (`x86_64`, `TrustZone`,
`IntelTDX`, `ChaCha20`, `VirtualLock`, …) so the `doc_markdown` lint
catches genuine missed backticks instead of every domain term.

---

## Installation

```toml
[dependencies]
key-vault = "0.2"
```

Default features (`std`, `mlock`, `zeroize`, `fragment-standard`,
`decoy-self-ref`) match 0.1.0. The full feature graph is documented in
`Cargo.toml`.

Minimum supported Rust version: **1.85** (edition 2024).

---

## Documentation

- [`README.md`](../../README.md) — overview, badges, threat model
- [`docs/SECURITY.md`](../SECURITY.md) — 9-layer architecture
- [`docs/TRANSFORMATION.md`](../TRANSFORMATION.md) — visual walkthrough
- [`CHANGELOG.md`](../../CHANGELOG.md) — full change log

---

## Diff

Full diff: [`v0.1.0...v0.2.0`](https://github.com/jamesgober/key-vault/compare/v0.1.0...v0.2.0)

---

<sub>key-vault v0.2.0 — Copyright (c) 2026 James Gober. Apache-2.0 OR MIT.</sub>
