/// <summary> /// Initialize the distributed leaf calculation reset i,j and compute OTSseed with seed0 /// </summary> /// /// <param name="Seed">The starting seed</param> public void InitLeafCalc(byte[] Seed) { _ctr1 = 0; _ctr2 = 0; byte[] dummy = new byte[_mdsize]; Array.Copy(Seed, 0, dummy, 0, _seed.Length); _seed = _gmssRandom.NextSeed(dummy); }
/// <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], m_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] - m_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> /// 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)m_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> /// Updates the nextSeed of this treehash instance one step needed for the schedulng of the seeds /// </summary> /// /// <param name="GmssRand">The prng used for the seeds</param> public void UpdateNextSeed(GMSSRandom GmssRand) { GmssRand.NextSeed(_seedNext); }
/// <summary> /// Calculates one update of the treehash instance, i.e. creates a new leaf and hashes if possible /// </summary> /// /// <param name="GmssRand">An instance of the PRNG</param> /// <param name="Leaf">The byte value of the leaf needed for the update</param> public void Update(GMSSRandom GmssRand, byte[] Leaf) { if (_isFinished) { return; } if (!m_isInitialized) { return; } byte[] help = new byte[_msgDigestTree.DigestSize]; int helpHeight = -1; GmssRand.NextSeed(_seedActive); // if treehash gets first update if (_firstNode == null) { _firstNode = Leaf; _firstNodeHeight = 0; } else { // store the new node in help array, do not push it on the stack help = Leaf; helpHeight = 0; // hash the nodes on the stack if possible while (_tailLength > 0 && helpHeight == ((int)_heightOfNodes[_heightOfNodes.Count - 1])) { // put top element of the stack and help node in array 'tobehashed' // and hash them together, put result again in help array byte[] toBeHashed = new byte[_msgDigestTree.DigestSize << 1]; // pop element from stack Array.Copy(_tailStack[_tailStack.Count - 1], 0, toBeHashed, 0, _msgDigestTree.DigestSize); _tailStack.RemoveAt(_tailStack.Count - 1); _heightOfNodes.RemoveAt(_heightOfNodes.Count - 1); Array.Copy(help, 0, toBeHashed, _msgDigestTree.DigestSize, _msgDigestTree.DigestSize); _msgDigestTree.BlockUpdate(toBeHashed, 0, toBeHashed.Length); help = new byte[_msgDigestTree.DigestSize]; _msgDigestTree.DoFinal(help, 0); // increase help height, stack was reduced by one element helpHeight++; _tailLength--; } // push the new node on the stack _tailStack.Add(help); _heightOfNodes.Add(helpHeight); _tailLength++; // finally check whether the top node on stack and the first node in treehash have same height. // If so hash them together and store them in treehash if (((int)_heightOfNodes[_heightOfNodes.Count - 1] == _firstNodeHeight)) { byte[] toBeHashed = new byte[_msgDigestTree.DigestSize << 1]; Array.Copy(_firstNode, 0, toBeHashed, 0, _msgDigestTree.DigestSize); // pop element from tailStack and copy it into help2 array Array.Copy(_tailStack[_tailStack.Count - 1], 0, toBeHashed, _msgDigestTree.DigestSize, _msgDigestTree.DigestSize); _tailStack.RemoveAt(_tailStack.Count - 1); _heightOfNodes.RemoveAt(_heightOfNodes.Count - 1); // store new element in firstNode, stack is then empty _msgDigestTree.BlockUpdate(toBeHashed, 0, toBeHashed.Length); _firstNode = new byte[_msgDigestTree.DigestSize]; _msgDigestTree.DoFinal(_firstNode, 0); _firstNodeHeight++; // empty the stack _tailLength = 0; } } // check if treehash instance is completed if (_firstNodeHeight == _maxHeight) { _isFinished = true; } }
/// <summary> /// Return The one-time signature of the message, generated step by step /// </summary> private void OneStep() { if (8 % _W == 0) { if (_testCtr == 0) { // get current OTSprivateKey _privateKeyOTS = _gmssRand.NextSeed(_otsSeed); if (_iI < _mdSize) { // for main message part _testCtr = _msgHash[_iI] & m_K; _msgHash[_iI] = (byte)(IntUtils.URShift(_msgHash[_iI], _W)); } else { // for checksum part _testCtr = _chkSum & m_K; _chkSum = IntUtils.URShift(_chkSum, _W); } } else if (_testCtr > 0) { // hash the private Key 'test' times (on time each step) _msgDigestOTS.BlockUpdate(_privateKeyOTS, 0, _privateKeyOTS.Length); _privateKeyOTS = new byte[_msgDigestOTS.DigestSize]; _msgDigestOTS.DoFinal(_privateKeyOTS, 0); _testCtr--; } if (_testCtr == 0) { // if all hashes done copy result to siganture array Array.Copy(_privateKeyOTS, 0, _sgnCode, _Counter * _mdSize, _mdSize); _Counter++; // raise array index for main massage part if (_Counter % (8 / _W) == 0) { _iI++; } } } else if (_W < 8) { if (_testCtr == 0) { if (_Counter % 8 == 0 && _iI < _mdSize) { // after every 8th "add to signature"-step _big8 = 0; if (_Counter < ((_mdSize / _W) << 3)) { // main massage (generate w*8 Bits every time) part for (int j = 0; j < _W; j++) { _big8 ^= (_msgHash[_iI] & 0xff) << (j << 3); _iI++; } } else { // rest of massage part (once) for (int j = 0; j < _mdSize % _W; j++) { _big8 ^= (_msgHash[_iI] & 0xff) << (j << 3); _iI++; } } } // checksum part (once) if (_Counter == _msgSize) { _big8 = _chkSum; } _testCtr = (int)(_big8 & m_K); // generate current OTSprivateKey _privateKeyOTS = _gmssRand.NextSeed(_otsSeed); } else if (_testCtr > 0) { // hash the private Key 'test' times (on time each step) _msgDigestOTS.BlockUpdate(_privateKeyOTS, 0, _privateKeyOTS.Length); _privateKeyOTS = new byte[_msgDigestOTS.DigestSize]; _msgDigestOTS.DoFinal(_privateKeyOTS, 0); _testCtr--; } if (_testCtr == 0) { // if all hashes done copy result to siganture array Array.Copy(_privateKeyOTS, 0, _sgnCode, _Counter * _mdSize, _mdSize); _big8 = IntUtils.URShift(_big8, _W); _Counter++; } } else if (_W < 57) { if (_test8 == 0) { int s, f, rest; _big8 = 0; _iI = 0; rest = _R % 8; s = IntUtils.URShift(_R, 3); // message part if (s < _mdSize) { if (_R <= ((_mdSize << 3) - _W)) { // first message part _R += _W; f = IntUtils.URShift((_R + 7), 3); } else { // rest of message part (once) f = _mdSize; _R += _W; } // generate long 'big8' with minimum w next bits of the message array for (int i = s; i < f; i++) { _big8 ^= (_msgHash[i] & 0xff) << (_iI << 3); _iI++; } // delete bits on the right side, which were used already by the last loop _big8 = IntUtils.URShift(_big8, rest); _test8 = (_big8 & m_K); } // checksum part else { _test8 = (_chkSum & m_K); _chkSum = IntUtils.URShift(_chkSum, _W); } // generate current OTSprivateKey _privateKeyOTS = _gmssRand.NextSeed(_otsSeed); } else if (_test8 > 0) { // hash the private Key 'test' times (on time each step) _msgDigestOTS.BlockUpdate(_privateKeyOTS, 0, _privateKeyOTS.Length); _privateKeyOTS = new byte[_msgDigestOTS.DigestSize]; _msgDigestOTS.DoFinal(_privateKeyOTS, 0); _test8--; } if (_test8 == 0) { // if all hashes done copy result to siganture array Array.Copy(_privateKeyOTS, 0, _sgnCode, _Counter * _mdSize, _mdSize); _Counter++; } } }