shaky, shaky

This commit is contained in:
eschorn1 2024-10-01 14:29:06 -05:00
parent 8c03d1f9c3
commit ab0f62369a
13 changed files with 421 additions and 226 deletions

View file

@ -30,8 +30,8 @@ use fips205::traits::{SerDes, Signer, Verifier};
let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
// Generate key pair and signature
let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate signature
let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate signature
// Serialize the public key, and send with message and signature bytes
let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -39,7 +39,7 @@ let (pk_recv, msg_recv, sig_recv) = (pk_send, msg_send, sig_send);
// Deserialize the public key, then use it to verify the msg signature
let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
assert!(v);
# Ok(())
# }

View file

@ -12,117 +12,117 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let message = [0u8, 1, 2, 3, 4, 5, 6, 7];
let randomize = false;
let (pk_sha2_128s, sk_sha2_128s) = slh_dsa_sha2_128s::KG::try_keygen_vt().unwrap();
let (pk_sha2_128f, sk_sha2_128f) = slh_dsa_sha2_128f::KG::try_keygen_vt().unwrap();
let (pk_sha2_192s, sk_sha2_192s) = slh_dsa_sha2_192s::KG::try_keygen_vt().unwrap();
let (pk_sha2_192f, sk_sha2_192f) = slh_dsa_sha2_192f::KG::try_keygen_vt().unwrap();
let (pk_sha2_256s, sk_sha2_256s) = slh_dsa_sha2_256s::KG::try_keygen_vt().unwrap();
let (pk_sha2_256f, sk_sha2_256f) = slh_dsa_sha2_256f::KG::try_keygen_vt().unwrap();
let (pk_shake_128s, sk_shake_128s) = slh_dsa_shake_128s::KG::try_keygen_vt().unwrap();
let (pk_shake_128f, sk_shake_128f) = slh_dsa_shake_128f::KG::try_keygen_vt().unwrap();
let (pk_shake_192s, sk_shake_192s) = slh_dsa_shake_192s::KG::try_keygen_vt().unwrap();
let (pk_shake_192f, sk_shake_192f) = slh_dsa_shake_192f::KG::try_keygen_vt().unwrap();
let (pk_shake_256s, sk_shake_256s) = slh_dsa_shake_256s::KG::try_keygen_vt().unwrap();
let (pk_shake_256f, sk_shake_256f) = slh_dsa_shake_256f::KG::try_keygen_vt().unwrap();
let (pk_sha2_128s, sk_sha2_128s) = slh_dsa_sha2_128s::KG::try_keygen().unwrap();
let (pk_sha2_128f, sk_sha2_128f) = slh_dsa_sha2_128f::KG::try_keygen().unwrap();
let (pk_sha2_192s, sk_sha2_192s) = slh_dsa_sha2_192s::KG::try_keygen().unwrap();
let (pk_sha2_192f, sk_sha2_192f) = slh_dsa_sha2_192f::KG::try_keygen().unwrap();
let (pk_sha2_256s, sk_sha2_256s) = slh_dsa_sha2_256s::KG::try_keygen().unwrap();
let (pk_sha2_256f, sk_sha2_256f) = slh_dsa_sha2_256f::KG::try_keygen().unwrap();
let (pk_shake_128s, sk_shake_128s) = slh_dsa_shake_128s::KG::try_keygen().unwrap();
let (pk_shake_128f, sk_shake_128f) = slh_dsa_shake_128f::KG::try_keygen().unwrap();
let (pk_shake_192s, sk_shake_192s) = slh_dsa_shake_192s::KG::try_keygen().unwrap();
let (pk_shake_192f, sk_shake_192f) = slh_dsa_shake_192f::KG::try_keygen().unwrap();
let (pk_shake_256s, sk_shake_256s) = slh_dsa_shake_256s::KG::try_keygen().unwrap();
let (pk_shake_256f, sk_shake_256f) = slh_dsa_shake_256f::KG::try_keygen().unwrap();
let sig_sha2_128s = sk_sha2_128s.try_sign_ct(&message, randomize).unwrap();
let sig_sha2_128f = sk_sha2_128f.try_sign_ct(&message, randomize).unwrap();
let sig_sha2_192s = sk_sha2_192s.try_sign_ct(&message, randomize).unwrap();
let sig_sha2_192f = sk_sha2_192f.try_sign_ct(&message, randomize).unwrap();
let sig_sha2_256s = sk_sha2_256s.try_sign_ct(&message, randomize).unwrap();
let sig_sha2_256f = sk_sha2_256f.try_sign_ct(&message, randomize).unwrap();
let sig_shake_128s = sk_shake_128s.try_sign_ct(&message, randomize).unwrap();
let sig_shake_128f = sk_shake_128f.try_sign_ct(&message, randomize).unwrap();
let sig_shake_192s = sk_shake_192s.try_sign_ct(&message, randomize).unwrap();
let sig_shake_192f = sk_shake_192f.try_sign_ct(&message, randomize).unwrap();
let sig_shake_256s = sk_shake_256s.try_sign_ct(&message, randomize).unwrap();
let sig_shake_256f = sk_shake_256f.try_sign_ct(&message, randomize).unwrap();
let sig_sha2_128s = sk_sha2_128s.try_sign(&message, randomize).unwrap();
let sig_sha2_128f = sk_sha2_128f.try_sign(&message, randomize).unwrap();
let sig_sha2_192s = sk_sha2_192s.try_sign(&message, randomize).unwrap();
let sig_sha2_192f = sk_sha2_192f.try_sign(&message, randomize).unwrap();
let sig_sha2_256s = sk_sha2_256s.try_sign(&message, randomize).unwrap();
let sig_sha2_256f = sk_sha2_256f.try_sign(&message, randomize).unwrap();
let sig_shake_128s = sk_shake_128s.try_sign(&message, randomize).unwrap();
let sig_shake_128f = sk_shake_128f.try_sign(&message, randomize).unwrap();
let sig_shake_192s = sk_shake_192s.try_sign(&message, randomize).unwrap();
let sig_shake_192f = sk_shake_192f.try_sign(&message, randomize).unwrap();
let sig_shake_256s = sk_shake_256s.try_sign(&message, randomize).unwrap();
let sig_shake_256f = sk_shake_256f.try_sign(&message, randomize).unwrap();
c.bench_function("sha2_128f keygen", |b| b.iter(|| slh_dsa_sha2_128f::KG::try_keygen_vt()));
c.bench_function("sha2_192f keygen", |b| b.iter(|| slh_dsa_sha2_192f::KG::try_keygen_vt()));
c.bench_function("sha2_256f keygen", |b| b.iter(|| slh_dsa_sha2_256f::KG::try_keygen_vt()));
c.bench_function("shake_128f keygen", |b| b.iter(|| slh_dsa_shake_128f::KG::try_keygen_vt()));
c.bench_function("shake_192f keygen", |b| b.iter(|| slh_dsa_shake_192f::KG::try_keygen_vt()));
c.bench_function("shake_256f keygen", |b| b.iter(|| slh_dsa_shake_256f::KG::try_keygen_vt()));
c.bench_function("sha2_128s keygen", |b| b.iter(|| slh_dsa_sha2_128s::KG::try_keygen_vt()));
c.bench_function("sha2_192s keygen", |b| b.iter(|| slh_dsa_sha2_192s::KG::try_keygen_vt()));
c.bench_function("sha2_256s keygen", |b| b.iter(|| slh_dsa_sha2_256s::KG::try_keygen_vt()));
c.bench_function("shake_128s keygen", |b| b.iter(|| slh_dsa_shake_128s::KG::try_keygen_vt()));
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 keygen", |b| b.iter(|| slh_dsa_sha2_128f::KG::try_keygen()));
c.bench_function("sha2_192f keygen", |b| b.iter(|| slh_dsa_sha2_192f::KG::try_keygen()));
c.bench_function("sha2_256f keygen", |b| b.iter(|| slh_dsa_sha2_256f::KG::try_keygen()));
c.bench_function("shake_128f keygen", |b| b.iter(|| slh_dsa_shake_128f::KG::try_keygen()));
c.bench_function("shake_192f keygen", |b| b.iter(|| slh_dsa_shake_192f::KG::try_keygen()));
c.bench_function("shake_256f keygen", |b| b.iter(|| slh_dsa_shake_256f::KG::try_keygen()));
c.bench_function("sha2_128s keygen", |b| b.iter(|| slh_dsa_sha2_128s::KG::try_keygen()));
c.bench_function("sha2_192s keygen", |b| b.iter(|| slh_dsa_sha2_192s::KG::try_keygen()));
c.bench_function("sha2_256s keygen", |b| b.iter(|| slh_dsa_sha2_256s::KG::try_keygen()));
c.bench_function("shake_128s keygen", |b| b.iter(|| slh_dsa_shake_128s::KG::try_keygen()));
c.bench_function("shake_192s keygen", |b| b.iter(|| slh_dsa_shake_192s::KG::try_keygen()));
c.bench_function("shake_256s keygen", |b| b.iter(|| slh_dsa_shake_256s::KG::try_keygen()));
//
c.bench_function("sha2_128f sign ", |b| {
b.iter(|| sk_sha2_128f.try_sign_ct(&message, randomize))
b.iter(|| sk_sha2_128f.try_sign(&message, randomize))
});
c.bench_function("sha2_192f sign ", |b| {
b.iter(|| sk_sha2_192f.try_sign_ct(&message, randomize))
b.iter(|| sk_sha2_192f.try_sign(&message, randomize))
});
c.bench_function("sha2_256f sign ", |b| {
b.iter(|| sk_sha2_256f.try_sign_ct(&message, randomize))
b.iter(|| sk_sha2_256f.try_sign(&message, randomize))
});
c.bench_function("shake_128f sign ", |b| {
b.iter(|| sk_shake_128f.try_sign_ct(&message, randomize))
b.iter(|| sk_shake_128f.try_sign(&message, randomize))
});
c.bench_function("shake_192f sign ", |b| {
b.iter(|| sk_shake_192f.try_sign_ct(&message, randomize))
b.iter(|| sk_shake_192f.try_sign(&message, randomize))
});
c.bench_function("shake_256f sign ", |b| {
b.iter(|| sk_shake_256f.try_sign_ct(&message, randomize))
b.iter(|| sk_shake_256f.try_sign(&message, randomize))
});
c.bench_function("sha2_128s sign ", |b| {
b.iter(|| sk_sha2_128s.try_sign_ct(&message, randomize))
b.iter(|| sk_sha2_128s.try_sign(&message, randomize))
});
c.bench_function("sha2_192s sign ", |b| {
b.iter(|| sk_sha2_192s.try_sign_ct(&message, randomize))
b.iter(|| sk_sha2_192s.try_sign(&message, randomize))
});
c.bench_function("sha2_256s sign ", |b| {
b.iter(|| sk_sha2_256s.try_sign_ct(&message, randomize))
b.iter(|| sk_sha2_256s.try_sign(&message, randomize))
});
c.bench_function("shake_128s sign ", |b| {
b.iter(|| sk_shake_128s.try_sign_ct(&message, randomize))
b.iter(|| sk_shake_128s.try_sign(&message, randomize))
});
c.bench_function("shake_192s sign ", |b| {
b.iter(|| sk_shake_192s.try_sign_ct(&message, randomize))
b.iter(|| sk_shake_192s.try_sign(&message, randomize))
});
c.bench_function("shake_256s sign ", |b| {
b.iter(|| sk_shake_256s.try_sign_ct(&message, randomize))
b.iter(|| sk_shake_256s.try_sign(&message, randomize))
});
//
c.bench_function("sha2_128f verify", |b| {
b.iter(|| pk_sha2_128f.try_verify_vt(&message, &sig_sha2_128f))
b.iter(|| pk_sha2_128f.try_verify(&message, &sig_sha2_128f))
});
c.bench_function("sha2_192f verify", |b| {
b.iter(|| pk_sha2_192f.try_verify_vt(&message, &sig_sha2_192f))
b.iter(|| pk_sha2_192f.try_verify(&message, &sig_sha2_192f))
});
c.bench_function("sha2_256f verify", |b| {
b.iter(|| pk_sha2_256f.try_verify_vt(&message, &sig_sha2_256f))
b.iter(|| pk_sha2_256f.try_verify(&message, &sig_sha2_256f))
});
c.bench_function("shake_128f verify", |b| {
b.iter(|| pk_shake_128f.try_verify_vt(&message, &sig_shake_128f))
b.iter(|| pk_shake_128f.try_verify(&message, &sig_shake_128f))
});
c.bench_function("shake_192f verify", |b| {
b.iter(|| pk_shake_192f.try_verify_vt(&message, &sig_shake_192f))
b.iter(|| pk_shake_192f.try_verify(&message, &sig_shake_192f))
});
c.bench_function("shake_256f verify", |b| {
b.iter(|| pk_shake_256f.try_verify_vt(&message, &sig_shake_256f))
b.iter(|| pk_shake_256f.try_verify(&message, &sig_shake_256f))
});
c.bench_function("sha2_128s verify", |b| {
b.iter(|| pk_sha2_128s.try_verify_vt(&message, &sig_sha2_128s))
b.iter(|| pk_sha2_128s.try_verify(&message, &sig_sha2_128s))
});
c.bench_function("sha2_192s verify", |b| {
b.iter(|| pk_sha2_192s.try_verify_vt(&message, &sig_sha2_192s))
b.iter(|| pk_sha2_192s.try_verify(&message, &sig_sha2_192s))
});
c.bench_function("sha2_256s verify", |b| {
b.iter(|| pk_sha2_256s.try_verify_vt(&message, &sig_sha2_256s))
b.iter(|| pk_sha2_256s.try_verify(&message, &sig_sha2_256s))
});
c.bench_function("shake_128s verify", |b| {
b.iter(|| pk_shake_128s.try_verify_vt(&message, &sig_shake_128s))
b.iter(|| pk_shake_128s.try_verify(&message, &sig_shake_128s))
});
c.bench_function("shake_192s verify", |b| {
b.iter(|| pk_shake_192s.try_verify_vt(&message, &sig_shake_192s))
b.iter(|| pk_shake_192s.try_verify(&message, &sig_shake_192s))
});
c.bench_function("shake_256s verify", |b| {
b.iter(|| pk_shake_256s.try_verify_vt(&message, &sig_shake_256s))
b.iter(|| pk_shake_256s.try_verify(&message, &sig_shake_256s))
});
}

