1use auths_core::crypto::signer::encrypt_keypair;
8use auths_core::crypto::ssh::build_ed25519_pkcs8_v2_from_seed;
9use auths_core::storage::keychain::{KeyAlias, KeyStorage};
10use auths_crypto::SecureSeed;
11use auths_verifier::IdentityDID;
12use thiserror::Error;
13use zeroize::Zeroizing;
14
15#[derive(Debug, Error)]
17#[non_exhaustive]
18pub enum KeyImportError {
19 #[error("seed must be exactly 32 bytes, got {0}")]
21 InvalidSeedLength(usize),
22
23 #[error("key alias cannot be empty")]
25 EmptyAlias,
26
27 #[error("failed to generate PKCS#8 from seed: {0}")]
29 Pkcs8Generation(String),
30
31 #[error("failed to encrypt private key: {0}")]
33 Encryption(String),
34
35 #[error("failed to store key in keychain: {0}")]
37 KeychainStore(String),
38}
39
40#[derive(Debug, Clone)]
42pub struct KeyImportResult {
43 pub public_key: [u8; 32],
45 pub alias: String,
47}
48
49pub fn import_seed(
71 seed: &Zeroizing<[u8; 32]>,
72 passphrase: &Zeroizing<String>,
73 alias: &str,
74 controller_did: &IdentityDID,
75 keychain: &dyn KeyStorage,
76) -> Result<KeyImportResult, KeyImportError> {
77 if alias.trim().is_empty() {
78 return Err(KeyImportError::EmptyAlias);
79 }
80
81 let secure_seed = SecureSeed::new(**seed);
82
83 let pkcs8_bytes = build_ed25519_pkcs8_v2_from_seed(&secure_seed)
84 .map_err(|e| KeyImportError::Pkcs8Generation(e.to_string()))?;
85
86 let encrypted = encrypt_keypair(&pkcs8_bytes, passphrase)
87 .map_err(|e| KeyImportError::Encryption(e.to_string()))?;
88
89 keychain
90 .store_key(&KeyAlias::new_unchecked(alias), controller_did, &encrypted)
91 .map_err(|e| KeyImportError::KeychainStore(e.to_string()))?;
92
93 let public_key =
94 auths_core::crypto::provider_bridge::ed25519_public_key_from_seed_sync(&secure_seed)
95 .map_err(|e| {
96 KeyImportError::Pkcs8Generation(format!("failed to derive public key: {e}"))
97 })?;
98
99 Ok(KeyImportResult {
100 public_key,
101 alias: alias.to_string(),
102 })
103}