bullet_rust_sdk/
keypair.rs1use crate::errors::{SDKError, SDKResult};
4
5#[derive(Clone)]
14pub struct Keypair {
15 signing_key: ed25519_dalek::SigningKey,
16}
17
18impl Keypair {
19 pub fn from_bytes(secret_key: [u8; 32]) -> Self {
21 let signing_key = ed25519_dalek::SigningKey::from_bytes(&secret_key);
22 Self { signing_key }
23 }
24
25 pub fn from_hex(hex: &str) -> SDKResult<Self> {
29 let hex = hex.strip_prefix("0x").unwrap_or(hex);
30 let bytes: [u8; 32] = hex::decode(hex)
31 .map_err(|e| SDKError::InvalidPrivateKey(e.to_string()))?
32 .try_into()
33 .map_err(|_| SDKError::InvalidPrivateKey("Expected 32 bytes".into()))?;
34 Ok(Self::from_bytes(bytes))
35 }
36
37 pub fn generate() -> Self {
41 use ed25519_dalek::SigningKey;
42 use rand::rngs::OsRng;
43 let signing_key = SigningKey::generate(&mut OsRng);
44 Self { signing_key }
45 }
46
47 pub fn sign(&self, message: &[u8]) -> Vec<u8> {
49 use ed25519_dalek::Signer;
50 let signature = self.signing_key.sign(message);
51 signature.to_bytes().to_vec()
52 }
53
54 pub fn public_key(&self) -> Vec<u8> {
56 self.signing_key.verifying_key().as_bytes().to_vec()
57 }
58
59 pub fn address(&self) -> String {
64 let pk_bytes: [u8; 32] = self.signing_key.verifying_key().to_bytes();
65 bullet_exchange_interface::address::Address(pk_bytes).to_string()
66 }
67
68 pub fn address_hex(&self) -> String {
70 hex::encode(self.public_key())
71 }
72
73 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
78 let secret = self.signing_key.to_bytes();
79 let public = self.signing_key.verifying_key().to_bytes();
80 let mut bytes = [0u8; 64];
81 bytes[..32].copy_from_slice(&secret);
82 bytes[32..].copy_from_slice(&public);
83 let json = serde_json::to_string(&bytes.as_slice())
84 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
85 std::fs::write(path, json)
86 }
87
88 pub fn read_from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
93 let path = path.as_ref();
94 let data = std::fs::read_to_string(path)?;
95 let bytes: Vec<u8> = serde_json::from_str(&data)
96 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
97 if bytes.len() < 32 {
98 return Err(std::io::Error::new(
99 std::io::ErrorKind::InvalidData,
100 format!("keystore too short: {} bytes (need ≥32)", bytes.len()),
101 ));
102 }
103 let mut secret = [0u8; 32];
104 secret.copy_from_slice(&bytes[..32]);
105 Ok(Self::from_bytes(secret))
106 }
107}
108
109impl std::fmt::Debug for Keypair {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 f.debug_struct("Keypair").field("address", &self.address()).finish_non_exhaustive()
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_generate_and_sign() {
121 let keypair = Keypair::generate();
122 let message = b"test message";
123 let signature = keypair.sign(message);
124 assert_eq!(signature.len(), 64); }
126
127 #[test]
128 fn test_from_hex() {
129 let hex = "0000000000000000000000000000000000000000000000000000000000000001";
130 let keypair = Keypair::from_hex(hex).unwrap();
131 assert_eq!(keypair.public_key().len(), 32);
132 }
133
134 #[test]
135 fn test_from_hex_with_prefix() {
136 let hex = "0x0000000000000000000000000000000000000000000000000000000000000001";
137 let keypair = Keypair::from_hex(hex).unwrap();
138 assert_eq!(keypair.public_key().len(), 32);
139 }
140}