Coverage Report

Created: 2026-07-24 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssh/ssh-mldsa-eddsa.c
Line
Count
Source
1
/* $OpenBSD: ssh-mldsa-eddsa.c,v 1.2 2026/07/14 04:43:13 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
/* draft-miller-sshm-mldsa44-ed25519-composite-sigs-00 */
19
20
#include "includes.h"
21
22
#ifdef USE_MLDSA
23
24
#include <sys/types.h>
25
#include <stdint.h>
26
#include <string.h>
27
#include <stdlib.h>
28
29
#include "crypto_api.h"
30
#include "sshbuf.h"
31
#include "ssherr.h"
32
#include "digest.h"
33
#define SSHKEY_INTERNAL
34
#include "sshkey.h"
35
#include "log.h"
36
37
0
#define COMPOSITE_PREFIX "CompositeAlgorithmSignatures2025"
38
0
#define COMPOSITE_LABEL  "COMPSIG-MLDSA44-Ed25519-SHA512"
39
0
#define SSH_MLDSA44_ED25519_ALG_NAME   "ssh-mldsa44-ed25519@openssh.com"
40
41
/*
42
 * raw_* functions implement the draft-ietf-lamps-pq-composite-sigs-18
43
 * composite signature scheme. These are exposed (i.e. not static) so
44
 * we can test them separately in unittests/crypto.
45
 */
46
47
int
48
crypto_sign_mldsa44_ed25519_keygen(uint8_t pk[MLDSA44_ED25519_PK_SZ],
49
    uint8_t sk[MLDSA44_ED25519_SK_SZ])
50
0
{
51
0
  uint8_t mldsa_seed[MLDSA44_SEEDBYTES];
52
0
  uint8_t ed25519_seed[crypto_sign_ed25519_SEEDBYTES];
53
0
  int r;
54
55
0
  arc4random_buf(mldsa_seed, sizeof(mldsa_seed));
56
0
  arc4random_buf(ed25519_seed, sizeof(ed25519_seed));
57
58
0
  r = crypto_sign_mldsa44_ed25519_keygen_seeded(pk, sk, mldsa_seed,
59
0
      ed25519_seed);
60
0
  explicit_bzero(mldsa_seed, sizeof(mldsa_seed));
61
0
  explicit_bzero(ed25519_seed, sizeof(ed25519_seed));
62
0
  return r;
63
0
}
64
65
int
66
crypto_sign_mldsa44_ed25519_keygen_seeded(uint8_t pk[MLDSA44_ED25519_PK_SZ],
67
    uint8_t sk[MLDSA44_ED25519_SK_SZ],
68
    const uint8_t mldsa_seed[MLDSA44_SEEDBYTES],
69
    const uint8_t ed25519_seed[crypto_sign_ed25519_SEEDBYTES])
70
0
{
71
0
  uint8_t ed25519_pk[MLDSA44_SEEDBYTES];
72
0
  uint8_t ed25519_sk[crypto_sign_ed25519_SECRETKEYBYTES];
73
0
  uint8_t mldsa_sk[MLDSA44_SECRETKEYBYTES];
74
0
  int ret = -1;
75
76
0
  if (crypto_sign_mldsa44_keypair_seeded(pk, mldsa_sk, mldsa_seed) != 0)
77
0
    goto out;
78
0
  if (crypto_sign_ed25519_keypair_from_seed(ed25519_pk, ed25519_sk,
79
0
      ed25519_seed) != 0)
80
0
    goto out;
81
82
  /* Serialize PK: mldsaPK || ed25519PK */
83
0
  memcpy(pk + MLDSA44_PUBLICKEYBYTES, ed25519_pk,
84
0
      crypto_sign_ed25519_SEEDBYTES);
85
86
  /* Serialize SK: mldsaSeed || ed25519Seed */
87
0
  memcpy(sk, mldsa_seed, MLDSA44_SEEDBYTES);
88
0
  memcpy(sk + MLDSA44_SEEDBYTES, ed25519_seed,
89
0
      crypto_sign_ed25519_SEEDBYTES);
90
91
  /* success */
92
0
  ret = 0;
93
0
 out:
94
0
  explicit_bzero(mldsa_sk, sizeof(mldsa_sk));
95
0
  explicit_bzero(ed25519_sk, sizeof(ed25519_sk));
96
0
  return ret;
97
0
}
98
99
static int
100
construct_m_prime(uint8_t **m_primep, size_t *m_prime_lenp,
101
    const uint8_t *msg, size_t msglen,
102
    const uint8_t *ctx, size_t ctxlen)
