#![allow(dead_code)]
extern crate alloc;
pub mod address;
pub mod fors;
pub mod hash;
pub mod hypertree;
pub mod params;
pub mod wots;
pub mod xmss;
use alloc::vec::Vec;
use core::marker::PhantomData;
pub use address::{Address, AddressType};
pub use fors::Fors;
pub use hash::{Sha2Hash, ShakeHash, SlhDsaHash};
pub use hypertree::Hypertree;
pub use params::{
Sha2_128f, Sha2_128s, Sha2_192f, Sha2_192s, Sha2_256f, Sha2_256s, Shake128f, Shake128s,
SlhDsaParams,
};
use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct SlhDsaSigningKey<P: SlhDsaParams> {
sk_seed: Vec<u8>,
sk_prf: Vec<u8>,
pk_seed: Vec<u8>,
pk_root: Vec<u8>,
#[zeroize(skip)]
_params: PhantomData<P>,
}
impl<P: SlhDsaParams> SlhDsaSigningKey<P> {
pub fn from_components(
sk_seed: Vec<u8>,
sk_prf: Vec<u8>,
pk_seed: Vec<u8>,
pk_root: Vec<u8>,
) -> Option<Self> {
if sk_seed.len() != P::N
|| sk_prf.len() != P::N
|| pk_seed.len() != P::N
|| pk_root.len() != P::N
{
return None;
}
Some(Self {
sk_seed,
sk_prf,
pk_seed,
pk_root,
_params: PhantomData,
})
}
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() != P::SK_SIZE {
return None;
}
let n = P::N;
Some(Self {
sk_seed: bytes[0..n].to_vec(),
sk_prf: bytes[n..2 * n].to_vec(),
pk_seed: bytes[2 * n..3 * n].to_vec(),
pk_root: bytes[3 * n..4 * n].to_vec(),
_params: PhantomData,
})
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(P::SK_SIZE);
bytes.extend_from_slice(&self.sk_seed);
bytes.extend_from_slice(&self.sk_prf);
bytes.extend_from_slice(&self.pk_seed);
bytes.extend_from_slice(&self.pk_root);
bytes
}
pub fn verifying_key(&self) -> SlhDsaVerifyingKey<P> {
SlhDsaVerifyingKey {
pk_seed: self.pk_seed.clone(),
pk_root: self.pk_root.clone(),
_params: PhantomData,
}
}
pub(crate) fn sk_seed(&self) -> &[u8] {
&self.sk_seed
}
pub(crate) fn sk_prf(&self) -> &[u8] {
&self.sk_prf
}
pub fn pk_seed(&self) -> &[u8] {
&self.pk_seed
}
pub fn pk_root(&self) -> &[u8] {
&self.pk_root
}
}
impl<P: SlhDsaParams> core::fmt::Debug for SlhDsaSigningKey<P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SlhDsaSigningKey")
.field("algorithm", &P::ALGORITHM)
.field("sk_seed", &"[REDACTED]")
.field("sk_prf", &"[REDACTED]")
.finish()
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct SlhDsaVerifyingKey<P: SlhDsaParams> {
pk_seed: Vec<u8>,
pk_root: Vec<u8>,
_params: PhantomData<P>,
}
impl<P: SlhDsaParams> SlhDsaVerifyingKey<P> {
pub fn from_components(pk_seed: Vec<u8>, pk_root: Vec<u8>) -> Option<Self> {
if pk_seed.len() != P::N || pk_root.len() != P::N {
return None;
}
Some(Self {
pk_seed,
pk_root,
_params: PhantomData,
})
}
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() != P::PK_SIZE {
return None;
}
let n = P::N;
Some(Self {
pk_seed: bytes[0..n].to_vec(),
pk_root: bytes[n..2 * n].to_vec(),
_params: PhantomData,
})
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(P::PK_SIZE);
bytes.extend_from_slice(&self.pk_seed);
bytes.extend_from_slice(&self.pk_root);
bytes
}
pub fn pk_seed(&self) -> &[u8] {
&self.pk_seed
}
pub fn pk_root(&self) -> &[u8] {
&self.pk_root
}
}
impl<P: SlhDsaParams> core::fmt::Debug for SlhDsaVerifyingKey<P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SlhDsaVerifyingKey")
.field("algorithm", &P::ALGORITHM)
.field("pk_seed", &hex::encode(&self.pk_seed))
.field("pk_root", &hex::encode(&self.pk_root))
.finish()
}
}
#[derive(Clone)]
pub struct SlhDsaSignature<P: SlhDsaParams> {
data: Vec<u8>,
_params: PhantomData<P>,
}
impl<P: SlhDsaParams> SlhDsaSignature<P> {
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() != P::SIG_SIZE {
return None;
}
Some(Self {
data: bytes.to_vec(),
_params: PhantomData,
})
}
pub fn to_bytes(&self) -> Vec<u8> {
self.data.clone()
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn randomness(&self) -> &[u8] {
&self.data[0..P::N]
}
}
impl<P: SlhDsaParams> core::fmt::Debug for SlhDsaSignature<P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SlhDsaSignature")
.field("algorithm", &P::ALGORITHM)
.field("size", &self.data.len())
.finish()
}
}
pub struct SlhDsa<P: SlhDsaParams, H: SlhDsaHash<P> = Sha2Hash<P>> {
_params: PhantomData<P>,
_hash: PhantomData<H>,
}
impl<P: SlhDsaParams, H: SlhDsaHash<P>> SlhDsa<P, H> {
pub fn generate_keypair() -> (SlhDsaSigningKey<P>, SlhDsaVerifyingKey<P>) {
let mut sk_seed = vec![0u8; P::N];
let mut sk_prf = vec![0u8; P::N];
let mut pk_seed = vec![0u8; P::N];
getrandom::getrandom(&mut sk_seed).expect("Failed to generate random sk_seed");
getrandom::getrandom(&mut sk_prf).expect("Failed to generate random sk_prf");
getrandom::getrandom(&mut pk_seed).expect("Failed to generate random pk_seed");
Self::generate_keypair_from_seed(&sk_seed, &sk_prf, &pk_seed)
}
pub fn generate_keypair_from_seed(
sk_seed: &[u8],
sk_prf: &[u8],
pk_seed: &[u8],
) -> (SlhDsaSigningKey<P>, SlhDsaVerifyingKey<P>) {
let pk_root = Hypertree::<P, H>::ht_root(sk_seed, pk_seed);
let sk = SlhDsaSigningKey::from_components(
sk_seed.to_vec(),
sk_prf.to_vec(),
pk_seed.to_vec(),
pk_root.clone(),
)
.expect("Invalid seed lengths");
let vk = SlhDsaVerifyingKey::from_components(pk_seed.to_vec(), pk_root)
.expect("Invalid lengths");
(sk, vk)
}
pub fn sign(sk: &SlhDsaSigningKey<P>, message: &[u8]) -> SlhDsaSignature<P> {
let mut opt_rand = vec![0u8; P::N];
getrandom::getrandom(&mut opt_rand).expect("Failed to generate randomness");
Self::sign_internal(sk, message, &opt_rand)
}
pub fn sign_deterministic(sk: &SlhDsaSigningKey<P>, message: &[u8]) -> SlhDsaSignature<P> {
Self::sign_internal(sk, message, sk.pk_seed())
}
fn sign_internal(
sk: &SlhDsaSigningKey<P>,
message: &[u8],
opt_rand: &[u8],
) -> SlhDsaSignature<P> {
let r = H::prf_msg(sk.sk_prf(), opt_rand, message);
let digest_len = (P::K * P::A + P::H + 7) / 8;
let digest = H::h_msg(&r, sk.pk_seed(), sk.pk_root(), message, digest_len);
let fors_bits = P::K * P::A;
let fors_bytes = (fors_bits + 7) / 8;
let md = &digest[0..fors_bytes];
let tree_bits = P::H - P::H_PRIME;
let (idx_tree, idx_leaf) =
Self::extract_indices(&digest[fors_bytes..], tree_bits, P::H_PRIME);
let mut fors_adrs = Address::new();
fors_adrs.set_layer_address(0);
fors_adrs.set_tree_address(idx_tree);
fors_adrs.set_type(AddressType::ForsTree);
fors_adrs.set_keypair_address(idx_leaf);
let fors_sig = Fors::<P, H>::fors_sign(md, sk.sk_seed(), sk.pk_seed(), &fors_adrs);
let fors_pk = Fors::<P, H>::fors_pk_from_sig(md, &fors_sig, sk.pk_seed(), &fors_adrs);
let ht_sig =
Hypertree::<P, H>::ht_sign(&fors_pk, sk.sk_seed(), sk.pk_seed(), idx_tree, idx_leaf);
let mut data = Vec::with_capacity(P::SIG_SIZE);
data.extend_from_slice(&r);
data.extend_from_slice(&fors_sig.to_bytes());
data.extend_from_slice(&ht_sig.to_bytes());
SlhDsaSignature {
data,
_params: PhantomData,
}
}
fn extract_indices(bytes: &[u8], tree_bits: usize, leaf_bits: usize) -> (u64, u32) {
let mut idx_tree: u64 = 0;
let mut idx_leaf: u32 = 0;
let mut bit_offset = 0;
for i in 0..tree_bits {
let byte_idx = (bit_offset + i) / 8;
let bit_idx = 7 - ((bit_offset + i) % 8);
if byte_idx < bytes.len() {
let bit_val = ((bytes[byte_idx] >> bit_idx) & 1) as u64;
idx_tree |= bit_val << (tree_bits - 1 - i);
}
}
bit_offset = tree_bits;
for i in 0..leaf_bits {
let byte_idx = (bit_offset + i) / 8;
let bit_idx = 7 - ((bit_offset + i) % 8);
if byte_idx < bytes.len() {
let bit_val = ((bytes[byte_idx] >> bit_idx) & 1) as u32;
idx_leaf |= bit_val << (leaf_bits - 1 - i);
}
}
(idx_tree, idx_leaf)
}
pub fn verify(
vk: &SlhDsaVerifyingKey<P>,
message: &[u8],
sig: &SlhDsaSignature<P>,
) -> Result<(), SignatureError> {
if sig.len() != P::SIG_SIZE {
return Err(SignatureError::InvalidLength);
}
let r = sig.randomness();
let digest_len = (P::K * P::A + P::H + 7) / 8;
let digest = H::h_msg(r, vk.pk_seed(), vk.pk_root(), message, digest_len);
let fors_bits = P::K * P::A;
let fors_bytes = (fors_bits + 7) / 8;
let md = &digest[0..fors_bytes];
let tree_bits = P::H - P::H_PRIME;
let (idx_tree, idx_leaf) =
Self::extract_indices(&digest[fors_bytes..], tree_bits, P::H_PRIME);
let fors_sig_start = P::N; let fors_sig_size = fors::ForsSignature::<P>::size();
let ht_sig_start = fors_sig_start + fors_sig_size;
let fors_sig = match fors::ForsSignature::<P>::from_bytes(
&sig.data[fors_sig_start..fors_sig_start + fors_sig_size],
) {
Some(s) => s,
None => return Err(SignatureError::InvalidSignature),
};
let ht_sig = match hypertree::HypertreeSignature::<P>::from_bytes(&sig.data[ht_sig_start..])
{
Some(s) => s,
None => return Err(SignatureError::InvalidSignature),
};
let mut fors_adrs = Address::new();
fors_adrs.set_layer_address(0);
fors_adrs.set_tree_address(idx_tree);
fors_adrs.set_type(AddressType::ForsTree);
fors_adrs.set_keypair_address(idx_leaf);
let fors_pk = Fors::<P, H>::fors_pk_from_sig(md, &fors_sig, vk.pk_seed(), &fors_adrs);
let ht_valid = Hypertree::<P, H>::ht_verify(
&fors_pk,
&ht_sig,
vk.pk_seed(),
idx_tree,
idx_leaf,
vk.pk_root(),
);
if !ht_valid {
return Err(SignatureError::InvalidSignature);
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SignatureError {
InvalidLength,
InvalidSignature,
InvalidPublicKey,
}
impl core::fmt::Display for SignatureError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
SignatureError::InvalidLength => write!(f, "invalid signature length"),
SignatureError::InvalidSignature => write!(f, "signature verification failed"),
SignatureError::InvalidPublicKey => write!(f, "invalid public key"),
}
}
}
pub type SlhDsaSha2_128s = SlhDsa<Sha2_128s, Sha2Hash<Sha2_128s>>;
pub type SlhDsaSha2_128f = SlhDsa<Sha2_128f, Sha2Hash<Sha2_128f>>;
pub type SlhDsaSha2_192s = SlhDsa<Sha2_192s, Sha2Hash<Sha2_192s>>;
pub type SlhDsaSha2_192f = SlhDsa<Sha2_192f, Sha2Hash<Sha2_192f>>;
pub type SlhDsaSha2_256s = SlhDsa<Sha2_256s, Sha2Hash<Sha2_256s>>;
pub type SlhDsaSha2_256f = SlhDsa<Sha2_256f, Sha2Hash<Sha2_256f>>;
pub type SlhDsa128f = SlhDsaSha2_128f;
pub type SlhDsa128s = SlhDsaSha2_128s;
#[cfg(test)]
mod tests;