1use crate::error::{Result, SignError};
4use ed25519_dalek::{SigningKey, VerifyingKey, Signer as DalekSigner};
5use rand::rngs::OsRng;
6use std::fs;
7use std::path::Path;
8
9#[derive(Debug)]
11pub struct KeyPair {
12 signing_key: SigningKey,
13}
14
15impl KeyPair {
16 pub fn generate() -> Self {
18 let signing_key = SigningKey::generate(&mut OsRng);
19 Self { signing_key }
20 }
21
22 pub fn from_bytes(secret_bytes: &[u8; 32]) -> Self {
24 let signing_key = SigningKey::from_bytes(secret_bytes);
25 Self { signing_key }
26 }
27
28 pub fn secret_bytes(&self) -> [u8; 32] {
30 self.signing_key.to_bytes()
31 }
32
33 pub fn public_key(&self) -> PublicKey {
35 PublicKey {
36 verifying_key: self.signing_key.verifying_key(),
37 }
38 }
39
40 pub fn sign(&self, message: &[u8]) -> [u8; 64] {
42 let signature = self.signing_key.sign(message);
43 signature.to_bytes()
44 }
45
46 pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
53 use base64::Engine;
54 let engine = base64::engine::general_purpose::STANDARD;
55
56 let secret_b64 = engine.encode(self.signing_key.to_bytes());
57 let public_b64 = engine.encode(self.public_key().as_bytes());
58
59 let content = format!(
60 "RUST-SIGN PRIVATE KEY\n{}\n{}\n",
61 secret_b64, public_b64
62 );
63
64 fs::write(path, content)?;
65 Ok(())
66 }
67
68 pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
70 use base64::Engine;
71 let engine = base64::engine::general_purpose::STANDARD;
72
73 let content = fs::read_to_string(path)?;
74 let lines: Vec<&str> = content.lines().collect();
75
76 if lines.len() < 2 || lines[0] != "RUST-SIGN PRIVATE KEY" {
77 return Err(SignError::InvalidKey(
78 "Invalid key file format".to_string(),
79 ));
80 }
81
82 let secret_bytes = engine.decode(lines[1])?;
83 if secret_bytes.len() != 32 {
84 return Err(SignError::InvalidKey(format!(
85 "Invalid secret key length: expected 32, got {}",
86 secret_bytes.len()
87 )));
88 }
89
90 let mut arr = [0u8; 32];
91 arr.copy_from_slice(&secret_bytes);
92 Ok(Self::from_bytes(&arr))
93 }
94}
95
96#[derive(Debug, Clone)]
98pub struct PublicKey {
99 verifying_key: VerifyingKey,
100}
101
102impl PublicKey {
103 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
105 if bytes.len() != 32 {
106 return Err(SignError::InvalidKey(format!(
107 "Invalid public key length: expected 32, got {}",
108 bytes.len()
109 )));
110 }
111
112 let mut arr = [0u8; 32];
113 arr.copy_from_slice(bytes);
114 let verifying_key = VerifyingKey::from_bytes(&arr)?;
115 Ok(Self { verifying_key })
116 }
117
118 pub fn as_bytes(&self) -> [u8; 32] {
120 self.verifying_key.to_bytes()
121 }
122
123 pub fn to_base64(&self) -> String {
125 use base64::Engine;
126 base64::engine::general_purpose::STANDARD.encode(self.as_bytes())
127 }
128
129 pub fn from_base64(s: &str) -> Result<Self> {
131 use base64::Engine;
132 let bytes = base64::engine::general_purpose::STANDARD.decode(s)?;
133 Self::from_bytes(&bytes)
134 }
135
136 pub fn verify(&self, message: &[u8], signature: &[u8; 64]) -> Result<()> {
138 use ed25519_dalek::Signature;
139 let sig = Signature::from_bytes(signature);
140 self.verifying_key.verify_strict(message, &sig)?;
141 Ok(())
142 }
143
144 pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
146 use base64::Engine;
147 let engine = base64::engine::general_purpose::STANDARD;
148
149 let public_b64 = engine.encode(self.as_bytes());
150 let content = format!("RUST-SIGN PUBLIC KEY\n{}\n", public_b64);
151
152 fs::write(path, content)?;
153 Ok(())
154 }
155
156 pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
158 use base64::Engine;
159 let engine = base64::engine::general_purpose::STANDARD;
160
161 let content = fs::read_to_string(path)?;
162 let lines: Vec<&str> = content.lines().collect();
163
164 if lines.len() < 2 || lines[0] != "RUST-SIGN PUBLIC KEY" {
165 return Err(SignError::InvalidKey(
166 "Invalid public key file format".to_string(),
167 ));
168 }
169
170 let public_bytes = engine.decode(lines[1])?;
171 Self::from_bytes(&public_bytes)
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_keypair_generation() {
181 let keypair = KeyPair::generate();
182 let public_key = keypair.public_key();
183
184 let message = b"Test message";
186 let signature = keypair.sign(message);
187
188 assert!(public_key.verify(message, &signature).is_ok());
189 }
190
191 #[test]
192 fn test_keypair_roundtrip() {
193 let keypair = KeyPair::generate();
194 let secret_bytes = keypair.secret_bytes();
195
196 let restored = KeyPair::from_bytes(&secret_bytes);
197 assert_eq!(keypair.secret_bytes(), restored.secret_bytes());
198 }
199
200 #[test]
201 fn test_invalid_signature_fails() {
202 let keypair = KeyPair::generate();
203 let other_keypair = KeyPair::generate();
204
205 let message = b"Test message";
206 let signature = other_keypair.sign(message);
207
208 assert!(keypair.public_key().verify(message, &signature).is_err());
210 }
211
212 #[test]
213 fn test_public_key_base64_roundtrip() {
214 let keypair = KeyPair::generate();
215 let public_key = keypair.public_key();
216
217 let encoded = public_key.to_base64();
218 let decoded = PublicKey::from_base64(&encoded).unwrap();
219
220 assert_eq!(public_key.as_bytes(), decoded.as_bytes());
221 }
222}
223