103
0
{
104
0
  int r;
105
0
  uint8_t hash[64];
106
0
  struct sshbuf *m_prime;
107
108
0
  *m_primep = NULL;
109
0
  *m_prime_lenp = 0;
110
111
0
  if (ctxlen > 255)
112
0
    return SSH_ERR_INVALID_ARGUMENT;
113
0
  if ((r = ssh_digest_memory(SSH_DIGEST_SHA512, msg, msglen,
114
0
      hash, sizeof(hash))) != 0)
115
0
    return r;
116
0
  if ((m_prime = sshbuf_new()) == NULL)
117
0
    return SSH_ERR_ALLOC_FAIL;
118
0
  if ((r = sshbuf_put(m_prime, COMPOSITE_PREFIX,
119
0
      sizeof(COMPOSITE_PREFIX) - 1)) != 0 ||
120
0
      (r = sshbuf_put(m_prime, COMPOSITE_LABEL,
121
0
      sizeof(COMPOSITE_LABEL) - 1)) != 0 ||
122
0
      (r = sshbuf_put_u8(m_prime, (uint8_t)ctxlen)) != 0 ||
123
0
      (r = sshbuf_put(m_prime, ctx, ctxlen)) != 0 ||
124
0
      (r = sshbuf_put(m_prime, hash, sizeof(hash))) != 0) {
125
0
    sshbuf_free(m_prime);
126
0
    return r;
127
0
  }
128
0
  if ((*m_primep = malloc(sshbuf_len(m_prime))) == NULL) {
129
0
    sshbuf_free(m_prime);
130
0
    return SSH_ERR_ALLOC_FAIL;
131
0
  }
132
0
  memcpy(*m_primep, sshbuf_ptr(m_prime), sshbuf_len(m_prime));
133
0
  *m_prime_lenp = sshbuf_len(m_prime);
134
  /* success */
135
0
  sshbuf_free(m_prime);
136
0
  return 0;
137
0
}
138
139
int
140
crypto_sign_mldsa44_ed25519_sign(uint8_t sig[MLDSA44_ED25519_SIG_SZ],
141
    const uint8_t *msg, size_t msglen,
142
    const uint8_t *ctx, size_t ctxlen,
143
    const uint8_t sk[MLDSA44_ED25519_SK_SZ])
