Skip to content

Commit

Permalink
ML-DSA: Test vectors for signing with a context
Browse files Browse the repository at this point in the history
  • Loading branch information
peterdettman committed Nov 27, 2024
1 parent 43d0245 commit 7f8bb90
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 2 deletions.
2 changes: 2 additions & 0 deletions crypto/src/crypto/parameters/MLDsaParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ private MLDsaParameters(string name, MLDsaParameterSet parameterSet, DerObjectId
m_preHashOid = preHashOid;
}

public bool IsPreHash => m_preHashOid != null;

public string Name => m_name;

internal DerObjectIdentifier Oid => m_oid;
Expand Down
9 changes: 9 additions & 0 deletions crypto/src/security/ParameterUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,15 @@ public static ICipherParameters IgnoreRandom(ICipherParameters cipherParameters)
return cipherParameters;
}

public static ICipherParameters WithContext(ICipherParameters cp, byte[] context)
{
if (context != null)
{
cp = new ParametersWithContext(cp, context);
}
return cp;
}

public static ICipherParameters WithRandom(ICipherParameters cp, SecureRandom random)
{
if (random != null)
Expand Down
96 changes: 94 additions & 2 deletions crypto/test/src/crypto/test/MLDsaTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ public class MLDsaTest
{ "sigVer_ML-DSA-87.txt", MLDsaParameters.ml_dsa_87 },
};

private static readonly Dictionary<string, MLDsaParameters> ContextFileParameters =
new Dictionary<string, MLDsaParameters>()
{
{ "mldsa44.rsp", MLDsaParameters.ml_dsa_44 },
{ "mldsa65.rsp", MLDsaParameters.ml_dsa_65 },
{ "mldsa87.rsp", MLDsaParameters.ml_dsa_87 },
{ "mldsa44Sha512.rsp", MLDsaParameters.ml_dsa_44_with_sha512 },
{ "mldsa65Sha512.rsp", MLDsaParameters.ml_dsa_65_with_sha512 },
{ "mldsa87Sha512.rsp", MLDsaParameters.ml_dsa_87_with_sha512 },
};

private static readonly Dictionary<string, MLDsaParameters> Parameters =
new Dictionary<string, MLDsaParameters>()
{
Expand All @@ -51,6 +62,8 @@ public class MLDsaTest
"keyGen_ML-DSA-87.txt",
};

private static readonly IEnumerable<string> ContextFiles = ContextFileParameters.Keys;

private static readonly string[] SigGenAcvpFiles =
{
"sigGen_ML-DSA-44.txt",
Expand Down Expand Up @@ -107,6 +120,14 @@ public void Consistency(MLDsaParameters parameters)
while (msgLen <= 2048);
}

[TestCaseSource(nameof(ContextFiles))]
[Parallelizable]
public void Context(string fileName)
{
RunTestVectors("pqc/crypto/mldsa", fileName,
(name, data) => ImplContext(name, data, ContextFileParameters[name]));
}

[Test]
[Parallelizable]
public void KeyGen()
Expand Down Expand Up @@ -155,6 +176,77 @@ public void KeyGenAcvp(string fileName)
// (name, data) => ImplSigVer(name, data, AcvpFileParameters[name]));
//}

private static void ImplContext(string name, Dictionary<string, string> data, MLDsaParameters parameters)
{
string count = data["count"];
byte[] seed = Hex.Decode(data["seed"]);
byte[] msg = Hex.Decode(data["msg"]);
byte[] pk = Hex.Decode(data["pk"]);
byte[] sk = Hex.Decode(data["sk"]);
byte[] sm = Hex.Decode(data["sm"]);

byte[] context = null;
if (data.TryGetValue("context", out var contextValue))
{
context = Hex.Decode(contextValue);
}

var random = FixedSecureRandom.From(seed);

var kpg = new MLDsaKeyPairGenerator();
kpg.Init(new MLDsaKeyGenerationParameters(random, parameters));

var kp = kpg.GenerateKeyPair();

var publicKey = (MLDsaPublicKeyParameters)kp.Public;
var privateKey = (MLDsaPrivateKeyParameters)kp.Private;

Assert.True(Arrays.AreEqual(pk, publicKey.GetEncoded()), $"{name} {count}: public key");
Assert.True(Arrays.AreEqual(sk, privateKey.GetEncoded()), $"{name} {count}: secret key");

var publicKeyRT = (MLDsaPublicKeyParameters)PublicKeyFactory.CreateKey(
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
var privateKeyRT = (MLDsaPrivateKeyParameters)PrivateKeyFactory.CreateKey(
PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey));

Assert.True(Arrays.AreEqual(pk, publicKeyRT.GetEncoded()), $"{name} {count}: public key (round-trip)");
Assert.True(Arrays.AreEqual(sk, privateKeyRT.GetEncoded()), $"{name} {count}: secret key (round-trip)");

// Note that this is a deterministic signature test, since we are not given "rnd"
ISigner sig;
if (parameters.IsPreHash)
{
sig = new HashMLDsaSigner(parameters, deterministic: true);
}
else
{
sig = new MLDsaSigner(parameters, deterministic: true);
}

// The current test data is a bit weird and uses internal signing when no explicit context provided.
if (context == null)
{
//var rnd = new byte[32]; // Deterministic
//byte[] generated = privateKey.SignInternal(rnd, msg, 0, msg.Length);
//Assert.True(Arrays.AreEqual(sm, generated), $"{name} {count}: SignInternal");

//bool shouldVerify = publicKey.VerifyInternal(msg, 0, msg.Length, sm);
//Assert.True(shouldVerify, $"{name} {count}: VerifyInternal");
}
else
{
sig.Init(forSigning: true, ParameterUtilities.WithContext(privateKey, context));
sig.BlockUpdate(msg, 0, msg.Length);
byte[] generated = sig.GenerateSignature();
Assert.True(Arrays.AreEqual(sm, generated), $"{name} {count}: GenerateSignature");

sig.Init(forSigning: false, ParameterUtilities.WithContext(publicKey, context));
sig.BlockUpdate(msg, 0, msg.Length);
bool shouldVerify = sig.VerifySignature(sm);
Assert.True(shouldVerify, $"{name} {count}: VerifySignature");
}
}

private static void ImplKeyGen(string name, Dictionary<string, string> data, MLDsaParameters parameters)
{
byte[] seed = Hex.Decode(data["seed"]);
Expand Down Expand Up @@ -195,7 +287,7 @@ private static void ImplKeyGen(string name, Dictionary<string, string> data, MLD
// rnd = Hex.Decode(data["rnd"]);
// }

// var privateKey = new MLDsaPrivateKeyParameters(parameters, sk);
// var privateKey = MLDsaPrivateKeyParameters.FromEncoding(parameters, sk);

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

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

// var publicKey = new MLDsaPublicKeyParameters(parameters, pk);
// var publicKey = MLDsaPublicKeyParameters.FromEncoding(parameters, pk);

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

Expand Down

0 comments on commit 7f8bb90

Please sign in to comment.