1use ed25519_dalek::{
4 Signature as DalekSignature, Signer as DalekSigner, SigningKey, Verifier, VerifyingKey,
5};
6use rand_core::OsRng;
7use serde::{Deserialize, Serialize};
8use zeroize::Zeroize;
9
10use crate::error::{Error, Result};
11
12pub trait Signer {
17 fn public_key(&self) -> PublicKey;
18 fn sign(&self, message: &[u8]) -> Result<Signature>;
19}
20
21#[derive(Clone)]
23pub struct Keypair {
24 signing_key: SigningKey,
25}
26
27impl Keypair {
28 pub fn generate() -> Self {
40 let signing_key = SigningKey::generate(&mut OsRng);
41 Self { signing_key }
42 }
43
44 pub fn from_seed(seed: &[u8; 32]) -> Self {
46 let signing_key = SigningKey::from_bytes(seed);
47 Self { signing_key }
48 }
49
50 pub fn from_hex(hex_seed: &str) -> Result<Self> {
52 let hex_seed = hex_seed.strip_prefix("0x").unwrap_or(hex_seed);
53 let bytes = hex::decode(hex_seed).map_err(|e| Error::InvalidHex(e.to_string()))?;
54
55 if bytes.len() != 32 {
56 return Err(Error::InvalidPrivateKey);
57 }
58
59 let mut seed = [0u8; 32];
60 seed.copy_from_slice(&bytes);
61 Ok(Self::from_seed(&seed))
62 }
63
64 pub fn public_key(&self) -> PublicKey {
66 PublicKey {
67 verifying_key: self.signing_key.verifying_key(),
68 }
69 }
70
71 pub fn sign(&self, message: &[u8]) -> Signature {
83 let sig = self.signing_key.sign(message);
84 Signature { inner: sig }
85 }
86
87 pub fn to_hex(&self) -> String {
89 hex::encode(self.signing_key.to_bytes())
90 }
91}
92
93impl Signer for Keypair {
94 fn public_key(&self) -> PublicKey {
95 Keypair::public_key(self)
96 }
97
98 fn sign(&self, message: &[u8]) -> Result<Signature> {
99 Ok(Keypair::sign(self, message))
100 }
101}
102
103impl Drop for Keypair {
104 fn drop(&mut self) {
105 let mut seed = self.signing_key.to_bytes();
108 seed.zeroize();
109 self.signing_key = SigningKey::from_bytes(&seed);
111 }
112}
113
114#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
116#[serde(transparent)]
117pub struct PublicKey {
118 #[serde(with = "pubkey_serde")]
119 verifying_key: VerifyingKey,
120}
121
122mod pubkey_serde {
123 use super::*;
124 use serde::{Deserializer, Serializer};
125
126 pub fn serialize<S>(key: &VerifyingKey, s: S) -> std::result::Result<S::Ok, S::Error>
127 where
128 S: Serializer,
129 {
130 s.serialize_str(&hex::encode(key.to_bytes()))
131 }
132
133 pub fn deserialize<'de, D>(d: D) -> std::result::Result<VerifyingKey, D::Error>
134 where
135 D: Deserializer<'de>,
136 {
137 let hex_str = String::deserialize(d)?;
138 let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str);
139 let bytes = hex::decode(hex_str).map_err(serde::de::Error::custom)?;
140 let bytes: [u8; 32] = bytes
141 .try_into()
142 .map_err(|_| serde::de::Error::custom("public key must be 32 bytes"))?;
143 VerifyingKey::from_bytes(&bytes).map_err(serde::de::Error::custom)
144 }
145}
146
147impl PublicKey {
148 pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self> {
150 let verifying_key =
151 VerifyingKey::from_bytes(bytes).map_err(|e| Error::InvalidPublicKey(e.to_string()))?;
152 Ok(Self { verifying_key })
153 }
154
155 pub fn from_hex(hex_str: &str) -> Result<Self> {
157 let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
158 let bytes = hex::decode(hex_str).map_err(|e| Error::InvalidHex(e.to_string()))?;
159
160 if bytes.len() != 32 {
161 return Err(Error::InvalidPublicKey(format!(
162 "expected 32 bytes, got {}",
163 bytes.len()
164 )));
165 }
166
167 let mut arr = [0u8; 32];
168 arr.copy_from_slice(&bytes);
169 Self::from_bytes(&arr)
170 }
171
172 pub fn verify(&self, message: &[u8], signature: &Signature) -> bool {
187 self.verifying_key.verify(message, &signature.inner).is_ok()
188 }
189
190 pub fn to_hex(&self) -> String {
192 hex::encode(self.verifying_key.to_bytes())
193 }
194
195 pub fn to_hex_prefixed(&self) -> String {
197 format!("0x{}", self.to_hex())
198 }
199
200 pub fn as_bytes(&self) -> &[u8; 32] {
202 self.verifying_key.as_bytes()
203 }
204}
205
206#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
208#[serde(transparent)]
209pub struct Signature {
210 #[serde(with = "sig_serde")]
211 inner: DalekSignature,
212}
213
214mod sig_serde {
215 use super::*;
216 use serde::{Deserializer, Serializer};
217
218 pub fn serialize<S>(sig: &DalekSignature, s: S) -> std::result::Result<S::Ok, S::Error>
219 where
220 S: Serializer,
221 {
222 s.serialize_str(&hex::encode(sig.to_bytes()))
223 }
224
225 pub fn deserialize<'de, D>(d: D) -> std::result::Result<DalekSignature, D::Error>
226 where
227 D: Deserializer<'de>,
228 {
229 let hex_str = String::deserialize(d)?;
230 let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str);
231 let bytes = hex::decode(hex_str).map_err(serde::de::Error::custom)?;
232 let bytes: [u8; 64] = bytes
233 .try_into()
234 .map_err(|_| serde::de::Error::custom("signature must be 64 bytes"))?;
235 Ok(DalekSignature::from_bytes(&bytes))
236 }
237}
238
239impl Signature {
240 pub fn from_bytes(bytes: &[u8; 64]) -> Self {
242 Self {
243 inner: DalekSignature::from_bytes(bytes),
244 }
245 }
246
247 pub fn from_hex(hex_str: &str) -> Result<Self> {
249 let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
250 let bytes = hex::decode(hex_str).map_err(|e| Error::InvalidHex(e.to_string()))?;
251
252 if bytes.len() != 64 {
253 return Err(Error::InvalidSignature);
254 }
255
256 let mut arr = [0u8; 64];
257 arr.copy_from_slice(&bytes);
258 Ok(Self::from_bytes(&arr))
259 }
260
261 pub fn to_hex(&self) -> String {
263 hex::encode(self.inner.to_bytes())
264 }
265
266 pub fn to_hex_prefixed(&self) -> String {
268 format!("0x{}", self.to_hex())
269 }
270
271 pub fn to_bytes(&self) -> [u8; 64] {
273 self.inner.to_bytes()
274 }
275}
276
277pub fn verify_signature(public_key: &PublicKey, message: &[u8], signature: &Signature) -> bool {
279 public_key.verify(message, signature)
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285
286 #[test]
287 fn test_sign_verify() {
288 let keypair = Keypair::generate();
289 let message = b"Hello, Clawdstrike!";
290
291 let signature = keypair.sign(message);
292 assert!(keypair.public_key().verify(message, &signature));
293 }
294
295 #[test]
296 fn test_sign_verify_wrong_message() {
297 let keypair = Keypair::generate();
298 let signature = keypair.sign(b"Hello, Clawdstrike!");
299 assert!(!keypair.public_key().verify(b"Wrong message", &signature));
300 }
301
302 #[test]
303 fn test_keypair_from_seed() {
304 let seed = [42u8; 32];
305 let kp1 = Keypair::from_seed(&seed);
306 let kp2 = Keypair::from_seed(&seed);
307
308 assert_eq!(kp1.public_key().to_hex(), kp2.public_key().to_hex());
309 }
310
311 #[test]
312 fn test_hex_roundtrip() {
313 let keypair = Keypair::generate();
314 let pubkey_hex = keypair.public_key().to_hex();
315 let restored = PublicKey::from_hex(&pubkey_hex).unwrap();
316
317 assert_eq!(keypair.public_key(), restored);
318 }
319
320 #[test]
321 fn test_signature_hex_roundtrip() {
322 let keypair = Keypair::generate();
323 let signature = keypair.sign(b"test");
324 let sig_hex = signature.to_hex();
325 let restored = Signature::from_hex(&sig_hex).unwrap();
326
327 assert_eq!(signature.to_bytes(), restored.to_bytes());
328 }
329
330 #[test]
331 fn test_serde_roundtrip() {
332 let keypair = Keypair::generate();
333 let pubkey = keypair.public_key();
334 let signature = keypair.sign(b"test");
335
336 let pubkey_json = serde_json::to_string(&pubkey).unwrap();
337 let sig_json = serde_json::to_string(&signature).unwrap();
338
339 let pubkey_restored: PublicKey = serde_json::from_str(&pubkey_json).unwrap();
340 let sig_restored: Signature = serde_json::from_str(&sig_json).unwrap();
341
342 assert_eq!(pubkey, pubkey_restored);
343 assert!(pubkey.verify(b"test", &sig_restored));
344 }
345}