diff options
author | David Hook <dgh@cryptoworkshop.com> | 2013-05-31 11:07:45 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2013-05-31 11:07:45 +0400 |
commit | 2b976f5364cfdbc37d3086019d93483c983eb80b (patch) | |
tree | cb846af3fd1d43f9c2562a1fb2d06b997ad8f229 /core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java | |
parent | 5f714bd92fbd780d22406f4bc3681be005f6f04a (diff) |
initial reshuffle
Diffstat (limited to 'core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java')
-rw-r--r-- | core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java | 1041 |
1 files changed, 1041 insertions, 0 deletions
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java new file mode 100644 index 00000000..83cf7972 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java @@ -0,0 +1,1041 @@ +package org.bouncycastle.pqc.crypto.gmss; + +import java.util.Vector; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.pqc.crypto.gmss.util.GMSSRandom; +import org.bouncycastle.pqc.crypto.gmss.util.WinternitzOTSignature; +import org.bouncycastle.util.Arrays; + + +/** + * This class provides a specification for a GMSS private key. + */ +public class GMSSPrivateKeyParameters + extends GMSSKeyParameters +{ + private int[] index; + + private byte[][] currentSeeds; + private byte[][] nextNextSeeds; + + private byte[][][] currentAuthPaths; + private byte[][][] nextAuthPaths; + + private Treehash[][] currentTreehash; + private Treehash[][] nextTreehash; + + private Vector[] currentStack; + private Vector[] nextStack; + + private Vector[][] currentRetain; + private Vector[][] nextRetain; + + private byte[][][] keep; + + private GMSSLeaf[] nextNextLeaf; + private GMSSLeaf[] upperLeaf; + private GMSSLeaf[] upperTreehashLeaf; + + private int[] minTreehash; + + private GMSSParameters gmssPS; + + private byte[][] nextRoot; + private GMSSRootCalc[] nextNextRoot; + + private byte[][] currentRootSig; + private GMSSRootSig[] nextRootSig; + + private GMSSDigestProvider digestProvider; + + private boolean used = false; + + /** + * An array of the heights of the authentication trees of each layer + */ + private int[] heightOfTrees; + + /** + * An array of the Winternitz parameter 'w' of each layer + */ + private int[] otsIndex; + + /** + * The parameter K needed for the authentication path computation + */ + private int[] K; + + /** + * the number of Layers + */ + private int numLayer; + + /** + * The hash function used to construct the authentication trees + */ + private Digest messDigestTrees; + + /** + * The message digest length + */ + private int mdLength; + + /** + * The PRNG used for private key generation + */ + private GMSSRandom gmssRandom; + + + /** + * The number of leafs of one tree of each layer + */ + private int[] numLeafs; + + + /** + * Generates a new GMSS private key + * + * @param currentSeed seed for the generation of private OTS keys for the + * current subtrees + * @param nextNextSeed seed for the generation of private OTS keys for the next + * subtrees + * @param currentAuthPath array of current authentication paths + * @param nextAuthPath array of next authentication paths + * @param currentTreehash array of current treehash instances + * @param nextTreehash array of next treehash instances + * @param currentStack array of current shared stacks + * @param nextStack array of next shared stacks + * @param currentRetain array of current retain stacks + * @param nextRetain array of next retain stacks + * @param nextRoot the roots of the next subtree + * @param currentRootSig array of signatures of the roots of the current subtrees + * @param gmssParameterset the GMSS Parameterset + * @see org.bouncycastle.pqc.crypto.gmss.GMSSKeyPairGenerator + */ + + public GMSSPrivateKeyParameters(byte[][] currentSeed, byte[][] nextNextSeed, + byte[][][] currentAuthPath, byte[][][] nextAuthPath, + Treehash[][] currentTreehash, Treehash[][] nextTreehash, + Vector[] currentStack, Vector[] nextStack, + Vector[][] currentRetain, Vector[][] nextRetain, byte[][] nextRoot, + byte[][] currentRootSig, GMSSParameters gmssParameterset, + GMSSDigestProvider digestProvider) + { + this(null, currentSeed, nextNextSeed, currentAuthPath, nextAuthPath, + null, currentTreehash, nextTreehash, currentStack, nextStack, + currentRetain, nextRetain, null, null, null, null, nextRoot, + null, currentRootSig, null, gmssParameterset, digestProvider); + } + + /** + * /** + * + * @param index tree indices + * @param keep keep array for the authPath algorithm + * @param currentTreehash treehash for authPath algorithm of current tree + * @param nextTreehash treehash for authPath algorithm of next tree (TREE+) + * @param currentStack shared stack for authPath algorithm of current tree + * @param nextStack shared stack for authPath algorithm of next tree (TREE+) + * @param currentRetain retain stack for authPath algorithm of current tree + * @param nextRetain retain stack for authPath algorithm of next tree (TREE+) + * @param nextNextLeaf array of upcoming leafs of the tree after next (LEAF++) of + * each layer + * @param upperLeaf needed for precomputation of upper nodes + * @param upperTreehashLeaf needed for precomputation of upper treehash nodes + * @param minTreehash index of next treehash instance to receive an update + * @param nextRoot the roots of the next trees (ROOT+) + * @param nextNextRoot the roots of the tree after next (ROOT++) + * @param currentRootSig array of signatures of the roots of the current subtrees + * (SIG) + * @param nextRootSig array of signatures of the roots of the next subtree + * (SIG+) + * @param gmssParameterset the GMSS Parameterset + */ + public GMSSPrivateKeyParameters(int[] index, byte[][] currentSeeds, + byte[][] nextNextSeeds, byte[][][] currentAuthPaths, + byte[][][] nextAuthPaths, byte[][][] keep, + Treehash[][] currentTreehash, Treehash[][] nextTreehash, + Vector[] currentStack, Vector[] nextStack, + Vector[][] currentRetain, Vector[][] nextRetain, + GMSSLeaf[] nextNextLeaf, GMSSLeaf[] upperLeaf, + GMSSLeaf[] upperTreehashLeaf, int[] minTreehash, byte[][] nextRoot, + GMSSRootCalc[] nextNextRoot, byte[][] currentRootSig, + GMSSRootSig[] nextRootSig, GMSSParameters gmssParameterset, + GMSSDigestProvider digestProvider) + { + + super(true, gmssParameterset); + + // construct message digest + + this.messDigestTrees = digestProvider.get(); + this.mdLength = messDigestTrees.getDigestSize(); + + + // Parameter + this.gmssPS = gmssParameterset; + this.otsIndex = gmssParameterset.getWinternitzParameter(); + this.K = gmssParameterset.getK(); + this.heightOfTrees = gmssParameterset.getHeightOfTrees(); + // initialize numLayer + this.numLayer = gmssPS.getNumOfLayers(); + + // initialize index if null + if (index == null) + { + this.index = new int[numLayer]; + for (int i = 0; i < numLayer; i++) + { + this.index[i] = 0; + } + } + else + { + this.index = index; + } + + this.currentSeeds = currentSeeds; + this.nextNextSeeds = nextNextSeeds; + + this.currentAuthPaths = currentAuthPaths; + this.nextAuthPaths = nextAuthPaths; + + // initialize keep if null + if (keep == null) + { + this.keep = new byte[numLayer][][]; + for (int i = 0; i < numLayer; i++) + { + this.keep[i] = new byte[(int)Math.floor(heightOfTrees[i] / 2)][mdLength]; + } + } + else + { + this.keep = keep; + } + + // initialize stack if null + if (currentStack == null) + { + this.currentStack = new Vector[numLayer]; + for (int i = 0; i < numLayer; i++) + { + this.currentStack[i] = new Vector(); + } + } + else + { + this.currentStack = currentStack; + } + + // initialize nextStack if null + if (nextStack == null) + { + this.nextStack = new Vector[numLayer - 1]; + for (int i = 0; i < numLayer - 1; i++) + { + this.nextStack[i] = new Vector(); + } + } + else + { + this.nextStack = nextStack; + } + + this.currentTreehash = currentTreehash; + this.nextTreehash = nextTreehash; + + this.currentRetain = currentRetain; + this.nextRetain = nextRetain; + + this.nextRoot = nextRoot; + + this.digestProvider = digestProvider; + + if (nextNextRoot == null) + { + this.nextNextRoot = new GMSSRootCalc[numLayer - 1]; + for (int i = 0; i < numLayer - 1; i++) + { + this.nextNextRoot[i] = new GMSSRootCalc( + this.heightOfTrees[i + 1], this.K[i + 1], this.digestProvider); + } + } + else + { + this.nextNextRoot = nextNextRoot; + } + this.currentRootSig = currentRootSig; + + // calculate numLeafs + numLeafs = new int[numLayer]; + for (int i = 0; i < numLayer; i++) + { + numLeafs[i] = 1 << heightOfTrees[i]; + } + // construct PRNG + this.gmssRandom = new GMSSRandom(messDigestTrees); + + if (numLayer > 1) + { + // construct the nextNextLeaf (LEAFs++) array for upcoming leafs in + // tree after next (TREE++) + if (nextNextLeaf == null) + { + this.nextNextLeaf = new GMSSLeaf[numLayer - 2]; + for (int i = 0; i < numLayer - 2; i++) + { + this.nextNextLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i + 1], numLeafs[i + 2], this.nextNextSeeds[i]); + } + } + else + { + this.nextNextLeaf = nextNextLeaf; + } + } + else + { + this.nextNextLeaf = new GMSSLeaf[0]; + } + + // construct the upperLeaf array for upcoming leafs in tree over the + // actual + if (upperLeaf == null) + { + this.upperLeaf = new GMSSLeaf[numLayer - 1]; + for (int i = 0; i < numLayer - 1; i++) + { + this.upperLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i], + numLeafs[i + 1], this.currentSeeds[i]); + } + } + else + { + this.upperLeaf = upperLeaf; + } + + // construct the leafs for upcoming leafs in treehashs in tree over the + // actual + if (upperTreehashLeaf == null) + { + this.upperTreehashLeaf = new GMSSLeaf[numLayer - 1]; + for (int i = 0; i < numLayer - 1; i++) + { + this.upperTreehashLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i], numLeafs[i + 1]); + } + } + else + { + this.upperTreehashLeaf = upperTreehashLeaf; + } + + if (minTreehash == null) + { + this.minTreehash = new int[numLayer - 1]; + for (int i = 0; i < numLayer - 1; i++) + { + this.minTreehash[i] = -1; + } + } + else + { + this.minTreehash = minTreehash; + } + + // construct the nextRootSig (RootSig++) + byte[] dummy = new byte[mdLength]; + byte[] OTSseed = new byte[mdLength]; + if (nextRootSig == null) + { + this.nextRootSig = new GMSSRootSig[numLayer - 1]; + for (int i = 0; i < numLayer - 1; i++) + { + System.arraycopy(currentSeeds[i], 0, dummy, 0, mdLength); + gmssRandom.nextSeed(dummy); + OTSseed = gmssRandom.nextSeed(dummy); + this.nextRootSig[i] = new GMSSRootSig(digestProvider.get(), otsIndex[i], + heightOfTrees[i + 1]); + this.nextRootSig[i].initSign(OTSseed, nextRoot[i]); + } + } + else + { + this.nextRootSig = nextRootSig; + } + } + + // we assume this only gets called from nextKey so used is never copied. + private GMSSPrivateKeyParameters(GMSSPrivateKeyParameters original) + { + super(true, original.getParameters()); + + this.index = Arrays.clone(original.index); + this.currentSeeds = Arrays.clone(original.currentSeeds); + this.nextNextSeeds = Arrays.clone(original.nextNextSeeds); + this.currentAuthPaths = Arrays.clone(original.currentAuthPaths); + this.nextAuthPaths = Arrays.clone(original.nextAuthPaths); + this.currentTreehash = original.currentTreehash; + this.nextTreehash = original.nextTreehash; + this.currentStack = original.currentStack; + this.nextStack = original.nextStack; + this.currentRetain = original.currentRetain; + this.nextRetain = original.nextRetain; + this.keep = Arrays.clone(original.keep); + this.nextNextLeaf = original.nextNextLeaf; + this.upperLeaf = original.upperLeaf; + this.upperTreehashLeaf = original.upperTreehashLeaf; + this.minTreehash = original.minTreehash; + this.gmssPS = original.gmssPS; + this.nextRoot = Arrays.clone(original.nextRoot); + this.nextNextRoot = original.nextNextRoot; + this.currentRootSig = original.currentRootSig; + this.nextRootSig = original.nextRootSig; + this.digestProvider = original.digestProvider; + this.heightOfTrees = original.heightOfTrees; + this.otsIndex = original.otsIndex; + this.K = original.K; + this.numLayer = original.numLayer; + this.messDigestTrees = original.messDigestTrees; + this.mdLength = original.mdLength; + this.gmssRandom = original.gmssRandom; + this.numLeafs = original.numLeafs; + } + + public boolean isUsed() + { + return this.used; + } + + public void markUsed() + { + this.used = true; + } + + public GMSSPrivateKeyParameters nextKey() + { + GMSSPrivateKeyParameters nKey = new GMSSPrivateKeyParameters(this); + + nKey.nextKey(gmssPS.getNumOfLayers() - 1); + + return nKey; + } + + /** + * This method updates the GMSS private key for the next signature + * + * @param layer the layer where the next key is processed + */ + private void nextKey(int layer) + { + // only for lowest layer ( other layers indices are raised in nextTree() + // method ) + if (layer == numLayer - 1) + { + index[layer]++; + } // else System.out.println(" --- nextKey on layer " + layer + " + // index is now : " + index[layer]); + + // if tree of this layer is depleted + if (index[layer] == numLeafs[layer]) + { + if (numLayer != 1) + { + nextTree(layer); + index[layer] = 0; + } + } + else + { + updateKey(layer); + } + } + + /** + * Switch to next subtree if the current one is depleted + * + * @param layer the layer where the next tree is processed + */ + private void nextTree(int layer) + { + // System.out.println("NextTree method called on layer " + layer); + // dont create next tree for the top layer + if (layer > 0) + { + // raise index for upper layer + index[layer - 1]++; + + // test if it is already the last tree + boolean lastTree = true; + int z = layer; + do + { + z--; + if (index[z] < numLeafs[z]) + { + lastTree = false; + } + } + while (lastTree && (z > 0)); + + // only construct next subtree if last one is not already in use + if (!lastTree) + { + gmssRandom.nextSeed(currentSeeds[layer]); + + // last step of distributed signature calculation + nextRootSig[layer - 1].updateSign(); + + // last step of distributed leaf calculation for nextNextLeaf + if (layer > 1) + { + nextNextLeaf[layer - 1 - 1] = nextNextLeaf[layer - 1 - 1].nextLeaf(); + } + + // last step of distributed leaf calculation for upper leaf + upperLeaf[layer - 1] = upperLeaf[layer - 1].nextLeaf(); + + // last step of distributed leaf calculation for all treehashs + + if (minTreehash[layer - 1] >= 0) + { + upperTreehashLeaf[layer - 1] = upperTreehashLeaf[layer - 1].nextLeaf(); + byte[] leaf = this.upperTreehashLeaf[layer - 1].getLeaf(); + // if update is required use the precomputed leaf to update + // treehash + try + { + currentTreehash[layer - 1][minTreehash[layer - 1]] + .update(this.gmssRandom, leaf); + // System.out.println("UUUpdated TH " + + // minTreehash[layer - 1]); + if (currentTreehash[layer - 1][minTreehash[layer - 1]] + .wasFinished()) + { + // System.out.println("FFFinished TH " + + // minTreehash[layer - 1]); + } + } + catch (Exception e) + { + System.out.println(e); + } + } + + // last step of nextNextAuthRoot calculation + this.updateNextNextAuthRoot(layer); + + // ******************************************************** / + + // NOW: advance to next tree on layer 'layer' + + // NextRootSig --> currentRootSigs + this.currentRootSig[layer - 1] = nextRootSig[layer - 1] + .getSig(); + + // ----------------------- + + // nextTreehash --> currentTreehash + // nextNextTreehash --> nextTreehash + for (int i = 0; i < heightOfTrees[layer] - K[layer]; i++) + { + this.currentTreehash[layer][i] = this.nextTreehash[layer - 1][i]; + this.nextTreehash[layer - 1][i] = this.nextNextRoot[layer - 1] + .getTreehash()[i]; + } + + // NextAuthPath --> currentAuthPath + // nextNextAuthPath --> nextAuthPath + for (int i = 0; i < heightOfTrees[layer]; i++) + { + System.arraycopy(nextAuthPaths[layer - 1][i], 0, + currentAuthPaths[layer][i], 0, mdLength); + System.arraycopy(nextNextRoot[layer - 1].getAuthPath()[i], + 0, nextAuthPaths[layer - 1][i], 0, mdLength); + } + + // nextRetain --> currentRetain + // nextNextRetain --> nextRetain + for (int i = 0; i < K[layer] - 1; i++) + { + this.currentRetain[layer][i] = this.nextRetain[layer - 1][i]; + this.nextRetain[layer - 1][i] = this.nextNextRoot[layer - 1] + .getRetain()[i]; + } + + // nextStack --> currentStack + this.currentStack[layer] = this.nextStack[layer - 1]; + // nextNextStack --> nextStack + this.nextStack[layer - 1] = this.nextNextRoot[layer - 1] + .getStack(); + + // nextNextRoot --> nextRoot + this.nextRoot[layer - 1] = this.nextNextRoot[layer - 1] + .getRoot(); + // ----------------------- + + // ----------------- + byte[] OTSseed = new byte[mdLength]; + byte[] dummy = new byte[mdLength]; + // gmssRandom.setSeed(currentSeeds[layer]); + System + .arraycopy(currentSeeds[layer - 1], 0, dummy, 0, + mdLength); + OTSseed = gmssRandom.nextSeed(dummy); // only need OTSSeed + OTSseed = gmssRandom.nextSeed(dummy); + OTSseed = gmssRandom.nextSeed(dummy); + // nextWinSig[layer-1]=new + // GMSSWinSig(OTSseed,algNames,otsIndex[layer-1],heightOfTrees[layer],nextRoot[layer-1]); + nextRootSig[layer - 1].initSign(OTSseed, nextRoot[layer - 1]); + + // nextKey for upper layer + nextKey(layer - 1); + } + } + } + + /** + * This method computes the authpath (AUTH) for the current tree, + * Additionally the root signature for the next tree (SIG+), the authpath + * (AUTH++) and root (ROOT++) for the tree after next in layer + * <code>layer</code>, and the LEAF++^1 for the next next tree in the + * layer above are updated This method is used by nextKey() + * + * @param layer + */ + private void updateKey(int layer) + { + // ----------current tree processing of actual layer--------- + // compute upcoming authpath for current Tree (AUTH) + computeAuthPaths(layer); + + // -----------distributed calculations part------------ + // not for highest tree layer + if (layer > 0) + { + + // compute (partial) next leaf on TREE++ (not on layer 1 and 0) + if (layer > 1) + { + nextNextLeaf[layer - 1 - 1] = nextNextLeaf[layer - 1 - 1].nextLeaf(); + } + + // compute (partial) next leaf on tree above (not on layer 0) + upperLeaf[layer - 1] = upperLeaf[layer - 1].nextLeaf(); + + // compute (partial) next leaf for all treehashs on tree above (not + // on layer 0) + + int t = (int)Math + .floor((double)(this.getNumLeafs(layer) * 2) + / (double)(this.heightOfTrees[layer - 1] - this.K[layer - 1])); + + if (index[layer] % t == 1) + { + // System.out.println(" layer: " + layer + " index: " + + // index[layer] + " t : " + t); + + // take precomputed node for treehash update + // ------------------------------------------------ + if (index[layer] > 1 && minTreehash[layer - 1] >= 0) + { + byte[] leaf = this.upperTreehashLeaf[layer - 1].getLeaf(); + // if update is required use the precomputed leaf to update + // treehash + try + { + currentTreehash[layer - 1][minTreehash[layer - 1]] + .update(this.gmssRandom, leaf); + // System.out.println("Updated TH " + minTreehash[layer + // - 1]); + if (currentTreehash[layer - 1][minTreehash[layer - 1]] + .wasFinished()) + { + // System.out.println("Finished TH " + + // minTreehash[layer - 1]); + } + } + catch (Exception e) + { + System.out.println(e); + } + // ------------------------------------------------ + } + + // initialize next leaf precomputation + // ------------------------------------------------ + + // get lowest index of treehashs + this.minTreehash[layer - 1] = getMinTreehashIndex(layer - 1); + + if (this.minTreehash[layer - 1] >= 0) + { + // initialize leaf + byte[] seed = this.currentTreehash[layer - 1][this.minTreehash[layer - 1]] + .getSeedActive(); + this.upperTreehashLeaf[layer - 1] = new GMSSLeaf( + this.digestProvider.get(), this.otsIndex[layer - 1], t, seed); + this.upperTreehashLeaf[layer - 1] = this.upperTreehashLeaf[layer - 1].nextLeaf(); + // System.out.println("restarted treehashleaf (" + (layer - + // 1) + "," + this.minTreehash[layer - 1] + ")"); + } + // ------------------------------------------------ + + } + else + { + // update the upper leaf for the treehash one step + if (this.minTreehash[layer - 1] >= 0) + { + this.upperTreehashLeaf[layer - 1] = this.upperTreehashLeaf[layer - 1].nextLeaf(); + // if (minTreehash[layer - 1] > 3) + // System.out.print("#"); + } + } + + // compute (partial) the signature of ROOT+ (RootSig+) (not on top + // layer) + nextRootSig[layer - 1].updateSign(); + + // compute (partial) AUTHPATH++ & ROOT++ (not on top layer) + if (index[layer] == 1) + { + // init root and authpath calculation for tree after next + // (AUTH++, ROOT++) + this.nextNextRoot[layer - 1].initialize(new Vector()); + } + + // update root and authpath calculation for tree after next (AUTH++, + // ROOT++) + this.updateNextNextAuthRoot(layer); + } + // ----------- end distributed calculations part----------------- + } + + /** + * This method returns the index of the next Treehash instance that should + * receive an update + * + * @param layer the layer of the GMSS tree + * @return index of the treehash instance that should get the update + */ + private int getMinTreehashIndex(int layer) + { + int minTreehash = -1; + for (int h = 0; h < heightOfTrees[layer] - K[layer]; h++) + { + if (currentTreehash[layer][h].wasInitialized() + && !currentTreehash[layer][h].wasFinished()) + { + if (minTreehash == -1) + { + minTreehash = h; + } + else if (currentTreehash[layer][h].getLowestNodeHeight() < currentTreehash[layer][minTreehash] + .getLowestNodeHeight()) + { + minTreehash = h; + } + } + } + return minTreehash; + } + + /** + * Computes the upcoming currentAuthpath of layer <code>layer</code> using + * the revisited authentication path computation of Dahmen/Schneider 2008 + * + * @param layer the actual layer + */ + private void computeAuthPaths(int layer) + { + + int Phi = index[layer]; + int H = heightOfTrees[layer]; + int K = this.K[layer]; + + // update all nextSeeds for seed scheduling + for (int i = 0; i < H - K; i++) + { + currentTreehash[layer][i].updateNextSeed(gmssRandom); + } + + // STEP 1 of Algorithm + int Tau = heightOfPhi(Phi); + + byte[] OTSseed = new byte[mdLength]; + OTSseed = gmssRandom.nextSeed(currentSeeds[layer]); + + // STEP 2 of Algorithm + // if phi's parent on height tau + 1 if left node, store auth_tau + // in keep_tau. + // TODO check it, formerly was + // int L = Phi / (int) Math.floor(Math.pow(2, Tau + 1)); + // L %= 2; + int L = (Phi >>> (Tau + 1)) & 1; + + byte[] tempKeep = new byte[mdLength]; + // store the keep node not in keep[layer][tau/2] because it might be in + // use + // wait until the space is freed in step 4a + if (Tau < H - 1 && L == 0) + { + System.arraycopy(currentAuthPaths[layer][Tau], 0, tempKeep, 0, + mdLength); + } + + byte[] help = new byte[mdLength]; + // STEP 3 of Algorithm + // if phi is left child, compute and store leaf for next currentAuthPath + // path, + // (obtained by veriying current signature) + if (Tau == 0) + { + // 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) + { + System.out.println(e); + } + } + } + } + else + { // on higher layers the updates are done later + this.minTreehash[layer] = getMinTreehashIndex(layer); + } + } + + /** + * Returns the largest h such that 2^h | Phi + * + * @param Phi the leaf index + * @return The largest <code>h</code> with <code>2^h | Phi</code> if + * <code>Phi!=0</code> else return <code>-1</code> + */ + private int heightOfPhi(int Phi) + { + if (Phi == 0) + { + return -1; + } + int Tau = 0; + int modul = 1; + while (Phi % modul == 0) + { + modul *= 2; + Tau += 1; + } + return Tau - 1; + } + + /** + * Updates the authentication path and root calculation for the tree after + * next (AUTH++, ROOT++) in layer <code>layer</code> + * + * @param layer + */ + private void updateNextNextAuthRoot(int layer) + { + + byte[] OTSseed = new byte[mdLength]; + OTSseed = gmssRandom.nextSeed(nextNextSeeds[layer - 1]); + + // get the necessary leaf + if (layer == numLayer - 1) + { // lowest layer computes the necessary + // leaf completely at this time + WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed, + digestProvider.get(), otsIndex[layer]); + this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1], ots + .getPublicKey()); + } + else + { // other layers use the precomputed leafs in nextNextLeaf + this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1], nextNextLeaf[layer - 1].getLeaf()); + this.nextNextLeaf[layer - 1].initLeafCalc(nextNextSeeds[layer - 1]); + } + } + + public int[] getIndex() + { + return index; + } + + /** + * @return The current index of layer i + */ + public int getIndex(int i) + { + return index[i]; + } + + public byte[][] getCurrentSeeds() + { + return Arrays.clone(currentSeeds); + } + + public byte[][][] getCurrentAuthPaths() + { + return Arrays.clone(currentAuthPaths); + } + + /** + * @return The one-time signature of the root of the current subtree + */ + public byte[] getSubtreeRootSig(int i) + { + return currentRootSig[i]; + } + + + public GMSSDigestProvider getName() + { + return digestProvider; + } + + /** + * @return The number of leafs of each tree of layer i + */ + public int getNumLeafs(int i) + { + return numLeafs[i]; + } +} |