144
0
{
145
0
  uint8_t *m_prime = NULL;
146
0
  size_t m_prime_len = 0;
147
0
  uint8_t mldsa_sk[MLDSA44_SECRETKEYBYTES];
148
0
  uint8_t mldsa_pk_dummy[MLDSA44_PUBLICKEYBYTES];
149
0
  uint8_t ed25519_pk[crypto_sign_ed25519_PUBLICKEYBYTES];
150
0
  uint8_t ed25519_sk[crypto_sign_ed25519_SECRETKEYBYTES];
151
0
  uint8_t mldsa_rnd[MLDSA44_SEEDBYTES];
152
0
  unsigned long long smlen;
153
0
  int r = -1;
154
155
0
  if (construct_m_prime(&m_prime, &m_prime_len, msg, msglen,
156
0
      ctx, ctxlen) != 0)
157
0
    return -1;
158
159
  /* Expand ML-DSA key from seed */
160
0
  if (crypto_sign_mldsa44_keypair_seeded(mldsa_pk_dummy, mldsa_sk, sk) != 0)
161
0
    goto out;
162
163
  /* Sign with ML-DSA */
164
0
  arc4random_buf(mldsa_rnd, sizeof(mldsa_rnd));
165
0
  if (crypto_sign_mldsa44_seeded(sig, m_prime, m_prime_len,
166
0
      (const uint8_t *)COMPOSITE_LABEL, sizeof(COMPOSITE_LABEL) - 1,
167
0
      mldsa_sk, mldsa_rnd) != 0)
168
0
    goto out;
169
170
  /* Expand Ed25519 key from seed */
171
0
  if (crypto_sign_ed25519_keypair_from_seed(ed25519_pk, ed25519_sk,
172
0
      sk + MLDSA44_SEEDBYTES) != 0)
173
0
    goto out;
174
175
  /* Sign with Ed25519 */
176
0
  uint8_t *sm = malloc(m_prime_len + crypto_sign_ed25519_BYTES);
177
0
  if (sm == NULL)
178
0
    goto out;
179
180
0
  if (crypto_sign_ed25519(sm, &smlen, m_prime, m_prime_len,
181
0
      ed25519_sk) != 0) {
182
0
    free(sm);
183
0
    goto out;
184
0
  }
185
0
  memcpy(sig + MLDSA44_SIGBYTES, sm, crypto_sign_ed25519_BYTES);
186
0
  free(sm);
187
188
0
  r = 0;
189
0
 out:
190
0
  free(m_prime);
191
0
  explicit_bzero(mldsa_rnd, sizeof(mldsa_rnd));
192
0
  explicit_bzero(mldsa_sk, sizeof(mldsa_sk));
193
0
  explicit_bzero(ed25519_sk, sizeof(ed25519_sk));
194
0
  return r;
195
0
}
196
197
int
198
crypto_sign_mldsa44_ed25519_verify(const uint8_t sig[MLDSA44_ED25519_SIG_SZ],
199
    const uint8_t *msg, size_t msglen,
200
    const uint8_t *ctx, size_t ctxlen,
201
    const uint8_t pk[MLDSA44_ED25519_PK_SZ])
202
0
{
203
0
  uint8_t *m_prime = NULL;
204
0
  size_t m_prime_len = 0;
205
0
  uint8_t *sm = NULL, *m = NULL;
206
0
  unsigned long long smlen, mlen;
207
0
  int r = -1;
208
209
0
  if (construct_m_prime(&m_prime, &m_prime_len, msg, msglen,
210
0
      ctx, ctxlen) != 0)
211
0
    return -1;
212
213
  /* Verify ML-DSA */
214
0
  if (crypto_sign_mldsa44_verify(sig, m_prime, m_prime_len,
215
0
      (const uint8_t *)COMPOSITE_LABEL, sizeof(COMPOSITE_LABEL) - 1,
216
0
      pk) != 0)
217
0
    goto out;
218
219
  /* Verify Ed25519 */
220
0
  smlen = m_prime_len + crypto_sign_ed25519_BYTES;
221
0
  mlen = smlen;
222
0
  if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL)
223
0
    goto out;
224
0
  memcpy(sm, sig + MLDSA44_SIGBYTES, crypto_sign_ed25519_BYTES);
225
0
  memcpy(sm + crypto_sign_ed25519_BYTES, m_prime, m_prime_len);
226
227
0
  if (crypto_sign_ed25519_open(m, &mlen, sm, smlen,
228
0
      pk + MLDSA44_PUBLICKEYBYTES) != 0)
229
0
    goto out;
230
0
  if (mlen != m_prime_len)
231
0
    goto out;
232
233
0
  r = 0;
234
0
 out:
235
0
  free(m_prime);
236
0
  free(sm);
237
0
  free(m);
238
0
  return r;
