use oxicrypto_core::CryptoError;
use rand_core::CryptoRng;
use slh_dsa::signature::{Keypair, Signer as SlhSigner, Verifier as SlhVerifier};
use slh_dsa::{
Sha2_128f, Sha2_128s, Sha2_192f, Sha2_192s, Sha2_256f, Sha2_256s, Shake128f, Shake128s,
Shake256f, Shake256s, SigningKey, VerifyingKey,
};
use zeroize::ZeroizeOnDrop;
pub const SLH_DSA_SHA2_128S_SK_LEN: usize = 64;
pub const SLH_DSA_SHA2_128S_VK_LEN: usize = 32;
pub const SLH_DSA_SHA2_128S_SIG_LEN: usize = 7856;
pub const SLH_DSA_SHA2_128F_SK_LEN: usize = 64;
pub const SLH_DSA_SHA2_128F_VK_LEN: usize = 32;
pub const SLH_DSA_SHA2_128F_SIG_LEN: usize = 17088;
pub const SLH_DSA_SHA2_256S_SK_LEN: usize = 128;
pub const SLH_DSA_SHA2_256S_VK_LEN: usize = 64;
pub const SLH_DSA_SHA2_256S_SIG_LEN: usize = 29792;
pub const SLH_DSA_SHA2_256F_SK_LEN: usize = 128;
pub const SLH_DSA_SHA2_256F_VK_LEN: usize = 64;
pub const SLH_DSA_SHA2_256F_SIG_LEN: usize = 49856;
pub const SLH_DSA_SHAKE_128S_SK_LEN: usize = 64;
pub const SLH_DSA_SHAKE_128S_VK_LEN: usize = 32;
pub const SLH_DSA_SHAKE_128S_SIG_LEN: usize = 7856;
pub const SLH_DSA_SHAKE_128F_SK_LEN: usize = 64;
pub const SLH_DSA_SHAKE_128F_VK_LEN: usize = 32;
pub const SLH_DSA_SHAKE_128F_SIG_LEN: usize = 17088;
pub const SLH_DSA_SHA2_192S_SK_LEN: usize = 96;
pub const SLH_DSA_SHA2_192S_VK_LEN: usize = 48;
pub const SLH_DSA_SHA2_192S_SIG_LEN: usize = 16224;
pub const SLH_DSA_SHA2_192F_SK_LEN: usize = 96;
pub const SLH_DSA_SHA2_192F_VK_LEN: usize = 48;
pub const SLH_DSA_SHA2_192F_SIG_LEN: usize = 35664;
pub const SLH_DSA_SHAKE_256S_SK_LEN: usize = 128;
pub const SLH_DSA_SHAKE_256S_VK_LEN: usize = 64;
pub const SLH_DSA_SHAKE_256S_SIG_LEN: usize = 29792;
pub const SLH_DSA_SHAKE_256F_SK_LEN: usize = 128;
pub const SLH_DSA_SHAKE_256F_VK_LEN: usize = 64;
pub const SLH_DSA_SHAKE_256F_SIG_LEN: usize = 49856;
macro_rules! impl_slh_dsa_param {
(
unit = $unit:ident,
sk = $sk:ident,
vk = $vk:ident,
sig = $sig:ident,
params = $params:ty,
sk_len = $sk_len:ident,
vk_len = $vk_len:ident,
sig_len = $sig_len:ident,
name = $name:literal $(,)?
) => {
pub struct $sk(SigningKey<$params>);
impl ZeroizeOnDrop for $sk {}
impl $sk {
pub fn sign(&self, msg: &[u8]) -> Result<$sig, CryptoError> {
self.0
.try_sign(msg)
.map($sig)
.map_err(|_| CryptoError::Sign)
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes().to_vec()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
SigningKey::<$params>::try_from(bytes)
.map(Self)
.map_err(|_| CryptoError::Encoding)
}
}
impl core::fmt::Debug for $sk {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}(***)", stringify!($sk))
}
}
pub struct $vk(VerifyingKey<$params>);
impl $vk {
pub fn verify(&self, msg: &[u8], sig: &$sig) -> Result<(), CryptoError> {
self.0.verify(msg, &sig.0).map_err(|_| CryptoError::Sign)
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes().to_vec()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
VerifyingKey::<$params>::try_from(bytes)
.map(Self)
.map_err(|_| CryptoError::Encoding)
}
}
impl core::fmt::Debug for $vk {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}(len={})", stringify!($vk), $vk_len)
}
}
pub struct $sig(slh_dsa::Signature<$params>);
impl $sig {
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes().to_vec()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
slh_dsa::Signature::<$params>::try_from(bytes)
.map(Self)
.map_err(|_| CryptoError::Encoding)
}
}
impl core::fmt::Debug for $sig {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}(len={})", stringify!($sig), $sig_len)
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct $unit;
impl $unit {
pub fn generate<R: CryptoRng>(rng: &mut R) -> ($sk, $vk) {
let sk = SigningKey::<$params>::new(rng);
let vk = sk.verifying_key();
($sk(sk), $vk(vk))
}
}
impl oxicrypto_core::Signer for $unit {
fn name(&self) -> &'static str {
$name
}
fn signature_len(&self) -> usize {
$sig_len
}
fn sign(
&self,
sk: &[u8],
msg: &[u8],
sig_out: &mut [u8],
) -> Result<usize, CryptoError> {
if sig_out.len() < $sig_len {
return Err(CryptoError::BufferTooSmall);
}
let signing_key = $sk::from_bytes(sk)?;
let sig = signing_key.sign(msg)?;
let sig_bytes = sig.to_bytes();
sig_out[..sig_bytes.len()].copy_from_slice(&sig_bytes);
Ok(sig_bytes.len())
}
}
impl oxicrypto_core::Verifier for $unit {
fn name(&self) -> &'static str {
$name
}
fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
let vk = $vk::from_bytes(pk)?;
let signature = $sig::from_bytes(sig)?;
vk.verify(msg, &signature)
}
}
};
}
impl_slh_dsa_param! {
unit = SlhDsaSha2_128s,
sk = SlhDsaSigningKey128s,
vk = SlhDsaVerifyingKey128s,
sig = SlhDsaSignature128s,
params = Sha2_128s,
sk_len = SLH_DSA_SHA2_128S_SK_LEN,
vk_len = SLH_DSA_SHA2_128S_VK_LEN,
sig_len = SLH_DSA_SHA2_128S_SIG_LEN,
name = "SLH-DSA-SHA2-128s",
}
impl_slh_dsa_param! {
unit = SlhDsaSha2_128f,
sk = SlhDsaSigningKey128f,
vk = SlhDsaVerifyingKey128f,
sig = SlhDsaSignature128f,
params = Sha2_128f,
sk_len = SLH_DSA_SHA2_128F_SK_LEN,
vk_len = SLH_DSA_SHA2_128F_VK_LEN,
sig_len = SLH_DSA_SHA2_128F_SIG_LEN,
name = "SLH-DSA-SHA2-128f",
}
impl_slh_dsa_param! {
unit = SlhDsaSha2_256s,
sk = SlhDsaSigningKey256s,
vk = SlhDsaVerifyingKey256s,
sig = SlhDsaSignature256s,
params = Sha2_256s,
sk_len = SLH_DSA_SHA2_256S_SK_LEN,
vk_len = SLH_DSA_SHA2_256S_VK_LEN,
sig_len = SLH_DSA_SHA2_256S_SIG_LEN,
name = "SLH-DSA-SHA2-256s",
}
impl_slh_dsa_param! {
unit = SlhDsaSha2_256f,
sk = SlhDsaSigningKey256f,
vk = SlhDsaVerifyingKey256f,
sig = SlhDsaSignature256f,
params = Sha2_256f,
sk_len = SLH_DSA_SHA2_256F_SK_LEN,
vk_len = SLH_DSA_SHA2_256F_VK_LEN,
sig_len = SLH_DSA_SHA2_256F_SIG_LEN,
name = "SLH-DSA-SHA2-256f",
}
impl_slh_dsa_param! {
unit = SlhDsaShake128s,
sk = SlhDsaSigningKeyShake128s,
vk = SlhDsaVerifyingKeyShake128s,
sig = SlhDsaSignatureShake128s,
params = Shake128s,
sk_len = SLH_DSA_SHAKE_128S_SK_LEN,
vk_len = SLH_DSA_SHAKE_128S_VK_LEN,
sig_len = SLH_DSA_SHAKE_128S_SIG_LEN,
name = "SLH-DSA-SHAKE-128s",
}
impl_slh_dsa_param! {
unit = SlhDsaShake128f,
sk = SlhDsaSigningKeyShake128f,
vk = SlhDsaVerifyingKeyShake128f,
sig = SlhDsaSignatureShake128f,
params = Shake128f,
sk_len = SLH_DSA_SHAKE_128F_SK_LEN,
vk_len = SLH_DSA_SHAKE_128F_VK_LEN,
sig_len = SLH_DSA_SHAKE_128F_SIG_LEN,
name = "SLH-DSA-SHAKE-128f",
}
impl_slh_dsa_param! {
unit = SlhDsaSha2_192s,
sk = SlhDsaSigningKey192s,
vk = SlhDsaVerifyingKey192s,
sig = SlhDsaSignature192s,
params = Sha2_192s,
sk_len = SLH_DSA_SHA2_192S_SK_LEN,
vk_len = SLH_DSA_SHA2_192S_VK_LEN,
sig_len = SLH_DSA_SHA2_192S_SIG_LEN,
name = "SLH-DSA-SHA2-192s",
}
impl_slh_dsa_param! {
unit = SlhDsaSha2_192f,
sk = SlhDsaSigningKey192f,
vk = SlhDsaVerifyingKey192f,
sig = SlhDsaSignature192f,
params = Sha2_192f,
sk_len = SLH_DSA_SHA2_192F_SK_LEN,
vk_len = SLH_DSA_SHA2_192F_VK_LEN,
sig_len = SLH_DSA_SHA2_192F_SIG_LEN,
name = "SLH-DSA-SHA2-192f",
}
impl_slh_dsa_param! {
unit = SlhDsaShake256s,
sk = SlhDsaSigningKeyShake256s,
vk = SlhDsaVerifyingKeyShake256s,
sig = SlhDsaSignatureShake256s,
params = Shake256s,
sk_len = SLH_DSA_SHAKE_256S_SK_LEN,
vk_len = SLH_DSA_SHAKE_256S_VK_LEN,
sig_len = SLH_DSA_SHAKE_256S_SIG_LEN,
name = "SLH-DSA-SHAKE-256s",
}
impl_slh_dsa_param! {
unit = SlhDsaShake256f,
sk = SlhDsaSigningKeyShake256f,
vk = SlhDsaVerifyingKeyShake256f,
sig = SlhDsaSignatureShake256f,
params = Shake256f,
sk_len = SLH_DSA_SHAKE_256F_SK_LEN,
vk_len = SLH_DSA_SHAKE_256F_VK_LEN,
sig_len = SLH_DSA_SHAKE_256F_SIG_LEN,
name = "SLH-DSA-SHAKE-256f",
}
#[cfg(test)]
mod tests {
use super::*;
use rand_chacha::ChaCha20Rng;
use rand_core::SeedableRng;
const TEST_MSG: &[u8] = b"oxicrypto-pq SLH-DSA test message";
#[test]
#[ignore] fn test_slh_dsa_sha2_128s_round_trip() {
let mut rng = ChaCha20Rng::from_seed([0xA1u8; 32]);
let (sk, vk) = SlhDsaSha2_128s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sha2_128s sign failed");
vk.verify(TEST_MSG, &sig).expect("sha2_128s verify failed");
}
#[test]
#[ignore] fn test_slh_dsa_sha2_128s_wrong_message_fails() {
let mut rng = ChaCha20Rng::from_seed([0xA2u8; 32]);
let (sk, vk) = SlhDsaSha2_128s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut altered = TEST_MSG.to_vec();
altered[0] ^= 0x01;
assert!(
vk.verify(&altered, &sig).is_err(),
"sha2_128s verify should fail on altered message"
);
}
#[test]
fn test_slh_dsa_sha2_128f_round_trip() {
let mut rng = ChaCha20Rng::from_seed([0xB1u8; 32]);
let (sk, vk) = SlhDsaSha2_128f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sha2_128f sign failed");
vk.verify(TEST_MSG, &sig).expect("sha2_128f verify failed");
}
#[test]
fn test_slh_dsa_sha2_128f_wrong_message_fails() {
let mut rng = ChaCha20Rng::from_seed([0xB2u8; 32]);
let (sk, vk) = SlhDsaSha2_128f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut altered = TEST_MSG.to_vec();
altered[0] ^= 0xFF;
assert!(
vk.verify(&altered, &sig).is_err(),
"sha2_128f verify should fail on altered message"
);
}
#[test]
#[ignore] fn test_slh_dsa_sha2_256s_round_trip() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0xC1u8; 32]);
let (sk, vk) = SlhDsaSha2_256s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sha2_256s sign failed");
vk.verify(TEST_MSG, &sig).expect("sha2_256s verify failed");
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
fn test_slh_dsa_sha2_256f_round_trip() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0xD1u8; 32]);
let (sk, vk) = SlhDsaSha2_256f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sha2_256f sign failed");
vk.verify(TEST_MSG, &sig).expect("sha2_256f verify failed");
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_shake_128s_round_trip() {
let mut rng = ChaCha20Rng::from_seed([0xE1u8; 32]);
let (sk, vk) = SlhDsaShake128s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("shake_128s sign failed");
vk.verify(TEST_MSG, &sig).expect("shake_128s verify failed");
}
#[test]
#[ignore] fn test_slh_dsa_shake_128s_wrong_message_fails() {
let mut rng = ChaCha20Rng::from_seed([0xE2u8; 32]);
let (sk, vk) = SlhDsaShake128s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut altered = TEST_MSG.to_vec();
altered[3] ^= 0x55;
assert!(
vk.verify(&altered, &sig).is_err(),
"shake_128s verify should fail on altered message"
);
}
#[test]
fn test_slh_dsa_shake_128f_round_trip() {
let mut rng = ChaCha20Rng::from_seed([0xF1u8; 32]);
let (sk, vk) = SlhDsaShake128f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("shake_128f sign failed");
vk.verify(TEST_MSG, &sig).expect("shake_128f verify failed");
}
#[test]
fn test_slh_dsa_shake_128f_wrong_message_fails() {
let mut rng = ChaCha20Rng::from_seed([0xF2u8; 32]);
let (sk, vk) = SlhDsaShake128f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut altered = TEST_MSG.to_vec();
altered[5] ^= 0x11;
assert!(
vk.verify(&altered, &sig).is_err(),
"shake_128f verify should fail on altered message"
);
}
#[test]
#[ignore] fn test_slh_dsa_sha2_192s_round_trip() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0x91u8; 32]);
let (sk, vk) = SlhDsaSha2_192s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sha2_192s sign failed");
vk.verify(TEST_MSG, &sig).expect("sha2_192s verify failed");
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_sha2_192s_wrong_message_fails() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0x92u8; 32]);
let (sk, vk) = SlhDsaSha2_192s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut altered = TEST_MSG.to_vec();
altered[2] ^= 0xAA;
assert!(
vk.verify(&altered, &sig).is_err(),
"sha2_192s verify should fail on altered message"
);
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_sha2_192f_round_trip() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0x93u8; 32]);
let (sk, vk) = SlhDsaSha2_192f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sha2_192f sign failed");
vk.verify(TEST_MSG, &sig).expect("sha2_192f verify failed");
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_sha2_192f_wrong_message_fails() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0x94u8; 32]);
let (sk, vk) = SlhDsaSha2_192f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut altered = TEST_MSG.to_vec();
altered[7] ^= 0xBB;
assert!(
vk.verify(&altered, &sig).is_err(),
"sha2_192f verify should fail on altered message"
);
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_shake_256s_round_trip() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0x95u8; 32]);
let (sk, vk) = SlhDsaShake256s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("shake_256s sign failed");
vk.verify(TEST_MSG, &sig).expect("shake_256s verify failed");
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_shake_256s_wrong_message_fails() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0x96u8; 32]);
let (sk, vk) = SlhDsaShake256s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut altered = TEST_MSG.to_vec();
altered[1] ^= 0xCC;
assert!(
vk.verify(&altered, &sig).is_err(),
"shake_256s verify should fail on altered message"
);
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_shake_256f_round_trip() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0x97u8; 32]);
let (sk, vk) = SlhDsaShake256f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("shake_256f sign failed");
vk.verify(TEST_MSG, &sig).expect("shake_256f verify failed");
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_shake_256f_wrong_message_fails() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0x98u8; 32]);
let (sk, vk) = SlhDsaShake256f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut altered = TEST_MSG.to_vec();
altered[4] ^= 0xDD;
assert!(
vk.verify(&altered, &sig).is_err(),
"shake_256f verify should fail on altered message"
);
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_serialization_round_trip() {
let mut rng = ChaCha20Rng::from_seed([0x11u8; 32]);
let (sk, vk) = SlhDsaSha2_128s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let sk_bytes = sk.to_bytes();
let sk2 = SlhDsaSigningKey128s::from_bytes(&sk_bytes).expect("sk from_bytes failed");
let sig2 = sk2
.sign(TEST_MSG)
.expect("sign with deserialized sk failed");
let vk_bytes = vk.to_bytes();
let vk2 = SlhDsaVerifyingKey128s::from_bytes(&vk_bytes).expect("vk from_bytes failed");
vk2.verify(TEST_MSG, &sig)
.expect("verify with deserialized vk failed");
vk2.verify(TEST_MSG, &sig2)
.expect("verify sig2 with deserialized vk failed");
let sig_bytes = sig.to_bytes();
let sig3 = SlhDsaSignature128s::from_bytes(&sig_bytes).expect("sig from_bytes failed");
vk2.verify(TEST_MSG, &sig3)
.expect("verify deserialized sig failed");
}
#[test]
fn test_slh_dsa_tamper_message_fails() {
let mut rng = ChaCha20Rng::from_seed([0x22u8; 32]);
let (sk, vk) = SlhDsaShake128f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut tampered = TEST_MSG.to_vec();
tampered[0] ^= 0x01;
assert!(
vk.verify(&tampered, &sig).is_err(),
"verify must fail when message is tampered"
);
}
#[test]
fn test_slh_dsa_tamper_signature_fails() {
let mut rng = ChaCha20Rng::from_seed([0x33u8; 32]);
let (sk, vk) = SlhDsaShake128f::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
let mut sig_bytes = sig.to_bytes();
sig_bytes[4] ^= 0xFF;
let tampered_sig =
SlhDsaSignatureShake128f::from_bytes(&sig_bytes).expect("from_bytes failed");
assert!(
vk.verify(TEST_MSG, &tampered_sig).is_err(),
"verify must fail when signature is tampered"
);
}
#[test]
fn test_slh_dsa_wrong_verifying_key_fails() {
let mut rng = ChaCha20Rng::from_seed([0x44u8; 32]);
let (sk, _vk) = SlhDsaSha2_128s::generate(&mut rng);
let (_, wrong_vk) = SlhDsaSha2_128s::generate(&mut rng);
let sig = sk.sign(TEST_MSG).expect("sign failed");
assert!(
wrong_vk.verify(TEST_MSG, &sig).is_err(),
"verify must fail with wrong verifying key"
);
}
#[test]
#[ignore] fn test_slh_dsa_param_set_key_sizes() {
let mut rng = ChaCha20Rng::from_seed([0x55u8; 32]);
let (sk, vk) = SlhDsaSha2_128s::generate(&mut rng);
let sig = sk.sign(b"size-check").expect("sign failed");
assert_eq!(
sk.to_bytes().len(),
SLH_DSA_SHA2_128S_SK_LEN,
"SHA2-128s SK size"
);
assert_eq!(
vk.to_bytes().len(),
SLH_DSA_SHA2_128S_VK_LEN,
"SHA2-128s VK size"
);
assert_eq!(
sig.to_bytes().len(),
SLH_DSA_SHA2_128S_SIG_LEN,
"SHA2-128s sig size"
);
let (sk, vk) = SlhDsaSha2_128f::generate(&mut rng);
let sig = sk.sign(b"size-check").expect("sign failed");
assert_eq!(
sk.to_bytes().len(),
SLH_DSA_SHA2_128F_SK_LEN,
"SHA2-128f SK size"
);
assert_eq!(
vk.to_bytes().len(),
SLH_DSA_SHA2_128F_VK_LEN,
"SHA2-128f VK size"
);
assert_eq!(
sig.to_bytes().len(),
SLH_DSA_SHA2_128F_SIG_LEN,
"SHA2-128f sig size"
);
let (sk, vk) = SlhDsaShake128s::generate(&mut rng);
let sig = sk.sign(b"size-check").expect("sign failed");
assert_eq!(
sk.to_bytes().len(),
SLH_DSA_SHAKE_128S_SK_LEN,
"SHAKE-128s SK size"
);
assert_eq!(
vk.to_bytes().len(),
SLH_DSA_SHAKE_128S_VK_LEN,
"SHAKE-128s VK size"
);
assert_eq!(
sig.to_bytes().len(),
SLH_DSA_SHAKE_128S_SIG_LEN,
"SHAKE-128s sig size"
);
let (sk, vk) = SlhDsaShake128f::generate(&mut rng);
let sig = sk.sign(b"size-check").expect("sign failed");
assert_eq!(
sk.to_bytes().len(),
SLH_DSA_SHAKE_128F_SK_LEN,
"SHAKE-128f SK size"
);
assert_eq!(
vk.to_bytes().len(),
SLH_DSA_SHAKE_128F_VK_LEN,
"SHAKE-128f VK size"
);
assert_eq!(
sig.to_bytes().len(),
SLH_DSA_SHAKE_128F_SIG_LEN,
"SHAKE-128f sig size"
);
}
#[test]
fn test_slh_dsa_sha2_192s_key_sizes() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0xA3u8; 32]);
let (sk, vk) = SlhDsaSha2_192s::generate(&mut rng);
assert_eq!(
sk.to_bytes().len(),
SLH_DSA_SHA2_192S_SK_LEN,
"SHA2-192s SK size"
);
assert_eq!(
vk.to_bytes().len(),
SLH_DSA_SHA2_192S_VK_LEN,
"SHA2-192s VK size"
);
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
fn test_slh_dsa_sha2_192f_key_sizes() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0xA4u8; 32]);
let (sk, vk) = SlhDsaSha2_192f::generate(&mut rng);
assert_eq!(
sk.to_bytes().len(),
SLH_DSA_SHA2_192F_SK_LEN,
"SHA2-192f SK size"
);
assert_eq!(
vk.to_bytes().len(),
SLH_DSA_SHA2_192F_VK_LEN,
"SHA2-192f VK size"
);
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_shake_256s_key_sizes() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0xA5u8; 32]);
let (sk, vk) = SlhDsaShake256s::generate(&mut rng);
assert_eq!(
sk.to_bytes().len(),
SLH_DSA_SHAKE_256S_SK_LEN,
"SHAKE-256s SK size"
);
assert_eq!(
vk.to_bytes().len(),
SLH_DSA_SHAKE_256S_VK_LEN,
"SHAKE-256s VK size"
);
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
fn test_slh_dsa_shake_256f_key_sizes() {
std::thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.spawn(|| {
let mut rng = ChaCha20Rng::from_seed([0xA6u8; 32]);
let (sk, vk) = SlhDsaShake256f::generate(&mut rng);
assert_eq!(
sk.to_bytes().len(),
SLH_DSA_SHAKE_256F_SK_LEN,
"SHAKE-256f SK size"
);
assert_eq!(
vk.to_bytes().len(),
SLH_DSA_SHAKE_256F_VK_LEN,
"SHAKE-256f VK size"
);
})
.expect("thread spawn failed")
.join()
.expect("thread panicked");
}
#[test]
#[ignore] fn test_slh_dsa_signer_verifier_trait_sha2_128s() {
use oxicrypto_core::{Signer, Verifier};
let mut rng = ChaCha20Rng::from_seed([0x66u8; 32]);
let (sk_typed, vk_typed) = SlhDsaSha2_128s::generate(&mut rng);
let sk_bytes = sk_typed.to_bytes();
let vk_bytes = vk_typed.to_bytes();
let signer = SlhDsaSha2_128s;
let verifier = SlhDsaSha2_128s;
let mut sig_buf = vec![0u8; SLH_DSA_SHA2_128S_SIG_LEN];
let written = signer
.sign(&sk_bytes, TEST_MSG, &mut sig_buf)
.expect("trait sign failed");
assert_eq!(written, SLH_DSA_SHA2_128S_SIG_LEN);
verifier
.verify(&vk_bytes, TEST_MSG, &sig_buf)
.expect("trait verify failed");
}
#[test]
#[ignore] fn test_slh_dsa_signer_verifier_trait_shake_128f() {
use oxicrypto_core::{Signer, Verifier};
let mut rng = ChaCha20Rng::from_seed([0x77u8; 32]);
let (sk_typed, vk_typed) = SlhDsaShake128f::generate(&mut rng);
let sk_bytes = sk_typed.to_bytes();
let vk_bytes = vk_typed.to_bytes();
let signer = SlhDsaShake128f;
let verifier = SlhDsaShake128f;
let mut sig_buf = vec![0u8; SLH_DSA_SHAKE_128F_SIG_LEN];
let written = signer
.sign(&sk_bytes, TEST_MSG, &mut sig_buf)
.expect("trait sign failed");
assert_eq!(written, SLH_DSA_SHAKE_128F_SIG_LEN);
verifier
.verify(&vk_bytes, TEST_MSG, &sig_buf)
.expect("trait verify failed");
}
#[test]
fn test_slh_dsa_signer_trait_buffer_too_small() {
use oxicrypto_core::Signer;
let mut rng = ChaCha20Rng::from_seed([0x88u8; 32]);
let (sk_typed, _) = SlhDsaSha2_128s::generate(&mut rng);
let sk_bytes = sk_typed.to_bytes();
let signer = SlhDsaSha2_128s;
let mut tiny = vec![0u8; 16];
let result = signer.sign(&sk_bytes, TEST_MSG, &mut tiny);
assert_eq!(result, Err(CryptoError::BufferTooSmall));
}
#[test]
fn test_slh_dsa_deserialization_invalid_bytes_fail() {
assert!(SlhDsaSigningKey128s::from_bytes(&[0u8; 16]).is_err());
assert!(SlhDsaVerifyingKey128s::from_bytes(&[0u8; 16]).is_err());
assert!(SlhDsaSignature128s::from_bytes(&[0u8; 16]).is_err());
}
}