From 0fa8a62bad2c9d2c14d25cc9e9f365e4017ac527 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Thu, 20 Oct 2022 14:29:12 +0700 Subject: Fix LMS tests namespace --- crypto/test/src/pqc/crypto/lms/HSSTests.cs | 871 --------------------- crypto/test/src/pqc/crypto/lms/LMSKeyGenTests.cs | 148 ---- crypto/test/src/pqc/crypto/lms/LMSTests.cs | 162 ---- crypto/test/src/pqc/crypto/lms/LMSVectorUtils.cs | 37 - crypto/test/src/pqc/crypto/lms/TypeTests.cs | 67 -- crypto/test/src/pqc/crypto/lms/test/HssTests.cs | 869 ++++++++++++++++++++ .../test/src/pqc/crypto/lms/test/LmsKeyGenTests.cs | 146 ++++ crypto/test/src/pqc/crypto/lms/test/LmsTests.cs | 162 ++++ .../src/pqc/crypto/lms/test/LmsVectorUtilities.cs | 37 + crypto/test/src/pqc/crypto/lms/test/TypeTests.cs | 67 ++ 10 files changed, 1281 insertions(+), 1285 deletions(-) delete mode 100644 crypto/test/src/pqc/crypto/lms/HSSTests.cs delete mode 100644 crypto/test/src/pqc/crypto/lms/LMSKeyGenTests.cs delete mode 100644 crypto/test/src/pqc/crypto/lms/LMSTests.cs delete mode 100644 crypto/test/src/pqc/crypto/lms/LMSVectorUtils.cs delete mode 100644 crypto/test/src/pqc/crypto/lms/TypeTests.cs create mode 100644 crypto/test/src/pqc/crypto/lms/test/HssTests.cs create mode 100644 crypto/test/src/pqc/crypto/lms/test/LmsKeyGenTests.cs create mode 100644 crypto/test/src/pqc/crypto/lms/test/LmsTests.cs create mode 100644 crypto/test/src/pqc/crypto/lms/test/LmsVectorUtilities.cs create mode 100644 crypto/test/src/pqc/crypto/lms/test/TypeTests.cs diff --git a/crypto/test/src/pqc/crypto/lms/HSSTests.cs b/crypto/test/src/pqc/crypto/lms/HSSTests.cs deleted file mode 100644 index 691c51914..000000000 --- a/crypto/test/src/pqc/crypto/lms/HSSTests.cs +++ /dev/null @@ -1,871 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -using NUnit.Framework; - -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Encoders; -using Org.BouncyCastle.Utilities.Test; - -namespace Org.BouncyCastle.Pqc.Crypto.Lms -{ - - [TestFixture] - public class HSSTests - { - - [Test] - public void TestHssKeySerialisation() - { - byte[] fixedSource = new byte[8192]; - for (int t = 0; t < fixedSource.Length; t++) - { - fixedSource[t] = 1; - } - - FixedSecureRandom.Source[] source = {new FixedSecureRandom.Source(fixedSource)}; - SecureRandom rand = new FixedSecureRandom(source); - - HSSPrivateKeyParameters generatedPrivateKey = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters(new LMSParameters[] - { - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), - }, rand) - ); - - HSSSignature sigFromGeneratedPrivateKey = HSS.GenerateSignature(generatedPrivateKey, Hex.Decode("ABCDEF")); - - byte[] keyPairEnc = generatedPrivateKey.GetEncoded(); - - HSSPrivateKeyParameters reconstructedPrivateKey = HSSPrivateKeyParameters.GetInstance(keyPairEnc); - Assert.True(reconstructedPrivateKey.Equals(generatedPrivateKey)); - - reconstructedPrivateKey.GetPublicKey(); - generatedPrivateKey.GetPublicKey(); - - // - // Are they still equal, public keys are only checked if they both - // exist because they are only created when requested as they are derived from the private key. - // - Assert.True(reconstructedPrivateKey.Equals(generatedPrivateKey)); - - // - // Check the reconstructed key can verify a signature. - // - Assert.True(HSS.VerifySignature(reconstructedPrivateKey.GetPublicKey(), sigFromGeneratedPrivateKey, - Hex.Decode("ABCDEF"))); - } - - /** - * Test Case 1 Signature - * From https://tools.ietf.org/html/rfc8554#appendix-F - */ - [Test] - public void TestHSSVector_1() - { - var blocks = LoadVector("pqc.lms.testcase_1.txt"); - - HSSPublicKeyParameters publicKey = HSSPublicKeyParameters.GetInstance(blocks[0]); - byte[] message = (byte[]) blocks[1]; - HSSSignature signature = HSSSignature.GetInstance(blocks[2], publicKey.L); - Assert.True(HSS.VerifySignature(publicKey, signature, message), "Test Case 1 "); - } - - /** - * Test Case 1 Signature - * From https://tools.ietf.org/html/rfc8554#appendix-F - */ - [Test] - public void TestHSSVector_2() - { - var blocks = LoadVector("pqc.lms.testcase_2.txt"); - - HSSPublicKeyParameters publicKey = HSSPublicKeyParameters.GetInstance(blocks[0]); - byte[] message = blocks[1]; - byte[] sig = blocks[2]; - HSSSignature signature = HSSSignature.GetInstance(sig, publicKey.L); - Assert.True(HSS.VerifySignature(publicKey, signature, message), "Test Case 2 Signature"); - - LMSPublicKeyParameters lmsPub = LMSPublicKeyParameters.GetInstance(blocks[3]); - LMSSignature lmsSignature = LMSSignature.GetInstance(blocks[4]); - - Assert.True(LMS.VerifySignature(lmsPub, lmsSignature, message), "Test Case 2 Signature 2"); - } - - private IList LoadVector(string vector) - { - StreamReader bin = new StreamReader(SimpleTest.GetTestDataAsStream(vector)); - var blocks = new List(); - StringBuilder sw = new StringBuilder(); - - string line; - while ((line = bin.ReadLine()) != null) - { - if (line.StartsWith("!")) - { - if (sw.Length > 0) - { - blocks.Add(LMSVectorUtils.ExtractPrefixedBytes(sw.ToString())); - sw.Length = 0; - } - } - sw.Append(line); - sw.Append("\n"); - } - - if (sw.Length > 0) - { - blocks.Add(LMSVectorUtils.ExtractPrefixedBytes(sw.ToString())); - sw.Length = 0; - } - return blocks; - } - - /** - * Test the generation of public keys from private key SEED and I. - * Level 0 - */ - [Test] - public void TestGenPublicKeys_L0() - { - byte[] seed = Hex.Decode("558b8966c48ae9cb898b423c83443aae014a72f1b1ab5cc85cf1d892903b5439"); - int level = 0; - LMSPrivateKeyParameters lmsPrivateKey = LMS.GenerateKeys(LMSigParameters.GetParametersByID(6), - LMOtsParameters.GetParametersByID(3), level, Hex.Decode("d08fabd4a2091ff0a8cb4ed834e74534"), seed); - LMSPublicKeyParameters publicKey = lmsPrivateKey.GetPublicKey(); - Assert.True(Arrays.AreEqual(publicKey.GetT1(), - Hex.Decode("32a58885cd9ba0431235466bff9651c6c92124404d45fa53cf161c28f1ad5a8e"))); - Assert.True(Arrays.AreEqual(publicKey.GetI(), Hex.Decode("d08fabd4a2091ff0a8cb4ed834e74534"))); - } - - /** - * Test the generation of public keys from private key SEED and I. - * Level 1; - */ - [Test] - public void TestGenPublicKeys_L1() - { - byte[] seed = Hex.Decode("a1c4696e2608035a886100d05cd99945eb3370731884a8235e2fb3d4d71f2547"); - int level = 1; - LMSPrivateKeyParameters lmsPrivateKey = LMS.GenerateKeys(LMSigParameters.GetParametersByID(5), - LMOtsParameters.GetParametersByID(4), level, Hex.Decode("215f83b7ccb9acbcd08db97b0d04dc2b"), seed); - LMSPublicKeyParameters publicKey = lmsPrivateKey.GetPublicKey(); - Assert.True(Arrays.AreEqual(publicKey.GetT1(), - Hex.Decode("a1cd035833e0e90059603f26e07ad2aad152338e7a5e5984bcd5f7bb4eba40b7"))); - Assert.True(Arrays.AreEqual(publicKey.GetI(), Hex.Decode("215f83b7ccb9acbcd08db97b0d04dc2b"))); - } - - [Test] - public void TestGenerate() - { - // - // Generate an HSS key pair for a two level HSS scheme. - // then use that to verify it compares with a value from the same reference implementation. - // Then check components of it serialize and deserialize properly. - // - byte[] fixedSource = new byte[8192]; - for (int t = 0; t < fixedSource.Length; t++) - { - fixedSource[t] = 1; - } - - FixedSecureRandom.Source[] source = {new FixedSecureRandom.Source(fixedSource)}; - SecureRandom rand = new FixedSecureRandom(source); - - HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters(new LMSParameters[] - { - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), - }, rand)); - - // - // Generated from reference implementation. - // check the encoded form of the public key matches. - // - string expectedPk = - "0000000200000005000000030101010101010101010101010101010166BF6F5816EEE4BBF33C50ACB480E09B4169EBB533372959BC4315C388E501AC"; - byte[] pkEnc = keyPair.GetPublicKey().GetEncoded(); - Assert.True(Arrays.AreEqual(Hex.Decode(expectedPk), pkEnc)); - - // - // Check that HSS public keys have value equality after deserialization. - // Use external sourced pk for deserialization. - // - Assert.True(keyPair.GetPublicKey().Equals(HSSPublicKeyParameters.GetInstance(Hex.Decode(expectedPk))), - "HSSPrivateKeyParameterss equal are deserialization"); - - // - // Generate, hopefully the same HSSKetPair for the same entropy. - // This is a sanity test - // - { - FixedSecureRandom.Source[] source1 = {new FixedSecureRandom.Source(fixedSource)}; - SecureRandom rand1 = new FixedSecureRandom(source1); - - HSSPrivateKeyParameters regenKeyPair = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters(new LMSParameters[] - { - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), - }, rand1)); - - Assert.True( - Arrays.AreEqual(regenKeyPair.GetPublicKey().GetEncoded(), keyPair.GetPublicKey().GetEncoded()), - "Both generated keys are the same"); - - Assert.True(keyPair.GetKeys().Count == regenKeyPair.GetKeys().Count, - "same private key size"); - - for (int t = 0; t < keyPair.GetKeys().Count; t++) - { - // - // Check the private keys can be encoded and are the same. - // - byte[] pk1 = keyPair.GetKeys()[t].GetEncoded(); - byte[] pk2 = regenKeyPair.GetKeys()[t].GetEncoded(); - Assert.True(Arrays.AreEqual(pk1, pk2)); - - // - // Deserialize them and see if they still equal. - // - LMSPrivateKeyParameters pk1O = LMSPrivateKeyParameters.GetInstance(pk1); - LMSPrivateKeyParameters pk2O = LMSPrivateKeyParameters.GetInstance(pk2); - - Assert.True(pk1O.Equals(pk2O), "LmsPrivateKey still equal after deserialization"); - - } - } - - // - // This time we will generate another set of keys using a different entropy source. - // they should be different! - // Useful for detecting accidental hard coded things. - // - - { - // Use a real secure random this time. - SecureRandom rand1 = new SecureRandom(); - - HSSPrivateKeyParameters differentKey = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters(new LMSParameters[] - { - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), - }, rand1) - ); - - Assert.False( - Arrays.AreEqual(differentKey.GetPublicKey().GetEncoded(), keyPair.GetPublicKey().GetEncoded()), - "Both generated keys are not the same"); - - for (int t = 0; t < keyPair.GetKeys().Count; t++) - { - // - // Check the private keys can be encoded and are not the same. - // - byte[] pk1 = keyPair.GetKeys()[t].GetEncoded(); - byte[] pk2 = differentKey.GetKeys()[t].GetEncoded(); - Assert.False(Arrays.AreEqual(pk1, pk2), "keys not the same"); - - // - // Deserialize them and see if they still equal. - // - LMSPrivateKeyParameters pk1O = LMSPrivateKeyParameters.GetInstance(pk1); - LMSPrivateKeyParameters pk2O = LMSPrivateKeyParameters.GetInstance(pk2); - - Assert.False(pk1O.Equals(pk2O), "LmsPrivateKey not suddenly equal after deserialization"); - } - } - } - - /** - * This test takes in a series of vectors generated by adding print statements to code called by - * the "test_sign.c" test in the reference implementation. - *

- * The purpose of this test is to ensure that the signatures and public keys exactly match for the - * same entropy source the values generated by the reference implementation. - *

- * It also verifies value equality between signature and public key objects as well as - * complimentary serialization and deserialization. - * - * @ - */ - [Test] - public void TestVectorsFromReference() - { - StreamReader sr = new StreamReader(SimpleTest.GetTestDataAsStream("pqc.lms.depth_1.txt")); - - var lmsParameters = new List(); - var lmOtsParameters = new List(); - byte[] message = null; - byte[] hssPubEnc = null; - MemoryStream fixedESBuffer = new MemoryStream(); - int d = 0, j = 0; - - string line; - while ((line = sr.ReadLine()) != null) - { - if (TrimLine(ref line)) - continue; - - if (line.StartsWith("Depth:")) - { - d = int.Parse(line.Substring("Depth:".Length).Trim()); - } - else if (line.StartsWith("LMType:")) - { - int typ = int.Parse(line.Substring("LMType:".Length).Trim()); - lmsParameters.Add(LMSigParameters.GetParametersByID(typ)); - } - else if (line.StartsWith("LMOtsType:")) - { - int typ = int.Parse(line.Substring("LMOtsType:".Length).Trim()); - lmOtsParameters.Add(LMOtsParameters.GetParametersByID(typ)); - } - else if (line.StartsWith("Rand:")) - { - var b = Hex.Decode(line.Substring("Rand:".Length).Trim()); - fixedESBuffer.Write(b, 0, b.Length); - } - else if (line.StartsWith("HSSPublicKey:")) - { - hssPubEnc = Hex.Decode(line.Substring("HSSPublicKey:".Length).Trim()); - } - else if (line.StartsWith("Message:")) - { - message = Hex.Decode(line.Substring("Message:".Length).Trim()); - } - else if (line.StartsWith("Signature:")) - { - j++; - - byte[] encodedSigFromVector = Hex.Decode(line.Substring("Signature:".Length).Trim()); - - // - // Assumes Signature is the last element in the set of vectors. - // - FixedSecureRandom.Source[] source = {new FixedSecureRandom.Source(fixedESBuffer.ToArray())}; - FixedSecureRandom fixRnd = new FixedSecureRandom(source); - fixedESBuffer.SetLength(0);//todo is this correct? buffer.reset(); - //fixedESBuffer = new MemoryStream(); - - // - // Deserialize pub key from reference impl. - // - HSSPublicKeyParameters vectorSourcedPubKey = HSSPublicKeyParameters.GetInstance(hssPubEnc); - var lmsParams = new List(); - - for (int i = 0; i != lmsParameters.Count; i++) - { - lmsParams.Add(new LMSParameters(lmsParameters[i], lmOtsParameters[i])); - } - - // - // Using our fixed entropy source generate hss keypair - // - - LMSParameters[] lmsParamsArray = new LMSParameters[lmsParams.Count]; - lmsParams.CopyTo(lmsParamsArray, 0); - HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters( - lmsParamsArray, fixRnd) - ); - - { - // Public Key should match vector. - - // Encoded value equality. - HSSPublicKeyParameters generatedPubKey = keyPair.GetPublicKey(); - Assert.True(Arrays.AreEqual(hssPubEnc, generatedPubKey.GetEncoded())); - - // Value equality. - Assert.True(vectorSourcedPubKey.Equals(generatedPubKey)); - } - - // - // Generate a signature using the keypair we generated. - // - HSSSignature sig = HSS.GenerateSignature(keyPair, message); - - HSSSignature signatureFromVector = null; - if (!Arrays.AreEqual(sig.GetEncoded(), encodedSigFromVector)) - { - signatureFromVector = HSSSignature.GetInstance(encodedSigFromVector, d); - signatureFromVector.Equals(sig); - } - - // check encoding signature matches. - Assert.True(Arrays.AreEqual(sig.GetEncoded(), encodedSigFromVector)); - - // Check we can verify our generated signature with the vectors sourced public key. - Assert.True(HSS.VerifySignature(vectorSourcedPubKey, sig, message)); - - // Deserialize the signature from the vector. - signatureFromVector = HSSSignature.GetInstance(encodedSigFromVector, d); - - // Can we verify signature from vector with public key from vector. - Assert.True(HSS.VerifySignature(vectorSourcedPubKey, signatureFromVector, message)); - - // - // Check our generated signature and the one deserialized from the vector - // have value equality. - Assert.True(signatureFromVector.Equals(sig)); - - // - // Other tests vandalise HSS signatures to check they Assert.Fail when tampered with - // we won't do that again here. - // - d = 0; - lmOtsParameters.Clear(); - lmsParameters.Clear(); - message = null; - hssPubEnc = null; - } - } - } - - [Test] - public void TestVectorsFromReference_Expanded() - { - using (StreamReader sr = new StreamReader(SimpleTest.GetTestDataAsStream("pqc.lms.expansion.txt"))) - { - var lmsParameters = new List(); - var lmOtsParameters = new List(); - byte[] message = null; - byte[] hssPubEnc = null; - MemoryStream fixedESBuffer = new MemoryStream(); - var sigVectors = new List(); - int d = 0; - - string line; - while ((line = sr.ReadLine()) != null) - { - if (TrimLine(ref line)) - continue; - - if (line.StartsWith("Depth:")) - { - d = int.Parse(line.Substring("Depth:".Length).Trim()); - } - else if (line.StartsWith("LMType:")) - { - int typ = int.Parse(line.Substring("LMType:".Length).Trim()); - lmsParameters.Add(LMSigParameters.GetParametersByID(typ)); - } - else if (line.StartsWith("LMOtsType:")) - { - int typ = int.Parse(line.Substring("LMOtsType:".Length).Trim()); - lmOtsParameters.Add(LMOtsParameters.GetParametersByID(typ)); - } - else if (line.StartsWith("Rand:")) - { - var b = Hex.Decode(line.Substring("Rand:".Length).Trim()); - fixedESBuffer.Write(b, 0, b.Length); - } - else if (line.StartsWith("HSSPublicKey:")) - { - hssPubEnc = Hex.Decode(line.Substring("HSSPublicKey:".Length).Trim()); - } - else if (line.StartsWith("Message:")) - { - message = Hex.Decode(line.Substring("Message:".Length).Trim()); - - } - else if (line.StartsWith("Signature:")) - { - sigVectors.Add(Hex.Decode(line.Substring("Signature:".Length).Trim())); - } - } - - // - // Assumes Signature is the last element in the set of vectors. - // - FixedSecureRandom.Source[] source = {new FixedSecureRandom.Source(fixedESBuffer.ToArray())}; - FixedSecureRandom fixRnd = new FixedSecureRandom(source); - fixedESBuffer.SetLength(0); - var lmsParams = new List(); - - for (int i = 0; i != lmsParameters.Count; i++) - { - lmsParams.Add(new LMSParameters(lmsParameters[i], lmOtsParameters[i])); - } - - LMSParameters[] lmsParamsArray = new LMSParameters[lmsParams.Count]; - lmsParams.CopyTo(lmsParamsArray, 0); - HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters(lmsParamsArray, fixRnd) - ); - - Assert.True(Arrays.AreEqual(hssPubEnc, keyPair.GetPublicKey().GetEncoded())); - - HSSPublicKeyParameters pubKeyFromVector = HSSPublicKeyParameters.GetInstance(hssPubEnc); - HSSPublicKeyParameters pubKeyGenerated = null; - - - Assert.AreEqual(1024, keyPair.GetUsagesRemaining()); - Assert.AreEqual(1024, keyPair.IndexLimit); - - // - // Split the space up with a shard. - // - - HSSPrivateKeyParameters shard1 = keyPair.ExtractKeyShard(500); - pubKeyGenerated = shard1.GetPublicKey(); - - - HSSPrivateKeyParameters pair = shard1; - - int c = 0; - for (int i = 0; i < keyPair.IndexLimit; i++) - { - if (i == 500) - { - try - { - HSS.IncrementIndex(pair); - Assert.Fail("shard should be exhausted."); - } - catch (Exception ex) - { - Assert.AreEqual("hss private key shard is exhausted", ex.Message); - } - - pair = keyPair; - pubKeyGenerated = keyPair.GetPublicKey(); - - Assert.AreEqual(pubKeyGenerated, shard1.GetPublicKey()); - } - - if (i % 5 == 0) - { - HSSSignature sigCalculated = HSS.GenerateSignature(pair, message); - Assert.True(Arrays.AreEqual(sigCalculated.GetEncoded(),(byte[]) sigVectors[c])); - - Assert.True(HSS.VerifySignature(pubKeyFromVector, sigCalculated, message)); - Assert.True(HSS.VerifySignature(pubKeyGenerated, sigCalculated, message)); - - HSSSignature sigFromVector = HSSSignature.GetInstance((byte[]) sigVectors[c], - pubKeyFromVector.L); - - Assert.True(HSS.VerifySignature(pubKeyFromVector, sigFromVector, message)); - Assert.True(HSS.VerifySignature(pubKeyGenerated, sigFromVector, message)); - - - Assert.True(sigCalculated.Equals(sigFromVector)); - - - c++; - } - else - { - HSS.IncrementIndex(pair); - } - } - } - } - - /** - * Test remaining calculation is accurate and a new key is generated when - * all the ots keys for that level are consumed. - * - * @ - */ - [Test] - public void TestRemaining() - { - HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters(new LMSParameters[] - { - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2) - }, new SecureRandom()) - ); - - - LMSPrivateKeyParameters lmsKey = keyPair.GetKeys()[keyPair.L - 1]; - // - // There should be a max of 32768 signatures for this key. - // - Assert.True(1024 == keyPair.GetUsagesRemaining()); - - HSS.IncrementIndex(keyPair); - HSS.IncrementIndex(keyPair); - HSS.IncrementIndex(keyPair); - HSS.IncrementIndex(keyPair); - HSS.IncrementIndex(keyPair); - - Assert.True(5 == keyPair.GetIndex()); // Next key is at index 5! - - Assert.True(1024 - 5 == keyPair.GetUsagesRemaining()); - - HSSPrivateKeyParameters shard = keyPair.ExtractKeyShard(10); - - Assert.True(15 == shard.IndexLimit); - Assert.True(5 == shard.GetIndex()); - - // Should not be the same. - Assert.False(shard.GetIndex() == keyPair.GetIndex()); - - // - // Should be 17 left, it will throw if it has been exhausted. - // - for (int t = 0; t < 17; t++) - { - HSS.IncrementIndex(keyPair); - } - - // We have used 32 keys. - Assert.True(1024 - 32 == keyPair.GetUsagesRemaining()); - - HSS.GenerateSignature(keyPair, Encoding.ASCII.GetBytes("Foo")); - - // - // This should trigger the generation of a new key. - // - LMSPrivateKeyParameters potentialNewLMSKey = keyPair.GetKeys()[keyPair.L - 1]; - Assert.False(potentialNewLMSKey.Equals(lmsKey)); - } - - [Test] - public void TestSharding() - { - HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters(new LMSParameters[] - { - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2) - }, new SecureRandom()) - ); - - Assert.True(1024 == keyPair.GetUsagesRemaining()); - Assert.True(1024 == keyPair.IndexLimit); - Assert.True(0 == keyPair.GetIndex()); - Assert.False(keyPair.IsShard()); - HSS.IncrementIndex(keyPair); - - - // - // Take a shard that should cross boundaries - // - HSSPrivateKeyParameters shard = keyPair.ExtractKeyShard(48); - Assert.True(shard.IsShard()); - Assert.True(48 == shard.GetUsagesRemaining()); - Assert.True(49 == shard.IndexLimit); - Assert.True(1 == shard.GetIndex()); - - Assert.True(49 == keyPair.GetIndex()); - - - int t = 47; - while (--t >= 0) - { - HSS.IncrementIndex(shard); - } - - HSSSignature sig = HSS.GenerateSignature(shard, Encoding.ASCII.GetBytes("Cats")); - - // - // Test it validates and nothing has gone wrong with the public keys. - // - Assert.True(HSS.VerifySignature(keyPair.GetPublicKey(), sig, Encoding.ASCII.GetBytes("Cats"))); - Assert.True(HSS.VerifySignature(shard.GetPublicKey(), sig, Encoding.ASCII.GetBytes("Cats"))); - - // Signing again should Assert.Fail. - - try - { - HSS.GenerateSignature(shard, Encoding.ASCII.GetBytes("Cats")); - Assert.Fail(); - } - catch (Exception ex) - { - Assert.True(ex.Message.Equals("hss private key shard is exhausted")); - } - - // Should work without throwing. - HSS.GenerateSignature(keyPair, Encoding.ASCII.GetBytes("Cats")); - } - - /** - * Take an HSS key pair and exhaust its signing capacity. - * - * @ - */ - internal class HSSSecureRandom - : SecureRandom - { - internal HSSSecureRandom() - : base(null) - { - } - - public override void NextBytes(byte[] buf) - { - NextBytes(buf, 0, buf.Length); - } - - public override void NextBytes(byte[] buf, int off, int len) - { - for (int t = 0; t < len; t++) - { - buf[off + t] = 1; - } - } - } - - [Test] - public void TestSignUnitExhaustion() - { - HSSSecureRandom rand = new HSSSecureRandom(); - - HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( - new HSSKeyGenerationParameters(new LMSParameters[] - { - new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), - new LMSParameters(LMSigParameters.lms_sha256_n32_h10, LMOtsParameters.sha256_n32_w1), - }, rand) - ); - - HSSPublicKeyParameters pk = keyPair.GetPublicKey(); - - - int ctr = 0; - byte[] message = new byte[32]; - - // - // There should be a max of 32768 signatures for this key. - // - - Assert.True(keyPair.GetUsagesRemaining() == 32768); - - int mod = 256; - try - { - while (ctr < 32769) // Just a number.. - { - if (ctr % mod == 0) - { - // - // We don't want to check every key. - // The test will take over an hour to complete. - // - Pack_Int32_To_BE(ctr, message, 0); - HSSSignature sig = HSS.GenerateSignature(keyPair, message); - - Assert.True(ctr % 1024 == sig.Signature.Q); - - // Check there was a post increment in the tail end LMS key. - Assert.True((ctr % 1024) + 1 == keyPair.GetKeys()[keyPair.L - 1].GetIndex()); - - Assert.True(ctr + 1 == keyPair.GetIndex()); - - - // Validate the heirarchial path building was correct. - - long[] qValues = new long[keyPair.GetKeys().Count]; - long q = ctr; - - for (int t = keyPair.GetKeys().Count - 1; t >= 0; t--) - { - LMSigParameters sigParameters = keyPair.GetKeys()[t].GetSigParameters(); - int mask = (1 << sigParameters.H) - 1; - qValues[t] = q & mask; - q >>= sigParameters.H; - } - - for (int t = 0; t < keyPair.GetKeys().Count; t++) - { - Assert.True(keyPair.GetKeys()[t].GetIndex() - 1 == qValues[t]); - } - - Assert.True(HSS.VerifySignature(pk, sig, message)); - Assert.True(sig.Signature.SigParameters.ID == LMSigParameters.lms_sha256_n32_h10.ID); - - { - // - // Vandalise hss signature. - // - byte[] rawSig = sig.GetEncoded(); - rawSig[100] ^= 1; - HSSSignature parsedSig = HSSSignature.GetInstance(rawSig, pk.L); - Assert.False(HSS.VerifySignature(pk, parsedSig, message)); - - try - { - HSSSignature.GetInstance(rawSig, 0); - Assert.Fail(); - } - catch (Exception ex) - { - Assert.True(ex.Message.Contains("nspk exceeded maxNspk")); - } - - } - - { - // - // Vandalise hss message - // - byte[] newMsg = new byte[message.Length]; - message.CopyTo(newMsg, 0); - newMsg[1] ^= 1; - Assert.False(HSS.VerifySignature(pk, sig, newMsg)); - } - - { - // - // Vandalise public key - // - byte[] pkEnc = pk.GetEncoded(); - pkEnc[35] ^= 1; - HSSPublicKeyParameters rebuiltPk = HSSPublicKeyParameters.GetInstance(pkEnc); - Assert.False(HSS.VerifySignature(rebuiltPk, sig, message)); - } - } - else - { - // Skip some keys. - HSS.IncrementIndex(keyPair); - } - - ctr++; - } - - //System.out.Println(ctr); - Assert.Fail(); - } - catch (Exception ex) - { - Assert.True(keyPair.GetUsagesRemaining() == 0); - Assert.True(ctr == 32768); - Assert.True(ex.Message.Contains("hss private key is exhausted")); - } - } - - private static void Pack_Int32_To_BE(int n, byte[] bs, int off) - { - bs[off] = (byte)(n >> 24); - bs[off + 1] = (byte)(n >> 16); - bs[off + 2] = (byte)(n >> 8); - bs[off + 3] = (byte)(n); - } - - private static bool TrimLine(ref string line) - { - int commentPos = line.IndexOf('#'); - if (commentPos >= 0) - { - line = line.Substring(0, commentPos); - } - - line = line.Trim(); - - return line.Length < 1; - } - } -} diff --git a/crypto/test/src/pqc/crypto/lms/LMSKeyGenTests.cs b/crypto/test/src/pqc/crypto/lms/LMSKeyGenTests.cs deleted file mode 100644 index 4dd417d01..000000000 --- a/crypto/test/src/pqc/crypto/lms/LMSKeyGenTests.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System; - -using NUnit.Framework; - -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Encoders; - -namespace Org.BouncyCastle.Pqc.Crypto.Lms -{ - [TestFixture] - public class LMSKeyGenTests - { - [Test] - public void TestGeneratePrivateKey() - { - // - // This is based on the second set of vectors and the second signature. - // We verify the correct private key is generated if the correct public key is - // derived from it. - // - byte[] msg = Hex.Decode("54686520656e756d65726174696f6e20\n" + - "696e2074686520436f6e737469747574\n" + - "696f6e2c206f66206365727461696e20\n" + - "7269676874732c207368616c6c206e6f\n" + - "7420626520636f6e7374727565642074\n" + - "6f2064656e79206f7220646973706172\n" + - "616765206f7468657273207265746169\n" + - "6e6564206279207468652070656f706c\n" + - "652e0a"); - - // From vector. - byte[] seed = Hex.Decode("a1c4696e2608035a886100d05cd99945eb3370731884a8235e2fb3d4d71f2547"); - byte[] I = Hex.Decode("215f83b7ccb9acbcd08db97b0d04dc2b"); - int level = 1; // This is the second level, we use this because it signs the message. - - // Generate the private key. - LMSPrivateKeyParameters lmsPrivateKey = LMS.GenerateKeys(LMSigParameters.GetParametersByID(5), - LMOtsParameters.GetParametersByID(4), level, I, seed); - - // This derives the public key. - LMSPublicKeyParameters publicKey = lmsPrivateKey.GetPublicKey(); - - // From the vector. - string pkEnc = "0000000500000004215f83b7ccb9acbcd08db97b0d04dc2ba1cd035833e0e90059603f26e07ad2aad152338e7a5e5984bcd5f7bb4eba40b7"; - - // Test public key encoded matched vector. - Assert.True(Arrays.AreEqual(Hex.Decode(pkEnc), publicKey.GetEncoded())); - - // - // Fast forward and burn off some OTS private keys until we get to key number 4. - // - lmsPrivateKey.ExtractKeyShard(3); - - LMSSignature signature = LMS.GenerateSign(lmsPrivateKey, msg); - - // The expected signature as encoded. - string sigEnc = "00000004\n" + - "00000004\n" + - "0eb1ed54a2460d512388cad533138d24\n" + - "0534e97b1e82d33bd927d201dfc24ebb\n" + - "11b3649023696f85150b189e50c00e98\n" + - "850ac343a77b3638319c347d7310269d\n" + - "3b7714fa406b8c35b021d54d4fdada7b\n" + - "9ce5d4ba5b06719e72aaf58c5aae7aca\n" + - "057aa0e2e74e7dcfd17a0823429db629\n" + - "65b7d563c57b4cec942cc865e29c1dad\n" + - "83cac8b4d61aacc457f336e6a10b6632\n" + - "3f5887bf3523dfcadee158503bfaa89d\n" + - "c6bf59daa82afd2b5ebb2a9ca6572a60\n" + - "67cee7c327e9039b3b6ea6a1edc7fdc3\n" + - "df927aade10c1c9f2d5ff446450d2a39\n" + - "98d0f9f6202b5e07c3f97d2458c69d3c\n" + - "8190643978d7a7f4d64e97e3f1c4a08a\n" + - "7c5bc03fd55682c017e2907eab07e5bb\n" + - "2f190143475a6043d5e6d5263471f4ee\n" + - "cf6e2575fbc6ff37edfa249d6cda1a09\n" + - "f797fd5a3cd53a066700f45863f04b6c\n" + - "8a58cfd341241e002d0d2c0217472bf1\n" + - "8b636ae547c1771368d9f317835c9b0e\n" + - "f430b3df4034f6af00d0da44f4af7800\n" + - "bc7a5cf8a5abdb12dc718b559b74cab9\n" + - "090e33cc58a955300981c420c4da8ffd\n" + - "67df540890a062fe40dba8b2c1c548ce\n" + - "d22473219c534911d48ccaabfb71bc71\n" + - "862f4a24ebd376d288fd4e6fb06ed870\n" + - "5787c5fedc813cd2697e5b1aac1ced45\n" + - "767b14ce88409eaebb601a93559aae89\n" + - "3e143d1c395bc326da821d79a9ed41dc\n" + - "fbe549147f71c092f4f3ac522b5cc572\n" + - "90706650487bae9bb5671ecc9ccc2ce5\n" + - "1ead87ac01985268521222fb9057df7e\n" + - "d41810b5ef0d4f7cc67368c90f573b1a\n" + - "c2ce956c365ed38e893ce7b2fae15d36\n" + - "85a3df2fa3d4cc098fa57dd60d2c9754\n" + - "a8ade980ad0f93f6787075c3f680a2ba\n" + - "1936a8c61d1af52ab7e21f416be09d2a\n" + - "8d64c3d3d8582968c2839902229f85ae\n" + - "e297e717c094c8df4a23bb5db658dd37\n" + - "7bf0f4ff3ffd8fba5e383a48574802ed\n" + - "545bbe7a6b4753533353d73706067640\n" + - "135a7ce517279cd683039747d218647c\n" + - "86e097b0daa2872d54b8f3e508598762\n" + - "9547b830d8118161b65079fe7bc59a99\n" + - "e9c3c7380e3e70b7138fe5d9be255150\n" + - "2b698d09ae193972f27d40f38dea264a\n" + - "0126e637d74ae4c92a6249fa103436d3\n" + - "eb0d4029ac712bfc7a5eacbdd7518d6d\n" + - "4fe903a5ae65527cd65bb0d4e9925ca2\n" + - "4fd7214dc617c150544e423f450c99ce\n" + - "51ac8005d33acd74f1bed3b17b7266a4\n" + - "a3bb86da7eba80b101e15cb79de9a207\n" + - "852cf91249ef480619ff2af8cabca831\n" + - "25d1faa94cbb0a03a906f683b3f47a97\n" + - "c871fd513e510a7a25f283b196075778\n" + - "496152a91c2bf9da76ebe089f4654877\n" + - "f2d586ae7149c406e663eadeb2b5c7e8\n" + - "2429b9e8cb4834c83464f079995332e4\n" + - "b3c8f5a72bb4b8c6f74b0d45dc6c1f79\n" + - "952c0b7420df525e37c15377b5f09843\n" + - "19c3993921e5ccd97e097592064530d3\n" + - "3de3afad5733cbe7703c5296263f7734\n" + - "2efbf5a04755b0b3c997c4328463e84c\n" + - "aa2de3ffdcd297baaaacd7ae646e44b5\n" + - "c0f16044df38fabd296a47b3a838a913\n" + - "982fb2e370c078edb042c84db34ce36b\n" + - "46ccb76460a690cc86c302457dd1cde1\n" + - "97ec8075e82b393d542075134e2a17ee\n" + - "70a5e187075d03ae3c853cff60729ba4\n" + - "00000005\n" + - "4de1f6965bdabc676c5a4dc7c35f97f8\n" + - "2cb0e31c68d04f1dad96314ff09e6b3d\n" + - "e96aeee300d1f68bf1bca9fc58e40323\n" + - "36cd819aaf578744e50d1357a0e42867\n" + - "04d341aa0a337b19fe4bc43c2e79964d\n" + - "4f351089f2e0e41c7c43ae0d49e7f404\n" + - "b0f75be80ea3af098c9752420a8ac0ea\n" + - "2bbb1f4eeba05238aef0d8ce63f0c6e5\n" + - "e4041d95398a6f7f3e0ee97cc1591849\n" + - "d4ed236338b147abde9f51ef9fd4e1c1"; - - // Check generated signature matches vector. - Assert.True(Arrays.AreEqual(Hex.Decode(sigEnc), signature.GetEncoded())); - - // Sanity test - Assert.True(LMS.VerifySignature(publicKey, signature, msg)); - } - } -} diff --git a/crypto/test/src/pqc/crypto/lms/LMSTests.cs b/crypto/test/src/pqc/crypto/lms/LMSTests.cs deleted file mode 100644 index 7f7b4c089..000000000 --- a/crypto/test/src/pqc/crypto/lms/LMSTests.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; - -using NUnit.Framework; - -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Encoders; - -namespace Org.BouncyCastle.Pqc.Crypto.Lms -{ - [TestFixture] - public class LMSTests - { - [Test] - public void TestCoefFunc() - { - byte[] S = Hex.Decode("1234"); - Assert.AreEqual(0, LM_OTS.Coef(S, 7, 1)); - Assert.AreEqual(1, LM_OTS.Coef(S, 0, 4)); - } - - [Test] - public void TestPrivateKeyRound() - { - LMOtsParameters parameter = LMOtsParameters.sha256_n32_w4; - - byte[] seed = Hex.Decode("558b8966c48ae9cb898b423c83443aae014a72f1b1ab5cc85cf1d892903b5439"); - byte[] I = Hex.Decode("d08fabd4a2091ff0a8cb4ed834e74534"); - - LMOtsPrivateKey privateKey = new LMOtsPrivateKey(parameter, I, 0, seed); - LMOtsPublicKey publicKey = LM_OTS.LmsOtsGeneratePublicKey(privateKey); - - byte[] ms = new byte[32]; - for (int t = 0; t < ms.Length; t++) - { - ms[t] = (byte) t; - } - - LMSContext ctx = privateKey.GetSignatureContext(null, null); - - ctx.BlockUpdate(ms, 0, ms.Length); - - LMOtsSignature sig = LM_OTS.LMOtsGenerateSignature(privateKey, ctx.GetQ(), ctx.C); - Assert.True(LM_OTS.LMOtsValidateSignature(publicKey, sig, ms, false)); - - // Vandalise signature - { - - byte[] vandalisedSignature = sig.GetEncoded(); // Arrays.clone(sig); - vandalisedSignature[256] ^= 1; // Single bit error - Assert.False(LM_OTS.LMOtsValidateSignature(publicKey, LMOtsSignature.GetInstance(vandalisedSignature), ms, false)); - } - - // Vandalise public key. - { - byte[] vandalisedPubKey = Arrays.Clone(publicKey.GetEncoded()); - vandalisedPubKey[50] ^= 1; - Assert.False(LM_OTS.LMOtsValidateSignature(LMOtsPublicKey.GetInstance(vandalisedPubKey), sig, ms, false)); - } - - // - // check incorrect alg type is detected. - // - try - { - byte[] vandalisedPubKey = Arrays.Clone(publicKey.GetEncoded()); - vandalisedPubKey[3] += 1; - LM_OTS.LMOtsValidateSignature(LMOtsPublicKey.GetInstance(vandalisedPubKey), sig, ms, false); - Assert.True(false, "Must fail as public key type not match signature type."); - } - catch (LMSException ex) - { - Assert.True(ex.Message.Contains("public key and signature ots types do not match")); - } - } - - [Test] - public void TestLMS() - { - byte[] msg = Hex.Decode("54686520656e756d65726174696f6e20\n" + - "696e2074686520436f6e737469747574\n" + - "696f6e2c206f66206365727461696e20\n" + - "7269676874732c207368616c6c206e6f\n" + - "7420626520636f6e7374727565642074\n" + - "6f2064656e79206f7220646973706172\n" + - "616765206f7468657273207265746169\n" + - "6e6564206279207468652070656f706c\n" + - "652e0a"); - - byte[] seed = Hex.Decode("a1c4696e2608035a886100d05cd99945eb3370731884a8235e2fb3d4d71f2547"); - int level = 1; - LMSPrivateKeyParameters lmsPrivateKey = LMS.GenerateKeys( - LMSigParameters.GetParametersByID(5), - LMOtsParameters.GetParametersByID(4), - level, Hex.Decode("215f83b7ccb9acbcd08db97b0d04dc2b"), seed); - - LMSPublicKeyParameters publicKey = lmsPrivateKey.GetPublicKey(); - - lmsPrivateKey.ExtractKeyShard(3); - - LMSSignature signature = LMS.GenerateSign(lmsPrivateKey, msg); - Assert.True(LMS.VerifySignature(publicKey, signature, msg)); - - // Serialize / Deserialize - Assert.True(LMS.VerifySignature( - LMSPublicKeyParameters.GetInstance(publicKey.GetEncoded()), - LMSSignature.GetInstance(signature.GetEncoded()), msg)); - - // - // Vandalise signature. - // - { - byte[] bustedSig = Arrays.Clone(signature.GetEncoded()); - bustedSig[100] ^= 1; - Assert.False(LMS.VerifySignature(publicKey, LMSSignature.GetInstance(bustedSig), msg)); - } - - // - // Vandalise message - // - { - byte[] msg2 = Arrays.Clone(msg); - msg2[10] ^= 1; - Assert.False(LMS.VerifySignature(publicKey, signature, msg2)); - } - } - - [Test] - public void TestContextSingleUse() - { - LMOtsParameters parameter = LMOtsParameters.sha256_n32_w4; - - byte[] seed = Hex.Decode("558b8966c48ae9cb898b423c83443aae014a72f1b1ab5cc85cf1d892903b5439"); - byte[] I = Hex.Decode("d08fabd4a2091ff0a8cb4ed834e74534"); - - LMOtsPrivateKey privateKey = new LMOtsPrivateKey(parameter, I, 0, seed); - LMOtsPublicKey publicKey = LM_OTS.LmsOtsGeneratePublicKey(privateKey); - - byte[] ms = new byte[32]; - for (int t = 0; t < ms.Length; t++) - { - ms[t] = (byte)t; - } - - LMSContext ctx = privateKey.GetSignatureContext(null, null); - - ctx.BlockUpdate(ms, 0, ms.Length); - - LMOtsSignature sig = LM_OTS.LMOtsGenerateSignature(privateKey, ctx.GetQ(), ctx.C); - Assert.True(LM_OTS.LMOtsValidateSignature(publicKey, sig, ms, false)); - - try - { - ctx.Update((byte)1); - Assert.Fail("Digest reuse after signature taken."); - } - catch (NullReferenceException) - { - // Expected - } - } - } -} diff --git a/crypto/test/src/pqc/crypto/lms/LMSVectorUtils.cs b/crypto/test/src/pqc/crypto/lms/LMSVectorUtils.cs deleted file mode 100644 index 642e29f2d..000000000 --- a/crypto/test/src/pqc/crypto/lms/LMSVectorUtils.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.IO; - -using Org.BouncyCastle.Utilities.Encoders; - -namespace Org.BouncyCastle.Pqc.Crypto.Lms -{ - public class LMSVectorUtils - { - public static byte[] ExtractPrefixedBytes(string vectorFromRFC) - { - MemoryStream bos = new MemoryStream(); - byte[] hexByte; - foreach (string line in vectorFromRFC.Split('\n')) - { - int start = line.IndexOf('$'); - if (start > -1) - { - ++start; - int end = line.IndexOf('#'); - string hex; - if (end < 0) - { - hex = line.Substring(start).Trim(); - } - else - { - hex = line.Substring(start, end - start).Trim(); - } - - hexByte = Hex.Decode(hex); - bos.Write(hexByte, 0, hexByte.Length); - } - } - return bos.ToArray(); - } - } -} diff --git a/crypto/test/src/pqc/crypto/lms/TypeTests.cs b/crypto/test/src/pqc/crypto/lms/TypeTests.cs deleted file mode 100644 index ca64737b8..000000000 --- a/crypto/test/src/pqc/crypto/lms/TypeTests.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; - -using NUnit.Framework; - -namespace Org.BouncyCastle.Pqc.Crypto.Lms -{ - [TestFixture] - public class TypeTests - { - /** - * Get instance methods are expected to return the instance passed to them if it is the same type. - * - * @throws Exception - */ - [Test] - public void TestTypeForType() - { - LMSSignature dummySig = new LMSSignature(0, null, null, null); - - { - var keys = new List(); - keys.Add(new LMSPrivateKeyParameters(LMSigParameters.lms_sha256_n32_h5, null, 0, null, 0, new byte[32])); - - var sig = new List(); - sig.Add(dummySig); - - object o = new HSSPrivateKeyParameters(0, keys, sig, 1, 2); - Assert.True(o.Equals(HSSPrivateKeyParameters.GetInstance(o))); - } - - { - object o = new HSSPublicKeyParameters(0, null); - Assert.True(o.Equals(HSSPublicKeyParameters.GetInstance(o))); - } - - { - object o = new HSSSignature(0, null, null); - Assert.True(o.Equals(HSSSignature.GetInstance(o, 0))); - } - - { - object o = new LMOtsPublicKey(null, null, 0, null); - Assert.True(o.Equals(LMOtsPublicKey.GetInstance(o))); - } - - { - object o = new LMOtsSignature(null, null, null); - Assert.True(o.Equals(LMOtsSignature.GetInstance(o))); - } - - { - object o = new LMSPrivateKeyParameters(LMSigParameters.lms_sha256_n32_h5, null, 0, null, 0, null); - Assert.True(o.Equals(LMSPrivateKeyParameters.GetInstance(o))); - } - - { - object o = new LMSPublicKeyParameters(null, null, null, null); - Assert.True(o.Equals(LMSPublicKeyParameters.GetInstance(o))); - } - - { - object o = new LMSSignature(0, null, null, null); - Assert.True(o.Equals(LMSSignature.GetInstance(o))); - } - } - } -} diff --git a/crypto/test/src/pqc/crypto/lms/test/HssTests.cs b/crypto/test/src/pqc/crypto/lms/test/HssTests.cs new file mode 100644 index 000000000..fcc3cb9c6 --- /dev/null +++ b/crypto/test/src/pqc/crypto/lms/test/HssTests.cs @@ -0,0 +1,869 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using NUnit.Framework; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Pqc.Crypto.Lms.Tests +{ + [TestFixture] + public class HssTests + { + [Test] + public void TestHssKeySerialisation() + { + byte[] fixedSource = new byte[8192]; + for (int t = 0; t < fixedSource.Length; t++) + { + fixedSource[t] = 1; + } + + FixedSecureRandom.Source[] source = { new FixedSecureRandom.Source(fixedSource) }; + SecureRandom rand = new FixedSecureRandom(source); + + HSSPrivateKeyParameters generatedPrivateKey = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters(new LMSParameters[] + { + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), + }, rand) + ); + + HSSSignature sigFromGeneratedPrivateKey = HSS.GenerateSignature(generatedPrivateKey, Hex.Decode("ABCDEF")); + + byte[] keyPairEnc = generatedPrivateKey.GetEncoded(); + + HSSPrivateKeyParameters reconstructedPrivateKey = HSSPrivateKeyParameters.GetInstance(keyPairEnc); + Assert.True(reconstructedPrivateKey.Equals(generatedPrivateKey)); + + reconstructedPrivateKey.GetPublicKey(); + generatedPrivateKey.GetPublicKey(); + + // + // Are they still equal, public keys are only checked if they both + // exist because they are only created when requested as they are derived from the private key. + // + Assert.True(reconstructedPrivateKey.Equals(generatedPrivateKey)); + + // + // Check the reconstructed key can verify a signature. + // + Assert.True(HSS.VerifySignature(reconstructedPrivateKey.GetPublicKey(), sigFromGeneratedPrivateKey, + Hex.Decode("ABCDEF"))); + } + + /** + * Test Case 1 Signature + * From https://tools.ietf.org/html/rfc8554#appendix-F + */ + [Test] + public void TestHssVector_1() + { + var blocks = LoadVector("pqc.lms.testcase_1.txt"); + + HSSPublicKeyParameters publicKey = HSSPublicKeyParameters.GetInstance(blocks[0]); + byte[] message = blocks[1]; + HSSSignature signature = HSSSignature.GetInstance(blocks[2], publicKey.L); + Assert.True(HSS.VerifySignature(publicKey, signature, message), "Test Case 1 "); + } + + /** + * Test Case 1 Signature + * From https://tools.ietf.org/html/rfc8554#appendix-F + */ + [Test] + public void TestHssVector_2() + { + var blocks = LoadVector("pqc.lms.testcase_2.txt"); + + HSSPublicKeyParameters publicKey = HSSPublicKeyParameters.GetInstance(blocks[0]); + byte[] message = blocks[1]; + byte[] sig = blocks[2]; + HSSSignature signature = HSSSignature.GetInstance(sig, publicKey.L); + Assert.True(HSS.VerifySignature(publicKey, signature, message), "Test Case 2 Signature"); + + LMSPublicKeyParameters lmsPub = LMSPublicKeyParameters.GetInstance(blocks[3]); + LMSSignature lmsSignature = LMSSignature.GetInstance(blocks[4]); + + Assert.True(LMS.VerifySignature(lmsPub, lmsSignature, message), "Test Case 2 Signature 2"); + } + + private IList LoadVector(string vector) + { + StreamReader bin = new StreamReader(SimpleTest.GetTestDataAsStream(vector)); + var blocks = new List(); + StringBuilder sw = new StringBuilder(); + + string line; + while ((line = bin.ReadLine()) != null) + { + if (line.StartsWith("!")) + { + if (sw.Length > 0) + { + blocks.Add(LmsVectorUtilities.ExtractPrefixedBytes(sw.ToString())); + sw.Length = 0; + } + } + sw.Append(line); + sw.Append("\n"); + } + + if (sw.Length > 0) + { + blocks.Add(LmsVectorUtilities.ExtractPrefixedBytes(sw.ToString())); + sw.Length = 0; + } + return blocks; + } + + /** + * Test the generation of public keys from private key SEED and I. + * Level 0 + */ + [Test] + public void TestGenPublicKeys_L0() + { + byte[] seed = Hex.Decode("558b8966c48ae9cb898b423c83443aae014a72f1b1ab5cc85cf1d892903b5439"); + int level = 0; + LMSPrivateKeyParameters lmsPrivateKey = LMS.GenerateKeys(LMSigParameters.GetParametersByID(6), + LMOtsParameters.GetParametersByID(3), level, Hex.Decode("d08fabd4a2091ff0a8cb4ed834e74534"), seed); + LMSPublicKeyParameters publicKey = lmsPrivateKey.GetPublicKey(); + Assert.True(Arrays.AreEqual(publicKey.GetT1(), + Hex.Decode("32a58885cd9ba0431235466bff9651c6c92124404d45fa53cf161c28f1ad5a8e"))); + Assert.True(Arrays.AreEqual(publicKey.GetI(), Hex.Decode("d08fabd4a2091ff0a8cb4ed834e74534"))); + } + + /** + * Test the generation of public keys from private key SEED and I. + * Level 1; + */ + [Test] + public void TestGenPublicKeys_L1() + { + byte[] seed = Hex.Decode("a1c4696e2608035a886100d05cd99945eb3370731884a8235e2fb3d4d71f2547"); + int level = 1; + LMSPrivateKeyParameters lmsPrivateKey = LMS.GenerateKeys(LMSigParameters.GetParametersByID(5), + LMOtsParameters.GetParametersByID(4), level, Hex.Decode("215f83b7ccb9acbcd08db97b0d04dc2b"), seed); + LMSPublicKeyParameters publicKey = lmsPrivateKey.GetPublicKey(); + Assert.True(Arrays.AreEqual(publicKey.GetT1(), + Hex.Decode("a1cd035833e0e90059603f26e07ad2aad152338e7a5e5984bcd5f7bb4eba40b7"))); + Assert.True(Arrays.AreEqual(publicKey.GetI(), Hex.Decode("215f83b7ccb9acbcd08db97b0d04dc2b"))); + } + + [Test] + public void TestGenerate() + { + // + // Generate an HSS key pair for a two level HSS scheme. + // then use that to verify it compares with a value from the same reference implementation. + // Then check components of it serialize and deserialize properly. + // + byte[] fixedSource = new byte[8192]; + for (int t = 0; t < fixedSource.Length; t++) + { + fixedSource[t] = 1; + } + + FixedSecureRandom.Source[] source = { new FixedSecureRandom.Source(fixedSource) }; + SecureRandom rand = new FixedSecureRandom(source); + + HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters(new LMSParameters[] + { + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), + }, rand)); + + // + // Generated from reference implementation. + // check the encoded form of the public key matches. + // + string expectedPk = + "0000000200000005000000030101010101010101010101010101010166BF6F5816EEE4BBF33C50ACB480E09B4169EBB533372959BC4315C388E501AC"; + byte[] pkEnc = keyPair.GetPublicKey().GetEncoded(); + Assert.True(Arrays.AreEqual(Hex.Decode(expectedPk), pkEnc)); + + // + // Check that HSS public keys have value equality after deserialization. + // Use external sourced pk for deserialization. + // + Assert.True(keyPair.GetPublicKey().Equals(HSSPublicKeyParameters.GetInstance(Hex.Decode(expectedPk))), + "HSSPrivateKeyParameterss equal are deserialization"); + + // + // Generate, hopefully the same HSSKetPair for the same entropy. + // This is a sanity test + // + { + FixedSecureRandom.Source[] source1 = { new FixedSecureRandom.Source(fixedSource) }; + SecureRandom rand1 = new FixedSecureRandom(source1); + + HSSPrivateKeyParameters regenKeyPair = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters(new LMSParameters[] + { + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), + }, rand1)); + + Assert.True( + Arrays.AreEqual(regenKeyPair.GetPublicKey().GetEncoded(), keyPair.GetPublicKey().GetEncoded()), + "Both generated keys are the same"); + + Assert.True(keyPair.GetKeys().Count == regenKeyPair.GetKeys().Count, + "same private key size"); + + for (int t = 0; t < keyPair.GetKeys().Count; t++) + { + // + // Check the private keys can be encoded and are the same. + // + byte[] pk1 = keyPair.GetKeys()[t].GetEncoded(); + byte[] pk2 = regenKeyPair.GetKeys()[t].GetEncoded(); + Assert.True(Arrays.AreEqual(pk1, pk2)); + + // + // Deserialize them and see if they still equal. + // + LMSPrivateKeyParameters pk1O = LMSPrivateKeyParameters.GetInstance(pk1); + LMSPrivateKeyParameters pk2O = LMSPrivateKeyParameters.GetInstance(pk2); + + Assert.True(pk1O.Equals(pk2O), "LmsPrivateKey still equal after deserialization"); + + } + } + + // + // This time we will generate another set of keys using a different entropy source. + // they should be different! + // Useful for detecting accidental hard coded things. + // + + { + // Use a real secure random this time. + SecureRandom rand1 = new SecureRandom(); + + HSSPrivateKeyParameters differentKey = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters(new LMSParameters[] + { + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), + }, rand1) + ); + + Assert.False( + Arrays.AreEqual(differentKey.GetPublicKey().GetEncoded(), keyPair.GetPublicKey().GetEncoded()), + "Both generated keys are not the same"); + + for (int t = 0; t < keyPair.GetKeys().Count; t++) + { + // + // Check the private keys can be encoded and are not the same. + // + byte[] pk1 = keyPair.GetKeys()[t].GetEncoded(); + byte[] pk2 = differentKey.GetKeys()[t].GetEncoded(); + Assert.False(Arrays.AreEqual(pk1, pk2), "keys not the same"); + + // + // Deserialize them and see if they still equal. + // + LMSPrivateKeyParameters pk1O = LMSPrivateKeyParameters.GetInstance(pk1); + LMSPrivateKeyParameters pk2O = LMSPrivateKeyParameters.GetInstance(pk2); + + Assert.False(pk1O.Equals(pk2O), "LmsPrivateKey not suddenly equal after deserialization"); + } + } + } + + /** + * This test takes in a series of vectors generated by adding print statements to code called by + * the "test_sign.c" test in the reference implementation. + *

+ * The purpose of this test is to ensure that the signatures and public keys exactly match for the + * same entropy source the values generated by the reference implementation. + *

+ * It also verifies value equality between signature and public key objects as well as + * complimentary serialization and deserialization. + * + * @ + */ + [Test] + public void TestVectorsFromReference() + { + StreamReader sr = new StreamReader(SimpleTest.GetTestDataAsStream("pqc.lms.depth_1.txt")); + + var lmsParameters = new List(); + var lmOtsParameters = new List(); + byte[] message = null; + byte[] hssPubEnc = null; + MemoryStream fixedESBuffer = new MemoryStream(); + int d = 0, j = 0; + + string line; + while ((line = sr.ReadLine()) != null) + { + if (TrimLine(ref line)) + continue; + + if (line.StartsWith("Depth:")) + { + d = int.Parse(line.Substring("Depth:".Length).Trim()); + } + else if (line.StartsWith("LMType:")) + { + int typ = int.Parse(line.Substring("LMType:".Length).Trim()); + lmsParameters.Add(LMSigParameters.GetParametersByID(typ)); + } + else if (line.StartsWith("LMOtsType:")) + { + int typ = int.Parse(line.Substring("LMOtsType:".Length).Trim()); + lmOtsParameters.Add(LMOtsParameters.GetParametersByID(typ)); + } + else if (line.StartsWith("Rand:")) + { + var b = Hex.Decode(line.Substring("Rand:".Length).Trim()); + fixedESBuffer.Write(b, 0, b.Length); + } + else if (line.StartsWith("HSSPublicKey:")) + { + hssPubEnc = Hex.Decode(line.Substring("HSSPublicKey:".Length).Trim()); + } + else if (line.StartsWith("Message:")) + { + message = Hex.Decode(line.Substring("Message:".Length).Trim()); + } + else if (line.StartsWith("Signature:")) + { + j++; + + byte[] encodedSigFromVector = Hex.Decode(line.Substring("Signature:".Length).Trim()); + + // + // Assumes Signature is the last element in the set of vectors. + // + FixedSecureRandom.Source[] source = { new FixedSecureRandom.Source(fixedESBuffer.ToArray()) }; + FixedSecureRandom fixRnd = new FixedSecureRandom(source); + fixedESBuffer.SetLength(0);//todo is this correct? buffer.reset(); + //fixedESBuffer = new MemoryStream(); + + // + // Deserialize pub key from reference impl. + // + HSSPublicKeyParameters vectorSourcedPubKey = HSSPublicKeyParameters.GetInstance(hssPubEnc); + var lmsParams = new List(); + + for (int i = 0; i != lmsParameters.Count; i++) + { + lmsParams.Add(new LMSParameters(lmsParameters[i], lmOtsParameters[i])); + } + + // + // Using our fixed entropy source generate hss keypair + // + + LMSParameters[] lmsParamsArray = new LMSParameters[lmsParams.Count]; + lmsParams.CopyTo(lmsParamsArray, 0); + HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters( + lmsParamsArray, fixRnd) + ); + + { + // Public Key should match vector. + + // Encoded value equality. + HSSPublicKeyParameters generatedPubKey = keyPair.GetPublicKey(); + Assert.True(Arrays.AreEqual(hssPubEnc, generatedPubKey.GetEncoded())); + + // Value equality. + Assert.True(vectorSourcedPubKey.Equals(generatedPubKey)); + } + + // + // Generate a signature using the keypair we generated. + // + HSSSignature sig = HSS.GenerateSignature(keyPair, message); + + HSSSignature signatureFromVector = null; + if (!Arrays.AreEqual(sig.GetEncoded(), encodedSigFromVector)) + { + signatureFromVector = HSSSignature.GetInstance(encodedSigFromVector, d); + signatureFromVector.Equals(sig); + } + + // check encoding signature matches. + Assert.True(Arrays.AreEqual(sig.GetEncoded(), encodedSigFromVector)); + + // Check we can verify our generated signature with the vectors sourced public key. + Assert.True(HSS.VerifySignature(vectorSourcedPubKey, sig, message)); + + // Deserialize the signature from the vector. + signatureFromVector = HSSSignature.GetInstance(encodedSigFromVector, d); + + // Can we verify signature from vector with public key from vector. + Assert.True(HSS.VerifySignature(vectorSourcedPubKey, signatureFromVector, message)); + + // + // Check our generated signature and the one deserialized from the vector + // have value equality. + Assert.True(signatureFromVector.Equals(sig)); + + // + // Other tests vandalise HSS signatures to check they Assert.Fail when tampered with + // we won't do that again here. + // + d = 0; + lmOtsParameters.Clear(); + lmsParameters.Clear(); + message = null; + hssPubEnc = null; + } + } + } + + [Test] + public void TestVectorsFromReference_Expanded() + { + using (StreamReader sr = new StreamReader(SimpleTest.GetTestDataAsStream("pqc.lms.expansion.txt"))) + { + var lmsParameters = new List(); + var lmOtsParameters = new List(); + byte[] message = null; + byte[] hssPubEnc = null; + MemoryStream fixedESBuffer = new MemoryStream(); + var sigVectors = new List(); + int d = 0; + + string line; + while ((line = sr.ReadLine()) != null) + { + if (TrimLine(ref line)) + continue; + + if (line.StartsWith("Depth:")) + { + d = int.Parse(line.Substring("Depth:".Length).Trim()); + } + else if (line.StartsWith("LMType:")) + { + int typ = int.Parse(line.Substring("LMType:".Length).Trim()); + lmsParameters.Add(LMSigParameters.GetParametersByID(typ)); + } + else if (line.StartsWith("LMOtsType:")) + { + int typ = int.Parse(line.Substring("LMOtsType:".Length).Trim()); + lmOtsParameters.Add(LMOtsParameters.GetParametersByID(typ)); + } + else if (line.StartsWith("Rand:")) + { + var b = Hex.Decode(line.Substring("Rand:".Length).Trim()); + fixedESBuffer.Write(b, 0, b.Length); + } + else if (line.StartsWith("HSSPublicKey:")) + { + hssPubEnc = Hex.Decode(line.Substring("HSSPublicKey:".Length).Trim()); + } + else if (line.StartsWith("Message:")) + { + message = Hex.Decode(line.Substring("Message:".Length).Trim()); + + } + else if (line.StartsWith("Signature:")) + { + sigVectors.Add(Hex.Decode(line.Substring("Signature:".Length).Trim())); + } + } + + // + // Assumes Signature is the last element in the set of vectors. + // + FixedSecureRandom.Source[] source = { new FixedSecureRandom.Source(fixedESBuffer.ToArray()) }; + FixedSecureRandom fixRnd = new FixedSecureRandom(source); + fixedESBuffer.SetLength(0); + var lmsParams = new List(); + + for (int i = 0; i != lmsParameters.Count; i++) + { + lmsParams.Add(new LMSParameters(lmsParameters[i], lmOtsParameters[i])); + } + + LMSParameters[] lmsParamsArray = new LMSParameters[lmsParams.Count]; + lmsParams.CopyTo(lmsParamsArray, 0); + HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters(lmsParamsArray, fixRnd) + ); + + Assert.True(Arrays.AreEqual(hssPubEnc, keyPair.GetPublicKey().GetEncoded())); + + HSSPublicKeyParameters pubKeyFromVector = HSSPublicKeyParameters.GetInstance(hssPubEnc); + HSSPublicKeyParameters pubKeyGenerated = null; + + + Assert.AreEqual(1024, keyPair.GetUsagesRemaining()); + Assert.AreEqual(1024, keyPair.IndexLimit); + + // + // Split the space up with a shard. + // + + HSSPrivateKeyParameters shard1 = keyPair.ExtractKeyShard(500); + pubKeyGenerated = shard1.GetPublicKey(); + + + HSSPrivateKeyParameters pair = shard1; + + int c = 0; + for (int i = 0; i < keyPair.IndexLimit; i++) + { + if (i == 500) + { + try + { + HSS.IncrementIndex(pair); + Assert.Fail("shard should be exhausted."); + } + catch (Exception ex) + { + Assert.AreEqual("hss private key shard is exhausted", ex.Message); + } + + pair = keyPair; + pubKeyGenerated = keyPair.GetPublicKey(); + + Assert.AreEqual(pubKeyGenerated, shard1.GetPublicKey()); + } + + if (i % 5 == 0) + { + HSSSignature sigCalculated = HSS.GenerateSignature(pair, message); + Assert.True(Arrays.AreEqual(sigCalculated.GetEncoded(), sigVectors[c])); + + Assert.True(HSS.VerifySignature(pubKeyFromVector, sigCalculated, message)); + Assert.True(HSS.VerifySignature(pubKeyGenerated, sigCalculated, message)); + + HSSSignature sigFromVector = HSSSignature.GetInstance(sigVectors[c], + pubKeyFromVector.L); + + Assert.True(HSS.VerifySignature(pubKeyFromVector, sigFromVector, message)); + Assert.True(HSS.VerifySignature(pubKeyGenerated, sigFromVector, message)); + + + Assert.True(sigCalculated.Equals(sigFromVector)); + + + c++; + } + else + { + HSS.IncrementIndex(pair); + } + } + } + } + + /** + * Test remaining calculation is accurate and a new key is generated when + * all the ots keys for that level are consumed. + * + * @ + */ + [Test] + public void TestRemaining() + { + HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters(new LMSParameters[] + { + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2) + }, new SecureRandom()) + ); + + + LMSPrivateKeyParameters lmsKey = keyPair.GetKeys()[keyPair.L - 1]; + // + // There should be a max of 32768 signatures for this key. + // + Assert.True(1024 == keyPair.GetUsagesRemaining()); + + HSS.IncrementIndex(keyPair); + HSS.IncrementIndex(keyPair); + HSS.IncrementIndex(keyPair); + HSS.IncrementIndex(keyPair); + HSS.IncrementIndex(keyPair); + + Assert.True(5 == keyPair.GetIndex()); // Next key is at index 5! + + Assert.True(1024 - 5 == keyPair.GetUsagesRemaining()); + + HSSPrivateKeyParameters shard = keyPair.ExtractKeyShard(10); + + Assert.True(15 == shard.IndexLimit); + Assert.True(5 == shard.GetIndex()); + + // Should not be the same. + Assert.False(shard.GetIndex() == keyPair.GetIndex()); + + // + // Should be 17 left, it will throw if it has been exhausted. + // + for (int t = 0; t < 17; t++) + { + HSS.IncrementIndex(keyPair); + } + + // We have used 32 keys. + Assert.True(1024 - 32 == keyPair.GetUsagesRemaining()); + + HSS.GenerateSignature(keyPair, Encoding.ASCII.GetBytes("Foo")); + + // + // This should trigger the generation of a new key. + // + LMSPrivateKeyParameters potentialNewLMSKey = keyPair.GetKeys()[keyPair.L - 1]; + Assert.False(potentialNewLMSKey.Equals(lmsKey)); + } + + [Test] + public void TestSharding() + { + HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters(new LMSParameters[] + { + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2) + }, new SecureRandom()) + ); + + Assert.True(1024 == keyPair.GetUsagesRemaining()); + Assert.True(1024 == keyPair.IndexLimit); + Assert.True(0 == keyPair.GetIndex()); + Assert.False(keyPair.IsShard()); + HSS.IncrementIndex(keyPair); + + + // + // Take a shard that should cross boundaries + // + HSSPrivateKeyParameters shard = keyPair.ExtractKeyShard(48); + Assert.True(shard.IsShard()); + Assert.True(48 == shard.GetUsagesRemaining()); + Assert.True(49 == shard.IndexLimit); + Assert.True(1 == shard.GetIndex()); + + Assert.True(49 == keyPair.GetIndex()); + + + int t = 47; + while (--t >= 0) + { + HSS.IncrementIndex(shard); + } + + HSSSignature sig = HSS.GenerateSignature(shard, Encoding.ASCII.GetBytes("Cats")); + + // + // Test it validates and nothing has gone wrong with the public keys. + // + Assert.True(HSS.VerifySignature(keyPair.GetPublicKey(), sig, Encoding.ASCII.GetBytes("Cats"))); + Assert.True(HSS.VerifySignature(shard.GetPublicKey(), sig, Encoding.ASCII.GetBytes("Cats"))); + + // Signing again should Assert.Fail. + + try + { + HSS.GenerateSignature(shard, Encoding.ASCII.GetBytes("Cats")); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.True(ex.Message.Equals("hss private key shard is exhausted")); + } + + // Should work without throwing. + HSS.GenerateSignature(keyPair, Encoding.ASCII.GetBytes("Cats")); + } + + /** + * Take an HSS key pair and exhaust its signing capacity. + * + * @ + */ + internal class HSSSecureRandom + : SecureRandom + { + internal HSSSecureRandom() + : base(null) + { + } + + public override void NextBytes(byte[] buf) + { + NextBytes(buf, 0, buf.Length); + } + + public override void NextBytes(byte[] buf, int off, int len) + { + for (int t = 0; t < len; t++) + { + buf[off + t] = 1; + } + } + } + + [Test] + public void TestSignUnitExhaustion() + { + HSSSecureRandom rand = new HSSSecureRandom(); + + HSSPrivateKeyParameters keyPair = HSS.GenerateHssKeyPair( + new HSSKeyGenerationParameters(new LMSParameters[] + { + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w2), + new LMSParameters(LMSigParameters.lms_sha256_n32_h10, LMOtsParameters.sha256_n32_w1), + }, rand) + ); + + HSSPublicKeyParameters pk = keyPair.GetPublicKey(); + + + int ctr = 0; + byte[] message = new byte[32]; + + // + // There should be a max of 32768 signatures for this key. + // + + Assert.True(keyPair.GetUsagesRemaining() == 32768); + + int mod = 256; + try + { + while (ctr < 32769) // Just a number.. + { + if (ctr % mod == 0) + { + // + // We don't want to check every key. + // The test will take over an hour to complete. + // + Pack_Int32_To_BE(ctr, message, 0); + HSSSignature sig = HSS.GenerateSignature(keyPair, message); + + Assert.True(ctr % 1024 == sig.Signature.Q); + + // Check there was a post increment in the tail end LMS key. + Assert.True(ctr % 1024 + 1 == keyPair.GetKeys()[keyPair.L - 1].GetIndex()); + + Assert.True(ctr + 1 == keyPair.GetIndex()); + + + // Validate the heirarchial path building was correct. + + long[] qValues = new long[keyPair.GetKeys().Count]; + long q = ctr; + + for (int t = keyPair.GetKeys().Count - 1; t >= 0; t--) + { + LMSigParameters sigParameters = keyPair.GetKeys()[t].GetSigParameters(); + int mask = (1 << sigParameters.H) - 1; + qValues[t] = q & mask; + q >>= sigParameters.H; + } + + for (int t = 0; t < keyPair.GetKeys().Count; t++) + { + Assert.True(keyPair.GetKeys()[t].GetIndex() - 1 == qValues[t]); + } + + Assert.True(HSS.VerifySignature(pk, sig, message)); + Assert.True(sig.Signature.SigParameters.ID == LMSigParameters.lms_sha256_n32_h10.ID); + + { + // + // Vandalise hss signature. + // + byte[] rawSig = sig.GetEncoded(); + rawSig[100] ^= 1; + HSSSignature parsedSig = HSSSignature.GetInstance(rawSig, pk.L); + Assert.False(HSS.VerifySignature(pk, parsedSig, message)); + + try + { + HSSSignature.GetInstance(rawSig, 0); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.True(ex.Message.Contains("nspk exceeded maxNspk")); + } + + } + + { + // + // Vandalise hss message + // + byte[] newMsg = new byte[message.Length]; + message.CopyTo(newMsg, 0); + newMsg[1] ^= 1; + Assert.False(HSS.VerifySignature(pk, sig, newMsg)); + } + + { + // + // Vandalise public key + // + byte[] pkEnc = pk.GetEncoded(); + pkEnc[35] ^= 1; + HSSPublicKeyParameters rebuiltPk = HSSPublicKeyParameters.GetInstance(pkEnc); + Assert.False(HSS.VerifySignature(rebuiltPk, sig, message)); + } + } + else + { + // Skip some keys. + HSS.IncrementIndex(keyPair); + } + + ctr++; + } + + //System.out.Println(ctr); + Assert.Fail(); + } + catch (Exception ex) + { + Assert.True(keyPair.GetUsagesRemaining() == 0); + Assert.True(ctr == 32768); + Assert.True(ex.Message.Contains("hss private key is exhausted")); + } + } + + private static void Pack_Int32_To_BE(int n, byte[] bs, int off) + { + bs[off] = (byte)(n >> 24); + bs[off + 1] = (byte)(n >> 16); + bs[off + 2] = (byte)(n >> 8); + bs[off + 3] = (byte)n; + } + + private static bool TrimLine(ref string line) + { + int commentPos = line.IndexOf('#'); + if (commentPos >= 0) + { + line = line.Substring(0, commentPos); + } + + line = line.Trim(); + + return line.Length < 1; + } + } +} diff --git a/crypto/test/src/pqc/crypto/lms/test/LmsKeyGenTests.cs b/crypto/test/src/pqc/crypto/lms/test/LmsKeyGenTests.cs new file mode 100644 index 000000000..fb66db457 --- /dev/null +++ b/crypto/test/src/pqc/crypto/lms/test/LmsKeyGenTests.cs @@ -0,0 +1,146 @@ +using NUnit.Framework; + +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Pqc.Crypto.Lms.Tests +{ + [TestFixture] + public class LmsKeyGenTests + { + [Test] + public void TestGeneratePrivateKey() + { + // + // This is based on the second set of vectors and the second signature. + // We verify the correct private key is generated if the correct public key is + // derived from it. + // + byte[] msg = Hex.Decode("54686520656e756d65726174696f6e20\n" + + "696e2074686520436f6e737469747574\n" + + "696f6e2c206f66206365727461696e20\n" + + "7269676874732c207368616c6c206e6f\n" + + "7420626520636f6e7374727565642074\n" + + "6f2064656e79206f7220646973706172\n" + + "616765206f7468657273207265746169\n" + + "6e6564206279207468652070656f706c\n" + + "652e0a"); + + // From vector. + byte[] seed = Hex.Decode("a1c4696e2608035a886100d05cd99945eb3370731884a8235e2fb3d4d71f2547"); + byte[] I = Hex.Decode("215f83b7ccb9acbcd08db97b0d04dc2b"); + int level = 1; // This is the second level, we use this because it signs the message. + + // Generate the private key. + LMSPrivateKeyParameters lmsPrivateKey = LMS.GenerateKeys(LMSigParameters.GetParametersByID(5), + LMOtsParameters.GetParametersByID(4), level, I, seed); + + // This derives the public key. + LMSPublicKeyParameters publicKey = lmsPrivateKey.GetPublicKey(); + + // From the vector. + string pkEnc = "0000000500000004215f83b7ccb9acbcd08db97b0d04dc2ba1cd035833e0e90059603f26e07ad2aad152338e7a5e5984bcd5f7bb4eba40b7"; + + // Test public key encoded matched vector. + Assert.True(Arrays.AreEqual(Hex.Decode(pkEnc), publicKey.GetEncoded())); + + // + // Fast forward and burn off some OTS private keys until we get to key number 4. + // + lmsPrivateKey.ExtractKeyShard(3); + + LMSSignature signature = LMS.GenerateSign(lmsPrivateKey, msg); + + // The expected signature as encoded. + string sigEnc = "00000004\n" + + "00000004\n" + + "0eb1ed54a2460d512388cad533138d24\n" + + "0534e97b1e82d33bd927d201dfc24ebb\n" + + "11b3649023696f85150b189e50c00e98\n" + + "850ac343a77b3638319c347d7310269d\n" + + "3b7714fa406b8c35b021d54d4fdada7b\n" + + "9ce5d4ba5b06719e72aaf58c5aae7aca\n" + + "057aa0e2e74e7dcfd17a0823429db629\n" + + "65b7d563c57b4cec942cc865e29c1dad\n" + + "83cac8b4d61aacc457f336e6a10b6632\n" + + "3f5887bf3523dfcadee158503bfaa89d\n" + + "c6bf59daa82afd2b5ebb2a9ca6572a60\n" + + "67cee7c327e9039b3b6ea6a1edc7fdc3\n" + + "df927aade10c1c9f2d5ff446450d2a39\n" + + "98d0f9f6202b5e07c3f97d2458c69d3c\n" + + "8190643978d7a7f4d64e97e3f1c4a08a\n" + + "7c5bc03fd55682c017e2907eab07e5bb\n" + + "2f190143475a6043d5e6d5263471f4ee\n" + + "cf6e2575fbc6ff37edfa249d6cda1a09\n" + + "f797fd5a3cd53a066700f45863f04b6c\n" + + "8a58cfd341241e002d0d2c0217472bf1\n" + + "8b636ae547c1771368d9f317835c9b0e\n" + + "f430b3df4034f6af00d0da44f4af7800\n" + + "bc7a5cf8a5abdb12dc718b559b74cab9\n" + + "090e33cc58a955300981c420c4da8ffd\n" + + "67df540890a062fe40dba8b2c1c548ce\n" + + "d22473219c534911d48ccaabfb71bc71\n" + + "862f4a24ebd376d288fd4e6fb06ed870\n" + + "5787c5fedc813cd2697e5b1aac1ced45\n" + + "767b14ce88409eaebb601a93559aae89\n" + + "3e143d1c395bc326da821d79a9ed41dc\n" + + "fbe549147f71c092f4f3ac522b5cc572\n" + + "90706650487bae9bb5671ecc9ccc2ce5\n" + + "1ead87ac01985268521222fb9057df7e\n" + + "d41810b5ef0d4f7cc67368c90f573b1a\n" + + "c2ce956c365ed38e893ce7b2fae15d36\n" + + "85a3df2fa3d4cc098fa57dd60d2c9754\n" + + "a8ade980ad0f93f6787075c3f680a2ba\n" + + "1936a8c61d1af52ab7e21f416be09d2a\n" + + "8d64c3d3d8582968c2839902229f85ae\n" + + "e297e717c094c8df4a23bb5db658dd37\n" + + "7bf0f4ff3ffd8fba5e383a48574802ed\n" + + "545bbe7a6b4753533353d73706067640\n" + + "135a7ce517279cd683039747d218647c\n" + + "86e097b0daa2872d54b8f3e508598762\n" + + "9547b830d8118161b65079fe7bc59a99\n" + + "e9c3c7380e3e70b7138fe5d9be255150\n" + + "2b698d09ae193972f27d40f38dea264a\n" + + "0126e637d74ae4c92a6249fa103436d3\n" + + "eb0d4029ac712bfc7a5eacbdd7518d6d\n" + + "4fe903a5ae65527cd65bb0d4e9925ca2\n" + + "4fd7214dc617c150544e423f450c99ce\n" + + "51ac8005d33acd74f1bed3b17b7266a4\n" + + "a3bb86da7eba80b101e15cb79de9a207\n" + + "852cf91249ef480619ff2af8cabca831\n" + + "25d1faa94cbb0a03a906f683b3f47a97\n" + + "c871fd513e510a7a25f283b196075778\n" + + "496152a91c2bf9da76ebe089f4654877\n" + + "f2d586ae7149c406e663eadeb2b5c7e8\n" + + "2429b9e8cb4834c83464f079995332e4\n" + + "b3c8f5a72bb4b8c6f74b0d45dc6c1f79\n" + + "952c0b7420df525e37c15377b5f09843\n" + + "19c3993921e5ccd97e097592064530d3\n" + + "3de3afad5733cbe7703c5296263f7734\n" + + "2efbf5a04755b0b3c997c4328463e84c\n" + + "aa2de3ffdcd297baaaacd7ae646e44b5\n" + + "c0f16044df38fabd296a47b3a838a913\n" + + "982fb2e370c078edb042c84db34ce36b\n" + + "46ccb76460a690cc86c302457dd1cde1\n" + + "97ec8075e82b393d542075134e2a17ee\n" + + "70a5e187075d03ae3c853cff60729ba4\n" + + "00000005\n" + + "4de1f6965bdabc676c5a4dc7c35f97f8\n" + + "2cb0e31c68d04f1dad96314ff09e6b3d\n" + + "e96aeee300d1f68bf1bca9fc58e40323\n" + + "36cd819aaf578744e50d1357a0e42867\n" + + "04d341aa0a337b19fe4bc43c2e79964d\n" + + "4f351089f2e0e41c7c43ae0d49e7f404\n" + + "b0f75be80ea3af098c9752420a8ac0ea\n" + + "2bbb1f4eeba05238aef0d8ce63f0c6e5\n" + + "e4041d95398a6f7f3e0ee97cc1591849\n" + + "d4ed236338b147abde9f51ef9fd4e1c1"; + + // Check generated signature matches vector. + Assert.True(Arrays.AreEqual(Hex.Decode(sigEnc), signature.GetEncoded())); + + // Sanity test + Assert.True(LMS.VerifySignature(publicKey, signature, msg)); + } + } +} diff --git a/crypto/test/src/pqc/crypto/lms/test/LmsTests.cs b/crypto/test/src/pqc/crypto/lms/test/LmsTests.cs new file mode 100644 index 000000000..5a7a84031 --- /dev/null +++ b/crypto/test/src/pqc/crypto/lms/test/LmsTests.cs @@ -0,0 +1,162 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Pqc.Crypto.Lms.Tests +{ + [TestFixture] + public class LmsTests + { + [Test] + public void TestCoefFunc() + { + byte[] S = Hex.Decode("1234"); + Assert.AreEqual(0, LM_OTS.Coef(S, 7, 1)); + Assert.AreEqual(1, LM_OTS.Coef(S, 0, 4)); + } + + [Test] + public void TestPrivateKeyRound() + { + LMOtsParameters parameter = LMOtsParameters.sha256_n32_w4; + + byte[] seed = Hex.Decode("558b8966c48ae9cb898b423c83443aae014a72f1b1ab5cc85cf1d892903b5439"); + byte[] I = Hex.Decode("d08fabd4a2091ff0a8cb4ed834e74534"); + + LMOtsPrivateKey privateKey = new LMOtsPrivateKey(parameter, I, 0, seed); + LMOtsPublicKey publicKey = LM_OTS.LmsOtsGeneratePublicKey(privateKey); + + byte[] ms = new byte[32]; + for (int t = 0; t < ms.Length; t++) + { + ms[t] = (byte)t; + } + + LMSContext ctx = privateKey.GetSignatureContext(null, null); + + ctx.BlockUpdate(ms, 0, ms.Length); + + LMOtsSignature sig = LM_OTS.LMOtsGenerateSignature(privateKey, ctx.GetQ(), ctx.C); + Assert.True(LM_OTS.LMOtsValidateSignature(publicKey, sig, ms, false)); + + // Vandalise signature + { + + byte[] vandalisedSignature = sig.GetEncoded(); // Arrays.clone(sig); + vandalisedSignature[256] ^= 1; // Single bit error + Assert.False(LM_OTS.LMOtsValidateSignature(publicKey, LMOtsSignature.GetInstance(vandalisedSignature), ms, false)); + } + + // Vandalise public key. + { + byte[] vandalisedPubKey = Arrays.Clone(publicKey.GetEncoded()); + vandalisedPubKey[50] ^= 1; + Assert.False(LM_OTS.LMOtsValidateSignature(LMOtsPublicKey.GetInstance(vandalisedPubKey), sig, ms, false)); + } + + // + // check incorrect alg type is detected. + // + try + { + byte[] vandalisedPubKey = Arrays.Clone(publicKey.GetEncoded()); + vandalisedPubKey[3] += 1; + LM_OTS.LMOtsValidateSignature(LMOtsPublicKey.GetInstance(vandalisedPubKey), sig, ms, false); + Assert.True(false, "Must fail as public key type not match signature type."); + } + catch (LMSException ex) + { + Assert.True(ex.Message.Contains("public key and signature ots types do not match")); + } + } + + [Test] + public void TestLMS() + { + byte[] msg = Hex.Decode("54686520656e756d65726174696f6e20\n" + + "696e2074686520436f6e737469747574\n" + + "696f6e2c206f66206365727461696e20\n" + + "7269676874732c207368616c6c206e6f\n" + + "7420626520636f6e7374727565642074\n" + + "6f2064656e79206f7220646973706172\n" + + "616765206f7468657273207265746169\n" + + "6e6564206279207468652070656f706c\n" + + "652e0a"); + + byte[] seed = Hex.Decode("a1c4696e2608035a886100d05cd99945eb3370731884a8235e2fb3d4d71f2547"); + int level = 1; + LMSPrivateKeyParameters lmsPrivateKey = LMS.GenerateKeys( + LMSigParameters.GetParametersByID(5), + LMOtsParameters.GetParametersByID(4), + level, Hex.Decode("215f83b7ccb9acbcd08db97b0d04dc2b"), seed); + + LMSPublicKeyParameters publicKey = lmsPrivateKey.GetPublicKey(); + + lmsPrivateKey.ExtractKeyShard(3); + + LMSSignature signature = LMS.GenerateSign(lmsPrivateKey, msg); + Assert.True(LMS.VerifySignature(publicKey, signature, msg)); + + // Serialize / Deserialize + Assert.True(LMS.VerifySignature( + LMSPublicKeyParameters.GetInstance(publicKey.GetEncoded()), + LMSSignature.GetInstance(signature.GetEncoded()), msg)); + + // + // Vandalise signature. + // + { + byte[] bustedSig = Arrays.Clone(signature.GetEncoded()); + bustedSig[100] ^= 1; + Assert.False(LMS.VerifySignature(publicKey, LMSSignature.GetInstance(bustedSig), msg)); + } + + // + // Vandalise message + // + { + byte[] msg2 = Arrays.Clone(msg); + msg2[10] ^= 1; + Assert.False(LMS.VerifySignature(publicKey, signature, msg2)); + } + } + + [Test] + public void TestContextSingleUse() + { + LMOtsParameters parameter = LMOtsParameters.sha256_n32_w4; + + byte[] seed = Hex.Decode("558b8966c48ae9cb898b423c83443aae014a72f1b1ab5cc85cf1d892903b5439"); + byte[] I = Hex.Decode("d08fabd4a2091ff0a8cb4ed834e74534"); + + LMOtsPrivateKey privateKey = new LMOtsPrivateKey(parameter, I, 0, seed); + LMOtsPublicKey publicKey = LM_OTS.LmsOtsGeneratePublicKey(privateKey); + + byte[] ms = new byte[32]; + for (int t = 0; t < ms.Length; t++) + { + ms[t] = (byte)t; + } + + LMSContext ctx = privateKey.GetSignatureContext(null, null); + + ctx.BlockUpdate(ms, 0, ms.Length); + + LMOtsSignature sig = LM_OTS.LMOtsGenerateSignature(privateKey, ctx.GetQ(), ctx.C); + Assert.True(LM_OTS.LMOtsValidateSignature(publicKey, sig, ms, false)); + + try + { + ctx.Update(1); + Assert.Fail("Digest reuse after signature taken."); + } + catch (NullReferenceException) + { + // Expected + } + } + } +} diff --git a/crypto/test/src/pqc/crypto/lms/test/LmsVectorUtilities.cs b/crypto/test/src/pqc/crypto/lms/test/LmsVectorUtilities.cs new file mode 100644 index 000000000..3ad03b0e1 --- /dev/null +++ b/crypto/test/src/pqc/crypto/lms/test/LmsVectorUtilities.cs @@ -0,0 +1,37 @@ +using System.IO; + +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Pqc.Crypto.Lms.Tests +{ + public class LmsVectorUtilities + { + public static byte[] ExtractPrefixedBytes(string vectorFromRFC) + { + MemoryStream bos = new MemoryStream(); + byte[] hexByte; + foreach (string line in vectorFromRFC.Split('\n')) + { + int start = line.IndexOf('$'); + if (start > -1) + { + ++start; + int end = line.IndexOf('#'); + string hex; + if (end < 0) + { + hex = line.Substring(start).Trim(); + } + else + { + hex = line.Substring(start, end - start).Trim(); + } + + hexByte = Hex.Decode(hex); + bos.Write(hexByte, 0, hexByte.Length); + } + } + return bos.ToArray(); + } + } +} diff --git a/crypto/test/src/pqc/crypto/lms/test/TypeTests.cs b/crypto/test/src/pqc/crypto/lms/test/TypeTests.cs new file mode 100644 index 000000000..948ce4747 --- /dev/null +++ b/crypto/test/src/pqc/crypto/lms/test/TypeTests.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; + +using NUnit.Framework; + +namespace Org.BouncyCastle.Pqc.Crypto.Lms.Tests +{ + [TestFixture] + public class TypeTests + { + /** + * Get instance methods are expected to return the instance passed to them if it is the same type. + * + * @throws Exception + */ + [Test] + public void TestTypeForType() + { + LMSSignature dummySig = new LMSSignature(0, null, null, null); + + { + var keys = new List(); + keys.Add(new LMSPrivateKeyParameters(LMSigParameters.lms_sha256_n32_h5, null, 0, null, 0, new byte[32])); + + var sig = new List(); + sig.Add(dummySig); + + object o = new HSSPrivateKeyParameters(0, keys, sig, 1, 2); + Assert.True(o.Equals(HSSPrivateKeyParameters.GetInstance(o))); + } + + { + object o = new HSSPublicKeyParameters(0, null); + Assert.True(o.Equals(HSSPublicKeyParameters.GetInstance(o))); + } + + { + object o = new HSSSignature(0, null, null); + Assert.True(o.Equals(HSSSignature.GetInstance(o, 0))); + } + + { + object o = new LMOtsPublicKey(null, null, 0, null); + Assert.True(o.Equals(LMOtsPublicKey.GetInstance(o))); + } + + { + object o = new LMOtsSignature(null, null, null); + Assert.True(o.Equals(LMOtsSignature.GetInstance(o))); + } + + { + object o = new LMSPrivateKeyParameters(LMSigParameters.lms_sha256_n32_h5, null, 0, null, 0, null); + Assert.True(o.Equals(LMSPrivateKeyParameters.GetInstance(o))); + } + + { + object o = new LMSPublicKeyParameters(null, null, null, null); + Assert.True(o.Equals(LMSPublicKeyParameters.GetInstance(o))); + } + + { + object o = new LMSSignature(0, null, null, null); + Assert.True(o.Equals(LMSSignature.GetInstance(o))); + } + } + } +} -- cgit 1.4.1