extern crate alloc;
use alloc::vec::Vec;
use core::borrow::Borrow;
use super::{assert_ct_eq, assert_ct_ne};
use crate::{
csprng::{Csprng, Random},
import::Import,
keys::RawSecretBytes,
signer::{Signer, SigningKey, VerifyingKey},
};
#[macro_export]
macro_rules! for_each_signer_test {
($callback:ident) => {
$crate::__apply! {
$callback,
test_default,
test_pk_eq,
test_sk_ct_eq,
test_public,
test_batch_simple_good,
test_batch_simple_bad,
}
};
}
pub use for_each_signer_test;
#[macro_export]
macro_rules! test_signer {
(@test $signer:ty $(, $f:ident, $which:ident, $vectors:ident)? $(,)?) => {
macro_rules! __signer_test {
($test:ident) => {
#[test]
fn $test() {
$crate::test_util::signer::$test::<$signer, _>(&mut $crate::default::Rng)
}
};
}
$crate::for_each_signer_test!(__signer_test);
$(
#[test]
fn vectors() {
$crate::test_util::vectors::$f::<$signer>(
$crate::test_util::vectors::$which::$vectors,
);
}
)?
};
($name:ident, $signer:ty) => {
mod $name {
#[allow(unused_imports)]
use super::*;
$crate::test_signer!($signer);
}
};
($signer:ty) => {
$crate::test_signer!(@test $signer);
};
($name:ident, $signer:ty, EcdsaTest::$vectors:ident $(,)?) => {
mod $name {
#[allow(unused_imports)]
use super::*;
$crate::test_signer!($signer, EcdsaTest::$vectors);
}
};
($signer:ty, EcdsaTest::$vectors:ident $(,)?) => {
$crate::test_signer!(@test $signer, test_ecdsa, EcdsaTest, $vectors);
};
($name:ident, $signer:ty, EddsaTest::$vectors:ident $(,)?) => {
mod $name {
#[allow(unused_imports)]
use super::*;
$crate::test_signer!($signer, EddsaTest::$vectors);
}
};
($signer:ty, EddsaTest::$vectors:ident $(,)?) => {
$crate::test_signer!(@test $signer, test_eddsa, EddsaTest, $vectors);
};
}
pub use test_signer;
pub fn test_default<T: Signer, R: Csprng>(rng: &R) {
const MSG: &[u8] = b"hello, world!";
let sk = T::SigningKey::random(rng);
let sig = sk.sign(MSG).expect("unable to create signature");
sk.public()
.expect("signing key should be valid")
.verify(MSG, &sig)
.expect("unable to verify signature");
}
pub fn test_sk_ct_eq<T: Signer, R: Csprng>(rng: &R) {
let sk1 = T::SigningKey::random(rng);
let sk2 = T::SigningKey::random(rng);
fn same_key<T: Signer, K: SigningKey<T> + for<'a> Import<&'a [u8]>>(k: K) {
let data = match k.try_export_secret() {
Ok(data) => data,
Err(_) => {
return;
}
};
let sk1 = K::import(data.raw_secret_bytes()).expect("should be able to import key");
let sk2 = K::import(data.raw_secret_bytes()).expect("should be able to import key");
assert_ct_eq!(sk1, sk2);
}
assert_ct_ne!(sk1, sk2);
same_key(sk1);
same_key(sk2);
}
pub fn test_pk_eq<T: Signer, R: Csprng>(rng: &R) {
let pk1 = T::SigningKey::random(rng)
.public()
.expect("signing key should be valid");
let pk2 = T::SigningKey::random(rng)
.public()
.expect("signing key should be valid");
fn same_key<T: Signer, K: VerifyingKey<T>>(k: K) {
let pk1 = K::import(k.export().borrow()).expect("should be able to import key");
let pk2 = K::import(k.export().borrow()).expect("should be able to import key");
assert_eq!(pk1, pk2);
}
assert_ne!(pk1, pk2);
same_key(pk1);
same_key(pk2);
}
pub fn test_public<T: Signer, R: Csprng>(rng: &R) {
let sk = T::SigningKey::random(rng);
assert_eq!(sk.public(), sk.public());
}
pub fn test_batch_simple_good<T: Signer, R: Csprng>(rng: &R) {
const MSGS: &[&[u8]] = &[
b"hello",
b"world",
b"!",
b"a longer message",
b"",
b"test_batch_simple_good",
b"message #7",
b"message #9",
b"off by one",
];
let (pks, sigs): (Vec<_>, Vec<_>) = MSGS
.iter()
.map(|msg| {
let sk = T::SigningKey::random(rng);
let sig = sk.sign(msg).expect("should not fail");
(sk.public().expect("signer key should be valid"), sig)
})
.unzip();
T::verify_batch(MSGS, &sigs[..], &pks[..]).expect("should not fail")
}
pub fn test_batch_simple_bad<T: Signer, R: Csprng>(rng: &R) {
let msgs: &mut [&[u8]] = &mut [
b"hello",
b"world",
b"!",
b"a longer message",
b"",
b"test_batch_simple_bad",
b"message #7",
b"message #9",
b"off by one",
];
let (pks, sigs): (Vec<_>, Vec<_>) = msgs
.iter()
.map(|msg| {
let sk = T::SigningKey::random(rng);
let sig = sk.sign(msg).expect("should not fail");
(sk.public().expect("signing key should be valid"), sig)
})
.unzip();
msgs[msgs.len() / 2] = b"AAAAAAAAAAAAA";
T::verify_batch(msgs, &sigs[..], &pks[..]).expect_err("should fail");
}