use crate::error::{MrvbError, MrvbResult};
use crate::pqc::{Dilithium3KeyPair, Dilithium3PublicKey, Dilithium3Signer, Dilithium3Verifier};
use base64::Engine;
use ed25519_dalek::{Signature, Signer as Ed25519SignerTrait, SigningKey, Verifier, VerifyingKey};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HybridSignature {
pub classical_sig: String, pub pqc_sig: String, pub algorithm: String,
}
impl HybridSignature {
pub fn new(classical_sig: String, pqc_sig: String) -> Self {
Self {
classical_sig,
pqc_sig,
algorithm: "Ed25519+Dilithium3".to_string(),
}
}
pub fn to_json(&self) -> MrvbResult<String> {
serde_json::to_string(self).map_err(|e| MrvbError::EncodingError(e.to_string()))
}
pub fn from_json(json: &str) -> MrvbResult<Self> {
serde_json::from_str(json).map_err(|e| MrvbError::EncodingError(e.to_string()))
}
}
#[derive(Debug, Clone)]
pub struct HybridKeyPair {
pub ed25519_signing_key: SigningKey,
pub ed25519_verifying_key: VerifyingKey,
pub dilithium3_keypair: Dilithium3KeyPair,
}
impl HybridKeyPair {
pub fn generate() -> Self {
let mut rng = rand::thread_rng();
let ed25519_signing_key = SigningKey::generate(&mut rng);
let ed25519_verifying_key = ed25519_signing_key.verifying_key();
let dilithium3_keypair = Dilithium3KeyPair::generate();
Self {
ed25519_signing_key,
ed25519_verifying_key,
dilithium3_keypair,
}
}
pub fn ed25519_public_key_bytes(&self) -> [u8; 32] {
self.ed25519_verifying_key.to_bytes()
}
pub fn dilithium3_public_key(&self) -> &Dilithium3PublicKey {
&self.dilithium3_keypair.public_key
}
}
pub struct HybridSigner {
ed25519_signing_key: SigningKey,
ed25519_verifying_key: VerifyingKey,
dilithium3_signer: Dilithium3Signer,
}
impl HybridSigner {
pub fn new(keypair: HybridKeyPair) -> Self {
let dilithium3_signer = Dilithium3Signer::new(keypair.dilithium3_keypair);
Self {
ed25519_signing_key: keypair.ed25519_signing_key,
ed25519_verifying_key: keypair.ed25519_verifying_key,
dilithium3_signer,
}
}
pub fn ed25519_verifying_key(&self) -> &VerifyingKey {
&self.ed25519_verifying_key
}
pub fn dilithium3_public_key(&self) -> &Dilithium3PublicKey {
self.dilithium3_signer.public_key()
}
pub fn sign(&self, message: &[u8]) -> MrvbResult<HybridSignature> {
let ed25519_sig: Signature = self.ed25519_signing_key.sign(message);
let classical_sig = base64::engine::general_purpose::STANDARD.encode(ed25519_sig.to_bytes());
let pqc_sig = self.dilithium3_signer.sign_base64(message)?;
Ok(HybridSignature::new(classical_sig, pqc_sig))
}
pub fn sign_json(&self, message: &[u8]) -> MrvbResult<String> {
let sig = self.sign(message)?;
sig.to_json()
}
}
impl std::fmt::Debug for HybridSigner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HybridSigner")
.field("ed25519_verifying_key", &self.ed25519_verifying_key)
.field("dilithium3_signer", &self.dilithium3_signer)
.finish()
}
}
#[derive(Debug, Clone)]
pub struct HybridVerifier {
ed25519_verifying_key: VerifyingKey,
dilithium3_verifier: Dilithium3Verifier,
}
impl HybridVerifier {
pub fn new(
ed25519_verifying_key: VerifyingKey,
dilithium3_public_key: Dilithium3PublicKey,
) -> Self {
let dilithium3_verifier = Dilithium3Verifier::new(dilithium3_public_key);
Self {
ed25519_verifying_key,
dilithium3_verifier,
}
}
pub fn from_public_key_bytes(
ed25519_public_key: &[u8; 32],
dilithium3_public_key_bytes: &[u8],
) -> MrvbResult<Self> {
let ed25519_verifying_key = VerifyingKey::from_bytes(ed25519_public_key)
.map_err(|e| MrvbError::CryptoError(format!("Invalid Ed25519 public key: {}", e)))?;
let dilithium3_public_key = Dilithium3PublicKey::from_bytes(dilithium3_public_key_bytes)?;
Ok(Self::new(ed25519_verifying_key, dilithium3_public_key))
}
pub fn ed25519_verifying_key(&self) -> &VerifyingKey {
&self.ed25519_verifying_key
}
pub fn dilithium3_public_key(&self) -> &Dilithium3PublicKey {
self.dilithium3_verifier.public_key()
}
pub fn verify(&self, message: &[u8], signature: &HybridSignature) -> MrvbResult<bool> {
if signature.algorithm != "Ed25519+Dilithium3" {
return Err(MrvbError::InvalidAlgorithm {
expected: "Ed25519+Dilithium3".to_string(),
actual: signature.algorithm.clone(),
});
}
let ed25519_sig_bytes = base64::engine::general_purpose::STANDARD
.decode(&signature.classical_sig)
.map_err(|e| MrvbError::EncodingError(e.to_string()))?;
let ed25519_sig = Signature::from_slice(&ed25519_sig_bytes)
.map_err(|e| MrvbError::CryptoError(format!("Invalid Ed25519 signature: {}", e)))?;
let ed25519_valid = self
.ed25519_verifying_key
.verify(message, &ed25519_sig)
.is_ok();
if !ed25519_valid {
return Ok(false);
}
let dilithium3_valid = self
.dilithium3_verifier
.verify_base64(message, &signature.pqc_sig)?;
Ok(ed25519_valid && dilithium3_valid)
}
pub fn verify_json(&self, message: &[u8], signature_json: &str) -> MrvbResult<bool> {
let signature = HybridSignature::from_json(signature_json)?;
self.verify(message, &signature)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hybrid_key_generation() {
let keypair = HybridKeyPair::generate();
assert_eq!(keypair.ed25519_public_key_bytes().len(), 32);
assert!(!keypair.dilithium3_public_key().as_bytes().is_empty());
}
#[test]
fn test_hybrid_sign_and_verify() {
let keypair = HybridKeyPair::generate();
let signer = HybridSigner::new(keypair.clone());
let verifier = HybridVerifier::new(
keypair.ed25519_verifying_key,
keypair.dilithium3_keypair.public_key,
);
let message = b"Hybrid quantum-resistant message";
let signature = signer.sign(message).unwrap();
assert!(verifier.verify(message, &signature).unwrap());
let wrong_message = b"Wrong message";
assert!(!verifier.verify(wrong_message, &signature).unwrap());
}
#[test]
fn test_hybrid_signature_json() {
let keypair = HybridKeyPair::generate();
let signer = HybridSigner::new(keypair.clone());
let message = b"Test message";
let sig_json = signer.sign_json(message).unwrap();
assert!(sig_json.contains("classical_sig"));
assert!(sig_json.contains("pqc_sig"));
assert!(sig_json.contains("Ed25519+Dilithium3"));
let verifier = HybridVerifier::new(
keypair.ed25519_verifying_key,
keypair.dilithium3_keypair.public_key,
);
assert!(verifier.verify_json(message, &sig_json).unwrap());
}
#[test]
fn test_hybrid_signature_structure() {
let keypair = HybridKeyPair::generate();
let signer = HybridSigner::new(keypair);
let message = b"Test";
let signature = signer.sign(message).unwrap();
assert_eq!(signature.algorithm, "Ed25519+Dilithium3");
assert!(!signature.classical_sig.is_empty());
assert!(!signature.pqc_sig.is_empty());
let json = signature.to_json().unwrap();
let restored = HybridSignature::from_json(&json).unwrap();
assert_eq!(signature.classical_sig, restored.classical_sig);
assert_eq!(signature.pqc_sig, restored.pqc_sig);
assert_eq!(signature.algorithm, restored.algorithm);
}
#[test]
fn test_invalid_algorithm_rejection() {
let keypair = HybridKeyPair::generate();
let signer = HybridSigner::new(keypair.clone());
let verifier = HybridVerifier::new(
keypair.ed25519_verifying_key,
keypair.dilithium3_keypair.public_key,
);
let message = b"Test";
let mut signature = signer.sign(message).unwrap();
signature.algorithm = "WrongAlgorithm".to_string();
let result = verifier.verify(message, &signature);
assert!(result.is_err());
match result {
Err(MrvbError::InvalidAlgorithm { expected, actual }) => {
assert_eq!(expected, "Ed25519+Dilithium3");
assert_eq!(actual, "WrongAlgorithm");
}
_ => panic!("Expected InvalidAlgorithm error"),
}
}
#[test]
fn test_tampered_classical_signature_rejected() {
let keypair = HybridKeyPair::generate();
let signer = HybridSigner::new(keypair.clone());
let verifier = HybridVerifier::new(
keypair.ed25519_verifying_key,
keypair.dilithium3_keypair.public_key,
);
let message = b"Test";
let mut signature = signer.sign(message).unwrap();
signature.classical_sig = base64::engine::general_purpose::STANDARD.encode(&[0u8; 64]);
assert!(!verifier.verify(message, &signature).unwrap());
}
#[test]
fn test_tampered_pqc_signature_rejected() {
let keypair = HybridKeyPair::generate();
let signer = HybridSigner::new(keypair.clone());
let verifier = HybridVerifier::new(
keypair.ed25519_verifying_key,
keypair.dilithium3_keypair.public_key,
);
let message = b"Test";
let mut signature = signer.sign(message).unwrap();
signature.pqc_sig = base64::engine::general_purpose::STANDARD.encode(&[0u8; 100]);
let result = verifier.verify(message, &signature);
assert!(result.is_err() || !result.unwrap());
}
#[test]
fn test_both_signatures_must_be_valid() {
let keypair1 = HybridKeyPair::generate();
let keypair2 = HybridKeyPair::generate();
let signer = HybridSigner::new(keypair1.clone());
let verifier = HybridVerifier::new(
keypair1.ed25519_verifying_key, keypair2.dilithium3_keypair.public_key, );
let message = b"Test";
let signature = signer.sign(message).unwrap();
assert!(!verifier.verify(message, &signature).unwrap());
}
}