zoe_wire_protocol/
keys.rs

1//! Hybrid cryptographic key system supporting multiple signature algorithms.
2//!
3//! This module provides a unified interface for working with different signature algorithms,
4//! supporting both legacy Ed25519 and post-quantum ML-DSA signatures. The hybrid approach
5//! allows for gradual migration from classical to post-quantum cryptography.
6//!
7//! ## Supported Algorithms
8//!
9//! - **Ed25519**: Legacy elliptic curve signatures (32-byte keys, 64-byte signatures)
10//! - **ML-DSA-44**: Post-quantum signatures for TLS certificates (~128-bit security)
11//! - **ML-DSA-65**: Post-quantum signatures for messages (~192-bit security)
12//! - **ML-DSA-87**: Post-quantum signatures for high security (~256-bit security)
13//!
14//! ## Key Generation
15//!
16//! ```rust
17//! use zoe_wire_protocol::{KeyPair, VerifyingKey, SigningKey};
18//! use rand::rngs::OsRng;
19//!
20//! // Generate different key types
21//! let ed25519_keypair = KeyPair::generate_ed25519(&mut OsRng);
22//! let ml_dsa_65_keypair = KeyPair::generate(&mut OsRng); // Default: ML-DSA-65
23//!
24//! // Access keys
25//! let verifying_key = ed25519_keypair.public_key();
26//! let signature = ed25519_keypair.sign(b"message");
27//! ```
28//!
29//! ## Signing and Verification
30//!
31//! ```rust
32//! use zoe_wire_protocol::{KeyPair, VerifyingKey, SigningKey};
33//! use rand::rngs::OsRng;
34//!
35//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
36//! let keypair = KeyPair::generate(&mut OsRng);
37//! let message = b"Hello, world!";
38//!
39//! // Sign message
40//! let signature = keypair.sign(message);
41//!
42//! // Verify signature
43//! let verifying_key = keypair.public_key();
44//! let is_valid = verifying_key.verify(message, &signature)?;
45//! assert!(is_valid);
46//! # Ok(())
47//! # }
48//! ```
49//!
50//! ## Serialization
51//!
52//! All key types support postcard serialization for storage and transmission:
53//!
54//! ```rust
55//! use zoe_wire_protocol::{VerifyingKey, Signature};
56//!
57//! # fn example(verifying_key: VerifyingKey, signature: Signature) -> Result<(), postcard::Error> {
58//! // Serialize keys and signatures
59//! let key_bytes = verifying_key.encode();
60//! let sig_bytes = signature.encode();
61//!
62//! // Keys can be deserialized using postcard
63//! let key_restored: VerifyingKey = postcard::from_bytes(&key_bytes)?;
64//! let sig_restored: Signature = postcard::from_bytes(&sig_bytes)?;
65//! # Ok(())
66//! # }
67//! ```
68use crate::{Hash, KeyId};
69use hex;
70use libcrux_ml_dsa::{
71    ml_dsa_44,
72    ml_dsa_44::{MLDSA44KeyPair, MLDSA44Signature, MLDSA44SigningKey, MLDSA44VerificationKey},
73    ml_dsa_65,
74    ml_dsa_65::{MLDSA65KeyPair, MLDSA65Signature, MLDSA65SigningKey, MLDSA65VerificationKey},
75    ml_dsa_87,
76    ml_dsa_87::{MLDSA87KeyPair, MLDSA87Signature, MLDSA87SigningKey, MLDSA87VerificationKey},
77    KEY_GENERATION_RANDOMNESS_SIZE, SIGNING_RANDOMNESS_SIZE,
78};
79use pem::{encode, parse_many, Pem};
80use rand::RngCore;
81use serde::{Deserialize, Serialize};
82use signature::{Signer, Verifier};
83use std::fmt;
84
85/// Error type for KeyPair serialization and deserialization operations
86#[derive(Debug, thiserror::Error)]
87pub enum KeyPairError {
88    #[error("Failed to serialize KeyPair: {0}")]
89    Serialization(#[from] postcard::Error),
90    #[error("Failed to deserialize KeyPair: {0}")]
91    Deserialization(postcard::Error),
92    #[error("Failed to decode base64: {0}")]
93    Base64Decode(#[from] base64::DecodeError),
94    #[error("Invalid key data: {0}")]
95    InvalidKeyData(String),
96}
97
98/// Error type for VerifyingKey PEM operations
99#[derive(Debug, thiserror::Error)]
100pub enum VerifyingKeyError {
101    #[error("Failed to serialize VerifyingKey: {0}")]
102    SerializationError(String),
103    #[error("Failed to deserialize VerifyingKey: {0}")]
104    DeserializationError(String),
105    #[error("Failed to parse PEM: {0}")]
106    PemParseError(String),
107    #[error("Invalid PEM label: expected 'ZOE PUBLIC KEY', got '{0}'")]
108    InvalidPemLabel(String),
109}
110
111/// Cryptographic algorithm identifier
112#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
113pub enum Algorithm {
114    /// Ed25519 elliptic curve signatures
115    Ed25519,
116    /// ML-DSA-44 post-quantum signatures (TLS certificates, ~128-bit security)
117    MlDsa44,
118    /// ML-DSA-65 post-quantum signatures (messages, ~192-bit security)
119    MlDsa65,
120    /// ML-DSA-87 post-quantum signatures (high security, ~256-bit security)
121    MlDsa87,
122}
123
124impl fmt::Display for Algorithm {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        match self {
127            Algorithm::Ed25519 => write!(f, "Ed25519"),
128            Algorithm::MlDsa44 => write!(f, "ML-DSA-44"),
129            Algorithm::MlDsa65 => write!(f, "ML-DSA-65"),
130            Algorithm::MlDsa87 => write!(f, "ML-DSA-87"),
131        }
132    }
133}
134
135/// Public key for signature verification supporting multiple algorithms.
136///
137/// This enum provides a unified interface for verifying signatures across different
138/// cryptographic algorithms, supporting both classical and post-quantum schemes.
139///
140/// ## Algorithm Selection
141///
142/// - **Ed25519**: Use for legacy compatibility and smaller key sizes
143/// - **ML-DSA-44**: Use for TLS certificates requiring post-quantum security
144/// - **ML-DSA-65**: Use for message signatures with strong post-quantum security
145/// - **ML-DSA-87**: Use for high-security applications requiring maximum protection
146///
147/// ## Examples
148///
149/// ```rust
150/// use zoe_wire_protocol::{VerifyingKey, SigningKey, KeyPair};
151/// use rand::rngs::OsRng;
152///
153/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
154/// // Generate a keypair
155/// let keypair = KeyPair::generate(&mut OsRng);
156/// let verifying_key = keypair.public_key();
157///
158/// // Sign and verify a message
159/// let message = b"Hello, world!";
160/// let signature = keypair.sign(message);
161/// let is_valid = verifying_key.verify(message, &signature)?;
162/// assert!(is_valid);
163/// # Ok(())
164/// # }
165/// ```
166
167#[derive(Clone, Serialize, Deserialize)]
168pub enum VerifyingKey {
169    /// Ed25519 public key (32 bytes)
170    Ed25519(Box<ed25519_dalek::VerifyingKey>),
171    /// ML-DSA-44 public key (1,312 bytes) - for TLS certificates
172    #[serde(with = "serde_helpers::VerifyingKeyDef44")]
173    MlDsa44((Box<MLDSA44VerificationKey>, Hash)),
174    /// ML-DSA-65 public key (1,952 bytes) - for message signatures
175    #[serde(with = "serde_helpers::VerifyingKeyDef65")]
176    MlDsa65((Box<MLDSA65VerificationKey>, Hash)),
177    /// ML-DSA-87 public key (2,592 bytes) - for high security
178    #[serde(with = "serde_helpers::VerifyingKeyDef87")]
179    MlDsa87((Box<MLDSA87VerificationKey>, Hash)),
180}
181
182impl std::fmt::Debug for VerifyingKey {
183    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184        match self {
185            VerifyingKey::Ed25519(key) => f.debug_tuple("Ed25519").field(key).finish(),
186            VerifyingKey::MlDsa44((_, hash)) => f
187                .debug_tuple("MlDsa44")
188                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
189                .finish(),
190            VerifyingKey::MlDsa65((_, hash)) => f
191                .debug_tuple("MlDsa65")
192                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
193                .finish(),
194            VerifyingKey::MlDsa87((_, hash)) => f
195                .debug_tuple("MlDsa87")
196                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
197                .finish(),
198        }
199    }
200}
201
202impl From<MLDSA44VerificationKey> for VerifyingKey {
203    fn from(key: MLDSA44VerificationKey) -> Self {
204        let hash = blake3::hash(key.as_slice());
205        VerifyingKey::MlDsa44((Box::new(key), hash))
206    }
207}
208
209impl From<MLDSA65VerificationKey> for VerifyingKey {
210    fn from(key: MLDSA65VerificationKey) -> Self {
211        let hash = blake3::hash(key.as_slice());
212        VerifyingKey::MlDsa65((Box::new(key), hash))
213    }
214}
215
216impl From<MLDSA87VerificationKey> for VerifyingKey {
217    fn from(key: MLDSA87VerificationKey) -> Self {
218        let hash = blake3::hash(key.as_slice());
219        VerifyingKey::MlDsa87((Box::new(key), hash))
220    }
221}
222
223impl PartialEq for VerifyingKey {
224    fn eq(&self, other: &Self) -> bool {
225        self.id() == other.id()
226    }
227}
228
229impl Eq for VerifyingKey {}
230
231impl PartialOrd for VerifyingKey {
232    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
233        Some(self.cmp(other))
234    }
235}
236
237impl Ord for VerifyingKey {
238    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
239        // we order by index first
240        let my_key = match self {
241            VerifyingKey::Ed25519(_) => 0,
242            VerifyingKey::MlDsa44(..) => 1,
243            VerifyingKey::MlDsa65(..) => 2,
244            VerifyingKey::MlDsa87(..) => 3,
245        };
246        let other_key_idx = match other {
247            VerifyingKey::Ed25519(_) => 0,
248            VerifyingKey::MlDsa44(..) => 1,
249            VerifyingKey::MlDsa65(..) => 2,
250            VerifyingKey::MlDsa87(..) => 3,
251        };
252        if my_key < other_key_idx {
253            return std::cmp::Ordering::Less;
254        } else if my_key > other_key_idx {
255            return std::cmp::Ordering::Greater;
256        }
257        // we only check the bytes if we are of the same type
258        self.id().cmp(&other.id())
259    }
260}
261
262impl std::hash::Hash for VerifyingKey {
263    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
264        self.id().hash(state);
265    }
266}
267
268impl TryFrom<&[u8]> for VerifyingKey {
269    type Error = postcard::Error;
270    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
271        let key: VerifyingKey = postcard::from_bytes(value)?;
272        Ok(key)
273    }
274}
275
276#[derive(Debug, thiserror::Error)]
277pub enum VerifyError {
278    #[error("Invalid key")]
279    InvalidKey,
280    #[error("Ed25519 signature error")]
281    Ed25519SignatureError(ed25519_dalek::SignatureError),
282    #[error("ML-DSA verify error")]
283    MlDsaVerifyError(libcrux_ml_dsa::VerificationError),
284}
285
286/// flutter_rust_bridge:opaque
287impl VerifyingKey {
288    /// Get the algorithm for this key type
289    ///
290    pub fn algorithm(&self) -> Algorithm {
291        match self {
292            Self::Ed25519(_) => Algorithm::Ed25519,
293            Self::MlDsa44(..) => Algorithm::MlDsa44,
294            Self::MlDsa65(..) => Algorithm::MlDsa65,
295            Self::MlDsa87(..) => Algorithm::MlDsa87,
296        }
297    }
298
299    /// Verify a signature against a message using the appropriate algorithm.
300    ///
301    /// This method automatically matches the signature type with the key type
302    /// and returns `Ok(false)` if they don't match (rather than an error).
303    ///
304    /// # Arguments
305    ///
306    /// * `message` - The message bytes that were signed
307    /// * `signature` - The signature to verify
308    ///
309    /// # Returns
310    ///
311    /// * `Ok(true)` - Signature is valid for this key and message
312    /// * `Ok(false)` - Signature is invalid or key/signature types don't match
313    /// * `Err(_)` - Verification error (malformed signature, etc.)
314    ///
315    /// # Examples
316    ///
317    /// ```rust
318    /// use zoe_wire_protocol::{KeyPair, VerifyingKey, SigningKey};
319    /// use rand::rngs::OsRng;
320    ///
321    /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
322    /// let keypair = KeyPair::generate_ed25519(&mut OsRng);
323    /// let message = b"Hello, world!";
324    /// let signature = keypair.sign(message);
325    /// let verifying_key = keypair.public_key();
326    ///
327    /// let is_valid = verifying_key.verify(message, &signature)?;
328    /// assert!(is_valid);
329    /// # Ok(())
330    /// # }
331    /// ```
332    pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), VerifyError> {
333        match (self, signature) {
334            (VerifyingKey::Ed25519(key), Signature::Ed25519(sig)) => key
335                .verify(message, sig)
336                .map_err(VerifyError::Ed25519SignatureError),
337            (VerifyingKey::MlDsa44((key, _hash)), Signature::MlDsa44((sig, _hash2))) => {
338                ml_dsa_44::portable::verify(key, message, &[], sig)
339                    .map_err(VerifyError::MlDsaVerifyError)
340            }
341            (VerifyingKey::MlDsa65((key, _hash)), Signature::MlDsa65((sig, _hash2))) => {
342                ml_dsa_65::portable::verify(key, message, &[], sig)
343                    .map_err(VerifyError::MlDsaVerifyError)
344            }
345            (VerifyingKey::MlDsa87((key, _hash)), Signature::MlDsa87((sig, _hash2))) => {
346                ml_dsa_87::portable::verify(key, message, &[], sig)
347                    .map_err(VerifyError::MlDsaVerifyError)
348            }
349            _ => Err(VerifyError::InvalidKey), // Mismatched key and signature types
350        }
351    }
352
353    /// Encode the VerifyingKey to bytes for serialization.
354    ///
355    /// This method serializes the key using postcard format for efficient storage
356    /// and transmission. The resulting bytes can be deserialized back to a
357    /// `VerifyingKey` using `postcard::from_bytes()`.
358    ///
359    /// # Returns
360    ///
361    /// A `Vec<u8>` containing the serialized key data.
362    ///
363    /// # Examples
364    ///
365    /// ```rust
366    /// use zoe_wire_protocol::{KeyPair, VerifyingKey};
367    /// use rand::rngs::OsRng;
368    ///
369    /// let keypair = KeyPair::generate_ed25519(&mut OsRng);
370    /// let verifying_key = keypair.public_key();
371    ///
372    /// // Serialize the key
373    /// let key_bytes = verifying_key.encode();
374    ///
375    /// // Deserialize it back
376    /// let restored_key: VerifyingKey = postcard::from_bytes(&key_bytes).unwrap();
377    /// assert_eq!(&verifying_key, &restored_key);
378    /// ```
379    pub fn encode(&self) -> Vec<u8> {
380        postcard::to_stdvec(self).expect("Failed to serialize VerifyingKey")
381    }
382
383    pub fn id(&self) -> KeyId {
384        match self {
385            VerifyingKey::Ed25519(key) => KeyId::from_bytes(*key.as_bytes()),
386            VerifyingKey::MlDsa44((_key, hash)) => KeyId::from(*hash),
387            VerifyingKey::MlDsa65((_key, hash)) => KeyId::from(*hash),
388            VerifyingKey::MlDsa87((_key, hash)) => KeyId::from(*hash),
389        }
390    }
391
392    pub fn to_bytes(&self) -> Result<Vec<u8>, postcard::Error> {
393        postcard::to_stdvec(self)
394    }
395
396    pub fn from_hex(hex: String) -> Result<Self, String> {
397        let bytes = hex::decode(hex).map_err(|e| format!("Invalid hex: {e}"))?;
398        let key: VerifyingKey =
399            postcard::from_bytes(&bytes).map_err(|e| format!("Invalid key data: {e}"))?;
400        Ok(key)
401    }
402
403    /// Export the VerifyingKey to PEM format.
404    ///
405    /// This method serializes the key using postcard format and then encodes it
406    /// as a PEM block with the label "ZOE PUBLIC KEY". This provides a standardized
407    /// text format that's compatible with many cryptographic tools and libraries.
408    ///
409    /// # Returns
410    ///
411    /// A `Result<String, VerifyingKeyError>` containing the PEM-encoded key or an error.
412    ///
413    /// # Examples
414    ///
415    /// ```rust
416    /// use zoe_wire_protocol::{KeyPair, VerifyingKey};
417    /// use rand::rngs::OsRng;
418    ///
419    /// let keypair = KeyPair::generate_ed25519(&mut OsRng);
420    /// let verifying_key = keypair.public_key();
421    /// let pem_string = verifying_key.to_pem().unwrap();
422    /// println!("Public key PEM:\n{}", pem_string);
423    /// ```
424    pub fn to_pem(&self) -> Result<String, VerifyingKeyError> {
425        let key_bytes = postcard::to_stdvec(self)
426            .map_err(|e| VerifyingKeyError::SerializationError(e.to_string()))?;
427
428        let pem = Pem::new("ZOE PUBLIC KEY", key_bytes);
429        Ok(encode(&pem))
430    }
431
432    /// Import a VerifyingKey from PEM format.
433    ///
434    /// This method parses a PEM-encoded string and deserializes it back to a
435    /// `VerifyingKey`. The PEM block should have the label "ZOE PUBLIC KEY".
436    ///
437    /// # Arguments
438    ///
439    /// * `pem_string` - A string containing the PEM-encoded public key
440    ///
441    /// # Returns
442    ///
443    /// A `Result<VerifyingKey, VerifyingKeyError>` containing the decoded key or an error.
444    ///
445    /// # Examples
446    ///
447    /// ```rust
448    /// use zoe_wire_protocol::{KeyPair, VerifyingKey};
449    /// use rand::rngs::OsRng;
450    ///
451    /// let original_keypair = KeyPair::generate_ed25519(&mut OsRng);
452    /// let original_key = original_keypair.public_key();
453    /// let pem_string = original_key.to_pem().unwrap();
454    ///
455    /// let restored_key = VerifyingKey::from_pem(&pem_string).unwrap();
456    /// assert_eq!(original_key.encode(), restored_key.encode());
457    /// ```
458    pub fn from_pem(pem_string: &str) -> Result<VerifyingKey, VerifyingKeyError> {
459        let pem =
460            pem::parse(pem_string).map_err(|e| VerifyingKeyError::PemParseError(e.to_string()))?;
461
462        if pem.tag() != "ZOE PUBLIC KEY" {
463            return Err(VerifyingKeyError::InvalidPemLabel(pem.tag().to_string()));
464        }
465
466        let key = postcard::from_bytes(pem.contents())
467            .map_err(|e| VerifyingKeyError::DeserializationError(e.to_string()))?;
468
469        Ok(key)
470    }
471}
472
473/// Private key for creating digital signatures supporting multiple algorithms.
474///
475/// This enum provides a unified interface for signing messages across different
476/// cryptographic algorithms, supporting both classical and post-quantum schemes.
477///
478/// ## Security Considerations
479///
480/// - **Keep private keys secure**: Never transmit or store signing keys in plaintext
481/// - **Use appropriate key sizes**: ML-DSA keys are larger but provide post-quantum security
482/// - **Match key types**: Ensure the signing key matches the expected verifying key type
483///
484/// ## Examples
485///
486/// ```rust
487/// use zoe_wire_protocol::{KeyPair, SigningKey, VerifyingKey};
488/// use rand::rngs::OsRng;
489///
490/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
491/// // Generate a keypair
492/// let keypair = KeyPair::generate(&mut OsRng);
493///
494/// // Sign a message
495/// let message = b"Important message";
496/// let signature = keypair.sign(message);
497///
498/// // Verify with corresponding public key
499/// let verifying_key = keypair.public_key();
500/// let is_valid = verifying_key.verify(message, &signature)?;
501/// assert!(is_valid);
502/// # Ok(())
503/// # }
504/// ```
505#[derive(Clone)]
506pub enum SigningKey {
507    /// Ed25519 private key (32 bytes)
508    Ed25519(Box<ed25519_dalek::SigningKey>),
509    /// ML-DSA-44 private key - for TLS certificates
510    MlDsa44((Box<MLDSA44SigningKey>, Hash)),
511    /// ML-DSA-65 private key - for message signatures
512    MlDsa65((Box<MLDSA65SigningKey>, Hash)),
513    /// ML-DSA-87 private key - for high security
514    MlDsa87((Box<MLDSA87SigningKey>, Hash)),
515}
516
517impl std::fmt::Debug for SigningKey {
518    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
519        match self {
520            SigningKey::Ed25519(_) => f.debug_tuple("Ed25519").field(&"<private_key>").finish(),
521            SigningKey::MlDsa44((_, hash)) => f
522                .debug_tuple("MlDsa44")
523                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
524                .finish(),
525            SigningKey::MlDsa65((_, hash)) => f
526                .debug_tuple("MlDsa65")
527                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
528                .finish(),
529            SigningKey::MlDsa87((_, hash)) => f
530                .debug_tuple("MlDsa87")
531                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
532                .finish(),
533        }
534    }
535}
536
537impl PartialEq for SigningKey {
538    fn eq(&self, other: &Self) -> bool {
539        match (self, other) {
540            (SigningKey::Ed25519(a), SigningKey::Ed25519(b)) => a == b,
541            (SigningKey::MlDsa44((_, hash_a)), SigningKey::MlDsa44((_, hash_b))) => {
542                hash_a == hash_b
543            }
544            (SigningKey::MlDsa65((_, hash_a)), SigningKey::MlDsa65((_, hash_b))) => {
545                hash_a == hash_b
546            }
547            (SigningKey::MlDsa87((_, hash_a)), SigningKey::MlDsa87((_, hash_b))) => {
548                hash_a == hash_b
549            }
550            _ => false,
551        }
552    }
553}
554
555impl SigningKey {
556    /// Sign a message with this signing key
557    pub fn sign(&self, message: &[u8]) -> Signature {
558        match self {
559            SigningKey::Ed25519(key) => Signature::Ed25519(Box::new(key.sign(message))),
560            SigningKey::MlDsa44((key, _)) => {
561                let mut randomness = [0u8; SIGNING_RANDOMNESS_SIZE];
562                rand::thread_rng().fill_bytes(&mut randomness);
563                let signature = ml_dsa_44::portable::sign(key, message, &[], randomness)
564                    .expect("ML-DSA signing should not fail");
565                signature.into()
566            }
567            SigningKey::MlDsa65((key, _)) => {
568                let mut randomness = [0u8; SIGNING_RANDOMNESS_SIZE];
569                rand::thread_rng().fill_bytes(&mut randomness);
570                let signature = ml_dsa_65::portable::sign(key, message, &[], randomness)
571                    .expect("ML-DSA signing should not fail");
572                signature.into()
573            }
574            SigningKey::MlDsa87((key, _)) => {
575                let mut randomness = [0u8; SIGNING_RANDOMNESS_SIZE];
576                rand::thread_rng().fill_bytes(&mut randomness);
577                let signature = ml_dsa_87::portable::sign(key, message, &[], randomness)
578                    .expect("ML-DSA signing should not fail");
579                signature.into()
580            }
581        }
582    }
583}
584
585impl Signature {
586    /// Encode the Signature to bytes for serialization
587    pub fn encode(&self) -> Vec<u8> {
588        postcard::to_stdvec(self).expect("Failed to serialize Signature")
589    }
590}
591
592#[derive(Clone, Serialize, Deserialize)]
593pub enum Signature {
594    Ed25519(Box<ed25519_dalek::Signature>),
595    #[serde(with = "serde_helpers::SignatureDef44")]
596    MlDsa44((Box<MLDSA44Signature>, Hash)),
597    #[serde(with = "serde_helpers::SignatureDef65")]
598    MlDsa65((Box<MLDSA65Signature>, Hash)),
599    #[serde(with = "serde_helpers::SignatureDef87")]
600    MlDsa87((Box<MLDSA87Signature>, Hash)),
601}
602
603impl std::fmt::Debug for Signature {
604    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
605        match self {
606            Signature::Ed25519(sig) => f.debug_tuple("Ed25519").field(sig).finish(),
607            Signature::MlDsa44((_, hash)) => f
608                .debug_tuple("MlDsa44")
609                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
610                .finish(),
611            Signature::MlDsa65((_, hash)) => f
612                .debug_tuple("MlDsa65")
613                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
614                .finish(),
615            Signature::MlDsa87((_, hash)) => f
616                .debug_tuple("MlDsa87")
617                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
618                .finish(),
619        }
620    }
621}
622
623impl From<MLDSA44Signature> for Signature {
624    fn from(sig: MLDSA44Signature) -> Self {
625        let hash = blake3::hash(sig.as_slice());
626        Signature::MlDsa44((Box::new(sig), hash))
627    }
628}
629
630impl From<MLDSA65Signature> for Signature {
631    fn from(sig: MLDSA65Signature) -> Self {
632        let hash = blake3::hash(sig.as_slice());
633        Signature::MlDsa65((Box::new(sig), hash))
634    }
635}
636
637impl From<MLDSA87Signature> for Signature {
638    fn from(sig: MLDSA87Signature) -> Self {
639        let hash = blake3::hash(sig.as_slice());
640        Signature::MlDsa87((Box::new(sig), hash))
641    }
642}
643
644impl Signature {
645    pub fn id(&self) -> KeyId {
646        match self {
647            Signature::Ed25519(sig) => KeyId::from_bytes(*sig.s_bytes()),
648            Signature::MlDsa44((_sig, hash)) => KeyId::from(*hash),
649            Signature::MlDsa65((_sig, hash)) => KeyId::from(*hash),
650            Signature::MlDsa87((_sig, hash)) => KeyId::from(*hash),
651        }
652    }
653}
654
655impl PartialEq for Signature {
656    fn eq(&self, other: &Self) -> bool {
657        self.partial_cmp(other) == Some(std::cmp::Ordering::Equal)
658    }
659}
660
661/// Signature "ordering" is used as tie-breaker for messages with the same timestamp,
662///
663/// The order is determined by the signature index (the higher the index in the enum, the higher the signature)
664/// and if they are the same by comparing the signature bytes directly with each other.
665impl PartialOrd for Signature {
666    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
667        // we first compare the signature index,
668        let my_key = match self {
669            Signature::Ed25519(_) => 0,
670            Signature::MlDsa44(..) => 1,
671            Signature::MlDsa65(..) => 2,
672            Signature::MlDsa87(..) => 3,
673        };
674        let other_key_idx = match other {
675            Signature::Ed25519(_) => 0,
676            Signature::MlDsa44(..) => 1,
677            Signature::MlDsa65(..) => 2,
678            Signature::MlDsa87(..) => 3,
679        };
680        if my_key < other_key_idx {
681            return Some(std::cmp::Ordering::Less);
682        } else if my_key > other_key_idx {
683            return Some(std::cmp::Ordering::Greater);
684        }
685        self.id().partial_cmp(&other.id())
686    }
687}
688
689pub enum KeyPair {
690    Ed25519(Box<ed25519_dalek::SigningKey>),
691    MlDsa44(Box<MLDSA44KeyPair>, Hash),
692    MlDsa65(Box<MLDSA65KeyPair>, Hash),
693    MlDsa87(Box<MLDSA87KeyPair>, Hash),
694}
695
696impl std::fmt::Debug for KeyPair {
697    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
698        match self {
699            KeyPair::Ed25519(_) => f.debug_tuple("Ed25519").field(&"<keypair>").finish(),
700            KeyPair::MlDsa44(_, hash) => f
701                .debug_tuple("MlDsa44")
702                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
703                .finish(),
704            KeyPair::MlDsa65(_, hash) => f
705                .debug_tuple("MlDsa65")
706                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
707                .finish(),
708            KeyPair::MlDsa87(_, hash) => f
709                .debug_tuple("MlDsa87")
710                .field(&format!("hash:{}", hex::encode(hash.as_bytes())))
711                .finish(),
712        }
713    }
714}
715
716impl KeyPair {
717    pub fn id(&self) -> KeyId {
718        match self {
719            KeyPair::Ed25519(key) => KeyId::from_bytes(*key.as_bytes()),
720            KeyPair::MlDsa44(_key, hash) => KeyId::from(*hash),
721            KeyPair::MlDsa65(_key, hash) => KeyId::from(*hash),
722            KeyPair::MlDsa87(_key, hash) => KeyId::from(*hash),
723        }
724    }
725
726    pub fn public_key(&self) -> VerifyingKey {
727        self.into()
728    }
729
730    /// Get the algorithm for this key type
731    pub fn algorithm(&self) -> Algorithm {
732        match self {
733            Self::Ed25519(_) => Algorithm::Ed25519,
734            Self::MlDsa44(..) => Algorithm::MlDsa44,
735            Self::MlDsa65(..) => Algorithm::MlDsa65,
736            Self::MlDsa87(..) => Algorithm::MlDsa87,
737        }
738    }
739}
740
741impl PartialEq for KeyPair {
742    fn eq(&self, other: &Self) -> bool {
743        match (self, other) {
744            (KeyPair::Ed25519(a), KeyPair::Ed25519(b)) => a.to_bytes() == b.to_bytes(),
745            (KeyPair::MlDsa44(_, hash), KeyPair::MlDsa44(_, hash_other)) => hash == hash_other,
746            (KeyPair::MlDsa65(_, hash), KeyPair::MlDsa65(_, hash_other)) => hash == hash_other,
747            (KeyPair::MlDsa87(_, hash), KeyPair::MlDsa87(_, hash_other)) => hash == hash_other,
748            _ => false,
749        }
750    }
751}
752
753impl From<&KeyPair> for VerifyingKey {
754    fn from(val: &KeyPair) -> Self {
755        match val {
756            KeyPair::Ed25519(a) => VerifyingKey::Ed25519(Box::new(a.verifying_key())),
757            KeyPair::MlDsa44(a, hash) => {
758                // the keypair hash is over the verifying key, so we can just use the hash
759                let key = a.verification_key.clone();
760                VerifyingKey::MlDsa44((Box::new(key), *hash))
761            }
762            KeyPair::MlDsa65(a, hash) => {
763                let key = a.verification_key.clone();
764                VerifyingKey::MlDsa65((Box::new(key), *hash))
765            }
766            KeyPair::MlDsa87(a, hash) => {
767                let key = a.verification_key.clone();
768                VerifyingKey::MlDsa87((Box::new(key), *hash))
769            }
770        }
771    }
772}
773
774impl KeyPair {
775    pub fn sign(&self, message: &[u8]) -> Signature {
776        match self {
777            KeyPair::Ed25519(a) => Signature::Ed25519(Box::new(a.sign(message))),
778            KeyPair::MlDsa44(a, _) => {
779                let mut randomness = [0u8; SIGNING_RANDOMNESS_SIZE];
780                rand::thread_rng().fill_bytes(&mut randomness);
781                let signature = ml_dsa_44::portable::sign(&a.signing_key, message, &[], randomness)
782                    .expect("ML-DSA signing should not fail");
783                let hash = blake3::hash(signature.as_slice());
784                Signature::MlDsa44((Box::new(signature), hash))
785            }
786            KeyPair::MlDsa65(a, _) => {
787                let mut randomness = [0u8; SIGNING_RANDOMNESS_SIZE];
788                rand::thread_rng().fill_bytes(&mut randomness);
789                let signature = ml_dsa_65::portable::sign(&a.signing_key, message, &[], randomness)
790                    .expect("ML-DSA signing should not fail");
791                let hash = blake3::hash(signature.as_slice());
792                Signature::MlDsa65((Box::new(signature), hash))
793            }
794            KeyPair::MlDsa87(a, _) => {
795                let mut randomness = [0u8; SIGNING_RANDOMNESS_SIZE];
796                rand::thread_rng().fill_bytes(&mut randomness);
797                let signature = ml_dsa_87::portable::sign(&a.signing_key, message, &[], randomness)
798                    .expect("ML-DSA signing should not fail");
799                let hash = blake3::hash(signature.as_slice());
800                Signature::MlDsa87((Box::new(signature), hash))
801            }
802        }
803    }
804
805    pub fn generate_ml_dsa44<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> KeyPair {
806        let mut randomness = [0u8; KEY_GENERATION_RANDOMNESS_SIZE];
807        rng.fill_bytes(&mut randomness);
808        let key = ml_dsa_44::portable::generate_key_pair(randomness);
809        let hash = blake3::hash(key.verification_key.as_slice());
810        KeyPair::MlDsa44(Box::new(key), hash)
811    }
812
813    pub fn generate_ml_dsa65<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> KeyPair {
814        let mut randomness = [0u8; KEY_GENERATION_RANDOMNESS_SIZE];
815        rng.fill_bytes(&mut randomness);
816        let key = ml_dsa_65::portable::generate_key_pair(randomness);
817        let hash = blake3::hash(key.verification_key.as_slice());
818        KeyPair::MlDsa65(Box::new(key), hash)
819    }
820
821    pub fn generate_ml_dsa87<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> KeyPair {
822        let mut randomness = [0u8; KEY_GENERATION_RANDOMNESS_SIZE];
823        rng.fill_bytes(&mut randomness);
824        let key = ml_dsa_87::portable::generate_key_pair(randomness);
825        let hash = blake3::hash(key.verification_key.as_slice());
826        KeyPair::MlDsa87(Box::new(key), hash)
827    }
828
829    pub fn generate<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> KeyPair {
830        KeyPair::generate_ml_dsa65(rng)
831    }
832
833    pub fn generate_for_algorithm<R: rand::CryptoRng + rand::RngCore>(
834        algorithm: Algorithm,
835        rng: &mut R,
836    ) -> KeyPair {
837        match algorithm {
838            Algorithm::Ed25519 => KeyPair::generate_ed25519(rng),
839            Algorithm::MlDsa44 => KeyPair::generate_ml_dsa44(rng),
840            Algorithm::MlDsa65 => KeyPair::generate_ml_dsa65(rng),
841            Algorithm::MlDsa87 => KeyPair::generate_ml_dsa87(rng),
842        }
843    }
844
845    pub fn generate_ed25519<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> KeyPair {
846        KeyPair::Ed25519(Box::new(ed25519_dalek::SigningKey::generate(rng)))
847    }
848
849    /// Encode the KeyPair to a PEM string suitable for environment variables or file storage.
850    ///
851    /// This method creates PEM blocks containing:
852    /// - For Ed25519: Only the private key (public key can be derived)
853    /// - For ML-DSA: Both private and public keys in separate PEM blocks (hash is derived from public key)
854    ///
855    /// All PEM blocks are prefixed with "ZOE" to identify them as Zoe-specific formats.
856    ///
857    /// # Returns
858    ///
859    /// A PEM-formatted string containing the key data.
860    ///
861    /// # Examples
862    ///
863    /// ```rust
864    /// use zoe_wire_protocol::KeyPair;
865    /// use rand::rngs::OsRng;
866    ///
867    /// let keypair = KeyPair::generate_ed25519(&mut OsRng);
868    /// let pem_string = keypair.to_pem().unwrap();
869    ///
870    /// // Store in environment variable or file
871    /// std::env::set_var("MY_PRIVATE_KEY", &pem_string);
872    /// ```
873    pub fn to_pem(&self) -> Result<String, KeyPairError> {
874        match self {
875            KeyPair::Ed25519(signing_key) => {
876                // For Ed25519, we only need the private key
877                let private_key_bytes = signing_key.to_bytes();
878                let pem = Pem::new("ZOE ED25519 PRIVATE KEY", private_key_bytes.to_vec());
879                Ok(encode(&pem))
880            }
881            KeyPair::MlDsa44(keypair, _hash) => {
882                // For ML-DSA, create separate PEM blocks for private and public keys
883                let private_pem = Pem::new(
884                    "ZOE ML-DSA-44 PRIVATE KEY",
885                    keypair.signing_key.as_slice().to_vec(),
886                );
887                let public_pem = Pem::new(
888                    "ZOE ML-DSA-44 PUBLIC KEY",
889                    keypair.verification_key.as_slice().to_vec(),
890                );
891
892                Ok(format!("{}\n{}", encode(&private_pem), encode(&public_pem)))
893            }
894            KeyPair::MlDsa65(keypair, _hash) => {
895                // For ML-DSA, create separate PEM blocks for private and public keys
896                let private_pem = Pem::new(
897                    "ZOE ML-DSA-65 PRIVATE KEY",
898                    keypair.signing_key.as_slice().to_vec(),
899                );
900                let public_pem = Pem::new(
901                    "ZOE ML-DSA-65 PUBLIC KEY",
902                    keypair.verification_key.as_slice().to_vec(),
903                );
904
905                Ok(format!("{}\n{}", encode(&private_pem), encode(&public_pem)))
906            }
907            KeyPair::MlDsa87(keypair, _hash) => {
908                // For ML-DSA, create separate PEM blocks for private and public keys
909                let private_pem = Pem::new(
910                    "ZOE ML-DSA-87 PRIVATE KEY",
911                    keypair.signing_key.as_slice().to_vec(),
912                );
913                let public_pem = Pem::new(
914                    "ZOE ML-DSA-87 PUBLIC KEY",
915                    keypair.verification_key.as_slice().to_vec(),
916                );
917
918                Ok(format!("{}\n{}", encode(&private_pem), encode(&public_pem)))
919            }
920        }
921    }
922
923    /// Decode a KeyPair from a PEM string.
924    ///
925    /// This method can parse PEM files created by `to_pem()`, using `parse_many` to
926    /// read multiple PEM blocks and automatically detecting the key type from the
927    /// PEM labels to reconstruct the appropriate KeyPair.
928    ///
929    /// # Arguments
930    ///
931    /// * `pem_string` - The PEM-formatted string containing key data
932    ///
933    /// # Returns
934    ///
935    /// A `KeyPair` instance reconstructed from the PEM data.
936    ///
937    /// # Examples
938    ///
939    /// ```rust
940    /// use zoe_wire_protocol::KeyPair;
941    /// use rand::rngs::OsRng;
942    ///
943    /// let original = KeyPair::generate_ed25519(&mut OsRng);
944    /// let pem_string = original.to_pem().unwrap();
945    /// let restored = KeyPair::from_pem(&pem_string).unwrap();
946    ///
947    /// assert_eq!(original.public_key(), restored.public_key());
948    /// ```
949    pub fn from_pem(pem_string: &str) -> Result<KeyPair, KeyPairError> {
950        let pems = parse_many(pem_string)
951            .map_err(|e| KeyPairError::InvalidKeyData(format!("Invalid PEM format: {e}")))?;
952
953        if pems.is_empty() {
954            return Err(KeyPairError::InvalidKeyData(
955                "No PEM blocks found".to_string(),
956            ));
957        }
958
959        // Check for Ed25519 (single block)
960        if pems.len() == 1 && pems[0].tag() == "ZOE ED25519 PRIVATE KEY" {
961            if pems[0].contents().len() != 32 {
962                return Err(KeyPairError::InvalidKeyData(
963                    "Invalid Ed25519 private key length".to_string(),
964                ));
965            }
966            let mut key_bytes = [0u8; 32];
967            key_bytes.copy_from_slice(pems[0].contents());
968            let signing_key = ed25519_dalek::SigningKey::from_bytes(&key_bytes);
969            return Ok(KeyPair::Ed25519(Box::new(signing_key)));
970        }
971
972        // Check for ML-DSA (two blocks: private, public)
973        if pems.len() == 2 {
974            let mut private_key_bytes: Option<Vec<u8>> = None;
975            let mut public_key_bytes: Option<Vec<u8>> = None;
976            let mut algorithm: Option<&str> = None;
977
978            for pem in &pems {
979                match pem.tag() {
980                    "ZOE ML-DSA-44 PRIVATE KEY" => {
981                        private_key_bytes = Some(pem.contents().to_vec());
982                        algorithm = Some("ML-DSA-44");
983                    }
984                    "ZOE ML-DSA-44 PUBLIC KEY" => {
985                        public_key_bytes = Some(pem.contents().to_vec());
986                    }
987                    "ZOE ML-DSA-65 PRIVATE KEY" => {
988                        private_key_bytes = Some(pem.contents().to_vec());
989                        algorithm = Some("ML-DSA-65");
990                    }
991                    "ZOE ML-DSA-65 PUBLIC KEY" => {
992                        public_key_bytes = Some(pem.contents().to_vec());
993                    }
994                    "ZOE ML-DSA-87 PRIVATE KEY" => {
995                        private_key_bytes = Some(pem.contents().to_vec());
996                        algorithm = Some("ML-DSA-87");
997                    }
998                    "ZOE ML-DSA-87 PUBLIC KEY" => {
999                        public_key_bytes = Some(pem.contents().to_vec());
1000                    }
1001                    _ => {
1002                        return Err(KeyPairError::InvalidKeyData(format!(
1003                            "Unsupported PEM key type: {}",
1004                            pem.tag()
1005                        )));
1006                    }
1007                }
1008            }
1009
1010            // Reconstruct the keypair based on the algorithm
1011            match (algorithm, private_key_bytes, public_key_bytes) {
1012                (Some("ML-DSA-44"), Some(private_bytes), Some(public_bytes)) => {
1013                    let signing_key =
1014                        MLDSA44SigningKey::new(private_bytes.try_into().map_err(|_| {
1015                            KeyPairError::InvalidKeyData(
1016                                "Invalid ML-DSA-44 signing key size".to_string(),
1017                            )
1018                        })?);
1019                    let verification_key =
1020                        MLDSA44VerificationKey::new(public_bytes.try_into().map_err(|_| {
1021                            KeyPairError::InvalidKeyData(
1022                                "Invalid ML-DSA-44 verification key size".to_string(),
1023                            )
1024                        })?);
1025                    let keypair = MLDSA44KeyPair {
1026                        signing_key,
1027                        verification_key,
1028                    };
1029                    // Generate hash from public key
1030                    let hash = blake3::hash(keypair.verification_key.as_slice());
1031                    Ok(KeyPair::MlDsa44(Box::new(keypair), hash))
1032                }
1033                (Some("ML-DSA-65"), Some(private_bytes), Some(public_bytes)) => {
1034                    let signing_key =
1035                        MLDSA65SigningKey::new(private_bytes.try_into().map_err(|_| {
1036                            KeyPairError::InvalidKeyData(
1037                                "Invalid ML-DSA-65 signing key size".to_string(),
1038                            )
1039                        })?);
1040                    let verification_key =
1041                        MLDSA65VerificationKey::new(public_bytes.try_into().map_err(|_| {
1042                            KeyPairError::InvalidKeyData(
1043                                "Invalid ML-DSA-65 verification key size".to_string(),
1044                            )
1045                        })?);
1046                    let keypair = MLDSA65KeyPair {
1047                        signing_key,
1048                        verification_key,
1049                    };
1050                    // Generate hash from public key
1051                    let hash = blake3::hash(keypair.verification_key.as_slice());
1052                    Ok(KeyPair::MlDsa65(Box::new(keypair), hash))
1053                }
1054                (Some("ML-DSA-87"), Some(private_bytes), Some(public_bytes)) => {
1055                    let signing_key =
1056                        MLDSA87SigningKey::new(private_bytes.try_into().map_err(|_| {
1057                            KeyPairError::InvalidKeyData(
1058                                "Invalid ML-DSA-87 signing key size".to_string(),
1059                            )
1060                        })?);
1061                    let verification_key =
1062                        MLDSA87VerificationKey::new(public_bytes.try_into().map_err(|_| {
1063                            KeyPairError::InvalidKeyData(
1064                                "Invalid ML-DSA-87 verification key size".to_string(),
1065                            )
1066                        })?);
1067                    let keypair = MLDSA87KeyPair {
1068                        signing_key,
1069                        verification_key,
1070                    };
1071                    // Generate hash from public key
1072                    let hash = blake3::hash(keypair.verification_key.as_slice());
1073                    Ok(KeyPair::MlDsa87(Box::new(keypair), hash))
1074                }
1075                _ => Err(KeyPairError::InvalidKeyData(
1076                    "Incomplete or mismatched ML-DSA key blocks".to_string(),
1077                )),
1078            }
1079        } else {
1080            Err(KeyPairError::InvalidKeyData(format!(
1081                "Expected 1 PEM block for Ed25519 or 2 blocks for ML-DSA, found {}",
1082                pems.len()
1083            )))
1084        }
1085    }
1086}
1087
1088impl fmt::Display for VerifyingKey {
1089    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1090        match self {
1091            Self::Ed25519(key) => {
1092                write!(f, "Ed25519({})", hex::encode(key.to_bytes()))
1093            }
1094            Self::MlDsa44((_key, hash)) => {
1095                write!(f, "ML-DSA-44({})", hex::encode(hash.as_bytes()))
1096            }
1097            Self::MlDsa65((_key, hash)) => {
1098                write!(f, "ML-DSA-65({})", hex::encode(hash.as_bytes()))
1099            }
1100            Self::MlDsa87((_key, hash)) => {
1101                write!(f, "ML-DSA-87({})", hex::encode(hash.as_bytes()))
1102            }
1103        }
1104    }
1105}
1106
1107impl fmt::Display for KeyPair {
1108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1109        match self {
1110            Self::Ed25519(key) => {
1111                write!(
1112                    f,
1113                    "Ed25519({})",
1114                    hex::encode(key.verifying_key().to_bytes())
1115                )
1116            }
1117            Self::MlDsa44(_keypair, hash) => {
1118                write!(f, "ML-DSA-44({})", hex::encode(hash.as_bytes()))
1119            }
1120            Self::MlDsa65(_keypair, hash) => {
1121                write!(f, "ML-DSA-65({})", hex::encode(hash.as_bytes()))
1122            }
1123            Self::MlDsa87(_keypair, hash) => {
1124                write!(f, "ML-DSA-87({})", hex::encode(hash.as_bytes()))
1125            }
1126        }
1127    }
1128}
1129
1130mod serde_helpers {
1131    #![allow(clippy::borrowed_box)]
1132
1133    use crate::Hash;
1134    use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
1135    use libcrux_ml_dsa::{
1136        ml_dsa_44::{MLDSA44Signature, MLDSA44VerificationKey},
1137        ml_dsa_65::{MLDSA65Signature, MLDSA65VerificationKey},
1138        ml_dsa_87::{MLDSA87Signature, MLDSA87VerificationKey},
1139    };
1140    use serde_bytes::ByteArray;
1141
1142    // ML-DSA sizes from FIPS 204 standard
1143    const ML_DSA_44_VERIFICATION_KEY_SIZE: usize = 1312;
1144    const ML_DSA_44_SIGNATURE_SIZE: usize = 2420;
1145    const ML_DSA_65_VERIFICATION_KEY_SIZE: usize = 1952;
1146    const ML_DSA_65_SIGNATURE_SIZE: usize = 3309;
1147    const ML_DSA_87_VERIFICATION_KEY_SIZE: usize = 2592;
1148    const ML_DSA_87_SIGNATURE_SIZE: usize = 4627;
1149
1150    /// Remote serde definition for ML-DSA-44 VerifyingKey
1151    /// Use with #[serde(with = "zoe_wire_protocol::serde::VerifyingKeyDef44")]
1152    pub struct VerifyingKeyDef44;
1153
1154    impl VerifyingKeyDef44 {
1155        pub fn serialize<S>(
1156            key: &(Box<MLDSA44VerificationKey>, Hash),
1157            serializer: S,
1158        ) -> Result<S::Ok, S::Error>
1159        where
1160            S: Serializer,
1161        {
1162            // Use serde_bytes::ByteArray for efficient fixed-size serialization
1163            let key_bytes: &[u8; ML_DSA_44_VERIFICATION_KEY_SIZE] = key
1164                .0
1165                .as_slice()
1166                .try_into()
1167                .map_err(|_| serde::ser::Error::custom("ML-DSA-44 key has incorrect size"))?;
1168            let byte_array = ByteArray::new(*key_bytes);
1169            byte_array.serialize(serializer)
1170        }
1171
1172        pub fn deserialize<'de, D>(
1173            deserializer: D,
1174        ) -> Result<(Box<MLDSA44VerificationKey>, Hash), D::Error>
1175        where
1176            D: Deserializer<'de>,
1177        {
1178            // Deserialize directly to fixed-size array via serde_bytes
1179            let byte_array =
1180                ByteArray::<ML_DSA_44_VERIFICATION_KEY_SIZE>::deserialize(deserializer)?;
1181            let key_bytes: [u8; ML_DSA_44_VERIFICATION_KEY_SIZE] = byte_array.into_array();
1182            let key = MLDSA44VerificationKey::new(key_bytes);
1183            let hash = blake3::hash(&key_bytes);
1184            Ok((Box::new(key), hash))
1185        }
1186    }
1187
1188    /// Remote serde definition for ML-DSA-65 VerifyingKey
1189    /// Use with #[serde(with = "zoe_wire_protocol::serde::VerifyingKeyDef65")]
1190    pub struct VerifyingKeyDef65;
1191
1192    impl VerifyingKeyDef65 {
1193        pub fn serialize<S>(
1194            key: &(Box<MLDSA65VerificationKey>, Hash),
1195            serializer: S,
1196        ) -> Result<S::Ok, S::Error>
1197        where
1198            S: Serializer,
1199        {
1200            // Use serde_bytes::ByteArray for efficient fixed-size serialization
1201            let key_bytes: &[u8; ML_DSA_65_VERIFICATION_KEY_SIZE] = key
1202                .0
1203                .as_slice()
1204                .try_into()
1205                .map_err(|_| serde::ser::Error::custom("ML-DSA-65 key has incorrect size"))?;
1206            let byte_array = ByteArray::new(*key_bytes);
1207            byte_array.serialize(serializer)
1208        }
1209
1210        pub fn deserialize<'de, D>(
1211            deserializer: D,
1212        ) -> Result<(Box<MLDSA65VerificationKey>, Hash), D::Error>
1213        where
1214            D: Deserializer<'de>,
1215        {
1216            // Deserialize directly to fixed-size array via serde_bytes
1217            let byte_array =
1218                ByteArray::<ML_DSA_65_VERIFICATION_KEY_SIZE>::deserialize(deserializer)?;
1219            let key_bytes: [u8; ML_DSA_65_VERIFICATION_KEY_SIZE] = byte_array.into_array();
1220            let key = MLDSA65VerificationKey::new(key_bytes);
1221            let hash = blake3::hash(&key_bytes);
1222            Ok((Box::new(key), hash))
1223        }
1224    }
1225
1226    /// Remote serde definition for ML-DSA-87 VerifyingKey
1227    /// Use with #[serde(with = "zoe_wire_protocol::serde::VerifyingKeyDef87")]
1228    pub struct VerifyingKeyDef87;
1229
1230    impl VerifyingKeyDef87 {
1231        pub fn serialize<S>(
1232            key: &(Box<MLDSA87VerificationKey>, Hash),
1233            serializer: S,
1234        ) -> Result<S::Ok, S::Error>
1235        where
1236            S: Serializer,
1237        {
1238            // Use serde_bytes::ByteArray for efficient fixed-size serialization
1239            let key_bytes: &[u8; ML_DSA_87_VERIFICATION_KEY_SIZE] = key
1240                .0
1241                .as_slice()
1242                .try_into()
1243                .map_err(|_| serde::ser::Error::custom("ML-DSA-87 key has incorrect size"))?;
1244            let byte_array = ByteArray::new(*key_bytes);
1245            byte_array.serialize(serializer)
1246        }
1247
1248        pub fn deserialize<'de, D>(
1249            deserializer: D,
1250        ) -> Result<(Box<MLDSA87VerificationKey>, Hash), D::Error>
1251        where
1252            D: Deserializer<'de>,
1253        {
1254            // Deserialize directly to fixed-size array via serde_bytes
1255            let byte_array =
1256                ByteArray::<ML_DSA_87_VERIFICATION_KEY_SIZE>::deserialize(deserializer)?;
1257            let key_bytes: [u8; ML_DSA_87_VERIFICATION_KEY_SIZE] = byte_array.into_array();
1258            let key = MLDSA87VerificationKey::new(key_bytes);
1259            let hash = blake3::hash(&key_bytes);
1260            Ok((Box::new(key), hash))
1261        }
1262    }
1263
1264    /// Remote serde definition for ML-DSA-44 Signature
1265    /// Use with #[serde(with = "zoe_wire_protocol::serde::SignatureDef44")]
1266    pub struct SignatureDef44;
1267
1268    impl SignatureDef44 {
1269        pub fn serialize<S>(
1270            sig: &(Box<MLDSA44Signature>, Hash),
1271            serializer: S,
1272        ) -> Result<S::Ok, S::Error>
1273        where
1274            S: Serializer,
1275        {
1276            // Use serde_bytes::ByteArray for efficient fixed-size serialization
1277            let sig_bytes: &[u8; ML_DSA_44_SIGNATURE_SIZE] =
1278                sig.0.as_slice().try_into().map_err(|_| {
1279                    serde::ser::Error::custom("ML-DSA-44 signature has incorrect size")
1280                })?;
1281            let byte_array = ByteArray::new(*sig_bytes);
1282            byte_array.serialize(serializer)
1283        }
1284
1285        pub fn deserialize<'de, D>(
1286            deserializer: D,
1287        ) -> Result<(Box<MLDSA44Signature>, Hash), D::Error>
1288        where
1289            D: Deserializer<'de>,
1290        {
1291            // Deserialize directly to fixed-size array via serde_bytes
1292            let byte_array = ByteArray::<ML_DSA_44_SIGNATURE_SIZE>::deserialize(deserializer)?;
1293            let sig_bytes: [u8; ML_DSA_44_SIGNATURE_SIZE] = byte_array.into_array();
1294            let sig = MLDSA44Signature::new(sig_bytes);
1295            let hash = blake3::hash(&sig_bytes);
1296            Ok((Box::new(sig), hash))
1297        }
1298    }
1299
1300    /// Remote serde definition for ML-DSA-65 Signature
1301    /// Use with #[serde(with = "zoe_wire_protocol::serde::SignatureDef65")]
1302    pub struct SignatureDef65;
1303
1304    impl SignatureDef65 {
1305        pub fn serialize<S>(
1306            sig: &(Box<MLDSA65Signature>, Hash),
1307            serializer: S,
1308        ) -> Result<S::Ok, S::Error>
1309        where
1310            S: Serializer,
1311        {
1312            // Use serde_bytes::ByteArray for efficient fixed-size serialization
1313            let sig_bytes: &[u8; ML_DSA_65_SIGNATURE_SIZE] =
1314                sig.0.as_slice().try_into().map_err(|_| {
1315                    serde::ser::Error::custom("ML-DSA-65 signature has incorrect size")
1316                })?;
1317            let byte_array = ByteArray::new(*sig_bytes);
1318            byte_array.serialize(serializer)
1319        }
1320
1321        pub fn deserialize<'de, D>(
1322            deserializer: D,
1323        ) -> Result<(Box<MLDSA65Signature>, Hash), D::Error>
1324        where
1325            D: Deserializer<'de>,
1326        {
1327            // Deserialize directly to fixed-size array via serde_bytes
1328            let byte_array = ByteArray::<ML_DSA_65_SIGNATURE_SIZE>::deserialize(deserializer)?;
1329            let sig_bytes: [u8; ML_DSA_65_SIGNATURE_SIZE] = byte_array.into_array();
1330            let sig = MLDSA65Signature::new(sig_bytes);
1331            let hash = blake3::hash(&sig_bytes);
1332            Ok((Box::new(sig), hash))
1333        }
1334    }
1335
1336    /// Remote serde definition for ML-DSA-87 Signature
1337    /// Use with #[serde(with = "zoe_wire_protocol::serde::SignatureDef87")]
1338    pub struct SignatureDef87;
1339
1340    impl SignatureDef87 {
1341        pub fn serialize<S>(
1342            sig: &(Box<MLDSA87Signature>, Hash),
1343            serializer: S,
1344        ) -> Result<S::Ok, S::Error>
1345        where
1346            S: Serializer,
1347        {
1348            // Use serde_bytes::ByteArray for efficient fixed-size serialization
1349            let sig_bytes: &[u8; ML_DSA_87_SIGNATURE_SIZE] =
1350                sig.0.as_slice().try_into().map_err(|_| {
1351                    serde::ser::Error::custom("ML-DSA-87 signature has incorrect size")
1352                })?;
1353            let byte_array = ByteArray::new(*sig_bytes);
1354            byte_array.serialize(serializer)
1355        }
1356
1357        pub fn deserialize<'de, D>(
1358            deserializer: D,
1359        ) -> Result<(Box<MLDSA87Signature>, Hash), D::Error>
1360        where
1361            D: Deserializer<'de>,
1362        {
1363            // Deserialize directly to fixed-size array via serde_bytes
1364            let byte_array = ByteArray::<ML_DSA_87_SIGNATURE_SIZE>::deserialize(deserializer)?;
1365            let sig_bytes: [u8; ML_DSA_87_SIGNATURE_SIZE] = byte_array.into_array();
1366            let sig = MLDSA87Signature::new(sig_bytes);
1367            let hash = blake3::hash(&sig_bytes);
1368            Ok((Box::new(sig), hash))
1369        }
1370    }
1371}
1372
1373#[cfg(test)]
1374mod tests {
1375    use super::*;
1376    use rand::rngs::OsRng;
1377    use std::collections::{BTreeSet, HashSet};
1378
1379    /// Test helper to create test keypairs of all types
1380    fn create_test_keypairs() -> Vec<KeyPair> {
1381        let mut rng = OsRng;
1382        vec![
1383            KeyPair::generate_ed25519(&mut rng),
1384            KeyPair::generate_ml_dsa44(&mut rng),
1385            KeyPair::generate_ml_dsa65(&mut rng),
1386            KeyPair::generate_ml_dsa87(&mut rng),
1387        ]
1388    }
1389
1390    /// Test helper to create verifying keys of all types
1391    fn create_test_verifying_keys() -> Vec<VerifyingKey> {
1392        create_test_keypairs()
1393            .iter()
1394            .map(|kp| kp.public_key())
1395            .collect()
1396    }
1397
1398    #[test]
1399    fn test_verifying_key_equality_and_id_consistency() {
1400        let keypairs = create_test_keypairs();
1401
1402        for keypair in &keypairs {
1403            let key1 = keypair.public_key();
1404            let key2 = keypair.public_key();
1405
1406            // Same keypair should produce equal verifying keys
1407            assert_eq!(
1408                key1, key2,
1409                "VerifyingKeys from same KeyPair should be equal"
1410            );
1411
1412            // IDs should be identical
1413            assert_eq!(
1414                key1.id(),
1415                key2.id(),
1416                "IDs should be identical for equal keys"
1417            );
1418
1419            // Keys should be equal to themselves
1420            assert_eq!(key1, key1, "VerifyingKey should equal itself");
1421        }
1422
1423        // Different keypairs should produce different verifying keys
1424        let keys = create_test_verifying_keys();
1425        for (i, key1) in keys.iter().enumerate() {
1426            for (j, key2) in keys.iter().enumerate() {
1427                if i != j {
1428                    assert_ne!(
1429                        key1, key2,
1430                        "Different keypairs should produce different VerifyingKeys"
1431                    );
1432                    assert_ne!(
1433                        key1.id(),
1434                        key2.id(),
1435                        "Different keys should have different IDs"
1436                    );
1437                }
1438            }
1439        }
1440    }
1441
1442    #[test]
1443    fn test_verifying_key_ordering() {
1444        let keys = create_test_verifying_keys();
1445
1446        // Test ordering is consistent
1447        for key1 in &keys {
1448            for key2 in &keys {
1449                let cmp1 = key1.cmp(key2);
1450                let cmp2 = key2.cmp(key1);
1451
1452                // Ordering should be antisymmetric
1453                match cmp1 {
1454                    std::cmp::Ordering::Less => assert_eq!(cmp2, std::cmp::Ordering::Greater),
1455                    std::cmp::Ordering::Greater => assert_eq!(cmp2, std::cmp::Ordering::Less),
1456                    std::cmp::Ordering::Equal => assert_eq!(cmp2, std::cmp::Ordering::Equal),
1457                }
1458
1459                // PartialOrd should be consistent with Ord
1460                assert_eq!(key1.partial_cmp(key2), Some(cmp1));
1461            }
1462        }
1463
1464        // Test transitivity with multiple keys
1465        let mut sorted_keys = keys.clone();
1466        sorted_keys.sort();
1467
1468        // Verify the sort order follows our algorithm-index-first rule
1469        for i in 0..sorted_keys.len() {
1470            for j in i + 1..sorted_keys.len() {
1471                assert!(
1472                    sorted_keys[i] <= sorted_keys[j],
1473                    "Sort order should be maintained"
1474                );
1475            }
1476        }
1477    }
1478
1479    #[test]
1480    fn test_verifying_key_hash_consistency() {
1481        let keys = create_test_verifying_keys();
1482
1483        for key in &keys {
1484            let mut hasher1 = std::collections::hash_map::DefaultHasher::new();
1485            let mut hasher2 = std::collections::hash_map::DefaultHasher::new();
1486
1487            std::hash::Hash::hash(key, &mut hasher1);
1488            std::hash::Hash::hash(key, &mut hasher2);
1489
1490            let hash1 = std::hash::Hasher::finish(&hasher1);
1491            let hash2 = std::hash::Hasher::finish(&hasher2);
1492
1493            assert_eq!(hash1, hash2, "Hash should be consistent for same key");
1494        }
1495
1496        // Test that equal keys have equal hashes
1497        let keypair = &create_test_keypairs()[0];
1498        let key1 = keypair.public_key();
1499        let key2 = keypair.public_key();
1500
1501        let mut hasher1 = std::collections::hash_map::DefaultHasher::new();
1502        let mut hasher2 = std::collections::hash_map::DefaultHasher::new();
1503
1504        std::hash::Hash::hash(&key1, &mut hasher1);
1505        std::hash::Hash::hash(&key2, &mut hasher2);
1506
1507        assert_eq!(
1508            std::hash::Hasher::finish(&hasher1),
1509            std::hash::Hasher::finish(&hasher2)
1510        );
1511
1512        // Test keys can be used in HashSet and BTreeSet
1513        let mut hash_set = HashSet::new();
1514        let mut btree_set = BTreeSet::new();
1515
1516        for key in &keys {
1517            hash_set.insert(key.clone());
1518            btree_set.insert(key.clone());
1519        }
1520
1521        assert_eq!(
1522            hash_set.len(),
1523            keys.len(),
1524            "All keys should be unique in HashSet"
1525        );
1526        assert_eq!(
1527            btree_set.len(),
1528            keys.len(),
1529            "All keys should be unique in BTreeSet"
1530        );
1531    }
1532
1533    #[test]
1534    fn test_verifying_key_serialization_round_trip() {
1535        let keys = create_test_verifying_keys();
1536
1537        for original_key in &keys {
1538            // Test postcard serialization round trip
1539            let encoded = original_key.encode();
1540            let decoded: VerifyingKey = postcard::from_bytes(&encoded)
1541                .expect("Should successfully deserialize VerifyingKey");
1542
1543            assert_eq!(
1544                *original_key, decoded,
1545                "Round-trip serialization should preserve equality"
1546            );
1547            assert_eq!(
1548                original_key.id(),
1549                decoded.id(),
1550                "Round-trip should preserve ID"
1551            );
1552
1553            // Test that encoding is deterministic
1554            let encoded2 = decoded.encode();
1555            assert_eq!(encoded, encoded2, "Encoding should be deterministic");
1556
1557            // Test alternative serialization method
1558            let bytes = original_key.to_bytes().expect("Should serialize to bytes");
1559            let restored = VerifyingKey::try_from(bytes.as_slice())
1560                .expect("Should successfully restore from bytes");
1561
1562            assert_eq!(
1563                *original_key, restored,
1564                "Alternative serialization should work"
1565            );
1566            assert_eq!(
1567                original_key.id(),
1568                restored.id(),
1569                "Alternative serialization should preserve ID"
1570            );
1571        }
1572    }
1573
1574    #[test]
1575    fn test_signing_key_equality() {
1576        let mut rng = OsRng;
1577
1578        // Test Ed25519 SigningKey equality
1579        let ed25519_bytes = [42u8; 32]; // Fixed seed for reproducible keys
1580        let ed25519_key1 = ed25519_dalek::SigningKey::from_bytes(&ed25519_bytes);
1581        let ed25519_key2 = ed25519_dalek::SigningKey::from_bytes(&ed25519_bytes);
1582
1583        let signing_key1 = SigningKey::Ed25519(Box::new(ed25519_key1));
1584        let signing_key2 = SigningKey::Ed25519(Box::new(ed25519_key2));
1585
1586        assert_eq!(
1587            signing_key1, signing_key2,
1588            "SigningKeys from same bytes should be equal"
1589        );
1590
1591        // Test that different keys are not equal
1592        let different_ed25519 = KeyPair::generate_ed25519(&mut rng);
1593        let different_ml_dsa = KeyPair::generate_ml_dsa65(&mut rng);
1594
1595        let ed25519_signing = match different_ed25519 {
1596            KeyPair::Ed25519(ref key) => SigningKey::Ed25519(key.clone()),
1597            _ => panic!("Expected Ed25519 keypair"),
1598        };
1599
1600        let ml_dsa_signing = match different_ml_dsa {
1601            KeyPair::MlDsa65(ref keypair, hash) => {
1602                SigningKey::MlDsa65((Box::new(keypair.signing_key.clone()), hash))
1603            }
1604            _ => panic!("Expected ML-DSA-65 keypair"),
1605        };
1606
1607        assert_ne!(
1608            ed25519_signing, ml_dsa_signing,
1609            "Different key types should not be equal"
1610        );
1611    }
1612
1613    #[test]
1614    fn test_signing_key_functionality() {
1615        let keypairs = create_test_keypairs();
1616        let message = b"test message for signing";
1617
1618        for keypair in &keypairs {
1619            let signature = keypair.sign(message);
1620            let verifying_key = keypair.public_key();
1621
1622            // Test that signature can be verified
1623            verifying_key.verify(message, &signature).unwrap();
1624            // Test with wrong message
1625            let wrong_message = b"different message";
1626            let is_invalid = verifying_key.verify(wrong_message, &signature);
1627            assert!(
1628                is_invalid.is_err(),
1629                "Signature should be invalid for wrong message"
1630            );
1631        }
1632    }
1633
1634    #[test]
1635    fn test_signature_equality_and_ordering() {
1636        let keypairs = create_test_keypairs();
1637        let message = b"test message";
1638
1639        let mut signatures = Vec::new();
1640        for keypair in &keypairs {
1641            signatures.push(keypair.sign(message));
1642        }
1643
1644        // Test equality
1645        for (i, sig1) in signatures.iter().enumerate() {
1646            for (j, sig2) in signatures.iter().enumerate() {
1647                if i == j {
1648                    assert_eq!(sig1, sig2, "Signature should equal itself");
1649                } else {
1650                    // Different signatures should not be equal (very high probability)
1651                    assert_ne!(sig1, sig2, "Different signatures should not be equal");
1652                }
1653            }
1654        }
1655
1656        // Test ordering consistency
1657        for sig1 in &signatures {
1658            for sig2 in &signatures {
1659                let cmp = sig1.partial_cmp(sig2);
1660                assert!(cmp.is_some(), "Signatures should always be comparable");
1661
1662                // Test antisymmetry
1663                let reverse_cmp = sig2.partial_cmp(sig1);
1664                match cmp.unwrap() {
1665                    std::cmp::Ordering::Less => {
1666                        assert_eq!(reverse_cmp, Some(std::cmp::Ordering::Greater))
1667                    }
1668                    std::cmp::Ordering::Greater => {
1669                        assert_eq!(reverse_cmp, Some(std::cmp::Ordering::Less))
1670                    }
1671                    std::cmp::Ordering::Equal => {
1672                        assert_eq!(reverse_cmp, Some(std::cmp::Ordering::Equal))
1673                    }
1674                }
1675            }
1676        }
1677
1678        // Test that sorting works
1679        let mut sorted_signatures = signatures.clone();
1680        sorted_signatures.sort_by(|a, b| a.partial_cmp(b).unwrap());
1681
1682        // Verify sort order maintains our algorithm-first ordering
1683        for i in 0..sorted_signatures.len() {
1684            for j in i + 1..sorted_signatures.len() {
1685                assert!(
1686                    sorted_signatures[i].partial_cmp(&sorted_signatures[j])
1687                        != Some(std::cmp::Ordering::Greater)
1688                );
1689            }
1690        }
1691    }
1692
1693    #[test]
1694    fn test_signature_id_consistency() {
1695        let keypairs = create_test_keypairs();
1696        let message = b"test message";
1697
1698        for keypair in &keypairs {
1699            let sig1 = keypair.sign(message);
1700            let sig2 = keypair.sign(message);
1701
1702            // IDs might be different for same message (signatures can be non-deterministic)
1703            // but the same signature object should have consistent ID
1704            assert_eq!(sig1.id(), sig1.id(), "Signature ID should be consistent");
1705            assert_eq!(sig2.id(), sig2.id(), "Signature ID should be consistent");
1706        }
1707    }
1708
1709    #[test]
1710    fn test_signature_serialization_round_trip() {
1711        let keypairs = create_test_keypairs();
1712        let message = b"test message";
1713
1714        for keypair in &keypairs {
1715            let original_signature = keypair.sign(message);
1716
1717            // Test postcard serialization round trip
1718            let encoded = original_signature.encode();
1719            let decoded: Signature =
1720                postcard::from_bytes(&encoded).expect("Should successfully deserialize Signature");
1721
1722            assert_eq!(
1723                original_signature, decoded,
1724                "Round-trip serialization should preserve equality"
1725            );
1726            assert_eq!(
1727                original_signature.id(),
1728                decoded.id(),
1729                "Round-trip should preserve ID"
1730            );
1731
1732            // Test that encoding is deterministic
1733            let encoded2 = decoded.encode();
1734            assert_eq!(encoded, encoded2, "Encoding should be deterministic");
1735        }
1736    }
1737
1738    #[test]
1739    fn test_keypair_equality_and_id_consistency() {
1740        let _rng = OsRng;
1741
1742        // Test that same-seed keypairs are equal (for deterministic algorithms)
1743        let ed25519_bytes = [42u8; 32];
1744        let ed25519_key1 = ed25519_dalek::SigningKey::from_bytes(&ed25519_bytes);
1745        let ed25519_key2 = ed25519_dalek::SigningKey::from_bytes(&ed25519_bytes);
1746
1747        let keypair1 = KeyPair::Ed25519(Box::new(ed25519_key1));
1748        let keypair2 = KeyPair::Ed25519(Box::new(ed25519_key2));
1749
1750        assert_eq!(
1751            keypair1, keypair2,
1752            "KeyPairs from same bytes should be equal"
1753        );
1754        assert_eq!(
1755            keypair1.id(),
1756            keypair2.id(),
1757            "Equal KeyPairs should have same ID"
1758        );
1759
1760        // Test different keypairs are not equal
1761        let different_keypairs = create_test_keypairs();
1762        for (i, kp1) in different_keypairs.iter().enumerate() {
1763            for (j, kp2) in different_keypairs.iter().enumerate() {
1764                if i != j {
1765                    assert_ne!(kp1, kp2, "Different KeyPairs should not be equal");
1766                    assert_ne!(
1767                        kp1.id(),
1768                        kp2.id(),
1769                        "Different KeyPairs should have different IDs"
1770                    );
1771                }
1772            }
1773        }
1774    }
1775
1776    #[test]
1777    fn test_cross_algorithm_verification_rejection() {
1778        let keypairs = create_test_keypairs();
1779        let message = b"test message";
1780
1781        // Create signatures from each keypair
1782        let mut signatures = Vec::new();
1783        let mut verifying_keys = Vec::new();
1784
1785        for keypair in &keypairs {
1786            signatures.push(keypair.sign(message));
1787            verifying_keys.push(keypair.public_key());
1788        }
1789
1790        // Test that matching key/signature pairs work
1791        for (key, sig) in verifying_keys.iter().zip(signatures.iter()) {
1792            key.verify(message, sig).unwrap();
1793        }
1794
1795        // Test that mismatched key/signature pairs fail
1796        for (i, key) in verifying_keys.iter().enumerate() {
1797            for (j, sig) in signatures.iter().enumerate() {
1798                if i != j {
1799                    let is_valid = key.verify(message, sig);
1800                    assert!(
1801                        is_valid.is_err(),
1802                        "Mismatched key and signature should fail verification"
1803                    );
1804                }
1805            }
1806        }
1807    }
1808
1809    #[test]
1810    fn test_verifying_key_pem_round_trip() {
1811        let keys = create_test_verifying_keys();
1812
1813        for original_key in &keys {
1814            // Test PEM encoding/decoding round trip
1815            let pem_string = original_key.to_pem().expect("Should encode to PEM");
1816
1817            // Verify it's valid PEM format
1818            assert!(
1819                pem_string.contains("-----BEGIN ZOE PUBLIC KEY-----"),
1820                "Should contain PEM begin marker with correct label"
1821            );
1822            assert!(
1823                pem_string.contains("-----END ZOE PUBLIC KEY-----"),
1824                "Should contain PEM end marker with correct label"
1825            );
1826
1827            // Verify PEM structure
1828            assert!(
1829                pem_string.lines().count() >= 3,
1830                "PEM should have at least begin, content, and end lines"
1831            );
1832
1833            let restored_key = VerifyingKey::from_pem(&pem_string).expect("Should decode from PEM");
1834
1835            // Verify the keys are functionally equivalent
1836            assert_eq!(
1837                original_key.encode(),
1838                restored_key.encode(),
1839                "Keys should be identical after PEM round trip"
1840            );
1841
1842            assert_eq!(
1843                original_key.algorithm(),
1844                restored_key.algorithm(),
1845                "Algorithms should be identical after PEM round trip"
1846            );
1847
1848            assert_eq!(
1849                original_key.id(),
1850                restored_key.id(),
1851                "Key IDs should be identical after PEM round trip"
1852            );
1853
1854            // Test that multiple encodings are deterministic
1855            let pem_string2 = restored_key.to_pem().expect("Should encode to PEM again");
1856            assert_eq!(
1857                pem_string, pem_string2,
1858                "Multiple PEM encodings should be identical"
1859            );
1860        }
1861    }
1862
1863    #[test]
1864    fn test_verifying_key_pem_error_cases() {
1865        // Test invalid PEM format
1866        let invalid_pem = "not a pem file";
1867        let result = VerifyingKey::from_pem(invalid_pem);
1868        assert!(result.is_err(), "Should fail to parse invalid PEM format");
1869        assert!(
1870            matches!(result.unwrap_err(), VerifyingKeyError::PemParseError(_)),
1871            "Should return PemParseError for invalid format"
1872        );
1873
1874        // Test wrong PEM label
1875        let wrong_label_pem = "-----BEGIN WRONG LABEL-----\nZGF0YQ==\n-----END WRONG LABEL-----";
1876        let result = VerifyingKey::from_pem(wrong_label_pem);
1877        assert!(result.is_err(), "Should fail with wrong PEM label");
1878        assert!(
1879            matches!(result.unwrap_err(), VerifyingKeyError::InvalidPemLabel(_)),
1880            "Should return InvalidPemLabel error"
1881        );
1882
1883        // Test invalid key data in PEM
1884        let invalid_data_pem =
1885            "-----BEGIN ZOE PUBLIC KEY-----\ninvalid_base64_data!\n-----END ZOE PUBLIC KEY-----";
1886        let result = VerifyingKey::from_pem(invalid_data_pem);
1887        assert!(result.is_err(), "Should fail with invalid key data");
1888        // Note: This could be either PemParseError or DeserializationError depending on where it fails
1889    }
1890
1891    #[test]
1892    fn test_verifying_key_pem_compatibility_with_different_algorithms() {
1893        let keys = create_test_verifying_keys();
1894
1895        // Test that each algorithm type can be encoded/decoded via PEM
1896        for key in &keys {
1897            let pem = key.to_pem().expect("Should encode to PEM");
1898            let restored = VerifyingKey::from_pem(&pem).expect("Should decode from PEM");
1899
1900            // Verify algorithm-specific properties are preserved
1901            match (key, &restored) {
1902                (VerifyingKey::Ed25519(_), VerifyingKey::Ed25519(_)) => {
1903                    assert_eq!(key.encode(), restored.encode(), "Ed25519 keys should match");
1904                }
1905                (VerifyingKey::MlDsa44(_), VerifyingKey::MlDsa44(_)) => {
1906                    assert_eq!(
1907                        key.encode(),
1908                        restored.encode(),
1909                        "ML-DSA-44 keys should match"
1910                    );
1911                }
1912                (VerifyingKey::MlDsa65(_), VerifyingKey::MlDsa65(_)) => {
1913                    assert_eq!(
1914                        key.encode(),
1915                        restored.encode(),
1916                        "ML-DSA-65 keys should match"
1917                    );
1918                }
1919                (VerifyingKey::MlDsa87(_), VerifyingKey::MlDsa87(_)) => {
1920                    assert_eq!(
1921                        key.encode(),
1922                        restored.encode(),
1923                        "ML-DSA-87 keys should match"
1924                    );
1925                }
1926                _ => panic!("Algorithm type changed during PEM round trip"),
1927            }
1928        }
1929    }
1930
1931    #[test]
1932    fn test_verifying_key_pem_whitespace_handling() {
1933        let key = create_test_verifying_keys()[0].clone();
1934        let pem = key.to_pem().expect("Should encode to PEM");
1935
1936        // Test with extra whitespace
1937        let pem_with_whitespace = format!("  \n\t{pem}\n  \t");
1938        let restored = VerifyingKey::from_pem(&pem_with_whitespace)
1939            .expect("Should handle whitespace gracefully");
1940
1941        assert_eq!(
1942            key.encode(),
1943            restored.encode(),
1944            "Should handle extra whitespace in PEM"
1945        );
1946
1947        // Test with different line endings
1948        let pem_crlf = pem.replace('\n', "\r\n");
1949        let restored_crlf =
1950            VerifyingKey::from_pem(&pem_crlf).expect("Should handle CRLF line endings");
1951
1952        assert_eq!(
1953            key.encode(),
1954            restored_crlf.encode(),
1955            "Should handle CRLF line endings"
1956        );
1957    }
1958
1959    #[test]
1960    fn test_verifying_key_pem_consistency_with_keypair_pem() {
1961        let keypairs = create_test_keypairs();
1962
1963        for keypair in &keypairs {
1964            let verifying_key = keypair.public_key();
1965            let verifying_key_pem = verifying_key
1966                .to_pem()
1967                .expect("Should encode VerifyingKey to PEM");
1968
1969            // Verify the PEM uses the same label format as KeyPair PEM
1970            assert!(
1971                verifying_key_pem.contains("ZOE PUBLIC KEY"),
1972                "VerifyingKey PEM should use consistent ZOE label format"
1973            );
1974
1975            // Verify round trip works
1976            let restored_key = VerifyingKey::from_pem(&verifying_key_pem)
1977                .expect("Should decode VerifyingKey from PEM");
1978
1979            assert_eq!(
1980                verifying_key.encode(),
1981                restored_key.encode(),
1982                "VerifyingKey PEM round trip should preserve key data"
1983            );
1984
1985            // Verify the restored key can still verify signatures
1986            let message = b"test message for PEM verification";
1987            let signature = keypair.sign(message);
1988
1989            restored_key
1990                .verify(message, &signature)
1991                .expect("Restored key should be able to verify signatures");
1992        }
1993    }
1994
1995    #[test]
1996    fn test_algorithm_ordering_consistency() {
1997        let mut rng = OsRng;
1998
1999        // Create one key of each type
2000        let ed25519_key = KeyPair::generate_ed25519(&mut rng).public_key();
2001        let ml_dsa44_key = KeyPair::generate_ml_dsa44(&mut rng).public_key();
2002        let ml_dsa65_key = KeyPair::generate_ml_dsa65(&mut rng).public_key();
2003        let ml_dsa87_key = KeyPair::generate_ml_dsa87(&mut rng).public_key();
2004
2005        // Test that algorithm order is: Ed25519 < ML-DSA-44 < ML-DSA-65 < ML-DSA-87
2006        assert!(
2007            ed25519_key < ml_dsa44_key,
2008            "Ed25519 should be less than ML-DSA-44"
2009        );
2010        assert!(
2011            ml_dsa44_key < ml_dsa65_key,
2012            "ML-DSA-44 should be less than ML-DSA-65"
2013        );
2014        assert!(
2015            ml_dsa65_key < ml_dsa87_key,
2016            "ML-DSA-65 should be less than ML-DSA-87"
2017        );
2018
2019        // Test same for signatures
2020        let message = b"test message";
2021        let ed25519_sig = KeyPair::generate_ed25519(&mut rng).sign(message);
2022        let ml_dsa44_sig = KeyPair::generate_ml_dsa44(&mut rng).sign(message);
2023        let ml_dsa65_sig = KeyPair::generate_ml_dsa65(&mut rng).sign(message);
2024        let ml_dsa87_sig = KeyPair::generate_ml_dsa87(&mut rng).sign(message);
2025
2026        assert!(
2027            ed25519_sig < ml_dsa44_sig,
2028            "Ed25519 sig should be less than ML-DSA-44 sig"
2029        );
2030        assert!(
2031            ml_dsa44_sig < ml_dsa65_sig,
2032            "ML-DSA-44 sig should be less than ML-DSA-65 sig"
2033        );
2034        assert!(
2035            ml_dsa65_sig < ml_dsa87_sig,
2036            "ML-DSA-65 sig should be less than ML-DSA-87 sig"
2037        );
2038    }
2039
2040    #[test]
2041    fn test_id_across_operations() {
2042        let keypairs = create_test_keypairs();
2043
2044        for keypair in &keypairs {
2045            let public_key = keypair.public_key();
2046            let public_key_id = public_key.id();
2047            assert_eq!(
2048                public_key_id,
2049                keypair.public_key().id(),
2050                "Multiple public key extractions should have same ID"
2051            );
2052
2053            // ID should be stable across serialization
2054            let encoded = postcard::to_stdvec(&public_key).expect("Should serialize");
2055            let decoded: VerifyingKey = postcard::from_bytes(&encoded).expect("Should deserialize");
2056
2057            assert_eq!(
2058                public_key_id,
2059                decoded.id(), // this is the ID of the public key
2060                "ID should be stable across serialization"
2061            );
2062
2063            let signed = keypair.sign(b"test message");
2064            let signature_id = signed.id();
2065
2066            // ID should be stable across serialization
2067            let encoded = postcard::to_stdvec(&signed).expect("Should serialize");
2068            let decoded: Signature = postcard::from_bytes(&encoded).expect("Should deserialize");
2069
2070            assert_eq!(
2071                signature_id,
2072                decoded.id(), // this is the ID of the signature
2073                "signature ID should be stable across serialization"
2074            );
2075        }
2076    }
2077
2078    #[test]
2079    fn test_hash_based_ids_for_ml_dsa() {
2080        let mut rng = OsRng;
2081
2082        // Test that ML-DSA keys use blake3 hash of encoded key as ID
2083        let ml_dsa65_keypair = KeyPair::generate_ml_dsa65(&mut rng);
2084        let verifying_key = ml_dsa65_keypair.public_key();
2085
2086        match verifying_key {
2087            VerifyingKey::MlDsa65((ref key, ref stored_hash)) => {
2088                let computed_hash = blake3::hash(key.as_slice());
2089                assert_eq!(
2090                    stored_hash.as_bytes(),
2091                    computed_hash.as_bytes(),
2092                    "Stored hash should match computed hash of encoded key"
2093                );
2094                assert_eq!(
2095                    verifying_key.id().as_bytes(),
2096                    computed_hash.as_bytes(),
2097                    "ID should be the blake3 hash of encoded key"
2098                );
2099            }
2100            _ => panic!("Expected ML-DSA-65 key"),
2101        }
2102    }
2103
2104    #[test]
2105    fn test_ed25519_id_is_key_bytes() {
2106        let mut rng = OsRng;
2107        let ed25519_keypair = KeyPair::generate_ed25519(&mut rng);
2108        let verifying_key = ed25519_keypair.public_key();
2109
2110        match verifying_key {
2111            VerifyingKey::Ed25519(ref key) => {
2112                assert_eq!(
2113                    verifying_key.id().as_bytes(),
2114                    key.as_bytes(),
2115                    "Ed25519 ID should be the raw key bytes"
2116                );
2117            }
2118            _ => panic!("Expected Ed25519 key"),
2119        }
2120    }
2121
2122    #[test]
2123    fn test_keypair_generate_defaults_to_ml_dsa65() {
2124        let mut rng = OsRng;
2125        let default_keypair = KeyPair::generate(&mut rng);
2126
2127        match default_keypair {
2128            KeyPair::MlDsa65(..) => {
2129                // This is expected
2130            }
2131            _ => panic!("KeyPair::generate should default to ML-DSA-65"),
2132        }
2133    }
2134
2135    #[test]
2136    fn test_signature_id_implementation() {
2137        let mut rng = OsRng;
2138        let message = b"test message";
2139
2140        // Test Ed25519 signature ID uses s_bytes
2141        let ed25519_keypair = KeyPair::generate_ed25519(&mut rng);
2142        let ed25519_sig = ed25519_keypair.sign(message);
2143
2144        match ed25519_sig {
2145            Signature::Ed25519(ref sig) => {
2146                assert_eq!(
2147                    ed25519_sig.id().as_bytes(),
2148                    sig.s_bytes(),
2149                    "Ed25519 signature ID should be s_bytes"
2150                );
2151            }
2152            _ => panic!("Expected Ed25519 signature"),
2153        }
2154
2155        // Test ML-DSA signature ID uses hash
2156        let ml_dsa_keypair = KeyPair::generate_ml_dsa65(&mut rng);
2157        let ml_dsa_sig = ml_dsa_keypair.sign(message);
2158
2159        match ml_dsa_sig {
2160            Signature::MlDsa65((ref sig, ref stored_hash)) => {
2161                let computed_hash = blake3::hash(sig.as_slice());
2162                assert_eq!(
2163                    stored_hash.as_bytes(),
2164                    computed_hash.as_bytes(),
2165                    "Stored hash should match computed hash"
2166                );
2167                assert_eq!(
2168                    ml_dsa_sig.id().as_bytes(),
2169                    computed_hash.as_bytes(),
2170                    "ML-DSA signature ID should be blake3 hash"
2171                );
2172            }
2173            _ => panic!("Expected ML-DSA-65 signature"),
2174        }
2175    }
2176
2177    #[test]
2178    fn test_deterministic_encoding() {
2179        let keypairs = create_test_keypairs();
2180
2181        for keypair in &keypairs {
2182            let key = keypair.public_key();
2183
2184            // Encode multiple times and ensure consistency
2185            let encoded1 = key.encode();
2186            let encoded2 = key.encode();
2187            let encoded3 = postcard::to_stdvec(&key).expect("Should serialize");
2188
2189            assert_eq!(encoded1, encoded2, "Multiple encodings should be identical");
2190            assert_eq!(
2191                encoded2, encoded3,
2192                "Different encoding methods should produce same result"
2193            );
2194        }
2195    }
2196
2197    #[test]
2198    fn test_keypair_pem_round_trip() {
2199        let keypairs = create_test_keypairs();
2200
2201        for original_keypair in keypairs {
2202            // Test PEM encoding/decoding
2203            let pem_string = original_keypair.to_pem().expect("Should encode to PEM");
2204
2205            // Verify it's valid PEM format
2206            assert!(
2207                pem_string.contains("-----BEGIN"),
2208                "Should contain PEM begin marker"
2209            );
2210            assert!(
2211                pem_string.contains("-----END"),
2212                "Should contain PEM end marker"
2213            );
2214
2215            let restored_keypair = KeyPair::from_pem(&pem_string).expect("Should decode from PEM");
2216
2217            // Verify the keypairs are functionally equivalent
2218            assert_eq!(
2219                original_keypair.public_key(),
2220                restored_keypair.public_key(),
2221                "Public keys should be identical after PEM round trip"
2222            );
2223
2224            assert_eq!(
2225                original_keypair.algorithm(),
2226                restored_keypair.algorithm(),
2227                "Algorithms should be identical after PEM round trip"
2228            );
2229
2230            // Test signing functionality is preserved
2231            let message = b"test message for PEM round trip";
2232            let original_signature = original_keypair.sign(message);
2233            let restored_signature = restored_keypair.sign(message);
2234
2235            // Both signatures should verify with the public key
2236            let public_key = original_keypair.public_key();
2237            public_key.verify(message, &original_signature).unwrap();
2238            public_key.verify(message, &restored_signature).unwrap();
2239        }
2240    }
2241
2242    #[test]
2243    fn test_keypair_pem_environment_variable_simulation() {
2244        let keypairs = create_test_keypairs();
2245
2246        for (i, keypair) in keypairs.iter().enumerate() {
2247            // Simulate storing in environment variable
2248            let env_value = keypair
2249                .to_pem()
2250                .expect("Should encode for environment variable");
2251
2252            // Simulate reading from environment variable
2253            let restored_keypair =
2254                KeyPair::from_pem(&env_value).expect("Should decode from environment variable");
2255
2256            // Verify functionality
2257            assert_eq!(
2258                keypair.public_key(),
2259                restored_keypair.public_key(),
2260                "Keypair {i} should survive environment variable round trip"
2261            );
2262
2263            // Test that we can sign and verify
2264            let message = format!("Environment variable test message {i}");
2265            let signature = restored_keypair.sign(message.as_bytes());
2266            restored_keypair
2267                .public_key()
2268                .verify(message.as_bytes(), &signature)
2269                .unwrap();
2270        }
2271    }
2272
2273    #[test]
2274    fn test_keypair_pem_deterministic() {
2275        let mut rng = OsRng;
2276        let keypair = KeyPair::generate_ed25519(&mut rng);
2277
2278        // Multiple serializations should produce identical results
2279        let pem_1 = keypair.to_pem().unwrap();
2280        let pem_2 = keypair.to_pem().unwrap();
2281        let pem_3 = keypair.to_pem().unwrap();
2282
2283        assert_eq!(pem_1, pem_2, "PEM serialization should be deterministic");
2284        assert_eq!(pem_2, pem_3, "PEM serialization should be deterministic");
2285    }
2286
2287    #[test]
2288    fn test_keypair_pem_error_handling() {
2289        // Test invalid PEM format
2290        let invalid_pem = "not a valid PEM file";
2291        let result = KeyPair::from_pem(invalid_pem);
2292        assert!(result.is_err(), "Should fail on invalid PEM format");
2293        assert!(matches!(
2294            result.unwrap_err(),
2295            KeyPairError::InvalidKeyData(_)
2296        ));
2297
2298        // Test unsupported PEM type
2299        let unsupported_pem =
2300            "-----BEGIN CERTIFICATE-----\nVGVzdCBjZXJ0aWZpY2F0ZQ==\n-----END CERTIFICATE-----";
2301        let result = KeyPair::from_pem(unsupported_pem);
2302        assert!(result.is_err(), "Should fail on unsupported PEM type");
2303        assert!(matches!(
2304            result.unwrap_err(),
2305            KeyPairError::InvalidKeyData(_)
2306        ));
2307
2308        // Test Ed25519 key with wrong length
2309        let wrong_length_pem = "-----BEGIN PRIVATE KEY-----\nVGVzdA==\n-----END PRIVATE KEY-----";
2310        let result = KeyPair::from_pem(wrong_length_pem);
2311        assert!(result.is_err(), "Should fail on wrong key length");
2312        assert!(matches!(
2313            result.unwrap_err(),
2314            KeyPairError::InvalidKeyData(_)
2315        ));
2316    }
2317
2318    #[test]
2319    fn test_all_keypair_types_pem_compatibility() {
2320        let mut rng = OsRng;
2321
2322        let test_cases = vec![
2323            ("Ed25519", KeyPair::generate_ed25519(&mut rng)),
2324            ("ML-DSA-44", KeyPair::generate_ml_dsa44(&mut rng)),
2325            ("ML-DSA-65", KeyPair::generate_ml_dsa65(&mut rng)),
2326            ("ML-DSA-87", KeyPair::generate_ml_dsa87(&mut rng)),
2327        ];
2328
2329        for (name, keypair) in test_cases {
2330            // Test PEM round trip
2331            let pem_string = keypair
2332                .to_pem()
2333                .unwrap_or_else(|_| panic!("{name} should encode to PEM"));
2334            let restored = KeyPair::from_pem(&pem_string)
2335                .unwrap_or_else(|_| panic!("{name} should decode from PEM"));
2336
2337            assert_eq!(
2338                keypair.public_key(),
2339                restored.public_key(),
2340                "{name} public key should match after PEM round trip"
2341            );
2342
2343            // Verify signing still works
2344            let message = format!("Test message for {name}");
2345            let signature = restored.sign(message.as_bytes());
2346            restored
2347                .public_key()
2348                .verify(message.as_bytes(), &signature)
2349                .unwrap();
2350
2351            // Verify PEM format contains expected labels
2352            match name {
2353                "Ed25519" => assert!(pem_string.contains("ZOE ED25519 PRIVATE KEY")),
2354                "ML-DSA-44" => {
2355                    assert!(pem_string.contains("ZOE ML-DSA-44 PRIVATE KEY"));
2356                    assert!(pem_string.contains("ZOE ML-DSA-44 PUBLIC KEY"));
2357                }
2358                "ML-DSA-65" => {
2359                    assert!(pem_string.contains("ZOE ML-DSA-65 PRIVATE KEY"));
2360                    assert!(pem_string.contains("ZOE ML-DSA-65 PUBLIC KEY"));
2361                }
2362                "ML-DSA-87" => {
2363                    assert!(pem_string.contains("ZOE ML-DSA-87 PRIVATE KEY"));
2364                    assert!(pem_string.contains("ZOE ML-DSA-87 PUBLIC KEY"));
2365                }
2366                _ => panic!("Unexpected key type"),
2367            }
2368        }
2369    }
2370
2371    #[test]
2372    fn test_pem_format_structure() {
2373        let mut rng = OsRng;
2374
2375        // Test Ed25519 PEM structure
2376        let ed25519_keypair = KeyPair::generate_ed25519(&mut rng);
2377        let ed25519_pem = ed25519_keypair.to_pem().unwrap();
2378
2379        assert!(ed25519_pem.contains("-----BEGIN ZOE ED25519 PRIVATE KEY-----"));
2380        assert!(ed25519_pem.contains("-----END ZOE ED25519 PRIVATE KEY-----"));
2381
2382        // Test ML-DSA PEM structure
2383        let ml_dsa_keypair = KeyPair::generate_ml_dsa65(&mut rng);
2384        let ml_dsa_pem = ml_dsa_keypair.to_pem().unwrap();
2385
2386        assert!(ml_dsa_pem.contains("-----BEGIN ZOE ML-DSA-65 PRIVATE KEY-----"));
2387        assert!(ml_dsa_pem.contains("-----END ZOE ML-DSA-65 PRIVATE KEY-----"));
2388        assert!(ml_dsa_pem.contains("-----BEGIN ZOE ML-DSA-65 PUBLIC KEY-----"));
2389        assert!(ml_dsa_pem.contains("-----END ZOE ML-DSA-65 PUBLIC KEY-----"));
2390
2391        // Verify the PEM files are different (Ed25519 is smaller)
2392        assert!(
2393            ed25519_pem.len() < ml_dsa_pem.len(),
2394            "Ed25519 PEM should be smaller than ML-DSA PEM"
2395        );
2396    }
2397}