package org.bouncycastle.pqc.crypto.sphincs;
class Tree
{
static class leafaddr
{
int level;
long subtree;
long subleaf;
public leafaddr()
{
}
public leafaddr(leafaddr leafaddr)
{
this.level = leafaddr.level;
this.subtree = leafaddr.subtree;
this.subleaf = leafaddr.subleaf;
}
}
static void l_tree(HashFunctions hs, byte[] leaf, int leafOff, byte[] wots_pk, int pkOff, byte[] masks, int masksOff)
{
int l = Wots.WOTS_L;
int i, j = 0;
for (i = 0; i < Wots.WOTS_LOG_L; i++)
{
for (j = 0; j < (l >>> 1); j++)
{
hs.hash_2n_n_mask(wots_pk, pkOff + j * SPHINCS256Config.HASH_BYTES, wots_pk, pkOff + j * 2 * SPHINCS256Config.HASH_BYTES, masks, masksOff + i * 2 * SPHINCS256Config.HASH_BYTES);
}
if ((l & 1) != 0)
{
System.arraycopy(wots_pk, pkOff + (l - 1) * SPHINCS256Config.HASH_BYTES, wots_pk, pkOff + (l >>> 1) * SPHINCS256Config.HASH_BYTES, SPHINCS256Config.HASH_BYTES);
l = (l >>> 1) + 1;
}
else
{
l = (l >>> 1);
}
}
System.arraycopy(wots_pk, pkOff, leaf, leafOff, SPHINCS256Config.HASH_BYTES);
}
static void treehash(HashFunctions hs, byte[] node, int nodeOff, int height, byte[] sk, leafaddr leaf, byte[] masks, int masksOff)
{
leafaddr a = new leafaddr(leaf);
int lastnode, i;
byte[] stack = new byte[(height + 1) * SPHINCS256Config.HASH_BYTES];
int[] stacklevels = new int[height + 1];
int stackoffset = 0;
lastnode = (int)(a.subleaf + (1 << height));
for (; a.subleaf < lastnode; a.subleaf++)
{
gen_leaf_wots(hs, stack, stackoffset * SPHINCS256Config.HASH_BYTES, masks, masksOff, sk, a);
stacklevels[stackoffset] = 0;
stackoffset++;
while (stackoffset > 1 && stacklevels[stackoffset - 1] == stacklevels[stackoffset - 2])
{
int maskoffset = 2 * (stacklevels[stackoffset - 1] + Wots.WOTS_LOG_L) * SPHINCS256Config.HASH_BYTES;
hs.hash_2n_n_mask(stack, (stackoffset - 2) * SPHINCS256Config.HASH_BYTES, stack, (stackoffset - 2) * SPHINCS256Config.HASH_BYTES,
masks, masksOff + maskoffset);
stacklevels[stackoffset - 2]++;
stackoffset--;
}
}
for (i = 0; i < SPHINCS256Config.HASH_BYTES; i++)
{
node[nodeOff + i] = stack[i];
}
}
static void gen_leaf_wots(HashFunctions hs, byte[] leaf, int leafOff, byte[] masks, int masksOff, byte[] sk, leafaddr a)
{
byte[] seed = new byte[SPHINCS256Config.SEED_BYTES];
byte[] pk = new byte[Wots.WOTS_L * SPHINCS256Config.HASH_BYTES];
Wots w = new Wots();
Seed.get_seed(hs, seed, 0, sk, a);
w.wots_pkgen(hs, pk, 0, seed, 0, masks, masksOff);
l_tree(hs, leaf, leafOff, pk, 0, masks, masksOff);
}
}