239
0
}
240
241
/* sshkey integration */
242
243
static void
244
ssh_mldsa44_ed25519_cleanup(struct sshkey *k)
245
81
{
246
81
  freezero(k->mldsa_ed25519_pk, MLDSA44_ED25519_PK_SZ);
247
81
  freezero(k->mldsa_ed25519_sk, MLDSA44_ED25519_SK_SZ);
248
81
  k->mldsa_ed25519_pk = NULL;
249
81
  k->mldsa_ed25519_sk = NULL;
250
81
}
251
252
static int
253
ssh_mldsa44_ed25519_equal(const struct sshkey *a, const struct sshkey *b)
254
0
{
255
0
  if (a->mldsa_ed25519_pk == NULL || b->mldsa_ed25519_pk == NULL)
256
0
    return 0;
257
0
  if (memcmp(a->mldsa_ed25519_pk, b->mldsa_ed25519_pk,
258
0
      MLDSA44_ED25519_PK_SZ) != 0)
259
0
    return 0;
260
0
  return 1;
261
0
}
262
263
static int
264
ssh_mldsa44_ed25519_serialize_public(const struct sshkey *key, struct sshbuf *b,
265
    enum sshkey_serialize_rep opts)
266
0
{
267
0
  int r;
268
269
0
  if (key->mldsa_ed25519_pk == NULL)
270
0
    return SSH_ERR_INVALID_ARGUMENT;
271
0
  if ((r = sshbuf_put_string(b, key->mldsa_ed25519_pk,
272
0
      MLDSA44_ED25519_PK_SZ)) != 0)
273
0
    return r;
274
275
0
  return 0;
276
0
}
277
278
static int
279
ssh_mldsa44_ed25519_serialize_private(const struct sshkey *key, struct sshbuf *b,
280
    enum sshkey_serialize_rep opts)
281
0
{
282
0
  int r;
283
284
0
  if (key->mldsa_ed25519_sk == NULL)
285
0
    return SSH_ERR_INVALID_ARGUMENT;
286
0
  if (!sshkey_is_cert(key)) {
287
0
    if ((r = ssh_mldsa44_ed25519_serialize_public(key,
288
0
        b, opts)) != 0)
289
0
      return r;
290
0
  }
291
0
  if ((r = sshbuf_put_string(b, key->mldsa_ed25519_sk,
292
0
      MLDSA44_ED25519_SK_SZ)) != 0)
293
0
    return r;
294
295
0
  return 0;
296
0
}
297
298
static int
299
ssh_mldsa44_ed25519_deserialize_public(const char *ktype, struct sshbuf *b,
300
    struct sshkey *key)
301
81
{
302
81
  u_char *pk = NULL;
303
81
  size_t len = 0;
304
81
  int r;
305
306
81
  if ((r = sshbuf_get_string(b, &pk, &len)) != 0)
307
10
    return r;
308
71
  if (len != MLDSA44_ED25519_PK_SZ) {
309
46
    freezero(pk, len);
310
46
    return SSH_ERR_INVALID_FORMAT;
311
46
  }
312
25
  key->mldsa_ed25519_pk = pk;
313
25
  return 0;
314
71
}
315
316
static int
317
ssh_mldsa44_ed25519_deserialize_private(const char *ktype, struct sshbuf *b,
318
    struct sshkey *key)
