feat(secret): add alknet-secret crate and architecture spec for Phase 3
Create the alknet-secret crate with BIP39 mnemonic generation, SLIP-0010 Ed25519 HD key derivation, AES-256-GCM encryption, and SecretProtocol irpc service definition. This is Phase 3.1 from the integration plan. Architecture changes: - Promote secret-service.md to reviewed status with full spec format (crate structure, public API, security model, phase progression, ADR/OQ cross-references, wire format compatibility section) - Add ADR-038 (seed lifecycle and memory security): zeroize for v1, mlock deferred to Phase B - Add OQ-SEC-01 (mlock/VirtualLock for seed RAM) to open-questions.md - Update README.md with ADR-038 and secret-service status Crate structure: - src/mnemonic.rs: BIP39 phrase generation, validation, seed derivation - src/derivation.rs: SLIP-0010 HD key derivation, path constants (74') - src/encryption.rs: AES-256-GCM encrypt/decrypt, EncryptedData type - src/protocol.rs: SecretProtocol irpc enum, DerivedKey, KeyType - src/service.rs: SecretServiceHandle with Unlock/Lock lifecycle - 40 passing tests (unit + integration + doc)
This commit is contained in:
@@ -36,7 +36,7 @@ OQ-20 (worker registration), OQ-CP-01 (per-identity credentials), OQ-CP-02
|
||||
| [configuration.md](configuration.md) | draft | StaticConfig, DynamicConfig, API keys, forwarding policy, reload |
|
||||
| [storage.md](storage.md) | draft | alknet-storage: metagraph, identity, ACL, honker |
|
||||
| [flowgraph.md](flowgraph.md) | draft | alknet-flowgraph: call graph, operation graph, petgraph |
|
||||
| [secret-service.md](secret-service.md) | draft | alknet-secret: BIP39, SLIP-0010, AES-GCM, SecretProtocol |
|
||||
| [secret-service.md](secret-service.md) | reviewed | alknet-secret: BIP39, SLIP-0010, AES-GCM, SecretProtocol |
|
||||
| [credentials.md](credentials.md) | draft | CredentialProvider, CredentialSet (outbound auth) |
|
||||
| [definitions.md](definitions.md) | draft | Terminology disambiguation and concept mapping |
|
||||
|
||||
@@ -97,6 +97,8 @@ OQ-20 (worker registration), OQ-CP-01 (per-identity credentials), OQ-CP-02
|
||||
| [036](decisions/036-credentialprovider-core-type.md) | CredentialProvider as core type (outbound auth) | Accepted |
|
||||
| [037](decisions/037-api-keys-dynamic-config.md) | API keys as DynamicConfig auth | Accepted |
|
||||
|
||||
| [038](decisions/038-seed-lifecycle-memory-security.md) | Seed lifecycle and memory security (zeroize for v1) | Accepted |
|
||||
|
||||
> ADR numbers 020–022 were allocated to proposals that were withdrawn before
|
||||
> acceptance and are not listed.
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
# ADR-038: Seed Lifecycle and Memory Security
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
The alknet-secret crate holds the master BIP39 seed phrase in RAM. This seed is
|
||||
the root of trust for all derived keys (identity, encryption, signing). If the
|
||||
seed is leaked — through memory dumps, swap files, or core dumps — an attacker
|
||||
can derive every key in the system.
|
||||
|
||||
Security-conscious key management systems typically employ three defenses:
|
||||
|
||||
1. **Zeroize**: Overwrite sensitive memory before deallocating. Prevents
|
||||
stale-data reads from freed memory.
|
||||
|
||||
2. **Memory locking** (`mlock`/`VirtualLock`): Prevent the OS from paging
|
||||
sensitive RAM to disk. Prevents swap-file leakage.
|
||||
|
||||
3. **Constant-time comparison**: Prevent timing side-channels when comparing
|
||||
keys or tokens.
|
||||
|
||||
The question is: which of these should alknet-secret adopt in v1, and which
|
||||
should be deferred?
|
||||
|
||||
## Decision
|
||||
|
||||
**Phase 3 (v1): Zeroize only. Defer mlock and constant-time comparison to
|
||||
Phase B.**
|
||||
|
||||
- All sensitive types (seed bytes, derived private keys, passphrase strings)
|
||||
derive `Zeroize` and implement `Drop` to call `zeroize()` before deallocation.
|
||||
- The `Lock` operation calls `zeroize()` on the seed and all cached derived
|
||||
keys, then drops them.
|
||||
- `mlock`/`VirtualLock` and constant-time comparison are not included in v1.
|
||||
|
||||
### Rationale for deferring mlock
|
||||
|
||||
1. **Complexity**: `mlock` requires root/CAP_IPC_LOCK on Linux or
|
||||
`SeLockMemory` on Windows. The crate should work in unprivileged contexts
|
||||
(development, testing, single-user nodes) without requiring system
|
||||
configuration changes.
|
||||
|
||||
2. **Performance**: `mlock` locks physical pages, which are typically 4KB.
|
||||
Locking many small buffers wastes physical memory. The seed (64 bytes) and
|
||||
derived keys (32–64 bytes each) are tiny — the real risk is swap-file
|
||||
leakage, which `zeroize` partially mitigates by wiping before free.
|
||||
|
||||
3. **Deployment flexibility**: Production head nodes running as root or with
|
||||
`CAP_IPC_LOCK` can add `mlock` in Phase B. Development and CLI nodes
|
||||
shouldn't need it.
|
||||
|
||||
4. **Audit surface**: `mlock` introduces platform-specific code paths (Linux
|
||||
vs macOS vs Windows) that should be audited together, not bolted on
|
||||
incrementally.
|
||||
|
||||
### Rationale for deferring constant-time comparison
|
||||
|
||||
The `SecretProtocol` service receives requests over irpc (local mpsc or remote
|
||||
QUIC). Comparison timing is not observable by callers — they send a message and
|
||||
wait for a response. The comparison that matters (auth token verification) is
|
||||
in alknet-core's `IdentityProvider`, not in alknet-secret. Key derivation
|
||||
results (DerivedKey) are not compared against attacker-controlled input within
|
||||
this crate.
|
||||
|
||||
### Zeroize implementation
|
||||
|
||||
```rust
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[derive(Zeroize)]
|
||||
#[zeroize(drop)]
|
||||
struct SeedHolder {
|
||||
seed: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Zeroize)]
|
||||
#[zeroize(drop)]
|
||||
struct DerivedKeyCache {
|
||||
keys: HashMap<String, Vec<u8>>,
|
||||
}
|
||||
```
|
||||
|
||||
`#[zeroize(drop)]` ensures that `Drop` calls `zeroize()` on all fields,
|
||||
overwriting memory before deallocation. This is a compile-time guarantee —
|
||||
forgetting to zeroize a field is a compile error.
|
||||
|
||||
### Lock lifecycle
|
||||
|
||||
```
|
||||
Unlock(passphrase)
|
||||
→ validate mnemonic (if restoring) or generate new
|
||||
→ derive master key from seed
|
||||
→ store seed in SeedHolder (Zeroize-protected)
|
||||
→ cache empty (keys derived on demand)
|
||||
|
||||
DeriveEd25519/DeriveEncryptionKey/Encrypt/Decrypt
|
||||
→ require unlocked state (error if locked)
|
||||
→ derive key, return result
|
||||
→ optionally cache derived key
|
||||
|
||||
Lock
|
||||
→ zeroize all cached derived keys
|
||||
→ zeroize seed
|
||||
→ drop all sensitive material
|
||||
→ service returns to locked state
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
- **Positive**: Zeroize is zero-cost at compile time, minimal dependency
|
||||
(`zeroize` crate is ~500 lines, no `unsafe` on stable), and provides
|
||||
meaningful protection against stale-memory reads.
|
||||
- **Positive**: Lock effectively purges all sensitive material. After Lock,
|
||||
the process memory contains no useful secret data.
|
||||
- **Positive**: No platform-specific code paths in v1. The crate compiles and
|
||||
runs everywhere without privilege requirements.
|
||||
- **Negative**: Without `mlock`, the OS can page the seed to swap before
|
||||
zeroization occurs. This is a window of vulnerability that Phase B closes.
|
||||
The risk is acceptable for v1 because swap-file extraction requires root
|
||||
access or physical access to the machine — the same threat model as reading
|
||||
process memory directly.
|
||||
- **Negative**: Without constant-time comparison, timing side-channels exist
|
||||
in theory. In practice, no comparison in alknet-secret operates on
|
||||
attacker-controlled input, so the risk is nil within this crate.
|
||||
- **Negative**: `zeroize` adds a dependency. The `zeroize` crate is widely
|
||||
used in Rust crypto (ring, ed25519-dalek, x25519-dalek) and is a de facto
|
||||
standard.
|
||||
|
||||
## References
|
||||
|
||||
- [secret-service.md](../secret-service.md) — Security model, Lock/Unlock lifecycle
|
||||
- [ADR-027](027-crate-decomposition.md) — Crate decomposition (alknet-secret is independent)
|
||||
- [credentials.md](../credentials.md) — SecretStoreCredentialProvider integration
|
||||
- `zeroize` crate — https://crates.io/crates/zeroize
|
||||
@@ -328,4 +328,13 @@ last_updated: 2026-06-07
|
||||
- **Status**: resolved
|
||||
- **Priority**: medium
|
||||
- **Resolution**: Yes. Adopted in [definitions.md](definitions.md). Use "credential presentation" for the mechanism of presenting credentials on a (Transport, Interface) pair. Never use "auth interface" (overloads "Interface").
|
||||
- **Cross-references**: [definitions.md](definitions.md), [auth.md](auth.md)
|
||||
- **Cross-references**: [definitions.md](definitions.md), [auth.md](auth.md)
|
||||
|
||||
## Secret Service
|
||||
|
||||
### OQ-SEC-01: Should alknet-secret use mlock/VirtualLock to prevent seed RAM from being paged to disk?
|
||||
- **Origin**: [secret-service.md](secret-service.md)
|
||||
- **Status**: open
|
||||
- **Priority**: low
|
||||
- **Resolution**: (deferred to Phase B — zeroize is sufficient for v1; mlock requires root/CAP_IPC_LOCK on Linux and SeLockMemory on Windows, adding platform complexity that should be audited together)
|
||||
- **Cross-references**: [ADR-038](decisions/038-seed-lifecycle-memory-security.md), [secret-service.md](secret-service.md)
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-06-07
|
||||
status: reviewed
|
||||
last_updated: 2026-06-09
|
||||
---
|
||||
|
||||
# Secret Service
|
||||
# Secret Service (alknet-secret)
|
||||
|
||||
## What
|
||||
|
||||
@@ -22,21 +22,124 @@ OAuth tokens) cannot be derived and must be stored encrypted, with the
|
||||
encryption key itself derived from the seed.
|
||||
|
||||
The secret service isolates this responsibility: no other crate sees the seed,
|
||||
and derived keys are provided on demand through an irpc service interface.
|
||||
and derived keys are provided on demand through an irpc service interface. This
|
||||
follows ADR-027 (crate decomposition) — alknet-secret is fully independent of
|
||||
alknet-core and alknet-storage.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Crate Structure
|
||||
|
||||
```
|
||||
alknet-secret/
|
||||
├── Cargo.toml
|
||||
├── src/
|
||||
│ ├── lib.rs # Crate root, re-exports
|
||||
│ ├── mnemonic.rs # BIP39: phrase generation, validation, seed derivation
|
||||
│ ├── derivation.rs # SLIP-0010: HD key derivation, path constants
|
||||
│ ├── encryption.rs # AES-256-GCM: encrypt/decrypt, EncryptedData type
|
||||
│ ├── protocol.rs # SecretProtocol irpc service enum, DerivedKey, KeyType
|
||||
│ └── service.rs # SecretServiceImpl: in-memory seed, Unlock/Lock lifecycle
|
||||
└── tests/
|
||||
├── derivation_tests.rs # Path derivation, coin type 74' consistency
|
||||
├── encryption_tests.rs # Round-trip encrypt/decrypt, key version
|
||||
└── service_tests.rs # Unlock/Lock lifecycle, derive on locked = error
|
||||
```
|
||||
|
||||
### Dependencies
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
bip39 = "2"
|
||||
ed25519-bip32 = "0.x" # IOHK SLIP-0010 Ed25519 HD derivation
|
||||
aes-gcm = "0.10" # AES-256-GCM
|
||||
sha2 = "0.10" # SHA-256
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
thiserror = "2"
|
||||
irpc = "0.x" # Always-on, not feature-gated (ADR-027)
|
||||
zeroize = { version = "1", features = ["derive"] } # Secure memory wiping (ADR-038)
|
||||
```
|
||||
|
||||
irpc is always a dependency (not behind a feature flag). Per ADR-027, irpc
|
||||
in alknet-secret and alknet-storage is not feature-gated because these crates
|
||||
are used in production deployments where the service layer is always active.
|
||||
|
||||
### Crate Interface (Public API)
|
||||
|
||||
The crate exposes these types as its stable public interface:
|
||||
|
||||
```rust
|
||||
// Core types (always available)
|
||||
pub use mnemonic::{Mnemonic, Language, Seed};
|
||||
pub use derivation::{ExtendedPrivKey, DerivationPath, PATHS};
|
||||
pub use encryption::{EncryptedData, EncryptionError};
|
||||
pub use protocol::{SecretProtocol, DerivedKey, KeyType, SecretMessage};
|
||||
pub use service::{SecretService, SecretServiceHandle, SecretServiceError};
|
||||
```
|
||||
|
||||
Other crates consume this interface:
|
||||
- **alknet-storage** references `EncryptedData` for wire format compatibility
|
||||
(type-level, not a crate dependency)
|
||||
- **alknet** (CLI binary) assembles `SecretService` and wires it to the
|
||||
`OperationEnv`
|
||||
- **alknet-core** never depends on alknet-secret; `CredentialProvider` stub
|
||||
returns `None` until Phase A wiring
|
||||
|
||||
### Security Model
|
||||
|
||||
Per ADR-038 (seed lifecycle and memory security):
|
||||
|
||||
| State | What's in memory | What's on disk |
|
||||
|-------|-----------------|---------------|
|
||||
| Locked | Nothing | Encrypted database, derivation path metadata |
|
||||
| Unlocked | Master seed in RAM | Same (seed is never persisted) |
|
||||
| After use | Derived keys cached in RAM | Derivation paths only |
|
||||
| Unlocked | Master seed in zeroize-protected RAM | Same (seed is never persisted) |
|
||||
| After use | Derived keys cached in zeroize-protected RAM | Derivation paths only |
|
||||
|
||||
The seed phrase is entered once (at node startup or via `Unlock` call), held
|
||||
only in RAM, and never written to disk. The `Lock` call purges the seed and all
|
||||
cached derived keys from memory.
|
||||
The seed phrase is entered once (at node startup or via `Unlock`), held only in
|
||||
RAM, and never written to disk. `Lock` calls `zeroize()` on the seed and all
|
||||
cached derived keys. The `SecretService` uses `Zeroize`-derived types for all
|
||||
sensitive material.
|
||||
|
||||
### Key Derivation
|
||||
|
||||
#### BIP39 Mnemonic and Seed Derivation
|
||||
|
||||
```rust
|
||||
let mnemonic = Mnemonic::from_phrase(&phrase, Language::English)?;
|
||||
let seed = mnemonic.to_seed(Some(&passphrase));
|
||||
let master_key = ExtendedPrivKey::new_master(Network::Alknet, &seed)?;
|
||||
```
|
||||
|
||||
#### SLIP-0010 Ed25519 HD Key Derivation
|
||||
|
||||
The `74'` coin type is unallocated per SLIP-0044 and reserved for alknet.
|
||||
|
||||
#### Derivation Path Constants
|
||||
|
||||
| Path | Purpose | Curve/Algorithm |
|
||||
|------|---------|----------------|
|
||||
| `m/74'/0'/0'/0'` | Primary identity keypair | Ed25519 (alknet auth) |
|
||||
| `m/74'/0'/0'/{n}'` | Worker/device identity | Ed25519 |
|
||||
| `m/74'/0'/1'/0'` | SSH host key | Ed25519 |
|
||||
| `m/74'/1'/0'/{hash}'` | Site-specific password | Deterministic |
|
||||
| `m/74'/2'/0'/0'` | Encryption key for external credentials | AES-256-GCM |
|
||||
| `m/44'/60'/0'/0/0` | Ethereum signing key | secp256k1 |
|
||||
|
||||
These constants are defined in `derivation::PATHS` for programmatic access.
|
||||
|
||||
### AES-256-GCM Encryption for External Credentials
|
||||
|
||||
External credentials (API keys, OAuth tokens) that cannot be derived are
|
||||
encrypted using a key derived from the seed at path `m/74'/2'/0'/0'`. The
|
||||
`EncryptedData` type stores the key version, salt, IV, and ciphertext.
|
||||
|
||||
1. The secret service derives an AES-256-GCM key via path `m/74'/2'/0'/0'`
|
||||
2. External credentials are encrypted with this key
|
||||
3. The encrypted data is stored as a `SecretNode` in the metagraph
|
||||
4. Only the derivation path and key version are stored in plain attributes
|
||||
5. The seed phrase (or derived encryption key) is held only by the secret
|
||||
service — never in the database
|
||||
|
||||
### SecretProtocol irpc Service
|
||||
|
||||
@@ -100,42 +203,17 @@ struct EncryptedData {
|
||||
}
|
||||
```
|
||||
|
||||
### BIP39 Mnemonic and Seed Derivation
|
||||
### Wire Format Compatibility with alknet-storage
|
||||
|
||||
```rust
|
||||
let mnemonic = Mnemonic::from_phrase(&phrase, Language::English)?;
|
||||
let seed = mnemonic.to_seed(Some(&passphrase));
|
||||
let master_key = ExtendedPrivKey::new_master(Network::Alknet, &seed)?;
|
||||
```
|
||||
The `EncryptedData` type (`key_version`, `salt`, `iv`, `data`) is the stable
|
||||
wire format shared with alknet-storage. This is type-level compatibility — not a
|
||||
crate dependency. alknet-storage stores encrypted nodes using this format;
|
||||
alknet-secret encrypts and decrypts using this format.
|
||||
|
||||
### SLIP-0010 Ed25519 HD Key Derivation
|
||||
|
||||
The `74'` coin type is unallocated per SLIP-0044 and reserved for alknet.
|
||||
|
||||
### Derivation Path Constants
|
||||
|
||||
| Path | Purpose | Curve/Algorithm |
|
||||
|------|---------|----------------|
|
||||
| `m/74'/0'/0'/0'` | Primary identity keypair | Ed25519 (alknet auth) |
|
||||
| `m/74'/0'/0'/{n}'` | Worker/device identity | Ed25519 |
|
||||
| `m/74'/0'/1'/0'` | SSH host key | Ed25519 |
|
||||
| `m/74'/1'/0'/{hash}'` | Site-specific password | Deterministic |
|
||||
| `m/74'/2'/0'/0'` | Encryption key for external credentials | AES-256-GCM |
|
||||
| `m/44'/60'/0'/0/0` | Ethereum signing key | secp256k1 |
|
||||
|
||||
### AES-256-GCM Encryption for External Credentials
|
||||
|
||||
External credentials (API keys, OAuth tokens) that cannot be derived are
|
||||
encrypted using a key derived from the seed at path `m/74'/2'/0'/0'`. The
|
||||
`EncryptedData` type stores the key version, salt, IV, and ciphertext. This
|
||||
format is compatible with the existing `@alkdev/storage` `EncryptedDataSchema`.
|
||||
|
||||
1. The secret service derives an AES-256-GCM key via path `m/74'/2'/0'/0'`
|
||||
2. External credentials are encrypted with this key
|
||||
3. The encrypted data is stored as a `SecretNode` in the metagraph
|
||||
4. Only the derivation path and key version are stored in plain attributes
|
||||
5. The seed phrase (or derived encryption key) is held only by the secret
|
||||
service — never in the database
|
||||
The Rust `EncryptedData` struct in alknet-secret is a superset of the TypeScript
|
||||
`EncryptedDataSchema` from `@alkdev/storage`. Migration path: re-encrypt
|
||||
TypeScript-encrypted data using the Rust secret service with a new key version.
|
||||
See OQ-SVC-03.
|
||||
|
||||
### Deployment Topologies
|
||||
|
||||
@@ -149,33 +227,43 @@ never leaves the secret service node.
|
||||
## Constraints
|
||||
|
||||
- The seed phrase is never persisted to disk. It is entered at startup or via
|
||||
`Unlock` and held only in RAM.
|
||||
- `Lock` purges the seed and all cached derived keys from memory.
|
||||
`Unlock` and held only in `Zeroize`-protected RAM (ADR-038).
|
||||
- `Lock` calls `zeroize()` on the seed and all cached derived keys.
|
||||
- alknet-secret does not depend on alknet-core or alknet-storage. It is fully
|
||||
independent.
|
||||
- The `EncryptedData` wire format (key_version, salt, iv, data) is shared with
|
||||
alknet-storage for compatibility, but this is type-level compatibility — not a
|
||||
crate dependency.
|
||||
- Per ADR-032, the secret service's Honker streams (key derivation notifications)
|
||||
stay within the service boundary. External consumers use irpc calls or call
|
||||
protocol operations that project to integration events.
|
||||
- The irpc service defines the wire format for in-cluster communication
|
||||
independent (ADR-027).
|
||||
- The `EncryptedData` wire format is shared with alknet-storage for type-level
|
||||
compatibility, not a crate dependency.
|
||||
- Per ADR-032, secret service domain events (key derivation notifications) stay
|
||||
within the service boundary. External consumers use irpc calls or call
|
||||
protocol operations projected to integration events.
|
||||
- irpc is always a dependency (not feature-gated) per ADR-027.
|
||||
- `SecretProtocol` defines the wire format for in-cluster communication
|
||||
(postcard serialization). For call protocol exposure (e.g.,
|
||||
`/head/secrets/derive`), the service is wrapped in an operation that serializes
|
||||
to JSON.
|
||||
`/head/secrets/derive`), the service is wrapped in an operation that
|
||||
serializes to JSON.
|
||||
|
||||
## Phase Progression
|
||||
|
||||
| Phase | Scope | Notes |
|
||||
|-------|-------|-------|
|
||||
| Phase 3 (now) | Basic crate: mnemonic, derivation, encryption, irpc protocol, service lifecycle | Core key management |
|
||||
| Phase A | Integration with alknet-storage via `EncryptedData` wire format. CLI commands for unlock/lock/derive. `SecretStoreCredentialProvider` wiring. | Full service integration |
|
||||
| Phase B | Memory hardening: `mlock`/`VirtualLock` for seed RAM, constant-time comparison, audit logging of derivation requests. | Security hardening |
|
||||
| Phase C | Multi-seed support (tenant isolation): indexed `Unlock` with tenant ID. | Multi-tenancy |
|
||||
|
||||
## Open Questions
|
||||
|
||||
- **OQ-SVC-01**: Should the secret service support multiple seed phrases (one
|
||||
per tenant)? See [open-questions.md](open-questions.md).
|
||||
|
||||
- **OQ-SVC-02**: Should service protocols use postcard (binary) or JSON for
|
||||
remote calls? See [open-questions.md](open-questions.md).
|
||||
|
||||
- **OQ-SVC-03**: How does the secret service integrate with the existing
|
||||
`EncryptedDataSchema` from `@alkdev/storage`? See [open-questions.md](open-questions.md).
|
||||
|
||||
- **OQ-SVC-04**: Should workers cache derived keys locally? See [open-questions.md](open-questions.md).
|
||||
- **OQ-SVC-04**: Should workers cache derived keys locally? See
|
||||
[open-questions.md](open-questions.md).
|
||||
|
||||
- **OQ-SEC-01**: Should alknet-secret use `mlock`/`VirtualLock` to prevent seed
|
||||
RAM from being paged to disk? See [open-questions.md](open-questions.md).
|
||||
|
||||
## Design Decisions
|
||||
|
||||
@@ -183,11 +271,13 @@ never leaves the secret service node.
|
||||
|-----|----------|---------|
|
||||
| [027](decisions/027-crate-decomposition.md) | Crate decomposition | alknet-secret is independent of core and storage |
|
||||
| [032](decisions/032-event-boundary-discipline.md) | Event boundary | Secret service domain events stay internal |
|
||||
| [038](decisions/038-seed-lifecycle-memory-security.md) | Seed lifecycle and memory security | Zeroize for sensitive material, mlock deferred to Phase B |
|
||||
|
||||
## References
|
||||
|
||||
- [research/services.md](../research/services.md) — SecretProtocol definition, DerivedKey, KeyType
|
||||
- [research/storage.md](../research/storage.md) — Secrets section, derivation paths, EncryptedData
|
||||
- [research/integration-plan.md](../research/integration-plan.md) — Phase 2.1
|
||||
- [research/integration-plan.md](../research/integration-plan.md) — Phase 3.1
|
||||
- [credentials.md](credentials.md) — CredentialProvider (outbound auth, consumes SecretProtocol::Decrypt)
|
||||
- SLIP-0010 — https://github.com/satoshilabs/slips/blob/master/slip-0010.md
|
||||
- BIP39 — https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
|
||||
Reference in New Issue
Block a user