/// <summary> /// Updates the key pair one step. Should be called my MCT in order to safely advance key. /// </summary> /// <param name="keyPair"></param> /// <returns></returns> public async Task <HssKeyPair> UpdateKeyPairOneStepAsync(HssKeyPair keyPair) { var keyPairCopy = keyPair.GetDeepCopy(); int d = _lms.Length; while (keyPairCopy.PrivateKey.PrivateKeys[d - 1].Q == (keyPairCopy.PrivateKey.PrivateKeys[d - 1].OTS_PRIV.Length / (_lms[d - 1].GetLmotsN() * _lms[d - 1].GetLmotsP() + 24)) - 1) { d--; if (d == 0) { keyPairCopy.Expired = true; return(keyPairCopy); } } var lowD = d; if (d < _lms.Length) { while (d < _lms.Length) { var newSeed = _sha256.HashMessage(_lms[d - 1].GetI() .ConcatenateBits(new BitString(keyPairCopy.PrivateKey.PrivateKeys[d - 1].Q + 1, 32)) .ConcatenateBits(new BitString(65534, 16)) .ConcatenateBits(new BitString("ff", 8)) .ConcatenateBits(_lms[d - 1].GetSeed())).Digest; var newI = _sha256.HashMessage(_lms[d - 1].GetI() .ConcatenateBits(new BitString(keyPairCopy.PrivateKey.PrivateKeys[d - 1].Q + 1, 32)) .ConcatenateBits(new BitString(65535, 16)) .ConcatenateBits(new BitString("ff", 8)) .ConcatenateBits(_lms[d - 1].GetSeed())).Digest; newI = newI.MSBSubstring(0, 128); _lms[d] = new Lms(_lmsTypes[d], _lmotsTypes[d], _entropyType, newSeed, newI); var newkeyPairCopy = await _lms[d].GenerateLmsKeyPairAsync(); keyPairCopy.PrivateKey.PrivateKeys[d] = newkeyPairCopy.PrivateKey; keyPairCopy.PrivateKey.PublicKeys[d] = newkeyPairCopy.PublicKey; keyPairCopy.PrivateKey.PrivateKeys[d - 1].Q = (keyPairCopy.PrivateKey.PrivateKeys[d - 1].Q + 1) % (1 << _lms[d - 1].GetH()); keyPairCopy.PrivateKey.Signatures[d - 1] = _lms[d - 1].GenerateLmsSignature( keyPairCopy.PrivateKey.PublicKeys[d], keyPairCopy.PrivateKey.PrivateKeys[d - 1]); if (keyPairCopy.PrivateKey.Signatures[d - 1] == null) { keyPairCopy.Expired = true; return(keyPairCopy); } d++; } } else { // Update Q value keyPairCopy.PrivateKey.PrivateKeys[d - 1].Q = (keyPairCopy.PrivateKey.PrivateKeys[d - 1].Q + 1) % (1 << _lms[d - 1].GetH()); } return(keyPairCopy); }
/// <summary> /// Used in signature generation to sign after advancing the key some number of times. /// This function is unsafe to use if the keyPair has been advanced before. /// </summary> /// <param name="keyPair"></param> /// <param name="times"></param> /// <returns></returns> private async Task <HssKeyPair> UpdateKeyPairAsync(HssKeyPair keyPair, int times = 1) { if (times == 0) { return(keyPair); } keyPair = keyPair.GetDeepCopy(); var divisor = 1; for (int i = 1; i < _lms.Length; i++) { divisor *= (1 << _lms[i].GetH()); } // If update would cause the key to expire, then expire key if (((1 << _lms[0].GetH()) - keyPair.PrivateKey.PrivateKeys[0].Q) * divisor <= times) { keyPair.Expired = true; return(keyPair); } for (int d = 0; d < _lms.Length; d++) { // Update divisor for next step if (d != 0) { divisor /= (1 << _lms[d].GetH()); } var qStep = times / divisor; // If tree update is needed if (qStep + keyPair.PrivateKey.PrivateKeys[d].Q >= (1 << _lms[d].GetH())) { // If update would cause the key to expire, then expire key if (d == 0) { keyPair.Expired = true; return(keyPair); } var newSeed = _sha256.HashMessage(_lms[d - 1].GetI() .ConcatenateBits(new BitString(keyPair.PrivateKey.PrivateKeys[d - 1].Q, 32)) .ConcatenateBits(new BitString(65534, 16)) .ConcatenateBits(new BitString("ff", 8)) .ConcatenateBits(_lms[d - 1].GetSeed())).Digest; var newI = _sha256.HashMessage(_lms[d - 1].GetI() .ConcatenateBits(new BitString(keyPair.PrivateKey.PrivateKeys[d - 1].Q, 32)) .ConcatenateBits(new BitString(65535, 16)) .ConcatenateBits(new BitString("ff", 8)) .ConcatenateBits(_lms[d - 1].GetSeed())).Digest; newI = newI.MSBSubstring(0, 128); _lms[d] = new Lms(_lmsTypes[d], _lmotsTypes[d], _entropyType, newSeed, newI); var newKeyPair = await _lms[d].GenerateLmsKeyPairAsync(); keyPair.PrivateKey.PrivateKeys[d] = newKeyPair.PrivateKey; keyPair.PrivateKey.PublicKeys[d] = newKeyPair.PublicKey; keyPair.PrivateKey.Signatures[d - 1] = _lms[d - 1].GenerateLmsSignature( keyPair.PrivateKey.PublicKeys[d], keyPair.PrivateKey.PrivateKeys[d - 1]); } // Update Q value keyPair.PrivateKey.PrivateKeys[d].Q = (keyPair.PrivateKey.PrivateKeys[d].Q + qStep) % (1 << _lms[d].GetH()); } return(keyPair); }