Skip to content

Commit b788586

Browse files
committed
Refactoring in LMS
1 parent ae9ac87 commit b788586

File tree

6 files changed

+79
-29
lines changed

6 files changed

+79
-29
lines changed

crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs

+9-9
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ protected void UpdateHierarchy(IList<LmsPrivateKeyParameters> newKeys, IList<Lms
155155

156156
public long IndexLimit => m_indexLimit;
157157

158-
public long GetUsagesRemaining() => m_indexLimit - m_index;
158+
public long GetUsagesRemaining() => IndexLimit - GetIndex();
159159

160160
internal LmsPrivateKeyParameters GetRootKey() => m_keys[0];
161161

@@ -172,22 +172,22 @@ public HssPrivateKeyParameters ExtractKeyShard(int usageCount)
172172
{
173173
lock (this)
174174
{
175-
if (GetUsagesRemaining() < usageCount)
176-
throw new ArgumentException("usageCount exceeds usages remaining in current leaf");
175+
if (usageCount < 0)
176+
throw new ArgumentOutOfRangeException("cannot be negative", nameof(usageCount));
177+
if (usageCount > m_indexLimit - m_index)
178+
throw new ArgumentException("exceeds usages remaining in current leaf", nameof(usageCount));
177179

178-
long maxIndexForShard = m_index + usageCount;
179-
long shardStartIndex = m_index;
180+
long shardIndex = m_index;
181+
long shardIndexLimit = m_index + usageCount;
180182

181-
//
182183
// Move this key's index along
183-
//
184-
m_index += usageCount;
184+
m_index = shardIndexLimit;
185185

186186
var keys = new List<LmsPrivateKeyParameters>(this.GetKeys());
187187
var sig = new List<LmsSignature>(this.GetSig());
188188

189189
HssPrivateKeyParameters shard = MakeCopy(
190-
new HssPrivateKeyParameters(m_level, keys, sig, shardStartIndex, maxIndexForShard, true));
190+
new HssPrivateKeyParameters(m_level, keys, sig, shardIndex, shardIndexLimit, isShard: true));
191191

192192
ResetKeyToIndex();
193193

crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs

+14-6
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,18 @@ public LmsPrivateKeyParameters ExtractKeyShard(int usageCount)
211211
{
212212
lock (this)
213213
{
214-
if (q + usageCount >= maxQ)
215-
throw new ArgumentException("usageCount exceeds usages remaining");
214+
if (usageCount < 0)
215+
throw new ArgumentOutOfRangeException("cannot be negative", nameof(usageCount));
216+
if (usageCount > maxQ - q)
217+
throw new ArgumentException("exceeds usages remaining", nameof(usageCount));
216218

217-
LmsPrivateKeyParameters keyParameters = new LmsPrivateKeyParameters(this, q, q + usageCount);
218-
q += usageCount;
219+
int shardIndex = q;
220+
int shardIndexLimit = q + usageCount;
219221

220-
return keyParameters;
222+
// Move this key's index along
223+
q = shardIndexLimit;
224+
225+
return new LmsPrivateKeyParameters(this, shardIndex, shardIndexLimit);
221226
}
222227
}
223228

@@ -235,7 +240,10 @@ public LmsPrivateKeyParameters ExtractKeyShard(int usageCount)
235240

236241
public byte[] GetMasterSecret() => Arrays.Clone(masterSecret);
237242

238-
public long GetUsagesRemaining() => maxQ - GetIndex();
243+
public int IndexLimit => maxQ;
244+
245+
// TODO[api] Only needs 'int'
246+
public long GetUsagesRemaining() => IndexLimit - GetIndex();
239247

240248
public LmsPublicKeyParameters GetPublicKey()
241249
{

crypto/src/pqc/crypto/utils/PqcPublicKeyFactory.cs

+42-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using Org.BouncyCastle.Asn1;
66
using Org.BouncyCastle.Asn1.BC;
7-
using Org.BouncyCastle.Asn1.Nist;
87
using Org.BouncyCastle.Asn1.Pkcs;
98
using Org.BouncyCastle.Asn1.X509;
109
using Org.BouncyCastle.Crypto;
@@ -232,21 +231,53 @@ internal static DilithiumPublicKeyParameters GetDilithiumPublicKey(DilithiumPara
232231

233232
private static AsymmetricKeyParameter LmsConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
234233
{
235-
byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
234+
DerBitString publicKey = keyInfo.PublicKey;
236235

237-
if (Pack.BE_To_UInt32(keyEnc, 0) == 1U)
238-
{
239-
return LmsPublicKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length));
240-
}
241-
else
236+
if (publicKey.IsOctetAligned())
242237
{
243-
// public key with extra tree height
244-
if (keyEnc.Length == 64)
238+
//int expectedLength = ???;
239+
240+
//int bytesLength = publicKey.GetBytesLength();
241+
//if (bytesLength == expectedLength)
242+
// return GetLmsKeyParameters(publicKey.GetOctets());
243+
244+
// TODO[pqc] Remove support for legacy/prototype formats?
245+
//if (bytesLength > expectedLength)
245246
{
246-
keyEnc = Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length);
247+
try
248+
{
249+
Asn1Object obj = Asn1Object.FromMemoryStream(publicKey.GetOctetMemoryStream());
250+
if (obj is Asn1OctetString oct)
251+
{
252+
//if (oct.GetOctetsLength() == expectedLength)
253+
{
254+
return GetLmsKeyParameters(oct.GetOctets());
255+
}
256+
}
257+
}
258+
catch (Exception)
259+
{
260+
}
247261
}
248-
return HssPublicKeyParameters.GetInstance(keyEnc);
262+
263+
return GetLmsKeyParameters(publicKey.GetOctets());
249264
}
265+
266+
throw new ArgumentException($"invalid LMS public key");
267+
}
268+
269+
private static LmsKeyParameters GetLmsKeyParameters(byte[] keyEnc)
270+
{
271+
if (Pack.BE_To_UInt32(keyEnc, 0) == 1U)
272+
return LmsPublicKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length));
273+
274+
// public key with extra tree height
275+
if (keyEnc.Length == 64)
276+
{
277+
keyEnc = Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length);
278+
}
279+
280+
return HssPublicKeyParameters.GetInstance(keyEnc);
250281
}
251282