319
55
{
320
55
  int r;
321
55
  size_t sklen = 0;
322
55
  u_char *sk = NULL;
323
324
55
  if (!sshkey_is_cert(key)) {
325
55
    if ((r = ssh_mldsa44_ed25519_deserialize_public(ktype,
326
55
        b, key)) != 0)
327
32
      return r;
328
55
  }
329
23
  if ((r = sshbuf_get_string(b, &sk, &sklen)) != 0)
330
2
    goto out;
331
21
  if (sklen != MLDSA44_ED25519_SK_SZ) {
332
20
    r = SSH_ERR_INVALID_FORMAT;
333
20
    goto out;
334
20
  }
335
1
  key->mldsa_ed25519_sk = sk;
336
1
  sk = NULL; /* transferred */
337
1
  r = 0;
338
23
 out:
339
23
  freezero(sk, sklen);
340
23
  return r;
341
1
}
342
343
static int
344
ssh_mldsa44_ed25519_generate(struct sshkey *k, int bits)
345
0
{
346
0
  free(k->mldsa_ed25519_pk);
347
0
  free(k->mldsa_ed25519_sk);
348
0
  k->mldsa_ed25519_pk = NULL;
349
0
  k->mldsa_ed25519_sk = NULL;
350
0
  if ((k->mldsa_ed25519_pk = malloc(MLDSA44_ED25519_PK_SZ)) == NULL ||
351
0
      (k->mldsa_ed25519_sk = malloc(MLDSA44_ED25519_SK_SZ)) == NULL) {
352
0
    free(k->mldsa_ed25519_pk);
353
0
    return SSH_ERR_ALLOC_FAIL;
354
0
  }
355
0
  if (crypto_sign_mldsa44_ed25519_keygen(k->mldsa_ed25519_pk,
356
0
      k->mldsa_ed25519_sk) != 0) {
357
0
    free(k->mldsa_ed25519_pk);
358
0
    free(k->mldsa_ed25519_sk);
359
0
    return SSH_ERR_CRYPTO_ERROR;
360
0
  }
361
0
  return 0;
362
0
}
363
364
static int
365
ssh_mldsa44_ed25519_copy_public(const struct sshkey *from, struct sshkey *to)
366
0
{
367
0
  if (from->mldsa_ed25519_pk == NULL)
368
0
    return SSH_ERR_INVALID_ARGUMENT;
369
0
  if ((to->mldsa_ed25519_pk = malloc(MLDSA44_ED25519_PK_SZ)) == NULL)
370
0
    return SSH_ERR_ALLOC_FAIL;
371
0
  memcpy(to->mldsa_ed25519_pk, from->mldsa_ed25519_pk,
372
0
      MLDSA44_ED25519_PK_SZ);
373
0
  return 0;
374
0
}
375
376
static int
377
ssh_mldsa44_ed25519_sign(struct sshkey *key,
378
    u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
379
    const char *alg, const char *sk_provider, const char *sk_pin,
380
    u_int compat)
381
0
{
382
0
  u_char sig[MLDSA44_ED25519_SIG_SZ];
383
0
  struct sshbuf *b = NULL;
384
0
  int r = SSH_ERR_INTERNAL_ERROR;
385
386
0
  if (lenp != NULL)
387
0
    *lenp = 0;
388
0
  if (sigp != NULL)
389
0
    *sigp = NULL;
390
391
0
  if (key == NULL ||
392
0
      sshkey_type_plain(key->type) != KEY_MLDSA44_ED25519 ||
393
0
      key->mldsa_ed25519_sk == NULL)
394
0
    return SSH_ERR_INVALID_ARGUMENT;
395
396
0
  if (crypto_sign_mldsa44_ed25519_sign(sig, data, datalen, NULL, 0,
397
0
      key->mldsa_ed25519_sk) != 0) {
398
0
    r = SSH_ERR_CRYPTO_ERROR;
399
0
    goto out;
400
0
  }
401
402
0
  if ((b = sshbuf_new()) == NULL) {
403
0
    r = SSH_ERR_ALLOC_FAIL;
404
0
    goto out;
405
0
  }
406
0
  if ((r = sshbuf_put_cstring(b, SSH_MLDSA44_ED25519_ALG_NAME)) != 0 ||
407
0
      (r = sshbuf_put_string(b, sig, sizeof(sig))) != 0)
408
0
    goto out;
409
410
0
  if (sigp != NULL) {
411
0
    if ((*sigp = malloc(sshbuf_len(b))) == NULL) {
412
0
      r = SSH_ERR_ALLOC_FAIL;
413
0
      goto out;
414
0
    }
415
0
    memcpy(*sigp, sshbuf_ptr(b), sshbuf_len(b));
416
0
  }
417
0
  if (lenp != NULL)
418
0
    *lenp = sshbuf_len(b);
419
0
  r = 0;
420
0
 out:
421
0
  sshbuf_free(b);
422
0
  explicit_bzero(sig, sizeof(sig));
423
0
  return r;
424
0
}
425
426
static int
427
ssh_mldsa44_ed25519_verify(const struct sshkey *key,
428
    const u_char *sig, size_t siglen, const u_char *data, size_t dlen,
429
    const char *alg, u_int compat, struct sshkey_sig_details **detailsp)
