1use ed25519_dalek::{SigningKey, VerifyingKey, Signature, Signer, Verifier};
7use rand::rngs::OsRng;
8use serde::{Deserialize, Serialize};
9use thiserror::Error;
10
11use crate::types::ids::EventId;
12use crate::types::event::Event;
13
14pub struct SigningKeyPair {
16 signing_key: SigningKey,
17}
18
19impl SigningKeyPair {
20 pub fn generate() -> Self {
22 let signing_key = SigningKey::generate(&mut OsRng);
23 Self { signing_key }
24 }
25
26 pub fn from_seed_hex(seed_hex: &str) -> Result<Self, SigningError> {
28 let seed_bytes = hex::decode(seed_hex)
29 .map_err(|e| SigningError::KeyParseError(e.to_string()))?;
30
31 if seed_bytes.len() != 32 {
32 return Err(SigningError::KeyParseError(
33 format!("Seed must be 32 bytes, got {}", seed_bytes.len())
34 ));
35 }
36
37 let mut seed_array = [0u8; 32];
38 seed_array.copy_from_slice(&seed_bytes);
39
40 let signing_key = SigningKey::from_bytes(&seed_array);
41 Ok(Self { signing_key })
42 }
43
44 pub fn seed_hex(&self) -> String {
46 hex::encode(self.signing_key.to_bytes())
47 }
48
49 pub fn public_key_hex(&self) -> String {
51 hex::encode(self.signing_key.verifying_key().to_bytes())
52 }
53
54 pub fn verifying_key(&self) -> VerifyingKey {
56 self.signing_key.verifying_key()
57 }
58
59 pub fn sign(&self, event_id: &EventId) -> Vec<u8> {
61 let signature = self.signing_key.sign(event_id);
62 signature.to_bytes().to_vec()
63 }
64
65 pub fn sign_event(&self, event: &Event) -> Vec<u8> {
67 self.sign(&event.event_id)
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
73#[serde(rename_all = "lowercase")]
74pub enum VerificationPolicy {
75 #[default]
77 Off,
78 Warn,
80 Require,
82}
83
84impl VerificationPolicy {
85 pub fn from_str(s: &str) -> Option<Self> {
87 match s.to_lowercase().as_str() {
88 "off" => Some(VerificationPolicy::Off),
89 "warn" => Some(VerificationPolicy::Warn),
90 "require" => Some(VerificationPolicy::Require),
91 _ => None,
92 }
93 }
94
95 pub fn as_str(&self) -> &'static str {
97 match self {
98 VerificationPolicy::Off => "off",
99 VerificationPolicy::Warn => "warn",
100 VerificationPolicy::Require => "require",
101 }
102 }
103}
104
105#[derive(Debug, Error)]
107pub enum SigningError {
108 #[error("signature missing")]
109 SignatureMissing,
110
111 #[error("invalid signature")]
112 InvalidSignature,
113
114 #[error("public key not found for actor {0}")]
115 PublicKeyNotFound(String),
116
117 #[error("key parse error: {0}")]
118 KeyParseError(String),
119
120 #[error("signature parse error: {0}")]
121 SignatureParseError(String),
122}
123
124pub fn verify_signature(event: &Event, public_key_hex: &str) -> Result<(), SigningError> {
126 let sig_bytes = event.sig.as_ref()
128 .ok_or(SigningError::SignatureMissing)?;
129
130 let pk_bytes = hex::decode(public_key_hex)
132 .map_err(|e| SigningError::KeyParseError(e.to_string()))?;
133
134 if pk_bytes.len() != 32 {
135 return Err(SigningError::KeyParseError(
136 format!("Public key must be 32 bytes, got {}", pk_bytes.len())
137 ));
138 }
139
140 let mut pk_array = [0u8; 32];
141 pk_array.copy_from_slice(&pk_bytes);
142
143 let verifying_key = VerifyingKey::from_bytes(&pk_array)
144 .map_err(|e| SigningError::KeyParseError(e.to_string()))?;
145
146 if sig_bytes.len() != 64 {
148 return Err(SigningError::SignatureParseError(
149 format!("Signature must be 64 bytes, got {}", sig_bytes.len())
150 ));
151 }
152
153 let mut sig_array = [0u8; 64];
154 sig_array.copy_from_slice(sig_bytes);
155
156 let signature = Signature::from_bytes(&sig_array);
157
158 verifying_key.verify(&event.event_id, &signature)
160 .map_err(|_| SigningError::InvalidSignature)
161}
162
163pub fn verify_raw(
165 event_id: &EventId,
166 signature: &[u8],
167 public_key_hex: &str,
168) -> Result<(), SigningError> {
169 let pk_bytes = hex::decode(public_key_hex)
171 .map_err(|e| SigningError::KeyParseError(e.to_string()))?;
172
173 if pk_bytes.len() != 32 {
174 return Err(SigningError::KeyParseError(
175 format!("Public key must be 32 bytes, got {}", pk_bytes.len())
176 ));
177 }
178
179 let mut pk_array = [0u8; 32];
180 pk_array.copy_from_slice(&pk_bytes);
181
182 let verifying_key = VerifyingKey::from_bytes(&pk_array)
183 .map_err(|e| SigningError::KeyParseError(e.to_string()))?;
184
185 if signature.len() != 64 {
187 return Err(SigningError::SignatureParseError(
188 format!("Signature must be 64 bytes, got {}", signature.len())
189 ));
190 }
191
192 let mut sig_array = [0u8; 64];
193 sig_array.copy_from_slice(signature);
194
195 let sig = Signature::from_bytes(&sig_array);
196
197 verifying_key.verify(event_id, &sig)
199 .map_err(|_| SigningError::InvalidSignature)
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use crate::types::event::EventKind;
206
207 #[test]
208 fn test_keypair_generation() {
209 let keypair = SigningKeyPair::generate();
210 let seed = keypair.seed_hex();
211 let pk = keypair.public_key_hex();
212
213 assert_eq!(seed.len(), 64);
215 assert_eq!(pk.len(), 64);
217 }
218
219 #[test]
220 fn test_keypair_from_seed() {
221 let keypair1 = SigningKeyPair::generate();
222 let seed = keypair1.seed_hex();
223
224 let keypair2 = SigningKeyPair::from_seed_hex(&seed).unwrap();
225
226 assert_eq!(keypair1.public_key_hex(), keypair2.public_key_hex());
228 }
229
230 #[test]
231 fn test_sign_and_verify() {
232 let keypair = SigningKeyPair::generate();
233 let event_id: EventId = [42u8; 32];
234
235 let signature = keypair.sign(&event_id);
236
237 assert_eq!(signature.len(), 64);
239
240 let result = verify_raw(&event_id, &signature, &keypair.public_key_hex());
242 assert!(result.is_ok());
243 }
244
245 #[test]
246 fn test_sign_event() {
247 let keypair = SigningKeyPair::generate();
248
249 let mut event = Event::new(
250 [1u8; 32],
251 [2u8; 16],
252 [3u8; 16],
253 1700000000000,
254 None,
255 EventKind::IssueCreated {
256 title: "Test".to_string(),
257 body: "Body".to_string(),
258 labels: vec![],
259 },
260 );
261
262 event.sig = Some(keypair.sign_event(&event));
263
264 let result = verify_signature(&event, &keypair.public_key_hex());
266 assert!(result.is_ok());
267 }
268
269 #[test]
270 fn test_verify_missing_signature() {
271 let keypair = SigningKeyPair::generate();
272
273 let event = Event::new(
274 [1u8; 32],
275 [2u8; 16],
276 [3u8; 16],
277 1700000000000,
278 None,
279 EventKind::CommentAdded { body: "test".to_string() },
280 );
281
282 let result = verify_signature(&event, &keypair.public_key_hex());
283 assert!(matches!(result, Err(SigningError::SignatureMissing)));
284 }
285
286 #[test]
287 fn test_verify_invalid_signature() {
288 let keypair = SigningKeyPair::generate();
289
290 let mut event = Event::new(
291 [1u8; 32],
292 [2u8; 16],
293 [3u8; 16],
294 1700000000000,
295 None,
296 EventKind::CommentAdded { body: "test".to_string() },
297 );
298
299 event.sig = Some(vec![0u8; 64]);
301
302 let result = verify_signature(&event, &keypair.public_key_hex());
303 assert!(matches!(result, Err(SigningError::InvalidSignature)));
304 }
305
306 #[test]
307 fn test_verify_wrong_public_key() {
308 let keypair1 = SigningKeyPair::generate();
309 let keypair2 = SigningKeyPair::generate();
310
311 let mut event = Event::new(
312 [1u8; 32],
313 [2u8; 16],
314 [3u8; 16],
315 1700000000000,
316 None,
317 EventKind::CommentAdded { body: "test".to_string() },
318 );
319
320 event.sig = Some(keypair1.sign_event(&event));
322
323 let result = verify_signature(&event, &keypair2.public_key_hex());
325 assert!(matches!(result, Err(SigningError::InvalidSignature)));
326 }
327
328 #[test]
329 fn test_verification_policy_parse() {
330 assert_eq!(VerificationPolicy::from_str("off"), Some(VerificationPolicy::Off));
331 assert_eq!(VerificationPolicy::from_str("warn"), Some(VerificationPolicy::Warn));
332 assert_eq!(VerificationPolicy::from_str("require"), Some(VerificationPolicy::Require));
333 assert_eq!(VerificationPolicy::from_str("REQUIRE"), Some(VerificationPolicy::Require));
334 assert_eq!(VerificationPolicy::from_str("invalid"), None);
335 }
336}