@@ -93,6 +93,84 @@ public static PublicPrivateKeyMaterial<PublicKeyMemory, PrivateKeyMemory> Create
9393 }
9494
9595
96+ /// <summary>
97+ /// Creates ML-DSA-44 key material (NIST FIPS 204, security level 2).
98+ /// Public key: 1312 bytes. Private key: 2560 bytes (seed-expanded).
99+ /// </summary>
100+ /// <param name="memoryPool">The memory pool to allocate key buffers from.</param>
101+ /// <returns>A new key pair. The caller must dispose each key individually.</returns>
102+ public static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateMlDsa44Keys ( MemoryPool < byte > memoryPool )
103+ {
104+ ArgumentNullException . ThrowIfNull ( memoryPool ) ;
105+ return CreateMlDsaKeys ( MLDsaParameters . ml_dsa_44 , memoryPool , CryptoTags . MlDsa44PublicKey , CryptoTags . MlDsa44PrivateKey ) ;
106+ }
107+
108+
109+ /// <summary>
110+ /// Creates ML-DSA-65 key material (NIST FIPS 204, security level 3).
111+ /// Public key: 1952 bytes. Private key: 4032 bytes (seed-expanded).
112+ /// </summary>
113+ /// <param name="memoryPool">The memory pool to allocate key buffers from.</param>
114+ /// <returns>A new key pair. The caller must dispose each key individually.</returns>
115+ public static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateMlDsa65Keys ( MemoryPool < byte > memoryPool )
116+ {
117+ ArgumentNullException . ThrowIfNull ( memoryPool ) ;
118+ return CreateMlDsaKeys ( MLDsaParameters . ml_dsa_65 , memoryPool , CryptoTags . MlDsa65PublicKey , CryptoTags . MlDsa65PrivateKey ) ;
119+ }
120+
121+
122+ /// <summary>
123+ /// Creates ML-DSA-87 key material (NIST FIPS 204, security level 5).
124+ /// Public key: 2592 bytes. Private key: 4896 bytes (seed-expanded).
125+ /// </summary>
126+ /// <param name="memoryPool">The memory pool to allocate key buffers from.</param>
127+ /// <returns>A new key pair. The caller must dispose each key individually.</returns>
128+ public static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateMlDsa87Keys ( MemoryPool < byte > memoryPool )
129+ {
130+ ArgumentNullException . ThrowIfNull ( memoryPool ) ;
131+ return CreateMlDsaKeys ( MLDsaParameters . ml_dsa_87 , memoryPool , CryptoTags . MlDsa87PublicKey , CryptoTags . MlDsa87PrivateKey ) ;
132+ }
133+
134+
135+ /// <summary>
136+ /// Creates ML-KEM-512 key material (NIST FIPS 203, security level 1).
137+ /// Public key: 800 bytes. Ciphertext: 768 bytes. Shared secret: 32 bytes.
138+ /// </summary>
139+ /// <param name="memoryPool">The memory pool to allocate key buffers from.</param>
140+ /// <returns>A new key pair. The caller must dispose each key individually.</returns>
141+ public static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateMlKem512Keys ( MemoryPool < byte > memoryPool )
142+ {
143+ ArgumentNullException . ThrowIfNull ( memoryPool ) ;
144+ return CreateMlKemKeys ( MLKemParameters . ml_kem_512 , memoryPool , CryptoTags . MlKem512PublicKey , CryptoTags . MlKem512PrivateKey ) ;
145+ }
146+
147+
148+ /// <summary>
149+ /// Creates ML-KEM-768 key material (NIST FIPS 203, security level 3).
150+ /// Public key: 1184 bytes. Ciphertext: 1088 bytes. Shared secret: 32 bytes.
151+ /// </summary>
152+ /// <param name="memoryPool">The memory pool to allocate key buffers from.</param>
153+ /// <returns>A new key pair. The caller must dispose each key individually.</returns>
154+ public static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateMlKem768Keys ( MemoryPool < byte > memoryPool )
155+ {
156+ ArgumentNullException . ThrowIfNull ( memoryPool ) ;
157+ return CreateMlKemKeys ( MLKemParameters . ml_kem_768 , memoryPool , CryptoTags . MlKem768PublicKey , CryptoTags . MlKem768PrivateKey ) ;
158+ }
159+
160+
161+ /// <summary>
162+ /// Creates ML-KEM-1024 key material (NIST FIPS 203, security level 5).
163+ /// Public key: 1568 bytes. Ciphertext: 1568 bytes. Shared secret: 32 bytes.
164+ /// </summary>
165+ /// <param name="memoryPool">The memory pool to allocate key buffers from.</param>
166+ /// <returns>A new key pair. The caller must dispose each key individually.</returns>
167+ public static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateMlKem1024Keys ( MemoryPool < byte > memoryPool )
168+ {
169+ ArgumentNullException . ThrowIfNull ( memoryPool ) ;
170+ return CreateMlKemKeys ( MLKemParameters . ml_kem_1024 , memoryPool , CryptoTags . MlKem1024PublicKey , CryptoTags . MlKem1024PrivateKey ) ;
171+ }
172+
173+
96174 private static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateEcKeys (
97175 string secCurveName ,
98176 Tag publicKeyTag ,
@@ -188,6 +266,62 @@ private static PublicPrivateKeyMaterial<PublicKeyMemory, PrivateKeyMemory> Creat
188266 }
189267
190268
269+ /// <summary>
270+ /// Creates ML-DSA key material for the given parameter set. The keys are serialized
271+ /// as raw encoded bytes via <c>GetEncoded()</c>.
272+ /// </summary>
273+ private static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateMlDsaKeys (
274+ MLDsaParameters parameters ,
275+ MemoryPool < byte > memoryPool ,
276+ Tag publicKeyTag ,
277+ Tag privateKeyTag )
278+ {
279+ var keyGenParameters = new MLDsaKeyGenerationParameters ( random , parameters ) ;
280+ var keyPairGen = new MLDsaKeyPairGenerator ( ) ;
281+ keyPairGen . Init ( keyGenParameters ) ;
282+
283+ AsymmetricCipherKeyPair keyPair = keyPairGen . GenerateKeyPair ( ) ;
284+ byte [ ] publicKeyBytes = ( ( MLDsaPublicKeyParameters ) keyPair . Public ) . GetEncoded ( ) ;
285+ byte [ ] privateKeyBytes = ( ( MLDsaPrivateKeyParameters ) keyPair . Private ) . GetEncoded ( ) ;
286+
287+ var publicKeyMemory = new PublicKeyMemory ( AsPooledMemory ( publicKeyBytes , memoryPool ) , publicKeyTag ) ;
288+ var privateKeyMemory = new PrivateKeyMemory ( AsPooledMemory ( privateKeyBytes , memoryPool ) , privateKeyTag ) ;
289+
290+ Array . Clear ( publicKeyBytes , 0 , publicKeyBytes . Length ) ;
291+ Array . Clear ( privateKeyBytes , 0 , privateKeyBytes . Length ) ;
292+
293+ return new PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > ( publicKeyMemory , privateKeyMemory ) ;
294+ }
295+
296+
297+ /// <summary>
298+ /// Creates ML-KEM key material for the given parameter set. The keys are serialized
299+ /// as raw encoded bytes via <c>GetEncoded()</c>.
300+ /// </summary>
301+ private static PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > CreateMlKemKeys (
302+ MLKemParameters parameters ,
303+ MemoryPool < byte > memoryPool ,
304+ Tag publicKeyTag ,
305+ Tag privateKeyTag )
306+ {
307+ var keyGenParameters = new MLKemKeyGenerationParameters ( random , parameters ) ;
308+ var keyPairGen = new MLKemKeyPairGenerator ( ) ;
309+ keyPairGen . Init ( keyGenParameters ) ;
310+
311+ AsymmetricCipherKeyPair keyPair = keyPairGen . GenerateKeyPair ( ) ;
312+ byte [ ] publicKeyBytes = ( ( MLKemPublicKeyParameters ) keyPair . Public ) . GetEncoded ( ) ;
313+ byte [ ] privateKeyBytes = ( ( MLKemPrivateKeyParameters ) keyPair . Private ) . GetEncoded ( ) ;
314+
315+ var publicKeyMemory = new PublicKeyMemory ( AsPooledMemory ( publicKeyBytes , memoryPool ) , publicKeyTag ) ;
316+ var privateKeyMemory = new PrivateKeyMemory ( AsPooledMemory ( privateKeyBytes , memoryPool ) , privateKeyTag ) ;
317+
318+ Array . Clear ( publicKeyBytes , 0 , publicKeyBytes . Length ) ;
319+ Array . Clear ( privateKeyBytes , 0 , privateKeyBytes . Length ) ;
320+
321+ return new PublicPrivateKeyMaterial < PublicKeyMemory , PrivateKeyMemory > ( publicKeyMemory , privateKeyMemory ) ;
322+ }
323+
324+
191325 private static IMemoryOwner < byte > AsPooledMemory ( byte [ ] keyBytes , MemoryPool < byte > memoryPool )
192326 {
193327 ArgumentNullException . ThrowIfNull ( keyBytes ) ;
0 commit comments