1 /* $OpenBSD: libcrux-mlkem-mldsa.c,v 1.1 2026/06/14 03:59:34 djm Exp $ */
2 /*
3 * Copyright (c) 2026 Damien Miller <djm@mindrot.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include "includes.h"
19
20 #if defined(USE_MLDSA) || defined(USE_MLKEM768X25519)
21
22 #include <sys/types.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <string.h>
27
28 #include "log.h"
29 #include "crypto_api.h"
30 #include "libcrux_internal.h"
31
32 /* ML-KEM 768 */
33
34 int
crypto_kem_mlkem768_keypair(uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES],uint8_t sk[crypto_kem_mlkem768_SECRETKEYBYTES])35 crypto_kem_mlkem768_keypair(uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES],
36 uint8_t sk[crypto_kem_mlkem768_SECRETKEYBYTES])
37 {
38 uint8_t rnd[crypto_kem_mlkem768_KEYPAIRSEEDBYTES];
39 int r;
40
41 arc4random_buf(rnd, sizeof(rnd));
42 r = crypto_kem_mlkem768_keypair_seeded(pk, sk, rnd);
43 explicit_bzero(rnd, sizeof(rnd));
44 return r;
45 }
46
47 int
crypto_kem_mlkem768_keypair_seeded(uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES],uint8_t sk[crypto_kem_mlkem768_SECRETKEYBYTES],const uint8_t seed[crypto_kem_mlkem768_KEYPAIRSEEDBYTES])48 crypto_kem_mlkem768_keypair_seeded(uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES],
49 uint8_t sk[crypto_kem_mlkem768_SECRETKEYBYTES],
50 const uint8_t seed[crypto_kem_mlkem768_KEYPAIRSEEDBYTES])
51 {
52 libcrux_mlkem768_keypair keypair;
53 libcrux_mlkem768_keypair_rnd rnd;
54
55 memcpy(rnd.data, seed, sizeof(rnd.data));
56 keypair = libcrux_ml_kem_mlkem768_portable_generate_key_pair(rnd);
57 memcpy(pk, keypair.pk.data, crypto_kem_mlkem768_PUBLICKEYBYTES);
58 memcpy(sk, keypair.sk.data, crypto_kem_mlkem768_SECRETKEYBYTES);
59
60 explicit_bzero(&keypair, sizeof(keypair));
61 explicit_bzero(&rnd, sizeof(rnd));
62 return 0;
63 }
64
65 int
crypto_kem_mlkem768_enc(uint8_t ct[crypto_kem_mlkem768_CIPHERTEXTBYTES],uint8_t shared_secret[crypto_kem_mlkem768_BYTES],const uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES])66 crypto_kem_mlkem768_enc(uint8_t ct[crypto_kem_mlkem768_CIPHERTEXTBYTES],
67 uint8_t shared_secret[crypto_kem_mlkem768_BYTES],
68 const uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES])
69 {
70 uint8_t rnd[crypto_kem_mlkem768_ENCSEEDBYTES];
71 int r;
72
73 arc4random_buf(rnd, sizeof(rnd));
74 r = crypto_kem_mlkem768_enc_seeded(ct, shared_secret, pk, rnd);
75 explicit_bzero(rnd, sizeof(rnd));
76 return r;
77 }
78
79 int
crypto_kem_mlkem768_enc_seeded(uint8_t ct[crypto_kem_mlkem768_CIPHERTEXTBYTES],uint8_t shared_secret[crypto_kem_mlkem768_BYTES],const uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES],const uint8_t seed[crypto_kem_mlkem768_ENCSEEDBYTES])80 crypto_kem_mlkem768_enc_seeded(uint8_t ct[crypto_kem_mlkem768_CIPHERTEXTBYTES],
81 uint8_t shared_secret[crypto_kem_mlkem768_BYTES],
82 const uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES],
83 const uint8_t seed[crypto_kem_mlkem768_ENCSEEDBYTES])
84 {
85 libcrux_mlkem768_enc_result enc;
86 libcrux_mlkem768_pk pk_internal;
87 libcrux_mlkem768_enc_rnd rnd;
88
89 memcpy(pk_internal.data, pk, crypto_kem_mlkem768_PUBLICKEYBYTES);
90 if (!libcrux_ml_kem_mlkem768_portable_validate_public_key(&pk_internal))
91 return -1;
92 memcpy(rnd.data, seed, sizeof(rnd.data));
93 enc = libcrux_ml_kem_mlkem768_portable_encapsulate(&pk_internal, rnd);
94 memcpy(ct, enc.fst.data, crypto_kem_mlkem768_CIPHERTEXTBYTES);
95 memcpy(shared_secret, enc.snd.data, crypto_kem_mlkem768_BYTES);
96
97 explicit_bzero(&enc, sizeof(enc));
98 explicit_bzero(&rnd, sizeof(rnd));
99 return 0;
100 }
101
102 int
crypto_kem_mlkem768_dec(uint8_t shared_secret[crypto_kem_mlkem768_BYTES],const uint8_t ct[crypto_kem_mlkem768_CIPHERTEXTBYTES],const uint8_t sk[crypto_kem_mlkem768_SECRETKEYBYTES])103 crypto_kem_mlkem768_dec(uint8_t shared_secret[crypto_kem_mlkem768_BYTES],
104 const uint8_t ct[crypto_kem_mlkem768_CIPHERTEXTBYTES],
105 const uint8_t sk[crypto_kem_mlkem768_SECRETKEYBYTES])
106 {
107 libcrux_mlkem768_sk sk_internal;
108 libcrux_mlkem768_ciphertext ct_internal;
109 libcrux_mlkem768_dec_result shared_secret_internal;
110
111 memcpy(sk_internal.data, sk, crypto_kem_mlkem768_SECRETKEYBYTES);
112 memcpy(ct_internal.data, ct, crypto_kem_mlkem768_CIPHERTEXTBYTES);
113 shared_secret_internal = libcrux_ml_kem_mlkem768_portable_decapsulate(
114 &sk_internal, &ct_internal);
115 memcpy(shared_secret, shared_secret_internal.data,
116 crypto_kem_mlkem768_BYTES);
117
118 explicit_bzero(&sk_internal, sizeof(sk_internal));
119 explicit_bzero(&shared_secret_internal, sizeof(shared_secret_internal));
120 return 0;
121 }
122
123 /* ML-DSA 44 */
124
125 int
crypto_sign_mldsa44_keypair(uint8_t pk[MLDSA44_PUBLICKEYBYTES],uint8_t sk[MLDSA44_SECRETKEYBYTES])126 crypto_sign_mldsa44_keypair(uint8_t pk[MLDSA44_PUBLICKEYBYTES],
127 uint8_t sk[MLDSA44_SECRETKEYBYTES])
128 {
129 uint8_t rnd[MLDSA44_SEEDBYTES];
130 int r;
131
132 arc4random_buf(rnd, sizeof(rnd));
133 r = crypto_sign_mldsa44_keypair_seeded(pk, sk, rnd);
134 explicit_bzero(rnd, sizeof(rnd));
135 return r;
136 }
137
138 int
crypto_sign_mldsa44_keypair_seeded(uint8_t pk[MLDSA44_PUBLICKEYBYTES],uint8_t sk[MLDSA44_SECRETKEYBYTES],const uint8_t seed[MLDSA44_SEEDBYTES])139 crypto_sign_mldsa44_keypair_seeded(uint8_t pk[MLDSA44_PUBLICKEYBYTES],
140 uint8_t sk[MLDSA44_SECRETKEYBYTES], const uint8_t seed[MLDSA44_SEEDBYTES])
141 {
142 libcrux_mldsa44_keypair_rnd rnd;
143 libcrux_mldsa44_keypair keypair;
144
145 memcpy(rnd.data, seed, sizeof(rnd.data));
146 keypair = libcrux_ml_dsa_ml_dsa_44_portable_generate_key_pair(rnd);
147 memcpy(pk, keypair.verification_key.data, MLDSA44_PUBLICKEYBYTES);
148 memcpy(sk, keypair.signing_key.data, MLDSA44_SECRETKEYBYTES);
149
150 explicit_bzero(&keypair, sizeof(keypair));
151 explicit_bzero(&rnd, sizeof(rnd));
152 return 0;
153 }
154
155 int
crypto_sign_mldsa44(uint8_t sig[MLDSA44_SIGBYTES],const uint8_t * msg,size_t msglen,const uint8_t * ctx,size_t ctxlen,const uint8_t sk[MLDSA44_SECRETKEYBYTES])156 crypto_sign_mldsa44(uint8_t sig[MLDSA44_SIGBYTES],
157 const uint8_t *msg, size_t msglen,
158 const uint8_t *ctx, size_t ctxlen,
159 const uint8_t sk[MLDSA44_SECRETKEYBYTES])
160 {
161 uint8_t rnd[MLDSA44_SEEDBYTES];
162 int r;
163
164 arc4random_buf(rnd, sizeof(rnd));
165 r = crypto_sign_mldsa44_seeded(sig, msg, msglen, ctx, ctxlen, sk, rnd);
166 explicit_bzero(rnd, sizeof(rnd));
167 return r;
168 }
169
170 int
crypto_sign_mldsa44_seeded(uint8_t sig[MLDSA44_SIGBYTES],const uint8_t * msg,size_t msglen,const uint8_t * ctx,size_t ctxlen,const uint8_t sk[MLDSA44_SECRETKEYBYTES],const uint8_t seed[MLDSA44_SEEDBYTES])171 crypto_sign_mldsa44_seeded(uint8_t sig[MLDSA44_SIGBYTES],
172 const uint8_t *msg, size_t msglen,
173 const uint8_t *ctx, size_t ctxlen,
174 const uint8_t sk[MLDSA44_SECRETKEYBYTES],
175 const uint8_t seed[MLDSA44_SEEDBYTES])
176 {
177 libcrux_mldsa44_sign_rnd rnd;
178 libcrux_mldsa44_sk sk_internal;
179 libcrux_mldsa44_message message = { msg, msglen };
180 libcrux_mldsa44_message context = { ctx, ctxlen };
181 libcrux_mldsa44_sign_result res;
182 int r = -1;
183
184 memcpy(sk_internal.data, sk, MLDSA44_SECRETKEYBYTES);
185 memcpy(rnd.data, seed, sizeof(rnd.data));
186 res = libcrux_ml_dsa_ml_dsa_44_portable_sign(&sk_internal,
187 message, context, rnd);
188 if (res.tag == LIBCRUX_RESULT_OK) {
189 memcpy(sig, res.val.case_Ok.data, MLDSA44_SIGBYTES);
190 r = 0;
191 }
192
193 explicit_bzero(&sk_internal, sizeof(sk_internal));
194 explicit_bzero(&res, sizeof(res));
195 explicit_bzero(&rnd, sizeof(rnd));
196 return r;
197 }
198
199 int
crypto_sign_mldsa44_verify(const uint8_t sig[MLDSA44_SIGBYTES],const uint8_t * msg,size_t msglen,const uint8_t * ctx,size_t ctxlen,const uint8_t pk[MLDSA44_PUBLICKEYBYTES])200 crypto_sign_mldsa44_verify(const uint8_t sig[MLDSA44_SIGBYTES],
201 const uint8_t *msg, size_t msglen,
202 const uint8_t *ctx, size_t ctxlen,
203 const uint8_t pk[MLDSA44_PUBLICKEYBYTES])
204 {
205 libcrux_mldsa44_pk pk_internal;
206 libcrux_mldsa44_signature sig_internal;
207 libcrux_mldsa44_message message = { msg, msglen };
208 libcrux_mldsa44_message context = { ctx, ctxlen };
209 libcrux_mldsa44_verify_result res;
210
211 memcpy(pk_internal.data, pk, MLDSA44_PUBLICKEYBYTES);
212 memcpy(sig_internal.data, sig, MLDSA44_SIGBYTES);
213 res = libcrux_ml_dsa_ml_dsa_44_portable_verify(&pk_internal,
214 message, context, &sig_internal);
215
216 return (res.tag == LIBCRUX_RESULT_OK) ? 0 : -1;
217 }
218
219 /* ML-DSA 65 */
220
221 #if 0
222 int
223 crypto_sign_mldsa65_keypair(uint8_t pk[MLDSA65_PUBLICKEYBYTES],
224 uint8_t sk[MLDSA65_SECRETKEYBYTES])
225 {
226 uint8_t rnd[MLDSA65_SEEDBYTES];
227 int r;
228
229 arc4random_buf(rnd, sizeof(rnd));
230 r = crypto_sign_mldsa65_keypair_seeded(pk, sk, rnd);
231 explicit_bzero(rnd, sizeof(rnd));
232 return r;
233 }
234
235 int
236 crypto_sign_mldsa65_keypair_seeded(uint8_t pk[MLDSA65_PUBLICKEYBYTES],
237 uint8_t sk[MLDSA65_SECRETKEYBYTES], const uint8_t seed[MLDSA65_SEEDBYTES])
238 {
239 libcrux_mldsa65_keypair_rnd rnd;
240 libcrux_mldsa65_keypair keypair;
241
242 memcpy(rnd.data, seed, sizeof(rnd.data));
243 keypair = libcrux_ml_dsa_ml_dsa_65_portable_generate_key_pair(rnd);
244 memcpy(pk, keypair.verification_key.data, MLDSA65_PUBLICKEYBYTES);
245 memcpy(sk, keypair.signing_key.data, MLDSA65_SECRETKEYBYTES);
246
247 explicit_bzero(&keypair, sizeof(keypair));
248 explicit_bzero(&rnd, sizeof(rnd));
249 return 0;
250 }
251
252 int
253 crypto_sign_mldsa65(uint8_t sig[MLDSA65_SIGBYTES],
254 const uint8_t *msg, size_t msglen,
255 const uint8_t *ctx, size_t ctxlen,
256 const uint8_t sk[MLDSA65_SECRETKEYBYTES])
257 {
258 uint8_t rnd[MLDSA65_SEEDBYTES];
259 int r;
260
261 arc4random_buf(rnd, sizeof(rnd));
262 r = crypto_sign_mldsa65_seeded(sig, msg, msglen, ctx, ctxlen, sk, rnd);
263 explicit_bzero(rnd, sizeof(rnd));
264 return r;
265 }
266
267 int
268 crypto_sign_mldsa65_seeded(uint8_t sig[MLDSA65_SIGBYTES],
269 const uint8_t *msg, size_t msglen,
270 const uint8_t *ctx, size_t ctxlen,
271 const uint8_t sk[MLDSA65_SECRETKEYBYTES],
272 const uint8_t seed[MLDSA65_SEEDBYTES])
273 {
274 libcrux_mldsa65_sign_rnd rnd;
275 libcrux_mldsa65_sk sk_internal;
276 libcrux_mldsa65_message message = { msg, msglen };
277 libcrux_mldsa65_message context = { ctx, ctxlen };
278 libcrux_mldsa65_sign_result res;
279 int r = -1;
280
281 memcpy(sk_internal.data, sk, MLDSA65_SECRETKEYBYTES);
282 memcpy(rnd.data, seed, sizeof(rnd.data));
283 res = libcrux_ml_dsa_ml_dsa_65_portable_sign(&sk_internal,
284 message, context, rnd);
285 if (res.tag == LIBCRUX_RESULT_OK) {
286 memcpy(sig, res.val.case_Ok.data, MLDSA65_SIGBYTES);
287 r = 0;
288 }
289
290 explicit_bzero(&sk_internal, sizeof(sk_internal));
291 explicit_bzero(&res, sizeof(res));
292 explicit_bzero(&rnd, sizeof(rnd));
293 return r;
294 }
295
296 int
297 crypto_sign_mldsa65_verify(const uint8_t sig[MLDSA65_SIGBYTES],
298 const uint8_t *msg, size_t msglen,
299 const uint8_t *ctx, size_t ctxlen,
300 const uint8_t pk[MLDSA65_PUBLICKEYBYTES])
301 {
302 libcrux_mldsa65_pk pk_internal;
303 libcrux_mldsa65_signature sig_internal;
304 libcrux_mldsa65_message message = { msg, msglen };
305 libcrux_mldsa65_message context = { ctx, ctxlen };
306 libcrux_mldsa65_verify_result res;
307
308 memcpy(pk_internal.data, pk, MLDSA65_PUBLICKEYBYTES);
309 memcpy(sig_internal.data, sig, MLDSA65_SIGBYTES);
310 res = libcrux_ml_dsa_ml_dsa_65_portable_verify(&pk_internal,
311 message, context, &sig_internal);
312
313 return (res.tag == LIBCRUX_RESULT_OK) ? 0 : -1;
314 }
315 #endif
316
317 /* ML-DSA 87 */
318
319 #if 0
320 int
321 crypto_sign_mldsa87_keypair(uint8_t pk[MLDSA87_PUBLICKEYBYTES],
322 uint8_t sk[MLDSA87_SECRETKEYBYTES])
323 {
324 uint8_t rnd[MLDSA87_SEEDBYTES];
325 int r;
326
327 arc4random_buf(rnd, sizeof(rnd));
328 r = crypto_sign_mldsa87_keypair_seeded(pk, sk, rnd);
329 explicit_bzero(rnd, sizeof(rnd));
330 return r;
331 }
332
333 int
334 crypto_sign_mldsa87_keypair_seeded(uint8_t pk[MLDSA87_PUBLICKEYBYTES],
335 uint8_t sk[MLDSA87_SECRETKEYBYTES], const uint8_t seed[MLDSA87_SEEDBYTES])
336 {
337 libcrux_mldsa87_keypair_rnd rnd;
338 libcrux_mldsa87_keypair keypair;
339
340 memcpy(rnd.data, seed, sizeof(rnd.data));
341 keypair = libcrux_ml_dsa_ml_dsa_87_portable_generate_key_pair(rnd);
342 memcpy(pk, keypair.verification_key.data, MLDSA87_PUBLICKEYBYTES);
343 memcpy(sk, keypair.signing_key.data, MLDSA87_SECRETKEYBYTES);
344
345 explicit_bzero(&keypair, sizeof(keypair));
346 explicit_bzero(&rnd, sizeof(rnd));
347 return 0;
348 }
349
350 int
351 crypto_sign_mldsa87(uint8_t sig[MLDSA87_SIGBYTES],
352 const uint8_t *msg, size_t msglen,
353 const uint8_t *ctx, size_t ctxlen,
354 const uint8_t sk[MLDSA87_SECRETKEYBYTES])
355 {
356 uint8_t rnd[MLDSA87_SEEDBYTES];
357 int r;
358
359 arc4random_buf(rnd, sizeof(rnd));
360 r = crypto_sign_mldsa87_seeded(sig, msg, msglen, ctx, ctxlen, sk, rnd);
361 explicit_bzero(rnd, sizeof(rnd));
362 return r;
363 }
364
365 int
366 crypto_sign_mldsa87_seeded(uint8_t sig[MLDSA87_SIGBYTES],
367 const uint8_t *msg, size_t msglen,
368 const uint8_t *ctx, size_t ctxlen,
369 const uint8_t sk[MLDSA87_SECRETKEYBYTES],
370 const uint8_t seed[MLDSA87_SEEDBYTES])
371 {
372 libcrux_mldsa87_sign_rnd rnd;
373 libcrux_mldsa87_sk sk_internal;
374 libcrux_mldsa87_message message = { msg, msglen };
375 libcrux_mldsa87_message context = { ctx, ctxlen };
376 libcrux_mldsa87_sign_result res;
377 int r = -1;
378
379 memcpy(sk_internal.data, sk, MLDSA87_SECRETKEYBYTES);
380 memcpy(rnd.data, seed, sizeof(rnd.data));
381 res = libcrux_ml_dsa_ml_dsa_87_portable_sign(&sk_internal,
382 message, context, rnd);
383 if (res.tag == LIBCRUX_RESULT_OK) {
384 memcpy(sig, res.val.case_Ok.data, MLDSA87_SIGBYTES);
385 r = 0;
386 }
387
388 explicit_bzero(&sk_internal, sizeof(sk_internal));
389 explicit_bzero(&res, sizeof(res));
390 explicit_bzero(&rnd, sizeof(rnd));
391 return r;
392 }
393
394 int
395 crypto_sign_mldsa87_verify(const uint8_t sig[MLDSA87_SIGBYTES],
396 const uint8_t *msg, size_t msglen,
397 const uint8_t *ctx, size_t ctxlen,
398 const uint8_t pk[MLDSA87_PUBLICKEYBYTES])
399 {
400 libcrux_mldsa87_pk pk_internal;
401 libcrux_mldsa87_signature sig_internal;
402 libcrux_mldsa87_message message = { msg, msglen };
403 libcrux_mldsa87_message context = { ctx, ctxlen };
404 libcrux_mldsa87_verify_result res;
405
406 memcpy(pk_internal.data, pk, MLDSA87_PUBLICKEYBYTES);
407 memcpy(sig_internal.data, sig, MLDSA87_SIGBYTES);
408 res = libcrux_ml_dsa_ml_dsa_87_portable_verify(&pk_internal,
409 message, context, &sig_internal);
410
411 return (res.tag == LIBCRUX_RESULT_OK) ? 0 : -1;
412 }
413 #endif
414
415 void
sha3_256(uint8_t digest[32],const uint8_t * data,size_t len)416 sha3_256(uint8_t digest[32], const uint8_t *data, size_t len)
417 {
418 Eurydice_borrow_slice_u8 input = { data, len };
419 Eurydice_mut_borrow_slice_u8 output = { digest, 32 };
420 libcrux_sha3_portable_sha256(output, input);
421 }
422
423 void
sha3_512(uint8_t digest[64],const uint8_t * data,size_t len)424 sha3_512(uint8_t digest[64], const uint8_t *data, size_t len)
425 {
426 Eurydice_borrow_slice_u8 input = { data, len };
427 Eurydice_mut_borrow_slice_u8 output = { digest, 64 };
428 libcrux_sha3_portable_sha512(output, input);
429 }
430 #endif /* defined(USE_MLDSA) || defined(USE_MLKEM768X25519) */
431