// LEAFCALC !!!
if (layer == numLayer - 1)
{ // lowest layer computes the
// necessary leaf completely at this
// time
WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed,
digestProvider.get(), otsIndex[layer]);
help = ots.getPublicKey();
}
else
{ // other layers use the precomputed leafs in
// nextNextLeaf
byte[] dummy = new byte[mdLength];
System.arraycopy(currentSeeds[layer], 0, dummy, 0, mdLength);
gmssRandom.nextSeed(dummy);
help = upperLeaf[layer].getLeaf();
this.upperLeaf[layer].initLeafCalc(dummy);
// WinternitzOTSVerify otsver = new
// WinternitzOTSVerify(algNames, otsIndex[layer]);
// byte[] help2 = otsver.Verify(currentRoot[layer],
// currentRootSig[layer]);
// System.out.println(" --- " + layer + " " +
// ByteUtils.toHexString(help) + " " +
// ByteUtils.toHexString(help2));
}
System.arraycopy(help, 0, currentAuthPaths[layer][0], 0, mdLength);
}
else
{
// STEP 4a of Algorithm
// get new left currentAuthPath node on height tau
byte[] toBeHashed = new byte[mdLength << 1];
System.arraycopy(currentAuthPaths[layer][Tau - 1], 0, toBeHashed,
0, mdLength);
// free the shared keep[layer][tau/2]
System.arraycopy(keep[layer][(int)Math.floor((Tau - 1) / 2)], 0,
toBeHashed, mdLength, mdLength);
messDigestTrees.update(toBeHashed, 0, toBeHashed.length);
currentAuthPaths[layer][Tau] = new byte[messDigestTrees.getDigestSize()];
messDigestTrees.doFinal(currentAuthPaths[layer][Tau], 0);
// STEP 4b and 4c of Algorithm
// copy right nodes to currentAuthPath on height 0..Tau-1
for (int i = 0; i < Tau; i++)
{
// STEP 4b of Algorithm
// 1st: copy from treehashs
if (i < H - K)
{
if (currentTreehash[layer][i].wasFinished())
{
System.arraycopy(currentTreehash[layer][i]
.getFirstNode(), 0, currentAuthPaths[layer][i],
0, mdLength);
currentTreehash[layer][i].destroy();
}
else
{
System.err
.println("Treehash ("
+ layer
+ ","
+ i
+ ") not finished when needed in AuthPathComputation");
}
}
// 2nd: copy precomputed values from Retain
if (i < H - 1 && i >= H - K)
{
if (currentRetain[layer][i - (H - K)].size() > 0)
{
// pop element from retain
System.arraycopy(currentRetain[layer][i - (H - K)]
.lastElement(), 0, currentAuthPaths[layer][i],
0, mdLength);
currentRetain[layer][i - (H - K)]
.removeElementAt(currentRetain[layer][i
- (H - K)].size() - 1);
}
}
// STEP 4c of Algorithm
// initialize new stack at heights 0..Tau-1
if (i < H - K)
{
// create stacks anew
int startPoint = Phi + 3 * (1 << i);
if (startPoint < numLeafs[layer])
{
// if (layer < 2) {
// System.out.println("initialized TH " + i + " on layer
// " + layer);
// }
currentTreehash[layer][i].initialize();
}
}
}
}
// now keep space is free to use
if (Tau < H - 1 && L == 0)
{
System.arraycopy(tempKeep, 0,
keep[layer][(int)Math.floor(Tau / 2)], 0, mdLength);
}
// only update empty stack at height h if all other stacks have
// tailnodes with height >h
// finds active stack with lowest node height, choses lower index in
// case of tie
// on the lowest layer leafs must be computed at once, no precomputation
// is possible. So all treehash updates are done at once here
if (layer == numLayer - 1)
{
for (int tmp = 1; tmp <= (H - K) / 2; tmp++)
{
// index of the treehash instance that receives the next update
int minTreehash = getMinTreehashIndex(layer);
// if active treehash is found update with a leaf
if (minTreehash >= 0)
{
try
{
byte[] seed = new byte[mdLength];
System.arraycopy(
this.currentTreehash[layer][minTreehash]
.getSeedActive(), 0, seed, 0, mdLength);
byte[] seed2 = gmssRandom.nextSeed(seed);
WinternitzOTSignature ots = new WinternitzOTSignature(
seed2, this.digestProvider.get(), this.otsIndex[layer]);
byte[] leaf = ots.getPublicKey();
currentTreehash[layer][minTreehash].update(
this.gmssRandom, leaf);
}
catch (Exception e)
{