Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions wrapper/CSharp/user_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@
#define ECC_TIMING_RESISTANT
#define HAVE_COMP_KEY

/* Enable ML-KEM, ML-DSA */
#define HAVE_MLKEM
#define WOLFSSL_WC_MLKEM
#define WOLFSSL_HAVE_MLKEM
#define WOLFSSL_DTLS_CH_FRAG
#define HAVE_DILITHIUM
#define WOLFSSL_WC_DILITHIUM
#define WOLFSSL_SHAKE128
#define WOLFSSL_SHAKE256

/* Disable features */
#define NO_PSK

Expand Down
295 changes: 295 additions & 0 deletions wrapper/CSharp/wolfCrypt-Test/wolfCrypt-Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,289 @@ private static void curve25519_test()
if (publicKeyB != IntPtr.Zero) wolfcrypt.Curve25519FreeKey(publicKeyB);
} /* END curve25519_test */

private static void mlkem_test(wolfcrypt.MlKemTypes type)
{
int ret = 0;
IntPtr keyA = IntPtr.Zero;
IntPtr keyB = IntPtr.Zero;
IntPtr heap = IntPtr.Zero;
int devId = wolfcrypt.INVALID_DEVID;
byte[] pubA, privA, cipherText, sharedSecretA, sharedSecretB;

try
{
Console.WriteLine("\nStarting " + type + " shared secret test ...");

/* Generate Key Pair */
Console.WriteLine("Testing ML-KEM Key Generation...");

Console.WriteLine("Generate Key Pair A...");
keyA = wolfcrypt.MlKemMakeKey(type, heap, devId);
if (keyA == IntPtr.Zero)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why ret = -1 (or some failure) is not set here?

ret = -1;
Console.Error.WriteLine("Failed to generate key pair A.");
}
if (ret == 0)
{
Console.WriteLine("Generate Key Pair B...");
keyB = wolfcrypt.MlKemMakeKey(type, heap, devId);
if (keyB == IntPtr.Zero)
{
ret = -1;
Console.Error.WriteLine("Failed to generate key pair B.");
}
}
if (ret == 0)
{
Console.WriteLine("ML-KEM Key Generation test passed.");
}

/* Encode */
if (ret == 0)
{
Console.WriteLine("Testing ML-KEM Key Encode...");
ret = wolfcrypt.MlKemEncodePublicKey(keyA, out pubA);
if (ret != 0)
{
Console.Error.WriteLine("Failed to encode public key of A.");
}
}
if (ret == 0)
{
ret = wolfcrypt.MlKemEncodePrivateKey(keyA, out privA);
if (ret != 0)
{
Console.Error.WriteLine("Failed to encode private key of A.");
}
}
if (ret == 0)
{
Console.WriteLine("ML-KEM Key Encode test passed.");
}

/* Encapsulate */
if (ret == 0)
{
Console.WriteLine("Testing ML-KEM Encapsulation...");
ret = wolfcrypt.MlKemEncapsulate(keyA, out cipherText, out sharedSecretA);
if (ret != 0)
{
Console.Error.WriteLine("Failed to encapsulate.");
}
}
if (ret == 0)
{
Console.WriteLine("ML-KEM Encapsulation test passed.");
}

/* Decode */
if (ret == 0)
{
Console.WriteLine("Testing ML-KEM Decode...");
ret = wolfcrypt.MlKemDecodePrivateKey(keyB, privA);
if (ret != 0)
{
Console.Error.WriteLine("Failed to decode private key of A.");
}
}
if (ret == 0)
{
ret = wolfcrypt.MlKemDecodePublicKey(keyB, pubA);
if (ret != 0)
{
Console.Error.WriteLine("Failed to decode public key of B.");
}
}
if (ret == 0)
{
Console.WriteLine("ML-KEM Decode test passed.");
}

/* Decapsulate */
if (ret == 0)
{
Console.WriteLine("Testing ML-KEM Decapsulation...");
ret = wolfcrypt.MlKemDecapsulate(keyB, cipherText, out sharedSecretB);
if (ret != 0)
{
Console.Error.WriteLine("Failed to decapsulate.");
}
}
if (ret == 0)
{
Console.WriteLine("ML-KEM Decapsulation test passed.");
}

/* DEBUG CODE FOR REVIEW */
ret = BAD_FUNC_ARG;

/* Check */
if (ret == 0)
{
Console.WriteLine("Comparing Shared Secrets...");
if (!wolfcrypt.ByteArrayVerify(sharedSecretA, sharedSecretB))
{
Console.Error.WriteLine("Shared secrets do not match.");
}
else
{
Console.WriteLine("ML-KEM shared secret match.");
}
}
}
catch
{
// todo:
// ........ https://github.com/wolfSSL/wolfssl/pull/9040#discussion_r2386193630
// ........ https://github.com/wolfSSL/wolfssl/pull/9040#discussion_r2386194020
}
finally
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be a good idea to have a catch above this, to describe the failure and decide how to proceed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's related to #9040 (comment)

