Skip to content

Commit 7f8bb90

Browse files
committed
ML-DSA: Test vectors for signing with a context
1 parent 43d0245 commit 7f8bb90

File tree

3 files changed

+105
-2
lines changed

3 files changed

+105
-2
lines changed

crypto/src/crypto/parameters/MLDsaParameters.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ private MLDsaParameters(string name, MLDsaParameterSet parameterSet, DerObjectId
6262
m_preHashOid = preHashOid;
6363
}
6464

65+
public bool IsPreHash => m_preHashOid != null;
66+
6567
public string Name => m_name;
6668

6769
internal DerObjectIdentifier Oid => m_oid;

crypto/src/security/ParameterUtilities.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,15 @@ public static ICipherParameters IgnoreRandom(ICipherParameters cipherParameters)
377377
return cipherParameters;
378378
}
379379

380+
public static ICipherParameters WithContext(ICipherParameters cp, byte[] context)
381+
{
382+
if (context != null)
383+
{
384+
cp = new ParametersWithContext(cp, context);
385+
}
386+
return cp;
387+
}
388+
380389
public static ICipherParameters WithRandom(ICipherParameters cp, SecureRandom random)
381390
{
382391
if (random != null)

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

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ public class MLDsaTest
3434
{ "sigVer_ML-DSA-87.txt", MLDsaParameters.ml_dsa_87 },
3535
};
3636

37+
private static readonly Dictionary<string, MLDsaParameters> ContextFileParameters =
38+
new Dictionary<string, MLDsaParameters>()
39+
{
40+
{ "mldsa44.rsp", MLDsaParameters.ml_dsa_44 },
41+
{ "mldsa65.rsp", MLDsaParameters.ml_dsa_65 },
42+
{ "mldsa87.rsp", MLDsaParameters.ml_dsa_87 },
43+
{ "mldsa44Sha512.rsp", MLDsaParameters.ml_dsa_44_with_sha512 },
44+
{ "mldsa65Sha512.rsp", MLDsaParameters.ml_dsa_65_with_sha512 },
45+
{ "mldsa87Sha512.rsp", MLDsaParameters.ml_dsa_87_with_sha512 },
46+
};
47+
3748
private static readonly Dictionary<string, MLDsaParameters> Parameters =
3849
new Dictionary<string, MLDsaParameters>()
3950
{
@@ -51,6 +62,8 @@ public class MLDsaTest
5162
"keyGen_ML-DSA-87.txt",
5263
};
5364

65+
private static readonly IEnumerable<string> ContextFiles = ContextFileParameters.Keys;
66+
5467
private static readonly string[] SigGenAcvpFiles =
5568
{
5669
"sigGen_ML-DSA-44.txt",
@@ -107,6 +120,14 @@ public void Consistency(MLDsaParameters parameters)
107120
while (msgLen <= 2048);
108121
}
109122

123+
[TestCaseSource(nameof(ContextFiles))]
124+
[Parallelizable]
125+
public void Context(string fileName)
126+
{
127+
RunTestVectors("pqc/crypto/mldsa", fileName,
128+
(name, data) => ImplContext(name, data, ContextFileParameters[name]));
129+
}
130+
110131
[Test]
111132
[Parallelizable]
112133
public void KeyGen()
@@ -155,6 +176,77 @@ public void KeyGenAcvp(string fileName)
155176
// (name, data) => ImplSigVer(name, data, AcvpFileParameters[name]));
156177
//}
157178

