Files
alkvault/docs/architecture/README.md
T
glm-5.3-flash 8e01fce5de docs: remove em dashes from prose across the repo
Adds the alk-family "no em dashes in prose" convention (as AGENTS.md
convention 10, mirroring alktty/alktunnels/alksocks) and rewrites the
existing prose to comply: markdown docs under docs/ (ADRs, spec docs,
OQs, sdd_process), README.md, CHANGELOG.md, Rust doc and inline
comments under src/, AGENTS.md, and the agent prompts under
.opencode/agents/. Punctuation substitutes are varied (colons,
parentheses, commas, semicolons, sentence splits); wire data, JSON
examples, and code identifiers are untouched. Prose-only change; no
code, API, or wire-format changes.

Also:
- ADR-021: add a historical note that the embedded code snippets
  predate review 001 (decrypt now returns Zeroizing<String>); the
  snippets are intentionally preserved as the decision record
- protocol.md: align the DerivedKey deserialization error snippet with
  the current error string in src/protocol.rs
- docs/reviews/ is exempt per convention 10 (archived review records)

Verification:
- grep for em/en clause dashes over docs/, src/, tests/, README.md,
  CHANGELOG.md, AGENTS.md, .opencode/agents/: clean (docs/reviews/
  exempt)
- cargo test --all-features: 108 passed, 0 failed
- cargo test: 101 passed, 0 failed
- cargo clippy --all-features --all-targets: clean
- cargo doc --no-deps --all-features: clean
2026-11-04 06:43:36 +00:00

8.3 KiB

status, last_updated
status last_updated
stable 2026-06-23

alkvault

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

alkvault 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
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

These ADRs are not copied here (they are not vault-specific), but the vault's design depends on them. They live in the parent @alkdev/alknet workspace.

ADR Title Relevance
@alkdev/alknet: docs/architecture/decisions/003-crate-decomposition.md Crate Decomposition alkvault's standalone position
@alkdev/alknet: docs/architecture/decisions/008-secret-service-integration.md Vault Integration Point CLI-embedded, capability source
@alkdev/alknet: docs/architecture/decisions/010-alpn-router-and-endpoint.md ALPN Router and Endpoint Ed25519 as default curve for TLS raw key identity
@alkdev/alknet: docs/architecture/decisions/014-secret-material-flow-and-capability-injection.md Secret Material Flow and Capability Injection Capabilities carry vault-derived material

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
// alkvault::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;

References

  • @alkdev/alknet: docs/architecture/decisions/003-crate-decomposition.md: crate decomposition (alkvault's standalone position)
  • @alkdev/alknet: docs/architecture/decisions/008-secret-service-integration.md: vault integration point (CLI-embedded, capability source)
  • @alkdev/alknet: docs/architecture/decisions/010-alpn-router-and-endpoint.md: ALPN router and endpoint (Ed25519 as default curve for TLS raw key identity)
  • @alkdev/alknet: docs/architecture/decisions/014-secret-material-flow-and-capability-injection.md: secret material flow and capability injection (capabilities carry vault-derived material)

Note

: Cross-repo references (@alkdev/alknet: ...) point to the parent @alkdev/alknet workspace where this crate originated. The artifacts are preserved there as historical context; they are not part of this standalone repo.