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_bytes(bytes: &[u8; 32]) -> Self {
52 let signing_key = SigningKey::from_bytes(bytes);
53 Self { signing_key }
54 }
55
56 pub fn from_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_bytes(&key_bytes))
74 }
75
76 #[inline]
78 #[must_use]
79 pub fn address(&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 secret_bytes(&self) -> Zeroizing<[u8; 32]> {
88 Zeroizing::new(*self.signing_key.as_bytes())
89 }
90
91 #[inline]
93 #[must_use]
94 pub fn secret_hex(&self) -> Zeroizing<String> {
95 Zeroizing::new(hex::encode(self.signing_key.as_bytes()))
96 }
97
98 #[inline]
100 #[must_use]
101 pub fn pubkey_hex(&self) -> String {
102 let verifying_key: VerifyingKey = self.signing_key.verifying_key();
103 hex::encode(verifying_key.as_bytes())
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[cfg(feature = "rand")]
112 #[test]
113 fn test_generate() {
114 let wallet = StandardWallet::generate().unwrap();
115 let address = wallet.address();
116
117 assert!(address.len() >= 32 && address.len() <= 44);
119 }
120
121 #[test]
122 fn test_from_bytes() {
123 let key = [1u8; 32];
124 let wallet = StandardWallet::from_bytes(&key);
125 let address = wallet.address();
126
127 assert!(address.len() >= 32 && address.len() <= 44);
128 }
129
130 #[test]
131 fn test_from_hex() {
132 let hex_key = "0101010101010101010101010101010101010101010101010101010101010101";
133 let wallet = StandardWallet::from_hex(hex_key).unwrap();
134 let address = wallet.address();
135
136 assert!(address.len() >= 32 && address.len() <= 44);
137 }
138
139 #[test]
140 fn test_deterministic() {
141 let key = [42u8; 32];
142 let wallet1 = StandardWallet::from_bytes(&key);
143 let wallet2 = StandardWallet::from_bytes(&key);
144
145 assert_eq!(wallet1.address(), wallet2.address());
146 }
147}