/// <summary> /// This function signs the message that has been updated, making use of the private key. /// <para>For computing the signature, L1 and L2 are needed, as well as LES should be solved /// for each layer in order to find the Oil-variables in the layer. /// The Vinegar-variables of the first layer are random generated.</para> /// </summary> /// /// <param name="Message">The message</param> /// /// <returns>The signature of the message</returns> private byte[] GenerateSignature(byte[] Message) { byte[] otsSig = new byte[_mdLength]; byte[] authPathBytes; byte[] indexBytes; otsSig = _Ots.GetSignature(Message); // get concatenated lowest layer tree authentication path authPathBytes = GMSSUtil.ConcatenateArray(_currentAuthPaths[_numLayer - 1]); // put lowest layer index into a byte array indexBytes = GMSSUtil.IntToBytesLittleEndian(_index[_numLayer - 1]); // create first part of GMSS signature byte[] gmssSigFirstPart = new byte[indexBytes.Length + otsSig.Length + authPathBytes.Length]; Array.Copy(indexBytes, 0, gmssSigFirstPart, 0, indexBytes.Length); Array.Copy(otsSig, 0, gmssSigFirstPart, indexBytes.Length, otsSig.Length); Array.Copy(authPathBytes, 0, gmssSigFirstPart, (indexBytes.Length + otsSig.Length), authPathBytes.Length); // create initial array with length 0 for iteration byte[] gmssSigNextPart = new byte[0]; for (int i = _numLayer - 1 - 1; i >= 0; i--) { // get concatenated next tree authentication path authPathBytes = GMSSUtil.ConcatenateArray(_currentAuthPaths[i]); // put next tree index into a byte array indexBytes = GMSSUtil.IntToBytesLittleEndian(_index[i]); // create help array and copy actual gmssSig into it byte[] helpGmssSig = new byte[gmssSigNextPart.Length]; Array.Copy(gmssSigNextPart, 0, helpGmssSig, 0, gmssSigNextPart.Length); // adjust length of gmssSigNextPart for adding next part gmssSigNextPart = new byte[helpGmssSig.Length + indexBytes.Length + _subtreeRootSig[i].Length + authPathBytes.Length]; // copy old data (help array) and new data in gmssSigNextPart Array.Copy(helpGmssSig, 0, gmssSigNextPart, 0, helpGmssSig.Length); Array.Copy(indexBytes, 0, gmssSigNextPart, helpGmssSig.Length, indexBytes.Length); Array.Copy(_subtreeRootSig[i], 0, gmssSigNextPart, (helpGmssSig.Length + indexBytes.Length), _subtreeRootSig[i].Length); Array.Copy(authPathBytes, 0, gmssSigNextPart, (helpGmssSig.Length + indexBytes.Length + _subtreeRootSig[i].Length), authPathBytes.Length); } // concatenate the two parts of the GMSS signature byte[] gmssSig = new byte[gmssSigFirstPart.Length + gmssSigNextPart.Length]; Array.Copy(gmssSigFirstPart, 0, gmssSig, 0, gmssSigFirstPart.Length); Array.Copy(gmssSigNextPart, 0, gmssSig, gmssSigFirstPart.Length, gmssSigNextPart.Length); // return the GMSS signature return(gmssSig); }
/// <summary> /// This constructor regenerates a prior treehash object /// </summary> /// /// <param name="Digest">The hash function</param> /// <param name="StatByte">The status bytes</param> /// <param name="StatInt">The status ints</param> /// <param name="TreeH">The tree hash</param> /// <param name="NodeRet">The retained nodes</param> public GMSSRootCalc(IDigest Digest, byte[][] StatByte, int[] StatInt, Treehash[] TreeH, List <byte[]>[] NodeRet) { _msgDigestTree = Digest; // decode statInt _heightOfTree = StatInt[0]; _mdLength = StatInt[1]; m_K = StatInt[2]; _indexForNextSeed = StatInt[3]; _heightOfNextSeed = StatInt[4]; if (StatInt[5] == 1) { _isFinished = true; } else { _isFinished = false; } if (StatInt[6] == 1) { m_isInitialized = true; } else { m_isInitialized = false; } int tailLength = StatInt[7]; _ndeIndex = new int[_heightOfTree]; for (int i = 0; i < _heightOfTree; i++) { _ndeIndex[i] = StatInt[8 + i]; } _heightOfNodes = new List <int>(); for (int i = 0; i < tailLength; i++) { _heightOfNodes.Add(StatInt[8 + _heightOfTree + i]); } // decode statByte _treeRoot = StatByte[0]; _authPath = ArrayUtils.CreateJagged <byte[][]>(_heightOfTree, _mdLength); for (int i = 0; i < _heightOfTree; i++) { _authPath[i] = StatByte[1 + i]; } _tailStack = new List <byte[]>(); for (int i = 0; i < tailLength; i++) { _tailStack.Add(StatByte[1 + _heightOfTree + i]); } // decode treeH _treehash = GMSSUtil.Clone(TreeH); // decode ret _ndeRetain = GMSSUtil.Clone(NodeRet); }
/// <summary> /// Returns the retain stacks storing all right nodes near to the root /// </summary> /// /// <returns>The retain stacks storing all right nodes near to the root</returns> public List <byte[]>[] GetRetain() { return(GMSSUtil.Clone(_ndeRetain)); }
/// <summary> /// Returns the initial treehash instances, storing value y_3(i) /// </summary> /// /// <returns>The initial treehash instances, storing value y_3(i)</returns> public Treehash[] GetTreehash() { return(GMSSUtil.Clone(_treehash)); }
/// <summary> /// Returns the authentication path of the first leaf of the tree /// </summary> /// /// <returns>The authentication path of the first leaf of the tree</returns> public byte[][] GetAuthPath() { return(GMSSUtil.Clone(_authPath)); }
/// <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); }