Skip to main content

lit/crypto/
signatures.rs

1/// Post-quantum digital signatures using NIST ML-DSA
2/// NIST FIPS 204 - Module-Lattice-Based Digital Signature Standard
3use pqcrypto_mldsa::mldsa87;
4use pqcrypto_traits::sign::{DetachedSignature as _, PublicKey as _};
5use serde::{Deserialize, Serialize};
6
7/// Post-quantum signature using ML-DSA-87 (FIPS 204)
8/// ML-DSA-87 provides NIST security level 5 (highest)
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct PQSignature {
11    /// The signature bytes
12    pub signature: Vec<u8>,
13    /// Public key for verification
14    pub public_key: Vec<u8>,
15    /// Algorithm identifier
16    pub algorithm: String,
17}
18
19/// Post-quantum keypair
20pub struct PQKeyPair {
21    pub public_key: mldsa87::PublicKey,
22    pub secret_key: mldsa87::SecretKey,
23}
24
25impl PQKeyPair {
26    /// Generate a new quantum-resistant keypair
27    pub fn generate() -> Self {
28        let (pk, sk) = mldsa87::keypair();
29        PQKeyPair {
30            public_key: pk,
31            secret_key: sk,
32        }
33    }
34
35    /// Sign a message with post-quantum signature
36    pub fn sign(&self, message: &[u8]) -> PQSignature {
37        let sig = mldsa87::detached_sign(message, &self.secret_key);
38
39        PQSignature {
40            signature: sig.as_bytes().to_vec(),
41            public_key: self.public_key.as_bytes().to_vec(),
42            algorithm: "ML-DSA-87".to_string(),
43        }
44    }
45}
46
47impl PQSignature {
48    /// Verify a post-quantum signature
49    pub fn verify(&self, message: &[u8]) -> Result<(), String> {
50        // Reconstruct public key
51        let pk =
52            mldsa87::PublicKey::from_bytes(&self.public_key).map_err(|_| "Invalid public key")?;
53
54        // Reconstruct signature
55        let sig = mldsa87::DetachedSignature::from_bytes(&self.signature)
56            .map_err(|_| "Invalid signature")?;
57
58        // Verify
59        mldsa87::verify_detached_signature(&sig, message, &pk)
60            .map_err(|_| "Signature verification failed".to_string())
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn test_pq_signature() {
70        let keypair = PQKeyPair::generate();
71        let message = b"Test commit message";
72
73        let signature = keypair.sign(message);
74        assert!(signature.verify(message).is_ok());
75
76        // Verify wrong message fails
77        let wrong_message = b"Wrong message";
78        assert!(signature.verify(wrong_message).is_err());
79    }
80}