use super::SlhDsaError;
use super::address::Adrs;
use super::fors;
use super::hash;
use super::hypertree;
use super::params::{self, Params};
use super::rng::CryptoRng;
use super::xmss;
use alloc::vec::Vec;
pub fn slh_keygen_internal<P: Params>(sk_seed: &[u8], sk_prf: &[u8], pk_seed: &[u8]) -> (Vec<u8>, Vec<u8>) {
let mut adrs = Adrs::new();
adrs.set_layer_address((P::D - 1) as u32);
let pk_root = xmss::xmss_node::<P>(sk_seed, pk_seed, 0, P::H_PRIME as u32, &mut adrs);
let mut sk = Vec::with_capacity(P::SK_LEN);
sk.extend_from_slice(sk_seed);
sk.extend_from_slice(sk_prf);
sk.extend_from_slice(pk_seed);
sk.extend_from_slice(&pk_root);
let mut pk = Vec::with_capacity(P::PK_LEN);
pk.extend_from_slice(pk_seed);
pk.extend_from_slice(&pk_root);
(sk, pk)
}
pub fn slh_sign_internal<P: Params>(m: &[u8], sk: &[u8], addrnd: &[u8]) -> Result<Vec<u8>, SlhDsaError> {
let n = P::N;
let sk_seed = &sk[..n];
let sk_prf = &sk[n..2 * n];
let pk_seed = &sk[2 * n..3 * n];
let pk_root = &sk[3 * n..4 * n];
let r = hash::prf_msg::<P>(sk_prf, addrnd, m);
let sig_len = params::sig_len::<P>();
let fors_sig_len = P::K * (1 + P::A) * n;
let mut sig = alloc::vec![0u8; sig_len];
sig[..n].copy_from_slice(&r);
let digest = hash::h_msg::<P>(&r, pk_seed, pk_root, m);
let md_len = (P::K * P::A + 7) / 8;
let tree_bits = P::H - P::H_PRIME; let tree_bytes = (tree_bits + 7) / 8;
let leaf_bytes = (P::H_PRIME + 7) / 8;
let md = &digest[..md_len];
let tree_part = &digest[md_len..md_len + tree_bytes];
let leaf_part = &digest[md_len + tree_bytes..md_len + tree_bytes + leaf_bytes];
let idx_tree = bytes_to_u64(tree_part) & ((1u64 << tree_bits) - 1);
let idx_leaf = bytes_to_u32(leaf_part) & ((1u32 << P::H_PRIME) - 1);
let mut adrs = Adrs::new();
adrs.set_tree_address(idx_tree);
adrs.set_type_and_clear(super::address::FORS_TREE);
adrs.set_key_pair_address(idx_leaf);
let adrs = adrs;
let pk_fors = {
let fors_slot = &mut sig[n..n + fors_sig_len];
#[cfg(feature = "sca-fors-redundancy")]
{
fors::fors_sign_into_redundant::<P>(md, sk_seed, pk_seed, &adrs, fors_slot)?
}
#[cfg(not(feature = "sca-fors-redundancy"))]
{
fors::fors_sign_into::<P>(md, sk_seed, pk_seed, &adrs, fors_slot)?;
fors::fors_pk_from_sig::<P>(&sig[n..n + fors_sig_len], md, pk_seed, &adrs)
}
};
{
let ht_slot = &mut sig[n + fors_sig_len..];
hypertree::ht_sign_into::<P>(&pk_fors, sk_seed, pk_seed, idx_tree, idx_leaf, ht_slot);
}
Ok(sig)
}
pub fn slh_verify_internal<P: Params>(m: &[u8], sig: &[u8], pk: &[u8]) -> bool {
let n = P::N;
let expected_sig_len = params::sig_len::<P>();
if sig.len() != expected_sig_len {
return false;
}
if pk.len() != P::PK_LEN {
return false;
}
let pk_seed = &pk[..n];
let pk_root = &pk[n..2 * n];
let r = &sig[..n];
let fors_sig_len = P::K * (1 + P::A) * n;
let sig_fors = &sig[n..n + fors_sig_len];
let sig_ht = &sig[n + fors_sig_len..];
let digest = hash::h_msg::<P>(r, pk_seed, pk_root, m);
let md_len = (P::K * P::A + 7) / 8;
let tree_bits = P::H - P::H_PRIME;
let tree_bytes = (tree_bits + 7) / 8;
let leaf_bytes = (P::H_PRIME + 7) / 8;
let md = &digest[..md_len];
let tree_part = &digest[md_len..md_len + tree_bytes];
let leaf_part = &digest[md_len + tree_bytes..md_len + tree_bytes + leaf_bytes];
let idx_tree = bytes_to_u64(tree_part) & ((1u64 << tree_bits) - 1);
let idx_leaf = bytes_to_u32(leaf_part) & ((1u32 << P::H_PRIME) - 1);
let mut adrs = Adrs::new();
adrs.set_tree_address(idx_tree);
adrs.set_type_and_clear(super::address::FORS_TREE);
adrs.set_key_pair_address(idx_leaf);
let adrs = adrs;
let pk_fors = fors::fors_pk_from_sig::<P>(sig_fors, md, pk_seed, &adrs);
hypertree::ht_verify::<P>(&pk_fors, sig_ht, pk_seed, idx_tree, idx_leaf, pk_root)
}
pub fn slh_keygen<P: Params>(rng: &mut dyn CryptoRng) -> Result<(Vec<u8>, Vec<u8>), SlhDsaError> {
let n = P::N;
let mut sk_seed = vec![0u8; n];
let mut sk_prf = vec![0u8; n];
let mut pk_seed = vec![0u8; n];
rng.fill_bytes(&mut sk_seed)?;
rng.fill_bytes(&mut sk_prf)?;
rng.fill_bytes(&mut pk_seed)?;
Ok(slh_keygen_internal::<P>(&sk_seed, &sk_prf, &pk_seed))
}
pub fn slh_sign<P: Params>(m: &[u8], sk: &[u8], rng: &mut dyn CryptoRng) -> Result<Vec<u8>, SlhDsaError> {
let n = P::N;
if sk.len() != P::SK_LEN {
return Err(SlhDsaError::InvalidKey);
}
let mut addrnd = vec![0u8; n];
rng.fill_bytes(&mut addrnd)?;
slh_sign_internal::<P>(m, sk, &addrnd)
}
pub fn slh_verify<P: Params>(m: &[u8], sig: &[u8], pk: &[u8]) -> Result<bool, SlhDsaError> {
if pk.len() != P::PK_LEN {
return Err(SlhDsaError::InvalidKey);
}
let expected_sig_len = params::sig_len::<P>();
if sig.len() != expected_sig_len {
return Err(SlhDsaError::InvalidSignature);
}
Ok(slh_verify_internal::<P>(m, sig, pk))
}
fn bytes_to_u64(b: &[u8]) -> u64 {
let mut val = 0u64;
for &byte in b {
val = (val << 8) | byte as u64;
}
val
}
fn bytes_to_u32(b: &[u8]) -> u32 {
let mut val = 0u32;
for &byte in b {
val = (val << 8) | byte as u32;
}
val
}