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 public_key_hex(&self) -> String {
75 self.address_hex()
76 }
77
78 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
83 let secret = self.signing_key.to_bytes();
84 let public = self.signing_key.verifying_key().to_bytes();
85 let mut bytes = [0u8; 64];
86 bytes[..32].copy_from_slice(&secret);
87 bytes[32..].copy_from_slice(&public);
88 let json = serde_json::to_string(&bytes.as_slice())
89 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
90 std::fs::write(path, json)
91 }
92
93 pub fn read_from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
98 let path = path.as_ref();
99 let data = std::fs::read_to_string(path)?;
100 let bytes: Vec<u8> = serde_json::from_str(&data)
101 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
102 if bytes.len() < 32 {
103 return Err(std::io::Error::new(
104 std::io::ErrorKind::InvalidData,
105 format!("keystore too short: {} bytes (need ≥32)", bytes.len()),
106 ));
107 }
108 let mut secret = [0u8; 32];
109 secret.copy_from_slice(&bytes[..32]);
110 Ok(Self::from_bytes(secret))
111 }
112}
113
114impl std::fmt::Debug for Keypair {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 f.debug_struct("Keypair").field("address", &self.address()).finish_non_exhaustive()
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_generate_and_sign() {
126 let keypair = Keypair::generate();
127 let message = b"test message";
128 let signature = keypair.sign(message);
129 assert_eq!(signature.len(), 64); }
131
132 #[test]
133 fn test_from_hex() {
134 let hex = "0000000000000000000000000000000000000000000000000000000000000001";
135 let keypair = Keypair::from_hex(hex).unwrap();
136 assert_eq!(keypair.public_key().len(), 32);
137 }
138
139 #[test]
140 fn test_from_hex_with_prefix() {
141 let hex = "0x0000000000000000000000000000000000000000000000000000000000000001";
142 let keypair = Keypair::from_hex(hex).unwrap();
143 assert_eq!(keypair.public_key().len(), 32);
144 }
145}