/// <summary> /// Initializes the calculation of a new root /// </summary> /// /// <param name="SharedStack">The stack shared by all treehash instances of this tree</param> public void Initialize(List <byte[]> SharedStack) { _treehash = new Treehash[_heightOfTree - m_K]; for (int i = 0; i < _heightOfTree - m_K; i++) { _treehash[i] = new Treehash(SharedStack, i, _msgDigestTree); } _ndeIndex = new int[_heightOfTree]; _authPath = ArrayUtils.CreateJagged <byte[][]>(_heightOfTree, _mdLength); _treeRoot = new byte[_mdLength]; _tailStack = new List <byte[]>(); _heightOfNodes = new List <int>(); m_isInitialized = true; _isFinished = false; for (int i = 0; i < _heightOfTree; i++) { _ndeIndex[i] = -1; } _ndeRetain = new List <byte[]> [m_K - 1]; for (int i = 0; i < m_K - 1; i++) { _ndeRetain[i] = new List <byte[]>(); } _indexForNextSeed = 3; _heightOfNextSeed = 0; }
/// <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]; _K = StatInt[2]; _indexForNextSeed = StatInt[3]; _heightOfNextSeed = StatInt[4]; if (StatInt[5] == 1) _isFinished = true; else _isFinished = false; if (StatInt[6] == 1) _isInitialized = true; else _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> /// Generate an encryption Key pair /// </summary> /// /// <returns>A GMSSKeyPair containing public and private keys</returns> public IAsymmetricKeyPair GenerateKeyPair() { // initialize authenticationPaths and treehash instances byte[][][] currentAuthPaths = new byte[_numLayer][][]; byte[][][] nextAuthPaths = new byte[_numLayer - 1][][]; Treehash[][] currentTreehash = new Treehash[_numLayer][]; Treehash[][] nextTreehash = new Treehash[_numLayer - 1][]; List<byte[]>[] currentStack = new List<byte[]>[_numLayer]; List<byte[]>[] nextStack = new List<byte[]>[_numLayer - 1]; List<byte[]>[][] currentRetain = new List<byte[]>[_numLayer][]; List<byte[]>[][] nextRetain = new List<byte[]>[_numLayer - 1][]; for (int i = 0; i < _numLayer; i++) { currentAuthPaths[i] = ArrayUtils.CreateJagged<byte[][]>(_heightOfTrees[i], _mdLength);//new byte[heightOfTrees[i]][mdLength]; currentTreehash[i] = new Treehash[_heightOfTrees[i] - _K[i]]; if (i > 0) { nextAuthPaths[i - 1] = ArrayUtils.CreateJagged<byte[][]>(_heightOfTrees[i], _mdLength);//new byte[heightOfTrees[i]][mdLength]; nextTreehash[i - 1] = new Treehash[_heightOfTrees[i] - _K[i]]; } currentStack[i] = new List<byte[]>(); if (i > 0) nextStack[i - 1] = new List<byte[]>(); } // initialize roots byte[][] currentRoots = ArrayUtils.CreateJagged<byte[][]>(_numLayer, _mdLength); byte[][] nextRoots = ArrayUtils.CreateJagged<byte[][]>(_numLayer - 1, _mdLength); // initialize seeds byte[][] seeds = ArrayUtils.CreateJagged<byte[][]>(_numLayer, _mdLength); // initialize seeds[] by copying starting-seeds of first trees of each layer for (int i = 0; i < _numLayer; i++) Array.Copy(_currentSeeds[i], 0, seeds[i], 0, _mdLength); // initialize rootSigs _currentRootSigs = ArrayUtils.CreateJagged<byte[][]>(_numLayer - 1, _mdLength);//new byte[numLayer - 1][mdLength]; // calculation of current authpaths and current rootsigs (AUTHPATHS, SIG) from bottom up to the root for (int h = _numLayer - 1; h >= 0; h--) { GMSSRootCalc tree = new GMSSRootCalc(_heightOfTrees[h], _K[h], GetDigest(_msgDigestType)); try { // on lowest layer no lower root is available, so just call the method with null as first parameter if (h == _numLayer - 1) tree = GenerateCurrentAuthpathAndRoot(null, currentStack[h], seeds[h], h); else // otherwise call the method with the former computed root value tree = GenerateCurrentAuthpathAndRoot(currentRoots[h + 1], currentStack[h], seeds[h], h); } catch { } // set initial values needed for the private key construction for (int i = 0; i < _heightOfTrees[h]; i++) Array.Copy(tree.GetAuthPath()[i], 0, currentAuthPaths[h][i], 0, _mdLength); currentRetain[h] = tree.GetRetain(); currentTreehash[h] = tree.GetTreehash(); Array.Copy(tree.GetRoot(), 0, currentRoots[h], 0, _mdLength); } // calculation of next authpaths and next roots (AUTHPATHS+, ROOTS+) for (int h = _numLayer - 2; h >= 0; h--) { GMSSRootCalc tree = GenerateNextAuthpathAndRoot(nextStack[h], seeds[h + 1], h + 1); // set initial values needed for the private key construction for (int i = 0; i < _heightOfTrees[h + 1]; i++) Array.Copy(tree.GetAuthPath()[i], 0, nextAuthPaths[h][i], 0, _mdLength); nextRetain[h] = tree.GetRetain(); nextTreehash[h] = tree.GetTreehash(); Array.Copy(tree.GetRoot(), 0, nextRoots[h], 0, _mdLength); // create seed for the Merkle tree after next (nextNextSeeds) SEEDs++ Array.Copy(seeds[h + 1], 0, _nextNextSeeds[h], 0, _mdLength); } // generate JDKGMSSPublicKey int[] len = new int[] { currentRoots[0].Length }; byte[] btlen = new byte[4]; Buffer.BlockCopy(len, 0, btlen, 0, btlen.Length); GMSSPublicKey pubKey = new GMSSPublicKey(ArrayUtils.Concat(btlen, currentRoots[0])); // generate the JDKGMSSPrivateKey GMSSPrivateKey privKey = new GMSSPrivateKey(_currentSeeds, _nextNextSeeds, currentAuthPaths, nextAuthPaths, currentTreehash, nextTreehash, currentStack, nextStack, currentRetain, nextRetain, nextRoots, _currentRootSigs, _gmssParams, _msgDigestType); // return the KeyPair return new GMSSKeyPair(pubKey, privKey); }
/// <summary> /// Initializes the calculation of a new root /// </summary> /// /// <param name="SharedStack">The stack shared by all treehash instances of this tree</param> public void Initialize(List<byte[]> SharedStack) { _treehash = new Treehash[_heightOfTree - _K]; for (int i = 0; i < _heightOfTree - _K; i++) _treehash[i] = new Treehash(SharedStack, i, _msgDigestTree); _ndeIndex = new int[_heightOfTree]; _authPath = ArrayUtils.CreateJagged<byte[][]>(_heightOfTree, _mdLength); _treeRoot = new byte[_mdLength]; _tailStack = new List<byte[]>(); _heightOfNodes = new List<int>(); _isInitialized = true; _isFinished = false; for (int i = 0; i < _heightOfTree; i++) _ndeIndex[i] = -1; _ndeRetain = new List<byte[]>[_K - 1]; for (int i = 0; i < _K - 1; i++) _ndeRetain[i] = new List<byte[]>(); _indexForNextSeed = 3; _heightOfNextSeed = 0; }
/// <summary> /// /// </summary> /// /// <param name="Index">The tree indices</param> /// <param name="CurrentSeeds">A seed for the generation of private OTS keys for the current subtrees</param> /// <param name="NextNextSeeds">A seed for the generation of private OTS keys for the next subtrees</param> /// <param name="CurrentAuthPaths">Array of current authentication paths</param> /// <param name="NextAuthPaths">Array of next authentication paths</param> /// <param name="Keep">Keep array for the authPath algorithm</param> /// <param name="CurrentTreehash">Treehash for authPath algorithm of current tree</param> /// <param name="NextTreehash">Treehash for authPath algorithm of next tree (TREE+)</param> /// <param name="CurrentStack">Shared stack for authPath algorithm of current tree</param> /// <param name="NextStack">Shared stack for authPath algorithm of next tree (TREE+)</param> /// <param name="CurrentRetain">Retain stack for authPath algorithm of current tree</param> /// <param name="NextRetain">Retain stack for authPath algorithm of next tree (TREE+)</param> /// <param name="NextNextLeaf">Array of upcoming leafs of the tree after next (LEAF++) of each layer</param> /// <param name="UpperLeaf">Needed for precomputation of upper nodes</param> /// <param name="UpperTreehashLeaf">Needed for precomputation of upper treehash nodes</param> /// <param name="MinTreehash">Index of next treehash instance to receive an update</param> /// <param name="NextRoot">The roots of the next trees (ROOT+)</param> /// <param name="NextNextRoot">The roots of the tree after next (ROOT++)</param> /// <param name="CurrentRootSig">Array of signatures of the roots of the current subtrees (SIG)</param> /// <param name="NextRootSig">Array of signatures of the roots of the next subtree (SIG+)</param> /// <param name="ParameterSet">The GMSS Parameterset</param> /// <param name="Digest">The digest type</param> internal GMSSPrivateKey(int[] Index, byte[][] CurrentSeeds, byte[][] NextNextSeeds, byte[][][] CurrentAuthPaths, byte[][][] NextAuthPaths, byte[][][] Keep, Treehash[][] CurrentTreehash, Treehash[][] NextTreehash, List<byte[]>[] CurrentStack, List<byte[]>[] NextStack, List<byte[]>[][] CurrentRetain, List<byte[]>[][] NextRetain, GMSSLeaf[] NextNextLeaf, GMSSLeaf[] UpperLeaf, GMSSLeaf[] UpperTreehashLeaf, int[] MinTreehash, byte[][] NextRoot, GMSSRootCalc[] NextNextRoot, byte[][] CurrentRootSig, GMSSRootSig[] NextRootSig, GMSSParameters ParameterSet, Digests Digest) { _msgDigestType = Digest; // construct message digest _msgDigestTrees = GetDigest(Digest); _mdLength = _msgDigestTrees.DigestSize; // Parameter _gmssPS = ParameterSet; _otsIndex = ParameterSet.WinternitzParameter; _K = ParameterSet.K; _heightOfTrees = ParameterSet.HeightOfTrees; // initialize numLayer _numLayer = _gmssPS.NumLayers; // initialize index if null if (Index == null) { _index = new int[_numLayer]; for (int i = 0; i < _numLayer; i++) _index[i] = 0; } else { _index = Index; } _currentSeeds = CurrentSeeds; _nextNextSeeds = NextNextSeeds; _currentAuthPaths = CurrentAuthPaths; _nextAuthPaths = NextAuthPaths; // initialize keep if null if (Keep == null) { _keep = new byte[_numLayer][][]; for (int i = 0; i < _numLayer; i++) _keep[i] = ArrayUtils.CreateJagged<byte[][]>((int)Math.Floor((decimal)_heightOfTrees[i] / 2), _mdLength); } else { _keep = Keep; } // initialize stack if null if (CurrentStack == null) { _currentStack = new List<byte[]>[_numLayer]; for (int i = 0; i < _numLayer; i++) _currentStack[i] = new List<byte[]>(); } else { _currentStack = CurrentStack; } // initialize nextStack if null if (NextStack == null) { _nextStack = new List<byte[]>[_numLayer - 1]; for (int i = 0; i < _numLayer - 1; i++) _nextStack[i] = new List<byte[]>(); } else { _nextStack = NextStack; } _currentTreehash = CurrentTreehash; _nextTreehash = NextTreehash; _currentRetain = CurrentRetain; _nextRetain = NextRetain; _nextRoot = NextRoot; if (NextNextRoot == null) { NextNextRoot = new GMSSRootCalc[_numLayer - 1]; for (int i = 0; i < _numLayer - 1; i++) NextNextRoot[i] = new GMSSRootCalc(_heightOfTrees[i + 1], _K[i + 1], GetDigest(Digest)); } else { _nextNextRoot = NextNextRoot; } _currentRootSig = CurrentRootSig; // calculate numLeafs _numLeafs = new int[_numLayer]; for (int i = 0; i < _numLayer; i++) _numLeafs[i] = 1 << _heightOfTrees[i]; // construct PRNG _gmssRandom = new GMSSRandom(_msgDigestTrees); if (_numLayer > 1) { // construct the nextNextLeaf (LEAFs++) array for upcoming leafs in // tree after next (TREE++) if (NextNextLeaf == null) { _nextNextLeaf = new GMSSLeaf[_numLayer - 2]; for (int i = 0; i < _numLayer - 2; i++) _nextNextLeaf[i] = new GMSSLeaf(GetDigest(Digest), _otsIndex[i + 1], _numLeafs[i + 2], _nextNextSeeds[i]); } else { _nextNextLeaf = NextNextLeaf; } } else { _nextNextLeaf = new GMSSLeaf[0]; } // construct the upperLeaf array for upcoming leafs in tree over the // actual if (UpperLeaf == null) { _upperLeaf = new GMSSLeaf[_numLayer - 1]; for (int i = 0; i < _numLayer - 1; i++) _upperLeaf[i] = new GMSSLeaf(GetDigest(Digest), _otsIndex[i], _numLeafs[i + 1], _currentSeeds[i]); } else { _upperLeaf = UpperLeaf; } // construct the leafs for upcoming leafs in treehashs in tree over the actual if (UpperTreehashLeaf == null) { _upperTreehashLeaf = new GMSSLeaf[_numLayer - 1]; for (int i = 0; i < _numLayer - 1; i++) _upperTreehashLeaf[i] = new GMSSLeaf(GetDigest(Digest), _otsIndex[i], _numLeafs[i + 1]); } else { _upperTreehashLeaf = UpperTreehashLeaf; } if (MinTreehash == null) { _minTreehash = new int[_numLayer - 1]; for (int i = 0; i < _numLayer - 1; i++) _minTreehash[i] = -1; } else { _minTreehash = MinTreehash; } // construct the nextRootSig (RootSig++) byte[] dummy = new byte[_mdLength]; byte[] OTSseed = new byte[_mdLength]; if (NextRootSig == null) { _nextRootSig = new GMSSRootSig[_numLayer - 1]; for (int i = 0; i < _numLayer - 1; i++) { Array.Copy(CurrentSeeds[i], 0, dummy, 0, _mdLength); _gmssRandom.NextSeed(dummy); OTSseed = _gmssRandom.NextSeed(dummy); _nextRootSig[i] = new GMSSRootSig(GetDigest(Digest), _otsIndex[i], _heightOfTrees[i + 1]); _nextRootSig[i].InitSign(OTSseed, NextRoot[i]); } } else { _nextRootSig = NextRootSig; } }
/// <summary> /// Generates a new GMSS private key /// </summary> /// /// <param name="CurrentSeed">A seed for the generation of private OTS keys for the current subtrees</param> /// <param name="NextNextSeed">A seed for the generation of private OTS keys for the next subtrees</param> /// <param name="CurrentAuthPath">Array of current authentication paths</param> /// <param name="NextAuthPath">Array of next authentication paths</param> /// <param name="CurrentTreehash">Array of current treehash instances</param> /// <param name="NextTreehash">Array of next treehash instances</param> /// <param name="CurrentStack">Array of current shared stacks</param> /// <param name="NextStack">Array of next shared stacks</param> /// <param name="CurrentRetain">Array of current retain stacks</param> /// <param name="NextRetain">Array of next retain stacks</param> /// <param name="NextRoot">The roots of the next subtree</param> /// <param name="CurrentRootSig">Array of signatures of the roots of the current subtrees</param> /// <param name="ParameterSet">The GMSS Parameterset</param> /// <param name="Digest">The digest type</param> internal GMSSPrivateKey(byte[][] CurrentSeed, byte[][] NextNextSeed, byte[][][] CurrentAuthPath, byte[][][] NextAuthPath, Treehash[][] CurrentTreehash, Treehash[][] NextTreehash, List<byte[]>[] CurrentStack, List<byte[]>[] NextStack, List<byte[]>[][] CurrentRetain, List<byte[]>[][] NextRetain, byte[][] NextRoot, byte[][] CurrentRootSig, GMSSParameters ParameterSet, Digests Digest) : this(null, CurrentSeed, NextNextSeed, CurrentAuthPath, NextAuthPath, null, CurrentTreehash, NextTreehash, CurrentStack, NextStack, CurrentRetain, NextRetain, null, null, null, null, NextRoot, null, CurrentRootSig, null, ParameterSet, Digest) { }
/// <summary> /// Reconstructs a public key from its <c>byte</c> array representation. /// </summary> /// /// <param name="KeyStream">An input stream containing an encoded key</param> /// /// <exception cref="CryptoAsymmetricSignException">Thrown if the key could not be loaded</exception> public GMSSPrivateKey(Stream KeyStream) { try { BinaryReader reader = new BinaryReader(KeyStream); int len; int len2; byte[] data; len = reader.ReadInt32(); data = reader.ReadBytes(len); _gmssPS = new GMSSParameters(data); len = reader.ReadInt32(); if (len < 1) { _currentSeeds = ArrayUtils.CreateJagged<byte[][]>(0, 0); } else { data = reader.ReadBytes(len); _currentSeeds = ArrayUtils.ToArray2x8(data); } len = reader.ReadInt32(); if (len < 1) { _nextNextSeeds = ArrayUtils.CreateJagged<byte[][]>(0, 0); } else { data = reader.ReadBytes(len); _nextNextSeeds = ArrayUtils.ToArray2x8(data); } len = reader.ReadInt32(); if (len < 1) { _currentAuthPaths = ArrayUtils.CreateJagged<byte[][][]>(0, 0); } else { data = reader.ReadBytes(len); _currentAuthPaths = ArrayUtils.ToArray3x8(data); } len = reader.ReadInt32(); if (len < 1) { _nextAuthPaths = ArrayUtils.CreateJagged<byte[][][]>(0, 0); } else { data = reader.ReadBytes(len); _nextAuthPaths = ArrayUtils.ToArray3x8(data); } len = reader.ReadInt32(); if (len < 1) { _keep = ArrayUtils.CreateJagged<byte[][][]>(0, 0); } else { data = reader.ReadBytes(len); _keep = ArrayUtils.ToArray3x8(data); } len = reader.ReadInt32(); if (len < 1) { _currentTreehash = ArrayUtils.CreateJagged<Treehash[][]>(0, 0); } else { len2 = reader.ReadInt32(); _currentTreehash = ArrayUtils.CreateJagged<Treehash[][]>(len, len2); for (int i = 0; i < _currentTreehash.Length; i++) { for (int j = 0; j < _currentTreehash[i].Length; j++) { len = reader.ReadInt32(); data = reader.ReadBytes(len); _currentTreehash[i][j] = new Treehash(GetDigest(_gmssPS.DigestEngine), data); } } } len = reader.ReadInt32(); if (len < 1) { _nextTreehash = ArrayUtils.CreateJagged<Treehash[][]>(0, 0); } else { len2 = reader.ReadInt32(); _nextTreehash = ArrayUtils.CreateJagged<Treehash[][]>(len, len2); for (int i = 0; i < _nextTreehash.Length; i++) { for (int j = 0; j < _nextTreehash[i].Length; j++) { len = reader.ReadInt32(); data = reader.ReadBytes(len); _nextTreehash[i][j] = new Treehash(GetDigest(_gmssPS.DigestEngine), data); } } } len = reader.ReadInt32(); if (len < 1) { _currentStack = new List<byte[]>[0]; } else { _currentStack = new List<byte[]>[len]; for (int i = 0; i < _currentStack.Length; i++) { len = reader.ReadInt32(); data = reader.ReadBytes(len); _currentStack[i].Add(data); } } len = reader.ReadInt32(); if (len < 1) { _nextStack = new List<byte[]>[0]; } else { _nextStack = new List<byte[]>[len]; for (int i = 0; i < _nextStack.Length; i++) { len = reader.ReadInt32(); data = reader.ReadBytes(len); _nextStack[i].Add(data); } } len = reader.ReadInt32(); if (len < 1) { _currentRetain = ArrayUtils.CreateJagged<List<byte[]>[][]>(0, 0); } else { len2 = reader.ReadInt32(); _currentRetain = ArrayUtils.CreateJagged<List<byte[]>[][]>(len, len2); for (int i = 0; i < _currentRetain.Length; i++) { for (int j = 0; j < _currentRetain[i].Length; j++) { len = reader.ReadInt32(); data = reader.ReadBytes(len); _currentRetain[i][j] = new List<byte[]>(); _currentRetain[i][j].Add(data); } } } len = reader.ReadInt32(); if (len < 1) { _nextRetain = ArrayUtils.CreateJagged<List<byte[]>[][]>(0, 0); } else { len2 = reader.ReadInt32(); _nextRetain = ArrayUtils.CreateJagged<List<byte[]>[][]>(len, len2); for (int i = 0; i < _nextRetain.Length; i++) { for (int j = 0; j < _nextRetain[i].Length; j++) { len = reader.ReadInt32(); data = reader.ReadBytes(len); _nextRetain[i][j] = new List<byte[]>(); _nextRetain[i][j].Add(data); } } } len = reader.ReadInt32(); if (len < 1) { _nextRoot = ArrayUtils.CreateJagged<byte[][]>(0, 0); } else { data = reader.ReadBytes(len); _nextRoot = ArrayUtils.ToArray2x8(data); } len = reader.ReadInt32(); if (len < 1) { _currentRootSig = ArrayUtils.CreateJagged<byte[][]>(0, 0); } else { data = reader.ReadBytes(len); _currentRootSig = ArrayUtils.ToArray2x8(data); } } catch (Exception ex) { throw new CryptoAsymmetricException("GMSSPrivateKey:CTor", "The GMSSPrivateKey could not be loaded!", ex); } }
public static Treehash[][] Clone(Treehash[][] Data) { if (Data == null) return null; Treehash[][] copy = new Treehash[Data.Length][]; for (int i = 0; i != Data.Length; i++) copy[i] = Clone(Data[i]); return copy; }
public static Treehash[] Clone(Treehash[] Data) { if (Data == null) return null; Treehash[] copy = new Treehash[Data.Length]; Array.Copy(Data, 0, copy, 0, Data.Length); return copy; }