use super::address::{Adrs, TREE, WOTS_HASH};
use super::hash;
use super::params::Params;
use super::wots;
use alloc::vec::Vec;
pub fn xmss_node<P: Params>(sk_seed: &[u8], pk_seed: &[u8], i: u32, z: u32, adrs: &mut Adrs) -> Vec<u8> {
if z == 0 {
adrs.set_type_and_clear(WOTS_HASH);
adrs.set_key_pair_address(i);
return wots::wots_pk_gen::<P>(sk_seed, pk_seed, adrs);
}
let num_leaves = 1u32 << z;
let base = i;
let mut nodes: Vec<Vec<u8>> = Vec::with_capacity(num_leaves as usize);
for j in 0..num_leaves {
adrs.set_type_and_clear(WOTS_HASH);
adrs.set_key_pair_address(base + j);
let leaf = wots::wots_pk_gen::<P>(sk_seed, pk_seed, adrs);
nodes.push(leaf);
}
for height in 1..=z {
let mut new_nodes = Vec::with_capacity(nodes.len() / 2);
for j in 0..(nodes.len() / 2) {
adrs.set_type_and_clear(TREE);
adrs.set_tree_height(height);
adrs.set_tree_index(base / (1 << height) + j as u32);
let parent = hash::hash_h::<P>(pk_seed, adrs, &nodes[2 * j], &nodes[2 * j + 1]);
new_nodes.push(parent);
}
nodes = new_nodes;
}
nodes.into_iter().next().unwrap()
}
pub fn xmss_sign<P: Params>(m: &[u8], sk_seed: &[u8], idx: u32, pk_seed: &[u8], adrs: &mut Adrs) -> Vec<u8> {
let mut sig = alloc::vec![0u8; (P::LEN + P::H_PRIME) * P::N];
xmss_sign_into::<P>(m, sk_seed, idx, pk_seed, adrs, &mut sig);
sig
}
pub fn xmss_sign_into<P: Params>(m: &[u8], sk_seed: &[u8], idx: u32, pk_seed: &[u8], adrs: &mut Adrs, out: &mut [u8]) {
let wots_sig_len = P::LEN * P::N;
let total_len = wots_sig_len + P::H_PRIME * P::N;
debug_assert!(out.len() >= total_len);
let (sig_wots_slot, auth_slot) = out[..total_len].split_at_mut(wots_sig_len);
for j in 0..P::H_PRIME {
let k = (idx >> j) ^ 1;
let node = xmss_node::<P>(sk_seed, pk_seed, k * (1 << j), j as u32, adrs);
auth_slot[j * P::N..(j + 1) * P::N].copy_from_slice(&node);
}
adrs.set_type_and_clear(WOTS_HASH);
adrs.set_key_pair_address(idx);
wots::wots_sign_into::<P>(m, sk_seed, pk_seed, adrs, sig_wots_slot);
}
pub fn xmss_pk_from_sig<P: Params>(idx: u32, sig_xmss: &[u8], m: &[u8], pk_seed: &[u8], adrs: &mut Adrs) -> Vec<u8> {
let wots_sig_len = P::LEN * P::N;
let sig_wots = &sig_xmss[..wots_sig_len];
let auth = &sig_xmss[wots_sig_len..];
adrs.set_type_and_clear(WOTS_HASH);
adrs.set_key_pair_address(idx);
let mut node = wots::wots_pk_from_sig::<P>(sig_wots, m, pk_seed, adrs);
adrs.set_type_and_clear(TREE);
adrs.set_tree_index(idx);
for k in 0..P::H_PRIME {
let auth_k = &auth[k * P::N..(k + 1) * P::N];
adrs.set_tree_height((k + 1) as u32);
if ((idx >> k) & 1) == 0 {
adrs.set_tree_index(idx >> (k + 1));
node = hash::hash_h::<P>(pk_seed, adrs, &node, auth_k);
} else {
adrs.set_tree_index(idx >> (k + 1));
node = hash::hash_h::<P>(pk_seed, adrs, auth_k, &node);
}
}
node
}