/// <summary> /// Calculates the authpath and root for tree in layer h which starts with seed[h] /// </summary> /// /// <param name="NextStack">Stack used for the treehash instance created by this method</param> /// <param name="Seed">Starting seeds</param> /// <param name="H">Actual layer</param> /// /// <returns>An initialized GMSSRootCalc</returns> private GMSSRootCalc GenerateNextAuthpathAndRoot(List<byte[]> NextStack, byte[] Seed, int H) { byte[] OTSseed = new byte[_numLayer]; WinternitzOTSignature ots; // data structure that constructs the whole tree and stores the initial values for treehash, Auth and retain GMSSRootCalc treeToConstruct = new GMSSRootCalc(_heightOfTrees[H], _K[H], GetDigest(_msgDigestType)); treeToConstruct.Initialize(NextStack); int seedForTreehashIndex = 3; int count = 0; // update the tree 2^(H) times, from the first to the last leaf for (int i = 0; i < (1 << _heightOfTrees[H]); i++) { // initialize the seeds for the leaf generation with index 3 * 2^h if (i == seedForTreehashIndex && count < _heightOfTrees[H] - _K[H]) { treeToConstruct.InitializeTreehashSeed(Seed, count); seedForTreehashIndex *= 2; count++; } OTSseed = _gmssRand.NextSeed(Seed); ots = new WinternitzOTSignature(OTSseed, GetDigest(_msgDigestType), _otsIndex[H]); treeToConstruct.Update(ots.GetPublicKey()); } if (treeToConstruct.IsFinished()) return treeToConstruct; return null; }
/// <summary> /// Calculates the authpath for tree in layer h which starts with seed[h] additionally computes the rootSignature of underlaying root /// </summary> /// /// <param name="LowerRoot">Stores the root of the lower tree</param> /// <param name="CurrentStack">Stack used for the treehash instance created by this method</param> /// <param name="Seed">Starting seeds</param> /// <param name="H">Actual layer</param> /// <returns>An initialized GMSSRootCalc</returns> private GMSSRootCalc GenerateCurrentAuthpathAndRoot(byte[] LowerRoot, List<byte[]> CurrentStack, byte[] Seed, int H) { byte[] help = new byte[_mdLength]; byte[] OTSseed = new byte[_mdLength]; OTSseed = _gmssRand.NextSeed(Seed); WinternitzOTSignature ots; // data structure that constructs the whole tree and stores the initial values for treehash, Auth and retain GMSSRootCalc treeToConstruct = new GMSSRootCalc(_heightOfTrees[H], _K[H], GetDigest(_msgDigestType)); treeToConstruct.Initialize(CurrentStack); // generate the first leaf if (H == _numLayer - 1) { ots = new WinternitzOTSignature(OTSseed, GetDigest(_msgDigestType), _otsIndex[H]); help = ots.GetPublicKey(); } else { // for all layers except the lowest, generate the signature of the underlying root // and reuse this signature to compute the first leaf of acual layer more efficiently (by verifiing the signature) ots = new WinternitzOTSignature(OTSseed, GetDigest(_msgDigestType), _otsIndex[H]); _currentRootSigs[H] = ots.GetSignature(LowerRoot); WinternitzOTSVerify otsver = new WinternitzOTSVerify(GetDigest(_msgDigestType), _otsIndex[H]); help = otsver.Verify(LowerRoot, _currentRootSigs[H]); } // update the tree with the first leaf treeToConstruct.Update(help); int seedForTreehashIndex = 3; int count = 0; // update the tree 2^(H) - 1 times, from the second to the last leaf for (int i = 1; i < (1 << _heightOfTrees[H]); i++) { // initialize the seeds for the leaf generation with index 3 * 2^h if (i == seedForTreehashIndex && count < _heightOfTrees[H] - _K[H]) { treeToConstruct.InitializeTreehashSeed(Seed, count); seedForTreehashIndex *= 2; count++; } OTSseed = _gmssRand.NextSeed(Seed); ots = new WinternitzOTSignature(OTSseed, GetDigest(_msgDigestType), _otsIndex[H]); treeToConstruct.Update(ots.GetPublicKey()); } if (treeToConstruct.IsFinished()) return treeToConstruct; return null; }
/// <summary> /// Updates the authentication path and root calculation for the tree after next (AUTH++, ROOT++) in layer <c>layer</c> /// </summary> /// /// <param name="Layer">The layer</param> 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, GetDigest(_msgDigestType), _otsIndex[Layer]); _nextNextRoot[Layer - 1].Update(_nextNextSeeds[Layer - 1], ots.GetPublicKey()); } else { // other layers use the precomputed leafs in nextNextLeaf _nextNextRoot[Layer - 1].Update(_nextNextSeeds[Layer - 1], _nextNextLeaf[Layer - 1].GetLeaf()); _nextNextLeaf[Layer - 1].InitLeafCalc(_nextNextSeeds[Layer - 1]); } }
/// <summary> /// Initializes the signature algorithm for signing a message /// </summary> private void InitSign() { _msgDigestTrees.Reset(); // set private key and take from it ots key, auth, tree and key counter, rootSign GMSSPrivateKey gmssPrivateKey = (GMSSPrivateKey)_asmKey; if (gmssPrivateKey.IsUsed) throw new Exception("Private key already used"); // check if last signature has been generated if (gmssPrivateKey.GetCurrentIndex(0) >= gmssPrivateKey.GetNumLeafs(0)) throw new Exception("No more signatures can be generated"); // get numLayer _numLayer = _gmssPS.NumLayers; // get OTS Instance of lowest layer byte[] seed = gmssPrivateKey.CurrentSeeds[_numLayer - 1]; byte[] OTSSeed = new byte[_mdLength]; byte[] dummy = new byte[_mdLength]; Array.Copy(seed, 0, dummy, 0, _mdLength); OTSSeed = _gmssRandom.NextSeed(dummy); _Ots = new WinternitzOTSignature(OTSSeed, GetDigest(_gmssPS.DigestEngine), _gmssPS.WinternitzParameter[_numLayer - 1]); byte[][][] helpCurrentAuthPaths = gmssPrivateKey.CurrentAuthPaths; _currentAuthPaths = new byte[_numLayer][][]; // copy the main tree authentication path for (int j = 0; j < _numLayer; j++) { _currentAuthPaths[j] = ArrayUtils.CreateJagged<byte[][]>(helpCurrentAuthPaths[j].Length, _mdLength); for (int i = 0; i < helpCurrentAuthPaths[j].Length; i++) Array.Copy(helpCurrentAuthPaths[j][i], 0, _currentAuthPaths[j][i], 0, _mdLength); } // copy index _index = new int[_numLayer]; Array.Copy(gmssPrivateKey.Index, 0, _index, 0, _numLayer); // copy subtreeRootSig byte[] helpSubtreeRootSig; _subtreeRootSig = new byte[_numLayer - 1][]; for (int i = 0; i < _numLayer - 1; i++) { helpSubtreeRootSig = gmssPrivateKey.SubtreeRootSig(i); _subtreeRootSig[i] = new byte[helpSubtreeRootSig.Length]; Array.Copy(helpSubtreeRootSig, 0, _subtreeRootSig[i], 0, helpSubtreeRootSig.Length); } if (gmssPrivateKey.GetCurrentIndex(0) >= gmssPrivateKey.GetNumLeafs(0)) gmssPrivateKey.IsUsed = true; }
/// <summary> /// Computes the upcoming currentAuthpath of <c>layer</c> using the revisited authentication path computation of Dahmen/Schneider 2008 /// </summary> /// /// <param name="Layer">The actual layer</param> private void ComputeAuthPaths(int Layer) { int Phi = _index[Layer]; int H = _heightOfTrees[Layer]; int K = _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 int L = (IntUtils.URShift(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) Array.Copy(_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) { // leaf calc if (Layer == _numLayer - 1) { // lowest layer computes the necessary leaf completely at this time WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed, GetDigest(_msgDigestType), _otsIndex[Layer]); help = ots.GetPublicKey(); } else { // other layers use the precomputed leafs in nextNextLeaf byte[] dummy = new byte[_mdLength]; Array.Copy(_currentSeeds[Layer], 0, dummy, 0, _mdLength); _gmssRandom.NextSeed(dummy); help = _upperLeaf[Layer].GetLeaf(); _upperLeaf[Layer].InitLeafCalc(dummy); } Array.Copy(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]; Array.Copy(_currentAuthPaths[Layer][Tau - 1], 0, toBeHashed, 0, _mdLength); // free the shared keep[layer][tau/2] Array.Copy(_keep[Layer][(int)Math.Floor((decimal)(Tau - 1) / 2)], 0, toBeHashed, _mdLength, _mdLength); _msgDigestTrees.BlockUpdate(toBeHashed, 0, toBeHashed.Length); _currentAuthPaths[Layer][Tau] = new byte[_msgDigestTrees.DigestSize]; _msgDigestTrees.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].IsFinished()) { Array.Copy(_currentTreehash[Layer][i].GetFirstNode(), 0, _currentAuthPaths[Layer][i], 0, _mdLength); _currentTreehash[Layer][i].Destroy(); } } // 2nd: copy precomputed values from Retain if (i < H - 1 && i >= H - K) { if (_currentRetain[Layer][i - (H - K)].Count > 0) { // pop element from retain Array.Copy(_currentRetain[Layer][i - (H - K)][_currentRetain[Layer][i - (H - K)].Count - 1], 0, _currentAuthPaths[Layer][i], 0, _mdLength); _currentRetain[Layer][i - (H - K)].RemoveAt(_currentRetain[Layer][i - (H - K)].Count - 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]) _currentTreehash[Layer][i].Initialize(); } } } // now keep space is free to use if (Tau < H - 1 && L == 0) { Array.Copy(tempKeep, 0, _keep[Layer][(int)Math.Floor((decimal)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]; Array.Copy(_currentTreehash[Layer][minTreehash].GetSeedActive(), 0, seed, 0, _mdLength); byte[] seed2 = _gmssRandom.NextSeed(seed); WinternitzOTSignature ots = new WinternitzOTSignature(seed2, GetDigest(_msgDigestType), _otsIndex[Layer]); byte[] leaf = ots.GetPublicKey(); _currentTreehash[Layer][minTreehash].Update(_gmssRandom, leaf); } catch { } } } } else { // on higher layers the updates are done later _minTreehash[Layer] = GetMinTreehashIndex(Layer); } }