Skip to content

Commit e3f1ffc

Browse files
committed
SLH-DSA: Test vectors for signing with a context
1 parent 7f8bb90 commit e3f1ffc

File tree

3 files changed

+149
-7
lines changed

3 files changed

+149
-7
lines changed

crypto/src/crypto/parameters/SlhDsaParameters.cs

+2
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ private SlhDsaParameters(string name, SlhDsaParameterSet parameterSet, DerObject
153153
m_preHashOid = preHashOid;
154154
}
155155

156+
public bool IsPreHash => m_preHashOid != null;
157+
156158
public string Name => m_name;
157159

158160
internal DerObjectIdentifier Oid => m_oid;

crypto/test/src/crypto/test/MLDsaTest.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ public class MLDsaTest
4545
{ "mldsa87Sha512.rsp", MLDsaParameters.ml_dsa_87_with_sha512 },
4646
};
4747

48+
private static readonly IEnumerable<string> ContextFiles = ContextFileParameters.Keys;
49+
4850
private static readonly Dictionary<string, MLDsaParameters> Parameters =
4951
new Dictionary<string, MLDsaParameters>()
5052
{
@@ -62,8 +64,6 @@ public class MLDsaTest
6264
"keyGen_ML-DSA-87.txt",
6365
};
6466

65-
private static readonly IEnumerable<string> ContextFiles = ContextFileParameters.Keys;
66-
6767
private static readonly string[] SigGenAcvpFiles =
6868
{
6969
"sigGen_ML-DSA-44.txt",

crypto/test/src/crypto/test/SlhDsaTest.cs

+145-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Org.BouncyCastle.Crypto.Parameters;
88
using Org.BouncyCastle.Crypto.Signers;
99
using Org.BouncyCastle.Pkcs;
10+
using Org.BouncyCastle.Pqc.Crypto.Tests;
1011
using Org.BouncyCastle.Security;
1112
using Org.BouncyCastle.Utilities;
1213
using Org.BouncyCastle.Utilities.Encoders;
@@ -39,6 +40,44 @@ public class SlhDsaTest
3940
{ "sigVer_SLH-DSA-SHAKE-256f.txt", SlhDsaParameters.slh_dsa_shake_256f },
4041
};
4142

43+
private static readonly Dictionary<string, SlhDsaParameters> ContextFastFileParameters =
44+
new Dictionary<string, SlhDsaParameters>()
45+
{
46+
{ "sha2-128f.rsp", SlhDsaParameters.slh_dsa_sha2_128f },
47+
{ "sha2-128f-sha256.rsp", SlhDsaParameters.slh_dsa_sha2_128f_with_sha256 },
48+
{ "sha2-192f.rsp", SlhDsaParameters.slh_dsa_sha2_192f },
49+
{ "sha2-192f-sha512.rsp", SlhDsaParameters.slh_dsa_sha2_192f_with_sha512 },
50+
{ "sha2-256f.rsp", SlhDsaParameters.slh_dsa_sha2_256f },
51+
{ "sha2-256f-sha512.rsp", SlhDsaParameters.slh_dsa_sha2_256f_with_sha512 },
52+
{ "shake-128f.rsp", SlhDsaParameters.slh_dsa_shake_128f },
53+
{ "shake-128f-shake128.rsp", SlhDsaParameters.slh_dsa_shake_128f_with_shake128 },
54+
{ "shake-192f.rsp", SlhDsaParameters.slh_dsa_shake_192f },
55+
{ "shake-192f-shake256.rsp", SlhDsaParameters.slh_dsa_shake_192f_with_shake256 },
56+
{ "shake-256f.rsp", SlhDsaParameters.slh_dsa_shake_256f },
57+
{ "shake-256f-shake256.rsp", SlhDsaParameters.slh_dsa_shake_256f_with_shake256 },
58+
};
59+
60+
private static readonly IEnumerable<string> ContextFastFiles = ContextFastFileParameters.Keys;
61+
62+
private static readonly Dictionary<string, SlhDsaParameters> ContextSlowFileParameters =
63+
new Dictionary<string, SlhDsaParameters>()
64+
{
65+
{ "sha2-128s.rsp", SlhDsaParameters.slh_dsa_sha2_128s },
66+
{ "sha2-128s-sha256.rsp", SlhDsaParameters.slh_dsa_sha2_128s_with_sha256 },
67+
{ "sha2-192s.rsp", SlhDsaParameters.slh_dsa_sha2_192s },
68+
{ "sha2-192s-sha512.rsp", SlhDsaParameters.slh_dsa_sha2_192s_with_sha512 },
69+
{ "sha2-256s.rsp", SlhDsaParameters.slh_dsa_sha2_256s },
70+
{ "sha2-256s-sha512.rsp", SlhDsaParameters.slh_dsa_sha2_256s_with_sha512 },
71+
{ "shake-128s.rsp", SlhDsaParameters.slh_dsa_shake_128s },
72+
{ "shake-128s-shake128.rsp", SlhDsaParameters.slh_dsa_shake_128s_with_shake128 },
73+
{ "shake-192s.rsp", SlhDsaParameters.slh_dsa_shake_192s },
74+
{ "shake-192s-shake256.rsp", SlhDsaParameters.slh_dsa_shake_192s_with_shake256 },
75+
{ "shake-256s.rsp", SlhDsaParameters.slh_dsa_shake_256s },
76+
{ "shake-256s-shake256.rsp", SlhDsaParameters.slh_dsa_shake_256s_with_shake256 },
77+
};
78+
79+
private static readonly IEnumerable<string> ContextSlowFiles = ContextSlowFileParameters.Keys;
80+
4281
private static readonly Dictionary<string, SlhDsaParameters> Parameters =
4382
new Dictionary<string, SlhDsaParameters>()
4483
{
@@ -118,6 +157,22 @@ public void Consistency(SlhDsaParameters parameters)
118157
}
119158
}
120159

