Skip to content

Commit 8fd896a

Browse files
authored
Merge pull request #10191 from dgarske/csharp_pqc
C# Wrapper: ML-KEM and ML-DSA (Dilithium) Support
2 parents 0b88017 + d692f99 commit 8fd896a

File tree

4 files changed

+1438
-0
lines changed

4 files changed

+1438
-0
lines changed

wrapper/CSharp/user_settings.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@
8787
#define ECC_TIMING_RESISTANT
8888
#define HAVE_COMP_KEY
8989

90+
/* Enable ML-KEM, ML-DSA */
91+
#define HAVE_MLKEM
92+
#define WOLFSSL_WC_MLKEM
93+
#define WOLFSSL_HAVE_MLKEM
94+
/* Required for PQC with DTLS 1.3 (auto-enabled in settings.h, explicit for clarity) */
95+
#define WOLFSSL_DTLS_CH_FRAG
96+
#define HAVE_DILITHIUM
97+
#define WOLFSSL_WC_DILITHIUM
98+
#define WOLFSSL_SHAKE128
99+
#define WOLFSSL_SHAKE256
100+
90101
/* Disable features */
91102
#define NO_PSK
92103

wrapper/CSharp/wolfCrypt-Test/wolfCrypt-Test.cs

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,311 @@ private static void curve25519_test()
674674
if (publicKeyB != IntPtr.Zero) wolfcrypt.Curve25519FreeKey(publicKeyB);
675675
} /* END curve25519_test */
676676

