use crate::{PqcError, Result};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use zeroize::Zeroize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SignatureAlgorithm {
MlDsa44,
MlDsa65,
MlDsa87,
SlhDsa128s,
SlhDsa192s,
SlhDsa256s,
Ed25519,
}
impl SignatureAlgorithm {
pub fn public_key_size(&self) -> usize {
match self {
Self::MlDsa44 => 1312, Self::MlDsa65 => 1952, Self::MlDsa87 => 2592, Self::SlhDsa128s => 32, Self::SlhDsa192s => 48, Self::SlhDsa256s => 64, Self::Ed25519 => 32,
}
}
pub fn secret_key_size(&self) -> usize {
match self {
Self::MlDsa44 => 2560, Self::MlDsa65 => 4032, Self::MlDsa87 => 4896, Self::SlhDsa128s => 64, Self::SlhDsa192s => 96, Self::SlhDsa256s => 128, Self::Ed25519 => 32,
}
}
pub fn signature_size(&self) -> usize {
match self {
Self::MlDsa44 => 2420, Self::MlDsa65 => 3309, Self::MlDsa87 => 4627, Self::SlhDsa128s => 7856, Self::SlhDsa192s => 16224, Self::SlhDsa256s => 29792, Self::Ed25519 => 64,
}
}
#[cfg(feature = "ml-dsa")]
#[allow(dead_code)] pub(crate) fn to_saorsa_variant(&self) -> Option<saorsa_pqc::MlDsaVariant> {
match self {
Self::MlDsa44 => Some(saorsa_pqc::MlDsaVariant::MlDsa44),
Self::MlDsa65 => Some(saorsa_pqc::MlDsaVariant::MlDsa65),
Self::MlDsa87 => Some(saorsa_pqc::MlDsaVariant::MlDsa87),
_ => None,
}
}
}
impl Default for SignatureAlgorithm {
fn default() -> Self {
Self::MlDsa65 }
}
#[derive(Clone, Serialize, Deserialize)]
pub struct VerifyingKey {
pub algorithm: SignatureAlgorithm,
pub key_bytes: Vec<u8>,
}
#[derive(Clone)]
pub struct SigningKey {
pub algorithm: SignatureAlgorithm,
pub key_bytes: Vec<u8>,
}
impl Drop for SigningKey {
fn drop(&mut self) {
self.key_bytes.zeroize();
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DigitalSignature {
pub algorithm: SignatureAlgorithm,
pub signature_bytes: Vec<u8>,
}
#[async_trait]
pub trait Signature: Send + Sync {
async fn generate_keypair(&self, alg: SignatureAlgorithm)
-> Result<(VerifyingKey, SigningKey)>;
async fn sign(&self, key: &SigningKey, message: &[u8]) -> Result<DigitalSignature>;
async fn verify(
&self,
key: &VerifyingKey,
message: &[u8],
signature: &DigitalSignature,
) -> Result<bool>;
}
#[cfg(feature = "ml-dsa")]
pub struct MlDsa {
_phantom: std::marker::PhantomData<()>,
}
#[cfg(feature = "ml-dsa")]
impl MlDsa {
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
#[cfg(feature = "ml-dsa")]
#[async_trait]
impl Signature for MlDsa {
async fn generate_keypair(
&self,
alg: SignatureAlgorithm,
) -> Result<(VerifyingKey, SigningKey)> {
use saorsa_pqc::{MlDsa65, MlDsaOperations};
if !matches!(
alg,
SignatureAlgorithm::MlDsa44 | SignatureAlgorithm::MlDsa65 | SignatureAlgorithm::MlDsa87
) {
return Err(PqcError::UnsupportedAlgorithm(format!(
"{:?} not supported",
alg
)));
}
let ml_dsa = MlDsa65::new();
let (pub_key, sec_key) = ml_dsa
.generate_keypair()
.map_err(|e| PqcError::SignatureError(format!("Keypair generation failed: {:?}", e)))?;
Ok((
VerifyingKey {
algorithm: alg,
key_bytes: pub_key.as_bytes().to_vec(),
},
SigningKey {
algorithm: alg,
key_bytes: sec_key.as_bytes().to_vec(),
},
))
}
async fn sign(&self, key: &SigningKey, message: &[u8]) -> Result<DigitalSignature> {
use saorsa_pqc::{MlDsa65, MlDsaOperations, MlDsaSecretKey};
let ml_dsa = MlDsa65::new();
let sec_key = MlDsaSecretKey::from_bytes(&key.key_bytes)
.map_err(|e| PqcError::SignatureError(format!("Invalid signing key: {:?}", e)))?;
let signature = ml_dsa
.sign(&sec_key, message)
.map_err(|e| PqcError::SignatureError(format!("Signing failed: {:?}", e)))?;
Ok(DigitalSignature {
algorithm: key.algorithm,
signature_bytes: signature.as_bytes().to_vec(),
})
}
async fn verify(
&self,
key: &VerifyingKey,
message: &[u8],
signature: &DigitalSignature,
) -> Result<bool> {
use saorsa_pqc::{MlDsa65, MlDsaOperations, MlDsaPublicKey, MlDsaSignature};
if key.algorithm != signature.algorithm {
return Ok(false);
}
let ml_dsa = MlDsa65::new();
let pub_key = MlDsaPublicKey::from_bytes(&key.key_bytes)
.map_err(|e| PqcError::SignatureError(format!("Invalid verifying key: {:?}", e)))?;
let sig = MlDsaSignature::from_bytes(&signature.signature_bytes)
.map_err(|e| PqcError::SignatureError(format!("Invalid signature: {:?}", e)))?;
Ok(ml_dsa.verify(&pub_key, message, &sig).is_ok())
}
}
pub struct Ed25519Sig;
#[async_trait]
impl Signature for Ed25519Sig {
async fn generate_keypair(
&self,
alg: SignatureAlgorithm,
) -> Result<(VerifyingKey, SigningKey)> {
if !matches!(alg, SignatureAlgorithm::Ed25519) {
return Err(PqcError::UnsupportedAlgorithm(
"Use MlDsa for ML-DSA".into(),
));
}
use ed25519_dalek::SigningKey as Ed25519SigningKey;
use rand::{rngs::OsRng, Rng};
let mut csprng = OsRng;
let mut secret_bytes = [0u8; 32];
csprng.fill(&mut secret_bytes);
let signing_key = Ed25519SigningKey::from_bytes(&secret_bytes);
let verifying_key = signing_key.verifying_key();
Ok((
VerifyingKey {
algorithm: alg,
key_bytes: verifying_key.as_bytes().to_vec(),
},
SigningKey {
algorithm: alg,
key_bytes: signing_key.as_bytes().to_vec(),
},
))
}
async fn sign(&self, key: &SigningKey, message: &[u8]) -> Result<DigitalSignature> {
use ed25519_dalek::{Signer, SigningKey as Ed25519SigningKey};
let mut sk_bytes = [0u8; 32];
sk_bytes.copy_from_slice(&key.key_bytes);
let signing_key = Ed25519SigningKey::from_bytes(&sk_bytes);
let signature = signing_key.sign(message);
Ok(DigitalSignature {
algorithm: key.algorithm,
signature_bytes: signature.to_bytes().to_vec(),
})
}
async fn verify(
&self,
key: &VerifyingKey,
message: &[u8],
signature: &DigitalSignature,
) -> Result<bool> {
use ed25519_dalek::{
Signature as Ed25519Signature, Verifier, VerifyingKey as Ed25519VerifyingKey,
};
let mut vk_bytes = [0u8; 32];
vk_bytes.copy_from_slice(&key.key_bytes);
let verifying_key = Ed25519VerifyingKey::from_bytes(&vk_bytes)
.map_err(|e| PqcError::SignatureError(format!("Invalid verifying key: {}", e)))?;
let mut sig_bytes = [0u8; 64];
sig_bytes.copy_from_slice(&signature.signature_bytes);
let sig = Ed25519Signature::from_bytes(&sig_bytes);
Ok(verifying_key.verify(message, &sig).is_ok())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
#[cfg(feature = "ml-dsa")]
async fn test_ml_dsa_65() {
let signer = MlDsa::new();
let (vk, sk) = signer
.generate_keypair(SignatureAlgorithm::MlDsa65)
.await
.unwrap();
let message = b"Test message for ML-DSA-65";
let signature = signer.sign(&sk, message).await.unwrap();
assert!(signer.verify(&vk, message, &signature).await.unwrap());
assert_eq!(signature.signature_bytes.len(), 3309);
}
#[tokio::test]
async fn test_ed25519() {
let signer = Ed25519Sig;
let (vk, sk) = signer
.generate_keypair(SignatureAlgorithm::Ed25519)
.await
.unwrap();
let message = b"Test message for Ed25519";
let signature = signer.sign(&sk, message).await.unwrap();
assert!(signer.verify(&vk, message, &signature).await.unwrap());
}
}