1use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, thiserror::Error)]
18pub enum SigningError {
19 #[error("invalid hex encoding: {0}")]
21 HexDecode(String),
22
23 #[error("invalid key format: {0}")]
25 InvalidKey(String),
26
27 #[error("invalid signature format: {0}")]
29 InvalidSignature(String),
30
31 #[error("signature verification failed")]
33 VerificationFailed,
34}
35
36pub struct SigningKeyPair {
45 inner: SigningKey,
46}
47
48impl std::fmt::Debug for SigningKeyPair {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 f.debug_struct("SigningKeyPair")
51 .field("public_key", &self.verifying_key_hex())
52 .finish()
53 }
54}
55
56impl SigningKeyPair {
57 pub fn from_bytes(bytes: &[u8; 32]) -> Self {
59 Self {
60 inner: SigningKey::from_bytes(bytes),
61 }
62 }
63
64 pub fn from_hex(hex: &str) -> Result<Self, SigningError> {
66 let bytes = hex_decode(hex)?;
67 let arr: [u8; 32] = bytes
68 .try_into()
69 .map_err(|_| SigningError::InvalidKey("secret key must be 32 bytes".into()))?;
70 Ok(Self::from_bytes(&arr))
71 }
72
73 pub fn secret_key_hex(&self) -> String {
75 hex_encode(self.inner.as_bytes())
76 }
77
78 pub fn verifying_key(&self) -> VerifyingKey {
80 self.inner.verifying_key()
81 }
82
83 pub fn verifying_key_hex(&self) -> String {
85 hex_encode(self.verifying_key().as_bytes())
86 }
87
88 pub fn sign(&self, message: &[u8]) -> Signature {
90 self.inner.sign(message)
91 }
92}
93
94pub fn generate_keypair() -> (SigningKeyPair, VerifyingKey) {
102 let mut csprng = rand::rngs::OsRng;
103 let signing_key = SigningKey::generate(&mut csprng);
104 let verifying_key = signing_key.verifying_key();
105 (SigningKeyPair { inner: signing_key }, verifying_key)
106}
107
108pub fn sign_manifest(keypair: &SigningKeyPair, manifest_bytes: &[u8]) -> String {
114 let sig = keypair.sign(manifest_bytes);
115 hex_encode(&sig.to_bytes())
116}
117
118pub fn verify_manifest(
120 verifying_key: &VerifyingKey,
121 manifest_bytes: &[u8],
122 signature_hex: &str,
123) -> Result<bool, SigningError> {
124 let sig_bytes = hex_decode(signature_hex)?;
125 let sig_arr: [u8; 64] = sig_bytes
126 .try_into()
127 .map_err(|_| SigningError::InvalidSignature("signature must be 64 bytes".into()))?;
128 let signature = Signature::from_bytes(&sig_arr);
129 Ok(verifying_key.verify(manifest_bytes, &signature).is_ok())
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct SignedManifest {
142 pub manifest: Vec<u8>,
144 pub signature: String,
146 pub public_key: String,
148}
149
150pub fn sign_and_wrap(keypair: &SigningKeyPair, manifest: Vec<u8>) -> SignedManifest {
152 let signature = sign_manifest(keypair, &manifest);
153 let public_key = keypair.verifying_key_hex();
154 SignedManifest {
155 manifest,
156 signature,
157 public_key,
158 }
159}
160
161pub fn verify_signed_manifest(signed: &SignedManifest) -> Result<bool, SigningError> {
164 let pk_bytes = hex_decode(&signed.public_key)?;
165 let pk_arr: [u8; 32] = pk_bytes
166 .try_into()
167 .map_err(|_| SigningError::InvalidKey("public key must be 32 bytes".into()))?;
168 let verifying_key = VerifyingKey::from_bytes(&pk_arr)
169 .map_err(|e| SigningError::InvalidKey(format!("invalid public key: {}", e)))?;
170 verify_manifest(&verifying_key, &signed.manifest, &signed.signature)
171}
172
173pub fn verifying_key_from_hex(hex: &str) -> Result<VerifyingKey, SigningError> {
179 let bytes = hex_decode(hex)?;
180 let arr: [u8; 32] = bytes
181 .try_into()
182 .map_err(|_| SigningError::InvalidKey("public key must be 32 bytes".into()))?;
183 VerifyingKey::from_bytes(&arr)
184 .map_err(|e| SigningError::InvalidKey(format!("invalid public key: {}", e)))
185}
186
187fn hex_encode(bytes: &[u8]) -> String {
192 bytes.iter().map(|b| format!("{:02x}", b)).collect()
193}
194
195fn hex_decode(hex: &str) -> Result<Vec<u8>, SigningError> {
196 if !hex.len().is_multiple_of(2) {
197 return Err(SigningError::HexDecode(
198 "odd number of hex characters".into(),
199 ));
200 }
201 (0..hex.len())
202 .step_by(2)
203 .map(|i| {
204 u8::from_str_radix(&hex[i..i + 2], 16).map_err(|e| {
205 SigningError::HexDecode(format!("invalid hex at position {}: {}", i, e))
206 })
207 })
208 .collect()
209}
210
211#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn test_generate_keypair() {
221 let (kp, vk) = generate_keypair();
222 assert_eq!(kp.verifying_key(), vk);
223 }
224
225 #[test]
226 fn test_sign_and_verify() {
227 let (kp, vk) = generate_keypair();
228 let manifest = b"hello manifest";
229 let sig = sign_manifest(&kp, manifest);
230 let valid = verify_manifest(&vk, manifest, &sig).unwrap();
231 assert!(valid);
232 }
233
234 #[test]
235 fn test_tamper_detection() {
236 let (kp, vk) = generate_keypair();
237 let manifest = b"original manifest";
238 let sig = sign_manifest(&kp, manifest);
239 let valid = verify_manifest(&vk, b"tampered manifest", &sig).unwrap();
240 assert!(!valid, "tampered manifest should fail verification");
241 }
242
243 #[test]
244 fn test_wrong_key_rejection() {
245 let (kp1, _vk1) = generate_keypair();
246 let (_kp2, vk2) = generate_keypair();
247 let manifest = b"manifest for keypair 1";
248 let sig = sign_manifest(&kp1, manifest);
249 let valid = verify_manifest(&vk2, manifest, &sig).unwrap();
250 assert!(!valid, "wrong verifying key should fail");
251 }
252
253 #[test]
254 fn test_signed_manifest_roundtrip() {
255 let (kp, _vk) = generate_keypair();
256 let manifest = b"roundtrip manifest".to_vec();
257 let signed = sign_and_wrap(&kp, manifest.clone());
258 assert_eq!(signed.manifest, manifest);
259 let valid = verify_signed_manifest(&signed).unwrap();
260 assert!(valid);
261 }
262
263 #[test]
264 fn test_signed_manifest_tampered() {
265 let (kp, _vk) = generate_keypair();
266 let manifest = b"original data".to_vec();
267 let mut signed = sign_and_wrap(&kp, manifest);
268 signed.manifest = b"tampered data".to_vec();
269 let valid = verify_signed_manifest(&signed).unwrap();
270 assert!(!valid);
271 }
272
273 #[test]
274 fn test_key_hex_roundtrip() {
275 let (kp, _vk) = generate_keypair();
276 let secret_hex = kp.secret_key_hex();
277 let restored = SigningKeyPair::from_hex(&secret_hex).unwrap();
278 assert_eq!(restored.verifying_key(), kp.verifying_key());
279 }
280
281 #[test]
282 fn test_verifying_key_hex_roundtrip() {
283 let (_kp, vk) = generate_keypair();
284 let hex = hex_encode(vk.as_bytes());
285 let restored = verifying_key_from_hex(&hex).unwrap();
286 assert_eq!(restored, vk);
287 }
288
289 #[test]
290 fn test_invalid_hex_signature() {
291 let (_kp, vk) = generate_keypair();
292 let result = verify_manifest(&vk, b"data", "not_valid_hex!");
293 assert!(result.is_err());
294 }
295
296 #[test]
297 fn test_invalid_hex_key() {
298 let result = SigningKeyPair::from_hex("zzzz");
299 assert!(result.is_err());
300 }
301
302 #[test]
303 fn test_empty_manifest_signing() {
304 let (kp, vk) = generate_keypair();
305 let sig = sign_manifest(&kp, b"");
306 let valid = verify_manifest(&vk, b"", &sig).unwrap();
307 assert!(valid, "empty manifest should sign and verify");
308 }
309
310 #[test]
311 fn test_large_manifest_signing() {
312 let (kp, vk) = generate_keypair();
313 let manifest = vec![0xABu8; 1_000_000];
314 let sig = sign_manifest(&kp, &manifest);
315 let valid = verify_manifest(&vk, &manifest, &sig).unwrap();
316 assert!(valid, "large manifest should sign and verify");
317 }
318
319 #[test]
320 fn test_signature_is_hex_encoded() {
321 let (kp, _vk) = generate_keypair();
322 let sig = sign_manifest(&kp, b"data");
323 assert_eq!(sig.len(), 128);
325 assert!(sig.chars().all(|c| c.is_ascii_hexdigit()));
326 }
327
328 #[test]
329 fn test_signed_manifest_serialization() {
330 let (kp, _vk) = generate_keypair();
331 let signed = sign_and_wrap(&kp, b"json test".to_vec());
332 let json = serde_json::to_string(&signed).unwrap();
333 let deserialized: SignedManifest = serde_json::from_str(&json).unwrap();
334 let valid = verify_signed_manifest(&deserialized).unwrap();
335 assert!(valid, "deserialized signed manifest should verify");
336 }
337}