179+
private static void ImplContext(string name, Dictionary<string, string> data, MLDsaParameters parameters)
180+
{
181+
string count = data["count"];
182+
byte[] seed = Hex.Decode(data["seed"]);
183+
byte[] msg = Hex.Decode(data["msg"]);
184+
byte[] pk = Hex.Decode(data["pk"]);
185+
byte[] sk = Hex.Decode(data["sk"]);
186+
byte[] sm = Hex.Decode(data["sm"]);
187+
188+
byte[] context = null;
189+
if (data.TryGetValue("context", out var contextValue))
190+
{
191+
context = Hex.Decode(contextValue);
192+
}
193+
194+
var random = FixedSecureRandom.From(seed);
195+
196+
var kpg = new MLDsaKeyPairGenerator();
197+
kpg.Init(new MLDsaKeyGenerationParameters(random, parameters));
198+
199+
var kp = kpg.GenerateKeyPair();
200+
201+
var publicKey = (MLDsaPublicKeyParameters)kp.Public;
202+
var privateKey = (MLDsaPrivateKeyParameters)kp.Private;
203+
204+
Assert.True(Arrays.AreEqual(pk, publicKey.GetEncoded()), $"{name} {count}: public key");
205+
Assert.True(Arrays.AreEqual(sk, privateKey.GetEncoded()), $"{name} {count}: secret key");
206+
207+
var publicKeyRT = (MLDsaPublicKeyParameters)PublicKeyFactory.CreateKey(
208+
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
209+
var privateKeyRT = (MLDsaPrivateKeyParameters)PrivateKeyFactory.CreateKey(
210+
PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey));
211+
212+
Assert.True(Arrays.AreEqual(pk, publicKeyRT.GetEncoded()), $"{name} {count}: public key (round-trip)");
213+
Assert.True(Arrays.AreEqual(sk, privateKeyRT.GetEncoded()), $"{name} {count}: secret key (round-trip)");
214+
215+
// Note that this is a deterministic signature test, since we are not given "rnd"
216+
ISigner sig;
217+
if (parameters.IsPreHash)
218+
{
219+
sig = new HashMLDsaSigner(parameters, deterministic: true);
220+
}
221+
else
222+
{
223+
sig = new MLDsaSigner(parameters, deterministic: true);
224+
}
225+
226+
// The current test data is a bit weird and uses internal signing when no explicit context provided.
227+
if (context == null)
228+
{
229+
//var rnd = new byte[32]; // Deterministic
230+
//byte[] generated = privateKey.SignInternal(rnd, msg, 0, msg.Length);
231+
//Assert.True(Arrays.AreEqual(sm, generated), $"{name} {count}: SignInternal");
232+
233+
//bool shouldVerify = publicKey.VerifyInternal(msg, 0, msg.Length, sm);
234+
//Assert.True(shouldVerify, $"{name} {count}: VerifyInternal");
235+
}
236+
else
237+
{
238+
sig.Init(forSigning: true, ParameterUtilities.WithContext(privateKey, context));
239+
sig.BlockUpdate(msg, 0, msg.Length);
240+
byte[] generated = sig.GenerateSignature();
241+
Assert.True(Arrays.AreEqual(sm, generated), $"{name} {count}: GenerateSignature");
242+
243+
sig.Init(forSigning: false, ParameterUtilities.WithContext(publicKey, context));
244+
sig.BlockUpdate(msg, 0, msg.Length);
245+
bool shouldVerify = sig.VerifySignature(sm);
246+
Assert.True(shouldVerify, $"{name} {count}: VerifySignature");
247+
}
248+
}
249+
158250
private static void ImplKeyGen(string name, Dictionary<string, string> data, MLDsaParameters parameters)
159251
{
160252
byte[] seed = Hex.Decode(data["seed"]);
@@ -195,7 +287,7 @@ private static void ImplKeyGen(string name, Dictionary<string, string> data, MLD
195287
// rnd = Hex.Decode(data["rnd"]);
196288
// }
197289

198-
// var privateKey = new MLDsaPrivateKeyParameters(parameters, sk);
290+
// var privateKey = MLDsaPrivateKeyParameters.FromEncoding(parameters, sk);
199291

200292
// byte[] generated = privateKey.SignInternal(rnd, message, 0, message.Length);
201293

@@ -209,7 +301,7 @@ private static void ImplKeyGen(string name, Dictionary<string, string> data, MLD
209301
// byte[] message = Hex.Decode(data["message"]);
210302
// byte[] signature = Hex.Decode(data["signature"]);
211303

212-
// var publicKey = new MLDsaPublicKeyParameters(parameters, pk);
304+
// var publicKey = MLDsaPublicKeyParameters.FromEncoding(parameters, pk);
213305

214306
// bool verified = publicKey.VerifyInternal(message, 0, message.Length, signature);
215307

0 commit comments

Comments
 (0)