prep update

This commit is contained in:
eschorn1 2024-10-01 09:30:20 -05:00
parent fca844d470
commit 8c03d1f9c3
12 changed files with 531 additions and 490 deletions

View file

@ -1,8 +1,10 @@
use criterion::{criterion_group, criterion_main, Criterion};
use fips205::traits::{KeyGen, Signer, Verifier};
use fips205::{slh_dsa_sha2_128s, slh_dsa_shake_128s, slh_dsa_sha2_128f, slh_dsa_shake_128f,
slh_dsa_sha2_192s, slh_dsa_shake_192s, slh_dsa_sha2_192f, slh_dsa_shake_192f,
slh_dsa_sha2_256s, slh_dsa_shake_256s, slh_dsa_sha2_256f, slh_dsa_shake_256f};
use fips205::{
slh_dsa_sha2_128f, slh_dsa_sha2_128s, slh_dsa_sha2_192f, slh_dsa_sha2_192s, slh_dsa_sha2_256f,
slh_dsa_sha2_256s, slh_dsa_shake_128f, slh_dsa_shake_128s, slh_dsa_shake_192f,
slh_dsa_shake_192s, slh_dsa_shake_256f, slh_dsa_shake_256s,
};
#[allow(clippy::redundant_closure)]
@ -49,31 +51,79 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("shake_192s keygen", |b| b.iter(|| slh_dsa_shake_192s::KG::try_keygen_vt()));
c.bench_function("shake_256s keygen", |b| b.iter(|| slh_dsa_shake_256s::KG::try_keygen_vt()));
//
c.bench_function("sha2_128f sign ", |b| b.iter(|| sk_sha2_128f.try_sign_ct(&message, randomize)));
c.bench_function("sha2_192f sign ", |b| b.iter(|| sk_sha2_192f.try_sign_ct(&message, randomize)));
c.bench_function("sha2_256f sign ", |b| b.iter(|| sk_sha2_256f.try_sign_ct(&message, randomize)));
c.bench_function("shake_128f sign ", |b| b.iter(|| sk_shake_128f.try_sign_ct(&message, randomize)));
c.bench_function("shake_192f sign ", |b| b.iter(|| sk_shake_192f.try_sign_ct(&message, randomize)));
c.bench_function("shake_256f sign ", |b| b.iter(|| sk_shake_256f.try_sign_ct(&message, randomize)));
c.bench_function("sha2_128s sign ", |b| b.iter(|| sk_sha2_128s.try_sign_ct(&message, randomize)));
c.bench_function("sha2_192s sign ", |b| b.iter(|| sk_sha2_192s.try_sign_ct(&message, randomize)));
c.bench_function("sha2_256s sign ", |b| b.iter(|| sk_sha2_256s.try_sign_ct(&message, randomize)));
c.bench_function("shake_128s sign ", |b| b.iter(|| sk_shake_128s.try_sign_ct(&message, randomize)));
c.bench_function("shake_192s sign ", |b| b.iter(|| sk_shake_192s.try_sign_ct(&message, randomize)));
c.bench_function("shake_256s sign ", |b| b.iter(|| sk_shake_256s.try_sign_ct(&message, randomize)));
c.bench_function("sha2_128f sign ", |b| {
b.iter(|| sk_sha2_128f.try_sign_ct(&message, randomize))
});
c.bench_function("sha2_192f sign ", |b| {
b.iter(|| sk_sha2_192f.try_sign_ct(&message, randomize))
});
c.bench_function("sha2_256f sign ", |b| {
b.iter(|| sk_sha2_256f.try_sign_ct(&message, randomize))
});
c.bench_function("shake_128f sign ", |b| {
b.iter(|| sk_shake_128f.try_sign_ct(&message, randomize))
});
c.bench_function("shake_192f sign ", |b| {
b.iter(|| sk_shake_192f.try_sign_ct(&message, randomize))
});
c.bench_function("shake_256f sign ", |b| {
b.iter(|| sk_shake_256f.try_sign_ct(&message, randomize))
});
c.bench_function("sha2_128s sign ", |b| {
b.iter(|| sk_sha2_128s.try_sign_ct(&message, randomize))
});
c.bench_function("sha2_192s sign ", |b| {
b.iter(|| sk_sha2_192s.try_sign_ct(&message, randomize))
});
c.bench_function("sha2_256s sign ", |b| {
b.iter(|| sk_sha2_256s.try_sign_ct(&message, randomize))
});
c.bench_function("shake_128s sign ", |b| {
b.iter(|| sk_shake_128s.try_sign_ct(&message, randomize))
});
c.bench_function("shake_192s sign ", |b| {
b.iter(|| sk_shake_192s.try_sign_ct(&message, randomize))
});
c.bench_function("shake_256s sign ", |b| {
b.iter(|| sk_shake_256s.try_sign_ct(&message, randomize))
});
//
c.bench_function("sha2_128f verify", |b| b.iter(|| pk_sha2_128f.try_verify_vt(&message, &sig_sha2_128f)));
c.bench_function("sha2_192f verify", |b| b.iter(|| pk_sha2_192f.try_verify_vt(&message, &sig_sha2_192f)));
c.bench_function("sha2_256f verify", |b| b.iter(|| pk_sha2_256f.try_verify_vt(&message, &sig_sha2_256f)));
c.bench_function("shake_128f verify", |b| b.iter(|| pk_shake_128f.try_verify_vt(&message, &sig_shake_128f)));
c.bench_function("shake_192f verify", |b| b.iter(|| pk_shake_192f.try_verify_vt(&message, &sig_shake_192f)));
c.bench_function("shake_256f verify", |b| b.iter(|| pk_shake_256f.try_verify_vt(&message, &sig_shake_256f)));
c.bench_function("sha2_128s verify", |b| b.iter(|| pk_sha2_128s.try_verify_vt(&message, &sig_sha2_128s)));
c.bench_function("sha2_192s verify", |b| b.iter(|| pk_sha2_192s.try_verify_vt(&message, &sig_sha2_192s)));
c.bench_function("sha2_256s verify", |b| b.iter(|| pk_sha2_256s.try_verify_vt(&message, &sig_sha2_256s)));
c.bench_function("shake_128s verify", |b| b.iter(|| pk_shake_128s.try_verify_vt(&message, &sig_shake_128s)));
c.bench_function("shake_192s verify", |b| b.iter(|| pk_shake_192s.try_verify_vt(&message, &sig_shake_192s)));
c.bench_function("shake_256s verify", |b| b.iter(|| pk_shake_256s.try_verify_vt(&message, &sig_shake_256s)));
c.bench_function("sha2_128f verify", |b| {
b.iter(|| pk_sha2_128f.try_verify_vt(&message, &sig_sha2_128f))
});
c.bench_function("sha2_192f verify", |b| {
b.iter(|| pk_sha2_192f.try_verify_vt(&message, &sig_sha2_192f))
});
c.bench_function("sha2_256f verify", |b| {
b.iter(|| pk_sha2_256f.try_verify_vt(&message, &sig_sha2_256f))
});
c.bench_function("shake_128f verify", |b| {
b.iter(|| pk_shake_128f.try_verify_vt(&message, &sig_shake_128f))
});
c.bench_function("shake_192f verify", |b| {
b.iter(|| pk_shake_192f.try_verify_vt(&message, &sig_shake_192f))
});
c.bench_function("shake_256f verify", |b| {
b.iter(|| pk_shake_256f.try_verify_vt(&message, &sig_shake_256f))
});
c.bench_function("sha2_128s verify", |b| {
b.iter(|| pk_sha2_128s.try_verify_vt(&message, &sig_sha2_128s))
});
c.bench_function("sha2_192s verify", |b| {
b.iter(|| pk_sha2_192s.try_verify_vt(&message, &sig_sha2_192s))
});
c.bench_function("sha2_256s verify", |b| {
b.iter(|| pk_sha2_256s.try_verify_vt(&message, &sig_sha2_256s))
});
c.bench_function("shake_128s verify", |b| {
b.iter(|| pk_shake_128s.try_verify_vt(&message, &sig_shake_128s))
});
c.bench_function("shake_192s verify", |b| {
b.iter(|| pk_shake_192s.try_verify_vt(&message, &sig_shake_192s))
});
c.bench_function("shake_256s verify", |b| {
b.iter(|| pk_shake_256s.try_verify_vt(&message, &sig_shake_256s))
});
}
criterion_group!(benches, criterion_benchmark);

