The vault spec-to-implementation sync is complete. Remove the drift tracking tools that were only needed during sync: - Remove the Known Source Drift table from vault/README.md - Remove 'known drift' / 'current source uses X' prose from Security Constraints sections in vault/README.md, encryption.md, and service.md. The permanent constraint statements (OsRng for IVs, zeroized drop, no unwrap, etc.) are preserved. - Remove the drift paragraph in encryption.md Key Versioning. - Remove stale 'to be updated per ADR-025' / 'postcard tests to be removed' notes in protocol.md References. - Bump status: draft -> stable in the frontmatter of all vault docs (README, mnemonic-derivation, encryption, service, protocol). - Update architecture/README.md: vault doc status entries to stable, Current State paragraph reflects vault implementation complete (no 'pending ADR-025/026 refactor' language).
status, last_updated
| status | last_updated |
|---|---|
| stable | 2026-06-23 |
alknet-vault
Local key vault: BIP39 mnemonic generation, SLIP-0010 Ed25519 HD key derivation, BIP-0032 secp256k1 derivation (feature-gated), and AES-256-GCM encryption. Holds the master seed — the root of trust for all derived keys and encrypted credentials in the alknet system.
What This Crate Is
alknet-vault is a standalone crate with zero alknet crate dependencies
(ADR-018) and zero RPC framework dependencies (ADR-025). It provides the
cryptographic primitives and runtime API for managing the root of trust.
The CLI binary (the alknet crate) is the sole component that talks to the
vault directly (ADR-019) — handlers receive derived/decrypted material
through capabilities, never through a vault reference.
The vault is not a network service. It has no ALPN, no
ProtocolHandler implementation, no operations registered in the call
protocol (ADR-008, ADR-014), and no remote dispatch capability (ADR-025).
The vault is local-only by construction — direct method calls on
VaultServiceHandle, no actor, no message enum, no wire format. The master
seed and derived private keys never cross the network.
Documents
| Document | Status | Description |
|---|---|---|
| mnemonic-derivation.md | stable | BIP39, SLIP-0010, BIP-0032, derivation paths, key types |
| encryption.md | stable | AES-256-GCM, EncryptedData, key versioning, HD derivation (ADR-020) |
| service.md | stable | VaultServiceHandle lifecycle, direct dispatch, cache, error model |
| protocol.md | stable | DerivedKey redaction, KeyType, serialization behavior |
Applicable ADRs
| ADR | Title | Relevance |
|---|---|---|
| 003 | Crate Decomposition | alknet-vault's standalone position |
| 008 | Vault Integration Point | CLI-embedded, capability source |
| 010 | ALPN Router and Endpoint | Ed25519 as default curve for TLS raw key identity |
| 014 | Secret Material Flow and Capability Injection | Capabilities carry vault-derived material |
| 018 | Vault as Standalone Crate | Zero alknet crate dependencies |
| 019 | Vault Assembly-Layer-Only Access | The assembly layer is the sole caller |
| 020 | HD Derivation for Encryption Keys | SLIP-0010 derivation, not PBKDF2; salt unused in v2 |
| 021 | Key Rotation via Version-Indexed Paths | Version-indexed paths; rotate re-encrypts |
| 025 | Vault Local-Only Dispatch | Dropped irpc; direct method calls; local-only by construction |
| 026 | Vault Key Model — HD Derivation | HD derivation from BIP39 seed; 74' coin type; AES-256-GCM |
Relevant Open Questions
| OQ | Title | Status | Relevance |
|---|---|---|---|
| OQ-20 | Encryption key derivation | resolved (ADR-020) | HD derivation from seed; salt field unused in v2 |
| OQ-21 | Remote vault access | resolved (ADR-025) | Vault is local-only by construction; remote access requires a separate vault-server crate with its own ADR |
| OQ-22 | Key rotation mechanism | resolved (ADR-021) | Version-indexed paths; rotate method |
Key Design Principles
- Standalone: The vault depends on no alknet crate and no RPC framework. It defines its own types and errors. External crates depend on the vault; the vault depends on nothing in alknet.
- Assembly-layer only: The vault's API is consumed by the CLI binary, not by handlers. Handlers receive material through capabilities (ADR-014). The vault is not on the wire.
- Local-only by construction: The vault has no remote dispatch
capability. Direct method calls on
VaultServiceHandle— no actor, no message enum, no wire format (ADR-025). Remote access, if ever needed, requires a separate crate with its own ADR. - Zeroize everything sensitive: The mnemonic, seed, derived private
keys, encryption keys, and cached keys all implement
ZeroizeandZeroizeOnDrop. Secret material does not linger in freed heap memory. - Deterministic derivation: The same mnemonic + passphrase + path always produces the same key. Derivation is reproducible across runs and across nodes.
- OsRng for nonces: AES-GCM IVs and any cryptographic nonces use
OsRng(or equivalent CSPRNG), neverrand::random(). IV reuse under the same key is catastrophic for GCM. - No
unwrap()orexpect()outside tests: vault operations propagate errors. A poisoned lock is recovered withunwrap_or_else(|e| e.into_inner()), notunwrap(). A panic in one vault operation must not brick the vault for all other operations.
Security Constraints
These are security-critical implementation requirements, not architectural decisions (the architecture is locked by the ADRs above). They are documented here so implementation agents don't miss them. See service.md → Security Constraints for the full list.
- OsRng for IVs: AES-GCM IVs must use
OsRng, notrand::random(). - Zeroized drop:
Seed,Mnemonic,ExtendedPrivKey,Secp256k1ExtendedPrivKey,EncryptionKey,CachedKey, andDerivedKeyall deriveZeroizeandZeroizeOnDrop. The cache must clear on drop, not just on explicitlock(). - No
unwrap()outside tests: poisoned lock recovery usesunwrap_or_else(|e| e.into_inner())or explicit error propagation. - DerivedKey redaction in serialization:
DerivedKeyserializes theprivate_keyas"[REDACTED]"in all formats (ADR-025 dropped the postcard/remote path that previously preserved bytes in binary formats). Deserialization rejects"[REDACTED]"with an error (resolves review #002 W8). The redaction is a defense-in-depth measure for logging safety, not the primary control — the primary control is thatDerivedKeynever crosses the call protocol wire (ADR-014).
Public API
The vault re-exports its primary types from the crate root:
// Mnemonic and seed
pub use mnemonic::{Language, Mnemonic, Seed};
// Derivation
pub use derivation::{DerivationError, ExtendedPrivKey, PATHS};
// Derivation helpers (derive_path_from_seed, parse_derivation_path,
// device_path, encryption_path_for_version) are accessible as
// alknet_vault::derivation::* — not re-exported at crate root to avoid
// clutter, but fully public.
// Encryption
pub use encryption::{EncryptedData, EncryptionError, EncryptionKey};
pub use encryption::CURRENT_KEY_VERSION;
// Key types (DerivedKey, KeyType)
pub use protocol::{DerivedKey, KeyType};
// Service (runtime)
pub use service::{VaultServiceError, VaultServiceHandle};
// Cache
pub use cache::CacheConfig;
The secp256k1 feature flag gates Ethereum (BIP-0032) derivation:
#[cfg(feature = "secp256k1")]
pub mod ethereum;