The vault uses SLIP-0010 HD derivation from the BIP39 seed for the AES-256-GCM encryption key, not PBKDF2. This replaces the TypeScript predecessor's (@alkdev/storage/src/graphs/crypto.ts) PBKDF2-based approach. Key decisions: - HD derivation at m/74'/2'/0'/0' produces the encryption key - PBKDF2 is not implemented in the vault; no password-based derivation - salt field is unused in v2 (wire-format compat only) - key_version=1 reserved for TS PBKDF2 data; key_version=2 for vault HD - TS-encrypted data requires one-time migration to v2 - CURRENT_KEY_VERSION changes from 1 to 2 (source drift flagged) OQ-20 resolved: the encryption key derivation method is locked. OQ-22 (key rotation workflow) remains open but does not block implementation.
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-06-19 |
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). 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, and no operations registered in the call
protocol (ADR-008, ADR-014). The master seed and derived private keys never
cross the network.
Documents
| Document | Status | Description |
|---|---|---|
| mnemonic-derivation.md | draft | BIP39, SLIP-0010, BIP-0032, derivation paths, key types |
| encryption.md | draft | AES-256-GCM, EncryptedData, key versioning, HD derivation (ADR-020) |
| service.md | draft | VaultServiceHandle lifecycle, actor dispatch, cache, error model |
| protocol.md | draft | VaultProtocol irpc messages, DerivedKey redaction, serialization |
Applicable ADRs
| ADR | Title | Relevance |
|---|---|---|
| 003 | Crate Decomposition | alknet-vault's standalone position |
| 005 | irpc as Call Protocol Foundation | VaultProtocol uses irpc directly |
| 008 | Vault Integration Point | CLI-embedded, capability source |
| 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 |
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 administration | deferred | Network unlock not supported; needs ADR if ever needed |
| OQ-22 | Key rotation mechanism | open | Key versioning is in place; rotation workflow is not specced |
Key Design Principles
- Standalone: The vault depends on no alknet crate. It defines its own types, errors, and protocol. 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.
- 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(). The current source usesrand::random()— this is a known drift from the spec and must be corrected during implementation sync. - 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. The current source usesunwrap()inVaultServiceHandlemethods — this is a known drift and must be corrected. - DerivedKey redaction in JSON:
DerivedKeyserializes theprivate_keyas"[REDACTED]"in human-readable formats (JSON) and as raw bytes in binary formats (postcard). The redaction is a defense-in- depth measure, 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};
// Encryption
pub use encryption::{EncryptedData, EncryptionError};
// Protocol (irpc messages)
pub use protocol::{DerivedKey, KeyType, VaultMessage, VaultProtocol};
// Service (runtime)
pub use service::{VaultService, VaultServiceActor, VaultServiceError, VaultServiceHandle};
// Cache
pub use cache::CacheConfig;
The secp256k1 feature flag gates Ethereum (BIP-0032) derivation:
#[cfg(feature = "secp256k1")]
pub mod ethereum;