# alkvault Local key vault: BIP39 mnemonic generation, SLIP-0010 Ed25519 HD key derivation, and AES-256-GCM encryption for securing provider keys, credentials, and identity material. `alkvault` is a standalone crate with **zero network dependencies**. It holds the master seed — the root of trust for all derived keys and encrypted credentials — and provides the cryptographic primitives and a runtime API for managing it. Nothing important goes in env vars. ## What it is A local key vault built on the principle that **secrets are derived, not stored**. From a single BIP39 mnemonic, the vault deterministically derives Ed25519 identity keys, SSH host keys, and AES-256-GCM encryption keys on demand. External credentials (API keys, OAuth tokens) that can't be derived are encrypted with a seed-derived key and stored as `EncryptedData` blobs. The vault is **local-only by construction** — direct method calls on `VaultServiceHandle`, no actor, no message enum, no wire format, no remote dispatch. The master seed and derived private keys never cross a process boundary. ## Usage ```rust use alkvault::derivation::PATHS; use alkvault::{VaultServiceHandle, KeyType}; // Generate a new mnemonic and unlock the vault. let vault = VaultServiceHandle::new(); let phrase = vault.unlock_new(24)?; // 24-word BIP39 mnemonic // Store `phrase` securely — it is the root of trust. // Derive an Ed25519 identity keypair at m/74'/0'/0'/0'. let identity = vault.derive_ed25519(PATHS::IDENTITY)?; assert_eq!(identity.key_type, KeyType::Ed25519); assert_eq!(identity.private_key.len(), 32); // Encrypt an external credential with a seed-derived AES-256-GCM key. let plaintext = "sk-proj-abc123xyz789"; let encrypted = vault.encrypt(plaintext, 2)?; let decrypted = vault.decrypt(&encrypted)?; assert_eq!(decrypted, plaintext); // Lock the vault — purges the seed and all cached derived keys. vault.lock(); # Ok::<(), Box>(()) ``` ## Features | Feature | Default | Description | |---------|---------|-------------| | `secp256k1` | off | BIP-0032 secp256k1 HD key derivation for Ethereum signing keys (`m/44'/60'/0'/0/0`) | Without `secp256k1`, `derive_ethereum_key` returns `UnsupportedKeyType`. The `secp256k1` crate is a heavy dependency (C library for curve operations); feature-gating it keeps the default build lightweight. ## Derivation paths `alkvault` reserves the `74'` coin type (unallocated per SLIP-0044). | Path | Purpose | Key type | |------|---------|----------| | `m/74'/0'/0'/0'` | Primary identity keypair | Ed25519 | | `m/74'/0'/0'/{n}'` | Worker/device identity | Ed25519 | | `m/74'/0'/1'/0'` | SSH host key | Ed25519 | | `m/74'/2'/0'/0'` | Encryption key (v2) | AES-256-GCM | | `m/74'/2'/0'/{n}'` | Encryption key (v{n+2}) | AES-256-GCM | | `m/44'/60'/0'/0/0` | Ethereum signing key | secp256k1 (feature-gated) | Key rotation re-encrypts `EncryptedData` from one version to another via version-indexed derivation paths — same seed, different keys, no new mnemonic needed. ## Security model - **Seed never persisted.** The BIP39 mnemonic is entered at startup or via `unlock` and held only in `Zeroize`-protected RAM. `lock()` purges the seed and all cached derived keys. - **Zeroize everything sensitive.** `Mnemonic`, `Seed`, `ExtendedPrivKey`, `EncryptionKey`, `DerivedKey`, and `CachedKey` all implement `Zeroize` and `ZeroizeOnDrop`. Secret material does not linger in freed heap memory. - **OsRng for nonces.** AES-GCM IVs use the operating system's CSPRNG (`SysRng`), never a thread-local RNG. IV reuse under the same key is catastrophic for GCM. - **`DerivedKey` redaction.** `DerivedKey` serializes `private_key` as `"[REDACTED]"` in all formats (defense-in-depth for logging accidents) and rejects redacted payloads on deserialization. `Debug` impls also redact. - **Move-only, not `Clone`.** `DerivedKey` and `EncryptionKey` are move-only — no accidental duplication of secret material. - **No `unwrap()` outside tests.** Vault operations propagate errors. A poisoned lock is recovered with `unwrap_or_else(|e| e.into_inner())`, not panicked. ## Crate independence `alkvault` does **not** depend on any application or networking crate. It defines its own types (`VaultServiceError`, `DerivedKey`, `EncryptedData`, etc.) and is usable in contexts where networking doesn't exist — CLI tools, test harnesses, key-derivation utilities, and future WASM targets. ## Documentation Architecture documentation lives under [`docs/architecture/`](docs/architecture/): - [Mnemonic and key derivation](docs/architecture/mnemonic-derivation.md) — BIP39, SLIP-0010, BIP-0032, derivation paths - [Encryption](docs/architecture/encryption.md) — AES-256-GCM, `EncryptedData`, key versioning - [Service](docs/architecture/service.md) — `VaultServiceHandle` lifecycle, cache, error model - [Protocol](docs/architecture/protocol.md) — `DerivedKey` redaction, `KeyType`, serialization - [Architecture decisions (ADRs)](docs/architecture/decisions/) — standalone crate, local-only dispatch, HD derivation, key rotation ## License Licensed under either of - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.