1use crate::error::{PachaError, Result};
36use serde::{Deserialize, Serialize};
37use std::collections::HashMap;
38use std::fmt;
39use std::path::Path;
40use std::time::{SystemTime, UNIX_EPOCH};
41
42#[derive(Clone)]
51pub struct SigningKey {
52 #[cfg(feature = "signing")]
53 inner: ed25519_dalek::SigningKey,
54 #[cfg(not(feature = "signing"))]
55 bytes: [u8; 32],
56}
57
58impl SigningKey {
59 #[must_use]
61 pub fn generate() -> Self {
62 #[cfg(feature = "signing")]
63 {
64 use rand::rngs::OsRng;
65 Self { inner: ed25519_dalek::SigningKey::generate(&mut OsRng) }
66 }
67 #[cfg(not(feature = "signing"))]
68 {
69 use std::collections::hash_map::RandomState;
70 use std::hash::{BuildHasher, Hasher};
71
72 let mut bytes = [0u8; 32];
73 let hasher_state = RandomState::new();
74
75 for (i, byte) in bytes.iter_mut().enumerate() {
76 let mut hasher = hasher_state.build_hasher();
77 hasher.write_usize(i);
78 hasher.write_u64(
79 SystemTime::now()
80 .duration_since(UNIX_EPOCH)
81 .map(|d| d.as_nanos() as u64)
82 .unwrap_or(0),
83 );
84 *byte = (hasher.finish() & 0xFF) as u8;
85 }
86
87 Self { bytes }
88 }
89 }
90
91 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
97 if bytes.len() != 32 {
98 return Err(PachaError::Validation(format!(
99 "Invalid key length: expected 32, got {}",
100 bytes.len()
101 )));
102 }
103
104 #[cfg(feature = "signing")]
105 {
106 let mut key_bytes = [0u8; 32];
107 key_bytes.copy_from_slice(bytes);
108 Ok(Self { inner: ed25519_dalek::SigningKey::from_bytes(&key_bytes) })
109 }
110 #[cfg(not(feature = "signing"))]
111 {
112 let mut key_bytes = [0u8; 32];
113 key_bytes.copy_from_slice(bytes);
114 Ok(Self { bytes: key_bytes })
115 }
116 }
117
118 #[must_use]
120 pub fn as_bytes(&self) -> &[u8; 32] {
121 #[cfg(feature = "signing")]
122 {
123 self.inner.as_bytes()
124 }
125 #[cfg(not(feature = "signing"))]
126 {
127 &self.bytes
128 }
129 }
130
131 #[must_use]
133 pub fn verifying_key(&self) -> VerifyingKey {
134 #[cfg(feature = "signing")]
135 {
136 VerifyingKey { inner: self.inner.verifying_key() }
137 }
138 #[cfg(not(feature = "signing"))]
139 {
140 let mut public = [0u8; 32];
142 let hash = blake3::hash(&self.bytes);
143 public.copy_from_slice(&hash.as_bytes()[..32]);
144 VerifyingKey { bytes: public }
145 }
146 }
147
148 #[must_use]
150 pub fn sign(&self, message: &[u8]) -> Signature {
151 #[cfg(feature = "signing")]
152 {
153 use ed25519_dalek::Signer;
154 let sig = self.inner.sign(message);
155 Signature { bytes: sig.to_bytes() }
156 }
157 #[cfg(not(feature = "signing"))]
158 {
159 let mut hasher = blake3::Hasher::new();
161 hasher.update(&self.bytes);
162 hasher.update(message);
163 let r_hash = hasher.finalize();
164
165 let mut hasher2 = blake3::Hasher::new();
166 hasher2.update(r_hash.as_bytes());
167 hasher2.update(&self.verifying_key().bytes);
168 hasher2.update(message);
169 let s_hash = hasher2.finalize();
170
171 let mut signature_bytes = [0u8; 64];
172 signature_bytes[..32].copy_from_slice(r_hash.as_bytes());
173 signature_bytes[32..].copy_from_slice(s_hash.as_bytes());
174
175 Signature { bytes: signature_bytes }
176 }
177 }
178
179 #[must_use]
181 pub fn to_pem(&self) -> String {
182 let encoded = base64_encode(self.as_bytes());
183 format!(
184 "-----BEGIN PACHA ED25519 SIGNING KEY-----\n{encoded}\n-----END PACHA ED25519 SIGNING KEY-----\n"
185 )
186 }
187
188 pub fn from_pem(pem: &str) -> Result<Self> {
194 let pem = pem.trim();
195
196 let (start, end) = if pem.contains("ED25519") {
198 ("-----BEGIN PACHA ED25519 SIGNING KEY-----", "-----END PACHA ED25519 SIGNING KEY-----")
199 } else {
200 ("-----BEGIN PACHA SIGNING KEY-----", "-----END PACHA SIGNING KEY-----")
201 };
202
203 if !pem.starts_with(start) || !pem.ends_with(end) {
204 return Err(PachaError::Validation("Invalid PEM format".to_string()));
205 }
206
207 let content = pem.trim_start_matches(start).trim_end_matches(end).trim().replace('\n', "");
208
209 let bytes = base64_decode(&content)?;
210 Self::from_bytes(&bytes)
211 }
212}
213
214impl fmt::Debug for SigningKey {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 write!(f, "SigningKey([REDACTED])")
217 }
218}
219
220#[derive(Clone, PartialEq, Eq)]
222pub struct VerifyingKey {
223 #[cfg(feature = "signing")]
224 inner: ed25519_dalek::VerifyingKey,
225 #[cfg(not(feature = "signing"))]
226 bytes: [u8; 32],
227}
228
229impl fmt::Debug for VerifyingKey {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 write!(f, "VerifyingKey({})", self.to_hex())
232 }
233}
234
235impl Serialize for VerifyingKey {
236 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
237 where
238 S: serde::Serializer,
239 {
240 serializer.serialize_str(&self.to_hex())
241 }
242}
243
244impl<'de> Deserialize<'de> for VerifyingKey {
245 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
246 where
247 D: serde::Deserializer<'de>,
248 {
249 let hex = String::deserialize(deserializer)?;
250 Self::from_hex(&hex).map_err(serde::de::Error::custom)
251 }
252}
253
254impl VerifyingKey {
255 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
261 if bytes.len() != 32 {
262 return Err(PachaError::Validation(format!(
263 "Invalid key length: expected 32, got {}",
264 bytes.len()
265 )));
266 }
267
268 #[cfg(feature = "signing")]
269 {
270 let mut key_bytes = [0u8; 32];
271 key_bytes.copy_from_slice(bytes);
272 let inner = ed25519_dalek::VerifyingKey::from_bytes(&key_bytes)
273 .map_err(|e| PachaError::Validation(format!("Invalid Ed25519 public key: {e}")))?;
274 Ok(Self { inner })
275 }
276 #[cfg(not(feature = "signing"))]
277 {
278 let mut key_bytes = [0u8; 32];
279 key_bytes.copy_from_slice(bytes);
280 Ok(Self { bytes: key_bytes })
281 }
282 }
283
284 #[must_use]
286 pub fn as_bytes(&self) -> &[u8; 32] {
287 #[cfg(feature = "signing")]
288 {
289 self.inner.as_bytes()
290 }
291 #[cfg(not(feature = "signing"))]
292 {
293 &self.bytes
294 }
295 }
296
297 pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<()> {
299 #[cfg(feature = "signing")]
300 {
301 use ed25519_dalek::Verifier;
302 let sig = ed25519_dalek::Signature::from_bytes(&signature.bytes);
303 self.inner.verify(message, &sig).map_err(|_| PachaError::SignatureInvalid)
304 }
305 #[cfg(not(feature = "signing"))]
306 {
307 let r = &signature.bytes[..32];
309 let s = &signature.bytes[32..];
310
311 let mut hasher = blake3::Hasher::new();
312 hasher.update(r);
313 hasher.update(&self.bytes);
314 hasher.update(message);
315 let expected_s = hasher.finalize();
316
317 if s != expected_s.as_bytes() {
318 return Err(PachaError::SignatureInvalid);
319 }
320
321 Ok(())
322 }
323 }
324
325 #[must_use]
327 pub fn to_hex(&self) -> String {
328 hex_encode(self.as_bytes())
329 }
330
331 pub fn from_hex(hex: &str) -> Result<Self> {
337 let bytes = hex_decode(hex)?;
338 Self::from_bytes(&bytes)
339 }
340
341 #[must_use]
343 pub fn to_pem(&self) -> String {
344 let encoded = base64_encode(self.as_bytes());
345 format!(
346 "-----BEGIN PACHA ED25519 VERIFYING KEY-----\n{encoded}\n-----END PACHA ED25519 VERIFYING KEY-----\n"
347 )
348 }
349
350 pub fn from_pem(pem: &str) -> Result<Self> {
356 let pem = pem.trim();
357
358 let (start, end) = if pem.contains("ED25519") {
360 (
361 "-----BEGIN PACHA ED25519 VERIFYING KEY-----",
362 "-----END PACHA ED25519 VERIFYING KEY-----",
363 )
364 } else {
365 ("-----BEGIN PACHA VERIFYING KEY-----", "-----END PACHA VERIFYING KEY-----")
366 };
367
368 if !pem.starts_with(start) || !pem.ends_with(end) {
369 return Err(PachaError::Validation("Invalid PEM format".to_string()));
370 }
371
372 let content = pem.trim_start_matches(start).trim_end_matches(end).trim().replace('\n', "");
373
374 let bytes = base64_decode(&content)?;
375 Self::from_bytes(&bytes)
376 }
377}
378
379#[derive(Debug, Clone, PartialEq, Eq)]
385pub struct Signature {
386 bytes: [u8; 64],
388}
389
390impl Serialize for Signature {
391 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
392 where
393 S: serde::Serializer,
394 {
395 serializer.serialize_str(&self.to_hex())
396 }
397}
398
399impl<'de> Deserialize<'de> for Signature {
400 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
401 where
402 D: serde::Deserializer<'de>,
403 {
404 let hex = String::deserialize(deserializer)?;
405 Self::from_hex(&hex).map_err(serde::de::Error::custom)
406 }
407}
408
409impl Signature {
410 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
416 if bytes.len() != 64 {
417 return Err(PachaError::Validation(format!(
418 "Invalid signature length: expected 64, got {}",
419 bytes.len()
420 )));
421 }
422 let mut sig_bytes = [0u8; 64];
423 sig_bytes.copy_from_slice(bytes);
424 Ok(Self { bytes: sig_bytes })
425 }
426
427 #[must_use]
429 pub fn as_bytes(&self) -> &[u8; 64] {
430 &self.bytes
431 }
432
433 #[must_use]
435 pub fn to_hex(&self) -> String {
436 hex_encode(&self.bytes)
437 }
438
439 pub fn from_hex(hex: &str) -> Result<Self> {
445 let bytes = hex_decode(hex)?;
446 Self::from_bytes(&bytes)
447 }
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize)]
456pub struct ModelSignature {
457 pub content_hash: String,
459 pub signature: String,
461 pub signer_key: String,
463 pub signer_id: Option<String>,
465 pub timestamp: u64,
467 pub algorithm: String,
469}
470
471impl ModelSignature {
472 #[must_use]
474 pub fn new(
475 content_hash: String,
476 signature: Signature,
477 signer_key: &VerifyingKey,
478 signer_id: Option<String>,
479 ) -> Self {
480 Self {
481 content_hash,
482 signature: signature.to_hex(),
483 signer_key: signer_key.to_hex(),
484 signer_id,
485 timestamp: SystemTime::now()
486 .duration_since(UNIX_EPOCH)
487 .map(|d| d.as_secs())
488 .unwrap_or(0),
489 algorithm: "ed25519-blake3".to_string(),
490 }
491 }
492
493 pub fn verify(&self, model_data: &[u8]) -> Result<()> {
499 let actual_hash = blake3::hash(model_data);
501 let actual_hex = hex_encode(actual_hash.as_bytes());
502
503 if actual_hex != self.content_hash {
504 return Err(PachaError::HashMismatch {
505 expected: self.content_hash.clone(),
506 actual: actual_hex,
507 });
508 }
509
510 let signature = Signature::from_hex(&self.signature)?;
512 let signer_key = VerifyingKey::from_hex(&self.signer_key)?;
513
514 signer_key.verify(self.content_hash.as_bytes(), &signature)
516 }
517
518 pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
524 let json = serde_json::to_string_pretty(self)?;
525 std::fs::write(path, json)?;
526 Ok(())
527 }
528
529 pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
535 let json = std::fs::read_to_string(path)?;
536 let sig: Self = serde_json::from_str(&json)?;
537 Ok(sig)
538 }
539}
540
541#[derive(Debug, Clone, Default, Serialize, Deserialize)]
547pub struct Keyring {
548 keys: HashMap<String, String>,
550 default_key: Option<String>,
552}
553
554impl Keyring {
555 #[must_use]
557 pub fn new() -> Self {
558 Self::default()
559 }
560
561 pub fn add(&mut self, name: impl Into<String>, key: &VerifyingKey) {
563 self.keys.insert(name.into(), key.to_hex());
564 }
565
566 pub fn get(&self, name: &str) -> Result<VerifyingKey> {
572 let hex = self.keys.get(name).ok_or_else(|| PachaError::NotFound {
573 kind: "key".to_string(),
574 name: name.to_string(),
575 version: "n/a".to_string(),
576 })?;
577 VerifyingKey::from_hex(hex)
578 }
579
580 pub fn remove(&mut self, name: &str) -> bool {
582 self.keys.remove(name).is_some()
583 }
584
585 #[must_use]
587 pub fn list(&self) -> Vec<&str> {
588 self.keys.keys().map(String::as_str).collect()
589 }
590
591 pub fn set_default(&mut self, name: impl Into<String>) {
593 self.default_key = Some(name.into());
594 }
595
596 pub fn default_key(&self) -> Result<VerifyingKey> {
602 let name = self
603 .default_key
604 .as_ref()
605 .ok_or_else(|| PachaError::Validation("No default key set".to_string()))?;
606 self.get(name)
607 }
608
609 #[must_use]
611 pub fn is_empty(&self) -> bool {
612 self.keys.is_empty()
613 }
614
615 #[must_use]
617 pub fn len(&self) -> usize {
618 self.keys.len()
619 }
620
621 pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
627 let json = serde_json::to_string_pretty(self)?;
628 std::fs::write(path, json)?;
629 Ok(())
630 }
631
632 pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
638 let json = std::fs::read_to_string(path)?;
639 let keyring: Self = serde_json::from_str(&json)?;
640 Ok(keyring)
641 }
642}
643
644pub fn sign_model(model_data: &[u8], signing_key: &SigningKey) -> Result<ModelSignature> {
654 sign_model_with_id(model_data, signing_key, None)
655}
656
657pub fn sign_model_with_id(
663 model_data: &[u8],
664 signing_key: &SigningKey,
665 signer_id: Option<String>,
666) -> Result<ModelSignature> {
667 let content_hash = blake3::hash(model_data);
669 let content_hex = hex_encode(content_hash.as_bytes());
670
671 let signature = signing_key.sign(content_hex.as_bytes());
673
674 Ok(ModelSignature::new(content_hex, signature, &signing_key.verifying_key(), signer_id))
675}
676
677pub fn verify_model(model_data: &[u8], signature: &ModelSignature) -> Result<()> {
683 signature.verify(model_data)
684}
685
686pub fn verify_model_with_key(
692 model_data: &[u8],
693 signature: &ModelSignature,
694 expected_key: &VerifyingKey,
695) -> Result<()> {
696 signature.verify(model_data)?;
698
699 if signature.signer_key != expected_key.to_hex() {
701 return Err(PachaError::Validation(
702 "Signature was not created by expected key".to_string(),
703 ));
704 }
705
706 Ok(())
707}
708
709fn hex_encode(bytes: &[u8]) -> String {
714 bytes.iter().map(|b| format!("{b:02x}")).collect()
715}
716
717fn hex_decode(hex: &str) -> Result<Vec<u8>> {
718 if hex.len() % 2 != 0 {
719 return Err(PachaError::Validation("Invalid hex length".to_string()));
720 }
721
722 (0..hex.len())
723 .step_by(2)
724 .map(|i| {
725 u8::from_str_radix(&hex[i..i + 2], 16)
726 .map_err(|_| PachaError::Validation("Invalid hex character".to_string()))
727 })
728 .collect()
729}
730
731fn base64_encode(bytes: &[u8]) -> String {
732 const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
733
734 let mut result = String::new();
735 let mut i = 0;
736
737 while i < bytes.len() {
738 let b0 = bytes[i];
739 let b1 = bytes.get(i + 1).copied().unwrap_or(0);
740 let b2 = bytes.get(i + 2).copied().unwrap_or(0);
741
742 result.push(ALPHABET[(b0 >> 2) as usize] as char);
743 result.push(ALPHABET[(((b0 & 0x03) << 4) | (b1 >> 4)) as usize] as char);
744
745 if i + 1 < bytes.len() {
746 result.push(ALPHABET[(((b1 & 0x0f) << 2) | (b2 >> 6)) as usize] as char);
747 } else {
748 result.push('=');
749 }
750
751 if i + 2 < bytes.len() {
752 result.push(ALPHABET[(b2 & 0x3f) as usize] as char);
753 } else {
754 result.push('=');
755 }
756
757 i += 3;
758 }
759
760 result
761}
762
763fn base64_decode(encoded: &str) -> Result<Vec<u8>> {
764 const DECODE: [i8; 128] = [
765 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
766 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
767 -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
768 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1,
769 -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
770 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
771 ];
772
773 let encoded = encoded.trim_end_matches('=');
774 let mut result = Vec::with_capacity(encoded.len() * 3 / 4);
775
776 let mut buf = 0u32;
777 let mut bits = 0;
778
779 for c in encoded.chars() {
780 let val = if (c as usize) < 128 { DECODE[c as usize] } else { -1 };
781
782 if val < 0 {
783 return Err(PachaError::Validation("Invalid base64 character".to_string()));
784 }
785
786 buf = (buf << 6) | (val as u32);
787 bits += 6;
788
789 if bits >= 8 {
790 bits -= 8;
791 result.push((buf >> bits) as u8);
792 buf &= (1 << bits) - 1;
793 }
794 }
795
796 Ok(result)
797}
798
799#[cfg(test)]
804mod tests {
805 use super::*;
806
807 #[test]
812 fn test_signing_key_generate_produces_unique_keys() {
813 let key1 = SigningKey::generate();
814 let key2 = SigningKey::generate();
815
816 assert_ne!(key1.as_bytes(), key2.as_bytes());
818 }
819
820 #[test]
821 fn test_signing_key_is_32_bytes() {
822 let key = SigningKey::generate();
823 assert_eq!(key.as_bytes().len(), 32);
824 }
825
826 #[test]
827 fn test_signing_key_from_bytes_valid() {
828 let bytes = [42u8; 32];
829 let key = SigningKey::from_bytes(&bytes).unwrap();
830 assert_eq!(key.as_bytes(), &bytes);
831 }
832
833 #[test]
834 fn test_signing_key_from_bytes_rejects_wrong_length() {
835 let short = [42u8; 16];
836 assert!(SigningKey::from_bytes(&short).is_err());
837
838 let long = [42u8; 64];
839 assert!(SigningKey::from_bytes(&long).is_err());
840 }
841
842 #[test]
843 fn test_verifying_key_derivation_is_deterministic() {
844 let signing = SigningKey::generate();
845 let v1 = signing.verifying_key();
846 let v2 = signing.verifying_key();
847
848 assert_eq!(v1.as_bytes(), v2.as_bytes());
849 }
850
851 #[test]
852 fn test_verifying_key_is_32_bytes() {
853 let signing = SigningKey::generate();
854 let verifying = signing.verifying_key();
855 assert_eq!(verifying.as_bytes().len(), 32);
856 }
857
858 #[test]
863 fn test_sign_produces_64_byte_signature() {
864 let key = SigningKey::generate();
865 let sig = key.sign(b"test message");
866 assert_eq!(sig.as_bytes().len(), 64);
867 }
868
869 #[test]
870 fn test_sign_and_verify_succeeds() {
871 let signing_key = SigningKey::generate();
872 let verifying_key = signing_key.verifying_key();
873
874 let message = b"Hello, World!";
875 let signature = signing_key.sign(message);
876
877 let result = verifying_key.verify(message, &signature);
878 assert!(result.is_ok(), "Signature verification should succeed");
879 }
880
881 #[test]
882 fn test_verify_rejects_wrong_message() {
883 let signing_key = SigningKey::generate();
884 let verifying_key = signing_key.verifying_key();
885
886 let message = b"Hello, World!";
887 let signature = signing_key.sign(message);
888
889 let wrong_message = b"Wrong message";
890 let result = verifying_key.verify(wrong_message, &signature);
891 assert!(result.is_err(), "Should reject signature for different message");
892 }
893
894 #[test]
895 fn test_verify_rejects_wrong_key() {
896 let key1 = SigningKey::generate();
897 let key2 = SigningKey::generate();
898
899 let message = b"Hello, World!";
900 let signature = key1.sign(message);
901
902 let result = key2.verifying_key().verify(message, &signature);
903 assert!(result.is_err(), "Should reject signature from different key");
904 }
905
906 #[test]
907 fn test_signature_is_deterministic() {
908 let key = SigningKey::generate();
910 let message = b"test message";
911
912 let sig1 = key.sign(message);
913 let sig2 = key.sign(message);
914
915 assert_eq!(sig1.as_bytes(), sig2.as_bytes(), "Ed25519 signatures should be deterministic");
916 }
917
918 #[test]
919 fn test_empty_message_signing() {
920 let key = SigningKey::generate();
921 let verifying = key.verifying_key();
922
923 let sig = key.sign(b"");
924 assert!(verifying.verify(b"", &sig).is_ok());
925 }
926
927 #[test]
928 fn test_large_message_signing() {
929 let key = SigningKey::generate();
930 let verifying = key.verifying_key();
931
932 let large_message = vec![0x42u8; 1024 * 1024];
934 let sig = key.sign(&large_message);
935 assert!(verifying.verify(&large_message, &sig).is_ok());
936 }
937
938 #[test]
943 fn test_signature_hex_roundtrip() {
944 let key = SigningKey::generate();
945 let signature = key.sign(b"test");
946
947 let hex = signature.to_hex();
948 let recovered = Signature::from_hex(&hex).unwrap();
949
950 assert_eq!(signature, recovered);
951 }
952
953 #[test]
954 fn test_verifying_key_hex_roundtrip() {
955 let signing_key = SigningKey::generate();
956 let verifying_key = signing_key.verifying_key();
957
958 let hex = verifying_key.to_hex();
959 let recovered = VerifyingKey::from_hex(&hex).unwrap();
960
961 assert_eq!(verifying_key, recovered);
962 }
963
964 #[test]
965 fn test_signing_key_pem_roundtrip() {
966 let key = SigningKey::generate();
967 let pem = key.to_pem();
968 let recovered = SigningKey::from_pem(&pem).unwrap();
969
970 assert_eq!(key.as_bytes(), recovered.as_bytes());
971 }
972
973 #[test]
974 fn test_verifying_key_pem_roundtrip() {
975 let signing_key = SigningKey::generate();
976 let verifying_key = signing_key.verifying_key();
977
978 let pem = verifying_key.to_pem();
979 let recovered = VerifyingKey::from_pem(&pem).unwrap();
980
981 assert_eq!(verifying_key, recovered);
982 }
983
984 #[test]
989 fn test_model_signature_creation_and_verification() {
990 let signing_key = SigningKey::generate();
991 let model_data = b"model weights here...";
992
993 let signature = sign_model(model_data, &signing_key).unwrap();
994 let result = verify_model(model_data, &signature);
995
996 assert!(result.is_ok());
997 }
998
999 #[test]
1000 fn test_model_signature_detects_tampering() {
1001 let signing_key = SigningKey::generate();
1002 let model_data = b"model weights here...";
1003
1004 let signature = sign_model(model_data, &signing_key).unwrap();
1005
1006 let tampered = b"tampered weights!!!!";
1007 let result = verify_model(tampered, &signature);
1008
1009 assert!(result.is_err());
1010 }
1011
1012 #[test]
1013 fn test_model_signature_with_signer_id() {
1014 let signing_key = SigningKey::generate();
1015 let model_data = b"model data";
1016
1017 let signature =
1018 sign_model_with_id(model_data, &signing_key, Some("developer@example.com".to_string()))
1019 .unwrap();
1020
1021 assert_eq!(signature.signer_id, Some("developer@example.com".to_string()));
1022 assert!(verify_model(model_data, &signature).is_ok());
1023 }
1024
1025 #[test]
1026 fn test_model_signature_algorithm_field() {
1027 let signing_key = SigningKey::generate();
1028 let signature = sign_model(b"data", &signing_key).unwrap();
1029
1030 assert_eq!(signature.algorithm, "ed25519-blake3");
1031 }
1032
1033 #[test]
1034 fn test_model_signature_has_recent_timestamp() {
1035 let signing_key = SigningKey::generate();
1036 let signature = sign_model(b"data", &signing_key).unwrap();
1037
1038 let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
1039
1040 assert!(signature.timestamp <= now);
1041 assert!(signature.timestamp > now - 60, "Timestamp should be within last minute");
1042 }
1043
1044 #[test]
1045 fn test_verify_with_expected_key() {
1046 let signing_key = SigningKey::generate();
1047 let verifying_key = signing_key.verifying_key();
1048 let model_data = b"model data";
1049
1050 let signature = sign_model(model_data, &signing_key).unwrap();
1051
1052 let result = verify_model_with_key(model_data, &signature, &verifying_key);
1054 assert!(result.is_ok());
1055
1056 let other_key = SigningKey::generate().verifying_key();
1058 let result = verify_model_with_key(model_data, &signature, &other_key);
1059 assert!(result.is_err());
1060 }
1061
1062 #[test]
1067 fn test_keyring_basic_operations() {
1068 let mut keyring = Keyring::new();
1069 assert!(keyring.is_empty());
1070
1071 let key = SigningKey::generate().verifying_key();
1072 keyring.add("test", &key);
1073
1074 assert_eq!(keyring.len(), 1);
1075 assert!(!keyring.is_empty());
1076
1077 let retrieved = keyring.get("test").unwrap();
1078 assert_eq!(retrieved, key);
1079 }
1080
1081 #[test]
1082 fn test_keyring_default_key() {
1083 let mut keyring = Keyring::new();
1084 let key = SigningKey::generate().verifying_key();
1085
1086 keyring.add("main", &key);
1087 keyring.set_default("main");
1088
1089 let default = keyring.default_key().unwrap();
1090 assert_eq!(default, key);
1091 }
1092
1093 #[test]
1094 fn test_keyring_list() {
1095 let mut keyring = Keyring::new();
1096 keyring.add("key1", &SigningKey::generate().verifying_key());
1097 keyring.add("key2", &SigningKey::generate().verifying_key());
1098
1099 let names = keyring.list();
1100 assert_eq!(names.len(), 2);
1101 assert!(names.contains(&"key1"));
1102 assert!(names.contains(&"key2"));
1103 }
1104
1105 #[test]
1106 fn test_keyring_remove() {
1107 let mut keyring = Keyring::new();
1108 keyring.add("test", &SigningKey::generate().verifying_key());
1109
1110 assert!(keyring.remove("test"));
1111 assert!(!keyring.remove("test")); assert!(keyring.is_empty());
1113 }
1114
1115 #[test]
1120 fn test_hex_roundtrip() {
1121 let data = vec![0, 127, 255, 42, 100];
1122 let hex = hex_encode(&data);
1123 let decoded = hex_decode(&hex).unwrap();
1124 assert_eq!(data, decoded);
1125 }
1126
1127 #[test]
1128 fn test_base64_roundtrip() {
1129 let data = vec![0, 127, 255, 42, 100, 200];
1130 let encoded = base64_encode(&data);
1131 let decoded = base64_decode(&encoded).unwrap();
1132 assert_eq!(data, decoded);
1133 }
1134
1135 #[test]
1136 fn test_base64_empty() {
1137 let data: Vec<u8> = vec![];
1138 let encoded = base64_encode(&data);
1139 let decoded = base64_decode(&encoded).unwrap();
1140 assert_eq!(data, decoded);
1141 }
1142
1143 #[test]
1148 fn test_sign_verify_any_message() {
1149 for size in [0, 1, 10, 100, 1000, 10000] {
1151 let key = SigningKey::generate();
1152 let verifying = key.verifying_key();
1153 let message: Vec<u8> = (0..size).map(|i| (i % 256) as u8).collect();
1154
1155 let sig = key.sign(&message);
1156 assert!(verifying.verify(&message, &sig).is_ok(), "Failed for message size {size}");
1157 }
1158 }
1159
1160 #[test]
1161 fn test_different_keys_produce_different_signatures() {
1162 let message = b"test message";
1163 let key1 = SigningKey::generate();
1164 let key2 = SigningKey::generate();
1165
1166 let sig1 = key1.sign(message);
1167 let sig2 = key2.sign(message);
1168
1169 assert_ne!(sig1.as_bytes(), sig2.as_bytes());
1170 }
1171
1172 #[test]
1173 fn test_serialization_preserves_signature_validity() {
1174 let key = SigningKey::generate();
1175 let verifying = key.verifying_key();
1176 let message = b"test data";
1177
1178 let sig = key.sign(message);
1179
1180 let hex = sig.to_hex();
1182 let recovered = Signature::from_hex(&hex).unwrap();
1183
1184 assert!(verifying.verify(message, &recovered).is_ok());
1186 }
1187}