diff --git a/crypto/src/pqc/crypto/lms/HSS.cs b/crypto/src/pqc/crypto/lms/HSS.cs
index 4634088c7..75d8a0558 100644
--- a/crypto/src/pqc/crypto/lms/HSS.cs
+++ b/crypto/src/pqc/crypto/lms/HSS.cs
@@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
+using Org.BouncyCastle.Security;
+
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public static class Hss
{
public static HssPrivateKeyParameters GenerateHssKeyPair(HssKeyGenerationParameters parameters)
@@ -13,11 +16,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
LmsPrivateKeyParameters[] keys = new LmsPrivateKeyParameters[parameters.Depth];
LmsSignature[] sig = new LmsSignature[parameters.Depth - 1];
- byte[] rootSeed = new byte[32];
- parameters.Random.NextBytes(rootSeed);
-
- byte[] I = new byte[16];
- parameters.Random.NextBytes(I);
+ byte[] rootSeed = SecureRandom.GetNextBytes(parameters.Random,
+ parameters.GetLmsParameters(0).LMSigParameters.M);
+ byte[] I = SecureRandom.GetNextBytes(parameters.Random, 16);
//
// Set the HSS key up with a valid root LMSPrivateKeyParameters and placeholders for the remaining LMS keys.
@@ -85,7 +86,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
RangeTestKeys(keyPair);
keyPair.IncIndex();
- keyPair.GetKeys()[keyPair.L - 1].IncIndex();
+ keyPair.GetKeys()[keyPair.Level - 1].IncIndex();
}
}
@@ -95,18 +96,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
if (keyPair.GetIndex() >= keyPair.IndexLimit)
{
+ // TODO ExhaustedPrivateKeyException
throw new Exception(
- "hss private key" +
- ((keyPair.IsShard()) ? " shard" : "") +
- " is exhausted");
+ "hss private key" + (keyPair.IsShard() ? " shard" : "") + " is exhausted");
}
- int L = keyPair.L;
+ int L = keyPair.Level;
int d = L;
var prv = keyPair.GetKeys();
while (prv[d - 1].GetIndex() == 1 << prv[d - 1].GetSigParameters().H)
{
if (--d == 0)
+ // TODO ExhaustedPrivateKeyException
throw new Exception("hss private key" + (keyPair.IsShard() ? " shard" : "") +
" is exhausted the maximum limit for this HSS private key");
}
@@ -118,12 +119,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
}
}
-
public static HssSignature GenerateSignature(HssPrivateKeyParameters keyPair, byte[] message)
{
LmsSignedPubKey[] signed_pub_key;
LmsPrivateKeyParameters nextKey;
- int L = keyPair.L;
+ int L = keyPair.Level;
lock (keyPair)
{
@@ -163,8 +163,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public static bool VerifySignature(HssPublicKeyParameters publicKey, HssSignature signature, byte[] message)
{
- int Nspk = signature.GetLMinus1();
- if (Nspk + 1 != publicKey.L)
+ int Nspk = signature.LMinus1;
+ if (Nspk + 1 != publicKey.Level)
return false;
LmsSignature[] sigList = new LmsSignature[Nspk + 1];
@@ -172,8 +172,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
for (int i = 0; i < Nspk; i++)
{
- sigList[i] = signature.GetSignedPubKeys()[i].GetSignature();
- pubList[i] = signature.GetSignedPubKeys()[i].GetPublicKey();
+ sigList[i] = signature.SignedPubKeys[i].Signature;
+ pubList[i] = signature.SignedPubKeys[i].PublicKey;
}
sigList[Nspk] = signature.Signature;
@@ -184,9 +184,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
LmsSignature sig = sigList[i];
byte[] msg = pubList[i].ToByteArray();
if (!Lms.VerifySignature(key, sig, msg))
- {
return false;
- }
+
try
{
key = pubList[i];
diff --git a/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
index 676da3db4..cda020b82 100644
--- a/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
@@ -11,25 +11,25 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public class HssPrivateKeyParameters
: LmsKeyParameters, ILmsContextBasedSigner
{
- private int l;
- private bool isShard;
- private IList<LmsPrivateKeyParameters> keys;
- private IList<LmsSignature> sig;
- private long indexLimit;
- private long index = 0;
+ private readonly int m_level;
+ private readonly bool m_isShard;
+ private IList<LmsPrivateKeyParameters> m_keys;
+ private IList<LmsSignature> m_sig;
+ private readonly long m_indexLimit;
+ private long m_index = 0;
- private HssPublicKeyParameters publicKey;
+ private HssPublicKeyParameters m_publicKey;
public HssPrivateKeyParameters(int l, IList<LmsPrivateKeyParameters> keys, IList<LmsSignature> sig, long index,
long indexLimit)
- :base(true)
+ : base(true)
{
- this.l = l;
- this.keys = new List<LmsPrivateKeyParameters>(keys);
- this.sig = new List<LmsSignature>(sig);
- this.index = index;
- this.indexLimit = indexLimit;
- this.isShard = false;
+ m_level = l;
+ m_isShard = false;
+ m_keys = new List<LmsPrivateKeyParameters>(keys);
+ m_sig = new List<LmsSignature>(sig);
+ m_index = index;
+ m_indexLimit = indexLimit;
//
// Correct Intermediate LMS values will be constructed during reset to index.
@@ -42,22 +42,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
:base(true)
{
- this.l = l;
- // this.keys = new UnmodifiableListProxy(keys);
- // this.sig = new UnmodifiableListProxy(sig);
- this.keys = new List<LmsPrivateKeyParameters>(keys);
- this.sig = new List<LmsSignature>(sig);
- this.index = index;
- this.indexLimit = indexLimit;
- this.isShard = isShard;
+ m_level = l;
+ m_isShard = isShard;
+ m_keys = new List<LmsPrivateKeyParameters>(keys);
+ m_sig = new List<LmsSignature>(sig);
+ m_index = index;
+ m_indexLimit = indexLimit;
}
public static HssPrivateKeyParameters GetInstance(byte[] privEnc, byte[] pubEnc)
{
HssPrivateKeyParameters pKey = GetInstance(privEnc);
-
- pKey.publicKey = HssPublicKeyParameters.GetInstance(pubEnc);
-
+ pKey.m_publicKey = HssPublicKeyParameters.GetInstance(pubEnc);
return pKey;
}
@@ -107,39 +103,38 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return new HssPrivateKeyParameters(d, keys, signatures, index, maxIndex, limited);
}
- public int L => l;
+ [Obsolete("Use 'Level' instead")]
+ public int L => m_level;
+
+ public int Level => m_level;
public long GetIndex()
{
- lock (this)
- return index;
+ lock (this) return m_index;
}
public LmsParameters[] GetLmsParameters()
{
lock (this)
{
- int len = keys.Count;
+ int len = m_keys.Count;
- LmsParameters[] parms = new LmsParameters[len];
+ LmsParameters[] parameters = new LmsParameters[len];
for (int i = 0; i < len; i++)
{
- LmsPrivateKeyParameters lmsPrivateKey = keys[i];
+ LmsPrivateKeyParameters lmsPrivateKey = m_keys[i];
- parms[i] = new LmsParameters(lmsPrivateKey.GetSigParameters(), lmsPrivateKey.GetOtsParameters());
+ parameters[i] = new LmsParameters(lmsPrivateKey.GetSigParameters(), lmsPrivateKey.GetOtsParameters());
}
- return parms;
+ return parameters;
}
}
internal void IncIndex()
{
- lock (this)
- {
- index++;
- }
+ lock (this) m_index++;
}
private static HssPrivateKeyParameters MakeCopy(HssPrivateKeyParameters privateKeyParameters)
@@ -151,27 +146,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
lock (this)
{
- keys = new List<LmsPrivateKeyParameters>(newKeys);
- sig = new List<LmsSignature>(newSig);
+ m_keys = new List<LmsPrivateKeyParameters>(newKeys);
+ m_sig = new List<LmsSignature>(newSig);
}
}
- public bool IsShard()
- {
- return isShard;
- }
+ public bool IsShard() => m_isShard;
- public long IndexLimit => indexLimit;
+ public long IndexLimit => m_indexLimit;
- public long GetUsagesRemaining()
- {
- return indexLimit - index;
- }
+ public long GetUsagesRemaining() => m_indexLimit - m_index;
- LmsPrivateKeyParameters GetRootKey()
- {
- return keys[0];
- }
+ internal LmsPrivateKeyParameters GetRootKey() => m_keys[0];
/**
* Return a key that can be used usageCount times.
@@ -189,19 +175,19 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
if (GetUsagesRemaining() < usageCount)
throw new ArgumentException("usageCount exceeds usages remaining in current leaf");
- long maxIndexForShard = index + usageCount;
- long shardStartIndex = index;
+ long maxIndexForShard = m_index + usageCount;
+ long shardStartIndex = m_index;
//
// Move this key's index along
//
- index += usageCount;
+ m_index += usageCount;
var keys = new List<LmsPrivateKeyParameters>(this.GetKeys());
var sig = new List<LmsSignature>(this.GetSig());
HssPrivateKeyParameters shard = MakeCopy(
- new HssPrivateKeyParameters(l, keys, sig, shardStartIndex, maxIndexForShard, true));
+ new HssPrivateKeyParameters(m_level, keys, sig, shardStartIndex, maxIndexForShard, true));
ResetKeyToIndex();
@@ -211,12 +197,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public IList<LmsPrivateKeyParameters> GetKeys()
{
- lock (this) return keys;
+ lock (this) return m_keys;
}
internal IList<LmsSignature> GetSig()
{
- lock (this) return sig;
+ lock (this) return m_sig;
}
/**
@@ -252,9 +238,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
//
// We need to replace the root key to a new q value.
//
- if (keys[0].GetIndex() - 1 != qTreePath[0])
+ if (m_keys[0].GetIndex() - 1 != qTreePath[0])
{
- keys[0] = Lms.GenerateKeys(
+ m_keys[0] = Lms.GenerateKeys(
originalRootKey.GetSigParameters(),
originalRootKey.GetOtsParameters(),
(int)qTreePath[0], originalRootKey.GetI(), originalRootKey.GetMasterSecret());
@@ -263,21 +249,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
for (int i = 1; i < qTreePath.Length; i++)
{
- LmsPrivateKeyParameters intermediateKey = keys[i - 1];
+ LmsPrivateKeyParameters intermediateKey = m_keys[i - 1];
+ int n = intermediateKey.GetOtsParameters().N;
byte[] childI = new byte[16];
- byte[] childSeed = new byte[32];
+ byte[] childSeed = new byte[n];
SeedDerive derive = new SeedDerive(
intermediateKey.GetI(),
intermediateKey.GetMasterSecret(),
- DigestUtilities.GetDigest(intermediateKey.GetOtsParameters().DigestOid))
+ LmsUtilities.GetDigest(intermediateKey.GetOtsParameters()))
{
Q = (int)qTreePath[i - 1],
J = ~1,
};
derive.DeriveSeed(true, childSeed, 0);
- byte[] postImage = new byte[32];
+ byte[] postImage = new byte[n];
derive.DeriveSeed(false, postImage, 0);
Array.Copy(postImage, 0, childI, 0, childI.Length);
@@ -287,22 +274,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
// For the end key its value will match so no correction is required.
//
bool lmsQMatch = (i < qTreePath.Length - 1)
- ? qTreePath[i] == keys[i].GetIndex() - 1
- : qTreePath[i] == keys[i].GetIndex();
+ ? qTreePath[i] == m_keys[i].GetIndex() - 1
+ : qTreePath[i] == m_keys[i].GetIndex();
//
// Equality is I and seed being equal and the lmsQMath.
// I and seed are derived from this nodes parent and will change if the parent q, I, seed changes.
//
- bool seedEquals = Arrays.AreEqual(childI, keys[i].GetI())
- && Arrays.AreEqual(childSeed, keys[i].GetMasterSecret());
+ bool seedEquals = Arrays.AreEqual(childI, m_keys[i].GetI())
+ && Arrays.AreEqual(childSeed, m_keys[i].GetMasterSecret());
if (!seedEquals)
{
//
// This means the parent has changed.
//
- keys[i] = Lms.GenerateKeys(
+ m_keys[i] = Lms.GenerateKeys(
originalKeys[i].GetSigParameters(),
originalKeys[i].GetOtsParameters(),
(int)qTreePath[i], childI, childSeed);
@@ -310,7 +297,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
//
// Ensure post increment occurs on parent and the new public key is signed.
//
- sig[i - 1] = Lms.GenerateSign((LmsPrivateKeyParameters)keys[i - 1], ((LmsPrivateKeyParameters)keys[i]).GetPublicKey().ToByteArray());
+ m_sig[i - 1] = Lms.GenerateSign((LmsPrivateKeyParameters)m_keys[i - 1], ((LmsPrivateKeyParameters)m_keys[i]).GetPublicKey().ToByteArray());
changed = true;
}
else if (!lmsQMatch)
@@ -319,7 +306,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
// Q is different so we can generate a new private key but it will have the same public
// key so we do not need to sign it again.
//
- keys[i] = Lms.GenerateKeys(
+ m_keys[i] = Lms.GenerateKeys(
originalKeys[i].GetSigParameters(),
originalKeys[i].GetOtsParameters(),
(int)qTreePath[i], childI, childSeed);
@@ -330,92 +317,60 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
if (changed)
{
// We mutate the HSS key here!
- UpdateHierarchy(keys, sig);
+ UpdateHierarchy(m_keys, m_sig);
}
}
public HssPublicKeyParameters GetPublicKey()
{
lock (this)
- return new HssPublicKeyParameters(l, GetRootKey().GetPublicKey());
+ return new HssPublicKeyParameters(m_level, GetRootKey().GetPublicKey());
}
internal void ReplaceConsumedKey(int d)
{
- SeedDerive deriver = keys[d - 1].GetCurrentOtsKey().GetDerivationFunction();
+ LMOtsPrivateKey currentOtsKey = m_keys[d - 1].GetCurrentOtsKey();
+ int n = currentOtsKey.Parameters.N;
+
+ SeedDerive deriver = currentOtsKey.GetDerivationFunction();
deriver.J = ~1;
- byte[] childRootSeed = new byte[32];
+ byte[] childRootSeed = new byte[n];
deriver.DeriveSeed(true, childRootSeed, 0);
- byte[] postImage = new byte[32];
+ byte[] postImage = new byte[n];
deriver.DeriveSeed(false, postImage, 0);
byte[] childI = new byte[16];
Array.Copy(postImage, 0, childI, 0, childI.Length);
- var newKeys = new List<LmsPrivateKeyParameters>(keys);
+ var newKeys = new List<LmsPrivateKeyParameters>(m_keys);
//
// We need the parameters from the LMS key we are replacing.
//
- LmsPrivateKeyParameters oldPk = keys[d];
+ LmsPrivateKeyParameters oldPk = m_keys[d];
newKeys[d] = Lms.GenerateKeys(oldPk.GetSigParameters(), oldPk.GetOtsParameters(), 0, childI, childRootSeed);
- var newSig = new List<LmsSignature>(sig);
+ var newSig = new List<LmsSignature>(m_sig);
newSig[d - 1] = Lms.GenerateSign(newKeys[d - 1], newKeys[d].GetPublicKey().ToByteArray());
- this.keys = new List<LmsPrivateKeyParameters>(newKeys);
- this.sig = new List<LmsSignature>(newSig);
+ this.m_keys = new List<LmsPrivateKeyParameters>(newKeys);
+ this.m_sig = new List<LmsSignature>(newSig);
}
- public override bool Equals(Object o)
+ public override bool Equals(object obj)
{
- if (this == o)
- {
+ if (this == obj)
return true;
- }
- if (o == null || GetType() != o.GetType())
- {
- return false;
- }
-
- HssPrivateKeyParameters that = (HssPrivateKeyParameters)o;
-
- if (l != that.l)
- {
- return false;
- }
- if (isShard != that.isShard)
- {
- return false;
- }
- if (indexLimit != that.indexLimit)
- {
- return false;
- }
- if (index != that.index)
- {
- return false;
- }
- if (!CompareLists(keys, that.keys))
- {
- return false;
- }
- return CompareLists(sig, that.sig);
- }
- private bool CompareLists<T>(IList<T> arr1, IList<T> arr2)
- {
- for (int i=0; i<arr1.Count && i<arr2.Count; i++)
- {
- if (!Object.Equals(arr1[i], arr2[i]))
- {
- return false;
- }
- }
- return true;
+ return obj is HssPrivateKeyParameters that
+ && this.m_level == that.m_level
+ && this.m_isShard == that.m_isShard
+ && this.m_indexLimit == that.m_indexLimit
+ && this.m_index == that.m_index
+ && CompareLists(this.m_keys, that.m_keys)
+ && CompareLists(this.m_sig, that.m_sig);
}
-
public override byte[] GetEncoded()
{
@@ -427,17 +382,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
Composer composer = Composer.Compose()
.U32Str(0) // Version.
- .U32Str(l)
- .U64Str(index)
- .U64Str(indexLimit)
- .Boolean(isShard); // Depth
+ .U32Str(m_level)
+ .U64Str(m_index)
+ .U64Str(m_indexLimit)
+ .Boolean(m_isShard); // Depth
- foreach (LmsPrivateKeyParameters key in keys)
+ foreach (LmsPrivateKeyParameters key in m_keys)
{
composer.Bytes(key);
}
- foreach (LmsSignature s in sig)
+ foreach (LmsSignature s in m_sig)
{
composer.Bytes(s);
}
@@ -448,12 +403,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public override int GetHashCode()
{
- int result = l;
- result = 31 * result + (isShard ? 1 : 0);
- result = 31 * result + keys.GetHashCode();
- result = 31 * result + sig.GetHashCode();
- result = 31 * result + (int)(indexLimit ^ (indexLimit >> 32));
- result = 31 * result + (int)(index ^ (index >> 32));
+ int result = m_level;
+ result = 31 * result + m_isShard.GetHashCode();
+ result = 31 * result + m_keys.GetHashCode();
+ result = 31 * result + m_sig.GetHashCode();
+ result = 31 * result + m_indexLimit.GetHashCode();
+ result = 31 * result + m_index.GetHashCode();
return result;
}
@@ -466,7 +421,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
LmsSignedPubKey[] signed_pub_key;
LmsPrivateKeyParameters nextKey;
- int L = this.L;
+ int level = Level;
lock (this)
{
@@ -475,12 +430,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
var keys = this.GetKeys();
var sig = this.GetSig();
- nextKey = this.GetKeys()[L - 1];
+ nextKey = this.GetKeys()[level - 1];
- // Step 2. Stand in for sig[L-1]
+ // Step 2. Stand in for sig[level-1]
int i = 0;
- signed_pub_key = new LmsSignedPubKey[L - 1];
- while (i < L - 1)
+ signed_pub_key = new LmsSignedPubKey[level - 1];
+ while (i < level - 1)
{
signed_pub_key[i] = new LmsSignedPubKey(sig[i], keys[i + 1].GetPublicKey());
++i;
@@ -499,12 +454,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
try
{
- return Hss.GenerateSignature(L, context).GetEncoded();
+ return Hss.GenerateSignature(Level, context).GetEncoded();
}
catch (IOException e)
{
throw new Exception($"unable to encode signature: {e.Message}", e);
}
}
+
+ private static bool CompareLists<T>(IList<T> arr1, IList<T> arr2)
+ {
+ for (int i = 0; i < arr1.Count && i < arr2.Count; i++)
+ {
+ if (!Object.Equals(arr1[i], arr2[i]))
+ return false;
+ }
+ return true;
+ }
}
}
diff --git a/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
index d3bc697d9..9766efdd1 100644
--- a/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
@@ -1,6 +1,5 @@
using System;
using System.IO;
-using System.Text;
using Org.BouncyCastle.Utilities.IO;
@@ -9,14 +8,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public sealed class HssPublicKeyParameters
: LmsKeyParameters, ILmsContextBasedVerifier
{
- private readonly int m_l;
+ private readonly int m_level; // hierarchical level
private readonly LmsPublicKeyParameters m_lmsPublicKey;
public HssPublicKeyParameters(int l, LmsPublicKeyParameters lmsPublicKey)
- :base(false)
+ : base(false)
{
- m_l = l;
- m_lmsPublicKey = lmsPublicKey;
+ m_level = l;
+ m_lmsPublicKey = lmsPublicKey ?? throw new ArgumentNullException(nameof(lmsPublicKey));
}
public static HssPublicKeyParameters GetInstance(object src)
@@ -43,33 +42,35 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return new HssPublicKeyParameters(L, lmsPublicKey);
}
- public int L => m_l;
+ [Obsolete("Use 'Level' instead")]
+ public int L => m_level;
+
+ public int Level => m_level;
public LmsPublicKeyParameters LmsPublicKey => m_lmsPublicKey;
- public override bool Equals(Object o)
+ // TODO[api] Fix parameter name
+ public override bool Equals(object o)
{
if (this == o)
return true;
- if (o == null || GetType() != o.GetType())
- return false;
-
- HssPublicKeyParameters publicKey = (HssPublicKeyParameters)o;
- return m_l == publicKey.m_l
- && m_lmsPublicKey.Equals(publicKey.m_lmsPublicKey);
+ return o is HssPublicKeyParameters that
+ && this.m_level == that.m_level
+ && this.m_lmsPublicKey.Equals(that.m_lmsPublicKey);
}
public override int GetHashCode()
{
- int result = m_l;
+ int result = m_level;
result = 31 * result + m_lmsPublicKey.GetHashCode();
return result;
}
public override byte[] GetEncoded()
{
- return Composer.Compose().U32Str(m_l)
+ return Composer.Compose()
+ .U32Str(m_level)
.Bytes(m_lmsPublicKey.GetEncoded())
.Build();
}
@@ -79,18 +80,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
HssSignature signature;
try
{
- signature = HssSignature.GetInstance(sigEnc, L);
+ signature = HssSignature.GetInstance(sigEnc, Level);
}
catch (IOException e)
{
throw new Exception($"cannot parse signature: {e.Message}");
}
- LmsSignedPubKey[] signedPubKeys = signature.GetSignedPubKeys();
+ LmsSignedPubKey[] signedPubKeys = signature.SignedPubKeys;
LmsPublicKeyParameters key = LmsPublicKey;
if (signedPubKeys.Length != 0)
{
- key = signedPubKeys[signedPubKeys.Length - 1].GetPublicKey();
+ key = signedPubKeys[signedPubKeys.Length - 1].PublicKey;
}
return key.GenerateOtsContext(signature.Signature).WithSignedPublicKeys(signedPubKeys);
@@ -100,7 +101,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
LmsSignedPubKey[] sigKeys = context.SignedPubKeys;
- if (sigKeys.Length != L - 1)
+ if (sigKeys.Length != Level - 1)
return false;
LmsPublicKeyParameters key = LmsPublicKey;
@@ -108,16 +109,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
for (int i = 0; i < sigKeys.Length; i++)
{
- LmsSignature sig = sigKeys[i].GetSignature();
- byte[] msg = sigKeys[i].GetPublicKey().ToByteArray();
- if (!Lms.VerifySignature(key, sig, msg))
+ LmsSignature sig = sigKeys[i].Signature;
+ LmsPublicKeyParameters nextKey = sigKeys[i].PublicKey;
+
+ if (!Lms.VerifySignature(key, sig, nextKey.ToByteArray()))
{
failed = true;
}
- key = sigKeys[i].GetPublicKey();
+
+ key = nextKey;
}
return !failed & key.Verify(context);
}
}
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/lms/HSSSignature.cs b/crypto/src/pqc/crypto/lms/HSSSignature.cs
index bbf0c6f0f..946d0ef89 100644
--- a/crypto/src/pqc/crypto/lms/HSSSignature.cs
+++ b/crypto/src/pqc/crypto/lms/HSSSignature.cs
@@ -7,18 +7,19 @@ using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public sealed class HssSignature
: IEncodable
{
private readonly int m_lMinus1;
- private readonly LmsSignedPubKey[] m_signedPubKey;
+ private readonly LmsSignedPubKey[] m_signedPubKeys;
private readonly LmsSignature m_signature;
// TODO[api] signedPubKeys
public HssSignature(int lMinus1, LmsSignedPubKey[] signedPubKey, LmsSignature signature)
{
m_lMinus1 = lMinus1;
- m_signedPubKey = signedPubKey;
+ m_signedPubKeys = signedPubKey;
m_signature = signature;
}
@@ -75,46 +76,37 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
}
}
+ [Obsolete("Use 'LMinus1' instead")]
public int GetLMinus1()
{
return m_lMinus1;
}
- // FIXME
- public LmsSignedPubKey[] GetSignedPubKeys()
- {
- return m_signedPubKey;
- }
+ public int LMinus1 => m_lMinus1;
+
+ public LmsSignedPubKey[] GetSignedPubKeys() => (LmsSignedPubKey[])m_signedPubKeys?.Clone();
+
+ internal LmsSignedPubKey[] SignedPubKeys => m_signedPubKeys;
public LmsSignature Signature => m_signature;
+ // TODO[api] Fix parameter name
public override bool Equals(object other)
{
if (this == other)
return true;
- if (!(other is HssSignature that))
- return false;
-
- if (this.m_lMinus1 != that.m_lMinus1)
- return false;
-
- if (this.m_signedPubKey.Length != that.m_signedPubKey.Length)
- return false;
-
- for (int t = 0; t < m_signedPubKey.Length; t++)
- {
- if (!this.m_signedPubKey[t].Equals(that.m_signedPubKey[t]))
- return false;
- }
- return Equals(this.m_signature, that.m_signature);
+ return other is HssSignature that
+ && this.m_lMinus1 == that.m_lMinus1
+ && Arrays.AreEqual(this.m_signedPubKeys, that.m_signedPubKeys)
+ && Objects.Equals(this.m_signature, that.m_signature);
}
public override int GetHashCode()
{
int result = m_lMinus1;
- result = 31 * result + m_signedPubKey.GetHashCode();
- result = 31 * result + (m_signature != null ? m_signature.GetHashCode() : 0);
+ result = 31 * result + Arrays.GetHashCode(m_signedPubKeys);
+ result = 31 * result + Objects.GetHashCode(m_signature);
return result;
}
@@ -122,9 +114,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
Composer composer = Composer.Compose();
composer.U32Str(m_lMinus1);
- if (m_signedPubKey != null)
+ if (m_signedPubKeys != null)
{
- foreach (LmsSignedPubKey sigPub in m_signedPubKey)
+ foreach (LmsSignedPubKey sigPub in m_signedPubKeys)
{
composer.Bytes(sigPub);
}
diff --git a/crypto/src/pqc/crypto/lms/HSSSigner.cs b/crypto/src/pqc/crypto/lms/HSSSigner.cs
index 9ef7b57ae..295caa00e 100644
--- a/crypto/src/pqc/crypto/lms/HSSSigner.cs
+++ b/crypto/src/pqc/crypto/lms/HSSSigner.cs
@@ -39,7 +39,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
try
{
- return Hss.VerifySignature(pubKey, HssSignature.GetInstance(signature, pubKey.L), message);
+ return Hss.VerifySignature(pubKey, HssSignature.GetInstance(signature, pubKey.Level), message);
}
catch (IOException e)
{
diff --git a/crypto/src/pqc/crypto/lms/LMOtsParameters.cs b/crypto/src/pqc/crypto/lms/LMOtsParameters.cs
index 60bf28d50..ce472c18d 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsParameters.cs
@@ -9,22 +9,52 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
public sealed class LMOtsParameters
{
- // TODO add all parameter sets
-
- //public static int reserved = 0;
public static LMOtsParameters sha256_n32_w1 = new LMOtsParameters(1, 32, 1, 265, 7, 8516, NistObjectIdentifiers.IdSha256);
public static LMOtsParameters sha256_n32_w2 = new LMOtsParameters(2, 32, 2, 133, 6, 4292, NistObjectIdentifiers.IdSha256);
public static LMOtsParameters sha256_n32_w4 = new LMOtsParameters(3, 32, 4, 67, 4, 2180, NistObjectIdentifiers.IdSha256);
public static LMOtsParameters sha256_n32_w8 = new LMOtsParameters(4, 32, 8, 34, 0, 1124, NistObjectIdentifiers.IdSha256);
+ public static LMOtsParameters sha256_n24_w1 = new LMOtsParameters(5, 24, 1, 200, 8, 5436, NistObjectIdentifiers.IdSha256);
+ public static LMOtsParameters sha256_n24_w2 = new LMOtsParameters(6, 24, 2, 101, 6, 2940, NistObjectIdentifiers.IdSha256);
+ public static LMOtsParameters sha256_n24_w4 = new LMOtsParameters(7, 24, 4, 51, 4, 1500, NistObjectIdentifiers.IdSha256);
+ public static LMOtsParameters sha256_n24_w8 = new LMOtsParameters(8, 24, 8, 26, 0, 1020, NistObjectIdentifiers.IdSha256);
+
+ public static LMOtsParameters shake256_n32_w1 = new LMOtsParameters(9, 32, 1, 265, 7, 8516, NistObjectIdentifiers.IdShake256Len);
+ public static LMOtsParameters shake256_n32_w2 = new LMOtsParameters(10, 32, 2, 133, 6, 4292, NistObjectIdentifiers.IdShake256Len);
+ public static LMOtsParameters shake256_n32_w4 = new LMOtsParameters(11, 32, 4, 67, 4, 2180, NistObjectIdentifiers.IdShake256Len);
+ public static LMOtsParameters shake256_n32_w8 = new LMOtsParameters(12, 32, 8, 34, 0, 1124, NistObjectIdentifiers.IdShake256Len);
+
+ public static LMOtsParameters shake256_n24_w1 = new LMOtsParameters(13, 24, 1, 200, 8, 5436, NistObjectIdentifiers.IdShake256Len);
+ public static LMOtsParameters shake256_n24_w2 = new LMOtsParameters(14, 24, 2, 101, 6, 2940, NistObjectIdentifiers.IdShake256Len);
+ public static LMOtsParameters shake256_n24_w4 = new LMOtsParameters(15, 24, 4, 51, 4, 1500, NistObjectIdentifiers.IdShake256Len);
+ public static LMOtsParameters shake256_n24_w8 = new LMOtsParameters(16, 24, 8, 26, 0, 1020, NistObjectIdentifiers.IdShake256Len);
+
private static Dictionary<object, LMOtsParameters> Suppliers = new Dictionary<object, LMOtsParameters>
{
{ sha256_n32_w1.ID, sha256_n32_w1 },
{ sha256_n32_w2.ID, sha256_n32_w2 },
{ sha256_n32_w4.ID, sha256_n32_w4 },
- { sha256_n32_w8.ID, sha256_n32_w8 }
+ { sha256_n32_w8.ID, sha256_n32_w8 },
+
+ { sha256_n24_w1.ID, sha256_n24_w1 },
+ { sha256_n24_w2.ID, sha256_n24_w2 },
+ { sha256_n24_w4.ID, sha256_n24_w4 },
+ { sha256_n24_w8.ID, sha256_n24_w8 },
+
+ { shake256_n32_w1.ID, shake256_n32_w1 },
+ { shake256_n32_w2.ID, shake256_n32_w2 },
+ { shake256_n32_w4.ID, shake256_n32_w4 },
+ { shake256_n32_w8.ID, shake256_n32_w8 },
+
+ { shake256_n24_w1.ID, shake256_n24_w1 },
+ { shake256_n24_w2.ID, shake256_n24_w2 },
+ { shake256_n24_w4.ID, shake256_n24_w4 },
+ { shake256_n24_w8.ID, shake256_n24_w8 },
};
+ public static LMOtsParameters GetParametersByID(int id) =>
+ CollectionUtilities.GetValueOrNull(Suppliers, id);
+
private readonly int m_id;
private readonly int m_n;
private readonly int m_w;
@@ -57,10 +87,5 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public int SigLen => Convert.ToInt32(m_sigLen);
public DerObjectIdentifier DigestOid => m_digestOid;
-
- public static LMOtsParameters GetParametersByID(int id)
- {
- return CollectionUtilities.GetValueOrNull(Suppliers, id);
- }
}
}
diff --git a/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs b/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs
index 20b717af6..2a6a18155 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs
@@ -1,8 +1,11 @@
+using System;
+
using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public sealed class LMOtsPrivateKey
{
private readonly LMOtsParameters m_parameters;
@@ -20,13 +23,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public LmsContext GetSignatureContext(LMSigParameters sigParams, byte[][] path)
{
- byte[] C = new byte[LMOts.SEED_LEN];
+ byte[] C = new byte[m_parameters.N];
SeedDerive derive = GetDerivationFunction();
derive.J = LMOts.SEED_RANDOMISER_INDEX; // This value from reference impl.
derive.DeriveSeed(false, C, 0);
- IDigest ctx = DigestUtilities.GetDigest(m_parameters.DigestOid);
+ IDigest ctx = LmsUtilities.GetDigest(m_parameters);
LmsUtilities.ByteArray(m_I, ctx);
LmsUtilities.U32Str(m_q, ctx);
@@ -36,23 +39,27 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return new LmsContext(this, sigParams, ctx, C, path);
}
+ public byte[] GetI() => Arrays.Clone(m_I);
+
+ public byte[] GetMasterSecret() => Arrays.Clone(m_masterSecret);
+
+ public LMOtsParameters Parameters => m_parameters;
+
+ public int Q => m_q;
+
internal SeedDerive GetDerivationFunction()
{
- return new SeedDerive(m_I, m_masterSecret, DigestUtilities.GetDigest(m_parameters.DigestOid))
+ return new SeedDerive(m_I, m_masterSecret, LmsUtilities.GetDigest(m_parameters))
{
Q = m_q,
J = 0,
};
}
- public LMOtsParameters Parameters => m_parameters;
-
- // FIXME
+ [Obsolete("Use 'GetI' instead")]
public byte[] I => m_I;
- public int Q => m_q;
-
- // FIXME
+ [Obsolete("Use 'GetMasterSecret' instead")]
public byte[] MasterSecret => m_masterSecret;
}
}
diff --git a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
index 5be482e25..0f5d956e8 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
@@ -2,12 +2,12 @@ using System;
using System.IO;
using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public sealed class LMOtsPublicKey
{
private readonly LMOtsParameters m_parameters;
@@ -54,22 +54,21 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return new LMOtsPublicKey(parameter, I, q, K);
}
- public LMOtsParameters Parameters => m_parameters;
+ public byte[] GetI() => Arrays.Clone(m_I);
- public byte[] I => m_I;
+ public byte[] GetK() => Arrays.Clone(m_K);
- public int Q => m_q;
+ public LMOtsParameters Parameters => m_parameters;
- public byte[] K => m_K;
+ public int Q => m_q;
public override bool Equals(object obj)
{
if (this == obj)
return true;
- if (!(obj is LMOtsPublicKey that))
- return false;
- return m_q == that.m_q
+ return obj is LMOtsPublicKey that
+ && m_q == that.m_q
&& Objects.Equals(m_parameters, that.m_parameters)
&& Arrays.AreEqual(m_I, that.m_I)
&& Arrays.AreEqual(m_K, that.m_K);
@@ -77,9 +76,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public override int GetHashCode()
{
- int result = Objects.GetHashCode(m_parameters);
+ int result = m_q;
+ result = 31 * result + Objects.GetHashCode(m_parameters);
result = 31 * result + Arrays.GetHashCode(m_I);
- result = 31 * result + m_q;
result = 31 * result + Arrays.GetHashCode(m_K);
return result;
}
@@ -96,26 +95,36 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
internal LmsContext CreateOtsContext(LMOtsSignature signature)
{
- IDigest ctx = DigestUtilities.GetDigest(m_parameters.DigestOid);
+ IDigest ctx = LmsUtilities.GetDigest(m_parameters);
LmsUtilities.ByteArray(m_I, ctx);
LmsUtilities.U32Str(m_q, ctx);
LmsUtilities.U16Str((short)LMOts.D_MESG, ctx);
+#pragma warning disable CS0618 // Type or member is obsolete
LmsUtilities.ByteArray(signature.C, ctx);
+#pragma warning restore CS0618 // Type or member is obsolete
return new LmsContext(this, signature, ctx);
}
internal LmsContext CreateOtsContext(LmsSignature signature)
{
- IDigest ctx = DigestUtilities.GetDigest(m_parameters.DigestOid);
+ IDigest ctx = LmsUtilities.GetDigest(m_parameters);
LmsUtilities.ByteArray(m_I, ctx);
LmsUtilities.U32Str(m_q, ctx);
LmsUtilities.U16Str((short)LMOts.D_MESG, ctx);
+#pragma warning disable CS0618 // Type or member is obsolete
LmsUtilities.ByteArray(signature.OtsSignature.C, ctx);
+#pragma warning restore CS0618 // Type or member is obsolete
return new LmsContext(this, signature, ctx);
}
+
+ [Obsolete("Use 'GetI' instead")]
+ public byte[] I => m_I;
+
+ [Obsolete("Use 'GetK' instead")]
+ public byte[] K => m_K;
}
}
diff --git a/crypto/src/pqc/crypto/lms/LMOtsSignature.cs b/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
index afc309be6..f337461ac 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
@@ -6,6 +6,7 @@ using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public sealed class LMOtsSignature
: IEncodable
{
@@ -49,13 +50,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return new LMOtsSignature(parameter, C, sig);
}
- public LMOtsParameters ParamType => m_paramType;
+ public byte[] GetC() => Arrays.Clone(m_C);
- // FIXME
- public byte[] C => m_C;
+ public byte[] GetY() => Arrays.Clone(m_y);
- // FIXME
- public byte[] Y => m_y;
+ public LMOtsParameters ParamType => m_paramType;
public override bool Equals(object obj)
{
@@ -85,5 +84,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
.Bytes(m_y)
.Build();
}
+
+ [Obsolete("Use 'GetC' instead")]
+ public byte[] C => m_C;
+
+ [Obsolete("Use 'GetY' instead")]
+ public byte[] Y => m_y;
}
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/lms/LMS.cs b/crypto/src/pqc/crypto/lms/LMS.cs
index 6174d3889..1dbf105aa 100644
--- a/crypto/src/pqc/crypto/lms/LMS.cs
+++ b/crypto/src/pqc/crypto/lms/LMS.cs
@@ -5,6 +5,7 @@ using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public static class Lms
{
internal static ushort D_LEAF = 0x8282;
@@ -95,7 +96,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
// tmp = H(I || u32str(node_num) || u16str(D_LEAF) || Kc)
byte[] I = publicKey.GetI();
- IDigest H = DigestUtilities.GetDigest(lmsParameter.DigestOid);
+ IDigest H = LmsUtilities.GetDigest(lmsParameter);
byte[] tmp = new byte[H.GetDigestSize()];
H.BlockUpdate(I, 0, I.Length);
@@ -130,6 +131,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
node_num = node_num / 2;
i++;
+ // these two can get out of sync with an invalid signature, we'll
+ // try and fail gracefully
+ if (i == path.Length && node_num > 1)
+ return false;
}
byte[] Tc = tmp;
diff --git a/crypto/src/pqc/crypto/lms/LMSContext.cs b/crypto/src/pqc/crypto/lms/LMSContext.cs
index 6fcbd9413..83f06b4c2 100644
--- a/crypto/src/pqc/crypto/lms/LMSContext.cs
+++ b/crypto/src/pqc/crypto/lms/LMSContext.cs
@@ -17,6 +17,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
private LmsSignedPubKey[] m_signedPubKeys;
private volatile IDigest m_digest;
+ // TODO[api] Make internal
public LmsContext(LMOtsPrivateKey privateKey, LMSigParameters sigParams, IDigest digest, byte[] C,
byte[][] path)
{
@@ -29,6 +30,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
m_signature = null;
}
+ // TODO[api] Make internal
public LmsContext(LMOtsPublicKey publicKey, object signature, IDigest digest)
{
m_publicKey = publicKey;
@@ -54,6 +56,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
internal LMOtsPrivateKey PrivateKey => m_privateKey;
+ // TODO[api] Make internal
public LMOtsPublicKey PublicKey => m_publicKey;
internal LMSigParameters SigParams => m_sigParams;
diff --git a/crypto/src/pqc/crypto/lms/LMSException.cs b/crypto/src/pqc/crypto/lms/LMSException.cs
index 694a370ed..c581610d5 100644
--- a/crypto/src/pqc/crypto/lms/LMSException.cs
+++ b/crypto/src/pqc/crypto/lms/LMSException.cs
@@ -3,6 +3,7 @@ using System.Runtime.Serialization;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
[Serializable]
public class LmsException
: Exception
diff --git a/crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs b/crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs
index e1afb00d9..4c1f129fd 100644
--- a/crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs
@@ -15,16 +15,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public AsymmetricCipherKeyPair GenerateKeyPair()
{
- SecureRandom source = m_parameters.Random;
+ var random = m_parameters.Random;
+ byte[] I = SecureRandom.GetNextBytes(random, 16);
- byte[] I = new byte[16];
- source.NextBytes(I);
+ var lmsParameters = m_parameters.LmsParameters;
+ var sigParameters = lmsParameters.LMSigParameters;
+ var otsParameters = lmsParameters.LMOtsParameters;
+ byte[] rootSecret = SecureRandom.GetNextBytes(random, sigParameters.M);
- byte[] rootSecret = new byte[32];
- source.NextBytes(rootSecret);
-
- LmsPrivateKeyParameters privKey = Lms.GenerateKeys(m_parameters.LmsParameters.LMSigParameters,
- m_parameters.LmsParameters.LMOtsParameters, 0, I, rootSecret);
+ LmsPrivateKeyParameters privKey = Lms.GenerateKeys(sigParameters, otsParameters, 0, I, rootSecret);
return new AsymmetricCipherKeyPair(privKey.GetPublicKey(), privKey);
}
diff --git a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
index c5a188748..96f1765c2 100644
--- a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
@@ -12,8 +12,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public sealed class LmsPrivateKeyParameters
: LmsKeyParameters, ILmsContextBasedSigner
{
- private static CacheKey T1 = new CacheKey(1);
- private static CacheKey[] internedKeys = new CacheKey[129];
+ private static readonly CacheKey T1 = new CacheKey(1);
+ private static readonly CacheKey[] internedKeys = new CacheKey[129];
+
+ private static LmsPublicKeyParameters DerivePublicKey(LmsPrivateKeyParameters privateKey)
+ {
+ return new LmsPublicKeyParameters(privateKey.parameters, privateKey.otsParameters, privateKey.FindT(T1),
+ privateKey.I);
+ }
static LmsPrivateKeyParameters()
{
@@ -40,7 +46,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
// These are not final because they can be generated.
// They also do not need to be persisted.
//
- private LmsPublicKeyParameters publicKey;
+ private LmsPublicKeyParameters m_publicKey;
public LmsPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I,
int maxQ, byte[] masterSecret)
@@ -60,7 +66,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
this.masterSecret = Arrays.Clone(masterSecret);
this.maxCacheR = 1 << (parameters.H + 1);
this.tCache = new Dictionary<CacheKey, byte[]>();
- this.tDigest = DigestUtilities.GetDigest(lmsParameter.DigestOid);
+ this.tDigest = LmsUtilities.GetDigest(lmsParameter);
this.m_isPlaceholder = isPlaceholder;
}
@@ -75,16 +81,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
this.masterSecret = parent.masterSecret;
this.maxCacheR = 1 << parameters.H;
this.tCache = parent.tCache;
- this.tDigest = DigestUtilities.GetDigest(parameters.DigestOid);
- this.publicKey = parent.publicKey;
+ this.tDigest = LmsUtilities.GetDigest(parameters);
+ this.m_publicKey = parent.m_publicKey;
}
public static LmsPrivateKeyParameters GetInstance(byte[] privEnc, byte[] pubEnc)
{
LmsPrivateKeyParameters pKey = GetInstance(privEnc);
-
- pKey.publicKey = LmsPublicKeyParameters.GetInstance(pubEnc);
-
+ pKey.m_publicKey = LmsPublicKeyParameters.GetInstance(pubEnc);
return pKey;
}
@@ -137,6 +141,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
lock (this)
{
if (q >= maxQ)
+ // TODO ExhaustedPrivateKeyException
throw new Exception("ots private keys expired");
return new LMOtsPrivateKey(otsParameters, I, q, masterSecret);
@@ -266,14 +271,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
if (m_isPlaceholder)
throw new Exception("placeholder only");
- lock (this)
- {
- if (publicKey == null)
- {
- publicKey = new LmsPublicKeyParameters(parameters, otsParameters, this.FindT(T1), I);
- }
- return publicKey;
- }
+ return Objects.EnsureSingletonInitialized(ref m_publicKey, this, DerivePublicKey);
}
internal byte[] FindT(int r)
@@ -293,7 +291,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
if (tCache.TryGetValue(key, out byte[] t))
return t;
- return tCache[key] = CalcT(key.index);
+ return tCache[key] = CalcT(key.m_index);
}
}
@@ -339,65 +337,29 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return T;
}
- public override bool Equals(Object o)
+ // TODO[api] Fix parameter name
+ public override bool Equals(object o)
{
if (this == o)
- {
return true;
- }
- if (o == null || GetType() != o.GetType())
- {
- return false;
- }
-
- LmsPrivateKeyParameters that = (LmsPrivateKeyParameters)o;
- if (q != that.q)
- {
- return false;
- }
- if (maxQ != that.maxQ)
- {
- return false;
- }
- if (!Arrays.AreEqual(I, that.I))
- {
- return false;
- }
- if (parameters != null ? !parameters.Equals(that.parameters) : that.parameters != null)
- {
- return false;
- }
- if (otsParameters != null ? !otsParameters.Equals(that.otsParameters) : that.otsParameters != null)
- {
- return false;
- }
- if (!Arrays.AreEqual(masterSecret, that.masterSecret))
- {
- return false;
- }
-
- //
- // Only compare public keys if they both exist.
- // Otherwise we would trigger the creation of one or both of them
- //
- if (publicKey != null && that.publicKey != null)
- {
- return publicKey.Equals(that.publicKey);
- }
-
- return true;
+ return o is LmsPrivateKeyParameters that
+ && this.q == that.q
+ && this.maxQ == that.maxQ
+ && Arrays.AreEqual(this.I, that.I)
+ && Objects.Equals(this.parameters, that.parameters)
+ && Objects.Equals(this.otsParameters, that.otsParameters)
+ && Arrays.AreEqual(this.masterSecret, that.masterSecret);
}
public override int GetHashCode()
{
int result = q;
- result = 31 * result + Arrays.GetHashCode(I);
- result = 31 * result + (parameters != null ? parameters.GetHashCode() : 0);
- result = 31 * result + (otsParameters != null ? otsParameters.GetHashCode() : 0);
result = 31 * result + maxQ;
+ result = 31 * result + Arrays.GetHashCode(I);
+ result = 31 * result + Objects.GetHashCode(parameters);
+ result = 31 * result + Objects.GetHashCode(otsParameters);
result = 31 * result + Arrays.GetHashCode(masterSecret);
- result = 31 * result + (publicKey != null ? publicKey.GetHashCode() : 0);
return result;
}
@@ -430,29 +392,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
.Build();
}
- class CacheKey
+ internal struct CacheKey
{
- internal int index;
+ internal readonly int m_index;
public CacheKey(int index)
{
- this.index = index;
+ m_index = index;
}
- public override int GetHashCode()
+ public override bool Equals(object obj)
{
- return index;
+ return obj is CacheKey that
+ && this.m_index == that.m_index;
}
- public override bool Equals(Object o)
- {
- if (o is CacheKey)
- {
- return ((CacheKey)o).index == this.index;
- }
-
- return false;
- }
+ public override int GetHashCode() => m_index;
}
}
}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
index 37fa76e2d..506b78096 100644
--- a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
@@ -55,72 +55,33 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return new LmsPublicKeyParameters(lmsParameter, ostTypeCode, T1, I);
}
- public override byte[] GetEncoded()
- {
- return this.ToByteArray();
- }
+ public override byte[] GetEncoded() => ToByteArray();
- public LMSigParameters GetSigParameters()
- {
- return parameterSet;
- }
+ public LMSigParameters GetSigParameters() => parameterSet;
- public LMOtsParameters GetOtsParameters()
- {
- return lmOtsType;
- }
+ public LMOtsParameters GetOtsParameters() => lmOtsType;
- public LmsParameters GetLmsParameters()
- {
- return new LmsParameters(this.GetSigParameters(), this.GetOtsParameters());
- }
+ public LmsParameters GetLmsParameters() => new LmsParameters(GetSigParameters(), GetOtsParameters());
- public byte[] GetT1()
- {
- return Arrays.Clone(T1);
- }
+ public byte[] GetT1() => Arrays.Clone(T1);
- internal bool MatchesT1(byte[] sig)
- {
- return Arrays.FixedTimeEquals(T1, sig);
- }
+ internal bool MatchesT1(byte[] sig) => Arrays.FixedTimeEquals(T1, sig);
- public byte[] GetI()
- {
- return Arrays.Clone(I);
- }
+ public byte[] GetI() => Arrays.Clone(I);
- byte[] RefI()
- {
- return I;
- }
+ internal byte[] RefI() => I;
- public override bool Equals(Object o)
+ // TODO[api] Fix parameter name
+ public override bool Equals(object o)
{
if (this == o)
- {
return true;
- }
- if (o == null || GetType() != o.GetType())
- {
- return false;
- }
-
- LmsPublicKeyParameters publicKey = (LmsPublicKeyParameters)o;
- if (!parameterSet.Equals(publicKey.parameterSet))
- {
- return false;
- }
- if (!lmOtsType.Equals(publicKey.lmOtsType))
- {
- return false;
- }
- if (!Arrays.AreEqual(I, publicKey.I))
- {
- return false;
- }
- return Arrays.AreEqual(T1, publicKey.T1);
+ return o is LmsPublicKeyParameters that
+ && this.parameterSet.Equals(that.parameterSet)
+ && this.lmOtsType.Equals(that.lmOtsType)
+ && Arrays.AreEqual(this.I, that.I)
+ && Arrays.AreEqual(this.T1, that.T1);
}
public override int GetHashCode()
@@ -167,9 +128,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
.CreateOtsContext(S);
}
- public bool Verify(LmsContext context)
- {
- return Lms.VerifySignature(this, context);
- }
+ public bool Verify(LmsContext context) => Lms.VerifySignature(this, context);
}
}
diff --git a/crypto/src/pqc/crypto/lms/LMSSignature.cs b/crypto/src/pqc/crypto/lms/LMSSignature.cs
index d25a498ea..75b0bdfbb 100644
--- a/crypto/src/pqc/crypto/lms/LMSSignature.cs
+++ b/crypto/src/pqc/crypto/lms/LMSSignature.cs
@@ -6,20 +6,21 @@ using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public class LmsSignature
: IEncodable
{
- private int q;
- private LMOtsSignature otsSignature;
- private LMSigParameters parameter;
- private byte[][] y;
+ private readonly int m_q;
+ private readonly LMOtsSignature m_otsSignature;
+ private readonly LMSigParameters m_parameters;
+ private readonly byte[][] m_y;
public LmsSignature(int q, LMOtsSignature otsSignature, LMSigParameters parameter, byte[][] y)
{
- this.q = q;
- this.otsSignature = otsSignature;
- this.parameter = parameter;
- this.y = y;
+ m_q = q;
+ m_otsSignature = otsSignature;
+ m_parameters = parameter;
+ m_y = y;
}
public static LmsSignature GetInstance(object src)
@@ -58,74 +59,80 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return new LmsSignature(q, otsSignature, type, path);
}
- public override bool Equals(Object o)
+ // TODO[api] Fix parameter name
+ public override bool Equals(object o)
{
if (this == o)
- {
return true;
- }
- if (o == null || GetType() != o.GetType())
- {
- return false;
- }
-
- LmsSignature that = (LmsSignature)o;
- if (q != that.q)
- {
- return false;
- }
- if (otsSignature != null ? !otsSignature.Equals(that.otsSignature) : that.otsSignature != null)
- {
- return false;
- }
- if (parameter != null ? !parameter.Equals(that.parameter) : that.parameter != null)
- {
- return false;
- }
-
- return Compare2DArrays(y, that.y);
- }
-
- private bool Compare2DArrays(byte[][] a, byte[][] b)
- {
- for (int i = 0; i < a.Length; i++)
- {
- for (int j = 0; j < a[0].Length; j++)
- {
- if (!a[i][j].Equals(b[i][j]))
- return false;
- }
- }
- return true;
+ return o is LmsSignature that
+ && this.m_q == that.m_q
+ && Objects.Equals(this.m_otsSignature, that.m_otsSignature)
+ && Objects.Equals(this.m_parameters, that.m_parameters)
+ && DeepEquals(this.m_y, that.m_y);
}
public override int GetHashCode()
{
- int result = q;
- result = (31 * result + (otsSignature != null ? otsSignature.GetHashCode() : 0));
- result = (31 * result + (parameter != null ? parameter.GetHashCode() : 0));
- // result = 31 * result + Arrays.GetHashCode(y); //Todo arrays support for 2d arrays?
+ int result = m_q;
+ result = 31 * result + Objects.GetHashCode(m_otsSignature);
+ result = 31 * result + Objects.GetHashCode(m_parameters);
+ result = 31 * result + DeepGetHashCode(m_y);
return result;
}
public byte[] GetEncoded()
{
return Composer.Compose()
- .U32Str(q)
- .Bytes(otsSignature.GetEncoded())
- .U32Str(parameter.ID)
- .Bytes2(y)
+ .U32Str(m_q)
+ .Bytes(m_otsSignature.GetEncoded())
+ .U32Str(m_parameters.ID)
+ .Bytes2(m_y)
.Build();
}
- public int Q => q;
+ public LMOtsSignature OtsSignature => m_otsSignature;
+
+ public int Q => m_q;
+
+ public LMSigParameters SigParameters => m_parameters;
+
+ // TODO[api]
+ public byte[][] Y => m_y;
+
+ private static bool DeepEquals(byte[][] a, byte[][] b)
+ {
+ if (a == b)
+ return true;
+
+ int length = a.Length;
+ if (length != b.Length)
+ return false;
+
+ for (int i = 0; i < length; ++i)
+ {
+ if (!Arrays.AreEqual(a[i], b[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static int DeepGetHashCode(byte[][] a)
+ {
+ if (a == null)
+ return 0;
- public LMOtsSignature OtsSignature => otsSignature;
+ int length = a.Length;
+ int hc = length + 1;
- public LMSigParameters SigParameters => parameter;
+ for (int i = 0; i < length; ++i)
+ {
+ hc *= 257;
+ hc ^= Arrays.GetHashCode(a[i]);
+ }
- // FIXME
- public byte[][] Y => y;
+ return hc;
+ }
}
}
diff --git a/crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs b/crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs
index 5e07c9c93..666bddc7b 100644
--- a/crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs
+++ b/crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs
@@ -4,62 +4,52 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public class LmsSignedPubKey
: IEncodable
{
- private LmsSignature signature;
- private LmsPublicKeyParameters publicKey;
+ private readonly LmsSignature m_signature;
+ private readonly LmsPublicKeyParameters m_publicKey;
public LmsSignedPubKey(LmsSignature signature, LmsPublicKeyParameters publicKey)
{
- this.signature = signature;
- this.publicKey = publicKey;
+ m_signature = signature;
+ m_publicKey = publicKey;
}
+ [Obsolete("Use 'PublicKey' instead")]
+ public LmsPublicKeyParameters GetPublicKey() => m_publicKey;
- public LmsSignature GetSignature()
- {
- return signature;
- }
+ [Obsolete("Use 'Signature' instead")]
+ public LmsSignature GetSignature() => m_signature;
- public LmsPublicKeyParameters GetPublicKey()
- {
- return publicKey;
- }
+ public LmsPublicKeyParameters PublicKey => m_publicKey;
- public override bool Equals(Object o)
+ public LmsSignature Signature => m_signature;
+
+ public override bool Equals(object obj)
{
- if (this == o)
- {
+ if (this == obj)
return true;
- }
- if (o == null || GetType() != o.GetType())
- {
- return false;
- }
-
- LmsSignedPubKey that = (LmsSignedPubKey)o;
- if (signature != null ? !signature.Equals(that.signature) : that.signature != null)
- {
- return false;
- }
- return publicKey != null ? publicKey.Equals(that.publicKey) : that.publicKey == null;
+ return obj is LmsSignedPubKey that
+ && Objects.Equals(this.m_signature, that.m_signature)
+ && Objects.Equals(this.m_publicKey, that.m_publicKey);
}
-
+
public override int GetHashCode()
{
- int result = signature != null ? signature.GetHashCode() : 0;
- result = 31 * result + (publicKey != null ? publicKey.GetHashCode() : 0);
+ int result = Objects.GetHashCode(m_signature);
+ result = 31 * result + Objects.GetHashCode(m_publicKey);
return result;
}
public byte[] GetEncoded()
{
return Composer.Compose()
- .Bytes(signature.GetEncoded())
- .Bytes(publicKey.GetEncoded())
+ .Bytes(m_signature.GetEncoded())
+ .Bytes(m_publicKey.GetEncoded())
.Build();
}
}
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/lms/LMSigParameters.cs b/crypto/src/pqc/crypto/lms/LMSigParameters.cs
index 1f2a90b2b..721560cb8 100644
--- a/crypto/src/pqc/crypto/lms/LMSigParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSigParameters.cs
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Nist;
-using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Utilities.Collections;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
@@ -15,15 +14,54 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public static LMSigParameters lms_sha256_n32_h20 = new LMSigParameters(8, 32, 20, NistObjectIdentifiers.IdSha256);
public static LMSigParameters lms_sha256_n32_h25 = new LMSigParameters(9, 32, 25, NistObjectIdentifiers.IdSha256);
+ public static LMSigParameters lms_sha256_n24_h5 = new LMSigParameters(10, 24, 5, NistObjectIdentifiers.IdSha256);
+ public static LMSigParameters lms_sha256_n24_h10 = new LMSigParameters(11, 24, 10, NistObjectIdentifiers.IdSha256);
+ public static LMSigParameters lms_sha256_n24_h15 = new LMSigParameters(12, 24, 15, NistObjectIdentifiers.IdSha256);
+ public static LMSigParameters lms_sha256_n24_h20 = new LMSigParameters(13, 24, 20, NistObjectIdentifiers.IdSha256);
+ public static LMSigParameters lms_sha256_n24_h25 = new LMSigParameters(14, 24, 25, NistObjectIdentifiers.IdSha256);
+
+ public static LMSigParameters lms_shake256_n32_h5 = new LMSigParameters(15, 32, 5, NistObjectIdentifiers.IdShake256Len);
+ public static LMSigParameters lms_shake256_n32_h10 = new LMSigParameters(16, 32, 10, NistObjectIdentifiers.IdShake256Len);
+ public static LMSigParameters lms_shake256_n32_h15 = new LMSigParameters(17, 32, 15, NistObjectIdentifiers.IdShake256Len);
+ public static LMSigParameters lms_shake256_n32_h20 = new LMSigParameters(18, 32, 20, NistObjectIdentifiers.IdShake256Len);
+ public static LMSigParameters lms_shake256_n32_h25 = new LMSigParameters(19, 32, 25, NistObjectIdentifiers.IdShake256Len);
+
+ public static LMSigParameters lms_shake256_n24_h5 = new LMSigParameters(20, 24, 5, NistObjectIdentifiers.IdShake256Len);
+ public static LMSigParameters lms_shake256_n24_h10 = new LMSigParameters(21, 24, 10, NistObjectIdentifiers.IdShake256Len);
+ public static LMSigParameters lms_shake256_n24_h15 = new LMSigParameters(22, 24, 15, NistObjectIdentifiers.IdShake256Len);
+ public static LMSigParameters lms_shake256_n24_h20 = new LMSigParameters(23, 24, 20, NistObjectIdentifiers.IdShake256Len);
+ public static LMSigParameters lms_shake256_n24_h25 = new LMSigParameters(24, 24, 25, NistObjectIdentifiers.IdShake256Len);
+
private static Dictionary<int, LMSigParameters> ParametersByID = new Dictionary<int, LMSigParameters>
{
{ lms_sha256_n32_h5.ID, lms_sha256_n32_h5 },
{ lms_sha256_n32_h10.ID, lms_sha256_n32_h10 },
{ lms_sha256_n32_h15.ID, lms_sha256_n32_h15 },
{ lms_sha256_n32_h20.ID, lms_sha256_n32_h20 },
- { lms_sha256_n32_h25.ID, lms_sha256_n32_h25 }
+ { lms_sha256_n32_h25.ID, lms_sha256_n32_h25 },
+
+ { lms_sha256_n24_h5.ID, lms_sha256_n24_h5 },
+ { lms_sha256_n24_h10.ID, lms_sha256_n24_h10 },
+ { lms_sha256_n24_h15.ID, lms_sha256_n24_h15 },
+ { lms_sha256_n24_h20.ID, lms_sha256_n24_h20 },
+ { lms_sha256_n24_h25.ID, lms_sha256_n24_h25 },
+
+ { lms_shake256_n32_h5.ID, lms_shake256_n32_h5 },
+ { lms_shake256_n32_h10.ID, lms_shake256_n32_h10 },
+ { lms_shake256_n32_h15.ID, lms_shake256_n32_h15 },
+ { lms_shake256_n32_h20.ID, lms_shake256_n32_h20 },
+ { lms_shake256_n32_h25.ID, lms_shake256_n32_h25 },
+
+ { lms_shake256_n24_h5.ID, lms_shake256_n24_h5 },
+ { lms_shake256_n24_h10.ID, lms_shake256_n24_h10 },
+ { lms_shake256_n24_h15.ID, lms_shake256_n24_h15 },
+ { lms_shake256_n24_h20.ID, lms_shake256_n24_h20 },
+ { lms_shake256_n24_h25.ID, lms_shake256_n24_h25 },
};
+ public static LMSigParameters GetParametersByID(int id) =>
+ CollectionUtilities.GetValueOrNull(ParametersByID, id);
+
private readonly int m_id;
private readonly int m_m;
private readonly int m_h;
@@ -37,17 +75,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
m_digestOid = digestOid;
}
- public int ID => m_id;
+ public DerObjectIdentifier DigestOid => m_digestOid;
public int H => m_h;
- public int M => m_m;
-
- public DerObjectIdentifier DigestOid => m_digestOid;
+ public int ID => m_id;
- public static LMSigParameters GetParametersByID(int id)
- {
- return CollectionUtilities.GetValueOrNull(ParametersByID, id);
- }
+ public int M => m_m;
}
}
diff --git a/crypto/src/pqc/crypto/lms/LM_OTS.cs b/crypto/src/pqc/crypto/lms/LM_OTS.cs
index 0aa5c580e..ace40524d 100644
--- a/crypto/src/pqc/crypto/lms/LM_OTS.cs
+++ b/crypto/src/pqc/crypto/lms/LM_OTS.cs
@@ -2,11 +2,11 @@ using System;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Utilities;
-using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public static class LMOts
{
private static ushort D_PBLC = 0x8080;
@@ -15,7 +15,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
private static int ITER_J = 22;
internal static int SEED_RANDOMISER_INDEX = ~2;
- internal static int SEED_LEN = 32;
internal static int MAX_HASH = 32;
internal static ushort D_MESG = 0x8181;
@@ -47,17 +46,19 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public static LMOtsPublicKey LmsOtsGeneratePublicKey(LMOtsPrivateKey privateKey)
{
+#pragma warning disable CS0618 // Type or member is obsolete
byte[] K = LmsOtsGeneratePublicKey(privateKey.Parameters, privateKey.I, privateKey.Q,
privateKey.MasterSecret);
return new LMOtsPublicKey(privateKey.Parameters, privateKey.I, privateKey.Q, K);
+#pragma warning restore CS0618 // Type or member is obsolete
}
- internal static byte[] LmsOtsGeneratePublicKey(LMOtsParameters parameter, byte[] I, int q, byte[] masterSecret)
+ internal static byte[] LmsOtsGeneratePublicKey(LMOtsParameters parameters, byte[] I, int q, byte[] masterSecret)
{
//
// Start hash that computes the final value.
//
- IDigest publicContext = DigestUtilities.GetDigest(parameter.DigestOid);
+ IDigest publicContext = LmsUtilities.GetDigest(parameters);
byte[] prehashPrefix = Composer.Compose()
.Bytes(I)
.U32Str(q)
@@ -66,7 +67,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
.Build();
publicContext.BlockUpdate(prehashPrefix, 0, prehashPrefix.Length);
- IDigest ctx = DigestUtilities.GetDigest(parameter.DigestOid);
+ IDigest ctx = LmsUtilities.GetDigest(parameters);
byte[] buf = Composer.Compose()
.Bytes(I)
@@ -74,15 +75,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
.PadUntil(0, 23 + ctx.GetDigestSize())
.Build();
- SeedDerive derive = new SeedDerive(I, masterSecret, DigestUtilities.GetDigest(parameter.DigestOid))
+ SeedDerive derive = new SeedDerive(I, masterSecret, LmsUtilities.GetDigest(parameters))
{
Q = q,
J = 0,
};
- int p = parameter.P;
- int n = parameter.N;
- int twoToWminus1 = (1 << parameter.W) - 1;
+ int p = parameters.P;
+ int n = parameters.N;
+ int twoToWminus1 = (1 << parameters.W) - 1;
for (ushort i = 0; i < p; i++)
{
@@ -102,6 +103,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return K;
}
+ // TODO[api] Rename
public static LMOtsSignature lm_ots_generate_signature(LMSigParameters sigParams, LMOtsPrivateKey privateKey,
byte[][] path, byte[] message, bool preHashed)
{
@@ -122,8 +124,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
}
else
{
- C = new byte[SEED_LEN];
- Array.Copy(message, 0, Q, 0, privateKey.Parameters.N);
+ int n = privateKey.Parameters.N;
+
+ C = new byte[n];
+ Array.Copy(message, 0, Q, 0, n);
}
return LMOtsGenerateSignature(privateKey, Q, C);
@@ -131,27 +135,29 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public static LMOtsSignature LMOtsGenerateSignature(LMOtsPrivateKey privateKey, byte[] Q, byte[] C)
{
- LMOtsParameters parameter = privateKey.Parameters;
+ LMOtsParameters parameters = privateKey.Parameters;
- int n = parameter.N;
- int p = parameter.P;
- int w = parameter.W;
+ int n = parameters.N;
+ int p = parameters.P;
+ int w = parameters.W;
byte[] sigComposer = new byte[p * n];
- IDigest ctx = DigestUtilities.GetDigest(parameter.DigestOid);
+ IDigest ctx = LmsUtilities.GetDigest(parameters);
SeedDerive derive = privateKey.GetDerivationFunction();
- int cs = Cksm(Q, n, parameter);
+ int cs = Cksm(Q, n, parameters);
Q[n] = (byte)((cs >> 8) & 0xFF);
Q[n + 1] = (byte)cs;
+#pragma warning disable CS0618 // Type or member is obsolete
byte[] tmp = Composer.Compose()
.Bytes(privateKey.I)
.U32Str(privateKey.Q)
.PadUntil(0, ITER_PREV + n)
.Build();
+#pragma warning restore CS0618 // Type or member is obsolete
derive.J = 0;
for (ushort i = 0; i < p; i++)
@@ -168,7 +174,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
Array.Copy(tmp, ITER_PREV, sigComposer, n * i, n);
}
- return new LMOtsSignature(parameter, C, sigComposer);
+ return new LMOtsSignature(parameters, C, sigComposer);
}
public static bool LMOtsValidateSignature(LMOtsPublicKey publicKey, LMOtsSignature signature, byte[] message,
@@ -177,7 +183,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
if (!signature.ParamType.Equals(publicKey.Parameters)) // todo check
throw new LmsException("public key and signature ots types do not match");
+#pragma warning disable CS0618 // Type or member is obsolete
return Arrays.AreEqual(LMOtsValidateSignatureCalculate(publicKey, signature, message), publicKey.K);
+#pragma warning restore CS0618 // Type or member is obsolete
}
public static byte[] LMOtsValidateSignatureCalculate(LMOtsPublicKey publicKey, LMOtsSignature signature,
@@ -193,31 +201,33 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
public static byte[] LMOtsValidateSignatureCalculate(LmsContext context)
{
LMOtsPublicKey publicKey = context.PublicKey;
- LMOtsParameters parameter = publicKey.Parameters;
+ LMOtsParameters parameters = publicKey.Parameters;
object sig = context.Signature;
LMOtsSignature signature;
- if (sig is LmsSignature)
+ if (sig is LmsSignature lmsSignature)
{
- signature = ((LmsSignature)sig).OtsSignature;
+ signature = lmsSignature.OtsSignature;
}
else
{
signature = (LMOtsSignature)sig;
}
- int n = parameter.N;
- int w = parameter.W;
- int p = parameter.P;
+ int n = parameters.N;
+ int w = parameters.W;
+ int p = parameters.P;
byte[] Q = context.GetQ();
- int cs = Cksm(Q, n, parameter);
+ int cs = Cksm(Q, n, parameters);
Q[n] = (byte)((cs >> 8) & 0xFF);
Q[n + 1] = (byte)cs;
+#pragma warning disable CS0618 // Type or member is obsolete
byte[] I = publicKey.I;
+#pragma warning restore CS0618 // Type or member is obsolete
int q = publicKey.Q;
- IDigest finalContext = DigestUtilities.GetDigest(parameter.DigestOid);
+ IDigest finalContext = LmsUtilities.GetDigest(parameters);
LmsUtilities.ByteArray(I, finalContext);
LmsUtilities.U32Str(q, finalContext);
LmsUtilities.U16Str((short)D_PBLC, finalContext);
@@ -230,9 +240,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
int max_digit = (1 << w) - 1;
+#pragma warning disable CS0618 // Type or member is obsolete
byte[] y = signature.Y;
+#pragma warning restore CS0618 // Type or member is obsolete
- IDigest ctx = DigestUtilities.GetDigest(parameter.DigestOid);
+ IDigest ctx = LmsUtilities.GetDigest(parameters);
for (ushort i = 0; i < p; i++)
{
Pack.UInt16_To_BE(i, tmp, ITER_K);
diff --git a/crypto/src/pqc/crypto/lms/LmsUtils.cs b/crypto/src/pqc/crypto/lms/LmsUtils.cs
index e99dfe585..33cad48f9 100644
--- a/crypto/src/pqc/crypto/lms/LmsUtils.cs
+++ b/crypto/src/pqc/crypto/lms/LmsUtils.cs
@@ -1,9 +1,13 @@
using System;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public static class LmsUtilities
{
public static void U32Str(int n, IDigest d)
@@ -38,5 +42,90 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
LMSigParameters sigParameters = lmsParameters.LMSigParameters;
return sigParameters.M << sigParameters.H;
}
+
+ internal static IDigest GetDigest(LMOtsParameters otsParameters) =>
+ CreateDigest(otsParameters.DigestOid, otsParameters.N);
+
+ internal static IDigest GetDigest(LMSigParameters sigParameters) =>
+ CreateDigest(sigParameters.DigestOid, sigParameters.M);
+
+ private static IDigest CreateDigest(DerObjectIdentifier oid, int length)
+ {
+ // TODO Perhaps support length-specified digests directly in DigestUtilities?
+
+ IDigest digest = CreateDigest(oid);
+
+ if (NistObjectIdentifiers.IdShake256Len.Equals(oid) ||
+ digest.GetDigestSize() != length)
+ {
+ return new WrapperDigest(digest, length);
+ }
+
+ return digest;
+ }
+
+ private static IDigest CreateDigest(DerObjectIdentifier oid)
+ {
+ if (NistObjectIdentifiers.IdSha256.Equals(oid))
+ return DigestUtilities.GetDigest(NistObjectIdentifiers.IdSha256);
+
+ if (NistObjectIdentifiers.IdShake256Len.Equals(oid))
+ return DigestUtilities.GetDigest(NistObjectIdentifiers.IdShake256);
+
+ throw new LmsException("unrecognized digest OID: " + oid);
+ }
+
+ internal class WrapperDigest
+ : IDigest
+ {
+ private readonly IDigest m_digest;
+ private readonly int m_length;
+
+ internal WrapperDigest(IDigest digest, int length)
+ {
+ m_digest = digest;
+ m_length = length;
+ }
+
+ public string AlgorithmName => m_digest.AlgorithmName;
+
+ public void BlockUpdate(byte[] input, int inOff, int inLen) => m_digest.BlockUpdate(input, inOff, inLen);
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input) => m_digest.BlockUpdate(input);
+#endif
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ byte[] buf = new byte[m_digest.GetDigestSize()];
+ m_digest.DoFinal(buf, 0);
+
+ Array.Copy(buf, 0, output, outOff, m_length);
+ return m_length;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ int digestSize = m_digest.GetDigestSize();
+ Span<byte> buf = digestSize <= 128
+ ? stackalloc byte[digestSize]
+ : new byte[digestSize];
+
+ m_digest.DoFinal(buf);
+
+ buf[..m_length].CopyTo(output);
+ return m_length;
+ }
+#endif
+
+ public int GetByteLength() => m_digest.GetByteLength();
+
+ public int GetDigestSize() => m_length;
+
+ public void Reset() => m_digest.Reset();
+
+ public void Update(byte input) => m_digest.Update(input);
+ }
}
}
diff --git a/crypto/src/pqc/crypto/lms/SeedDerive.cs b/crypto/src/pqc/crypto/lms/SeedDerive.cs
index 38b72fd3f..98076760e 100644
--- a/crypto/src/pqc/crypto/lms/SeedDerive.cs
+++ b/crypto/src/pqc/crypto/lms/SeedDerive.cs
@@ -2,9 +2,11 @@ using System;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
+ // TODO[api] Make internal
public sealed class SeedDerive
{
private readonly byte[] m_I;
@@ -18,15 +20,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
m_digest = digest;
}
- public int Q { get; set; }
+ public byte[] GetI() => Arrays.Clone(m_I);
- public int J { get; set; }
+ public byte[] GetMasterSeed() => Arrays.Clone(m_masterSeed);
- // FIXME
- public byte[] I => m_I;
+ public int J { get; set; }
- // FIXME
- public byte[] MasterSeed => m_masterSeed;
+ public int Q { get; set; }
public byte[] DeriveSeed(bool incJ, byte[] target, int offset)
{
@@ -35,7 +35,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
int q = Q, j = J;
+#pragma warning disable CS0618 // Type or member is obsolete
m_digest.BlockUpdate(I, 0, I.Length);
+#pragma warning restore CS0618 // Type or member is obsolete
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
Span<byte> qj = stackalloc byte[7];
@@ -54,7 +56,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
m_digest.Update(0xFF);
#endif
+#pragma warning disable CS0618 // Type or member is obsolete
m_digest.BlockUpdate(m_masterSeed, 0, m_masterSeed.Length);
+#pragma warning restore CS0618 // Type or member is obsolete
m_digest.DoFinal(target, offset); // Digest resets here.
@@ -65,5 +69,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
return target;
}
+
+ [Obsolete("Use 'GetI' instead")]
+ public byte[] I => m_I;
+
+ [Obsolete("Use 'GetMasterSeed' instead")]
+ public byte[] MasterSeed => m_masterSeed;
}
}
diff --git a/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
index 4be386ed4..235478258 100644
--- a/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
@@ -49,7 +49,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
}
if (privateKey is HssPrivateKeyParameters hssPrivateKeyParameters)
{
- int L = hssPrivateKeyParameters.L;
+ int L = hssPrivateKeyParameters.Level;
byte[] encoding = Composer.Compose().U32Str(L).Bytes(hssPrivateKeyParameters).Build();
byte[] pubEncoding = Composer.Compose().U32Str(L).Bytes(hssPrivateKeyParameters.GetPublicKey().LmsPublicKey).Build();
diff --git a/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
index d99b5966b..3c55705c1 100644
--- a/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
@@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
}
if (publicKey is HssPublicKeyParameters hssPublicKeyParameters)
{
- int L = hssPublicKeyParameters.L;
+ int L = hssPublicKeyParameters.Level;
byte[] encoding = Composer.Compose().U32Str(L).Bytes(hssPublicKeyParameters.LmsPublicKey).Build();
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdAlgHssLmsHashsig);
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index f99065512..ab96357b1 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -115,6 +115,44 @@ namespace Org.BouncyCastle.Utilities
return true;
}
+ public static bool AreEqual(object[] a, object[] b)
+ {
+ if (a == b)
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ int length = a.Length;
+ if (length != b.Length)
+ return false;
+
+ for (int i = 0; i < length; ++i)
+ {
+ if (!Objects.Equals(a[i], b[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ public static bool AreEqual(object[] a, int aFromIndex, int aToIndex, object[] b, int bFromIndex, int bToIndex)
+ {
+ int aLength = aToIndex - aFromIndex;
+ int bLength = bToIndex - bFromIndex;
+
+ if (aLength != bLength)
+ return false;
+
+ for (int i = 0; i < aLength; ++i)
+ {
+ if (!Objects.Equals(a[aFromIndex + i], b[bFromIndex + i]))
+ return false;
+ }
+
+ return true;
+ }
+
[Obsolete("Use 'FixedTimeEquals' instead")]
public static bool ConstantTimeAreEqual(byte[] a, byte[] b)
{
@@ -530,6 +568,35 @@ namespace Org.BouncyCastle.Utilities
return hc;
}
+ public static int GetHashCode(object[] data)
+ {
+ if (data == null)
+ return 0;
+
+ int len = data.Length;
+ int hc = len + 1;
+ for (int i = 0; i < len; ++i)
+ {
+ hc *= 257;
+ hc ^= Objects.GetHashCode(data[i]);
+ }
+ return hc;
+ }
+
+ public static int GetHashCode(object[] data, int off, int len)
+ {
+ if (data == null)
+ return 0;
+
+ int hc = len + 1;
+ for (int i = 0; i < len; ++i)
+ {
+ hc *= 257;
+ hc ^= Objects.GetHashCode(data[off + i]);
+ }
+ return hc;
+ }
+
public static bool[] Clone(bool[] data)
{
return data == null ? null : (bool[])data.Clone();
|