160+
[TestCaseSource(nameof(ContextFastFiles))]
161+
[Parallelizable]
162+
public void ContextFast(string fileName)
163+
{
164+
RunTestVectors("pqc/crypto/slhdsa", fileName, sampleOnly: true,
165+
(name, data) => ImplContext(name, data, ContextFastFileParameters[name]));
166+
}
167+
168+
[TestCaseSource(nameof(ContextSlowFiles)), Explicit]
169+
[Parallelizable]
170+
public void ContextSlow(string fileName)
171+
{
172+
RunTestVectors("pqc/crypto/slhdsa", fileName, sampleOnly: true,
173+
(name, data) => ImplContext(name, data, ContextSlowFileParameters[name]));
174+
}
175+
121176
[Test]
122177
[Parallelizable]
123178
public void KeyGen()
@@ -166,6 +221,80 @@ public void KeyGenAcvp(string fileName)
166221
// (name, data) => ImplSigVer(name, data, AcvpFileParameters[name]));
167222
//}
168223

224+
private static void ImplContext(string name, Dictionary<string, string> data, SlhDsaParameters parameters)
225+
{
226+
string count = data["count"];
227+
byte[] seed = Hex.Decode(data["seed"]);
228+
byte[] msg = Hex.Decode(data["msg"]);
229+
byte[] pk = Hex.Decode(data["pk"]);
230+
byte[] sk = Hex.Decode(data["sk"]);
231+
byte[] sm = Hex.Decode(data["sm"]);
232+
byte[] optrand = Hex.Decode(data["optrand"]);
233+
234+
byte[] context = null;
235+
if (data.TryGetValue("context", out var contextValue))
236+
{
237+
context = Hex.Decode(contextValue);
238+
}
239+
240+
var random = FixedSecureRandom.From(seed);
241+
242+
var kpg = new SlhDsaKeyPairGenerator();
243+
kpg.Init(new SlhDsaKeyGenerationParameters(random, parameters));
244+
245+
var kp = kpg.GenerateKeyPair();
246+
247+
var publicKey = (SlhDsaPublicKeyParameters)kp.Public;
248+
var privateKey = (SlhDsaPrivateKeyParameters)kp.Private;
249+
250+
Assert.True(Arrays.AreEqual(pk, publicKey.GetEncoded()), $"{name} {count}: public key");
251+
Assert.True(Arrays.AreEqual(sk, privateKey.GetEncoded()), $"{name} {count}: secret key");
252+
253+
var publicKeyRT = (SlhDsaPublicKeyParameters)PublicKeyFactory.CreateKey(
254+
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
255+
var privateKeyRT = (SlhDsaPrivateKeyParameters)PrivateKeyFactory.CreateKey(
256+
PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey));
257+
258+
Assert.True(Arrays.AreEqual(pk, publicKeyRT.GetEncoded()), $"{name} {count}: public key (round-trip)");
259+
Assert.True(Arrays.AreEqual(sk, privateKeyRT.GetEncoded()), $"{name} {count}: secret key (round-trip)");
260+
261+
// Note that this is not a deterministic signature test, since we are given "optrand"
262+
ISigner sig;
263+
if (parameters.IsPreHash)
264+
{
265+
sig = new HashSlhDsaSigner(parameters, deterministic: false);
266+
}
267+
else
268+
{
269+
sig = new SlhDsaSigner(parameters, deterministic: false);
270+
}
271+
272+
// The current test data is a bit weird and uses internal signing when no explicit context provided.
273+
if (context == null)
274+
{
275+
//byte[] generated = privateKey.SignInternal(optrand, msg, 0, msg.Length);
276+
//Assert.True(Arrays.AreEqual(sm, generated), $"{name} {count}: SignInternal");
277+
278+
//bool shouldVerify = publicKey.VerifyInternal(msg, 0, msg.Length, sm);
279+
//Assert.True(shouldVerify, $"{name} {count}: VerifyInternal");
280+
}
281+
else
282+
{
283+
sig.Init(forSigning: true,
284+
ParameterUtilities.WithContext(
285+
ParameterUtilities.WithRandom(privateKey, FixedSecureRandom.From(optrand)),
286+
context));
287+
sig.BlockUpdate(msg, 0, msg.Length);
288+
byte[] generated = sig.GenerateSignature();
289+
Assert.True(Arrays.AreEqual(sm, generated), $"{name} {count}: GenerateSignature");
290+
291+
sig.Init(forSigning: false, ParameterUtilities.WithContext(publicKey, context));
292+
sig.BlockUpdate(msg, 0, msg.Length);
293+
bool shouldVerify = sig.VerifySignature(sm);
294+
Assert.True(shouldVerify, $"{name} {count}: VerifySignature");
295+
}
296+
}
297+
169298
private static void ImplKeyGen(string name, Dictionary<string, string> data, SlhDsaParameters parameters)
170299
{
171300
byte[] skSeed = Hex.Decode(data["skSeed"]);
@@ -204,7 +333,7 @@ private static void ImplKeyGen(string name, Dictionary<string, string> data, Slh
204333
// additionalRandomness = Hex.Decode(data["additionalRandomness"]);
205334
// }
206335

207-
// var privateKey = new SlhDsaPrivateKeyParameters(parameters, sk);
336+
// var privateKey = SlhDsaPrivateKeyParameters.FromEncoding(parameters, sk);
208337

209338
// byte[] generated = privateKey.SignInternal(optRand: additionalRandomness, message, 0, message.Length);
210339

@@ -218,16 +347,21 @@ private static void ImplKeyGen(string name, Dictionary<string, string> data, Slh
218347
// byte[] message = Hex.Decode(data["message"]);
219348
// byte[] signature = Hex.Decode(data["signature"]);
220349

221-
// var publicKey = new SlhDsaPublicKeyParameters(parameters, pk);
350+
// var publicKey = SlhDsaPublicKeyParameters.FromEncoding(parameters, pk);
222351

223352
// bool verified = publicKey.VerifyInternal(message, 0, message.Length, signature);
224353

225354
// Assert.True(verified == testPassed, "expected " + testPassed);
226355
//}
227356

228-
private static void RunTestVectors(string homeDir, string fileName, RunTestVector runTestVector)
357+
private static void RunTestVectors(string homeDir, string fileName, RunTestVector runTestVector) =>
358+
RunTestVectors(homeDir, fileName, sampleOnly: false, runTestVector);
359+
360+
private static void RunTestVectors(string homeDir, string fileName, bool sampleOnly,
361+
RunTestVector runTestVector)
229362
{
230363
var data = new Dictionary<string, string>();
364+
var sampler = sampleOnly ? new TestSampler() : null;
231365
using (var src = new StreamReader(SimpleTest.FindTestResource(homeDir, fileName)))
232366
{
233367
string line;
@@ -249,14 +383,20 @@ private static void RunTestVectors(string homeDir, string fileName, RunTestVecto
249383

250384
if (data.Count > 0)
251385
{
252-
runTestVector(fileName, data);
386+
if (sampler == null || !sampler.SkipTest(data["count"]))
387+
{
388+
runTestVector(fileName, data);
389+
}
253390
data.Clear();
254391
}
255392
}
256393

257394
if (data.Count > 0)
258395
{
259-
runTestVector(fileName, data);
396+
if (sampler == null || !sampler.SkipTest(data["count"]))
397+
{
398+
runTestVector(fileName, data);
399+
}
260400
data.Clear();
261401
}
262402
}

0 commit comments

Comments
 (0)