Coverage Report

Created: 2026-07-16 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssh/libcrux-mlkem-mldsa.c
Line
Count
Source
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
35
crypto_kem_mlkem768_keypair(uint8_t pk[crypto_kem_mlkem768_PUBLICKEYBYTES],
36
    uint8_t sk[crypto_kem_mlkem768_SECRETKEYBYTES])
37
0
{
38
0
  uint8_t rnd[crypto_kem_mlkem768_KEYPAIRSEEDBYTES];
39
0
  int r;
40
41
0
  arc4random_buf(rnd, sizeof(rnd));
42
0
  r = crypto_kem_mlkem768_keypair_seeded(pk, sk, rnd);
43
0
  explicit_bzero(rnd, sizeof(rnd));
44
0
  return r;
45
0
}
46
47
int
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
0
{
52
0
  libcrux_mlkem768_keypair keypair;
53
0
  libcrux_mlkem768_keypair_rnd rnd;
54
55
0
  memcpy(rnd.data, seed, sizeof(rnd.data));
56
0
  keypair = libcrux_ml_kem_mlkem768_portable_generate_key_pair(rnd);
57
0
  memcpy(pk, keypair.pk.data, crypto_kem_mlkem768_PUBLICKEYBYTES);
58
0
  memcpy(sk, keypair.sk.data, crypto_kem_mlkem768_SECRETKEYBYTES);
59
60
0
  explicit_bzero(&keypair, sizeof(keypair));
61
0
  explicit_bzero(&rnd, sizeof(rnd));
62
0
  return 0;
63
0
}
64
65
int
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
0
{
70
0
  uint8_t rnd[crypto_kem_mlkem768_ENCSEEDBYTES];
71
0
  int r;
72
73
0
  arc4random_buf(rnd, sizeof(rnd));
74
0
  r = crypto_kem_mlkem768_enc_seeded(ct, shared_secret, pk, rnd);
75
0
  explicit_bzero(rnd, sizeof(rnd));
76
0
  return r;
77
0
}
78
79
int
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
0
{
85
0
  libcrux_mlkem768_enc_result enc;
86
0
  libcrux_mlkem768_pk pk_internal;
87
0
  libcrux_mlkem768_enc_rnd rnd;
88
89
0
  memcpy(pk_internal.data, pk, crypto_kem_mlkem768_PUBLICKEYBYTES);
90
0
  if (!libcrux_ml_kem_mlkem768_portable_validate_public_key(&pk_internal))
91
0
    return -1;
92
0
  memcpy(rnd.data, seed, sizeof(rnd.data));
93
0
  enc = libcrux_ml_kem_mlkem768_portable_encapsulate(&pk_internal, rnd);
94
0
  memcpy(ct, enc.fst.data, crypto_kem_mlkem768_CIPHERTEXTBYTES);
95
0
  memcpy(shared_secret, enc.snd.data, crypto_kem_mlkem768_BYTES);
96
97
0
  explicit_bzero(&enc, sizeof(enc));
98
0
  explicit_bzero(&rnd, sizeof(rnd));
99
0
  return 0;
100
0
}
101
102
int
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
0
{
107
0
  libcrux_mlkem768_sk sk_internal;
108
0
  libcrux_mlkem768_ciphertext ct_internal;
109
0
  libcrux_mlkem768_dec_result shared_secret_internal;
110
111
0
  memcpy(sk_internal.data, sk, crypto_kem_mlkem768_SECRETKEYBYTES);
112
0
  memcpy(ct_internal.data, ct, crypto_kem_mlkem768_CIPHERTEXTBYTES);
113
0
  shared_secret_internal = libcrux_ml_kem_mlkem768_portable_decapsulate(
114
0
      &sk_internal, &ct_internal);
115
0
  memcpy(shared_secret, shared_secret_internal.data,
116
0
      crypto_kem_mlkem768_BYTES);
117
118
0
  explicit_bzero(&sk_internal, sizeof(sk_internal));
119
0
  explicit_bzero(&shared_secret_internal, sizeof(shared_secret_internal));
120
0
  return 0;
121
0
}
122
123
/* ML-DSA 44 */
124
125
int
126
crypto_sign_mldsa44_keypair(uint8_t pk[MLDSA44_PUBLICKEYBYTES],
127
    uint8_t sk[MLDSA44_SECRETKEYBYTES])