430
0
{
431
0
  struct sshbuf *b = NULL;
432
0
  char *ktype = NULL;
433
0
  const u_char *sigblob;
434
0
  size_t len;
435
0
  int r;
436
437
0
  if (key == NULL ||
438
0
      sshkey_type_plain(key->type) != KEY_MLDSA44_ED25519 ||
439
0
      key->mldsa_ed25519_pk == NULL ||
440
0
      sig == NULL || siglen == 0)
441
0
    return SSH_ERR_INVALID_ARGUMENT;
442
443
0
  if ((b = sshbuf_from(sig, siglen)) == NULL)
444
0
    return SSH_ERR_ALLOC_FAIL;
445
0
  if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
446
0
      (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
447
0
    goto out;
448
0
  if (strcmp(SSH_MLDSA44_ED25519_ALG_NAME, ktype) != 0) {
449
0
    r = SSH_ERR_KEY_TYPE_MISMATCH;
450
0
    goto out;
451
0
  }
452
0
  if (sshbuf_len(b) != 0) {
453
0
    r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
454
0
    goto out;
455
0
  }
456
0
  if (len != MLDSA44_ED25519_SIG_SZ) {
457
0
    r = SSH_ERR_INVALID_FORMAT;
458
0
    goto out;
459
0
  }
460
461
0
  if (crypto_sign_mldsa44_ed25519_verify(sigblob, data, dlen, NULL, 0,
462
0
      key->mldsa_ed25519_pk) != 0) {
463
0
    r = SSH_ERR_SIGNATURE_INVALID;
464
0
    goto out;
465
0
  }
466
467
0
  r = 0;
468
0
 out:
469
0
  sshbuf_free(b);
470
0
  free(ktype);
471
0
  return r;
472
0
}
473
474
const struct sshkey_impl_funcs sshkey_mldsa44_ed25519_funcs = {
475
  /* .size = */   NULL,
476
  /* .alloc = */    NULL,
477
  /* .cleanup = */  ssh_mldsa44_ed25519_cleanup,
478
  /* .equal = */    ssh_mldsa44_ed25519_equal,
479
  /* .ssh_serialize_public = */ ssh_mldsa44_ed25519_serialize_public,
480
  /* .ssh_deserialize_public = */ ssh_mldsa44_ed25519_deserialize_public,
481
  /* .ssh_serialize_private = */ ssh_mldsa44_ed25519_serialize_private,
482
  /* .ssh_deserialize_private = */ ssh_mldsa44_ed25519_deserialize_private,
483
  /* .generate = */ ssh_mldsa44_ed25519_generate,
484
  /* .copy_public = */  ssh_mldsa44_ed25519_copy_public,
485
  /* .sign = */   ssh_mldsa44_ed25519_sign,
486
  /* .verify = */   ssh_mldsa44_ed25519_verify,
487
};
488
489
const struct sshkey_impl sshkey_mldsa44_ed25519_impl = {
490
  /* .name = */   "ssh-mldsa44-ed25519@openssh.com",
491
  /* .shortname = */  "MLDSA44-ED25519",
492
  /* .sigalg = */   NULL,
493
  /* .type = */   KEY_MLDSA44_ED25519,
494
  /* .nid = */    0,
495
  /* .cert = */   0,
496
  /* .sigonly = */  0,
497
  /* .keybits = */  256,
498
  /* .funcs = */    &sshkey_mldsa44_ed25519_funcs,
499
};
500
501
const struct sshkey_impl sshkey_mldsa44_ed25519_cert_impl = {
502
  /* .name = */   "ssh-mldsa44-ed25519-cert-v01@openssh.com",
503
  /* .shortname = */  "MLDSA44-ED25519-CERT",
504
  /* .sigalg = */   NULL,
505
  /* .type = */   KEY_MLDSA44_ED25519_CERT,
506
  /* .nid = */    0,
507
  /* .cert = */   1,
508
  /* .sigonly = */  0,
509
  /* .keybits = */  256,
510
  /* .funcs = */    &sshkey_mldsa44_ed25519_funcs,
511
};
512
#endif /* USE_MLDSA */