diff --git a/benchmark/bench_modules/wh_bench_mod_all.h b/benchmark/bench_modules/wh_bench_mod_all.h
index 629be885a..6cf71d466 100644
--- a/benchmark/bench_modules/wh_bench_mod_all.h
+++ b/benchmark/bench_modules/wh_bench_mod_all.h
@@ -424,4 +424,30 @@ int wh_Bench_Mod_MlKem1024DecapsDma(whClientContext* client,
whBenchOpContext* ctx, int id,
void* params);
+/*
+ * LMS benchmark module prototypes (wh_bench_mod_lms.c)
+ *
+ * LMS is stateful (hash-based) and DMA-only in wolfHSM, so there is a single
+ * variant per operation (no non-DMA counterpart).
+ */
+int wh_Bench_Mod_LmsKeyGen(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params);
+int wh_Bench_Mod_LmsSign(whClientContext* client, whBenchOpContext* ctx, int id,
+ void* params);
+int wh_Bench_Mod_LmsVerify(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params);
+
+/*
+ * XMSS benchmark module prototypes (wh_bench_mod_xmss.c)
+ *
+ * XMSS is stateful (hash-based) and DMA-only in wolfHSM, so there is a single
+ * variant per operation (no non-DMA counterpart).
+ */
+int wh_Bench_Mod_XmssKeyGen(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params);
+int wh_Bench_Mod_XmssSign(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params);
+int wh_Bench_Mod_XmssVerify(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params);
+
#endif /* WH_BENCH_MOD_ALL_H_ */
diff --git a/benchmark/bench_modules/wh_bench_mod_lms.c b/benchmark/bench_modules/wh_bench_mod_lms.c
new file mode 100644
index 000000000..d4c0d1505
--- /dev/null
+++ b/benchmark/bench_modules/wh_bench_mod_lms.c
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 2026 wolfSSL Inc.
+ *
+ * This file is part of wolfHSM.
+ *
+ * wolfHSM is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfHSM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wolfHSM. If not, see .
+ */
+#include "wh_bench_mod.h"
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_client.h"
+#include "wolfhsm/wh_client_crypto.h"
+
+
+#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_BENCH_ENABLE)
+
+/* LMS is stateful (hash-based) and is only exposed by wolfHSM over DMA. KEY-GEN
+ * and SIGN need a full (signing) build. VERIFY additionally works in a
+ * verify-only build: it runs against a precomputed public key and signature
+ * (see the vectors below) instead of generating them. The verify path is
+ * therefore guarded only by WOLFSSL_HAVE_LMS, while keygen/sign additionally
+ * require !WOLFSSL_LMS_VERIFY_ONLY. */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS)
+
+#include
+#include "wolfssl/wolfcrypt/random.h"
+#include "wolfssl/wolfcrypt/wc_lms.h"
+
+/*
+ * Timing characteristics of these benchmarks
+ * ------------------------------------------
+ * LMS is a stateful hash-based signature scheme: each signature consumes one
+ * one-time key and advances the private key state. In wolfHSM the observed
+ * timing is shaped less by the LMS algorithm than by how the server persists
+ * the key:
+ *
+ * - VERIFY is state-independent. It recomputes the LM-OTS public key candidate
+ * and walks the H authentication-path nodes to the root, a fixed amount of
+ * work regardless of the signature index. Its per-op time is flat. It runs
+ * against a fixed precomputed (public key, signature) pair, so - unlike
+ * keygen/sign - it is also available in a verify-only build, the config most
+ * likely deployed on a verifying device in the field.
+ *
+ * - SIGN is dominated by key reconstruction, not by the signature itself. The
+ * server persists only a compact LMS private key to NVM; before each sign it
+ * calls wc_LmsKey_Reload (see _HandleLmsSignDma in wh_server_crypto.c), which
+ * rebuilds the Merkle tree state from the seed. That reload costs about as
+ * much as key generation, so SIGN throughput here tracks KEY-GEN throughput
+ * and stays essentially flat across indices. (Standalone, key-resident
+ * wolfCrypt would instead advance an in-memory auth-path traversal per sign,
+ * which is cheap but state-dependent - wolfHSM does not keep that state
+ * resident between requests.)
+ *
+ * - Because the key is reconstructed from scratch on every request, the
+ * wolfCrypt "sign smoothing" optimization (on by default for single-level LMS
+ * unless WOLFSSL_LMS_NO_SIGN_SMOOTHING is defined) has no observable effect in
+ * this benchmark: smoothing spreads the cost of an in-process incremental
+ * traversal across many resident signatures, and that traversal never
+ * survives between signs here. Building with WOLFSSL_LMS_NO_SIGN_SMOOTHING
+ * produces identical timings (verified).
+ *
+ * Benchmarking note: only the first WOLFHSM_CFG_BENCH_PK_ITERS indices are
+ * signed. Because each sign reloads the full tree, per-sign cost is uniform, so
+ * this small sample is representative for LMS.
+ */
+
+/* LMS parameter set for the benchmark: L=1, H=5, W=8. This yields 2^5 = 32
+ * one-time signatures, ~1.3 KB signatures, and a fast keygen. */
+#define WH_BENCH_LMS_LEVELS (1)
+#define WH_BENCH_LMS_HEIGHT (5)
+#define WH_BENCH_LMS_WINTERNITZ (8)
+
+/* Precomputed public key and signature for the VERIFY benchmark, generated once
+ * with wolfCrypt over WH_BENCH_LMS_MSG using the parameter set above. Embedding
+ * them lets verify run without keygen/sign, so it is available in a verify-only
+ * build. */
+#define WH_BENCH_LMS_MSG "Test message for LMS signing"
+static const byte bench_lms_l1h5w8_pub[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x36, 0xa7, 0xe0, 0x89, 0x54, 0x18, 0xb6, 0x29, 0xd2, 0x22, 0x97, 0x29,
+ 0x3d, 0xb6, 0x5a, 0x2f, 0x1b, 0x7f, 0xf8, 0xe9, 0x63, 0x7b, 0xc1, 0xf6,
+ 0x46, 0x33, 0xd2, 0x70, 0x85, 0x5d, 0x5d, 0xc2, 0x27, 0xfc, 0x7e, 0x6b,
+ 0x1d, 0x26, 0xb8, 0xf5, 0x86, 0xb0, 0x54, 0xc0, 0xbb, 0xe8, 0xbb, 0xf6,
+};
+
+static const byte bench_lms_l1h5w8_sig[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x4a, 0xe9, 0x78, 0x79, 0xca, 0x8c, 0xfd, 0x1d, 0xee, 0x52, 0x0d, 0x71,
+ 0x46, 0xe3, 0x63, 0x22, 0x49, 0x7a, 0xa9, 0x12, 0xdb, 0x79, 0x49, 0x8d,
+ 0x22, 0x3c, 0xf6, 0x47, 0x7d, 0x68, 0xb2, 0x83, 0x24, 0x6e, 0x28, 0xd5,
+ 0x39, 0xfc, 0xcf, 0xee, 0xd5, 0x1e, 0xe0, 0x11, 0xfd, 0xb8, 0x4d, 0xf7,
+ 0xf6, 0xd7, 0xf6, 0x39, 0x0a, 0x98, 0x74, 0x70, 0x21, 0x4f, 0x27, 0x32,
+ 0xbd, 0x58, 0xb5, 0xea, 0x03, 0xce, 0x2c, 0x9e, 0x4c, 0x35, 0x4a, 0xca,
+ 0x1d, 0x3b, 0x5a, 0x5a, 0xe8, 0x4b, 0x6a, 0x31, 0x4c, 0xdb, 0xbe, 0x67,
+ 0x53, 0x0e, 0xc8, 0x40, 0xd4, 0xab, 0x03, 0xdb, 0xab, 0xd7, 0x77, 0x79,
+ 0xa7, 0x9a, 0x3e, 0x24, 0xe8, 0x55, 0x69, 0xe2, 0x02, 0x19, 0x56, 0x48,
+ 0xeb, 0x3d, 0x04, 0x47, 0x01, 0x22, 0x4d, 0x71, 0x6b, 0x2a, 0x42, 0xde,
+ 0x6b, 0x6e, 0xd4, 0x0e, 0x25, 0x5e, 0xb3, 0xab, 0x14, 0x96, 0x70, 0x3a,
+ 0xdc, 0x58, 0xb3, 0x6a, 0x84, 0x4a, 0xa2, 0x1c, 0x32, 0x37, 0xc4, 0x45,
+ 0x29, 0x16, 0xd4, 0x87, 0xfe, 0x01, 0x96, 0x5c, 0xd7, 0xad, 0xe7, 0xbb,
+ 0xf1, 0x0a, 0xbe, 0xc8, 0xaa, 0x7f, 0xba, 0x5e, 0xb6, 0xac, 0x43, 0x16,
+ 0x7c, 0x33, 0xdd, 0x0e, 0xfa, 0x30, 0xc8, 0xc1, 0xd2, 0x68, 0x1e, 0x48,
+ 0xe5, 0x53, 0x21, 0x63, 0x70, 0x07, 0xd3, 0x72, 0x11, 0x6f, 0xd2, 0x67,
+ 0x91, 0x81, 0x2d, 0xf8, 0xd7, 0x8f, 0x57, 0x74, 0x01, 0xa8, 0xb3, 0x7a,
+ 0x94, 0x11, 0x56, 0x9d, 0xe1, 0x2e, 0x52, 0xa7, 0x2a, 0x43, 0x52, 0xd5,
+ 0xb6, 0xf3, 0xc7, 0x44, 0xf1, 0xe3, 0xf4, 0x94, 0x5d, 0x21, 0x33, 0x70,
+ 0xc8, 0x0d, 0x31, 0xc5, 0xc1, 0x17, 0x5a, 0x1c, 0x3b, 0x47, 0x47, 0xce,
+ 0xe8, 0x04, 0x5e, 0x4d, 0xc1, 0x53, 0x13, 0xe7, 0xbb, 0xc4, 0x22, 0xc4,
+ 0xb6, 0x66, 0x2a, 0xe2, 0xf3, 0xf8, 0x12, 0x8a, 0x39, 0xd2, 0x5e, 0x74,
+ 0xc1, 0x00, 0x31, 0xf5, 0xc4, 0x3a, 0xe3, 0x92, 0xdd, 0x88, 0x35, 0x78,
+ 0x1c, 0x98, 0xc7, 0x4c, 0x0c, 0xdb, 0x3d, 0xb9, 0x99, 0x42, 0x4e, 0xc7,
+ 0x9a, 0x62, 0xe3, 0xa1, 0x83, 0xc3, 0x2a, 0xe4, 0x00, 0x35, 0x8a, 0x2a,
+ 0x2c, 0x91, 0x62, 0x89, 0xed, 0xb8, 0x45, 0x1d, 0x96, 0xd3, 0x9d, 0x56,
+ 0x63, 0xc1, 0xf9, 0xf9, 0x65, 0xb8, 0xf5, 0x2c, 0xbd, 0xb2, 0x21, 0xb0,
+ 0x22, 0x9f, 0xdf, 0x59, 0xdf, 0x97, 0x71, 0x11, 0xa8, 0xc9, 0x12, 0xfc,
+ 0xec, 0x66, 0xc7, 0xb8, 0x67, 0xc4, 0xc7, 0x42, 0x54, 0x7f, 0x4e, 0xe0,
+ 0x1e, 0xa3, 0xa1, 0x9d, 0xfb, 0x89, 0x72, 0x44, 0x55, 0x5a, 0x73, 0x91,
+ 0x6c, 0xd3, 0x0d, 0x16, 0x1a, 0x87, 0xe1, 0xac, 0xfe, 0xf8, 0xfd, 0x43,
+ 0x04, 0x8d, 0x91, 0x65, 0x8e, 0xda, 0x7e, 0xa5, 0xee, 0xbf, 0xfa, 0x1b,
+ 0x62, 0x4b, 0x09, 0x1c, 0x6c, 0xbf, 0x65, 0xaa, 0xc1, 0xad, 0x10, 0x46,
+ 0xf5, 0x67, 0xdf, 0x99, 0x53, 0x1a, 0xca, 0x22, 0x25, 0xd5, 0xb1, 0xda,
+ 0xec, 0x34, 0xf4, 0xea, 0x6d, 0x20, 0x04, 0xa6, 0xbb, 0xdb, 0xf4, 0x49,
+ 0xbe, 0x66, 0x74, 0x7f, 0x31, 0x7d, 0x94, 0xa1, 0x29, 0x59, 0x5d, 0x3b,
+ 0x0a, 0xc0, 0x56, 0xa6, 0x7a, 0xde, 0xd1, 0x07, 0x16, 0x1b, 0x06, 0x78,
+ 0xd4, 0xb6, 0xfb, 0x10, 0x36, 0xfd, 0x5e, 0x50, 0xae, 0xdb, 0x7f, 0xb6,
+ 0xa4, 0x92, 0xaa, 0x2d, 0x21, 0x61, 0x5f, 0x68, 0xd7, 0xe5, 0xa0, 0x09,
+ 0xa4, 0xeb, 0x55, 0xb7, 0x8d, 0xb5, 0xe1, 0x3d, 0xcd, 0x0c, 0x8c, 0x4c,
+ 0xea, 0xf8, 0xdf, 0x49, 0x29, 0xcb, 0x56, 0xa7, 0x83, 0xbb, 0x7c, 0x46,
+ 0x55, 0x70, 0x71, 0x07, 0x34, 0xde, 0x78, 0xdb, 0xa4, 0xc9, 0x66, 0x91,
+ 0x6f, 0xcc, 0x71, 0x50, 0x32, 0xd2, 0xb5, 0xa3, 0x11, 0x5f, 0x0f, 0x86,
+ 0xb5, 0x73, 0x9b, 0xd9, 0x2b, 0x00, 0xd9, 0x42, 0x64, 0x2f, 0xb9, 0x1a,
+ 0x85, 0x0c, 0xa8, 0xd8, 0xa3, 0x83, 0xfc, 0x23, 0x6b, 0xc2, 0xe8, 0x03,
+ 0xc1, 0x23, 0xd5, 0xdf, 0x0c, 0x1d, 0xcf, 0x39, 0x90, 0x06, 0x9f, 0x02,
+ 0x8d, 0x91, 0xe0, 0x1f, 0x4f, 0xf3, 0x37, 0x8c, 0x0c, 0x59, 0xe5, 0x98,
+ 0x66, 0x68, 0x49, 0xe8, 0x02, 0x2d, 0x73, 0x8c, 0xc5, 0xf7, 0xde, 0xb3,
+ 0xd7, 0x25, 0xd0, 0xc1, 0x92, 0x21, 0x33, 0x27, 0x26, 0xf1, 0xf0, 0xc1,
+ 0xe1, 0x0a, 0x9a, 0xff, 0x3d, 0x9f, 0x37, 0xdc, 0x68, 0x94, 0xe0, 0xc5,
+ 0x7c, 0x6a, 0xbf, 0xcd, 0xbb, 0x25, 0xd8, 0xf8, 0xeb, 0xf0, 0x15, 0x00,
+ 0x48, 0x52, 0xaa, 0xe4, 0xce, 0x6a, 0xd7, 0xf2, 0x94, 0x5b, 0x9b, 0xa4,
+ 0x45, 0x2f, 0x73, 0x50, 0x5c, 0x38, 0xea, 0x1d, 0x85, 0xb9, 0x51, 0x53,
+ 0x73, 0x59, 0x48, 0x93, 0x30, 0x9f, 0xd0, 0x98, 0x5b, 0xb7, 0x25, 0x27,
+ 0x54, 0x41, 0x1c, 0xa4, 0xfb, 0xbd, 0xfc, 0x42, 0x57, 0x41, 0x40, 0xff,
+ 0x2e, 0xa6, 0x06, 0x26, 0x0b, 0x95, 0x06, 0x4c, 0x60, 0xd4, 0x01, 0x3e,
+ 0xcd, 0x30, 0xac, 0x27, 0x4c, 0xd1, 0x72, 0x79, 0x02, 0x0e, 0x44, 0x82,
+ 0x81, 0x61, 0xc2, 0xed, 0xd7, 0xc1, 0x1e, 0x93, 0x7e, 0xc1, 0xb2, 0x07,
+ 0xad, 0x98, 0xd0, 0x12, 0x83, 0x88, 0x3e, 0x73, 0xd9, 0xf0, 0xd1, 0x4e,
+ 0x41, 0x6f, 0xd5, 0x38, 0x37, 0x56, 0xfa, 0x89, 0xdf, 0x7e, 0x91, 0xd6,
+ 0x19, 0x29, 0x12, 0xe5, 0x09, 0xa7, 0x6d, 0x37, 0x82, 0xa7, 0xe2, 0x25,
+ 0x2a, 0x1d, 0x13, 0xa2, 0xdf, 0x33, 0x12, 0xc2, 0x87, 0x59, 0x5d, 0xf7,
+ 0x9a, 0x22, 0x55, 0xb9, 0xdc, 0xc6, 0x53, 0x69, 0xb8, 0xe0, 0x9b, 0xaf,
+ 0xb4, 0x08, 0x85, 0x44, 0x66, 0xd6, 0x4d, 0x55, 0xaf, 0x89, 0x10, 0x95,
+ 0xf4, 0x6c, 0x07, 0x86, 0x6c, 0x10, 0x33, 0x31, 0xea, 0x96, 0x6c, 0x15,
+ 0x11, 0xdf, 0xdd, 0xc6, 0x5f, 0x3a, 0x28, 0x21, 0xb4, 0xf5, 0xfb, 0x38,
+ 0x0e, 0x79, 0x6f, 0x47, 0xfe, 0xaa, 0x6c, 0x91, 0x17, 0xdb, 0xbb, 0x6c,
+ 0x67, 0x20, 0x70, 0x79, 0x19, 0x20, 0x80, 0x53, 0x18, 0xef, 0xd7, 0x4f,
+ 0x02, 0x9b, 0x6a, 0x80, 0x20, 0xcb, 0xd9, 0x1f, 0x54, 0xd4, 0xbe, 0x8d,
+ 0xa7, 0x6c, 0x51, 0x8f, 0xcd, 0x82, 0xce, 0xe9, 0x40, 0x82, 0x62, 0x16,
+ 0xad, 0x55, 0x5f, 0x67, 0x96, 0xa9, 0xe9, 0x5c, 0xad, 0xe0, 0x26, 0x80,
+ 0xb7, 0x44, 0xcb, 0x09, 0x55, 0xc8, 0x1a, 0x17, 0x73, 0xab, 0xbf, 0x93,
+ 0x96, 0x92, 0x03, 0xed, 0x66, 0x2a, 0xfb, 0x96, 0x2f, 0x2e, 0x05, 0xbe,
+ 0xe7, 0xf2, 0xd7, 0xca, 0x3f, 0x5c, 0x77, 0x1f, 0xa0, 0xa8, 0x86, 0xed,
+ 0xd8, 0xa5, 0xb9, 0xe4, 0xdf, 0x65, 0xc8, 0x15, 0x01, 0x02, 0xac, 0xd9,
+ 0x57, 0x82, 0x7a, 0x62, 0x4d, 0x83, 0x72, 0x4e, 0xd7, 0x84, 0xbc, 0x5c,
+ 0x20, 0x9e, 0x74, 0x35, 0x6e, 0x97, 0x77, 0xf6, 0x61, 0x80, 0x87, 0x59,
+ 0x13, 0x04, 0x5f, 0x70, 0xe3, 0x76, 0xcb, 0xbb, 0xa4, 0xa3, 0x16, 0x0e,
+ 0xeb, 0x88, 0xc3, 0x93, 0xd1, 0x22, 0xde, 0xcf, 0xf6, 0xe2, 0xcb, 0xa5,
+ 0x93, 0xf4, 0x1f, 0x96, 0x91, 0x4a, 0x50, 0x71, 0x0f, 0x98, 0x33, 0xf6,
+ 0x28, 0xa5, 0x68, 0x7a, 0xac, 0x6e, 0x91, 0xfb, 0xf7, 0x7e, 0xe7, 0xdb,
+ 0xec, 0x0c, 0x4f, 0xba, 0x17, 0x35, 0x40, 0x77, 0xdc, 0x90, 0xf9, 0xd4,
+ 0x97, 0x44, 0x61, 0xd7, 0x4b, 0x5c, 0x28, 0xe8, 0x88, 0x2d, 0xca, 0x6d,
+ 0xbb, 0xf9, 0xc4, 0xce, 0x47, 0xdc, 0x6e, 0xad, 0x9d, 0xe2, 0x80, 0x3d,
+ 0x1f, 0x60, 0xd0, 0xf0, 0x5d, 0x45, 0x35, 0x94, 0x9a, 0xc2, 0x38, 0x3c,
+ 0x6a, 0x28, 0xf0, 0xff, 0xaf, 0x41, 0xcd, 0xf0, 0x17, 0x86, 0x96, 0x92,
+ 0x4e, 0x1e, 0xe9, 0x01, 0x4c, 0x6e, 0x56, 0xee, 0x30, 0xe3, 0x37, 0xc2,
+ 0x47, 0xfd, 0xb0, 0x7c, 0xf5, 0xbf, 0x3e, 0x31, 0xe2, 0xa1, 0x13, 0x72,
+ 0x66, 0x56, 0x3a, 0x37, 0xcf, 0x98, 0x2c, 0xe3, 0x87, 0x07, 0xe4, 0x55,
+ 0xb7, 0x36, 0xd3, 0xa6, 0x36, 0xc4, 0xd7, 0x27, 0x24, 0x1b, 0x3a, 0xf4,
+ 0x15, 0xc8, 0x2e, 0xd0, 0x06, 0x98, 0x60, 0xca, 0xc6, 0xc2, 0xe2, 0x92,
+ 0x16, 0xf0, 0xe1, 0x58, 0x36, 0x07, 0x03, 0xe4, 0x49, 0xbe, 0xf5, 0x48,
+ 0x76, 0x45, 0xce, 0x1f, 0xe5, 0xac, 0xdb, 0xf1, 0x10, 0x70, 0xf5, 0xca,
+ 0xc5, 0x3b, 0xe5, 0xd2, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x93, 0xf0, 0xed,
+ 0xa3, 0x07, 0x74, 0x8a, 0xcf, 0x08, 0xed, 0x66, 0x76, 0x66, 0xab, 0x64,
+ 0xae, 0x8c, 0x7f, 0x9c, 0xe8, 0x0f, 0x47, 0x45, 0xd9, 0xb9, 0x36, 0xf1,
+ 0x46, 0x17, 0xb2, 0xc4, 0x0b, 0x70, 0x5e, 0x1a, 0x31, 0x93, 0x1c, 0x13,
+ 0x6e, 0x43, 0x9e, 0x65, 0x2c, 0xe9, 0x52, 0xe7, 0x35, 0x9d, 0x65, 0x54,
+ 0xdd, 0x3c, 0xcb, 0xb7, 0xbd, 0x3c, 0x70, 0xb0, 0x34, 0xa6, 0xd7, 0x7a,
+ 0xbb, 0x74, 0xfa, 0xf0, 0x86, 0x59, 0xd5, 0x8f, 0x61, 0x07, 0x46, 0xf8,
+ 0xa7, 0x94, 0xa5, 0x85, 0xe5, 0x0f, 0xd2, 0x81, 0x0a, 0xb7, 0x9a, 0x3a,
+ 0x7a, 0xb1, 0x72, 0x12, 0x7c, 0xdc, 0x36, 0x94, 0x85, 0xe9, 0x5c, 0x93,
+ 0x63, 0xec, 0xe5, 0xa2, 0x5f, 0x77, 0x0e, 0x1f, 0xaf, 0x8a, 0xa1, 0x62,
+ 0xf7, 0xb9, 0x6e, 0xea, 0xf5, 0x90, 0x59, 0x5a, 0x9f, 0x32, 0xa0, 0x7d,
+ 0xa5, 0x9a, 0x6a, 0x87, 0xdf, 0x48, 0x8c, 0xb0, 0x5f, 0xbb, 0x27, 0xc0,
+ 0x57, 0xd5, 0xa8, 0x17, 0xfa, 0x40, 0x69, 0x59, 0x70, 0x01, 0x77, 0x2f,
+ 0x98, 0xd2, 0x8b, 0xce, 0xc2, 0xb7, 0x74, 0x24, 0xd0, 0xe3, 0x04, 0xc6,
+};
+
+
+/* Helper function for LMS verify benchmark. Loads the precomputed public key
+ * into the HSM cache (ephemeral, verify-only) and times wc_LmsKey_Verify over
+ * the fixed signature. No keygen/sign, so this runs in verify-only builds. */
+static int _benchLmsVerify(whClientContext* client, whBenchOpContext* ctx,
+ int id)
+{
+ int ret = 0;
+ LmsKey key;
+ const byte msg[] = WH_BENCH_LMS_MSG;
+ const word32 msgSz = (word32)(sizeof(msg) - 1);
+ int i;
+ int initialized_key = 0;
+ whKeyId keyId = WH_KEYID_ERASED;
+ char keyLabel[] = "bench-lms-verify-key";
+
+ (void)wh_Client_SetDmaMode(client, 1);
+
+ /* Initialize the LMS key */
+ ret = wc_LmsKey_Init(&key, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_Init %d\n", ret);
+ goto exit;
+ }
+ initialized_key = 1;
+
+ /* Bind the parameter set (required before importing the public key) */
+ ret = wc_LmsKey_SetParameters(&key, WH_BENCH_LMS_LEVELS,
+ WH_BENCH_LMS_HEIGHT, WH_BENCH_LMS_WINTERNITZ);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_SetParameters %d\n", ret);
+ goto exit;
+ }
+
+ /* Load the precomputed public key into the wolfCrypt structure */
+ ret = wc_LmsKey_ImportPubRaw(&key, bench_lms_l1h5w8_pub,
+ (word32)sizeof(bench_lms_l1h5w8_pub));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_ImportPubRaw %d\n", ret);
+ goto exit;
+ }
+
+ /* Provision the verify-only public key into the HSM cache. EPHEMERAL keeps
+ * it out of NVM; it is evicted during cleanup. */
+ ret = wh_Client_LmsImportPubKey(client, &key, &keyId, WH_NVM_FLAGS_EPHEMERAL,
+ (uint16_t)strlen(keyLabel),
+ (uint8_t*)keyLabel);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Client_LmsImportPubKey %d\n", ret);
+ goto exit;
+ }
+
+ /* Set key ID */
+ ret = wh_Client_LmsSetKeyId(&key, keyId);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Client_LmsSetKeyId %d\n", ret);
+ goto exit;
+ }
+
+ /* Benchmark the verification operation over the fixed valid signature */
+ for (i = 0; i < WOLFHSM_CFG_BENCH_PK_ITERS && ret == 0; i++) {
+ int benchStartRet;
+ int benchStopRet;
+
+ /* Time only the verify operation */
+ benchStartRet = wh_Bench_StartOp(ctx, id);
+ ret = wc_LmsKey_Verify(&key, bench_lms_l1h5w8_sig,
+ (word32)sizeof(bench_lms_l1h5w8_sig), msg,
+ (int)msgSz);
+ benchStopRet = wh_Bench_StopOp(ctx, id);
+
+ if (benchStartRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StartOp %d\n", benchStartRet);
+ ret = benchStartRet;
+ break;
+ }
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_Verify %d\n", ret);
+ break;
+ }
+ if (benchStopRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StopOp %d\n", benchStopRet);
+ ret = benchStopRet;
+ break;
+ }
+ }
+
+exit:
+ /* Clean up resources */
+ if (initialized_key) {
+ wc_LmsKey_Free(&key);
+ }
+
+ /* Evict the cached verify-only public key */
+ if (!WH_KEYID_ISERASED(keyId)) {
+ int evictRet = wh_Client_KeyEvict(client, keyId);
+ if ((evictRet != 0) && (ret == 0)) {
+ ret = evictRet;
+ }
+ }
+
+ return ret;
+}
+
+#if !defined(WOLFSSL_LMS_VERIFY_ONLY)
+
+/* Signature buffer sized generously for L1_H5_W8 (~1328 bytes). File scope to
+ * keep it off the stack; benchmark modules run sequentially, so a single shared
+ * buffer is safe. */
+static byte g_lmsSigBuf[2048];
+
+/* Helper function for LMS key generation benchmark */
+static int _benchLmsKeyGen(whClientContext* client, whBenchOpContext* ctx,
+ int id)
+{
+ int ret = 0;
+ LmsKey key;
+ WC_RNG rng[1] = {0};
+ int i;
+ int initialized_rng = 0;
+ int initialized_key = 0;
+ whKeyId keyId = WH_KEYID_ERASED;
+
+ (void)wh_Client_SetDmaMode(client, 1);
+
+ /* Initialize the RNG */
+ ret = wc_InitRng_ex(rng, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_InitRng_ex %d\n", ret);
+ return ret;
+ }
+ initialized_rng = 1;
+
+ /* Benchmark the key generation */
+ for (i = 0; i < WOLFHSM_CFG_BENCH_KG_ITERS && ret == 0; i++) {
+ int benchStartRet;
+ int benchStopRet;
+ int keyIdRet = 0;
+
+ /* Initialize the LMS key before each iteration */
+ ret = wc_LmsKey_Init(&key, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_Init %d\n", ret);
+ break;
+ }
+ initialized_key = 1;
+
+ /* Bind the LMS parameter set */
+ ret = wc_LmsKey_SetParameters(&key, WH_BENCH_LMS_LEVELS,
+ WH_BENCH_LMS_HEIGHT,
+ WH_BENCH_LMS_WINTERNITZ);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_SetParameters %d\n", ret);
+ break;
+ }
+
+ /* Time only the key generation. Keygen commits the private key to NVM
+ * on the server, so it is erased afterwards outside the timed region. */
+ benchStartRet = wh_Bench_StartOp(ctx, id);
+ ret = wc_LmsKey_MakeKey(&key, rng);
+ benchStopRet = wh_Bench_StopOp(ctx, id);
+
+ /* Capture the keyId as soon as the key exists so cleanup can erase the
+ * committed key even if a check below fails. The getter only reads a
+ * field, but its result gates the NVM cleanup, so check it too. */
+ if (ret == 0) {
+ keyIdRet = wh_Client_LmsGetKeyId(&key, &keyId);
+ }
+
+ if (benchStartRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StartOp %d\n", benchStartRet);
+ ret = benchStartRet;
+ break;
+ }
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_MakeKey %d\n", ret);
+ break;
+ }
+ if (keyIdRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Client_LmsGetKeyId %d\n", keyIdRet);
+ ret = keyIdRet;
+ break;
+ }
+ if (benchStopRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StopOp %d\n", benchStopRet);
+ ret = benchStopRet;
+ break;
+ }
+
+ /* Erase the committed key from cache + NVM before the next iteration */
+ if (!WH_KEYID_ISERASED(keyId)) {
+ int eraseRet = wh_Client_KeyErase(client, keyId);
+ if (eraseRet != 0) {
+ WH_BENCH_PRINTF("Failed to erase key %d\n", eraseRet);
+ ret = eraseRet;
+ break;
+ }
+ keyId = WH_KEYID_ERASED;
+ }
+
+ /* Free the key after each iteration */
+ wc_LmsKey_Free(&key);
+ initialized_key = 0;
+ }
+
+ /* Clean up resources */
+ if (initialized_key) {
+ wc_LmsKey_Free(&key);
+ }
+ if (initialized_rng) {
+ wc_FreeRng(rng);
+ }
+
+ /* Erase a key left committed by a mid-iteration failure */
+ if (!WH_KEYID_ISERASED(keyId)) {
+ int eraseRet = wh_Client_KeyErase(client, keyId);
+ if ((eraseRet != 0) && (ret == 0)) {
+ ret = eraseRet;
+ }
+ }
+
+ return ret;
+}
+
+/* Helper function for LMS sign benchmark */
+static int _benchLmsSign(whClientContext* client, whBenchOpContext* ctx, int id)
+{
+ int ret = 0;
+ LmsKey key;
+ WC_RNG rng[1] = {0};
+ const byte msg[] = WH_BENCH_LMS_MSG;
+ const word32 msgSz = (word32)(sizeof(msg) - 1);
+ word32 sigSz = 0;
+ int i;
+ int iters = WOLFHSM_CFG_BENCH_PK_ITERS;
+ int initialized_rng = 0;
+ int initialized_key = 0;
+ whKeyId keyId = WH_KEYID_ERASED;
+
+ (void)wh_Client_SetDmaMode(client, 1);
+
+ /* Initialize the RNG */
+ ret = wc_InitRng_ex(rng, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_InitRng_ex %d\n", ret);
+ goto exit;
+ }
+ initialized_rng = 1;
+
+ /* Initialize the LMS key */
+ ret = wc_LmsKey_Init(&key, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_Init %d\n", ret);
+ goto exit;
+ }
+ initialized_key = 1;
+
+ /* Bind the LMS parameter set */
+ ret = wc_LmsKey_SetParameters(&key, WH_BENCH_LMS_LEVELS,
+ WH_BENCH_LMS_HEIGHT, WH_BENCH_LMS_WINTERNITZ);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_SetParameters %d\n", ret);
+ goto exit;
+ }
+
+ /* Determine the signature length and confirm it fits the buffer */
+ ret = wc_LmsKey_GetSigLen(&key, &sigSz);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_GetSigLen %d\n", ret);
+ goto exit;
+ }
+ if (sigSz > sizeof(g_lmsSigBuf)) {
+ WH_BENCH_PRINTF("LMS sig buffer too small: need=%u have=%u\n",
+ (unsigned)sigSz, (unsigned)sizeof(g_lmsSigBuf));
+ ret = BUFFER_E;
+ goto exit;
+ }
+
+ /* Generate the signing key once (untimed). Keygen commits the key to NVM
+ * on the server, so it is erased during cleanup. */
+ ret = wc_LmsKey_MakeKey(&key, rng);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_MakeKey %d\n", ret);
+ goto exit;
+ }
+ /* Capture the committed key's id so cleanup can erase it. Its result gates
+ * NVM cleanup, so surface a failure rather than leaking the key. */
+ ret = wh_Client_LmsGetKeyId(&key, &keyId);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Client_LmsGetKeyId %d\n", ret);
+ goto exit;
+ }
+
+ /* A fresh key must have signatures available */
+ if (wc_LmsKey_SigsLeft(&key) == 0) {
+ WH_BENCH_PRINTF("LMS reported exhausted on fresh key\n");
+ ret = WH_ERROR_ABORTED;
+ goto exit;
+ }
+
+ /* LMS is stateful: the key holds 2^H one-time signatures. Cap the loop to
+ * that budget so raising the global WOLFHSM_CFG_BENCH_PK_ITERS (shared with
+ * the other PK benchmarks) does not exhaust the key mid-run. */
+ if (iters > (1 << WH_BENCH_LMS_HEIGHT)) {
+ WH_BENCH_PRINTF("LMS sign capped to %d iterations (2^H OTS budget)\n",
+ (1 << WH_BENCH_LMS_HEIGHT));
+ iters = (1 << WH_BENCH_LMS_HEIGHT);
+ }
+
+ /* Benchmark the signing operation. Each sign advances the private state and
+ * commits it to NVM on the server before returning the signature. */
+ for (i = 0; i < iters && ret == 0; i++) {
+ int benchStartRet;
+ int benchStopRet;
+ word32 localSigSz = sigSz;
+
+ /* Time only the sign operation */
+ benchStartRet = wh_Bench_StartOp(ctx, id);
+ ret = wc_LmsKey_Sign(&key, g_lmsSigBuf, &localSigSz, msg, (int)msgSz);
+ benchStopRet = wh_Bench_StopOp(ctx, id);
+
+ if (benchStartRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StartOp %d\n", benchStartRet);
+ ret = benchStartRet;
+ break;
+ }
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_LmsKey_Sign %d\n", ret);
+ break;
+ }
+ if (benchStopRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StopOp %d\n", benchStopRet);
+ ret = benchStopRet;
+ break;
+ }
+ }
+
+exit:
+ /* Clean up resources */
+ if (initialized_key) {
+ wc_LmsKey_Free(&key);
+ }
+ if (initialized_rng) {
+ wc_FreeRng(rng);
+ }
+
+ /* Erase the committed key from cache + NVM */
+ if (!WH_KEYID_ISERASED(keyId)) {
+ int eraseRet = wh_Client_KeyErase(client, keyId);
+ if ((eraseRet != 0) && (ret == 0)) {
+ ret = eraseRet;
+ }
+ }
+
+ return ret;
+}
+
+#endif /* !WOLFSSL_LMS_VERIFY_ONLY */
+
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS */
+
+/* Public benchmark module functions for LMS */
+int wh_Bench_Mod_LmsKeyGen(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params)
+{
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) && \
+ !defined(WOLFSSL_LMS_VERIFY_ONLY)
+ (void)params;
+ return _benchLmsKeyGen(client, ctx, id);
+#else
+ (void)client;
+ (void)ctx;
+ (void)id;
+ (void)params;
+ return WH_ERROR_NOTIMPL;
+#endif
+}
+
+int wh_Bench_Mod_LmsSign(whClientContext* client, whBenchOpContext* ctx, int id,
+ void* params)
+{
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) && \
+ !defined(WOLFSSL_LMS_VERIFY_ONLY)
+ (void)params;
+ return _benchLmsSign(client, ctx, id);
+#else
+ (void)client;
+ (void)ctx;
+ (void)id;
+ (void)params;
+ return WH_ERROR_NOTIMPL;
+#endif
+}
+
+int wh_Bench_Mod_LmsVerify(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params)
+{
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS)
+ (void)params;
+ return _benchLmsVerify(client, ctx, id);
+#else
+ (void)client;
+ (void)ctx;
+ (void)id;
+ (void)params;
+ return WH_ERROR_NOTIMPL;
+#endif
+}
+
+#endif /* !WOLFHSM_CFG_NO_CRYPTO && WOLFHSM_CFG_BENCH_ENABLE */
diff --git a/benchmark/bench_modules/wh_bench_mod_xmss.c b/benchmark/bench_modules/wh_bench_mod_xmss.c
new file mode 100644
index 000000000..eb61b07d3
--- /dev/null
+++ b/benchmark/bench_modules/wh_bench_mod_xmss.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) 2026 wolfSSL Inc.
+ *
+ * This file is part of wolfHSM.
+ *
+ * wolfHSM is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfHSM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wolfHSM. If not, see .
+ */
+#include "wh_bench_mod.h"
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_client.h"
+#include "wolfhsm/wh_client_crypto.h"
+
+
+#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_BENCH_ENABLE)
+
+/* XMSS is stateful (hash-based) and is only exposed by wolfHSM over DMA. KEY-GEN
+ * and SIGN need a full (signing) build. VERIFY additionally works in a
+ * verify-only build: it runs against a precomputed public key and signature
+ * (see the vectors below) instead of generating them. The verify path is
+ * therefore guarded only by WOLFSSL_HAVE_XMSS, while keygen/sign additionally
+ * require !WOLFSSL_XMSS_VERIFY_ONLY. */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS)
+
+#include
+#include "wolfssl/wolfcrypt/random.h"
+#include "wolfssl/wolfcrypt/wc_xmss.h"
+
+/*
+ * Timing characteristics of these benchmarks
+ * ------------------------------------------
+ * XMSS is a stateful hash-based signature scheme: each signature consumes one
+ * one-time key and advances the private key state. The operations behave very
+ * differently under timing:
+ *
+ * - VERIFY is state-independent. It recomputes the WOTS+ public key candidate
+ * and walks the H authentication-path nodes to the root, a fixed amount of
+ * work regardless of the signature index. Its per-op time is flat. It runs
+ * against a fixed precomputed (public key, signature) pair, so - unlike
+ * keygen/sign - it is also available in a verify-only build, the config most
+ * likely deployed on a verifying device in the field.
+ *
+ * - SIGN is state-dependent, and - unlike LMS - fast relative to KEY-GEN. The
+ * server persists the full BDS traversal state, so wc_XmssKey_Reload (see
+ * _HandleXmssSignDma in wh_server_crypto.c) restores it cheaply rather than
+ * rebuilding the tree. Each sign then advances the BDS traversal to prepare
+ * the next auth path, and that cost is not uniform across indices: it spikes
+ * when treehash instances complete at subtree boundaries. Measured over
+ * consecutive indices the per-sign latency varies by several times, while
+ * KEY-GEN (which builds the whole tree once) is far slower than either.
+ *
+ * - XMSS has no "sign smoothing" option in wolfCrypt. The BDS worst-case-
+ * reduction parameter k (params->bds_k) is fixed to 0 for every parameter set
+ * (WC_XMSS_MAX_BDS_K == 0 in wc_xmss.h), so there is no build-time way to
+ * flatten the per-signature cost. Signing therefore stays inherently
+ * state-dependent.
+ *
+ * Benchmarking caveats:
+ * - SIGN only exercises the first WOLFHSM_CFG_BENCH_PK_ITERS signature indices,
+ * so the reported average undersamples the more expensive authentication-path
+ * refreshes that occur deeper in the key's lifetime.
+ * - KEY-GEN rebuilds the full 2^10 (1024-leaf) Merkle tree on every iteration,
+ * so it runs WOLFHSM_CFG_BENCH_KG_ITERS full tree builds (~seconds each) and
+ * dominates the wall-clock of a full benchmark run - by far the slowest module
+ * in the suite. Lower WOLFHSM_CFG_BENCH_KG_ITERS to shorten it.
+ */
+
+/* "XMSS-SHA2_10_256" is the smallest standardized XMSS parameter set (height
+ * 10, 2^10 = 1024 signatures, pubLen 68, sigLen 2500). */
+#define WH_BENCH_XMSS_PARAM_STR "XMSS-SHA2_10_256"
+#define WH_BENCH_XMSS_HEIGHT (10)
+
+/* Precomputed public key and signature for the VERIFY benchmark, generated once
+ * with wolfCrypt over WH_BENCH_XMSS_MSG using the parameter set above. Embedding
+ * them lets verify run without keygen/sign, so it is available in a verify-only
+ * build. */
+#define WH_BENCH_XMSS_MSG "Test message for XMSS signing"
+static const byte bench_xmss_sha2_10_256_pub[] = {
+ 0x00, 0x00, 0x00, 0x01, 0xd9, 0xc1, 0xc8, 0xb6, 0xd1, 0x86, 0xc0, 0x05,
+ 0xf3, 0x4f, 0x74, 0x60, 0xe7, 0xfd, 0xe5, 0xf7, 0xb9, 0x34, 0x3f, 0x1d,
+ 0x9e, 0x8e, 0x07, 0xf6, 0x9b, 0xff, 0x44, 0xda, 0xf7, 0x2d, 0x2c, 0x4c,
+ 0xdd, 0x8d, 0xb5, 0x4c, 0xd8, 0x72, 0xe6, 0xa6, 0x8d, 0x54, 0x2f, 0xed,
+ 0x02, 0xb2, 0x0c, 0xcf, 0xa3, 0x4e, 0x3a, 0x8e, 0x96, 0xdd, 0x32, 0xf2,
+ 0x8d, 0x7c, 0x7e, 0x14, 0x87, 0x2a, 0x64, 0x46,
+};
+
+static const byte bench_xmss_sha2_10_256_sig[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x5b, 0x6d, 0x27, 0x4b, 0xd2, 0xe5, 0x24,
+ 0x5c, 0x5a, 0xf3, 0x50, 0x67, 0x97, 0xbc, 0x76, 0x0a, 0x3b, 0x3f, 0x61,
+ 0xf1, 0xd5, 0xac, 0x8c, 0x7e, 0x5e, 0x36, 0xad, 0x9c, 0x8d, 0xf6, 0x7d,
+ 0xb9, 0xa8, 0xeb, 0xd0, 0xf0, 0x38, 0x02, 0xc2, 0xe9, 0xd0, 0x5e, 0x05,
+ 0x35, 0xc2, 0xa5, 0x39, 0xa5, 0xb0, 0x22, 0x60, 0xba, 0x03, 0x39, 0x11,
+ 0x3a, 0xcd, 0x0a, 0x7a, 0xfb, 0x03, 0xcb, 0xe3, 0xf3, 0xdf, 0x3f, 0xae,
+ 0x68, 0x7c, 0xb1, 0xfa, 0xd9, 0x9b, 0xd8, 0x39, 0x34, 0x94, 0xa4, 0x3f,
+ 0x98, 0xf2, 0x27, 0xa7, 0xee, 0x72, 0x84, 0x00, 0x97, 0x52, 0x0a, 0xec,
+ 0x55, 0xf0, 0x25, 0x32, 0x0f, 0x0b, 0x7a, 0x8f, 0xef, 0x36, 0x6f, 0xbb,
+ 0xc6, 0x0f, 0xa9, 0x19, 0x2f, 0xfc, 0x8a, 0xd7, 0x5b, 0xaa, 0xbc, 0x01,
+ 0x1e, 0x41, 0x45, 0xe2, 0x9f, 0x79, 0xd2, 0x92, 0xbc, 0x86, 0x6f, 0x6a,
+ 0x68, 0x56, 0xa0, 0x9a, 0x4c, 0x4e, 0x65, 0x33, 0xe5, 0x61, 0x81, 0x91,
+ 0xfe, 0x50, 0x49, 0xea, 0xf1, 0x7f, 0x77, 0x8e, 0x25, 0x2c, 0x1c, 0x63,
+ 0x4c, 0xd7, 0xb4, 0xaf, 0x62, 0x80, 0xe3, 0x05, 0xb4, 0x88, 0xf5, 0x9e,
+ 0x2b, 0x4b, 0xea, 0xf5, 0xa9, 0xbe, 0x80, 0xf7, 0xa0, 0x46, 0xa2, 0xa4,
+ 0x39, 0xd6, 0xd5, 0x70, 0x1d, 0xb3, 0x55, 0x53, 0xba, 0x94, 0x8d, 0xa7,
+ 0x71, 0x3f, 0x41, 0x76, 0x67, 0x7f, 0x30, 0x8c, 0xd7, 0x76, 0x76, 0xba,
+ 0xcf, 0x60, 0xa0, 0x73, 0x25, 0xd5, 0x73, 0x65, 0xdc, 0x79, 0x67, 0xd8,
+ 0x53, 0x93, 0x55, 0x3f, 0xd2, 0x61, 0x6e, 0x00, 0x17, 0x5a, 0x8e, 0x91,
+ 0xc0, 0x76, 0xcc, 0xea, 0xfc, 0x4c, 0xd6, 0x67, 0xe4, 0x8d, 0x34, 0x35,
+ 0x89, 0x8a, 0xc9, 0x6c, 0x4b, 0x16, 0x7c, 0x04, 0xdf, 0x7e, 0x0e, 0x52,
+ 0x12, 0x50, 0xbd, 0x0d, 0x9b, 0x22, 0xbd, 0xe0, 0x53, 0xa6, 0xeb, 0x8e,
+ 0x2e, 0xbf, 0x1a, 0x69, 0x77, 0xe0, 0x2a, 0xd4, 0x0d, 0x51, 0x25, 0x6e,
+ 0xc6, 0x2d, 0x5a, 0xed, 0x21, 0x22, 0x81, 0x6c, 0x36, 0xe2, 0xbf, 0x89,
+ 0x9f, 0xce, 0xd8, 0x28, 0xcc, 0x1e, 0x9b, 0x68, 0x6a, 0x44, 0x08, 0xc4,
+ 0x8c, 0x0d, 0x48, 0x76, 0xa0, 0xca, 0xfa, 0x49, 0x0b, 0x77, 0x03, 0x35,
+ 0x9d, 0x25, 0xc4, 0x90, 0xc9, 0x7d, 0x7a, 0xff, 0xfa, 0x3b, 0xb6, 0xc8,
+ 0xc7, 0x01, 0xa3, 0x7a, 0x2d, 0xfb, 0x08, 0x0b, 0x59, 0xa7, 0xb3, 0xd8,
+ 0x7e, 0x21, 0x9d, 0xe8, 0xb1, 0xc3, 0x6d, 0x82, 0xba, 0xfe, 0xab, 0x72,
+ 0x3c, 0x5b, 0x6c, 0xe1, 0xa0, 0xf1, 0x32, 0xab, 0x61, 0x99, 0xb6, 0xcd,
+ 0x7a, 0x27, 0x7d, 0x99, 0xe4, 0x00, 0xbe, 0xdc, 0x7e, 0x51, 0x30, 0xa7,
+ 0xf7, 0xa1, 0xfa, 0xe3, 0x17, 0xc1, 0x4f, 0x6f, 0x7b, 0xce, 0x50, 0x5f,
+ 0xc2, 0xb9, 0x49, 0x66, 0xca, 0xe4, 0x91, 0x0f, 0xb1, 0xe1, 0x7c, 0x29,
+ 0x05, 0x17, 0xfe, 0xe3, 0x89, 0xfd, 0x00, 0xf4, 0x05, 0x08, 0xe9, 0xc0,
+ 0x30, 0x37, 0x1c, 0xa0, 0xcf, 0x1c, 0x2d, 0xe7, 0xb6, 0x24, 0x25, 0x39,
+ 0x14, 0xf3, 0xa9, 0xdf, 0xe4, 0x37, 0xb7, 0xd2, 0x6f, 0xd5, 0xee, 0x47,
+ 0x17, 0x6d, 0x1a, 0xb8, 0x98, 0xba, 0x8e, 0x3f, 0x45, 0xb0, 0x40, 0x35,
+ 0x94, 0x93, 0x08, 0x42, 0xb2, 0x4f, 0xff, 0x95, 0x6c, 0x1c, 0xba, 0xbe,
+ 0xa8, 0x24, 0x61, 0x51, 0x07, 0x07, 0xe4, 0x93, 0xd4, 0xce, 0x5a, 0x4a,
+ 0x3b, 0xa7, 0x1b, 0xe8, 0xb0, 0x07, 0x09, 0xc4, 0x9d, 0xd1, 0x8b, 0xcc,
+ 0xd8, 0x33, 0x00, 0x9c, 0x34, 0xbf, 0x71, 0x4f, 0x0f, 0xdc, 0x2d, 0xb3,
+ 0x45, 0xf2, 0x67, 0x70, 0x76, 0xe0, 0x07, 0xc1, 0xc1, 0x9f, 0xfd, 0x6e,
+ 0xba, 0xe2, 0xfe, 0x6f, 0x4f, 0x66, 0x93, 0x87, 0x84, 0x99, 0xd8, 0x08,
+ 0x62, 0xcc, 0x33, 0x75, 0x31, 0x56, 0xcc, 0x48, 0x7b, 0x42, 0xb4, 0xfb,
+ 0xcc, 0x48, 0xaf, 0x97, 0xe1, 0x58, 0x9e, 0x35, 0x65, 0xae, 0x47, 0xb1,
+ 0x6c, 0xcd, 0xb2, 0x9f, 0x94, 0xd3, 0x67, 0x14, 0xb6, 0x33, 0xe4, 0xc0,
+ 0x25, 0x62, 0x6f, 0x37, 0x0e, 0x57, 0x7b, 0x95, 0x34, 0xe0, 0x44, 0x4f,
+ 0x66, 0x25, 0x59, 0xc9, 0x62, 0xa1, 0x83, 0xcf, 0xf0, 0x4e, 0xbb, 0x1e,
+ 0x6c, 0x84, 0x7f, 0xa6, 0x57, 0x08, 0xa7, 0x98, 0x82, 0xb6, 0xb6, 0x19,
+ 0x3f, 0x1e, 0x5b, 0xfb, 0x70, 0x9a, 0x1f, 0x7a, 0xed, 0x83, 0xf9, 0x03,
+ 0x15, 0x2a, 0x15, 0x3e, 0x5c, 0xc1, 0x46, 0x1d, 0xcc, 0xa5, 0xf6, 0x7e,
+ 0x22, 0x24, 0xb3, 0x4e, 0xda, 0x18, 0x13, 0xe9, 0xf0, 0x97, 0x5d, 0x3c,
+ 0xda, 0x67, 0xec, 0x8d, 0x88, 0x01, 0xec, 0x76, 0x83, 0xc6, 0x1f, 0xe1,
+ 0x1e, 0x5a, 0x35, 0xf9, 0x39, 0x52, 0x8c, 0x0e, 0xc9, 0x19, 0x6c, 0x48,
+ 0x3d, 0x4e, 0x8b, 0xb5, 0xfa, 0x04, 0x0e, 0x3f, 0x26, 0x5e, 0x10, 0x04,
+ 0x62, 0xd1, 0x63, 0xd9, 0xf2, 0xa0, 0x32, 0x22, 0x17, 0x82, 0x28, 0x09,
+ 0xac, 0xe0, 0xd5, 0x07, 0xdb, 0x31, 0x22, 0xe4, 0x70, 0x8b, 0x7c, 0x62,
+ 0x05, 0x66, 0x75, 0x65, 0xfc, 0xa5, 0xcb, 0x21, 0xa6, 0x53, 0xca, 0x1a,
+ 0x16, 0x5f, 0x02, 0xd2, 0x72, 0xde, 0x10, 0x6d, 0xda, 0x16, 0x86, 0xfc,
+ 0x4e, 0x24, 0xa8, 0x03, 0x87, 0xd8, 0xf9, 0x65, 0xbf, 0xa8, 0x2a, 0x31,
+ 0xf1, 0xeb, 0xb4, 0xee, 0x4c, 0xb5, 0x00, 0xde, 0x60, 0x44, 0x2a, 0x58,
+ 0x92, 0x7b, 0x3c, 0x2c, 0xf1, 0x95, 0x37, 0xd6, 0x5e, 0x72, 0xd9, 0x6e,
+ 0xd8, 0x76, 0x18, 0x45, 0x3a, 0xbf, 0xde, 0xf2, 0x50, 0xaa, 0x94, 0x78,
+ 0xf8, 0xcb, 0x2c, 0xe3, 0xa3, 0x08, 0x08, 0xc4, 0x99, 0x6e, 0xaf, 0x7f,
+ 0x04, 0xa1, 0x0e, 0x31, 0xa1, 0x21, 0x12, 0x48, 0x82, 0xac, 0x5b, 0x10,
+ 0xc8, 0x31, 0x99, 0xb4, 0x65, 0xf8, 0x57, 0x55, 0x91, 0x79, 0x56, 0x12,
+ 0x96, 0xb0, 0xc5, 0x55, 0x55, 0xc5, 0xff, 0x90, 0xfd, 0x66, 0x25, 0x33,
+ 0x49, 0x15, 0xb2, 0x0d, 0xba, 0xc2, 0xf7, 0xc8, 0x57, 0x16, 0x86, 0xf7,
+ 0xa8, 0x7b, 0x43, 0x6c, 0xdc, 0x7e, 0xed, 0xf8, 0x7a, 0x7b, 0xda, 0x8d,
+ 0x70, 0xe7, 0x81, 0x7d, 0xec, 0x9d, 0xc5, 0x9c, 0xf9, 0x26, 0x84, 0x93,
+ 0xbc, 0x80, 0x06, 0x88, 0xe5, 0xc1, 0x4b, 0xc5, 0x54, 0x05, 0x9c, 0xc5,
+ 0xea, 0x5e, 0x1d, 0x24, 0x0d, 0x1d, 0xde, 0xc2, 0xdd, 0x5d, 0x8f, 0x61,
+ 0xe0, 0x39, 0x65, 0xd4, 0x13, 0x21, 0x21, 0x0e, 0x7e, 0x16, 0x54, 0xee,
+ 0x0c, 0x6b, 0xcb, 0xff, 0x28, 0x66, 0xa1, 0x63, 0xe5, 0x84, 0x1d, 0x0b,
+ 0xa6, 0x59, 0x94, 0x28, 0x50, 0x54, 0xc4, 0x92, 0xae, 0x18, 0xb0, 0x1c,
+ 0xf2, 0xc8, 0x12, 0xf5, 0x62, 0x46, 0x5e, 0xc8, 0xa6, 0x3f, 0x09, 0x89,
+ 0x02, 0x86, 0x1a, 0x3c, 0x84, 0x1b, 0x6e, 0xd3, 0x58, 0xd7, 0x41, 0xf8,
+ 0x3d, 0x75, 0x2a, 0x23, 0xcd, 0x33, 0xa0, 0x7d, 0xd9, 0x51, 0x5d, 0x5f,
+ 0xe0, 0xc2, 0x94, 0x4c, 0x23, 0x13, 0xc7, 0xb4, 0xc7, 0xad, 0x8c, 0x33,
+ 0x61, 0x0a, 0xbb, 0x99, 0xc0, 0x06, 0xe0, 0x13, 0x4e, 0x60, 0x65, 0xb5,
+ 0x2f, 0xdf, 0xbf, 0x03, 0x37, 0x65, 0xa8, 0x07, 0x0e, 0x62, 0x94, 0xdc,
+ 0x94, 0xfa, 0xe0, 0xe4, 0xe5, 0xf3, 0x2b, 0x92, 0x78, 0x84, 0x7f, 0x96,
+ 0x51, 0x6f, 0x65, 0xe9, 0x79, 0xc3, 0xbb, 0x81, 0xe3, 0xe6, 0x56, 0xeb,
+ 0x9d, 0x99, 0x1f, 0x29, 0x9c, 0x82, 0x37, 0x5a, 0x5a, 0xd6, 0x54, 0xce,
+ 0xca, 0x88, 0x6a, 0x46, 0x2d, 0x3d, 0x50, 0xbe, 0x99, 0x0e, 0x5d, 0x85,
+ 0xb1, 0x0b, 0xa5, 0x7b, 0x73, 0x05, 0xac, 0x0a, 0x51, 0x6a, 0xe9, 0x7b,
+ 0xb0, 0xed, 0x77, 0x14, 0xa6, 0xaa, 0xf4, 0xd0, 0xc9, 0x45, 0xb1, 0x9a,
+ 0x41, 0xf8, 0xb2, 0x0b, 0x58, 0xf1, 0xdc, 0x55, 0xa3, 0xa3, 0xeb, 0xd5,
+ 0x2d, 0x43, 0x1c, 0xae, 0xce, 0x78, 0xfe, 0x10, 0x81, 0xd2, 0xf0, 0x70,
+ 0x37, 0x94, 0xb5, 0x9d, 0x64, 0xad, 0xa0, 0x39, 0xf9, 0x45, 0xbc, 0xc4,
+ 0xc6, 0x8f, 0x79, 0x3b, 0x8c, 0xf9, 0x54, 0x3c, 0xbd, 0x5f, 0x3a, 0x88,
+ 0x74, 0x04, 0x10, 0x4c, 0x75, 0x42, 0x8e, 0x42, 0xf0, 0x85, 0x1c, 0xa9,
+ 0x45, 0xc6, 0x74, 0xd3, 0x25, 0x9c, 0x1d, 0xfa, 0x9a, 0x3d, 0x3c, 0xd8,
+ 0x82, 0x81, 0x01, 0xbf, 0xbc, 0x7e, 0xda, 0x08, 0x55, 0x21, 0xac, 0x6d,
+ 0xca, 0x1e, 0x2b, 0x98, 0xf9, 0xf7, 0xe3, 0xfc, 0x20, 0x8b, 0x61, 0xaf,
+ 0x2b, 0x6e, 0x4b, 0x98, 0xe5, 0x8d, 0x1d, 0x8e, 0x3e, 0xc3, 0xbb, 0x37,
+ 0xfe, 0x99, 0xcf, 0xdf, 0x3b, 0xc2, 0xb9, 0x44, 0x76, 0x26, 0x50, 0x63,
+ 0x17, 0x49, 0xbc, 0x48, 0xf0, 0x26, 0x09, 0x50, 0x33, 0x1a, 0x75, 0xb0,
+ 0xae, 0x2a, 0x19, 0x86, 0xcb, 0xf4, 0x69, 0x60, 0xb7, 0x01, 0xe5, 0x61,
+ 0x59, 0xa7, 0xa0, 0x3d, 0xfb, 0x4e, 0x28, 0x1f, 0x82, 0x31, 0x8a, 0xd5,
+ 0x4b, 0x2e, 0x78, 0x58, 0x0d, 0x7f, 0x72, 0xdd, 0x87, 0x7e, 0xfa, 0x07,
+ 0xcb, 0xac, 0x6e, 0xd4, 0x13, 0x13, 0x32, 0x92, 0x5c, 0x3b, 0xce, 0x25,
+ 0x2f, 0xed, 0x24, 0x92, 0x38, 0xc4, 0x86, 0x5e, 0xd8, 0x58, 0x3e, 0x29,
+ 0x34, 0x23, 0x8a, 0x9f, 0xe4, 0x33, 0x95, 0x36, 0x6d, 0xfe, 0x74, 0x81,
+ 0xd9, 0xa4, 0x88, 0x64, 0x50, 0x7d, 0x14, 0xb3, 0x4c, 0x61, 0x48, 0xac,
+ 0x2c, 0xd7, 0x81, 0x8d, 0x57, 0x16, 0xb8, 0xb0, 0x94, 0x84, 0xb2, 0x1f,
+ 0xe6, 0x38, 0x52, 0x89, 0xc1, 0xae, 0xf9, 0x7d, 0x28, 0x79, 0x2e, 0x05,
+ 0xa3, 0x52, 0xb5, 0x5b, 0xf8, 0xc9, 0xbe, 0xc2, 0xb9, 0xe1, 0x8b, 0xb2,
+ 0x77, 0xb2, 0xea, 0x20, 0xc7, 0x79, 0x28, 0x63, 0xea, 0x7f, 0x89, 0xcc,
+ 0x3c, 0xac, 0x6e, 0x05, 0x0c, 0xe1, 0xcf, 0x0c, 0xaf, 0x9a, 0xfc, 0x64,
+ 0x80, 0xff, 0x03, 0x8d, 0x02, 0xfe, 0x61, 0xa5, 0xaf, 0x17, 0xc7, 0x05,
+ 0x3c, 0x03, 0x4b, 0xa5, 0x0c, 0x5c, 0x9b, 0x20, 0x6a, 0x82, 0x5c, 0x91,
+ 0x09, 0xd0, 0x2a, 0xcc, 0x39, 0xca, 0x30, 0xef, 0x8c, 0x1b, 0x9b, 0xf3,
+ 0xc6, 0x29, 0xd5, 0xd9, 0xbf, 0xb7, 0xb7, 0x0c, 0x14, 0x80, 0x1b, 0xbd,
+ 0x3a, 0x0b, 0xb8, 0x33, 0x72, 0x41, 0x47, 0x51, 0x3a, 0xda, 0x00, 0xac,
+ 0xfe, 0x63, 0xad, 0xf1, 0x59, 0x50, 0xc5, 0xdf, 0x4e, 0x28, 0xed, 0x2c,
+ 0x11, 0x40, 0x39, 0xdd, 0x65, 0x70, 0x7f, 0x60, 0xf9, 0x6a, 0x4a, 0x3d,
+ 0xc0, 0xab, 0x28, 0xd4, 0xd8, 0x2f, 0xe9, 0x8b, 0x54, 0x8b, 0x4f, 0xef,
+ 0xc9, 0x01, 0x47, 0x63, 0x5e, 0x1b, 0x70, 0xcc, 0x64, 0x31, 0x77, 0x7d,
+ 0x3f, 0x4d, 0x83, 0xaf, 0x50, 0x37, 0x4d, 0xda, 0xc5, 0x6c, 0xe3, 0xdf,
+ 0xa5, 0xc6, 0xcc, 0x0b, 0x6c, 0x5c, 0xf9, 0x87, 0x1a, 0x18, 0xa9, 0xf3,
+ 0x15, 0x77, 0x0e, 0x95, 0x63, 0x77, 0x5b, 0x34, 0x0e, 0xee, 0x75, 0x99,
+ 0xd4, 0xc3, 0x3a, 0xe3, 0xf2, 0xaf, 0x28, 0x39, 0x40, 0x00, 0x0a, 0x9f,
+ 0x1e, 0x6f, 0xb0, 0x9a, 0x96, 0xeb, 0xf4, 0xf0, 0x5b, 0x75, 0x34, 0x3d,
+ 0xcf, 0xd6, 0x5b, 0xcb, 0x8e, 0x45, 0x46, 0x1e, 0x73, 0xb0, 0x5e, 0x7d,
+ 0xad, 0xf1, 0xff, 0x09, 0xb2, 0xc4, 0xb7, 0x8a, 0xd7, 0x8e, 0x87, 0xbf,
+ 0xc5, 0xcb, 0x56, 0xac, 0x70, 0x89, 0xe4, 0xe0, 0x90, 0x46, 0xd6, 0xbd,
+ 0x9b, 0x57, 0x7d, 0xeb, 0x05, 0x58, 0xf5, 0x02, 0x15, 0xc2, 0xa3, 0x4a,
+ 0x76, 0xec, 0x2c, 0x18, 0x88, 0x77, 0x1d, 0xb7, 0x2b, 0x6d, 0x51, 0xf0,
+ 0x62, 0x17, 0x29, 0x23, 0x87, 0xc5, 0xea, 0x96, 0xac, 0xa8, 0x84, 0x15,
+ 0x28, 0x0a, 0x14, 0x04, 0xc3, 0x69, 0x34, 0xd7, 0x9d, 0x8e, 0xe2, 0x62,
+ 0xf1, 0xe3, 0x74, 0x4e, 0x27, 0x87, 0xd5, 0x49, 0xd4, 0x63, 0x24, 0xd2,
+ 0xa6, 0xfe, 0xd5, 0xc5, 0x5b, 0x45, 0x80, 0xe7, 0xde, 0x63, 0xc7, 0x9f,
+ 0x81, 0x2b, 0xe9, 0xf3, 0xe0, 0x37, 0xa1, 0x1f, 0x10, 0x5c, 0xc3, 0x98,
+ 0xbf, 0x17, 0xcd, 0x04, 0x6b, 0x78, 0xd8, 0x02, 0x50, 0x5d, 0xe7, 0x17,
+ 0x63, 0x6a, 0xbf, 0x6b, 0xf8, 0x56, 0x56, 0xa9, 0x8e, 0xd8, 0x08, 0x00,
+ 0x73, 0x0d, 0xe3, 0xe5, 0x8d, 0x82, 0x22, 0xc7, 0xe6, 0xc9, 0x07, 0xff,
+ 0x21, 0x1d, 0x08, 0xc6, 0xc8, 0xa8, 0x6a, 0xb8, 0x71, 0x65, 0x37, 0x81,
+ 0xb1, 0x0b, 0x10, 0x9e, 0xc4, 0x81, 0xe0, 0x9a, 0x86, 0x2c, 0xcd, 0x59,
+ 0xff, 0xbf, 0x4c, 0xb7, 0x8f, 0x8e, 0x82, 0xd1, 0xf7, 0xc6, 0x87, 0x71,
+ 0x2e, 0x9d, 0xbf, 0x70, 0xf5, 0xa7, 0xa1, 0xd3, 0xd9, 0xd8, 0x23, 0x97,
+ 0xf8, 0xb1, 0xcc, 0x1d, 0xf8, 0xdc, 0x76, 0x86, 0xa5, 0xe5, 0x74, 0xa3,
+ 0x68, 0xc5, 0xd7, 0x61, 0x4d, 0x6f, 0xd9, 0x04, 0x5f, 0xbe, 0xfd, 0x90,
+ 0xa8, 0x83, 0x31, 0xc2, 0xf5, 0x40, 0xdf, 0xbe, 0x2f, 0x36, 0xa3, 0x1c,
+ 0xaf, 0xc3, 0xbf, 0x00, 0xd2, 0xe0, 0xa4, 0xda, 0xfa, 0x01, 0x11, 0x1b,
+ 0xc3, 0xc5, 0xd0, 0x5c, 0xba, 0x36, 0x64, 0xd6, 0x29, 0x60, 0x61, 0x8f,
+ 0x16, 0xc1, 0xc1, 0x0f, 0xc8, 0x4c, 0xdf, 0x39, 0x6c, 0x7a, 0xea, 0x5d,
+ 0x52, 0xd6, 0xb8, 0x50, 0x38, 0xd8, 0x9a, 0x95, 0x60, 0x9b, 0x78, 0x76,
+ 0xf0, 0xab, 0x44, 0x7b, 0x46, 0x0e, 0x74, 0x96, 0x2e, 0x2a, 0x11, 0xcd,
+ 0x03, 0x6f, 0x87, 0x81, 0x07, 0x74, 0xed, 0x36, 0x02, 0x28, 0x79, 0x99,
+ 0xfa, 0x49, 0xb1, 0x83, 0x29, 0xec, 0x1a, 0x38, 0xe3, 0xb4, 0x00, 0x58,
+ 0x79, 0xe0, 0x72, 0x39, 0x62, 0xe7, 0xce, 0x1e, 0xeb, 0x86, 0x28, 0xad,
+ 0x8f, 0x9a, 0xba, 0xee, 0x1d, 0xf0, 0xc0, 0x45, 0x75, 0x05, 0xba, 0xd4,
+ 0x81, 0xf5, 0x10, 0x2f, 0x77, 0x84, 0xb3, 0x67, 0x70, 0x7b, 0xc7, 0x84,
+ 0xff, 0xe3, 0xd5, 0xf8, 0x98, 0xe7, 0x6e, 0x21, 0x4e, 0x98, 0xd6, 0x4d,
+ 0xcf, 0xad, 0x3a, 0x4e, 0x7d, 0xa4, 0x0c, 0x5e, 0x38, 0xef, 0x41, 0xa2,
+ 0x05, 0xa8, 0xe6, 0xcf, 0xb5, 0xdc, 0x2b, 0xeb, 0xd6, 0x37, 0x05, 0x5a,
+ 0xf1, 0xdc, 0xc9, 0x14, 0x21, 0x33, 0x85, 0xd4, 0x2d, 0x50, 0x86, 0x3d,
+ 0x25, 0x88, 0x6e, 0x21, 0x67, 0xcf, 0x7b, 0xea, 0xd4, 0xa3, 0x37, 0xd1,
+ 0x77, 0xc2, 0x4b, 0xe9, 0x0f, 0xc3, 0x78, 0xff, 0x83, 0x9b, 0xbe, 0x42,
+ 0x82, 0xef, 0x7c, 0x79, 0xcd, 0x1d, 0x68, 0x95, 0xc9, 0xbc, 0x19, 0x22,
+ 0x2f, 0x9f, 0x6f, 0x29, 0xc6, 0xca, 0x85, 0x98, 0x8e, 0xe4, 0xa8, 0x11,
+ 0xc2, 0x8b, 0x73, 0x63, 0x8f, 0xae, 0xe2, 0x97, 0xf6, 0x38, 0xe1, 0x95,
+ 0xc5, 0xb8, 0xef, 0xee, 0x56, 0xf5, 0xd7, 0xe4, 0x82, 0x91, 0x0b, 0xc4,
+ 0x48, 0x8c, 0x74, 0xe2, 0x34, 0x6b, 0xc1, 0x6b, 0x70, 0xa6, 0x98, 0xcb,
+ 0x21, 0xc4, 0x45, 0xbf, 0x9a, 0x4f, 0xe5, 0x0f, 0x5a, 0x7a, 0x17, 0x91,
+ 0xee, 0xf9, 0x6d, 0xb1, 0x35, 0xc3, 0x4e, 0x82, 0xf5, 0xf4, 0x8c, 0xca,
+ 0x21, 0x4a, 0x37, 0x35, 0xae, 0xf2, 0x0f, 0x6d, 0x5d, 0xe5, 0x63, 0xe6,
+ 0x9a, 0x61, 0x80, 0x36, 0x54, 0x3f, 0x28, 0x97, 0x20, 0x72, 0x31, 0x14,
+ 0xc7, 0x47, 0x46, 0x49, 0x29, 0xb9, 0x80, 0x38, 0x72, 0xc3, 0x08, 0x0a,
+ 0x87, 0xc6, 0x64, 0x4b, 0xd6, 0x1a, 0xd0, 0xcb, 0xb6, 0x2c, 0x9b, 0xc5,
+ 0x4a, 0x4e, 0x1d, 0xc6, 0x71, 0x6e, 0xc2, 0x31, 0x8c, 0xa4, 0xdb, 0xbd,
+ 0x98, 0xe6, 0xb1, 0xfa, 0x8d, 0x64, 0x4e, 0xb9, 0x2d, 0x99, 0xff, 0x00,
+ 0xc5, 0xd0, 0x8d, 0x81, 0x45, 0xd7, 0x01, 0x24, 0x4a, 0xc2, 0x88, 0x4f,
+ 0x7a, 0xff, 0xef, 0x7a, 0x12, 0xe1, 0xfa, 0x43, 0x78, 0x0c, 0x92, 0x2e,
+ 0xba, 0xf8, 0xce, 0x32, 0x9c, 0xde, 0xb3, 0x08, 0xa6, 0xed, 0x6c, 0x51,
+ 0xa6, 0x32, 0x05, 0x0a, 0x6a, 0x1b, 0xd6, 0xc8, 0x16, 0x5e, 0x2b, 0x75,
+ 0xf4, 0x67, 0xd9, 0x9c, 0x0b, 0x7e, 0xb5, 0x90, 0x5d, 0xd8, 0xe8, 0x38,
+ 0xbf, 0x7c, 0xff, 0xd7, 0xab, 0xba, 0x66, 0x06, 0x9a, 0x87, 0xd6, 0xe6,
+ 0xa7, 0x78, 0x54, 0x93, 0xfe, 0xd6, 0x8f, 0x47, 0x0c, 0x82, 0x13, 0x1c,
+ 0x26, 0x49, 0x69, 0x70, 0x5d, 0x0f, 0xdd, 0x84, 0x6d, 0x55, 0x88, 0x2d,
+ 0x67, 0xbe, 0x2a, 0x11, 0x13, 0xb3, 0xdc, 0xa0, 0xa7, 0xce, 0x49, 0x4a,
+ 0x72, 0x58, 0xa3, 0xec, 0x7c, 0xa8, 0xa5, 0x98, 0xeb, 0x30, 0x0b, 0xd9,
+ 0x6a, 0xb0, 0xdc, 0x64, 0x44, 0xe5, 0x21, 0x96, 0xa4, 0xbb, 0xc4, 0x66,
+ 0x31, 0xba, 0xce, 0x2b, 0xa4, 0x76, 0x76, 0x5e, 0x84, 0x08, 0xc9, 0x2c,
+ 0xdc, 0x55, 0x8f, 0x1d, 0xb9, 0xdc, 0xa3, 0x4e, 0xb1, 0x1c, 0xba, 0x7d,
+ 0xa1, 0x0a, 0x40, 0xae, 0x29, 0xb0, 0x6b, 0xe6, 0xa8, 0xa7, 0x93, 0xc9,
+ 0x15, 0xb8, 0x53, 0x2f, 0x5f, 0xd7, 0xc7, 0x0b, 0x2d, 0x25, 0xdd, 0xd0,
+ 0x0c, 0x2d, 0xc0, 0x12, 0xfa, 0x5a, 0x05, 0xe0, 0xda, 0xfc, 0x42, 0x78,
+ 0x1d, 0xc7, 0xe5, 0x08, 0x10, 0xae, 0x51, 0xf0, 0xd3, 0x7f, 0xac, 0x90,
+ 0xa7, 0xc1, 0xdb, 0x3a, 0xd0, 0x7f, 0x0a, 0xd7, 0x89, 0x74, 0x9e, 0x0a,
+ 0x0d, 0xc0, 0x98, 0x08, 0x7c, 0x5e, 0x06, 0xf8, 0x5b, 0x3f, 0xb1, 0xf8,
+ 0xdb, 0xf3, 0xab, 0x91, 0x50, 0x33, 0xdd, 0x50, 0xc8, 0x3a, 0xd8, 0xb4,
+ 0x93, 0x44, 0x29, 0x5d, 0xf2, 0xd3, 0x97, 0x6e, 0xd5, 0xb5, 0x93, 0x2f,
+ 0xde, 0xa9, 0xcb, 0x8e, 0x0f, 0xe3, 0xd5, 0x5a, 0x00, 0x3a, 0x7b, 0xdb,
+ 0x79, 0xb2, 0x16, 0x48, 0x5c, 0x7f, 0xcf, 0x08, 0xac, 0xa8, 0x6c, 0x41,
+ 0x6e, 0x43, 0x85, 0x4c, 0x92, 0xb2, 0x93, 0x18, 0xd4, 0xda, 0xf2, 0x5e,
+ 0x73, 0xf8, 0xaf, 0x11, 0xe0, 0xf2, 0xf6, 0x98, 0x30, 0xea, 0x04, 0xc7,
+ 0x7c, 0x9f, 0xe5, 0x66, 0x18, 0x55, 0x41, 0x47, 0x0b, 0x90, 0xeb, 0xc7,
+ 0x59, 0xa0, 0xfe, 0x48, 0x1d, 0xf2, 0x90, 0x37, 0xac, 0xff, 0x42, 0xb3,
+ 0xab, 0xde, 0x11, 0x69, 0xa8, 0xaa, 0xeb, 0xc4, 0x4b, 0x80, 0x75, 0xd6,
+ 0x59, 0xad, 0x86, 0x4e, 0x44, 0xae, 0xda, 0xab, 0x2f, 0xc2, 0x36, 0x60,
+ 0x7d, 0xf1, 0x33, 0x27, 0xdc, 0x39, 0x9b, 0x97, 0x19, 0x1b, 0x71, 0x0e,
+ 0xca, 0x50, 0x2c, 0xd0, 0xa0, 0x4d, 0xe7, 0xbd, 0x02, 0xb7, 0x5a, 0x17,
+ 0x40, 0x22, 0x77, 0xaa, 0xc1, 0x8c, 0x2b, 0x0e, 0xf2, 0x6f, 0xcf, 0x95,
+ 0xf3, 0x21, 0xdd, 0x0f, 0x7e, 0x0f, 0x62, 0x9f, 0x9b, 0xb2, 0xb8, 0xad,
+ 0x82, 0x18, 0x42, 0x47, 0x73, 0x7b, 0x16, 0xda, 0xbb, 0x86, 0xd5, 0x1c,
+ 0xd7, 0xcf, 0x74, 0x43, 0xed, 0x87, 0xa1, 0xf0, 0x3a, 0xe7, 0x24, 0x16,
+ 0xfa, 0x53, 0xf6, 0xc7,
+};
+
+
+/* Helper function for XMSS verify benchmark. Loads the precomputed public key
+ * into the HSM cache (ephemeral, verify-only) and times wc_XmssKey_Verify over
+ * the fixed signature. No keygen/sign, so this runs in verify-only builds. */
+static int _benchXmssVerify(whClientContext* client, whBenchOpContext* ctx,
+ int id)
+{
+ int ret = 0;
+ XmssKey key;
+ const byte msg[] = WH_BENCH_XMSS_MSG;
+ const word32 msgSz = (word32)(sizeof(msg) - 1);
+ int i;
+ int initialized_key = 0;
+ whKeyId keyId = WH_KEYID_ERASED;
+ char keyLabel[] = "bench-xmss-verify-key";
+
+ (void)wh_Client_SetDmaMode(client, 1);
+
+ /* Initialize the XMSS key */
+ ret = wc_XmssKey_Init(&key, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_Init %d\n", ret);
+ goto exit;
+ }
+ initialized_key = 1;
+
+ /* Bind the parameter string (required before importing the public key) */
+ ret = wc_XmssKey_SetParamStr(&key, WH_BENCH_XMSS_PARAM_STR);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_SetParamStr %d\n", ret);
+ goto exit;
+ }
+
+ /* Load the precomputed public key into the wolfCrypt structure */
+ ret = wc_XmssKey_ImportPubRaw(&key, bench_xmss_sha2_10_256_pub,
+ (word32)sizeof(bench_xmss_sha2_10_256_pub));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_ImportPubRaw %d\n", ret);
+ goto exit;
+ }
+
+ /* Provision the verify-only public key into the HSM cache. EPHEMERAL keeps
+ * it out of NVM; it is evicted during cleanup. */
+ ret = wh_Client_XmssImportPubKey(client, &key, &keyId,
+ WH_NVM_FLAGS_EPHEMERAL,
+ (uint16_t)strlen(keyLabel),
+ (uint8_t*)keyLabel);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Client_XmssImportPubKey %d\n", ret);
+ goto exit;
+ }
+
+ /* Set key ID */
+ ret = wh_Client_XmssSetKeyId(&key, keyId);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Client_XmssSetKeyId %d\n", ret);
+ goto exit;
+ }
+
+ /* Benchmark the verification operation over the fixed valid signature */
+ for (i = 0; i < WOLFHSM_CFG_BENCH_PK_ITERS && ret == 0; i++) {
+ int benchStartRet;
+ int benchStopRet;
+
+ /* Time only the verify operation */
+ benchStartRet = wh_Bench_StartOp(ctx, id);
+ ret = wc_XmssKey_Verify(&key, bench_xmss_sha2_10_256_sig,
+ (word32)sizeof(bench_xmss_sha2_10_256_sig), msg,
+ (int)msgSz);
+ benchStopRet = wh_Bench_StopOp(ctx, id);
+
+ if (benchStartRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StartOp %d\n", benchStartRet);
+ ret = benchStartRet;
+ break;
+ }
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_Verify %d\n", ret);
+ break;
+ }
+ if (benchStopRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StopOp %d\n", benchStopRet);
+ ret = benchStopRet;
+ break;
+ }
+ }
+
+exit:
+ /* Clean up resources */
+ if (initialized_key) {
+ wc_XmssKey_Free(&key);
+ }
+
+ /* Evict the cached verify-only public key */
+ if (!WH_KEYID_ISERASED(keyId)) {
+ int evictRet = wh_Client_KeyEvict(client, keyId);
+ if ((evictRet != 0) && (ret == 0)) {
+ ret = evictRet;
+ }
+ }
+
+ return ret;
+}
+
+#if !defined(WOLFSSL_XMSS_VERIFY_ONLY)
+
+/* Signature buffer sized for XMSS-SHA2_10_256 (2500 bytes). File scope to keep
+ * it off the stack; benchmark modules run sequentially, so a single shared
+ * buffer is safe. */
+static byte g_xmssSigBuf[2500];
+
+/* Helper function for XMSS key generation benchmark */
+static int _benchXmssKeyGen(whClientContext* client, whBenchOpContext* ctx,
+ int id)
+{
+ int ret = 0;
+ XmssKey key;
+ WC_RNG rng[1] = {0};
+ int i;
+ int initialized_rng = 0;
+ int initialized_key = 0;
+ whKeyId keyId = WH_KEYID_ERASED;
+
+ (void)wh_Client_SetDmaMode(client, 1);
+
+ /* Initialize the RNG */
+ ret = wc_InitRng_ex(rng, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_InitRng_ex %d\n", ret);
+ return ret;
+ }
+ initialized_rng = 1;
+
+ /* Benchmark the key generation */
+ for (i = 0; i < WOLFHSM_CFG_BENCH_KG_ITERS && ret == 0; i++) {
+ int benchStartRet;
+ int benchStopRet;
+ int keyIdRet = 0;
+
+ /* Initialize the XMSS key before each iteration */
+ ret = wc_XmssKey_Init(&key, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_Init %d\n", ret);
+ break;
+ }
+ initialized_key = 1;
+
+ /* Bind the XMSS parameter string */
+ ret = wc_XmssKey_SetParamStr(&key, WH_BENCH_XMSS_PARAM_STR);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_SetParamStr %d\n", ret);
+ break;
+ }
+
+ /* Time only the key generation. Keygen commits the private key to NVM
+ * on the server, so it is erased afterwards outside the timed region. */
+ benchStartRet = wh_Bench_StartOp(ctx, id);
+ ret = wc_XmssKey_MakeKey(&key, rng);
+ benchStopRet = wh_Bench_StopOp(ctx, id);
+
+ /* Capture the keyId as soon as the key exists so cleanup can erase the
+ * committed key even if a check below fails. The getter only reads a
+ * field, but its result gates the NVM cleanup, so check it too. */
+ if (ret == 0) {
+ keyIdRet = wh_Client_XmssGetKeyId(&key, &keyId);
+ }
+
+ if (benchStartRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StartOp %d\n", benchStartRet);
+ ret = benchStartRet;
+ break;
+ }
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_MakeKey %d\n", ret);
+ break;
+ }
+ if (keyIdRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Client_XmssGetKeyId %d\n", keyIdRet);
+ ret = keyIdRet;
+ break;
+ }
+ if (benchStopRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StopOp %d\n", benchStopRet);
+ ret = benchStopRet;
+ break;
+ }
+
+ /* Erase the committed key from cache + NVM before the next iteration */
+ if (!WH_KEYID_ISERASED(keyId)) {
+ int eraseRet = wh_Client_KeyErase(client, keyId);
+ if (eraseRet != 0) {
+ WH_BENCH_PRINTF("Failed to erase key %d\n", eraseRet);
+ ret = eraseRet;
+ break;
+ }
+ keyId = WH_KEYID_ERASED;
+ }
+
+ /* Free the key after each iteration */
+ wc_XmssKey_Free(&key);
+ initialized_key = 0;
+ }
+
+ /* Clean up resources */
+ if (initialized_key) {
+ wc_XmssKey_Free(&key);
+ }
+ if (initialized_rng) {
+ wc_FreeRng(rng);
+ }
+
+ /* Erase a key left committed by a mid-iteration failure */
+ if (!WH_KEYID_ISERASED(keyId)) {
+ int eraseRet = wh_Client_KeyErase(client, keyId);
+ if ((eraseRet != 0) && (ret == 0)) {
+ ret = eraseRet;
+ }
+ }
+
+ return ret;
+}
+
+/* Helper function for XMSS sign benchmark */
+static int _benchXmssSign(whClientContext* client, whBenchOpContext* ctx,
+ int id)
+{
+ int ret = 0;
+ XmssKey key;
+ WC_RNG rng[1] = {0};
+ const byte msg[] = WH_BENCH_XMSS_MSG;
+ const word32 msgSz = (word32)(sizeof(msg) - 1);
+ word32 sigSz = 0;
+ int i;
+ int iters = WOLFHSM_CFG_BENCH_PK_ITERS;
+ int initialized_rng = 0;
+ int initialized_key = 0;
+ whKeyId keyId = WH_KEYID_ERASED;
+
+ (void)wh_Client_SetDmaMode(client, 1);
+
+ /* Initialize the RNG */
+ ret = wc_InitRng_ex(rng, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_InitRng_ex %d\n", ret);
+ goto exit;
+ }
+ initialized_rng = 1;
+
+ /* Initialize the XMSS key */
+ ret = wc_XmssKey_Init(&key, NULL, WH_CLIENT_DEVID(client));
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_Init %d\n", ret);
+ goto exit;
+ }
+ initialized_key = 1;
+
+ /* Bind the XMSS parameter string */
+ ret = wc_XmssKey_SetParamStr(&key, WH_BENCH_XMSS_PARAM_STR);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_SetParamStr %d\n", ret);
+ goto exit;
+ }
+
+ /* Determine the signature length and confirm it fits the buffer */
+ ret = wc_XmssKey_GetSigLen(&key, &sigSz);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_GetSigLen %d\n", ret);
+ goto exit;
+ }
+ if (sigSz > sizeof(g_xmssSigBuf)) {
+ WH_BENCH_PRINTF("XMSS sig buffer too small: need=%u have=%u\n",
+ (unsigned)sigSz, (unsigned)sizeof(g_xmssSigBuf));
+ ret = BUFFER_E;
+ goto exit;
+ }
+
+ /* Generate the signing key once (untimed). Keygen commits the key to NVM
+ * on the server, so it is erased during cleanup. */
+ ret = wc_XmssKey_MakeKey(&key, rng);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_MakeKey %d\n", ret);
+ goto exit;
+ }
+ /* Capture the committed key's id so cleanup can erase it. Its result gates
+ * NVM cleanup, so surface a failure rather than leaking the key. */
+ ret = wh_Client_XmssGetKeyId(&key, &keyId);
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Client_XmssGetKeyId %d\n", ret);
+ goto exit;
+ }
+
+ /* A fresh key must have signatures available */
+ if (wc_XmssKey_SigsLeft(&key) == 0) {
+ WH_BENCH_PRINTF("XMSS reported exhausted on fresh key\n");
+ ret = WH_ERROR_ABORTED;
+ goto exit;
+ }
+
+ /* XMSS is stateful: the key holds 2^H one-time signatures. Cap the loop to
+ * that budget so raising the global WOLFHSM_CFG_BENCH_PK_ITERS (shared with
+ * the other PK benchmarks) does not exhaust the key mid-run. */
+ if (iters > (1 << WH_BENCH_XMSS_HEIGHT)) {
+ WH_BENCH_PRINTF("XMSS sign capped to %d iterations (2^H OTS budget)\n",
+ (1 << WH_BENCH_XMSS_HEIGHT));
+ iters = (1 << WH_BENCH_XMSS_HEIGHT);
+ }
+
+ /* Benchmark the signing operation. Each sign advances the private state and
+ * commits it to NVM on the server before returning the signature. */
+ for (i = 0; i < iters && ret == 0; i++) {
+ int benchStartRet;
+ int benchStopRet;
+ word32 localSigSz = sigSz;
+
+ /* Time only the sign operation */
+ benchStartRet = wh_Bench_StartOp(ctx, id);
+ ret = wc_XmssKey_Sign(&key, g_xmssSigBuf, &localSigSz, msg, (int)msgSz);
+ benchStopRet = wh_Bench_StopOp(ctx, id);
+
+ if (benchStartRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StartOp %d\n", benchStartRet);
+ ret = benchStartRet;
+ break;
+ }
+ if (ret != 0) {
+ WH_BENCH_PRINTF("Failed to wc_XmssKey_Sign %d\n", ret);
+ break;
+ }
+ if (benchStopRet != 0) {
+ WH_BENCH_PRINTF("Failed to wh_Bench_StopOp %d\n", benchStopRet);
+ ret = benchStopRet;
+ break;
+ }
+ }
+
+exit:
+ /* Clean up resources */
+ if (initialized_key) {
+ wc_XmssKey_Free(&key);
+ }
+ if (initialized_rng) {
+ wc_FreeRng(rng);
+ }
+
+ /* Erase the committed key from cache + NVM */
+ if (!WH_KEYID_ISERASED(keyId)) {
+ int eraseRet = wh_Client_KeyErase(client, keyId);
+ if ((eraseRet != 0) && (ret == 0)) {
+ ret = eraseRet;
+ }
+ }
+
+ return ret;
+}
+
+#endif /* !WOLFSSL_XMSS_VERIFY_ONLY */
+
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS */
+
+/* Public benchmark module functions for XMSS */
+int wh_Bench_Mod_XmssKeyGen(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params)
+{
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) && \
+ !defined(WOLFSSL_XMSS_VERIFY_ONLY)
+ (void)params;
+ return _benchXmssKeyGen(client, ctx, id);
+#else
+ (void)client;
+ (void)ctx;
+ (void)id;
+ (void)params;
+ return WH_ERROR_NOTIMPL;
+#endif
+}
+
+int wh_Bench_Mod_XmssSign(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params)
+{
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) && \
+ !defined(WOLFSSL_XMSS_VERIFY_ONLY)
+ (void)params;
+ return _benchXmssSign(client, ctx, id);
+#else
+ (void)client;
+ (void)ctx;
+ (void)id;
+ (void)params;
+ return WH_ERROR_NOTIMPL;
+#endif
+}
+
+int wh_Bench_Mod_XmssVerify(whClientContext* client, whBenchOpContext* ctx,
+ int id, void* params)
+{
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS)
+ (void)params;
+ return _benchXmssVerify(client, ctx, id);
+#else
+ (void)client;
+ (void)ctx;
+ (void)id;
+ (void)params;
+ return WH_ERROR_NOTIMPL;
+#endif
+}
+
+#endif /* !WOLFHSM_CFG_NO_CRYPTO && WOLFHSM_CFG_BENCH_ENABLE */
diff --git a/benchmark/config/user_settings.h b/benchmark/config/user_settings.h
index 6caa31755..c13fcaa81 100644
--- a/benchmark/config/user_settings.h
+++ b/benchmark/config/user_settings.h
@@ -157,6 +157,12 @@ extern "C" {
/* ML-KEM Options */
#define WOLFSSL_HAVE_MLKEM
+/* LMS / HSS Options (RFC 8554, NIST SP 800-208) */
+#define WOLFSSL_HAVE_LMS
+
+/* XMSS / XMSS^MT Options (RFC 8391, NIST SP 800-208) */
+#define WOLFSSL_HAVE_XMSS
+
/** Composite features */
#define HAVE_HKDF
#define HAVE_CMAC_KDF
diff --git a/benchmark/wh_bench.c b/benchmark/wh_bench.c
index fa595e847..7378af3cc 100644
--- a/benchmark/wh_bench.c
+++ b/benchmark/wh_bench.c
@@ -282,6 +282,26 @@ typedef enum BenchModuleIdx {
BENCH_MODULE_IDX_ML_KEM_1024_DECAPS_DMA,
#endif /* !WOLFSSL_NO_ML_KEM_1024 */
#endif /* WOLFSSL_HAVE_MLKEM */
+
+/* LMS (stateful, DMA-only) */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) && \
+ !defined(WOLFSSL_LMS_VERIFY_ONLY)
+ BENCH_MODULE_IDX_LMS_KEY_GEN,
+ BENCH_MODULE_IDX_LMS_SIGN,
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS)
+ BENCH_MODULE_IDX_LMS_VERIFY,
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS */
+
+/* XMSS (stateful, DMA-only) */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) && \
+ !defined(WOLFSSL_XMSS_VERIFY_ONLY)
+ BENCH_MODULE_IDX_XMSS_KEY_GEN,
+ BENCH_MODULE_IDX_XMSS_SIGN,
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS)
+ BENCH_MODULE_IDX_XMSS_VERIFY,
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS */
#endif /* !(WOLFHSM_CFG_NO_CRYPTO) */
/* number of modules. This must be the last entry and will be used as the
* size of the global modules array */
@@ -496,6 +516,26 @@ static BenchModule g_benchModules[] = {
[BENCH_MODULE_IDX_ML_KEM_1024_DECAPS_DMA] = {"ML-KEM-1024-DECAPS-DMA", wh_Bench_Mod_MlKem1024DecapsDma, BENCH_THROUGHPUT_OPS, 0, NULL},
#endif /* !WOLFSSL_NO_ML_KEM_1024 */
#endif /* WOLFSSL_HAVE_MLKEM */
+
+ /* LMS (stateful, DMA-only) */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) && \
+ !defined(WOLFSSL_LMS_VERIFY_ONLY)
+ [BENCH_MODULE_IDX_LMS_KEY_GEN] = {"LMS-L1H5W8-KEY-GEN", wh_Bench_Mod_LmsKeyGen, BENCH_THROUGHPUT_OPS, 0, NULL},
+ [BENCH_MODULE_IDX_LMS_SIGN] = {"LMS-L1H5W8-SIGN", wh_Bench_Mod_LmsSign, BENCH_THROUGHPUT_OPS, 0, NULL},
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS)
+ [BENCH_MODULE_IDX_LMS_VERIFY] = {"LMS-L1H5W8-VERIFY", wh_Bench_Mod_LmsVerify, BENCH_THROUGHPUT_OPS, 0, NULL},
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS */
+
+ /* XMSS (stateful, DMA-only) */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) && \
+ !defined(WOLFSSL_XMSS_VERIFY_ONLY)
+ [BENCH_MODULE_IDX_XMSS_KEY_GEN] = {"XMSS-SHA2_10_256-KEY-GEN", wh_Bench_Mod_XmssKeyGen, BENCH_THROUGHPUT_OPS, 0, NULL},
+ [BENCH_MODULE_IDX_XMSS_SIGN] = {"XMSS-SHA2_10_256-SIGN", wh_Bench_Mod_XmssSign, BENCH_THROUGHPUT_OPS, 0, NULL},
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */
+#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS)
+ [BENCH_MODULE_IDX_XMSS_VERIFY] = {"XMSS-SHA2_10_256-VERIFY", wh_Bench_Mod_XmssVerify, BENCH_THROUGHPUT_OPS, 0, NULL},
+#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS */
#endif /* !(WOLFHSM_CFG_NO_CRYPTO) */
};
/* clang-format on */
diff --git a/benchmark/wh_bench_ops.h b/benchmark/wh_bench_ops.h
index d2d0d3aad..c24fc02c7 100644
--- a/benchmark/wh_bench_ops.h
+++ b/benchmark/wh_bench_ops.h
@@ -26,7 +26,7 @@
#include
/* Maximum number of operations that can be registered */
-#define MAX_BENCH_OPS 119
+#define MAX_BENCH_OPS 128
/* Maximum length of operation name */
#define MAX_OP_NAME 64