View file

@ -1,6 +1,6 @@
use std::convert::TryInto;
use fips205;
use fips205::traits::{KeyGen, SerDes, Signer, Verifier};
use std::convert::TryInto;
use std::os::raw::c_int;
@ -43,7 +43,7 @@ pub extern "C" fn slh_dsa_sha2_128f_keygen(
) -> u8 {
//use fips205::traits::{KeyGen, SerDes};
let (Some(public_out), Some(private_out)) = (public_out, private_out) else {
let (Some(public_out), Some(private_out)) = (public_out, private_out) else {
return SLH_DSA_NULL_PTR_ERROR;
};
let Ok((pk, sk)) = fips205::slh_dsa_sha2_128f::KG::try_keygen_vt() else {
@ -58,8 +58,7 @@ pub extern "C" fn slh_dsa_sha2_128f_keygen(
#[no_mangle]
pub extern "C" fn slh_dsa_sha2_128f_sign(
message_buf: *const u8,
message_len: c_int,
message_buf: *const u8, message_len: c_int,
private_key: Option<&mut slh_dsa_sha2_128f_private_key>,
signature_out: Option<&mut slh_dsa_sha2_128f_signature>,
) -> u8 {
@ -67,9 +66,12 @@ pub extern "C" fn slh_dsa_sha2_128f_sign(
return SLH_DSA_NULL_PTR_ERROR;
};
if message_buf.is_null() {return SLH_DSA_NULL_PTR_ERROR};
if message_buf.is_null() {
return SLH_DSA_NULL_PTR_ERROR;
};
let message = unsafe { std::slice::from_raw_parts(message_buf, message_len.try_into().unwrap()) };
let message =
unsafe { std::slice::from_raw_parts(message_buf, message_len.try_into().unwrap()) };
let Ok(sk) = fips205::slh_dsa_sha2_128f::PrivateKey::try_from_bytes(&private_key.data) else {
return SLH_DSA_DESERIALIZATION_ERROR;
@ -83,22 +85,24 @@ pub extern "C" fn slh_dsa_sha2_128f_sign(
#[no_mangle]
pub extern "C" fn slh_dsa_sha2_128f_verify(
message_buf: *const u8,
message_len: c_int,
message_buf: *const u8, message_len: c_int,
public_key: Option<&mut slh_dsa_sha2_128f_public_key>,
signature: Option<&mut slh_dsa_sha2_128f_signature>,
) -> u8 {
let (Some(public_key), Some(signature)) = (public_key, signature) else {
return SLH_DSA_NULL_PTR_ERROR;
};
let message = unsafe { std::slice::from_raw_parts(message_buf, message_len.try_into().unwrap()) };
let message =
unsafe { std::slice::from_raw_parts(message_buf, message_len.try_into().unwrap()) };
let Ok(sk) = fips205::slh_dsa_sha2_128f::PublicKey::try_from_bytes(&public_key.data) else {
return SLH_DSA_DESERIALIZATION_ERROR;
};
let res = sk.try_verify_vt(&message, &signature.data);
if res.is_ok() && res.unwrap() { SLH_DSA_OK } else { SLH_DSA_VERIFY_ERROR }
if res.is_ok() && res.unwrap() {
SLH_DSA_OK
} else {
SLH_DSA_VERIFY_ERROR
}
}

View file

@ -230,12 +230,12 @@ impl Adrs {
pub(crate) fn set_tree_index(&mut self, i: u32) { self.f7 = i.to_be_bytes() }
#[cfg(any(
feature = "slh_dsa_shake_128f",
feature = "slh_dsa_shake_128s",
feature = "slh_dsa_shake_192f",
feature = "slh_dsa_shake_192s",
feature = "slh_dsa_shake_256f",
feature = "slh_dsa_shake_256s"
feature = "slh_dsa_shake_128f",
feature = "slh_dsa_shake_128s",
feature = "slh_dsa_shake_192f",
feature = "slh_dsa_shake_192s",
feature = "slh_dsa_shake_256f",
feature = "slh_dsa_shake_256s"
))]
pub(crate) fn to_32_bytes(&self) -> [u8; 32] {
let mut ret = [0u8; 32];
@ -250,12 +250,12 @@ impl Adrs {
}
#[cfg(any(
feature = "slh_dsa_sha2_128f",
feature = "slh_dsa_sha2_128s",
feature = "slh_dsa_sha2_192f",
feature = "slh_dsa_sha2_192s",
feature = "slh_dsa_sha2_256f",
feature = "slh_dsa_sha2_256s"
feature = "slh_dsa_sha2_128f",
feature = "slh_dsa_sha2_128s",
feature = "slh_dsa_sha2_192f",
feature = "slh_dsa_sha2_192s",
feature = "slh_dsa_sha2_256f",
feature = "slh_dsa_sha2_256s"
))]
pub(crate) fn to_22_bytes(&self) -> [u8; 22] {
let mut ret = [0u8; 22];

View file

@ -262,8 +262,8 @@ macro_rules! functionality {
fn simple_round_trips() {
let mut message = [0u8, 1, 2, 3];
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123);
for i in 0..5 {
message[3] = i as u8;
for i in 0..5u8 {
message[3] = i;
let (pk1, sk1) = KG::try_keygen_with_rng_vt(&mut rng).unwrap();
let pk1_bytes = pk1.into_bytes();
let pk2 = PublicKey::try_from_bytes(&pk1_bytes).unwrap();
@ -272,7 +272,7 @@ macro_rules! functionality {
let sig = sk2.try_sign_with_rng_ct(&mut rng, &message, true).unwrap();
let result = pk2.try_verify_vt(&message, &sig).unwrap();
assert_eq!(result, true, "Signature failed to verify");
message[3] = (i + 1) as u8;
message[3] = (i + 1);
let result = pk2.try_verify_vt(&message, &sig).unwrap();
assert_eq!(result, false, "Signature should not have verified");
}

View file

@ -79,6 +79,7 @@ pub struct XmssSig<const HP: usize, const LEN: usize, const N: usize> {
impl<const HP: usize, const LEN: usize, const N: usize> XmssSig<HP, LEN, N> {
pub(crate) fn get_wots_sig(&self) -> &WotsSig<LEN, N> { &self.sig_wots }
pub(crate) fn get_xmss_auth(&self) -> &[[u8; N]; HP] { &self.auth }
}

View file

@ -1,435 +0,0 @@
/// Runs tests using data from exports posted by NIST in their ACVP-Server repository
/// ACVP: Automated Cryptographic Validation Protocol
///
/// Repo: https://github.com/usnistgov/ACVP-Server/
///
/// Test files:
/// - https://github.com/usnistgov/ACVP-Server/raw/master/gen-val/json-files/SLH-DSA-keyGen-FIPS205/internalProjection.json
/// - https://github.com/usnistgov/ACVP-Server/raw/master/gen-val/json-files/SLH-DSA-sigGen-FIPS205/internalProjection.json
/// - https://github.com/usnistgov/ACVP-Server/raw/master/gen-val/json-files/SLH-DSA-sigVer-FIPS205/internalProjection.json
///
#[cfg(test)]
mod acvp_json_tests {
use fips205::traits::{KeyGen, SerDes, Signer, Verifier};
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Deserializer};
use serde_json::Value;
use std::fs::File;
use std::panic;
fn dehex<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
let buf = String::deserialize(deserializer)?;
hex::decode(buf).map_err(serde::de::Error::custom)
}
struct TestRng {
data: Vec<Vec<u8>>,
}
impl RngCore for TestRng {
fn next_u32(&mut self) -> u32 {
unimplemented!()
}
fn next_u64(&mut self) -> u64 {
unimplemented!()
}
fn fill_bytes(&mut self, out: &mut [u8]) {
let x = self.data.pop().expect("TestRng problem");
out.copy_from_slice(&x)
}
fn try_fill_bytes(&mut self, out: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(out);
Ok(()) // panic on probs is OK
}
}
impl CryptoRng for TestRng {}
impl TestRng {
fn new() -> Self {
TestRng { data: Vec::new() }
}
fn push(&mut self, new_data: &[u8]) {
let x = new_data.to_vec();
self.data.push(x);
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct KeyGenTest {
tc_id: usize,
#[serde(deserialize_with = "dehex")]
sk_seed: Vec<u8>,
#[serde(deserialize_with = "dehex")]
sk_prf: Vec<u8>,
#[serde(deserialize_with = "dehex")]
pk_seed: Vec<u8>,
#[serde(deserialize_with = "dehex")]
sk: Vec<u8>,
#[serde(deserialize_with = "dehex")]
pk: Vec<u8>,
}
macro_rules! test_keygen {
($test_group: ident, $param_set: ident, $fail_count: ident) => {
for test in $test_group["tests"].as_array().unwrap() {
let test: KeyGenTest = serde_json::from_value(test.clone()).unwrap();
print!(
"Testing key generation with {} test case id {}... ",
$param_set, test.tc_id
);
// Pre-load RNG
let mut rnd = TestRng::new();
rnd.push(&test.pk_seed);
rnd.push(&test.sk_prf);
rnd.push(&test.sk_seed);
// Generate key
let (pk, sk) = KG::try_keygen_with_rng_vt(&mut rnd).unwrap();
// Check against known answers
let pk_match = pk.into_bytes() == test.pk.as_slice();
let sk_match = sk.into_bytes() == test.sk.as_slice();
if pk_match && sk_match {
println!("Passed.")
} else {
println!("Failed.");
$fail_count += 1;
}
}
};
}
#[test]
fn run_keygen_tests() {
let mut fail_count = 0;
let file = "tests/SLH-DSA-keyGen-FIPS205/internalProjection.json";
let keygen_kat_file = File::open(file).expect("Error opening json file");
let kat_json: Value =
serde_json::from_reader(keygen_kat_file).expect("Error parsing json file");
assert_eq!(kat_json["algorithm"].as_str().unwrap(), "SLH-DSA");
assert_eq!(kat_json["mode"].as_str().unwrap(), "keyGen");
assert_eq!(kat_json["revision"].as_str().unwrap(), "FIPS205");
for test_group in kat_json["testGroups"].as_array().unwrap() {
let param_set = test_group["parameterSet"].as_str().unwrap();
match param_set {
"SLH-DSA-SHA2-128s" => {
use fips205::slh_dsa_sha2_128s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-128s" => {
use fips205::slh_dsa_shake_128s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-128f" => {
use fips205::slh_dsa_sha2_128f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-128f" => {
use fips205::slh_dsa_shake_128f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-192s" => {
use fips205::slh_dsa_sha2_192s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-192s" => {
use fips205::slh_dsa_shake_192s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-192f" => {
use fips205::slh_dsa_sha2_192f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-192f" => {
use fips205::slh_dsa_shake_192f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-256s" => {
use fips205::slh_dsa_sha2_256s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-256s" => {
use fips205::slh_dsa_shake_256s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-256f" => {
use fips205::slh_dsa_sha2_256f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-256f" => {
use fips205::slh_dsa_shake_256f::KG;
test_keygen!(test_group, param_set, fail_count);
}
_ => {
println!("Unrecognized Parameter set in test file: {}", param_set);
}
}
}
assert_eq!(fail_count, 0);
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct SignTest {
tc_id: usize,
#[serde(deserialize_with = "dehex")]
sk: Vec<u8>,
#[serde(deserialize_with = "dehex", default)]
additional_randomness: Vec<u8>,
#[serde(deserialize_with = "dehex")]
message: Vec<u8>,
#[serde(deserialize_with = "dehex")]
signature: Vec<u8>,
}
macro_rules! test_sign {
($test_group: ident, $param_set: ident, $deterministic:ident, $fail_count: ident) => {
for test in $test_group["tests"].as_array().unwrap() {
let test: SignTest = serde_json::from_value(test.clone()).unwrap();
print!("Testing signing with {}, test case {}... ", $param_set, test.tc_id);
// Load private key
let sk = PrivateKey::try_from_bytes(
test.sk
.as_slice()
.try_into()
.expect("Wrong length private key"),
)
.expect("Unable to load private key");
// Calculate signature
let sig_exp = if $deterministic {
sk.try_sign_ct(&test.message, false)
.expect("Error signing message")
} else {
let mut rnd = TestRng::new();
rnd.push(test.additional_randomness.as_slice());
sk.try_sign_with_rng_ct(&mut rnd, &test.message, true)
.expect("Error signing message")
};
// Check against known answer
if sig_exp == test.signature.as_slice() {
println!("Passed.");
} else {
println!("Failed.");
$fail_count += 1;
}
}
};
}
#[test]
fn run_signing_tests() {
let mut fail_count = 0;
let file = "tests/SLH-DSA-sigGen-FIPS205/internalProjection.json";
let sign_kat_file = File::open(file).expect("Error opening json file");
let kat_json: Value =
serde_json::from_reader(sign_kat_file).expect("Error parsing json file");
assert_eq!(kat_json["algorithm"].as_str().unwrap(), "SLH-DSA");
assert_eq!(kat_json["mode"].as_str().unwrap(), "sigGen");
assert_eq!(kat_json["revision"].as_str().unwrap(), "FIPS205");
for test_group in kat_json["testGroups"].as_array().unwrap() {
let param_set = test_group["parameterSet"].as_str().unwrap();
let deterministic = test_group["deterministic"].as_bool().unwrap();
match param_set {
"SLH-DSA-SHA2-128s" => {
use fips205::slh_dsa_sha2_128s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-128s" => {
use fips205::slh_dsa_shake_128s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-128f" => {
use fips205::slh_dsa_sha2_128f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-128f" => {
use fips205::slh_dsa_shake_128f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-192s" => {
use fips205::slh_dsa_sha2_192s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-192s" => {
use fips205::slh_dsa_shake_192s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-192f" => {
use fips205::slh_dsa_sha2_192f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-192f" => {
use fips205::slh_dsa_shake_192f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-256s" => {
use fips205::slh_dsa_sha2_256s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-256s" => {
use fips205::slh_dsa_shake_256s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-256f" => {
use fips205::slh_dsa_sha2_256f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-256f" => {
use fips205::slh_dsa_shake_256f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
_ => {
println!("Unrecognized Parameter set in test file: {}", param_set);
}
}
}
assert_eq!(fail_count, 0);
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct VerifyTest {
tc_id: usize,
test_passed: bool,
#[serde(deserialize_with = "dehex")]
pk: Vec<u8>,
#[serde(deserialize_with = "dehex")]
message: Vec<u8>,
#[serde(deserialize_with = "dehex")]
signature: Vec<u8>,
reason: String,
}
macro_rules! test_verify {
($test_group: ident, $param_set: ident, $fail_count: ident) => {
for test in $test_group["tests"].as_array().unwrap() {
let test: VerifyTest = serde_json::from_value(test.clone()).unwrap();
print!(
"Testing signing with {}, test case {}... ",
$param_set,
test.tc_id,
);
if test.test_passed == false {
println!("\nExpecting failed validation for: {}", test.reason);
}
let is_valid: Result<bool, _> = panic::catch_unwind(|| {
// Load public key
let pk = PublicKey::try_from_bytes(
test.pk
.as_slice()
.try_into()
.expect("Wrong length public key"),
)
.expect("Unable to load public key");
// Verify signature
pk.try_verify_vt(
test.message.as_slice(),
test.signature
.as_slice()
.try_into()
.expect("Signature length incorrect"),
)
.expect("Verification failed")
});
// Check against known answer
let is_valid = match is_valid {
Ok(true) => true,
Ok(false) => false,
Err(_) => false,
};
if is_valid == test.test_passed {
println!("Passed.");
} else {
println!("Failed.");
$fail_count += 1;
};
}
};
}
#[test]
fn run_verification_tests() {
let mut fail_count = 0;
let file = "tests/SLH-DSA-sigVer-FIPS205/internalProjection.json";
let sign_kat_file = File::open(file).expect("Error opening json file");
let kat_json: Value =
serde_json::from_reader(sign_kat_file).expect("Error parsing json file");
assert_eq!(kat_json["algorithm"].as_str().unwrap(), "SLH-DSA");
assert_eq!(kat_json["mode"].as_str().unwrap(), "sigVer");
assert_eq!(kat_json["revision"].as_str().unwrap(), "FIPS205");
for test_group in kat_json["testGroups"].as_array().unwrap() {
let param_set = test_group["parameterSet"].as_str().unwrap();
match param_set {
"SLH-DSA-SHA2-128s" => {
use fips205::slh_dsa_sha2_128s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-128s" => {
use fips205::slh_dsa_shake_128s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-128f" => {
use fips205::slh_dsa_sha2_128f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-128f" => {
use fips205::slh_dsa_shake_128f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-192s" => {
use fips205::slh_dsa_sha2_192s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-192s" => {
use fips205::slh_dsa_shake_192s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-192f" => {
use fips205::slh_dsa_sha2_192f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-192f" => {
use fips205::slh_dsa_shake_192f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-256s" => {
use fips205::slh_dsa_sha2_256s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-256s" => {
use fips205::slh_dsa_shake_256s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-256f" => {
use fips205::slh_dsa_sha2_256f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-256f" => {
use fips205::slh_dsa_shake_256f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
_ => {
println!("Unrecognized Parameter set in test file: {}", param_set);
}
}
}
assert_eq!(fail_count, 0);
}
}

1
tests/integration.rs Normal file
View file

@ -0,0 +1 @@
mod nist_acvp_vectors;

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,416 @@
/// Runs tests using data from exports posted by NIST in their ACVP-Server repository
/// ACVP: Automated Cryptographic Validation Protocol
///
/// Repo: https://github.com/usnistgov/ACVP-Server/
///
/// Test files:
/// - https://github.com/usnistgov/ACVP-Server/raw/master/gen-val/json-files/SLH-DSA-keyGen-FIPS205/internalProjection.json
/// - https://github.com/usnistgov/ACVP-Server/raw/master/gen-val/json-files/SLH-DSA-sigGen-FIPS205/internalProjection.json
/// - https://github.com/usnistgov/ACVP-Server/raw/master/gen-val/json-files/SLH-DSA-sigVer-FIPS205/internalProjection.json
use fips205::traits::{KeyGen, SerDes, Signer, Verifier};
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Deserializer};
use serde_json::Value;
use std::fs::File;
use std::panic;
fn dehex<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
let buf = String::deserialize(deserializer)?;
hex::decode(buf).map_err(serde::de::Error::custom)
}
struct TestRng {
data: Vec<Vec<u8>>,
}
impl RngCore for TestRng {
fn next_u32(&mut self) -> u32 { unimplemented!() }
fn next_u64(&mut self) -> u64 { unimplemented!() }
fn fill_bytes(&mut self, out: &mut [u8]) {
let x = self.data.pop().expect("TestRng problem");
out.copy_from_slice(&x)
}
fn try_fill_bytes(&mut self, out: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(out);
Ok(()) // panic on probs is OK
}
}
impl CryptoRng for TestRng {}
impl TestRng {
fn new() -> Self { TestRng { data: Vec::new() } }
fn push(&mut self, new_data: &[u8]) {
let x = new_data.to_vec();
self.data.push(x);
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct KeyGenTest {
tc_id: usize,
#[serde(deserialize_with = "dehex")]
sk_seed: Vec<u8>,
#[serde(deserialize_with = "dehex")]
sk_prf: Vec<u8>,
#[serde(deserialize_with = "dehex")]
pk_seed: Vec<u8>,
#[serde(deserialize_with = "dehex")]
sk: Vec<u8>,
#[serde(deserialize_with = "dehex")]
pk: Vec<u8>,
}
macro_rules! test_keygen {
($test_group: ident, $param_set: ident, $fail_count: ident) => {
for test in $test_group["tests"].as_array().unwrap() {
let test: KeyGenTest = serde_json::from_value(test.clone()).unwrap();
print!("Testing key generation with {} test case id {}... ", $param_set, test.tc_id);
// Pre-load RNG
let mut rnd = TestRng::new();
rnd.push(&test.pk_seed);
rnd.push(&test.sk_prf);
rnd.push(&test.sk_seed);
// Generate key
let (pk, sk) = KG::try_keygen_with_rng_vt(&mut rnd).unwrap();
// Check against known answers
let pk_match = pk.into_bytes() == test.pk.as_slice();
let sk_match = sk.into_bytes() == test.sk.as_slice();
if pk_match && sk_match {
println!("Passed.")
} else {
println!("Failed.");
$fail_count += 1;
}
}
};
}
#[test]
fn run_keygen_tests() {
let mut fail_count = 0;
let file = "tests/nist_acvp_vectors/SLH-DSA-keyGen-FIPS205/internalProjection.json";
let keygen_kat_file = File::open(file).expect("Error opening json file");
let kat_json: Value =
serde_json::from_reader(keygen_kat_file).expect("Error parsing json file");
assert_eq!(kat_json["algorithm"].as_str().unwrap(), "SLH-DSA");
assert_eq!(kat_json["mode"].as_str().unwrap(), "keyGen");
assert_eq!(kat_json["revision"].as_str().unwrap(), "FIPS205");
for test_group in kat_json["testGroups"].as_array().unwrap() {
let param_set = test_group["parameterSet"].as_str().unwrap();
match param_set {
"SLH-DSA-SHA2-128s" => {
use fips205::slh_dsa_sha2_128s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-128s" => {
use fips205::slh_dsa_shake_128s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-128f" => {
use fips205::slh_dsa_sha2_128f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-128f" => {
use fips205::slh_dsa_shake_128f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-192s" => {
use fips205::slh_dsa_sha2_192s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-192s" => {
use fips205::slh_dsa_shake_192s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-192f" => {
use fips205::slh_dsa_sha2_192f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-192f" => {
use fips205::slh_dsa_shake_192f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-256s" => {
use fips205::slh_dsa_sha2_256s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-256s" => {
use fips205::slh_dsa_shake_256s::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-256f" => {
use fips205::slh_dsa_sha2_256f::KG;
test_keygen!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-256f" => {
use fips205::slh_dsa_shake_256f::KG;
test_keygen!(test_group, param_set, fail_count);
}
_ => {
println!("Unrecognized Parameter set in test file: {}", param_set);
}
}
}
assert_eq!(fail_count, 0);
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct SignTest {
tc_id: usize,
#[serde(deserialize_with = "dehex")]
sk: Vec<u8>,
#[serde(deserialize_with = "dehex", default)]
additional_randomness: Vec<u8>,
#[serde(deserialize_with = "dehex")]
message: Vec<u8>,
#[serde(deserialize_with = "dehex")]
signature: Vec<u8>,
}
macro_rules! test_sign {
($test_group: ident, $param_set: ident, $deterministic:ident, $fail_count: ident) => {
for test in $test_group["tests"].as_array().unwrap() {
let test: SignTest = serde_json::from_value(test.clone()).unwrap();
print!("Testing signing with {}, test case {}... ", $param_set, test.tc_id);
// Load private key
let sk = PrivateKey::try_from_bytes(
test.sk
.as_slice()
.try_into()
.expect("Wrong length private key"),
)
.expect("Unable to load private key");
// Calculate signature
let sig_exp = if $deterministic {
sk.try_sign_ct(&test.message, false)
.expect("Error signing message")
} else {
let mut rnd = TestRng::new();
rnd.push(test.additional_randomness.as_slice());
sk.try_sign_with_rng_ct(&mut rnd, &test.message, true)
.expect("Error signing message")
};
// Check against known answer
if sig_exp == test.signature.as_slice() {
println!("Passed.");
} else {
println!("Failed.");
$fail_count += 1;
}
}
};
}
#[test]
fn run_signing_tests() {
let mut fail_count = 0;
let file = "tests/nist_acvp_vectors/SLH-DSA-sigGen-FIPS205/internalProjection.json";
let sign_kat_file = File::open(file).expect("Error opening json file");
let kat_json: Value = serde_json::from_reader(sign_kat_file).expect("Error parsing json file");
assert_eq!(kat_json["algorithm"].as_str().unwrap(), "SLH-DSA");
assert_eq!(kat_json["mode"].as_str().unwrap(), "sigGen");
assert_eq!(kat_json["revision"].as_str().unwrap(), "FIPS205");
for test_group in kat_json["testGroups"].as_array().unwrap() {
let param_set = test_group["parameterSet"].as_str().unwrap();
let deterministic = test_group["deterministic"].as_bool().unwrap();
match param_set {
"SLH-DSA-SHA2-128s" => {
use fips205::slh_dsa_sha2_128s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-128s" => {
use fips205::slh_dsa_shake_128s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-128f" => {
use fips205::slh_dsa_sha2_128f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-128f" => {
use fips205::slh_dsa_shake_128f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-192s" => {
use fips205::slh_dsa_sha2_192s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-192s" => {
use fips205::slh_dsa_shake_192s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-192f" => {
use fips205::slh_dsa_sha2_192f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-192f" => {
use fips205::slh_dsa_shake_192f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-256s" => {
use fips205::slh_dsa_sha2_256s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-256s" => {
use fips205::slh_dsa_shake_256s::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHA2-256f" => {
use fips205::slh_dsa_sha2_256f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
"SLH-DSA-SHAKE-256f" => {
use fips205::slh_dsa_shake_256f::PrivateKey;
test_sign!(test_group, param_set, deterministic, fail_count);
}
_ => {
println!("Unrecognized Parameter set in test file: {}", param_set);
}
}
}
assert_eq!(fail_count, 0);
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct VerifyTest {
tc_id: usize,
test_passed: bool,
#[serde(deserialize_with = "dehex")]
pk: Vec<u8>,
#[serde(deserialize_with = "dehex")]
message: Vec<u8>,
#[serde(deserialize_with = "dehex")]
signature: Vec<u8>,
reason: String,
}
macro_rules! test_verify {
($test_group: ident, $param_set: ident, $fail_count: ident) => {
for test in $test_group["tests"].as_array().unwrap() {
let test: VerifyTest = serde_json::from_value(test.clone()).unwrap();
print!("Testing signing with {}, test case {}... ", $param_set, test.tc_id,);
if test.test_passed == false {
println!("\nExpecting failed validation for: {}", test.reason);
}
let is_valid: Result<bool, _> = panic::catch_unwind(|| {
// Load public key
let pk = PublicKey::try_from_bytes(
test.pk
.as_slice()
.try_into()
.expect("Wrong length public key"),
)
.expect("Unable to load public key");
// Verify signature
pk.try_verify_vt(
test.message.as_slice(),
test.signature
.as_slice()
.try_into()
.expect("Signature length incorrect"),
)
.expect("Verification failed")
});
// Check against known answer
let is_valid = match is_valid {
Ok(true) => true,
Ok(false) => false,
Err(_) => false,
};
if is_valid == test.test_passed {
println!("Passed.");
} else {
println!("Failed.");
$fail_count += 1;
};
}
};
}
#[test]
fn run_verification_tests() {
let mut fail_count = 0;
let file = "tests/nist_acvp_vectors/SLH-DSA-sigVer-FIPS205/internalProjection.json";
let sign_kat_file = File::open(file).expect("Error opening json file");
let kat_json: Value = serde_json::from_reader(sign_kat_file).expect("Error parsing json file");
assert_eq!(kat_json["algorithm"].as_str().unwrap(), "SLH-DSA");
assert_eq!(kat_json["mode"].as_str().unwrap(), "sigVer");
assert_eq!(kat_json["revision"].as_str().unwrap(), "FIPS205");
for test_group in kat_json["testGroups"].as_array().unwrap() {
let param_set = test_group["parameterSet"].as_str().unwrap();
match param_set {
"SLH-DSA-SHA2-128s" => {
use fips205::slh_dsa_sha2_128s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-128s" => {
use fips205::slh_dsa_shake_128s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-128f" => {
use fips205::slh_dsa_sha2_128f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-128f" => {
use fips205::slh_dsa_shake_128f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-192s" => {
use fips205::slh_dsa_sha2_192s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-192s" => {
use fips205::slh_dsa_shake_192s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-192f" => {
use fips205::slh_dsa_sha2_192f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-192f" => {
use fips205::slh_dsa_shake_192f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-256s" => {
use fips205::slh_dsa_sha2_256s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-256s" => {
use fips205::slh_dsa_shake_256s::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHA2-256f" => {
use fips205::slh_dsa_sha2_256f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
"SLH-DSA-SHAKE-256f" => {
use fips205::slh_dsa_shake_256f::PublicKey;
test_verify!(test_group, param_set, fail_count);
}
_ => {
println!("Unrecognized Parameter set in test file: {}", param_set);
}
}
}
assert_eq!(fail_count, 0);
}