xref: /freebsd/crypto/openssh/libcrux-mlkem-mldsa.c (revision bb5c77e9d281d6def6835d48249898764bc6a5fe)
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