Skip to main content

pacha/
signing.rs

1//! Model Signing and Verification
2//!
3//! Provides Ed25519 digital signatures for model integrity and authenticity.
4//! Uses ed25519-dalek for proper cryptographic implementation per RFC 8032.
5//!
6//! ## Features
7//!
8//! - Key generation and management
9//! - Model signing with detached signatures
10//! - Signature verification
11//! - Keyring for multiple signing identities
12//!
13//! ## Security
14//!
15//! - 128-bit security level (Ed25519)
16//! - Deterministic signatures (no random number generation during signing)
17//! - Fast verification suitable for load-time checks
18//!
19//! ## Example
20//!
21//! ```rust,ignore
22//! use pacha::signing::{SigningKey, VerifyingKey, sign_model, verify_model};
23//!
24//! // Generate a new key pair
25//! let signing_key = SigningKey::generate();
26//! let verifying_key = signing_key.verifying_key();
27//!
28//! // Sign a model
29//! let signature = sign_model(&model_bytes, &signing_key)?;
30//!
31//! // Verify the signature
32//! verify_model(&model_bytes, &signature)?;
33//! ```
34
35use 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// ============================================================================
43// SIGN-001: Key Types - Proper Ed25519 Implementation
44// ============================================================================
45
46/// Ed25519 signing key (private key)
47///
48/// This wraps ed25519-dalek's SigningKey for proper Ed25519 signatures
49/// per RFC 8032.
50#[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    /// Generate a new random signing key using a cryptographically secure RNG
60    #[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    /// Create from raw bytes (32 bytes for Ed25519 secret key)
92    ///
93    /// # Errors
94    ///
95    /// Returns error if bytes length is not 32
96    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    /// Get raw key bytes
119    #[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    /// Derive the verifying (public) key
132    #[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            // Simplified: deterministic derivation for fallback
141            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    /// Sign a message using Ed25519
149    #[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            // Simplified BLAKE3-based signature for fallback
160            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    /// Export to PEM format
180    #[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    /// Import from PEM format
189    ///
190    /// # Errors
191    ///
192    /// Returns error if PEM format is invalid
193    pub fn from_pem(pem: &str) -> Result<Self> {
194        let pem = pem.trim();
195
196        // Support both old and new PEM headers
197        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/// Ed25519 verifying key (public key)
221#[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    /// Create from raw bytes (32 bytes for Ed25519 public key)
256    ///
257    /// # Errors
258    ///
259    /// Returns error if bytes length is not 32 or key is invalid
260    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    /// Get raw key bytes
285    #[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    /// Verify a signature using Ed25519
298    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            // Simplified verification for fallback
308            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    /// Export to hex string
326    #[must_use]
327    pub fn to_hex(&self) -> String {
328        hex_encode(self.as_bytes())
329    }
330
331    /// Import from hex string
332    ///
333    /// # Errors
334    ///
335    /// Returns error if hex is invalid
336    pub fn from_hex(hex: &str) -> Result<Self> {
337        let bytes = hex_decode(hex)?;
338        Self::from_bytes(&bytes)
339    }
340
341    /// Export to PEM format
342    #[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    /// Import from PEM format
351    ///
352    /// # Errors
353    ///
354    /// Returns error if PEM format is invalid
355    pub fn from_pem(pem: &str) -> Result<Self> {
356        let pem = pem.trim();
357
358        // Support both old and new PEM headers
359        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// ============================================================================
380// SIGN-002: Signature Type
381// ============================================================================
382
383/// Ed25519 signature (64 bytes)
384#[derive(Debug, Clone, PartialEq, Eq)]
385pub struct Signature {
386    /// Raw signature bytes (64 bytes)
387    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    /// Create from raw bytes
411    ///
412    /// # Errors
413    ///
414    /// Returns error if bytes length is not 64
415    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    /// Get raw signature bytes
428    #[must_use]
429    pub fn as_bytes(&self) -> &[u8; 64] {
430        &self.bytes
431    }
432
433    /// Export to hex string
434    #[must_use]
435    pub fn to_hex(&self) -> String {
436        hex_encode(&self.bytes)
437    }
438
439    /// Import from hex string
440    ///
441    /// # Errors
442    ///
443    /// Returns error if hex is invalid
444    pub fn from_hex(hex: &str) -> Result<Self> {
445        let bytes = hex_decode(hex)?;
446        Self::from_bytes(&bytes)
447    }
448}
449
450// ============================================================================
451// SIGN-003: Model Signature Metadata
452// ============================================================================
453
454/// Metadata for a signed model
455#[derive(Debug, Clone, Serialize, Deserialize)]
456pub struct ModelSignature {
457    /// Model content hash (BLAKE3)
458    pub content_hash: String,
459    /// Signature over the content hash (hex-encoded)
460    pub signature: String,
461    /// Signer's public key (hex-encoded)
462    pub signer_key: String,
463    /// Signer identity (optional, e.g., email)
464    pub signer_id: Option<String>,
465    /// Timestamp (Unix epoch seconds)
466    pub timestamp: u64,
467    /// Algorithm identifier
468    pub algorithm: String,
469}
470
471impl ModelSignature {
472    /// Create a new model signature
473    #[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    /// Verify this signature against model data
494    ///
495    /// # Errors
496    ///
497    /// Returns error if verification fails
498    pub fn verify(&self, model_data: &[u8]) -> Result<()> {
499        // Verify content hash matches
500        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        // Verify signature
511        let signature = Signature::from_hex(&self.signature)?;
512        let signer_key = VerifyingKey::from_hex(&self.signer_key)?;
513
514        // Sign the content hash, not the raw data (for efficiency)
515        signer_key.verify(self.content_hash.as_bytes(), &signature)
516    }
517
518    /// Save to file
519    ///
520    /// # Errors
521    ///
522    /// Returns error if writing fails
523    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    /// Load from file
530    ///
531    /// # Errors
532    ///
533    /// Returns error if reading or parsing fails
534    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// ============================================================================
542// SIGN-004: Keyring
543// ============================================================================
544
545/// Keyring for managing multiple signing identities
546#[derive(Debug, Clone, Default, Serialize, Deserialize)]
547pub struct Keyring {
548    /// Named verifying keys (hex-encoded)
549    keys: HashMap<String, String>,
550    /// Default key name
551    default_key: Option<String>,
552}
553
554impl Keyring {
555    /// Create a new empty keyring
556    #[must_use]
557    pub fn new() -> Self {
558        Self::default()
559    }
560
561    /// Add a verifying key with a name
562    pub fn add(&mut self, name: impl Into<String>, key: &VerifyingKey) {
563        self.keys.insert(name.into(), key.to_hex());
564    }
565
566    /// Get a verifying key by name
567    ///
568    /// # Errors
569    ///
570    /// Returns error if key not found or invalid
571    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    /// Remove a key
581    pub fn remove(&mut self, name: &str) -> bool {
582        self.keys.remove(name).is_some()
583    }
584
585    /// List all key names
586    #[must_use]
587    pub fn list(&self) -> Vec<&str> {
588        self.keys.keys().map(String::as_str).collect()
589    }
590
591    /// Set the default key
592    pub fn set_default(&mut self, name: impl Into<String>) {
593        self.default_key = Some(name.into());
594    }
595
596    /// Get the default key
597    ///
598    /// # Errors
599    ///
600    /// Returns error if no default set or key not found
601    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    /// Check if keyring is empty
610    #[must_use]
611    pub fn is_empty(&self) -> bool {
612        self.keys.is_empty()
613    }
614
615    /// Get number of keys
616    #[must_use]
617    pub fn len(&self) -> usize {
618        self.keys.len()
619    }
620
621    /// Save keyring to file
622    ///
623    /// # Errors
624    ///
625    /// Returns error if writing fails
626    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    /// Load keyring from file
633    ///
634    /// # Errors
635    ///
636    /// Returns error if reading or parsing fails
637    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
644// ============================================================================
645// SIGN-005: High-Level API
646// ============================================================================
647
648/// Sign model data
649///
650/// # Errors
651///
652/// Returns error if signing fails
653pub fn sign_model(model_data: &[u8], signing_key: &SigningKey) -> Result<ModelSignature> {
654    sign_model_with_id(model_data, signing_key, None)
655}
656
657/// Sign model data with signer identity
658///
659/// # Errors
660///
661/// Returns error if signing fails
662pub fn sign_model_with_id(
663    model_data: &[u8],
664    signing_key: &SigningKey,
665    signer_id: Option<String>,
666) -> Result<ModelSignature> {
667    // Hash the model content
668    let content_hash = blake3::hash(model_data);
669    let content_hex = hex_encode(content_hash.as_bytes());
670
671    // Sign the hash (not raw data, for efficiency with large models)
672    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
677/// Verify a model signature
678///
679/// # Errors
680///
681/// Returns error if verification fails
682pub fn verify_model(model_data: &[u8], signature: &ModelSignature) -> Result<()> {
683    signature.verify(model_data)
684}
685
686/// Verify a model signature with a specific key
687///
688/// # Errors
689///
690/// Returns error if verification fails or key doesn't match
691pub fn verify_model_with_key(
692    model_data: &[u8],
693    signature: &ModelSignature,
694    expected_key: &VerifyingKey,
695) -> Result<()> {
696    // First verify the signature is valid
697    signature.verify(model_data)?;
698
699    // Then verify it was signed by the expected key
700    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
709// ============================================================================
710// Helper Functions
711// ============================================================================
712
713fn 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// ============================================================================
800// Tests - Extreme TDD
801// ============================================================================
802
803#[cfg(test)]
804mod tests {
805    use super::*;
806
807    // -------------------------------------------------------------------------
808    // Key Generation Tests
809    // -------------------------------------------------------------------------
810
811    #[test]
812    fn test_signing_key_generate_produces_unique_keys() {
813        let key1 = SigningKey::generate();
814        let key2 = SigningKey::generate();
815
816        // Keys should be different (probabilistically)
817        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    // -------------------------------------------------------------------------
859    // Signature Tests - Core Ed25519 Properties
860    // -------------------------------------------------------------------------
861
862    #[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        // Ed25519 signatures are deterministic (no randomness)
909        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        // 1MB message
933        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    // -------------------------------------------------------------------------
939    // Serialization Tests
940    // -------------------------------------------------------------------------
941
942    #[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    // -------------------------------------------------------------------------
985    // Model Signature Tests
986    // -------------------------------------------------------------------------
987
988    #[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        // Should succeed with correct key
1053        let result = verify_model_with_key(model_data, &signature, &verifying_key);
1054        assert!(result.is_ok());
1055
1056        // Should fail with wrong key
1057        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    // -------------------------------------------------------------------------
1063    // Keyring Tests
1064    // -------------------------------------------------------------------------
1065
1066    #[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")); // Already removed
1112        assert!(keyring.is_empty());
1113    }
1114
1115    // -------------------------------------------------------------------------
1116    // Helper Function Tests
1117    // -------------------------------------------------------------------------
1118
1119    #[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    // -------------------------------------------------------------------------
1144    // Property-Based Tests (Extreme TDD)
1145    // -------------------------------------------------------------------------
1146
1147    #[test]
1148    fn test_sign_verify_any_message() {
1149        // Test with various message sizes
1150        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        // Roundtrip through hex
1181        let hex = sig.to_hex();
1182        let recovered = Signature::from_hex(&hex).unwrap();
1183
1184        // Should still verify
1185        assert!(verifying.verify(message, &recovered).is_ok());
1186    }
1187}