1use anyhow::{Context, Result};
2use bip39::Mnemonic;
3use ed25519_dalek::{SigningKey, VerifyingKey, Signature, Signer, Verifier};
4use rand::RngCore;
5use rand_core::OsRng;
6use serde::{Deserialize, Serialize};
7use slip10::{BIP32Path, Curve};
8use std::str::FromStr;
9
10#[derive(Debug, Clone, Serialize, Deserialize, Eq, Hash, PartialEq)]
12pub struct KeyPairProperties {
13 pub seed_phrase_hd_path: String,
14 pub master_seed_phrase: String,
15 pub implicit_account_id: String,
16 #[serde(rename = "public_key")]
17 pub public_key_str: String,
18 #[serde(rename = "private_key")]
19 pub secret_keypair_str: String,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize, Eq, Hash, PartialEq)]
24pub struct AccountPrivate {
25 pub account_id: String,
26 pub seed_phrase_hd_path: String,
27 pub master_seed_phrase: String,
28 #[serde(rename = "public_key")]
29 pub public_key_str: String,
30 #[serde(rename = "private_key")]
31 pub secret_keypair_str: String,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize, Eq, Hash, PartialEq)]
36pub struct PublicKeyInfo {
37 #[serde(rename = "private_key")]
38 pub secret_keypair_str: String,
39 #[serde(rename = "public_key")]
40 pub public_key_str: String,
41 pub implicit_account_id: String,
42}
43
44pub fn generate_mnemonic() -> Result<String> {
46 let mut entropy = [0u8; 16];
47 OsRng.fill_bytes(&mut entropy);
48 let mnemonic = Mnemonic::from_entropy(&entropy)
49 .context("Failed to generate mnemonic")?;
50 Ok(mnemonic.to_string())
51}
52
53pub fn mnemonic_from_phrase(phrase: &str) -> Result<Mnemonic> {
55 Mnemonic::parse(phrase)
56 .context("Invalid mnemonic phrase")
57}
58
59pub fn generate_keypair_from_mnemonic(mnemonic: &Mnemonic) -> Result<(SigningKey, VerifyingKey)> {
61 let seed = mnemonic.to_seed("");
62 let seed_bytes: [u8; 32] = seed[..32]
64 .try_into()
65 .map_err(|_| anyhow::anyhow!("Failed to convert seed to 32 bytes"))?;
66
67 let signing_key = SigningKey::from_bytes(&seed_bytes);
68 let verifying_key = signing_key.verifying_key();
69
70 Ok((signing_key, verifying_key))
71}
72
73pub fn generate_keypair_from_mnemonic_with_path(
75 mnemonic: &Mnemonic,
76 path: &str,
77) -> Result<(SigningKey, VerifyingKey)> {
78 let seed = mnemonic.to_seed("");
79 let bip_path = BIP32Path::from_str(path)
80 .map_err(|e| anyhow::anyhow!("Invalid BIP32 path {}: {:?}", path, e))?;
81
82 let derived_key = slip10::derive_key_from_path(&seed, Curve::Ed25519, &bip_path)
83 .map_err(|e| anyhow::anyhow!("Failed to derive key from path: {:?}", e))?;
84
85 let signing_key = SigningKey::from_bytes(&derived_key.key);
86 let verifying_key = signing_key.verifying_key();
87
88 Ok((signing_key, verifying_key))
89}
90
91pub fn generate_keypair_raw() -> Result<(SigningKey, VerifyingKey)> {
93 let signing_key = SigningKey::generate(&mut OsRng);
94 let verifying_key = signing_key.verifying_key();
95 Ok((signing_key, verifying_key))
96}
97
98pub fn generate_keypair_properties(
101 mnemonic: Option<String>,
102 path: Option<String>,
103) -> Result<KeyPairProperties> {
104 let default_path = "m/44'/397'/0'".to_string();
105 let derivation_path = path.unwrap_or(default_path);
106
107 let (master_seed_phrase, master_seed) = {
108 let mnemonic = if let Some(m) = mnemonic {
109 Mnemonic::parse(&m)
110 .context("Invalid mnemonic phrase")?
111 } else {
112 let mut entropy = [0u8; 16];
113 OsRng.fill_bytes(&mut entropy);
114 Mnemonic::from_entropy(&entropy)
115 .context("Failed to generate mnemonic")?
116 };
117
118 let master_seed_phrase = mnemonic.words().collect::<Vec<&str>>().join(" ");
119 (master_seed_phrase, mnemonic.to_seed(""))
120 };
121
122 let bip_path = BIP32Path::from_str(&derivation_path)
123 .map_err(|e| anyhow::anyhow!("Invalid BIP32 path {}: {:?}", derivation_path, e))?;
124
125 let derived_private_key = slip10::derive_key_from_path(&master_seed, Curve::Ed25519, &bip_path)
126 .map_err(|e| anyhow::anyhow!("Failed to derive key from path: {:?}", e))?;
127
128 let secret_keypair = {
129 let secret = ed25519_dalek::SigningKey::from_bytes(&derived_private_key.key);
130 let public = secret.verifying_key();
131 (secret, public)
132 };
133
134 let implicit_account_id = hex::encode(secret_keypair.1.as_bytes());
135
136 let public_key_str = format!(
137 "ed25519:{}",
138 bs58::encode(secret_keypair.1.as_bytes()).into_string()
139 );
140
141 let secret_keypair_str = format!(
142 "ed25519:{}",
143 bs58::encode(secret_keypair.0.to_bytes()).into_string()
144 );
145
146 Ok(KeyPairProperties {
147 seed_phrase_hd_path: derivation_path,
148 master_seed_phrase,
149 implicit_account_id,
150 public_key_str,
151 secret_keypair_str,
152 })
153}
154
155pub fn get_key_with_account_id(
157 mnemonic: &str,
158 index: u128,
159 account_id: &str,
160) -> Result<AccountPrivate> {
161 let path_buf = format!("m/44'/397'/{}'", index);
162 let kp = get_key_with_mnemonic_path(mnemonic, &path_buf)?;
163
164 Ok(AccountPrivate {
165 account_id: account_id.to_string(),
166 seed_phrase_hd_path: kp.seed_phrase_hd_path,
167 master_seed_phrase: kp.master_seed_phrase,
168 public_key_str: kp.public_key_str,
169 secret_keypair_str: kp.secret_keypair_str,
170 })
171}
172
173pub fn get_key_with_mnemonic_path(
175 mnemonic: &str,
176 path: &str,
177) -> Result<KeyPairProperties> {
178 let mnemonic_obj = Mnemonic::parse(mnemonic)
179 .context("Invalid mnemonic phrase")?;
180
181 let master_seed = mnemonic_obj.to_seed("");
182
183 let bip_path = BIP32Path::from_str(path)
184 .map_err(|e| anyhow::anyhow!("Invalid BIP32 path {}: {:?}", path, e))?;
185
186 let derived_private_key = slip10::derive_key_from_path(&master_seed, Curve::Ed25519, &bip_path)
187 .map_err(|e| anyhow::anyhow!("Failed to derive key from path: {:?}", e))?;
188
189 let secret_keypair = {
190 let secret = ed25519_dalek::SigningKey::from_bytes(&derived_private_key.key);
191 let public = secret.verifying_key();
192 (secret, public)
193 };
194
195 let implicit_account_id = hex::encode(secret_keypair.1.as_bytes());
196
197 let public_key_str = format!(
198 "ed25519:{}",
199 bs58::encode(secret_keypair.1.as_bytes()).into_string()
200 );
201
202 let secret_keypair_str = format!(
203 "ed25519:{}",
204 bs58::encode(secret_keypair.0.to_bytes()).into_string()
205 );
206
207 Ok(KeyPairProperties {
208 seed_phrase_hd_path: path.to_string(),
209 master_seed_phrase: mnemonic.to_string(),
210 implicit_account_id,
211 public_key_str,
212 secret_keypair_str,
213 })
214}
215
216pub fn encode_public_key(key: &VerifyingKey) -> String {
218 bs58::encode(key.as_bytes()).into_string()
219}
220
221pub fn encode_private_key(key: &SigningKey) -> String {
223 bs58::encode(key.to_bytes()).into_string()
224}
225
226pub fn encode_public_key_ed25519(key: &VerifyingKey) -> String {
228 format!("ed25519:{}", encode_public_key(key))
229}
230
231pub fn encode_private_key_ed25519(key: &SigningKey) -> String {
233 format!("ed25519:{}", encode_private_key(key))
234}
235
236pub fn decode_public_key(encoded: &str) -> Result<VerifyingKey> {
238 let bytes = bs58::decode(encoded)
239 .into_vec()
240 .context("Base58 decode error")?;
241 let len = bytes.len();
242 let key_bytes: [u8; 32] = bytes
243 .try_into()
244 .map_err(|_| anyhow::anyhow!("Invalid key length: expected 32 bytes, got {}", len))?;
245 VerifyingKey::from_bytes(&key_bytes)
246 .map_err(|e| anyhow::anyhow!("Invalid public key: {}", e))
247}
248
249pub fn decode_public_key_ed25519(encoded: &str) -> Result<VerifyingKey> {
251 let encoded = encoded
252 .strip_prefix("ed25519:")
253 .context("Invalid ed25519 public key format")?;
254 decode_public_key(encoded)
255}
256
257pub fn decode_private_key(encoded: &str) -> Result<SigningKey> {
259 let bytes = bs58::decode(encoded)
260 .into_vec()
261 .context("Base58 decode error")?;
262 let len = bytes.len();
263 let key_bytes: [u8; 32] = bytes
264 .try_into()
265 .map_err(|_| anyhow::anyhow!("Invalid key length: expected 32 bytes, got {}", len))?;
266 Ok(SigningKey::from_bytes(&key_bytes))
267}
268
269pub fn decode_private_key_ed25519(encoded: &str) -> Result<SigningKey> {
271 let encoded = encoded
272 .strip_prefix("ed25519:")
273 .context("Invalid ed25519 private key format")?;
274 decode_private_key(encoded)
275}
276
277pub fn sign_message(key: &SigningKey, message: &[u8]) -> Signature {
279 key.sign(message)
280}
281
282pub fn verify_signature(key: &VerifyingKey, message: &[u8], signature: &Signature) -> bool {
284 key.verify(message, signature).is_ok()
285}
286
287pub fn generate_implicit_account_id(public_key: &VerifyingKey) -> String {
289 hex::encode(public_key.as_bytes())
290}
291
292pub fn get_signer_with_id_key(account_id: &str, key: &str) -> Result<(String, SigningKey, VerifyingKey)> {
295 let account_id_str = account_id.to_string();
296 let secret = decode_private_key_ed25519(key)
297 .or_else(|_| decode_private_key(key))
298 .context("Failed to decode private key")?;
299 let public_key = secret.verifying_key();
300 Ok((account_id_str, secret, public_key))
301}
302
303pub fn get_public_key_from_private(secret_keypair_str: &str) -> Result<PublicKeyInfo> {
306 let signing_key = decode_private_key_ed25519(secret_keypair_str)
307 .or_else(|_| decode_private_key(secret_keypair_str))
308 .context("Failed to decode private key")?;
309 let verifying_key = signing_key.verifying_key();
310 let public_key_str = encode_public_key_ed25519(&verifying_key);
311 let implicit_account_id = generate_implicit_account_id(&verifying_key);
312 Ok(PublicKeyInfo {
313 secret_keypair_str: secret_keypair_str.to_string(),
314 public_key_str,
315 implicit_account_id,
316 })
317}
318
319pub fn get_mnemonic_with_rand(mnemonic: Option<String>) -> Result<KeyPairProperties> {
323 generate_keypair_properties(mnemonic, None)
324}
325
326pub fn generate_keypair(mnemonic: Option<String>) -> Result<KeyPairProperties> {
328 generate_keypair_properties(mnemonic, None)
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334
335 #[test]
336 fn test_generate_mnemonic() -> Result<()> {
337 let mnemonic = generate_mnemonic()?;
338 assert!(!mnemonic.is_empty());
339 let words: Vec<&str> = mnemonic.split_whitespace().collect();
340 assert_eq!(words.len(), 12);
341 Ok(())
342 }
343
344 #[test]
345 fn test_generate_keypair() -> Result<()> {
346 let (signing_key, verifying_key) = generate_keypair_raw()?;
347 let message = b"test message";
348 let signature = sign_message(&signing_key, message);
349 assert!(verify_signature(&verifying_key, message, &signature));
350 Ok(())
351 }
352
353 #[test]
354 fn test_mnemonic_to_keypair() -> Result<()> {
355 let mnemonic_str = generate_mnemonic()?;
356 let mnemonic = mnemonic_from_phrase(&mnemonic_str)?;
357 let (signing_key, verifying_key) = generate_keypair_from_mnemonic(&mnemonic)?;
358 let message = b"test message";
359 let signature = sign_message(&signing_key, message);
360 assert!(verify_signature(&verifying_key, message, &signature));
361 Ok(())
362 }
363
364 #[test]
365 fn test_mnemonic_to_keypair_with_path() -> Result<()> {
366 let mnemonic_str = generate_mnemonic()?;
367 let mnemonic = mnemonic_from_phrase(&mnemonic_str)?;
368 let (signing_key, verifying_key) = generate_keypair_from_mnemonic_with_path(
369 &mnemonic,
370 "m/44'/397'/0'",
371 )?;
372 let message = b"test message";
373 let signature = sign_message(&signing_key, message);
374 assert!(verify_signature(&verifying_key, message, &signature));
375 Ok(())
376 }
377
378 #[test]
379 fn test_encode_decode_keys() -> Result<()> {
380 let (signing_key, verifying_key) = generate_keypair_raw()?;
381 let encoded_priv = encode_private_key(&signing_key);
382 let encoded_pub = encode_public_key(&verifying_key);
383
384 let decoded_priv = decode_private_key(&encoded_priv)?;
385 let decoded_pub = decode_public_key(&encoded_pub)?;
386
387 assert_eq!(signing_key.to_bytes(), decoded_priv.to_bytes());
388 assert_eq!(verifying_key.as_bytes(), decoded_pub.as_bytes());
389 Ok(())
390 }
391
392 #[test]
393 fn test_generate_keypair_properties() -> Result<()> {
394 let kp = generate_keypair_properties(None, None)?;
395 assert!(!kp.master_seed_phrase.is_empty());
396 assert_eq!(kp.seed_phrase_hd_path, "m/44'/397'/0'");
397 assert!(!kp.implicit_account_id.is_empty());
398 assert!(kp.public_key_str.starts_with("ed25519:"));
399 assert!(kp.secret_keypair_str.starts_with("ed25519:"));
400 Ok(())
401 }
402
403 #[test]
404 fn test_get_key_with_mnemonic_path() -> Result<()> {
405 let mnemonic = generate_mnemonic()?;
406 let kp = get_key_with_mnemonic_path(&mnemonic, "m/44'/397'/0'")?;
407 assert_eq!(kp.master_seed_phrase, mnemonic);
408 assert_eq!(kp.seed_phrase_hd_path, "m/44'/397'/0'");
409 assert!(!kp.implicit_account_id.is_empty());
410 Ok(())
411 }
412
413 #[test]
414 fn test_ed25519_format() -> Result<()> {
415 let (signing_key, verifying_key) = generate_keypair_raw()?;
416 let pub_str = encode_public_key_ed25519(&verifying_key);
417 let priv_str = encode_private_key_ed25519(&signing_key);
418
419 assert!(pub_str.starts_with("ed25519:"));
420 assert!(priv_str.starts_with("ed25519:"));
421
422 let decoded_pub = decode_public_key_ed25519(&pub_str)?;
423 let decoded_priv = decode_private_key_ed25519(&priv_str)?;
424
425 assert_eq!(verifying_key.as_bytes(), decoded_pub.as_bytes());
426 assert_eq!(signing_key.to_bytes(), decoded_priv.to_bytes());
427 Ok(())
428 }
429}