kobe_sol/
standard_wallet.rs1use alloc::string::String;
7use ed25519_dalek::{SigningKey, VerifyingKey};
8use zeroize::Zeroizing;
9
10use crate::Error;
11
12#[derive(Debug)]
27pub struct StandardWallet {
28 signing_key: SigningKey,
30}
31
32impl StandardWallet {
33 #[cfg(feature = "rand")]
39 pub fn generate() -> Result<Self, Error> {
40 let mut bytes = [0u8; 32];
41 getrandom::fill(&mut bytes)
42 .map_err(|e| Error::Derivation(alloc::format!("random generation failed: {e}")))?;
43 let signing_key = SigningKey::from_bytes(&bytes);
44 bytes.fill(0);
46 Ok(Self { signing_key })
47 }
48
49 #[must_use]
51 pub fn from_private_key(private_key: &[u8; 32]) -> Self {
52 let signing_key = SigningKey::from_bytes(private_key);
53 Self { signing_key }
54 }
55
56 pub fn from_private_key_hex(hex_key: &str) -> Result<Self, Error> {
62 let bytes = hex::decode(hex_key).map_err(|_| Error::InvalidHex)?;
63
64 if bytes.len() != 32 {
65 return Err(Error::Derivation(alloc::format!(
66 "expected 32 bytes, got {}",
67 bytes.len()
68 )));
69 }
70
71 let mut key_bytes = [0u8; 32];
72 key_bytes.copy_from_slice(&bytes);
73 Ok(Self::from_private_key(&key_bytes))
74 }
75
76 #[inline]
78 #[must_use]
79 pub fn address_string(&self) -> String {
80 let verifying_key: VerifyingKey = self.signing_key.verifying_key();
81 bs58::encode(verifying_key.as_bytes()).into_string()
82 }
83
84 #[inline]
86 #[must_use]
87 pub fn private_key_hex(&self) -> Zeroizing<String> {
88 Zeroizing::new(hex::encode(self.signing_key.as_bytes()))
89 }
90
91 #[inline]
93 #[must_use]
94 pub fn public_key_hex(&self) -> String {
95 let verifying_key: VerifyingKey = self.signing_key.verifying_key();
96 hex::encode(verifying_key.as_bytes())
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[cfg(feature = "rand")]
105 #[test]
106 fn test_generate() {
107 let wallet = StandardWallet::generate().unwrap();
108 let address = wallet.address_string();
109
110 assert!(address.len() >= 32 && address.len() <= 44);
112 }
113
114 #[test]
115 fn test_from_private_key() {
116 let key = [1u8; 32];
117 let wallet = StandardWallet::from_private_key(&key);
118 let address = wallet.address_string();
119
120 assert!(address.len() >= 32 && address.len() <= 44);
121 }
122
123 #[test]
124 fn test_from_private_key_hex() {
125 let hex_key = "0101010101010101010101010101010101010101010101010101010101010101";
126 let wallet = StandardWallet::from_private_key_hex(hex_key).unwrap();
127 let address = wallet.address_string();
128
129 assert!(address.len() >= 32 && address.len() <= 44);
130 }
131
132 #[test]
133 fn test_deterministic() {
134 let key = [42u8; 32];
135 let wallet1 = StandardWallet::from_private_key(&key);
136 let wallet2 = StandardWallet::from_private_key(&key);
137
138 assert_eq!(wallet1.address_string(), wallet2.address_string());
139 }
140}