-
Notifications
You must be signed in to change notification settings - Fork 900
Add ML-KEM/ML-DSA support for C# wrapper #9040
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
| { | ||
| 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be a good idea to have a There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The soft errors tracked by At the end here, the prior value of 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 Having just one exception will make future refactoring easier. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm sorry, but I'm currently unable to visualize the code you have in mind. |
||
| 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; | ||
|
|
@@ -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 */ | ||
|
|
||
There was a problem hiding this comment.
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?