use crate::ledger::sha512;
use crate::pqsig;
use alloc::vec::Vec;
const N: usize = 64;
fn leaf_hash(wots_pk: &[u8; N]) -> [u8; N] {
let mut b = Vec::with_capacity(1 + N);
b.push(0x00);
b.extend_from_slice(wots_pk);
sha512(&b)
}
fn node_hash(left: &[u8; N], right: &[u8; N]) -> [u8; N] {
let mut b = Vec::with_capacity(1 + 2 * N);
b.push(0x01);
b.extend_from_slice(left);
b.extend_from_slice(right);
sha512(&b)
}
fn leaf_seed(seed: &[u8; N], i: u32) -> [u8; N] {
let mut b = Vec::with_capacity(N + 5);
b.extend_from_slice(seed);
b.push(0x02);
b.extend_from_slice(&i.to_be_bytes());
sha512(&b)
}
fn build_levels(leaves: &[[u8; N]]) -> Vec<Vec<[u8; N]>> {
let mut levels = alloc::vec![leaves.to_vec()];
while levels.last().map(Vec::len).unwrap_or(0) > 1 {
let cur = levels.last().unwrap();
let mut next = Vec::with_capacity(cur.len() / 2);
for pair in cur.chunks(2) {
next.push(node_hash(&pair[0], &pair[1])); }
levels.push(next);
}
levels
}
pub struct MerkleKey {
seed: [u8; N],
pub height: u32,
pub root: [u8; N],
next: u32,
leaves: Vec<[u8; N]>,
}
pub struct MerkleSig {
pub index: u32,
pub wots: pqsig::Signature,
pub path: Vec<[u8; N]>,
}
impl MerkleKey {
pub fn keygen(seed: &[u8; N], height: u32) -> MerkleKey {
let n = 1u32 << height;
let mut leaves = Vec::with_capacity(n as usize);
for i in 0..n {
let wots_pk = pqsig::keygen(&leaf_seed(seed, i));
leaves.push(leaf_hash(&wots_pk));
}
let root = build_levels(&leaves).last().unwrap()[0];
MerkleKey {
seed: *seed,
height,
root,
next: 0,
leaves,
}
}
pub fn used(&self) -> u32 {
self.next
}
pub fn capacity(&self) -> u32 {
1u32 << self.height
}
pub fn sign(&mut self, msg: &[u8; N]) -> Option<MerkleSig> {
if self.next >= self.capacity() {
return None;
}
let index = self.next;
self.next += 1;
let wots = pqsig::sign(&leaf_seed(&self.seed, index), msg);
let levels = build_levels(&self.leaves);
let mut path = Vec::with_capacity(self.height as usize);
let mut idx = index;
for lv in levels.iter().take(self.height as usize) {
path.push(lv[(idx ^ 1) as usize]);
idx >>= 1;
}
Some(MerkleSig { index, wots, path })
}
}
pub fn verify(root: &[u8; N], height: u32, msg: &[u8; N], sig: &MerkleSig) -> bool {
if sig.path.len() != height as usize || sig.index >= (1u32 << height) {
return false;
}
let leaf_pk = match pqsig::pk_from_sig(msg, &sig.wots) {
Some(pk) => pk,
None => return false,
};
let mut node = leaf_hash(&leaf_pk);
let mut idx = sig.index;
for sib in &sig.path {
node = if idx & 1 == 0 {
node_hash(&node, sib)
} else {
node_hash(sib, &node)
};
idx >>= 1;
}
node == *root
}