use paraxiom_pqc::sign::{self as pqc_sign, SignAlgorithm, SigningKey, VerificationKey, Signature};
use sha3::{Sha3_512, Digest};
use zeroize::Zeroize;
use rand::RngCore;
use crate::{QsslError, QsslResult};
pub struct SphincsKem {
pub identity_sk: SigningKey,
pub identity_pk: VerificationKey,
pub ephemeral_sk: SigningKey,
pub ephemeral_pk: VerificationKey,
}
impl SphincsKem {
pub fn new() -> QsslResult<Self> {
let identity = pqc_sign::keypair(SignAlgorithm::SlhDsaShake128f)
.map_err(|e| QsslError::Crypto(format!("SLH-DSA keygen failed: {}", e)))?;
let ephemeral = pqc_sign::keypair(SignAlgorithm::Falcon512)
.map_err(|e| QsslError::Crypto(format!("Falcon keygen failed: {}", e)))?;
Ok(Self {
identity_sk: identity.sk,
identity_pk: identity.vk,
ephemeral_sk: ephemeral.sk,
ephemeral_pk: ephemeral.vk,
})
}
pub fn encapsulate(
&self,
peer_identity_pk: &[u8],
) -> QsslResult<(Vec<u8>, Vec<u8>)> {
let mut ephemeral_secret = vec![0u8; 64];
rand::thread_rng().fill_bytes(&mut ephemeral_secret);
let mut kem_message = Vec::new();
kem_message.extend_from_slice(&self.ephemeral_pk.bytes);
kem_message.extend_from_slice(&ephemeral_secret);
let signature = pqc_sign::sign(&self.identity_sk, &kem_message)
.map_err(|e| QsslError::Crypto(format!("Sign failed: {}", e)))?;
let mut ciphertext = kem_message.clone();
ciphertext.extend_from_slice(&signature.bytes);
let shared_secret = self.derive_shared_secret(
&ephemeral_secret,
peer_identity_pk,
&kem_message,
)?;
ephemeral_secret.zeroize();
Ok((ciphertext, shared_secret))
}
pub fn decapsulate(
&self,
ciphertext: &[u8],
peer_identity_pk: &[u8],
) -> QsslResult<Vec<u8>> {
let falcon_pk_size = self.ephemeral_pk.bytes.len();
const EPHEMERAL_SIZE: usize = 64;
let msg_size = falcon_pk_size + EPHEMERAL_SIZE;
if ciphertext.len() <= msg_size {
return Err(QsslError::Crypto(
format!("Invalid ciphertext size: got {}", ciphertext.len())
));
}
let signed_data = &ciphertext[..msg_size];
let sig_bytes = &ciphertext[msg_size..];
let ephemeral_secret = &ciphertext[falcon_pk_size..msg_size];
let peer_vk = VerificationKey {
algorithm: SignAlgorithm::SlhDsaShake128f,
bytes: peer_identity_pk.to_vec(),
};
let sig = Signature {
algorithm: SignAlgorithm::SlhDsaShake128f,
bytes: sig_bytes.to_vec(),
};
let valid = pqc_sign::verify(&peer_vk, signed_data, &sig)
.map_err(|e| QsslError::Crypto(format!("Verify failed: {}", e)))?;
if !valid {
return Err(QsslError::Crypto("Signature verification failed".to_string()));
}
let shared_secret = self.derive_shared_secret(
ephemeral_secret,
peer_identity_pk,
signed_data,
)?;
Ok(shared_secret)
}
fn derive_shared_secret(
&self,
ephemeral_secret: &[u8],
peer_identity: &[u8],
_transcript: &[u8],
) -> QsslResult<Vec<u8>> {
let mut hasher = Sha3_512::new();
hasher.update(b"SPHINCS+_KEM_v1.0");
hasher.update(ephemeral_secret);
let our_identity = &self.identity_pk.bytes;
if our_identity.as_slice() < peer_identity {
hasher.update(our_identity);
hasher.update(peer_identity);
} else {
hasher.update(peer_identity);
hasher.update(our_identity);
}
let hash = hasher.finalize();
Ok(hash[..32].to_vec())
}
}
pub struct HybridKem {
sphincs_kem: SphincsKem,
falcon_sk: SigningKey,
falcon_pk: VerificationKey,
}
impl HybridKem {
pub fn new() -> QsslResult<Self> {
let sphincs_kem = SphincsKem::new()?;
let falcon_kp = pqc_sign::keypair(SignAlgorithm::Falcon512)
.map_err(|e| QsslError::Crypto(format!("Falcon keygen failed: {}", e)))?;
Ok(Self {
sphincs_kem,
falcon_sk: falcon_kp.sk,
falcon_pk: falcon_kp.vk,
})
}
pub fn encapsulate(
&self,
peer_sphincs_pk: &[u8],
_peer_falcon_pk: &[u8],
) -> QsslResult<(Vec<u8>, Vec<u8>)> {
let (sphincs_ct, sphincs_ss) = self.sphincs_kem.encapsulate(peer_sphincs_pk)?;
let mut falcon_ephemeral = vec![0u8; 32];
rand::thread_rng().fill_bytes(&mut falcon_ephemeral);
let falcon_sig = pqc_sign::sign(&self.falcon_sk, &falcon_ephemeral)
.map_err(|e| QsslError::Crypto(format!("Falcon sign failed: {}", e)))?;
let mut hybrid_ct = Vec::new();
hybrid_ct.extend_from_slice(&(sphincs_ct.len() as u32).to_be_bytes());
hybrid_ct.extend_from_slice(&sphincs_ct);
hybrid_ct.extend_from_slice(&falcon_ephemeral);
hybrid_ct.extend_from_slice(&falcon_sig.bytes);
let mut hasher = Sha3_512::new();
hasher.update(b"HYBRID_KEM");
hasher.update(&sphincs_ss);
hasher.update(&falcon_ephemeral);
let final_ss = hasher.finalize();
Ok((hybrid_ct, final_ss[..32].to_vec()))
}
pub fn decapsulate(
&self,
ciphertext: &[u8],
peer_sphincs_pk: &[u8],
peer_falcon_pk: &[u8],
) -> QsslResult<Vec<u8>> {
if ciphertext.len() < 4 {
return Err(QsslError::Crypto("Invalid hybrid ciphertext".to_string()));
}
let sphincs_len = u32::from_be_bytes([
ciphertext[0], ciphertext[1], ciphertext[2], ciphertext[3]
]) as usize;
if ciphertext.len() < 4 + sphincs_len + 32 {
return Err(QsslError::Crypto("Invalid hybrid ciphertext size".into()));
}
let sphincs_ct = &ciphertext[4..4 + sphincs_len];
let falcon_ephemeral = &ciphertext[4 + sphincs_len..4 + sphincs_len + 32];
let falcon_sig_bytes = &ciphertext[4 + sphincs_len + 32..];
let peer_vk = VerificationKey {
algorithm: SignAlgorithm::Falcon512,
bytes: peer_falcon_pk.to_vec(),
};
let sig = Signature {
algorithm: SignAlgorithm::Falcon512,
bytes: falcon_sig_bytes.to_vec(),
};
let valid = pqc_sign::verify(&peer_vk, falcon_ephemeral, &sig)
.map_err(|e| QsslError::Crypto(format!("Falcon verify failed: {}", e)))?;
if !valid {
return Err(QsslError::Crypto("Falcon signature verification failed".into()));
}
let sphincs_ss = self.sphincs_kem.decapsulate(sphincs_ct, peer_sphincs_pk)?;
let mut hasher = Sha3_512::new();
hasher.update(b"HYBRID_KEM");
hasher.update(&sphincs_ss);
hasher.update(falcon_ephemeral);
let final_ss = hasher.finalize();
Ok(final_ss[..32].to_vec())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sphincs_kem() {
let alice = SphincsKem::new().unwrap();
let bob = SphincsKem::new().unwrap();
let alice_pk = &alice.identity_pk.bytes;
let bob_pk = &bob.identity_pk.bytes;
let (ciphertext, alice_secret) = alice.encapsulate(bob_pk).unwrap();
let bob_secret = bob.decapsulate(&ciphertext, alice_pk).unwrap();
assert_eq!(alice_secret, bob_secret);
}
#[test]
fn test_hybrid_kem() {
let alice = HybridKem::new().unwrap();
let bob = HybridKem::new().unwrap();
let alice_sphincs = &alice.sphincs_kem.identity_pk.bytes;
let alice_falcon = &alice.falcon_pk.bytes;
let bob_sphincs = &bob.sphincs_kem.identity_pk.bytes;
let bob_falcon = &bob.falcon_pk.bytes;
let (ct, alice_ss) = alice.encapsulate(bob_sphincs, bob_falcon).unwrap();
let bob_ss = bob.decapsulate(&ct, alice_sphincs, alice_falcon).unwrap();
assert_eq!(alice_ss, bob_ss);
}
}