use crate::sphincs::hash::tweakable_hash;
use crate::sphincs::Adrs;
pub fn merkle_node(
leaf: &impl Fn(u32) -> Vec<u8>,
mk_interior_adrs: &impl Fn(u16, u32) -> Adrs,
i: u32,
z: u16,
pk_seed: &[u8],
) -> Vec<u8> {
if z == 0 {
leaf(i)
} else {
let lnode = merkle_node(leaf, mk_interior_adrs, 2 * i, z - 1, pk_seed);
let rnode = merkle_node(leaf, mk_interior_adrs, 2 * i + 1, z - 1, pk_seed);
tweakable_hash(pk_seed, mk_interior_adrs(z, i), &[lnode, rnode].concat())
}
}
pub fn build_auth_path<F>(h: u16, leaf_idx: u32, node_at: F) -> Vec<Vec<u8>>
where
F: Fn(u16, u32) -> Vec<u8>,
{
let mut auth = Vec::with_capacity(h as usize);
let mut idx = leaf_idx;
for height in 0..h {
let sibling = idx ^ 1;
auth.push(node_at(height, sibling));
idx /= 2;
}
auth
}
pub fn compute_root_from_path(
leaf: Vec<u8>,
mut idx: u32,
auth: &[Vec<u8>],
pk_seed: &[u8],
mk_interior_adrs: impl Fn(u16, u32) -> Adrs,
) -> Vec<u8> {
let mut cur = leaf;
for (h, sibling) in auth.iter().enumerate() {
let combined = if idx.is_multiple_of(2) {
[cur.as_slice(), sibling.as_slice()].concat()
} else {
[sibling.as_slice(), cur.as_slice()].concat()
};
idx /= 2;
cur = tweakable_hash(pk_seed, mk_interior_adrs((h + 1) as u16, idx), &combined);
}
cur
}