diff options
| author | kenjiro <> | 2026-03-18 21:50:24 +0000 |
|---|---|---|
| committer | kenjiro <> | 2026-03-18 21:50:24 +0000 |
| commit | 82f203504202bf0d907e6a786382a70909be7a4f (patch) | |
| tree | f5c5ef338bc20a8eff13675f09785eaf74aa363a /src/usr.bin/openssl | |
| parent | 80318abdaa00a71f2fb14771bf4222c73b975fff (diff) | |
| download | openbsd-82f203504202bf0d907e6a786382a70909be7a4f.tar.gz openbsd-82f203504202bf0d907e6a786382a70909be7a4f.tar.bz2 openbsd-82f203504202bf0d907e6a786382a70909be7a4f.zip | |
openssl speed: add benchmarking support for ML-KEM
Add support for benchmarking ML-KEM key encapsulation mechanisms to
openssl speed. The following operations are measured:
- key generation
- encapsulation
- decapsulation
Two parameter sets are supported:
mlkem768
mlkem1024
The benchmark can be invoked using the following options:
mlkem run all ML-KEM benchmarks
mlkem768 run ML-KEM-768 benchmarks
mlkem1024 run ML-KEM-1024 benchmarks
Results are reported similarly to other public key algorithms, showing
time per operation and operations per second. Machine-readable output
(-mr) support is also added for ML-KEM.
ok tb
Diffstat (limited to 'src/usr.bin/openssl')
| -rw-r--r-- | src/usr.bin/openssl/speed.c | 181 |
1 files changed, 179 insertions, 2 deletions
diff --git a/src/usr.bin/openssl/speed.c b/src/usr.bin/openssl/speed.c index 1ece133f2e..8c0f0adca7 100644 --- a/src/usr.bin/openssl/speed.c +++ b/src/usr.bin/openssl/speed.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: speed.c,v 1.50 2025/12/13 01:58:53 kenjiro Exp $ */ | 1 | /* $OpenBSD: speed.c,v 1.51 2026/03/18 21:50:24 kenjiro Exp $ */ |
| 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * | 4 | * |
| @@ -78,6 +78,7 @@ | |||
| 78 | #define DSA_SECONDS 10 | 78 | #define DSA_SECONDS 10 |
| 79 | #define ECDSA_SECONDS 10 | 79 | #define ECDSA_SECONDS 10 |
| 80 | #define ECDH_SECONDS 10 | 80 | #define ECDH_SECONDS 10 |
| 81 | #define MLKEM_SECONDS 10 | ||
| 81 | 82 | ||
| 82 | #define MAX_UNALIGN 16 | 83 | #define MAX_UNALIGN 16 |
| 83 | 84 | ||
| @@ -95,6 +96,7 @@ | |||
| 95 | #include <openssl/crypto.h> | 96 | #include <openssl/crypto.h> |
| 96 | #include <openssl/err.h> | 97 | #include <openssl/err.h> |
| 97 | #include <openssl/evp.h> | 98 | #include <openssl/evp.h> |
| 99 | #include <openssl/mlkem.h> | ||
| 98 | #include <openssl/modes.h> | 100 | #include <openssl/modes.h> |
| 99 | #include <openssl/objects.h> | 101 | #include <openssl/objects.h> |
| 100 | #include <openssl/x509.h> | 102 | #include <openssl/x509.h> |
| @@ -214,6 +216,12 @@ enum { | |||
| 214 | EC_NUM, | 216 | EC_NUM, |
| 215 | }; | 217 | }; |
| 216 | 218 | ||
| 219 | enum { | ||
| 220 | R_MLKEM_768, | ||
| 221 | R_MLKEM_1024, | ||
| 222 | MLKEM_NUM, | ||
| 223 | }; | ||
| 224 | |||
| 217 | static const char *names[ALGOR_NUM] = { | 225 | static const char *names[ALGOR_NUM] = { |
| 218 | "md4", "md5", "hmac(sha256)", "sha1", "rmd160", | 226 | "md4", "md5", "hmac(sha256)", "sha1", "rmd160", |
| 219 | "rc4", "des cbc", "des ede3", "idea cbc", | 227 | "rc4", "des cbc", "des ede3", "idea cbc", |
| @@ -230,6 +238,18 @@ static double rsa_results[RSA_NUM][2]; | |||
| 230 | static double dsa_results[DSA_NUM][2]; | 238 | static double dsa_results[DSA_NUM][2]; |
| 231 | static double ecdsa_results[EC_NUM][2]; | 239 | static double ecdsa_results[EC_NUM][2]; |
| 232 | static double ecdh_results[EC_NUM][1]; | 240 | static double ecdh_results[EC_NUM][1]; |
| 241 | static double mlkem_results[MLKEM_NUM][3]; | ||
| 242 | |||
| 243 | struct mlkem_speed_param { | ||
| 244 | const char *name; | ||
| 245 | int bits; | ||
| 246 | int rank; | ||
| 247 | }; | ||
| 248 | |||
| 249 | static const struct mlkem_speed_param mlkem_params[MLKEM_NUM] = { | ||
| 250 | [R_MLKEM_768] = { "mlkem768", 768, MLKEM768_RANK }, | ||
| 251 | [R_MLKEM_1024] = { "mlkem1024", 1024, MLKEM1024_RANK }, | ||
| 252 | }; | ||
| 233 | 253 | ||
| 234 | static void sig_done(int sig); | 254 | static void sig_done(int sig); |
| 235 | 255 | ||
| @@ -1084,6 +1104,7 @@ speed_main(int argc, char **argv) | |||
| 1084 | int dsa_doit[DSA_NUM]; | 1104 | int dsa_doit[DSA_NUM]; |
| 1085 | int ecdsa_doit[EC_NUM]; | 1105 | int ecdsa_doit[EC_NUM]; |
| 1086 | int ecdh_doit[EC_NUM]; | 1106 | int ecdh_doit[EC_NUM]; |
| 1107 | int mlkem_doit[MLKEM_NUM]; | ||
| 1087 | int doit[ALGOR_NUM]; | 1108 | int doit[ALGOR_NUM]; |
| 1088 | int pr_header = 0; | 1109 | int pr_header = 0; |
| 1089 | const EVP_CIPHER *evp_cipher = NULL; | 1110 | const EVP_CIPHER *evp_cipher = NULL; |
| @@ -1134,6 +1155,8 @@ speed_main(int argc, char **argv) | |||
| 1134 | ecdsa_doit[i] = 0; | 1155 | ecdsa_doit[i] = 0; |
| 1135 | for (i = 0; i < EC_NUM; i++) | 1156 | for (i = 0; i < EC_NUM; i++) |
| 1136 | ecdh_doit[i] = 0; | 1157 | ecdh_doit[i] = 0; |
| 1158 | for (i = 0; i < MLKEM_NUM; i++) | ||
| 1159 | mlkem_doit[i] = 0; | ||
| 1137 | 1160 | ||
| 1138 | 1161 | ||
| 1139 | j = 0; | 1162 | j = 0; |
| @@ -1394,6 +1417,13 @@ speed_main(int argc, char **argv) | |||
| 1394 | else if (strcmp(*argv, "ecdh") == 0) { | 1417 | else if (strcmp(*argv, "ecdh") == 0) { |
| 1395 | for (i = 0; i < EC_NUM; i++) | 1418 | for (i = 0; i < EC_NUM; i++) |
| 1396 | ecdh_doit[i] = 1; | 1419 | ecdh_doit[i] = 1; |
| 1420 | } else if (strcmp(*argv, "mlkem") == 0) { | ||
| 1421 | mlkem_doit[R_MLKEM_768] = 1; | ||
| 1422 | mlkem_doit[R_MLKEM_1024] = 1; | ||
| 1423 | } else if (strcmp(*argv, "mlkem768") == 0) { | ||
| 1424 | mlkem_doit[R_MLKEM_768] = 2; | ||
| 1425 | } else if (strcmp(*argv, "mlkem1024") == 0) { | ||
| 1426 | mlkem_doit[R_MLKEM_1024] = 2; | ||
| 1397 | } else { | 1427 | } else { |
| 1398 | BIO_printf(bio_err, "Error: bad option or value\n"); | 1428 | BIO_printf(bio_err, "Error: bad option or value\n"); |
| 1399 | BIO_printf(bio_err, "\n"); | 1429 | BIO_printf(bio_err, "\n"); |
| @@ -1459,6 +1489,7 @@ speed_main(int argc, char **argv) | |||
| 1459 | BIO_printf(bio_err, "dsa512 dsa1024 dsa2048\n"); | 1489 | BIO_printf(bio_err, "dsa512 dsa1024 dsa2048\n"); |
| 1460 | BIO_printf(bio_err, "ecdsap224 ecdsap256 ecdsap384 ecdsap521\n"); | 1490 | BIO_printf(bio_err, "ecdsap224 ecdsap256 ecdsap384 ecdsap521\n"); |
| 1461 | BIO_printf(bio_err, "ecdhp224 ecdhp256 ecdhp384 ecdhp521\n"); | 1491 | BIO_printf(bio_err, "ecdhp224 ecdhp256 ecdhp384 ecdhp521\n"); |
| 1492 | BIO_printf(bio_err, "mlkem768 mlkem1024\n"); | ||
| 1462 | 1493 | ||
| 1463 | #ifndef OPENSSL_NO_IDEA | 1494 | #ifndef OPENSSL_NO_IDEA |
| 1464 | BIO_printf(bio_err, "idea "); | 1495 | BIO_printf(bio_err, "idea "); |
| @@ -1476,6 +1507,7 @@ speed_main(int argc, char **argv) | |||
| 1476 | BIO_printf(bio_err, "camellia "); | 1507 | BIO_printf(bio_err, "camellia "); |
| 1477 | #endif | 1508 | #endif |
| 1478 | BIO_printf(bio_err, "rsa "); | 1509 | BIO_printf(bio_err, "rsa "); |
| 1510 | BIO_printf(bio_err, "mlkem "); | ||
| 1479 | #ifndef OPENSSL_NO_BF | 1511 | #ifndef OPENSSL_NO_BF |
| 1480 | BIO_printf(bio_err, "blowfish"); | 1512 | BIO_printf(bio_err, "blowfish"); |
| 1481 | #endif | 1513 | #endif |
| @@ -1517,6 +1549,8 @@ speed_main(int argc, char **argv) | |||
| 1517 | ecdsa_doit[i] = 1; | 1549 | ecdsa_doit[i] = 1; |
| 1518 | for (i = 0; i < EC_NUM; i++) | 1550 | for (i = 0; i < EC_NUM; i++) |
| 1519 | ecdh_doit[i] = 1; | 1551 | ecdh_doit[i] = 1; |
| 1552 | for (i = 0; i < MLKEM_NUM; i++) | ||
| 1553 | mlkem_doit[i] = 1; | ||
| 1520 | } | 1554 | } |
| 1521 | for (i = 0; i < ALGOR_NUM; i++) | 1555 | for (i = 0; i < ALGOR_NUM; i++) |
| 1522 | if (doit[i]) | 1556 | if (doit[i]) |
| @@ -2362,7 +2396,124 @@ speed_main(int argc, char **argv) | |||
| 2362 | ecdh_doit[j] = 0; | 2396 | ecdh_doit[j] = 0; |
| 2363 | } | 2397 | } |
| 2364 | } | 2398 | } |
| 2365 | show_res: | 2399 | |
| 2400 | for (j = 0; j < MLKEM_NUM; j++) { | ||
| 2401 | const struct mlkem_speed_param *p = &mlkem_params[j]; | ||
| 2402 | int rank = p->rank; | ||
| 2403 | int bits = p->bits; | ||
| 2404 | MLKEM_private_key *priv = NULL; | ||
| 2405 | MLKEM_public_key *pub = NULL; | ||
| 2406 | uint8_t *encoded_pub = NULL; | ||
| 2407 | size_t encoded_pub_len = 0; | ||
| 2408 | uint8_t *ct = NULL, *ss = NULL; | ||
| 2409 | size_t ct_len = 0, ss_len = 0; | ||
| 2410 | |||
| 2411 | if (!mlkem_doit[j]) | ||
| 2412 | continue; | ||
| 2413 | |||
| 2414 | pkey_print_message("keygen", "mlkem", bits, MLKEM_SECONDS); | ||
| 2415 | time_f(START); | ||
| 2416 | for (count = 0, run = 1; COND; count++) { | ||
| 2417 | /* | ||
| 2418 | * MLKEM_generate_key requires an uninitialized key | ||
| 2419 | * object, so allocate and free on every iteration. | ||
| 2420 | */ | ||
| 2421 | if ((priv = MLKEM_private_key_new(rank)) == NULL) | ||
| 2422 | break; | ||
| 2423 | if (!MLKEM_generate_key(priv, &encoded_pub, | ||
| 2424 | &encoded_pub_len, NULL, NULL)) { | ||
| 2425 | MLKEM_private_key_free(priv); | ||
| 2426 | priv = NULL; | ||
| 2427 | break; | ||
| 2428 | } | ||
| 2429 | MLKEM_private_key_free(priv); | ||
| 2430 | priv = NULL; | ||
| 2431 | free(encoded_pub); | ||
| 2432 | encoded_pub = NULL; | ||
| 2433 | } | ||
| 2434 | d = time_f(STOP); | ||
| 2435 | if (run) | ||
| 2436 | goto mlkem_err; | ||
| 2437 | BIO_printf(bio_err, mr ? "+R8:%ld:%d:%.2f\n" | ||
| 2438 | : "%ld %d-bit ML-KEM keygen in %.2fs\n", count, bits, d); | ||
| 2439 | mlkem_results[j][2] = d / (double)count; | ||
| 2440 | rsa_count = count; | ||
| 2441 | |||
| 2442 | if ((priv = MLKEM_private_key_new(rank)) == NULL || | ||
| 2443 | (pub = MLKEM_public_key_new(rank)) == NULL) | ||
| 2444 | goto mlkem_err; | ||
| 2445 | if (!MLKEM_generate_key(priv, &encoded_pub, &encoded_pub_len, | ||
| 2446 | NULL, NULL) || | ||
| 2447 | !MLKEM_parse_public_key(pub, encoded_pub, encoded_pub_len)) | ||
| 2448 | goto mlkem_err; | ||
| 2449 | free(encoded_pub); | ||
| 2450 | encoded_pub = NULL; | ||
| 2451 | |||
| 2452 | pkey_print_message("encap", "mlkem", bits, MLKEM_SECONDS); | ||
| 2453 | time_f(START); | ||
| 2454 | for (count = 0, run = 1; COND; count++) { | ||
| 2455 | if (!MLKEM_encap(pub, &ct, &ct_len, &ss, | ||
| 2456 | &ss_len)) | ||
| 2457 | break; | ||
| 2458 | free(ct); | ||
| 2459 | ct = NULL; | ||
| 2460 | free(ss); | ||
| 2461 | ss = NULL; | ||
| 2462 | } | ||
| 2463 | d = time_f(STOP); | ||
| 2464 | if (run) | ||
| 2465 | goto mlkem_err; | ||
| 2466 | BIO_printf(bio_err, mr ? "+R9:%ld:%d:%.2f\n" | ||
| 2467 | : "%ld %d-bit ML-KEM encap in %.2fs\n", count, bits, d); | ||
| 2468 | mlkem_results[j][0] = d / (double)count; | ||
| 2469 | rsa_count = count; | ||
| 2470 | |||
| 2471 | if (!MLKEM_encap(pub, &ct, &ct_len, &ss, &ss_len)) | ||
| 2472 | goto mlkem_err; | ||
| 2473 | free(ss); | ||
| 2474 | ss = NULL; | ||
| 2475 | |||
| 2476 | pkey_print_message("decap", "mlkem", bits, MLKEM_SECONDS); | ||
| 2477 | time_f(START); | ||
| 2478 | for (count = 0, run = 1; COND; count++) { | ||
| 2479 | if (!MLKEM_decap(priv, ct, ct_len, &ss, &ss_len)) | ||
| 2480 | break; | ||
| 2481 | free(ss); | ||
| 2482 | ss = NULL; | ||
| 2483 | } | ||
| 2484 | d = time_f(STOP); | ||
| 2485 | if (run) | ||
| 2486 | goto mlkem_err; | ||
| 2487 | BIO_printf(bio_err, mr ? "+R10:%ld:%d:%.2f\n" | ||
| 2488 | : "%ld %d-bit ML-KEM decap in %.2fs\n", count, bits, d); | ||
| 2489 | mlkem_results[j][1] = d / (double)count; | ||
| 2490 | rsa_count = count; | ||
| 2491 | |||
| 2492 | free(ct); | ||
| 2493 | ct = NULL; | ||
| 2494 | MLKEM_private_key_free(priv); | ||
| 2495 | priv = NULL; | ||
| 2496 | MLKEM_public_key_free(pub); | ||
| 2497 | pub = NULL; | ||
| 2498 | |||
| 2499 | if (rsa_count <= 1) { | ||
| 2500 | /* if longer than 10s, don't do any more */ | ||
| 2501 | for (j++; j < MLKEM_NUM; j++) | ||
| 2502 | mlkem_doit[j] = 0; | ||
| 2503 | } | ||
| 2504 | continue; | ||
| 2505 | |||
| 2506 | mlkem_err: | ||
| 2507 | BIO_printf(bio_err, "MLKEM failure\n"); | ||
| 2508 | ERR_print_errors(bio_err); | ||
| 2509 | MLKEM_private_key_free(priv); | ||
| 2510 | MLKEM_public_key_free(pub); | ||
| 2511 | free(encoded_pub); | ||
| 2512 | free(ct); | ||
| 2513 | free(ss); | ||
| 2514 | } | ||
| 2515 | |||
| 2516 | show_res: | ||
| 2366 | if (!mr) { | 2517 | if (!mr) { |
| 2367 | fprintf(stdout, "%s\n", SSLeay_version(SSLEAY_VERSION)); | 2518 | fprintf(stdout, "%s\n", SSLeay_version(SSLEAY_VERSION)); |
| 2368 | fprintf(stdout, "%s\n", SSLeay_version(SSLEAY_BUILT_ON)); | 2519 | fprintf(stdout, "%s\n", SSLeay_version(SSLEAY_BUILT_ON)); |
| @@ -2469,6 +2620,32 @@ show_res: | |||
| 2469 | ecdh_results[k][0], 1.0 / ecdh_results[k][0]); | 2620 | ecdh_results[k][0], 1.0 / ecdh_results[k][0]); |
| 2470 | } | 2621 | } |
| 2471 | 2622 | ||
| 2623 | j = 1; | ||
| 2624 | for (k = 0; k < MLKEM_NUM; k++) { | ||
| 2625 | if (!mlkem_doit[k]) | ||
| 2626 | continue; | ||
| 2627 | if (j && !mr) { | ||
| 2628 | printf("%-9s%12s%9s%12s%9s%12s%9s\n", | ||
| 2629 | "", "keygen", "keygen/s", | ||
| 2630 | "encap", "encap/s", | ||
| 2631 | "decap", "decap/s"); | ||
| 2632 | j = 0; | ||
| 2633 | } | ||
| 2634 | if (mr) | ||
| 2635 | fprintf(stdout, "+F6:%u:%f:%f:%f:%f:%f:%f\n", | ||
| 2636 | mlkem_params[k].bits, | ||
| 2637 | mlkem_results[k][2], 1.0 / mlkem_results[k][2], | ||
| 2638 | mlkem_results[k][0], 1.0 / mlkem_results[k][0], | ||
| 2639 | mlkem_results[k][1], 1.0 / mlkem_results[k][1]); | ||
| 2640 | else | ||
| 2641 | fprintf(stdout, | ||
| 2642 | "mlkem%4d %10.6fs %8.1f %10.6fs %8.1f %10.6fs %8.1f\n", | ||
| 2643 | mlkem_params[k].bits, | ||
| 2644 | mlkem_results[k][2], 1.0 / mlkem_results[k][2], | ||
| 2645 | mlkem_results[k][0], 1.0 / mlkem_results[k][0], | ||
| 2646 | mlkem_results[k][1], 1.0 / mlkem_results[k][1]); | ||
| 2647 | } | ||
| 2648 | |||
| 2472 | mret = 0; | 2649 | mret = 0; |
| 2473 | 2650 | ||
| 2474 | end: | 2651 | end: |
