use crate::der::{Reader, parse_oid};
use crate::signature_registry::SignatureAlgorithm;
use crate::slhdsa::{ParamSet, PublicKey};
use crate::x509::Error;
fn parse_slhdsa_spki(spki: &[u8], expected_set: ParamSet) -> Result<PublicKey, Error> {
let mut reader = Reader::new(spki);
let mut outer = reader.read_sequence()?;
let mut algid = outer.read_sequence()?;
let alg = parse_oid(algid.read_oid()?)?;
if alg.as_slice() != expected_set.oid() {
return Err(Error::UnsupportedAlgorithm);
}
let key_bits = outer.read_bit_string()?;
PublicKey::from_bytes(expected_set, key_bits).map_err(|_| Error::Malformed)
}
macro_rules! slhdsa_entry {
(
$(#[$m:meta])*
$name:ident, $id:expr, $set:expr
) => {
$(#[$m])*
pub(crate) struct $name;
impl SignatureAlgorithm for $name {
fn id(&self) -> &'static str { $id }
fn x509_oids(&self) -> &'static [&'static [u64]] {
$set.x509_oids_slice()
}
fn tls_schemes(&self) -> &'static [u16] { &[] }
fn verify(&self, spki: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Error> {
let key = parse_slhdsa_spki(spki, $set.set)?;
if key.verify(signature, message, b"") {
Ok(())
} else {
Err(Error::Verification)
}
}
}
};
}
struct SetOid {
set: ParamSet,
oids: &'static [&'static [u64]],
}
impl SetOid {
const fn new(set: ParamSet, oids: &'static [&'static [u64]]) -> Self {
SetOid { set, oids }
}
fn x509_oids_slice(&self) -> &'static [&'static [u64]] {
self.oids
}
}
const OID_SHA2_128S: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 20];
const OID_SHA2_128F: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 21];
const OID_SHA2_192S: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 22];
const OID_SHA2_192F: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 23];
const OID_SHA2_256S: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 24];
const OID_SHA2_256F: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 25];
const OID_SHAKE_128S: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 26];
const OID_SHAKE_128F: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 27];
const OID_SHAKE_192S: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 28];
const OID_SHAKE_192F: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 29];
const OID_SHAKE_256S: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 30];
const OID_SHAKE_256F: &[u64] = &[2, 16, 840, 1, 101, 3, 4, 3, 31];
const SHA2_128S: SetOid = SetOid::new(ParamSet::Sha2_128s, &[OID_SHA2_128S]);
const SHA2_128F: SetOid = SetOid::new(ParamSet::Sha2_128f, &[OID_SHA2_128F]);
const SHA2_192S: SetOid = SetOid::new(ParamSet::Sha2_192s, &[OID_SHA2_192S]);
const SHA2_192F: SetOid = SetOid::new(ParamSet::Sha2_192f, &[OID_SHA2_192F]);
const SHA2_256S: SetOid = SetOid::new(ParamSet::Sha2_256s, &[OID_SHA2_256S]);
const SHA2_256F: SetOid = SetOid::new(ParamSet::Sha2_256f, &[OID_SHA2_256F]);
const SHAKE_128S: SetOid = SetOid::new(ParamSet::Shake_128s, &[OID_SHAKE_128S]);
const SHAKE_128F: SetOid = SetOid::new(ParamSet::Shake_128f, &[OID_SHAKE_128F]);
const SHAKE_192S: SetOid = SetOid::new(ParamSet::Shake_192s, &[OID_SHAKE_192S]);
const SHAKE_192F: SetOid = SetOid::new(ParamSet::Shake_192f, &[OID_SHAKE_192F]);
const SHAKE_256S: SetOid = SetOid::new(ParamSet::Shake_256s, &[OID_SHAKE_256S]);
const SHAKE_256F: SetOid = SetOid::new(ParamSet::Shake_256f, &[OID_SHAKE_256F]);
slhdsa_entry!(
SlhDsaSha2128s, "slh-dsa-sha2-128s", SHA2_128S
);
slhdsa_entry!(
SlhDsaSha2128f, "slh-dsa-sha2-128f", SHA2_128F
);
slhdsa_entry!(
SlhDsaSha2192s, "slh-dsa-sha2-192s", SHA2_192S
);
slhdsa_entry!(
SlhDsaSha2192f, "slh-dsa-sha2-192f", SHA2_192F
);
slhdsa_entry!(
SlhDsaSha2256s, "slh-dsa-sha2-256s", SHA2_256S
);
slhdsa_entry!(
SlhDsaSha2256f, "slh-dsa-sha2-256f", SHA2_256F
);
slhdsa_entry!(
SlhDsaShake128s, "slh-dsa-shake-128s", SHAKE_128S
);
slhdsa_entry!(
SlhDsaShake128f, "slh-dsa-shake-128f", SHAKE_128F
);
slhdsa_entry!(
SlhDsaShake192s, "slh-dsa-shake-192s", SHAKE_192S
);
slhdsa_entry!(
SlhDsaShake192f, "slh-dsa-shake-192f", SHAKE_192F
);
slhdsa_entry!(
SlhDsaShake256s, "slh-dsa-shake-256s", SHAKE_256S
);
slhdsa_entry!(
SlhDsaShake256f, "slh-dsa-shake-256f", SHAKE_256F
);
#[cfg(test)]
mod tests {
use super::*;
use crate::hash::Sha256;
use crate::rng::HmacDrbg;
use crate::signature_registry::{find_by_id, find_by_oid};
use crate::slhdsa::PrivateKey;
use crate::x509::AnyPublicKey;
#[test]
fn slh_dsa_128f_lookup_and_verify() {
let mut rng = HmacDrbg::<Sha256>::new(b"reg-slhdsa-128f", b"n", &[]);
let (sk, pk) = PrivateKey::generate(ParamSet::Sha2_128f, &mut rng);
let spki = AnyPublicKey::SlhDsa(pk).to_spki_der();
let sig = sk.sign(&mut rng, b"hi", b"").unwrap();
let by_id = find_by_id("slh-dsa-sha2-128f").unwrap();
by_id.verify(&spki, b"hi", &sig).unwrap();
let by_oid = find_by_oid(OID_SHA2_128F).unwrap();
assert_eq!(by_oid.id(), "slh-dsa-sha2-128f");
}
}