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:
62
crates/alknet-secret/tests/derivation_tests.rs
Normal file
62
crates/alknet-secret/tests/derivation_tests.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
//! Integration tests for key derivation.
|
||||
//!
|
||||
//! These tests verify that SLIP-0010 derivation produces correct results
|
||||
//! against known test vectors and that path constants produce expected key types.
|
||||
|
||||
use alknet_secret::derivation::PATHS;
|
||||
use alknet_secret::service::SecretServiceHandle;
|
||||
|
||||
#[test]
|
||||
fn test_identity_key_derivation() {
|
||||
let service = SecretServiceHandle::new();
|
||||
let _phrase = service.unlock_new(24).unwrap();
|
||||
|
||||
let key = service.derive_ed25519(PATHS::IDENTITY).unwrap();
|
||||
assert_eq!(key.key_type, alknet_secret::protocol::KeyType::Ed25519);
|
||||
assert!(!key.private_key.is_empty());
|
||||
assert!(!key.public_key.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encryption_key_derivation() {
|
||||
let service = SecretServiceHandle::new();
|
||||
service.unlock_new(24).unwrap();
|
||||
|
||||
let key = service
|
||||
.derive_encryption_key(PATHS::ENCRYPTION)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
key.key_type,
|
||||
alknet_secret::protocol::KeyType::Aes256Gcm
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deterministic_derivation() {
|
||||
// Same seed + same path = same key
|
||||
let service = SecretServiceHandle::new();
|
||||
let phrase = service.unlock_new(24).unwrap();
|
||||
|
||||
let key1 = service.derive_ed25519(PATHS::IDENTITY).unwrap();
|
||||
|
||||
// Unlock with the same phrase again
|
||||
service.lock();
|
||||
service.unlock(&phrase, None).unwrap();
|
||||
|
||||
let key2 = service.derive_ed25519(PATHS::IDENTITY).unwrap();
|
||||
|
||||
assert_eq!(key1.private_key, key2.private_key);
|
||||
assert_eq!(key1.public_key, key2.public_key);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_paths_different_keys() {
|
||||
let service = SecretServiceHandle::new();
|
||||
service.unlock_new(24).unwrap();
|
||||
|
||||
let identity_key = service.derive_ed25519(PATHS::IDENTITY).unwrap();
|
||||
let ssh_key = service.derive_ed25519(PATHS::SSH_HOST).unwrap();
|
||||
|
||||
assert_ne!(identity_key.private_key, ssh_key.private_key);
|
||||
assert_ne!(identity_key.public_key, ssh_key.public_key);
|
||||
}
|
||||
Reference in New Issue
Block a user