Files
alkvault/docs/architecture
glm-5.2 8fd3428544 Port alknet-vault crate from alknet
Copy the local key vault (src/, tests/) verbatim from
alknet/crates/alknet-vault and create a standalone Cargo.toml
(workspace-inherited fields inlined). Port the architecture docs
(specs, ADRs 018-026, OQs 020-022) from alknet's nested multi-crate
layout to a flat single-crate layout, fixing relative link paths.

ADR and OQ numbers are preserved from alknet; a subsequent pass will
renumber them to a per-project sequence (001, 002, ...) and rebrand
alknet-vault -> alkvault (crate name, lib name, prose), updating the
cross-references to non-vault alknet ADRs (003, 005, 008, 010, 014,
064) that are referenced in the copied docs but not copied over.

Build, 108 tests, and clippy all pass clean.
2026-08-02 06:39:49 +00:00
..
2026-08-02 06:39:49 +00:00
2026-08-02 06:39:49 +00:00

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

  1. 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.
  2. 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.
  3. 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.
  4. Zeroize everything sensitive: The mnemonic, seed, derived private keys, encryption keys, and cached keys all implement Zeroize and ZeroizeOnDrop. Secret material does not linger in freed heap memory.
  5. Deterministic derivation: The same mnemonic + passphrase + path always produces the same key. Derivation is reproducible across runs and across nodes.
  6. OsRng for nonces: AES-GCM IVs and any cryptographic nonces use OsRng (or equivalent CSPRNG), never rand::random(). IV reuse under the same key is catastrophic for GCM.
  7. No unwrap() or expect() outside tests: vault operations propagate errors. A poisoned lock is recovered with unwrap_or_else(|e| e.into_inner()), not unwrap(). 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, not rand::random().
  • Zeroized drop: Seed, Mnemonic, ExtendedPrivKey, Secp256k1ExtendedPrivKey, EncryptionKey, CachedKey, and DerivedKey all derive Zeroize and ZeroizeOnDrop. The cache must clear on drop, not just on explicit lock().
  • No unwrap() outside tests: poisoned lock recovery uses unwrap_or_else(|e| e.into_inner()) or explicit error propagation.
  • DerivedKey redaction in serialization: DerivedKey serializes the private_key as "[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 that DerivedKey never 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;