{
/* Cleanup */
if (keyA != IntPtr.Zero)
{
ret = wolfcrypt.MlKemFreeKey(keyA);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The soft errors tracked by ret values (above) is good.

At the end here, the prior value of ret is lost. This may be important for test monitoring.

If there are any external tests such as GitHub workflows that expect error codes upon failure, it would be lost here, no?

Although it is much better to not throw many exceptions for each failure, there's also the desire to match existing code patterns. Since the test does not return a success / fail (it should, but beyond the scope of this PR) ... do you think it would be best to put just one final throw exception at the end here?

Having just one exception will make future refactoring easier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although it is much better to not throw many exceptions for each failure, there's also the desire to match existing code patterns. Since the test does not return a success / fail (it should, but beyond the scope of this PR) ... do you think it would be best to put just one final throw exception at the end here?

I'm sorry, but I'm currently unable to visualize the code you have in mind.
Could you show me some program code to illustrate what roles you think the try, catch, finally, and exception should each play?

if (ret != 0)
{
Console.Error.WriteLine("Failed to free MlKem key A. Error code: " + ret);
}
}
if (keyB != IntPtr.Zero)
{
ret = wolfcrypt.MlKemFreeKey(keyB);
if (ret != 0)
{
Console.Error.WriteLine("Failed to free MlKem key B. Error code: " + ret);
}
}
}
} /* END mlkem_test */

private static void mldsa_test(wolfcrypt.MlDsaTypes type)
{
int ret = 0;
IntPtr key = IntPtr.Zero;
IntPtr heap = IntPtr.Zero;
int devId = wolfcrypt.INVALID_DEVID;
byte[] privateKey;
byte[] publicKey;
byte[] message = Encoding.UTF8.GetBytes("This is some data to sign with ML-DSA");
byte[] signature;

try
{
Console.WriteLine("\nStarting " + type + " shared secret test ...");

/* Generate Key */
Console.WriteLine("Testing ML-DSA Key Generation...");
key = wolfcrypt.DilithiumMakeKey(heap, devId, type);
if (key == IntPtr.Zero)
{
ret = -1;
Console.Error.WriteLine("DilithiumMakeKey failed");
}
if (ret == 0)
{
Console.WriteLine("ML-DSA Key Generation test passed.");
}

/* Export */
if (ret == 0)
{
Console.WriteLine("Testing ML-DSA Key Export...");
ret = DilithiumExportPrivateKey(key, out privateKey);
if (ret != 0)
{
Console.Error.WriteLine("DilithiumExportPrivateKey failed");
}
}
if (ret == 0)
{
ret = DilithiumExportPublicKey(key, out publicKey);
if (ret != 0)
{
Console.Error.WriteLine("DilithiumExportPublicKey failed");
}
}
if (ret == 0)
{
Console.WriteLine("ML-DSA Key Export test passed.");
}

/* Import */
if (ret == 0)
{
Console.WriteLine("Testing ML-DSA Key Import...");
ret = DilithiumImportPrivateKey(privateKey, key);
if (ret != 0)
{
Console.Error.WriteLine("DilithiumImportPrivateKey failed");
}
}
if (ret == 0)
{
ret = DilithiumImportPublicKey(publicKey, key);
if (ret != 0)
{
Console.Error.WriteLine("DilithiumImportPrivateKey failed");
}
}
if (ret == 0)
{
Console.WriteLine("ML-DSA Key Import test passed.");
}

/* Sign */
if (ret == 0)
{
Console.WriteLine("Testing ML-DSA Signature Creation...");
ret = wolfcrypt.DilithiumSignMsg(key, message, out signature);
if (ret != 0)
{
Console.Error.WriteLine("DilithiumSign failed");
}
}
if (ret == 0)
{
Console.WriteLine($"ML-DSA Signature Creation test passed. Signature Length: {signature.Length}");
}

/* Verify */
if (ret == 0)
{
Console.WriteLine("Testing ML-DSA Signature Verification...");
ret = wolfcrypt.DilithiumVerifyMsg(key, message, signature);
if (ret != 0)
{
Console.Error.WriteLine("DilithiumVerify failed");
}
}
if (ret == 0)
{
Console.WriteLine("ML-DSA Signature Verification test passed.");
}
}
catch
{
// todo:
// ........ https://github.com/wolfSSL/wolfssl/pull/9040#discussion_r2386193630
// ........ https://github.com/wolfSSL/wolfssl/pull/9040#discussion_r2386194020
}
finally
{
if (key != IntPtr.Zero)
{
ret = wolfcrypt.DilithiumFreeKey(key);
if (ret != 0)
{
Console.Error.WriteLine("Failed to free Dilithium key. Error code: " + ret);
}
}
}

} /* END mldsa_test */

private static void aes_gcm_test()
{
IntPtr aes = IntPtr.Zero;
Expand Down Expand Up @@ -904,6 +1187,18 @@ public static void Main(string[] args)

curve25519_test(); /* curve25519 shared secret test */

Console.WriteLine("\nStarting ML-KEM test");

mlkem_test(wolfcrypt.MlKemTypes.ML_KEM_512); /* ML-KEM test */
mlkem_test(wolfcrypt.MlKemTypes.ML_KEM_768); /* ML-KEM test */
mlkem_test(wolfcrypt.MlKemTypes.ML_KEM_1024); /* ML-KEM test */

Console.WriteLine("\nStarting ML-DSA test");

mldsa_test(wolfcrypt.MlDsaTypes.ML_DSA_44); /* ML-DSA test */
mldsa_test(wolfcrypt.MlDsaTypes.ML_DSA_65); /* ML-DSA test */
mldsa_test(wolfcrypt.MlDsaTypes.ML_DSA_87); /* ML-DSA test */

Console.WriteLine("\nStarting AES-GCM test");

aes_gcm_test(); /* AES_GCM test */
Expand Down
Loading
Loading