use slh_dsa::signature::{Signer, Verifier};
use slh_dsa::{Sha2_128s, Signature, SigningKey, VerifyingKey};
use crate::{CryptoError, KeyType, error::Result};
#[derive(Debug, Clone)]
pub struct KeyPair {
pub key_type: KeyType,
pub private_bytes: Vec<u8>,
pub public_bytes: Vec<u8>,
}
pub fn generate_slh_dsa_sha2_128s() -> KeyPair {
let mut rng = rand_10::rng();
let sk = SigningKey::<Sha2_128s>::new(&mut rng);
let vk = sk.as_ref();
KeyPair {
key_type: KeyType::SlhDsaSha2_128s,
private_bytes: sk.to_bytes().to_vec(),
public_bytes: vk.to_bytes().to_vec(),
}
}
pub fn sign_slh_dsa_sha2_128s(private_key: &[u8], data: &[u8]) -> Result<Vec<u8>> {
let sk = SigningKey::<Sha2_128s>::try_from(private_key)
.map_err(|e| CryptoError::KeyError(format!("Invalid SLH-DSA private key: {e}")))?;
let sig = sk.sign(data);
Ok(sig.to_bytes().to_vec())
}
pub fn verify_slh_dsa_sha2_128s(public_key: &[u8], data: &[u8], signature: &[u8]) -> Result<()> {
let vk = VerifyingKey::<Sha2_128s>::try_from(public_key)
.map_err(|e| CryptoError::KeyError(format!("Invalid SLH-DSA public key: {e}")))?;
let sig = Signature::<Sha2_128s>::try_from(signature)
.map_err(|e| CryptoError::KeyError(format!("Invalid SLH-DSA signature: {e}")))?;
vk.verify(data, &sig)
.map_err(|e| CryptoError::KeyError(format!("SLH-DSA verification failed: {e}")))
}
#[cfg(test)]
mod tests {
use super::*;
fn hex(s: &str) -> Vec<u8> {
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
.collect()
}
#[test]
fn slh_dsa_sha2_128s_roundtrip() {
let kp = generate_slh_dsa_sha2_128s();
assert_eq!(kp.private_bytes.len(), 64);
assert_eq!(kp.public_bytes.len(), 32);
let msg = b"hello slh";
let sig = sign_slh_dsa_sha2_128s(&kp.private_bytes, msg).unwrap();
assert_eq!(sig.len(), 7856);
verify_slh_dsa_sha2_128s(&kp.public_bytes, msg, &sig).unwrap();
}
#[test]
fn slh_dsa_tampered_sig_fails() {
let kp = generate_slh_dsa_sha2_128s();
let mut sig = sign_slh_dsa_sha2_128s(&kp.private_bytes, b"x").unwrap();
sig[42] ^= 0x01;
assert!(verify_slh_dsa_sha2_128s(&kp.public_bytes, b"x", &sig).is_err());
}
#[test]
fn slh_dsa_sha2_128s_nist_kat_keygen() {
let sk_seed = hex("173D04C938C1C36BF289C3C022D04B14");
let sk_prf = hex("63AE23C41AA546DA589774AC20B745C4");
let pk_seed = hex("0D794777914C99766827F0F09CA972BE");
let expected_pk = hex("0D794777914C99766827F0F09CA972BE0162C10219D422ADBA1359E6AA65299C");
let sk = SigningKey::<Sha2_128s>::slh_keygen_internal(&sk_seed, &sk_prf, &pk_seed);
let pk_bytes = sk.as_ref().to_bytes();
assert_eq!(pk_bytes.as_slice(), expected_pk.as_slice());
let sk_bytes = sk.to_bytes();
let sig = sign_slh_dsa_sha2_128s(sk_bytes.as_slice(), b"acvp-roundtrip").unwrap();
verify_slh_dsa_sha2_128s(pk_bytes.as_slice(), b"acvp-roundtrip", &sig).unwrap();
}
}