View file

@ -8,8 +8,8 @@ fn sign(runner: &mut CtRunner, mut _rng: &mut BenchRng) {
let message = [0u8, 1, 2, 3, 4, 5, 6, 7];
let (_pk1, sk1) = slh_dsa_shake_128s::try_keygen_vt().unwrap(); // Generate both public and secret keys
let (_pk2, sk2) = slh_dsa_shake_128s::try_keygen_vt().unwrap(); // Generate both public and secret keys
let (_pk1, sk1) = slh_dsa_shake_128s::try_keygen().unwrap(); // Generate both public and secret keys
let (_pk2, sk2) = slh_dsa_shake_128s::try_keygen().unwrap(); // Generate both public and secret keys
let mut inputs: Vec<slh_dsa_shake_128s::PrivateKey> = Vec::new();
let mut classes = Vec::new();
@ -27,7 +27,7 @@ fn sign(runner: &mut CtRunner, mut _rng: &mut BenchRng) {
for (class, input) in classes.into_iter().zip(inputs.into_iter()) {
runner.run_one(class, || {
for _ in 0..ITERATIONS_INNER {
let _ = input.try_sign_ct(&message, true);
let _ = input.try_sign(&message, true);
}
})
}

View file

@ -46,7 +46,7 @@ pub extern "C" fn slh_dsa_sha2_128f_keygen(
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 {
let Ok((pk, sk)) = fips205::slh_dsa_sha2_128f::KG::try_keygen() else {
return SLH_DSA_KEYGEN_ERROR;
};
@ -76,7 +76,7 @@ pub extern "C" fn slh_dsa_sha2_128f_sign(
let Ok(sk) = fips205::slh_dsa_sha2_128f::PrivateKey::try_from_bytes(&private_key.data) else {
return SLH_DSA_DESERIALIZATION_ERROR;
};
let Ok(sig) = sk.try_sign_ct(&message, true) else {
let Ok(sig) = sk.try_sign(&message, true) else {
return SLH_DSA_SIGN_ERROR;
};
signature_out.data = sig;
@ -98,7 +98,7 @@ pub extern "C" fn slh_dsa_sha2_128f_verify(
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);
let res = sk.try_verify(&message, &signature.data);
if res.is_ok() && res.unwrap() {
SLH_DSA_OK

View file

@ -4,9 +4,9 @@ use crate::types::Adrs;
// Holds hasher function references; constructed by each security parameter set wrapper
#[allow(clippy::type_complexity)]
pub(crate) struct Hashers<const K: usize, const LEN: usize, const M: usize, const N: usize> {
pub(crate) h_msg: fn(&[u8], &[u8], &[u8], &[u8]) -> [u8; M],
pub(crate) h_msg: fn(&[u8], &[u8], &[u8], &[&[u8]]) -> [u8; M],
pub(crate) prf: fn(&[u8], &[u8], &Adrs) -> [u8; N],
pub(crate) prf_msg: fn(&[u8], &[u8], &[u8]) -> [u8; N],
pub(crate) prf_msg: fn(&[u8], &[u8], &[&[u8]]) -> [u8; N],
pub(crate) f: fn(&[u8], &Adrs, &[u8]) -> [u8; N],
pub(crate) h: fn(&[u8], &Adrs, &[u8], &[u8]) -> [u8; N],
pub(crate) t_l: fn(&[u8], &Adrs, &[[u8; N]; LEN]) -> [u8; N],
@ -37,10 +37,12 @@ pub(crate) mod shake {
pub(crate) fn h_msg<const M: usize>(
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[&[u8]],
) -> [u8; M] {
let mut digest = [0u8; M];
shake256(&[r, pk_seed, pk_root, m], &mut digest);
let mut inp = [r, pk_seed, pk_root, &[], &[], &[], &[], &[]];
inp[3..3 + m.len()].copy_from_slice(m); // m can have up to 5 elements
shake256(&inp, &mut digest);
digest
}
@ -53,9 +55,11 @@ pub(crate) mod shake {
}
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[u8]) -> [u8; N] {
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[&[u8]]) -> [u8; N] {
let mut digest = [0u8; N];
shake256(&[sk_prf, opt_rand, m], &mut digest);
let mut inp = [sk_prf, opt_rand, &[], &[], &[], &[], &[]];
inp[2..2 + m.len()].copy_from_slice(m); // m can have up to 5 elements
shake256(&inp, &mut digest);
digest
}
@ -106,10 +110,12 @@ pub(crate) mod sha2_cat_1 {
pub(crate) fn h_msg<const M: usize>(
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[&[u8]],
) -> [u8; M] {
let mut digest1 = [0u8; 32];
sha2_256(&[r, pk_seed, pk_root, m], &mut digest1);
let mut inp = [r, pk_seed, pk_root, &[], &[], &[], &[], &[]];
inp[3..3 + m.len()].copy_from_slice(m); // m can have up to 5 elements
sha2_256(&inp, &mut digest1);
let mut result = [0u8; M];
let mut start = 0;
let mut counter = 0u32;
@ -134,7 +140,7 @@ pub(crate) mod sha2_cat_1 {
}
fn hmac_sha_256(key: &[u8], a0: &[u8], b1: &[u8]) -> [u8; 32] {
fn hmac_sha_256(key: &[u8], a0: &[u8], m: &[&[u8]]) -> [u8; 32] {
let mut padding = [0x36; 64];
for (p, &k) in padding.iter_mut().zip(key.iter()) {
*p ^= k;
@ -142,7 +148,9 @@ pub(crate) mod sha2_cat_1 {
let mut inner_hasher = Sha256::new();
inner_hasher.update(&padding[..]);
inner_hasher.update(a0);
inner_hasher.update(b1);
for i in m {
inner_hasher.update(i);
}
for p in &mut padding {
*p ^= 0x6a;
}
@ -153,7 +161,7 @@ pub(crate) mod sha2_cat_1 {
}
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[u8]) -> [u8; N] {
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[&[u8]]) -> [u8; N] {
let mut digest = [0u8; N];
let full_digest = hmac_sha_256(sk_prf, opt_rand, m);
digest.copy_from_slice(&full_digest[0..N]);
@ -223,10 +231,12 @@ pub(crate) mod sha2_cat_3_5 {
pub(crate) fn h_msg<const M: usize>(
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[u8],
r: &[u8], pk_seed: &[u8], pk_root: &[u8], m: &[&[u8]],
) -> [u8; M] {
let mut digest1 = [0u8; 64];
sha2_512(&[r, pk_seed, pk_root, m], &mut digest1);
let mut inp = [r, pk_seed, pk_root, &[], &[], &[], &[], &[]];
inp[3..3 + m.len()].copy_from_slice(m); // m can have up to 5 elements
sha2_512(&inp, &mut digest1);
let mut result = [0u8; M];
let mut start = 0;
let mut counter = 0u32;
@ -251,7 +261,7 @@ pub(crate) mod sha2_cat_3_5 {
}
fn hmac_sha_512(key: &[u8], a0: &[u8], b1: &[u8]) -> [u8; 64] {
fn hmac_sha_512(key: &[u8], a0: &[u8], m: &[&[u8]]) -> [u8; 64] {
let mut padding = [0x36; 128];
for (p, &k) in padding.iter_mut().zip(key.iter()) {
*p ^= k;
@ -259,7 +269,9 @@ pub(crate) mod sha2_cat_3_5 {
let mut inner_hasher = Sha512::new();
inner_hasher.update(&padding[..]);
inner_hasher.update(a0);
inner_hasher.update(b1);
for i in m {
inner_hasher.update(i);
}
for p in &mut padding {
*p ^= 0x6a;
}
@ -270,7 +282,7 @@ pub(crate) mod sha2_cat_3_5 {
}
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[u8]) -> [u8; N] {
pub(crate) fn prf_msg<const N: usize>(sk_prf: &[u8], opt_rand: &[u8], m: &[&[u8]]) -> [u8; N] {
let mut digest = [0u8; N];
let full_digest = hmac_sha_512(sk_prf, opt_rand, m);
digest.copy_from_slice(&full_digest[0..N]);

View file

@ -42,6 +42,7 @@
/// All functionality is covered by traits, such that consumers can utilize trait objects as desired.
pub mod traits;
pub use types::Ph;
mod fors;
mod hashers;
@ -104,8 +105,8 @@ macro_rules! functionality {
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
///
/// // Generate public/private key pair and signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate a msg signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate a msg signature
///
/// // Serialize the public key, and send with message and signature bytes
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -113,14 +114,14 @@ macro_rules! functionality {
///
/// // Deserialize the public key, then use it to verify the msg signature
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
/// let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
/// assert!(v);
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "default-rng")]
pub fn try_keygen_vt() -> Result<(PublicKey, PrivateKey), &'static str> {
KG::try_keygen_vt()
pub fn try_keygen() -> Result<(PublicKey, PrivateKey), &'static str> {
KG::try_keygen()
}
@ -142,16 +143,16 @@ macro_rules! functionality {
/// let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123);
///
/// // Generate key pair and signature
/// let (pk, sk) = slh_dsa_shake_128s::try_keygen_with_rng_vt(&mut rng)?; // Generate both public and secret keys
/// let sig = sk.try_sign_ct(&message, true)?; // Use the secret key to generate a message signature ///
/// let v = pk.try_verify_vt(&message, &sig)?;
/// let (pk, sk) = slh_dsa_shake_128s::try_keygen_with_rng(&mut rng)?; // Generate both public and secret keys
/// let sig = sk.try_sign(&message, b"context", true)?; // Use the secret key to generate a message signature ///
/// let v = pk.try_verify(&message, &sig, b"context")?;
/// assert!(v);
/// # Ok(())}
/// ```
pub fn try_keygen_with_rng_vt(
pub fn try_keygen_with_rng(
rng: &mut impl CryptoRngCore,
) -> Result<(PublicKey, PrivateKey), &'static str> {
KG::try_keygen_with_rng_vt(rng)
KG::try_keygen_with_rng(rng)
}
@ -159,7 +160,7 @@ macro_rules! functionality {
type PrivateKey = PrivateKey;
type PublicKey = PublicKey;
fn try_keygen_with_rng_vt(
fn try_keygen_with_rng(
rng: &mut impl CryptoRngCore,
) -> Result<(PublicKey, PrivateKey), &'static str> {
let res = crate::slh::slh_keygen_with_rng::<D, H, HP, K, LEN, M, N>(rng, &HASHERS);
@ -171,11 +172,35 @@ macro_rules! functionality {
impl Signer for PrivateKey {
type Signature = [u8; SIG_LEN];
fn try_sign_with_rng_ct(
&self, rng: &mut impl CryptoRngCore, m: &[u8], randomize: bool,
fn try_sign_with_rng(
&self, rng: &mut impl CryptoRngCore, m: &[u8], ctx: &[u8], randomize: bool,
) -> Result<[u8; SIG_LEN], &'static str> {
let sig = crate::slh::slh_sign_with_rng::<A, D, H, HP, K, LEN, M, N>(
rng, &HASHERS, &m, &self.0, randomize,
rng, &HASHERS, &m, &self.0, ctx, randomize,
);
sig.map(|s| s.deserialize())
}
/// blah!
/// # Errors
fn _test_only_raw_sign(
&self, rng: &mut impl CryptoRngCore, m: &[u8], randomize: bool,
) -> Result<[u8; SIG_LEN], &'static str> {
let mut opt_rand = (self.0).pk_seed;
// 4: if (RANDOMIZE) then ▷ or to a random n-byte string
if randomize {
// 5: opt_rand ←$ Bn
rng.try_fill_bytes(&mut opt_rand)
.map_err(|_| "Alg17: rng failed")?;
// 6: end if
}
let sig = crate::slh::slh_sign_internal::<A, D, H, HP, K, LEN, M, N>(
&HASHERS,
&[m],
&self.0,
opt_rand,
);
sig.map(|s| s.deserialize())
}
@ -185,12 +210,22 @@ macro_rules! functionality {
impl Verifier for PublicKey {
type Signature = [u8; SIG_LEN];
fn try_verify_vt(
&self, m: &[u8], sig_bytes: &[u8; SIG_LEN],
fn try_verify(
&self, m: &[u8], sig_bytes: &[u8; SIG_LEN], ctx: &[u8],
) -> Result<bool, &'static str> {
let sig = SlhDsaSig::<A, D, HP, K, LEN, N>::serialize(sig_bytes);
let res = crate::slh::slh_verify::<A, D, H, HP, K, LEN, M, N>(
&HASHERS, &m, &sig, &self.0,
&HASHERS, &m, &sig, ctx, &self.0,
);
Ok(res)
}
fn _test_only_raw_verify(
&self, m: &[u8], sig_bytes: &[u8; SIG_LEN],
) -> Result<bool, &'static str> {
let sig = SlhDsaSig::<A, D, HP, K, LEN, N>::serialize(sig_bytes);
let res = crate::slh::slh_verify_internal::<A, D, H, HP, K, LEN, M, N>(
&HASHERS, &[m], &sig, &self.0,
);
Ok(res)
}
@ -264,16 +299,18 @@ macro_rules! functionality {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123);
for i in 0..5u8 {
message[3] = i;
let (pk1, sk1) = KG::try_keygen_with_rng_vt(&mut rng).unwrap();
let (pk1, sk1) = KG::try_keygen_with_rng(&mut rng).unwrap();
let pk1_bytes = pk1.into_bytes();
let pk2 = PublicKey::try_from_bytes(&pk1_bytes).unwrap();
let sk1_bytes = sk1.into_bytes();
let sk2 = PrivateKey::try_from_bytes(&sk1_bytes).unwrap();
let sig = sk2.try_sign_with_rng_ct(&mut rng, &message, true).unwrap();
let result = pk2.try_verify_vt(&message, &sig).unwrap();
let sig = sk2
.try_sign_with_rng(&mut rng, &message, b"context", true)
.unwrap();
let result = pk2.try_verify(&message, &sig, b"context").unwrap();
assert_eq!(result, true, "Signature failed to verify");
message[3] = (i + 1);
let result = pk2.try_verify_vt(&message, &sig).unwrap();
let result = pk2.try_verify(&message, &sig, b"context").unwrap();
assert_eq!(result, false, "Signature should not have verified");
}
}
@ -286,17 +323,17 @@ macro_rules! functionality {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHA2-128s parameter set is claimed to be in security strength category 1.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_128s::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_128s::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_128s::PublicKey`] and [`slh_dsa_sha2_128s::PrivateKey`] structs. The resulting
/// [`slh_dsa_sha2_128s::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_sha2_128s::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -334,17 +371,17 @@ pub mod slh_dsa_sha2_128s {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHAKE-128s parameter set is claimed to be in security strength category 1.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_128s::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_128s::try_keygen`] function below
/// to generate both [`slh_dsa_shake_128s::PublicKey`] and [`slh_dsa_shake_128s::PrivateKey`] structs. The resulting
/// [`slh_dsa_shake_128s::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_shake_128s::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -382,17 +419,17 @@ pub mod slh_dsa_shake_128s {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHA2-128f parameter set is claimed to be in security strength category 1.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_128f::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_128f::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_128f::PublicKey`] and [`slh_dsa_sha2_128f::PrivateKey`] structs. The resulting
/// [`slh_dsa_sha2_128f::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_sha2_128f::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -430,17 +467,17 @@ pub mod slh_dsa_sha2_128f {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHAKE-128f parameter set is claimed to be in security strength category 1.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_128f::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_128f::try_keygen`] function below
/// to generate both [`slh_dsa_shake_128f::PublicKey`] and [`slh_dsa_shake_128f::PrivateKey`] structs. The resulting
/// [`slh_dsa_shake_128f::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_shake_128f::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -478,17 +515,17 @@ pub mod slh_dsa_shake_128f {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHA2-192s parameter set is claimed to be in security strength category 3.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_192s::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_192s::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_192s::PublicKey`] and [`slh_dsa_sha2_192s::PrivateKey`] structs. The resulting
/// [`slh_dsa_sha2_192s::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_sha2_192s::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -526,17 +563,17 @@ pub mod slh_dsa_sha2_192s {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHAKE-192s parameter set is claimed to be in security strength category 3.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_192s::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_192s::try_keygen`] function below
/// to generate both [`slh_dsa_shake_192s::PublicKey`] and [`slh_dsa_shake_192s::PrivateKey`] structs. The resulting
/// [`slh_dsa_shake_192s::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_shake_192s::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -574,17 +611,17 @@ pub mod slh_dsa_shake_192s {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHA2-192f parameter set is claimed to be in security strength category 3.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_192f::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_192f::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_192f::PublicKey`] and [`slh_dsa_sha2_192f::PrivateKey`] structs. The resulting
/// [`slh_dsa_sha2_192f::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_sha2_192f::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -622,17 +659,17 @@ pub mod slh_dsa_sha2_192f {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHAKE-192f parameter set is claimed to be in security strength category 3.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_192f::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_192f::try_keygen`] function below
/// to generate both [`slh_dsa_shake_192f::PublicKey`] and [`slh_dsa_shake_192f::PrivateKey`] structs. The resulting
/// [`slh_dsa_shake_192f::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_shake_192f::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -670,17 +707,17 @@ pub mod slh_dsa_shake_192f {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHA2-256s parameter set is claimed to be in security strength category 5.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_256s::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_256s::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_256s::PublicKey`] and [`slh_dsa_sha2_256s::PrivateKey`] structs. The resulting
/// [`slh_dsa_sha2_256s::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_sha2_256s::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -718,17 +755,17 @@ pub mod slh_dsa_sha2_256s {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHAKE_256s parameter set is claimed to be in security strength category 5.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_256s::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_256s::try_keygen`] function below
/// to generate both [`slh_dsa_shake_256s::PublicKey`] and [`slh_dsa_shake_256s::PrivateKey`] structs. The resulting
/// [`slh_dsa_shake_256s::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_shake_256s::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -766,17 +803,17 @@ pub mod slh_dsa_shake_256s {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHA2-256f parameter set is claimed to be in security strength category 5.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_256f::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_sha2_256f::try_keygen`] function below
/// to generate both [`slh_dsa_sha2_256f::PublicKey`] and [`slh_dsa_sha2_256f::PrivateKey`] structs. The resulting
/// [`slh_dsa_sha2_256f::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_sha2_256f::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.
@ -814,17 +851,17 @@ pub mod slh_dsa_sha2_256f {
/// sizes for the public key, secret key, and signature along with a number of internal constants. The
/// SLH-DSA-SHAKE-256f parameter set is claimed to be in security strength category 5.
///
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_256f::try_keygen_vt`] function below
/// **1)** The basic usage is for an originator to start with the [`slh_dsa_shake_256f::try_keygen`] function below
/// to generate both [`slh_dsa_shake_256f::PublicKey`] and [`slh_dsa_shake_256f::PrivateKey`] structs. The resulting
/// [`slh_dsa_shake_256f::PrivateKey`] struct implements the [`traits::Signer`] trait which supplies several functions
/// to sign byte-array messages, such as [`traits::Signer::try_sign_ct()`], resulting in a Signature byte-array.
/// to sign byte-array messages, such as [`traits::Signer::try_sign()`], resulting in a Signature byte-array.
///
/// **2)** Both the `PrivateKey` and `PublicKey` structs implement the [`traits::SerDes`] trait. The originator
/// utilizes the [`traits::SerDes::into_bytes()`] functions to serialize the `PublicKey` struct into a byte-array for
/// distribution. The remote party utilizes the [`traits::SerDes::try_from_bytes()`] function to deserialize the
/// `PublicKey` byte-array into its struct.
///
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify_vt()`] function implemented on the
/// **3)** Finally, the remote party uses the [`traits::Verifier::try_verify()`] function implemented on the
/// [`slh_dsa_shake_256f::PublicKey`] struct to verify the message byte-array with the Signature byte-array..
///
/// See the top-level [crate] documentation for example code that implements the above flow.

View file

@ -22,7 +22,7 @@ pub(crate) fn slh_keygen_with_rng<
>(
rng: &mut impl CryptoRngCore, hashers: &Hashers<K, LEN, M, N>,
) -> Result<(SlhPrivateKey<N>, SlhPublicKey<N>), &'static str> {
let (d32, hp32) = (u32::try_from(D).unwrap(), u32::try_from(HP).unwrap());
//let (d32, hp32) = (u32::try_from(D).unwrap(), u32::try_from(HP).unwrap());
//
// 1: SK.seed ←$ B^n ▷ Set SK.seed, SK.prf, and PK.seed to random n-byte
@ -40,6 +40,45 @@ pub(crate) fn slh_keygen_with_rng<
rng.try_fill_bytes(&mut pk_seed)
.map_err(|_| "Alg17: rng failed3")?;
slh_keygen_internal::<D, H, HP, K, LEN, M, N>(hashers, sk_seed, sk_prf, pk_seed)
}
/// Algorithm 17: `slh_keygen()` on page 34.
/// Generate an SLH-DSA key pair.
///
/// Input: (none) <br>
/// Output: SLH-DSA key pair `(SK, PK)`.
#[allow(clippy::similar_names)] // sk_seed and pk_seed
pub(crate) fn slh_keygen_internal<
const D: usize,
const H: usize,
const HP: usize,
const K: usize,
const LEN: usize,
const M: usize,
const N: usize,
>(
hashers: &Hashers<K, LEN, M, N>, sk_seed: [u8; N], sk_prf: [u8; N], pk_seed: [u8; N],
) -> Result<(SlhPrivateKey<N>, SlhPublicKey<N>), &'static str> {
let (d32, hp32) = (u32::try_from(D).unwrap(), u32::try_from(HP).unwrap());
//
// //
// // 1: SK.seed ←$ B^n ▷ Set SK.seed, SK.prf, and PK.seed to random n-byte
// let mut sk_seed = [0u8; N];
// rng.try_fill_bytes(&mut sk_seed)
// .map_err(|_| "Alg17: rng failed1")?;
//
// // 2: SK.prf ←$ B^n ▷ strings using an approved random bit generator
// let mut sk_prf = [0u8; N];
// rng.try_fill_bytes(&mut sk_prf)
// .map_err(|_| "Alg17: rng failed2")?;
//
// // 3: PK.seed ←$ B^n
// let mut pk_seed = [0u8; N];
// rng.try_fill_bytes(&mut pk_seed)
// .map_err(|_| "Alg17: rng failed3")?;
// 4:
// 5: ADRS ← toByte(0, 32) ▷ Generate the public key for the top-level XMSS tree
let mut adrs = Adrs::default();
@ -77,12 +116,11 @@ pub(crate) fn slh_sign_with_rng<
const N: usize,
>(
rng: &mut impl CryptoRngCore, hashers: &Hashers<K, LEN, M, N>, m: &[u8], sk: &SlhPrivateKey<N>,
randomize: bool,
ctx: &[u8], randomize: bool,
) -> Result<SlhDsaSig<A, D, HP, K, LEN, N>, &'static str> {
let (d32, h32) = (u32::try_from(D).unwrap(), u32::try_from(H).unwrap());
//
// 1: ADRS ← toByte(0, 32)
let mut adrs = Adrs::default();
//let mut adrs = Adrs::default();
// 2:
// 3: opt_rand ← PK.seed ▷ Set opt_rand to either PK.seed
@ -97,6 +135,48 @@ pub(crate) fn slh_sign_with_rng<
// 6: end if
}
let mp: &[&[u8]] = &[&[0u8], &[ctx.len().to_le_bytes()[0]], ctx, m];
slh_sign_internal::<A, D, H, HP, K, LEN, M, N>(hashers, mp, sk, opt_rand)
}
/// Algorithm 18: `slh_sign(M, SK)` on page 35.
/// Generate an SLH-DSA signature.
///
/// Input: Message `M`, private key `SK = (SK.seed, SK.prf, PK.seed, PK.root)`. <br>
/// Output: SLH-DSA signature `SIG`.
#[allow(clippy::similar_names)]
#[allow(clippy::cast_possible_truncation)] // temporary, investigating idx_leaf int sizes
pub(crate) fn slh_sign_internal<
const A: usize,
const D: usize,
const H: usize,
const HP: usize,
const K: usize,
const LEN: usize,
const M: usize,
const N: usize,
>(
hashers: &Hashers<K, LEN, M, N>, m: &[&[u8]], sk: &SlhPrivateKey<N>, opt_rand: [u8; N],
) -> Result<SlhDsaSig<A, D, HP, K, LEN, N>, &'static str> {
let (d32, h32) = (u32::try_from(D).unwrap(), u32::try_from(H).unwrap());
//
// 1: ADRS ← toByte(0, 32)
let mut adrs = Adrs::default();
//
// // 2:
// // 3: opt_rand ← PK.seed ▷ Set opt_rand to either PK.seed
// let mut opt_rand = sk.pk_seed;
//
// // 4: if (RANDOMIZE) then ▷ or to a random n-byte string
// if randomize {
// // 5: opt_rand ←$ Bn
// rng.try_fill_bytes(&mut opt_rand)
// .map_err(|_| "Alg17: rng failed")?;
//
// // 6: end if
// }
// 7: R ← PRF_msg(SK.prf, opt_rand, M) ▷ Generate randomizer
let r = (hashers.prf_msg)(&sk.sk_prf, &opt_rand, m);
@ -175,7 +255,6 @@ pub(crate) fn slh_sign_with_rng<
Ok(sig)
}
/// Algorithm 19: `slh_verify(M, SIG, PK)`
/// Verify an SLH-DSA signature.
///
@ -193,7 +272,42 @@ pub(crate) fn slh_verify<
const M: usize,
const N: usize,
>(
hashers: &Hashers<K, LEN, M, N>, m: &[u8], sig: &SlhDsaSig<A, D, HP, K, LEN, N>,
hashers: &Hashers<K, LEN, M, N>, m: &[u8], sig: &SlhDsaSig<A, D, HP, K, LEN, N>, ctx: &[u8],
pk: &SlhPublicKey<N>,
) -> bool {
//let (d32, h32) = (u32::try_from(D).unwrap(), u32::try_from(H).unwrap());
// 1: if |SIG| != (1 + k(1 + a) + h + d · len) · n then
// 2: return false
// 3: end if
// The above size is performed in the wrapper/adapter deserialize function
// 4: ADRS ← toByte(0, 32)
//let mut adrs = Adrs::default();
let mp: &[&[u8]] = &[&[0u8], &[ctx.len().to_le_bytes()[0]], ctx, m];
slh_verify_internal::<A, D, H, HP, K, LEN, M, N>(hashers, mp, sig, pk)
}
/// Algorithm 19: `slh_verify(M, SIG, PK)`
/// Verify an SLH-DSA signature.
///
/// Input: Message `M`, signature `SIG`, public key `PK = (PK.seed, PK.root)`. <br>
/// Output: Boolean.
#[allow(clippy::cast_possible_truncation)] // TODO: temporary
#[allow(clippy::similar_names)]
pub(crate) fn slh_verify_internal<
const A: usize,
const D: usize,
const H: usize,
const HP: usize,
const K: usize,
const LEN: usize,
const M: usize,
const N: usize,
>(
hashers: &Hashers<K, LEN, M, N>, m: &[&[u8]], sig: &SlhDsaSig<A, D, HP, K, LEN, N>,
pk: &SlhPublicKey<N>,
) -> bool {
let (d32, h32) = (u32::try_from(D).unwrap(), u32::try_from(H).unwrap());

View file

@ -21,8 +21,8 @@ pub trait SerDes {
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
///
/// // Generate public/private key pair and signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate a msg signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate a msg signature
///
/// // Serialize the public key, and send with message and signature bytes
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -30,7 +30,7 @@ pub trait SerDes {
///
/// // Deserialize the public key, then use it to verify the msg signature
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
/// let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
/// assert!(v);
/// # Ok(())
/// # }
@ -51,8 +51,8 @@ pub trait SerDes {
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
///
/// // Generate public/private key pair and signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate a msg signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate a msg signature
///
/// // Serialize the public key, and send with message and signature bytes
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -60,7 +60,7 @@ pub trait SerDes {
///
/// // Deserialize the public key, then use it to verify the msg signature
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
/// let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
/// assert!(v);
/// # Ok(())
/// # }
@ -94,8 +94,8 @@ pub trait KeyGen {
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
///
/// // Generate public/private key pair and signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate a msg signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate a msg signature
///
/// // Serialize the public key, and send with message and signature bytes
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -103,14 +103,14 @@ pub trait KeyGen {
///
/// // Deserialize the public key, then use it to verify the msg signature
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
/// let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
/// assert!(v);
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "default-rng")]
fn try_keygen_vt() -> Result<(Self::PublicKey, Self::PrivateKey), &'static str> {
Self::try_keygen_with_rng_vt(&mut OsRng)
fn try_keygen() -> Result<(Self::PublicKey, Self::PrivateKey), &'static str> {
Self::try_keygen_with_rng(&mut OsRng)
}
/// Generates a public and private key pair specific to this security parameter set. <br>
@ -129,8 +129,8 @@ pub trait KeyGen {
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
///
/// // Generate public/private key pair and signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate a msg signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate a msg signature
///
/// // Serialize the public key, and send with message and signature bytes
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -138,12 +138,12 @@ pub trait KeyGen {
///
/// // Deserialize the public key, then use it to verify the msg signature
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
/// let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
/// assert!(v);
/// # Ok(())
/// # }
/// ```
fn try_keygen_with_rng_vt(
fn try_keygen_with_rng(
rng: &mut impl CryptoRngCore,
) -> Result<(Self::PublicKey, Self::PrivateKey), &'static str>;
}
@ -171,8 +171,8 @@ pub trait Signer {
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
///
/// // Generate public/private key pair and signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate a msg signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate a msg signature
///
/// // Serialize the public key, and send with message and signature bytes
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -180,16 +180,16 @@ pub trait Signer {
///
/// // Deserialize the public key, then use it to verify the msg signature
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
/// let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
/// assert!(v);
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "default-rng")]
fn try_sign_ct(
&self, message: &[u8], randomize: bool,
fn try_sign(
&self, message: &[u8], ctx: &[u8], randomize: bool,
) -> Result<Self::Signature, &'static str> {
self.try_sign_with_rng_ct(&mut OsRng, message, randomize)
self.try_sign_with_rng(&mut OsRng, message, ctx, randomize)
}
/// Attempt to sign the given message, returning a digital signature on success, or an error if
@ -209,8 +209,8 @@ pub trait Signer {
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
///
/// // Generate public/private key pair and signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate a msg signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate a msg signature
///
/// // Serialize the public key, and send with message and signature bytes
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -218,13 +218,19 @@ pub trait Signer {
///
/// // Deserialize the public key, then use it to verify the msg signature
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
/// let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
/// assert!(v);
/// # Ok(())
/// # }
/// ```
fn try_sign_with_rng_ct(
&self, rng: &mut impl CryptoRngCore, message: &[u8], randomize: bool,
fn try_sign_with_rng(
&self, rng: &mut impl CryptoRngCore, message: &[u8], ctx: &[u8], randomize: bool,
) -> Result<Self::Signature, &'static str>;
/// blah
/// # Errors
fn _test_only_raw_sign(
&self, rng: &mut impl CryptoRngCore, m: &[u8], randomize: bool,
) -> Result<Self::Signature, &'static str>;
}
@ -250,8 +256,8 @@ pub trait Verifier {
/// let msg_bytes = [0u8, 1, 2, 3, 4, 5, 6, 7];
///
/// // Generate public/private key pair and signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen_vt()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign_ct(&msg_bytes, true)?; // Use the secret key to generate a msg signature
/// let (pk1, sk) = slh_dsa_shake_128s::try_keygen()?; // Generate both public and secret keys
/// let sig_bytes = sk.try_sign(&msg_bytes, b"context", true)?; // Use the secret key to generate a msg signature
///
/// // Serialize the public key, and send with message and signature bytes
/// let (pk_send, msg_send, sig_send) = (pk1.into_bytes(), msg_bytes, sig_bytes);
@ -259,12 +265,18 @@ pub trait Verifier {
///
/// // Deserialize the public key, then use it to verify the msg signature
/// let pk2 = slh_dsa_shake_128s::PublicKey::try_from_bytes(&pk_recv)?;
/// let v = pk2.try_verify_vt(&msg_recv, &sig_recv)?;
/// let v = pk2.try_verify(&msg_recv, &sig_recv, b"context")?;
/// assert!(v);
/// # Ok(())
/// # }
/// ```
fn try_verify_vt(
&self, message: &[u8], signature: &Self::Signature,
fn try_verify(
&self, message: &[u8], signature: &Self::Signature, ctx: &[u8],
) -> Result<bool, &'static str>;
/// blah
/// # Errors
fn _test_only_raw_verify(
&self, m: &[u8], sig_bytes: &Self::Signature,
) -> Result<bool, &'static str>;
}

View file

@ -1,6 +1,19 @@
use zeroize::{Zeroize, ZeroizeOnDrop};
/// Supported hash functions for `hash_sign()` and `hash_verify()` functions
pub enum Ph {
/// Use SHA256 as the pre-hash function
SHA256,
/// Use SHA512 as the pre-hash function
SHA512,
/// Use Shake128 as the pre-hash function
SHAKE128,
/// Use Shake256 as the pre-hash function
SHAKE256,
}
/// Fig 16 on page 34
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
pub(crate) struct SlhDsaSig<

File diff suppressed because one or more lines are too long

View file

@ -13,6 +13,8 @@ use serde::{Deserialize, Deserializer};
use serde_json::Value;
use std::fs::File;
use std::panic;
// use fips205::slh_dsa_sha2_128f::_test_only_raw_sign;
// use fips205::slh_dsa_shake_192f::PrivateKey;
fn dehex<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
@ -82,7 +84,7 @@ macro_rules! test_keygen {
rnd.push(&test.sk_seed);
// Generate key
let (pk, sk) = KG::try_keygen_with_rng_vt(&mut rnd).unwrap();
let (pk, sk) = KG::try_keygen_with_rng(&mut rnd).unwrap();
// Check against known answers
let pk_match = pk.into_bytes() == test.pk.as_slice();
@ -197,12 +199,15 @@ macro_rules! test_sign {
// Calculate signature
let sig_exp = if $deterministic {
sk.try_sign_ct(&test.message, false)
//sk.try_sign(&test.message, false)
let mut rnd = TestRng::new();
sk._test_only_raw_sign(&mut rnd, &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)
// sk.try_sign_with_rng(&mut rnd, &test.message, true)
sk._test_only_raw_sign(&mut rnd, &test.message, true)
.expect("Error signing message")
};
@ -321,7 +326,7 @@ macro_rules! test_verify {
.expect("Unable to load public key");
// Verify signature
pk.try_verify_vt(
pk._test_only_raw_verify(
test.message.as_slice(),
test.signature
.as_slice()

File diff suppressed because one or more lines are too long

View file

@ -10,9 +10,9 @@ pub fn sign(message: &str) -> String {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed);
let randomize = true;
let (pk, sk) = slh_dsa_sha2_128f::try_keygen_with_rng_vt(&mut rng).expect("keygen failed");
let sig = sk.try_sign_with_rng_ct(&mut rng, message.as_ref(), randomize).expect("sign failed");
assert!(pk.try_verify_vt(message.as_ref(), &sig).expect("verify error"), "verify failed");
let (pk, sk) = slh_dsa_sha2_128f::try_keygen_with_rng(&mut rng).expect("keygen failed");
let sig = sk.try_sign_with_rng(&mut rng, message.as_ref(), randomize).expect("sign failed");
assert!(pk.try_verify(message.as_ref(), &sig).expect("verify error"), "verify failed");
let sk_hex = hex::encode(&sk.into_bytes());
let sig_hex = hex::encode(&sig);