Remove stale Phase B TODO; align encryption comments with ADR-020/021/018
The 'TODO(Phase B): Use salt in HKDF-based key derivation' at
src/encryption.rs:169 described a design direction that ADR-021
(Accepted) explicitly decided against — key rotation uses
version-indexed HD paths (m/74'/2'/0'/{version-2}'), not a KDF over
the salt. ADR-020 §6 W6 confirms v2 data's salt is permanently unused.
The salt field stays populated because ADR-018 locks the wire format.
No behavior or wire-format change. The implementation was already
correct per the ADRs; only the comments and TODO had drifted toward a
rejected design.
Changes (src/encryption.rs, comments/docs only):
- Module 'Salt Field' section: rewritten to match encryption.md and
ADR-020/021/018
- EncryptedData.salt field doc: removed Phase B framing, added ADR
references and pointer to encryption.md
- encrypt() doc: removed false claim 'salt allows key rotation'; now
states IV/salt roles and ADR pointers
- TODO(Phase B) line: removed, replaced with a one-line rationale
comment matching the neighboring IV comment's style
- Drive-by: fixed stale 'OQ-SVC-03' reference -> 'OQ-20' (the actual
OQ file; OQ-SVC-03 appears nowhere else in the repo)
Verification (matches 0.1.0 publish baseline):
- cargo test --all-features: 108 passed
- cargo test (default): 101 passed
- cargo clippy --all-features --all-targets: clean
- cargo doc --no-deps --all-features: clean
- cargo publish --dry-run --all-features --allow-dirty: 44 files packaged
This commit is contained in:
1 parent
31d1991394
commit
44c35a96dd
1 file changed
+33
-19
+33
-19
@@ -4,19 +4,24 @@
|
||||
//! seed 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.
|
||||
//!
|
||||
//! # Salt Field (Reserved for Future KDF-Based Key Derivation)
|
||||
//! # Salt Field (Unused in v2 — Wire-Format Compatibility)
|
||||
//!
|
||||
//! The `salt` field in `EncryptedData` is **reserved for future KDF-based key
|
||||
//! derivation** (Phase B). In v2, the encryption key is derived directly from the
|
||||
//! seed at path `m/74'/2'/0'/0'` without using the salt. The salt is generated
|
||||
//! randomly (32 bytes) and stored in `EncryptedData.salt` for forward
|
||||
//! compatibility, but it plays no role in the v2 key derivation process.
|
||||
//! The `salt` field in `EncryptedData` is **unused for key derivation in v2**
|
||||
//! (ADR-020). The encryption key is derived from the seed via SLIP-0010 HD
|
||||
//! derivation at path `m/74'/2'/0'/0'` (`PATHS::ENCRYPTION`); HD derivation
|
||||
//! doesn't need a salt because the derivation path provides domain separation.
|
||||
//! A 32-byte salt is generated randomly and stored for wire-format
|
||||
//! compatibility with the TypeScript `EncryptedDataSchema`, but it plays no
|
||||
//! cryptographic role.
|
||||
//!
|
||||
//! When key rotation is implemented in Phase B, the salt will be used as input to
|
||||
//! HKDF or PBKDF2 for stretch-based key derivation, allowing the same seed to
|
||||
//! produce different encryption keys without changing the derivation path. This
|
||||
//! design ensures that the wire format does not need to change — the `salt` field
|
||||
//! is already present and populated.
|
||||
//! Key rotation uses version-indexed derivation paths (ADR-021 —
|
||||
//! `m/74'/2'/0'/{version-2}'`), **not** a KDF over the salt. v2 data's salt is
|
||||
//! permanently unused (ADR-020 §6 W6): it was random, never participated in
|
||||
//! key derivation, and cannot be retroactively made load-bearing. The `salt`
|
||||
//! field is retained because the wire format is frozen (ADR-018); a future
|
||||
//! KDF-based derivation family would be a new `key_version` with its own
|
||||
//! design and v2→vN migration, using a freshly-generated salt for the new
|
||||
//! data only.
|
||||
//!
|
||||
//! # Wire Format
|
||||
//!
|
||||
@@ -65,17 +70,21 @@ pub const CURRENT_KEY_VERSION: u32 = 2;
|
||||
/// from `@alkdev/storage`. Migration path: re-encrypt TypeScript-encrypted data
|
||||
/// using the Rust vault with a new key version.
|
||||
///
|
||||
/// See OQ-SVC-03 for the compatibility tracking.
|
||||
/// See OQ-20 for the compatibility tracking.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct EncryptedData {
|
||||
/// Key version for rotation support.
|
||||
pub key_version: u32,
|
||||
/// Base64-encoded random salt.
|
||||
/// Base64-encoded random salt (32 bytes).
|
||||
///
|
||||
/// **Reserved for future KDF-based key derivation (Phase B).** In v2, the
|
||||
/// encryption key is derived directly from the seed at path `m/74'/2'/0'/0'`
|
||||
/// without using the salt. The salt is generated and stored for forward
|
||||
/// compatibility but does not participate in key derivation.
|
||||
/// **Unused for key derivation in v2** (ADR-020). HD derivation at
|
||||
/// `m/74'/2'/0'/0'` doesn't need a salt — the path provides domain
|
||||
/// separation. The salt is generated randomly and stored for wire-format
|
||||
/// compatibility with the TypeScript `EncryptedDataSchema`; it plays no
|
||||
/// cryptographic role. Key rotation uses version-indexed paths (ADR-021),
|
||||
/// not a KDF over the salt. The field is retained because the wire format
|
||||
/// is frozen (ADR-018). See `encryption.md` → "Salt field" for full
|
||||
/// rationale.
|
||||
pub salt: String,
|
||||
/// Base64-encoded initialization vector (12 bytes for AES-GCM).
|
||||
pub iv: String,
|
||||
@@ -143,7 +152,11 @@ impl fmt::Debug for EncryptionKey {
|
||||
/// Encrypt plaintext using an AES-256-GCM key.
|
||||
///
|
||||
/// Generates a random 12-byte IV and a random 32-byte salt for each encryption.
|
||||
/// The salt allows key rotation without re-deriving from the seed.
|
||||
/// The IV is the GCM nonce (fresh per call — IV reuse under the same key is
|
||||
/// catastrophic). The salt is stored for wire-format compatibility with the
|
||||
/// TypeScript `EncryptedDataSchema` and is not used in key derivation in v2
|
||||
/// (ADR-020); key rotation uses version-indexed derivation paths (ADR-021),
|
||||
/// not the salt.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -166,7 +179,8 @@ pub(crate) fn encrypt(
|
||||
.try_fill_bytes(&mut iv_bytes)
|
||||
.map_err(|e| EncryptionError::Encryption(format!("rng failure: {e}")))?;
|
||||
|
||||
// TODO(Phase B): Use salt in HKDF-based key derivation
|
||||
// Generate random salt (32 bytes, wire-format compat only — unused in v2 key
|
||||
// derivation per ADR-020; rotation uses version-indexed paths per ADR-021).
|
||||
let mut salt_bytes = [0u8; 32];
|
||||
SysRng
|
||||
.try_fill_bytes(&mut salt_bytes)
|
||||
|
||||
Reference in new issue
Block a user