677+
private static void mlkem_test(wolfcrypt.MlKemTypes type)
678+
{
679+
int ret = 0;
680+
IntPtr keyA = IntPtr.Zero;
681+
IntPtr keyB = IntPtr.Zero;
682+
IntPtr heap = IntPtr.Zero;
683+
int devId = wolfcrypt.INVALID_DEVID;
684+
byte[] pubA = null;
685+
byte[] privA = null;
686+
byte[] cipherText = null;
687+
byte[] sharedSecretA = null;
688+
byte[] sharedSecretB = null;
689+
690+
try
691+
{
692+
Console.WriteLine("\nStarting " + type + " shared secret test ...");
693+
694+
/* Generate Key Pair */
695+
Console.WriteLine("Testing ML-KEM Key Generation...");
696+
697+
Console.WriteLine("Generate Key Pair A...");
698+
keyA = wolfcrypt.MlKemMakeKey(type, heap, devId);
699+
if (keyA == IntPtr.Zero)
700+
{
701+
ret = -1;
702+
Console.Error.WriteLine("Failed to generate key pair A.");
703+
}
704+
if (ret == 0)
705+
{
706+
Console.WriteLine("Initialize Key B for decode...");
707+
keyB = wolfcrypt.MlKemNew(type, heap, devId);
708+
if (keyB == IntPtr.Zero)
709+
{
710+
ret = -1;
711+
Console.Error.WriteLine("Failed to initialize key B for decode.");
712+
}
713+
}
714+
if (ret == 0)
715+
{
716+
Console.WriteLine("ML-KEM Key Generation test passed.");
717+
}
718+
719+
/* Encode */
720+
if (ret == 0)
721+
{
722+
Console.WriteLine("Testing ML-KEM Key Encode...");
723+
ret = wolfcrypt.MlKemEncodePublicKey(keyA, out pubA);
724+
if (ret != 0)
725+
{
726+
Console.Error.WriteLine($"Failed to encode public key of A. Error code: {ret}");
727+
}
728+
}
729+
if (ret == 0)
730+
{
731+
ret = wolfcrypt.MlKemEncodePrivateKey(keyA, out privA);
732+
if (ret != 0)
733+
{
734+
Console.Error.WriteLine($"Failed to encode private key of A. Error code: {ret}");
735+
}
736+
}
737+
if (ret == 0)
738+
{
739+
Console.WriteLine("ML-KEM Key Encode test passed.");
740+
}
741+
742+
/* Encapsulate */
743+
if (ret == 0)
744+
{
745+
Console.WriteLine("Testing ML-KEM Encapsulation...");
746+
ret = wolfcrypt.MlKemEncapsulate(keyA, out cipherText, out sharedSecretA);
747+
if (ret != 0)
748+
{
749+
Console.Error.WriteLine($"Failed to encapsulate. Error code: {ret}");
750+
}
751+
}
752+
if (ret == 0)
753+
{
754+
Console.WriteLine("ML-KEM Encapsulation test passed.");
755+
}
756+
757+
/* Decode */
758+
if (ret == 0)
759+
{
760+
Console.WriteLine("Testing ML-KEM Decode...");
761+
ret = wolfcrypt.MlKemDecodePrivateKey(keyB, privA);
762+
if (ret != 0)
763+
{
764+
Console.Error.WriteLine($"Failed to decode private key of A. Error code: {ret}");
765+
}
766+
}
767+
if (ret == 0)
768+
{
769+
ret = wolfcrypt.MlKemDecodePublicKey(keyB, pubA);
770+
if (ret != 0)
771+
{
772+
Console.Error.WriteLine($"Failed to decode public key of A. Error code: {ret}");
773+
}
774+
}
775+
if (ret == 0)
776+
{
777+
Console.WriteLine("ML-KEM Decode test passed.");
778+
}
779+
780+
/* Decapsulate */
781+
if (ret == 0)
782+
{
783+
Console.WriteLine("Testing ML-KEM Decapsulation...");
784+
ret = wolfcrypt.MlKemDecapsulate(keyB, cipherText, out sharedSecretB);
785+
if (ret != 0)
786+
{
787+
Console.Error.WriteLine($"Failed to decapsulate. Error code: {ret}");
788+
}
789+
}
790+
if (ret == 0)
791+
{
792+
Console.WriteLine("ML-KEM Decapsulation test passed.");
793+
}
794+
795+
/* Check */
796+
if (ret == 0)
797+
{
798+
Console.WriteLine("Comparing Shared Secrets...");
799+
if (!wolfcrypt.ByteArrayVerify(sharedSecretA, sharedSecretB))
800+
{
801+
ret = -1;
802+
Console.Error.WriteLine($"Shared secrets do not match. Error code: {ret}");
803+
}
804+
}
805+
if (ret == 0)
806+
{
807+
Console.WriteLine("ML-KEM shared secret match.");
808+
}
809+
810+
if (ret != 0)
811+
{
812+
throw new Exception("ML-KEM test failed.");
813+
}
814+
}
815+
catch (Exception ex)
816+
{
817+
Console.WriteLine($"ML-KEM test failed: {ex.Message}");
818+
throw;
819+
}
820+
finally
821+
{
822+
/* Cleanup */
823+
if (keyA != IntPtr.Zero)
824+
{
825+
ret = wolfcrypt.MlKemFreeKey(ref keyA);
826+
if (ret != 0)
827+
{
828+
Console.Error.WriteLine($"Failed to free MlKem key A. Error code: {ret}");
829+
}
830+
}
831+
if (keyB != IntPtr.Zero)
832+
{
833+
ret = wolfcrypt.MlKemFreeKey(ref keyB);
834+
if (ret != 0)
835+
{
836+
Console.Error.WriteLine($"Failed to free MlKem key B. Error code: {ret}");
837+
}
838+
}
839+
}
840+
} /* END mlkem_test */
841+
842+
private static void mldsa_test(wolfcrypt.MlDsaLevels level)
843+
{
844+
int ret = 0;
845+
IntPtr key = IntPtr.Zero;
846+
IntPtr importKey = IntPtr.Zero;
847+
IntPtr heap = IntPtr.Zero;
848+
int devId = wolfcrypt.INVALID_DEVID;
849+
byte[] privateKey = null;
850+
byte[] publicKey = null;
851+
byte[] message = Encoding.UTF8.GetBytes("This is some data to sign with ML-DSA");
852+
byte[] signature = null;
853+
854+
try
855+
{
856+
Console.WriteLine("\nStarting " + level + " key generation and signature test ...");
857+
858+
/* Generate Key */
859+
Console.WriteLine("Testing ML-DSA Key Generation...");
860+
key = wolfcrypt.MlDsaMakeKey(heap, devId, level);
861+
if (key == IntPtr.Zero)
862+
{
863+
ret = -1;
864+
Console.Error.WriteLine("Failed to generate keypair.");
865+
}
866+
if (ret == 0)
867+
{
868+
Console.WriteLine("ML-DSA Key Generation test passed.");
869+
}
870+
871+
/* Export */
872+
if (ret == 0)
873+
{
874+
Console.WriteLine("Testing ML-DSA Key Export...");
875+
ret = wolfcrypt.MlDsaExportPrivateKey(key, out privateKey);
876+
if (ret != 0)
877+
{
878+
Console.Error.WriteLine($"Failed to export private key. Error code: {ret}");
879+
}
880+
}
881+
if (ret == 0)
882+
{
883+
ret = wolfcrypt.MlDsaExportPublicKey(key, out publicKey);
884+
if (ret != 0)
885+
{
886+
Console.Error.WriteLine($"Failed to export public key. Error code: {ret}");
887+
}
888+
}
889+
if (ret == 0)
890+
{
891+
Console.WriteLine("ML-DSA Key Export test passed.");
892+
}
893+
894+
/* Import into a fresh key to test the full import workflow */
895+
if (ret == 0)
896+
{
897+
Console.WriteLine("Testing ML-DSA Key Import...");
898+
/* Free the keygen key and create a fresh one for import */
899+
wolfcrypt.MlDsaFreeKey(ref key);
900+
importKey = wolfcrypt.MlDsaNew(heap, devId, level);
901+
if (importKey == IntPtr.Zero)
902+
{
903+
ret = -1;
904+
Console.Error.WriteLine("Failed to allocate key for import.");
905+
}
906+
}
907+
if (ret == 0)
908+
{
909+
ret = wolfcrypt.MlDsaImportPrivateKey(privateKey, importKey);
910+
if (ret != 0)
911+
{
912+
Console.Error.WriteLine($"Failed to import private key. Error code: {ret}");
913+
}
914+
}
915+
if (ret == 0)
916+
{
917+
ret = wolfcrypt.MlDsaImportPublicKey(publicKey, importKey);
918+
if (ret != 0)
919+
{
920+
Console.Error.WriteLine($"Failed to import public key. Error code: {ret}");
921+
}
922+
}
923+
if (ret == 0)
924+
{
925+
Console.WriteLine("ML-DSA Key Import test passed.");
926+
}
927+
928+
/* Sign with imported key */
929+
if (ret == 0)
930+
{
931+
Console.WriteLine("Testing ML-DSA Signature Creation...");
932+
ret = wolfcrypt.MlDsaSignMsg(importKey, message, out signature);
933+
if (ret != 0)
934+
{
935+
Console.Error.WriteLine($"Failed to sign. Error code: {ret}");
936+
}
937+
}
938+
if (ret == 0)
939+
{
940+
Console.WriteLine($"ML-DSA Signature Creation test passed. Signature Length: {signature.Length}");
941+
}
942+
943+
/* Verify with imported key */
944+
if (ret == 0)
945+
{
946+
Console.WriteLine("Testing ML-DSA Signature Verification...");
947+
ret = wolfcrypt.MlDsaVerifyMsg(importKey, message, signature);
948+
if (ret != 0)
949+
{
950+
Console.Error.WriteLine($"Failed to verify message. Error code: {ret}");
951+
}
952+
}
953+
if (ret == 0)
954+
{
955+
Console.WriteLine("ML-DSA Signature Verification test passed.");
956+
}
957+
958+
if (ret != 0)
959+
{
960+
throw new Exception("ML-DSA test failed.");
961+
}
962+
}
963+
catch (Exception ex)
964+
{
965+
Console.WriteLine($"ML-DSA test failed: {ex.Message}");
966+
throw;
967+
}
968+
finally
969+
{
970+
if (key != IntPtr.Zero)
971+
{
972+
wolfcrypt.MlDsaFreeKey(ref key);
973+
}
974+
if (importKey != IntPtr.Zero)
975+
{
976+
wolfcrypt.MlDsaFreeKey(ref importKey);
977+
}
978+
}
979+
980+
} /* END mldsa_test */
981+
677982
private static void aes_gcm_test()
678983
{
679984
IntPtr aes = IntPtr.Zero;
@@ -1126,6 +1431,18 @@ public static void Main(string[] args)
11261431

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

1434+
Console.WriteLine("\nStarting ML-KEM test");
1435+
1436+
mlkem_test(wolfcrypt.MlKemTypes.ML_KEM_512); /* ML-KEM test */
1437+
mlkem_test(wolfcrypt.MlKemTypes.ML_KEM_768); /* ML-KEM test */
1438+
mlkem_test(wolfcrypt.MlKemTypes.ML_KEM_1024); /* ML-KEM test */
1439+
1440+
Console.WriteLine("\nStarting ML-DSA test");
1441+
1442+
mldsa_test(wolfcrypt.MlDsaLevels.ML_DSA_44); /* ML-DSA test */
1443+
mldsa_test(wolfcrypt.MlDsaLevels.ML_DSA_65); /* ML-DSA test */
1444+
mldsa_test(wolfcrypt.MlDsaLevels.ML_DSA_87); /* ML-DSA test */
1445+
11291446
Console.WriteLine("\nStarting AES-GCM test");
11301447

11311448
aes_gcm_test(); /* AES_GCM test */

0 commit comments

Comments
 (0)