1 /* $NetBSD: libcrux-mlkem-mldsa.c,v 1.2 2026/09/21 23:01:54 christos Exp $ */ 2 /* $OpenBSD: libcrux-mlkem-mldsa.c,v 1.1 2026/06/14 03:59:34 djm Exp $ */ 3 4 /* 5 * Copyright (c) 2026 Damien Miller <djm (at) mindrot.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #include "includes.h" 20 __RCSID("$NetBSD: libcrux-mlkem-mldsa.c,v 1.2 2026/09/21 23:01:54 christos Exp $"); 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 { 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 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 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 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 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 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 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 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 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 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 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 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