128
0
{
129
0
  uint8_t rnd[MLDSA44_SEEDBYTES];
130
0
  int r;
131
132
0
  arc4random_buf(rnd, sizeof(rnd));
133
0
  r = crypto_sign_mldsa44_keypair_seeded(pk, sk, rnd);
134
0
  explicit_bzero(rnd, sizeof(rnd));
135
0
  return r;
136
0
}
137
138
int
139
crypto_sign_mldsa44_keypair_seeded(uint8_t pk[MLDSA44_PUBLICKEYBYTES],
140
    uint8_t sk[MLDSA44_SECRETKEYBYTES], const uint8_t seed[MLDSA44_SEEDBYTES])
141
0
{
142
0
  libcrux_mldsa44_keypair_rnd rnd;
143
0
  libcrux_mldsa44_keypair keypair;
144
145
0
  memcpy(rnd.data, seed, sizeof(rnd.data));
146
0
  keypair = libcrux_ml_dsa_ml_dsa_44_portable_generate_key_pair(rnd);
147
0
  memcpy(pk, keypair.verification_key.data, MLDSA44_PUBLICKEYBYTES);
148
0
  memcpy(sk, keypair.signing_key.data, MLDSA44_SECRETKEYBYTES);
149
150
0
  explicit_bzero(&keypair, sizeof(keypair));
151
0
  explicit_bzero(&rnd, sizeof(rnd));
152
0
  return 0;
153
0
}
154
155
int
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
0
{
161
0
  uint8_t rnd[MLDSA44_SEEDBYTES];
162
0
  int r;
163
164
0
  arc4random_buf(rnd, sizeof(rnd));
165
0
  r = crypto_sign_mldsa44_seeded(sig, msg, msglen, ctx, ctxlen, sk, rnd);
166
0
  explicit_bzero(rnd, sizeof(rnd));
167
0
  return r;
168
0
}
169
170
int
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
0
{
177
0
  libcrux_mldsa44_sign_rnd rnd;
178
0
  libcrux_mldsa44_sk sk_internal;
179
0
  libcrux_mldsa44_message message = { msg, msglen };
180
0
  libcrux_mldsa44_message context = { ctx, ctxlen };
181
0
  libcrux_mldsa44_sign_result res;
182
0
  int r = -1;
183
184
0
  memcpy(sk_internal.data, sk, MLDSA44_SECRETKEYBYTES);
185
0
  memcpy(rnd.data, seed, sizeof(rnd.data));
186
0
  res = libcrux_ml_dsa_ml_dsa_44_portable_sign(&sk_internal,
187
0
      message, context, rnd);
188
0
  if (res.tag == LIBCRUX_RESULT_OK) {
189
0
    memcpy(sig, res.val.case_Ok.data, MLDSA44_SIGBYTES);
190
0
    r = 0;
191
0
  }
192
193
0
  explicit_bzero(&sk_internal, sizeof(sk_internal));
194
0
  explicit_bzero(&res, sizeof(res));
195
0
  explicit_bzero(&rnd, sizeof(rnd));
196
0
  return r;
197
0
}
198
199
int
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
0
{
205
0
  libcrux_mldsa44_pk pk_internal;
206
0
  libcrux_mldsa44_signature sig_internal;
207
0
  libcrux_mldsa44_message message = { msg, msglen };
208
0
  libcrux_mldsa44_message context = { ctx, ctxlen };
209
0
  libcrux_mldsa44_verify_result res;
210
211
0
  memcpy(pk_internal.data, pk, MLDSA44_PUBLICKEYBYTES);
212
0
  memcpy(sig_internal.data, sig, MLDSA44_SIGBYTES);
213
0
  res = libcrux_ml_dsa_ml_dsa_44_portable_verify(&pk_internal,
214
0
      message, context, &sig_internal);
215
216
0
  return (res.tag == LIBCRUX_RESULT_OK) ? 0 : -1;
217
0
}
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
416
sha3_256(uint8_t digest[32], const uint8_t *data, size_t len)
417
0
{
418
0
  Eurydice_borrow_slice_u8 input = { data, len };
419
0
  Eurydice_mut_borrow_slice_u8 output = { digest, 32 };
420
0
  libcrux_sha3_portable_sha256(output, input);
421
0
}
422
423
void
424
sha3_512(uint8_t digest[64], const uint8_t *data, size_t len)
425
0
{
426
0
  Eurydice_borrow_slice_u8 input = { data, len };
427
0
  Eurydice_mut_borrow_slice_u8 output = { digest, 64 };
428
0
  libcrux_sha3_portable_sha512(output, input);
429
0
}
430
#endif /* defined(USE_MLDSA) || defined(USE_MLKEM768X25519) */