/// <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> /// This function verifies the signature of the message that has been updated, with the aid of the public key /// </summary> /// /// <param name="Message">The message</param> /// <param name="Signature">The signature of the message</param> /// /// <returns>Returns true if the signature has been verified, false otherwise</returns> private bool VerifySignature(byte[] Message, byte[] Signature) { bool success = false; // int halfSigLength = signature.length >>> 1; _msgDigestOTS.Reset(); WinternitzOTSVerify otsVerify; int otsSigLength; byte[] help = Message; byte[] otsSig; byte[] otsPublicKey; byte[][] authPath; byte[] dest; int nextEntry = 0; int index; // begin with message = 'message that was signed' and then in each step message = subtree root for (int j = _numLayer - 1; j >= 0; j--) { otsVerify = new WinternitzOTSVerify(GetDigest(_gmssPS.DigestEngine), _gmssPS.WinternitzParameter[j]); otsSigLength = otsVerify.GetSignatureLength(); Message = help; // get the subtree index index = GMSSUtil.BytesToIntLittleEndian(Signature, nextEntry); // 4 is the number of bytes in integer nextEntry += 4; // get one-time signature otsSig = new byte[otsSigLength]; Array.Copy(Signature, nextEntry, otsSig, 0, otsSigLength); nextEntry += otsSigLength; // compute public OTS key from the one-time signature otsPublicKey = otsVerify.Verify(Message, otsSig); // test if OTSsignature is correct if (otsPublicKey == null) return false; // get authentication path from the signature authPath = ArrayUtils.CreateJagged<byte[][]>(_gmssPS.HeightOfTrees[j], _mdLength);//new byte[gmssPS.GetHeightOfTrees()[j]][mdLength]; for (int i = 0; i < authPath.Length; i++) { Array.Copy(Signature, nextEntry, authPath[i], 0, _mdLength); nextEntry = nextEntry + _mdLength; } // compute the root of the subtree from the authentication path help = new byte[_mdLength]; help = otsPublicKey; int count = 1 << authPath.Length; count = count + index; for (int i = 0; i < authPath.Length; i++) { dest = new byte[_mdLength << 1]; if ((count % 2) == 0) { Array.Copy(help, 0, dest, 0, _mdLength); Array.Copy(authPath[i], 0, dest, _mdLength, _mdLength); count = count / 2; } else { Array.Copy(authPath[i], 0, dest, 0, _mdLength); Array.Copy(help, 0, dest, _mdLength, help.Length); count = (count - 1) / 2; } _msgDigestTrees.BlockUpdate(dest, 0, dest.Length); help = new byte[_msgDigestTrees.DigestSize]; _msgDigestTrees.DoFinal(help, 0); } } // now help contains the root of the maintree // test if help is equal to the GMSS public key if (Compare.IsEqual(_pubKeyBytes, help)) success = true; return success; }