#[cfg(feature = "random")]
use lib_q_ml_dsa::{
ml_dsa_44,
ml_dsa_65,
ml_dsa_87,
};
#[cfg(feature = "random")]
use lib_q_random::LibQRng;
#[cfg(feature = "random")]
use rand_core::Rng;
#[cfg(feature = "random")]
fn random_array<const L: usize>() -> [u8; L] {
let mut rng = LibQRng::new_secure().expect("Failed to create secure RNG");
let mut seed = [0; L];
rng.fill_bytes(&mut seed);
seed
}
#[cfg(feature = "random")]
fn random_message() -> Vec<u8> {
let mut rng = LibQRng::new_secure().expect("Failed to create secure RNG");
let mut length = [0u8; 2];
rng.fill_bytes(&mut length);
let length = ((length[1] as u16) << 8) | length[0] as u16;
let length = length.min(4096);
let mut message = vec![0u8; length as usize];
rng.fill_bytes(&mut message);
message
}
#[cfg(feature = "random")]
fn modify_signing_key<const SIGNING_KEY_SIZE: usize>(signing_key: &mut [u8; SIGNING_KEY_SIZE]) {
let mut rng = LibQRng::new_secure().expect("Failed to create secure RNG");
let mut option_bytes = [0u8; 1];
rng.fill_bytes(&mut option_bytes);
let option = option_bytes[0] % 2;
let position = match option {
0 => {
let mut pos_bytes = [0u8; 1];
rng.fill_bytes(&mut pos_bytes);
(pos_bytes[0] % 32) as usize
}
1 => {
let mut pos_bytes = [0u8; 1];
rng.fill_bytes(&mut pos_bytes);
(64 + (pos_bytes[0] % 64)) as usize
}
_ => unreachable!(),
};
let random_byte = {
let byte = random_array::<1>()[0];
if byte == 0 { byte + 1 } else { byte }
};
signing_key[position] ^= random_byte;
}
#[cfg(feature = "random")]
macro_rules! impl_consistency_test {
($name:ident, $key_gen:expr, $sign:expr, $verify:expr) => {
#[test]
fn $name() {
let key_generation_seed = random_array();
let signing_randomness = random_array();
let message = random_message();
let key_pair = $key_gen(key_generation_seed);
let signature = $sign(&key_pair.signing_key, &message, b"", signing_randomness)
.expect("Rejection sampling failure probability is < 2⁻¹²⁸");
$verify(&key_pair.verification_key, &message, b"", &signature)
.expect("Verification should pass since the signature was honestly generated");
}
};
}
#[cfg(feature = "random")]
macro_rules! impl_modified_signing_key_test {
($name:ident, $key_gen:expr, $signing_key_size: expr, $sign:expr, $verify:expr) => {
#[test]
fn $name() {
let key_generation_seed = random_array();
let signing_randomness = random_array();
let message = random_message();
let mut key_pair = $key_gen(key_generation_seed);
modify_signing_key::<{ $signing_key_size }>(key_pair.signing_key.as_ref_mut());
let signature = $sign(&key_pair.signing_key, &message, b"", signing_randomness)
.expect("Rejection sampling failure probability is < 2⁻¹²⁸");
assert!($verify(&key_pair.verification_key, &message, b"", &signature).is_err());
}
};
}
#[cfg(feature = "random")]
impl_consistency_test!(
consistency_44,
ml_dsa_44::generate_key_pair,
ml_dsa_44::sign,
ml_dsa_44::verify
);
#[cfg(feature = "random")]
impl_modified_signing_key_test!(
modified_signing_key_44,
ml_dsa_44::generate_key_pair,
ml_dsa_44::MLDSA44SigningKey::len(),
ml_dsa_44::sign,
ml_dsa_44::verify
);
#[cfg(feature = "random")]
impl_consistency_test!(
consistency_44_portable,
ml_dsa_44::portable::generate_key_pair,
ml_dsa_44::portable::sign,
ml_dsa_44::portable::verify
);
#[cfg(feature = "random")]
impl_modified_signing_key_test!(
modified_signing_key_44_portable,
ml_dsa_44::portable::generate_key_pair,
ml_dsa_44::MLDSA44SigningKey::len(),
ml_dsa_44::portable::sign,
ml_dsa_44::portable::verify
);
#[cfg(all(feature = "simd128", feature = "random"))]
impl_consistency_test!(
consistency_44_simd128,
ml_dsa_44::neon::generate_key_pair,
ml_dsa_44::neon::sign,
ml_dsa_44::neon::verify
);
#[cfg(all(feature = "simd128", feature = "random"))]
impl_modified_signing_key_test!(
modified_signing_key_44_simd128,
ml_dsa_44::neon::generate_key_pair,
ml_dsa_44::MLDSA44SigningKey::len(),
ml_dsa_44::neon::sign,
ml_dsa_44::neon::verify
);
#[cfg(all(feature = "simd256", feature = "random"))]
impl_consistency_test!(
consistency_44_simd256,
ml_dsa_44::avx2::generate_key_pair,
ml_dsa_44::avx2::sign,
ml_dsa_44::avx2::verify
);
#[cfg(all(feature = "simd256", feature = "random"))]
impl_modified_signing_key_test!(
modified_signing_key_44_simd256,
ml_dsa_44::avx2::generate_key_pair,
ml_dsa_44::MLDSA44SigningKey::len(),
ml_dsa_44::avx2::sign,
ml_dsa_44::avx2::verify
);
#[cfg(feature = "random")]
impl_consistency_test!(
consistency_65,
ml_dsa_65::generate_key_pair,
ml_dsa_65::sign,
ml_dsa_65::verify
);
#[cfg(feature = "random")]
impl_modified_signing_key_test!(
modified_signing_key_65,
ml_dsa_65::generate_key_pair,
ml_dsa_65::MLDSA65SigningKey::len(),
ml_dsa_65::sign,
ml_dsa_65::verify
);
#[cfg(feature = "random")]
impl_consistency_test!(
consistency_87,
ml_dsa_87::generate_key_pair,
ml_dsa_87::sign,
ml_dsa_87::verify
);
#[cfg(feature = "random")]
impl_modified_signing_key_test!(
modified_signing_key_87,
ml_dsa_87::generate_key_pair,
ml_dsa_87::MLDSA87SigningKey::len(),
ml_dsa_87::sign,
ml_dsa_87::verify
);