252283
#pragma warning disable CS0618 // Type or member is obsolete

crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(AsymmetricKeyParam
4343
byte[] encoding = Composer.Compose().U32Str(1).Bytes(lmsPublicKeyParameters).Build();
4444

4545
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdAlgHssLmsHashsig);
46-
return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
46+
return new SubjectPublicKeyInfo(algorithmIdentifier, encoding);
4747
}
4848
if (publicKey is HssPublicKeyParameters hssPublicKeyParameters)
4949
{
5050
int L = hssPublicKeyParameters.Level;
5151
byte[] encoding = Composer.Compose().U32Str(L).Bytes(hssPublicKeyParameters.LmsPublicKey).Build();
5252

5353
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdAlgHssLmsHashsig);
54-
return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
54+
return new SubjectPublicKeyInfo(algorithmIdentifier, encoding);
5555
}
5656
#pragma warning disable CS0618 // Type or member is obsolete
5757
if (publicKey is SphincsPlusPublicKeyParameters sphincsPlusPublicKeyParameters)

crypto/test/src/pqc/crypto/lms/test/HssTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ public void TestVectorsFromReference_Expanded()
507507

508508
Assert.AreEqual(1024, keyPair.GetUsagesRemaining());
509509
Assert.AreEqual(1024, keyPair.IndexLimit);
510+
Assert.AreEqual(0, keyPair.GetIndex());
510511

511512
//
512513
// Split the space up with a shard.
@@ -603,6 +604,7 @@ public void TestRemaining()
603604

604605
HssPrivateKeyParameters shard = keyPair.ExtractKeyShard(10);
605606

607+
Assert.True(10 == shard.GetUsagesRemaining());
606608
Assert.True(15 == shard.IndexLimit);
607609
Assert.True(5 == shard.GetIndex());
608610

crypto/test/src/pqc/crypto/test/LMSTest.cs

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using NUnit.Framework;
44

55
using Org.BouncyCastle.Asn1.Pkcs;
6+
using Org.BouncyCastle.Asn1.X509;
67
using Org.BouncyCastle.Crypto;
78
using Org.BouncyCastle.Pqc.Crypto.Lms;
89
using Org.BouncyCastle.Pqc.Crypto.Utilities;
@@ -97,6 +98,7 @@ public void TestKeyGenAndSignTwoSigsWithShard()
9798
LmsSigner signer = new LmsSigner();
9899

99100
Assert.AreEqual(2, privKey.GetUsagesRemaining());
101+
Assert.AreEqual(2, privKey.IndexLimit);
100102
Assert.AreEqual(0, privKey.GetIndex());
101103

102104
signer.Init(true, privKey);
@@ -141,12 +143,19 @@ public void TestKeyGenAndSignTwoSigsWithShard()
141143

142144
Assert.True(signer.VerifySignature(msg1, sig1));
143145

144-
PrivateKeyInfo pInfo = PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo(kp.Private);//TODO
146+
PrivateKeyInfo pInfo = PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo(kp.Private);
145147
AsymmetricKeyParameter pKey = PqcPrivateKeyFactory.CreateKey(pInfo.GetEncoded());
146148

147149
signer.Init(false, ((LmsPrivateKeyParameters)pKey).GetPublicKey());
148150

149151
Assert.True(signer.VerifySignature(msg1, sig1));
152+
153+
SubjectPublicKeyInfo spki = PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(kp.Public);
154+
AsymmetricKeyParameter publicKeyRT = PqcPublicKeyFactory.CreateKey(spki.GetEncoded());
155+
156+
signer.Init(false, publicKeyRT);
157+
158+
Assert.True(signer.VerifySignature(msg1, sig1));
150159
}
151160

152161
[Test]

0 commit comments

Comments
 (0)