diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index d10fce34c1..3f49780c35 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -90,6 +90,7 @@ CONFIG_CRYPTO_FIPS CONFIG_CRYPTO_GCM CONFIG_CRYPTO_HMAC CONFIG_CRYPTO_MANAGER +CONFIG_CRYPTO_MLDSA CONFIG_CRYPTO_RSA CONFIG_CRYPTO_SELFTESTS CONFIG_CRYPTO_SELFTESTS_FULL @@ -387,6 +388,8 @@ LIBWOLFSSL_VERSION_GIT_ORIGIN LIBWOLFSSL_VERSION_GIT_SHORT_HASH LIBWOLFSSL_VERSION_GIT_TAG LINUXKM_DONT_FORCE_FIPS_ENABLED +LINUXKM_LKCAPI_DONT_REGISTER_ED25519 +LINUXKM_LKCAPI_DONT_REGISTER_ED448 LINUXKM_LKCAPI_PRIORITY_ALLOW_MASKING LINUX_CYCLE_COUNT LINUX_RUSAGE_UTIME diff --git a/configure.ac b/configure.ac index c0d22cde91..6cb9b67ca5 100644 --- a/configure.ac +++ b/configure.ac @@ -11945,6 +11945,13 @@ then AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_RSA -DWC_RSA_NO_PADDING" ;; 'dh') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_DH -DWOLFSSL_DH_EXTRA" ;; + 'ed') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_ED" ;; + 'mldsa') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_MLDSA" ;; + 'mlkem') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_MLKEM" ;; + 'slhdsa') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_SLHDSA" ;; + 'lms') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_LMS" ;; + 'xmss') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_REGISTER_XMSS" ;; + # disable options '-cbc(aes)') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESCBC" ;; '-cfb(aes)') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_AESCFB" ;; @@ -11974,6 +11981,13 @@ then '-ecdh') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_ECDH" ;; '-rsa') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_RSA" ;; '-dh') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_DH" ;; + '-ed') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_ED" ;; + '-mldsa') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_MLDSA" ;; + '-mlkem') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_MLKEM" ;; + '-slhdsa') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_SLHDSA" ;; + '-lms') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_LMS" ;; + '-xmss') AM_CFLAGS="$AM_CFLAGS -DLINUXKM_LKCAPI_DONT_REGISTER_XMSS" ;; + *) AC_MSG_ERROR([Unsupported LKCAPI algorithm "$lkcapi_alg".]) ;; esac done diff --git a/linuxkm/include.am b/linuxkm/include.am index 724014f0b0..0917aa08d7 100644 --- a/linuxkm/include.am +++ b/linuxkm/include.am @@ -23,6 +23,12 @@ EXTRA_DIST += m4/ax_linuxkm.m4 \ linuxkm/lkcapi_ecdsa_glue.c \ linuxkm/lkcapi_ecdh_glue.c \ linuxkm/lkcapi_rsa_glue.c \ + linuxkm/lkcapi_ed_glue.c \ + linuxkm/lkcapi_lms_glue.c \ + linuxkm/lkcapi_mldsa_glue.c \ + linuxkm/lkcapi_mlkem_glue.c \ + linuxkm/lkcapi_slhdsa_glue.c \ + linuxkm/lkcapi_xmss_glue.c \ linuxkm/wolfcrypt.lds \ linuxkm/patches/5.10.17/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v10v17.patch \ linuxkm/patches/5.10.236/WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS-5v10v236.patch \ diff --git a/linuxkm/linuxkm_wc_port.h b/linuxkm/linuxkm_wc_port.h index 51db536567..a59cb40590 100644 --- a/linuxkm/linuxkm_wc_port.h +++ b/linuxkm/linuxkm_wc_port.h @@ -31,7 +31,7 @@ #include #include - #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) && !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) #error Unsupported kernel. #endif @@ -53,7 +53,8 @@ #endif #endif - #if defined(HAVE_FIPS) && defined(LINUXKM_LKCAPI_REGISTER_AESXTS) && defined(WC_LINUX_CONFIG_SELFTESTS_FULL) + #if defined(HAVE_FIPS) && defined(LINUXKM_LKCAPI_REGISTER_AESXTS) && defined(WC_LINUX_CONFIG_SELFTESTS_FULL) && \ + !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) /* CONFIG_CRYPTO_MANAGER_EXTRA_TESTS expects AES-XTS-384 to work, even when CONFIG_CRYPTO_FIPS, but FIPS 140-3 only allows AES-XTS-256 and AES-XTS-512. */ #error CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is incompatible with FIPS wolfCrypt AES-XTS -- please reconfigure the target kernel to disable CONFIG_CRYPTO_MANAGER_EXTRA_TESTS/CONFIG_CRYPTO_SELFTESTS_FULL. #endif @@ -70,7 +71,8 @@ defined(HAVE_ECC) && \ (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ defined(LINUXKM_LKCAPI_REGISTER_ECDSA) || \ - (defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECDSA))) + (defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_ECDSA))) && \ + !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) #error Target kernel requires SHA-1 signature verification support. #endif @@ -125,7 +127,7 @@ * also needed to suppress inclusion of stdlib.h in * wolfssl/wolfcrypt/types.h. */ - #define XATOI(s) ({ \ + #define XATOI(s) __extension__ ({ \ long long _xatoi_res = 0; \ int _xatoi_ret = kstrtoll(s, 10, &_xatoi_res); \ if (_xatoi_ret != 0) { \ @@ -212,7 +214,7 @@ WOLFSSL_API int wc_linuxkm_sig_ignore_end(void); WOLFSSL_API int wc_linuxkm_check_for_intr_signals(void); #ifndef WC_LINUXKM_MAX_NS_WITHOUT_YIELD - #define WC_LINUXKM_MAX_NS_WITHOUT_YIELD 1000000000 + #define WC_LINUXKM_MAX_NS_WITHOUT_YIELD (25 * 1000 * 1000) #endif WOLFSSL_API void wc_linuxkm_relax_long_loop(void); @@ -740,8 +742,10 @@ #if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && \ defined(CONFIG_X86) - extern __must_check int allocate_wolfcrypt_linuxkm_fpu_states(void); - extern void free_wolfcrypt_linuxkm_fpu_states(void); + extern __must_check int wc_linuxkm_allocate_svr_states(void); + extern void wc_linuxkm_free_svr_states(void); + WOLFSSL_API void wc_svr_disallowed_count_reset(void); + WOLFSSL_API __must_check unsigned long long int wc_svr_disallowed_count_current(void); WOLFSSL_API __must_check int wc_can_save_vector_registers_x86(void); WOLFSSL_API __must_check int wc_save_vector_registers_x86(enum wc_svr_flags flags); WOLFSSL_API void wc_restore_vector_registers_x86(enum wc_svr_flags flags); @@ -760,12 +764,25 @@ #endif #endif #ifndef CAN_SAVE_VECTOR_REGISTERS - #define CAN_SAVE_VECTOR_REGISTERS() wc_can_save_vector_registers_x86() + #if defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_OFF) + #define CAN_SAVE_VECTOR_REGISTERS() 0 + #elif defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON) + #define CAN_SAVE_VECTOR_REGISTERS() 1 + #else + #define CAN_SAVE_VECTOR_REGISTERS() wc_can_save_vector_registers_x86() + #endif #endif #if defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON) && \ - defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_OFF) - #error Conflicting settings for DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_foo + defined(LINUXKM_LKCAPI_REGISTER) && \ + !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) + #error DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON is incompatible with LINUXKM_LKCAPI_REGISTER. + #endif + + #if defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_OFF) && \ + defined(WOLFSSL_LINUXKM_BENCHMARKS) && \ + !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) + #error DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_OFF is incompatible with WOLFSSL_LINUXKM_BENCHMARKS. #endif #ifndef SAVE_VECTOR_REGISTERS @@ -806,7 +823,7 @@ #endif #ifndef SAVE_VECTOR_REGISTERS2 #if defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON) - #define SAVE_VECTOR_REGISTERS2() \ + #define SAVE_VECTOR_REGISTERS2() __extension__ \ ({ \ int _svr_ret = wc_save_vector_registers_x86(WC_SVR_FLAG_NONE); \ if (_svr_ret != 0) { \ @@ -817,7 +834,10 @@ _svr_ret; \ }) #elif defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_OFF) - #define SAVE_VECTOR_REGISTERS2() WC_ACCEL_INHIBIT_E + #define SAVE_VECTOR_REGISTERS2() __extension__ ({ \ + WC_RELAX_LONG_LOOP(); \ + WC_ACCEL_INHIBIT_E; \ + }) #elif defined(DEBUG_VECTOR_REGISTER_ACCESS_FUZZING) #define SAVE_VECTOR_REGISTERS2() wc_save_vector_registers_x86(WC_SVR_FLAG_FUZZ) #else @@ -834,7 +854,7 @@ * DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON build -- ERROR if any * calls occur. */ - #define DISABLE_VECTOR_REGISTERS() \ + #define DISABLE_VECTOR_REGISTERS() __extension__ \ ({ \ pr_err("ERROR: DISABLE_VECTOR_REGISTERS() with DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON " \ "in %s at %s L %d\n", __func__, __FILE__, __LINE__); \ @@ -850,7 +870,10 @@ #endif #ifndef SAVE_VECTOR_REGISTERS_MAYBE_INHIBIT - #ifdef DEBUG_VECTOR_REGISTER_ACCESS_FUZZING + #if (defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON) || \ + defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_OFF)) + #define SAVE_VECTOR_REGISTERS_MAYBE_INHIBIT() SAVE_VECTOR_REGISTERS2() + #elif defined(DEBUG_VECTOR_REGISTER_ACCESS_FUZZING) #define SAVE_VECTOR_REGISTERS_MAYBE_INHIBIT() wc_save_vector_registers_x86(WC_SVR_FLAG_FUZZ | WC_SVR_FLAG_MAYBE_INHIBIT) #else #define SAVE_VECTOR_REGISTERS_MAYBE_INHIBIT() wc_save_vector_registers_x86(WC_SVR_FLAG_MAYBE_INHIBIT) @@ -896,7 +919,14 @@ #define RESTORE_VECTOR_REGISTERS() restore_vector_registers_arm() #endif - #elif defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) + #elif (defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && \ + (!defined(SAVE_VECTOR_REGISTERS) || \ + !defined(SAVE_VECTOR_REGISTERS2) || \ + !defined(RESTORE_VECTOR_REGISTERS) || \ + !defined(DISABLE_VECTOR_REGISTERS) || \ + !defined(REENABLE_VECTOR_REGISTERS) || \ + !defined(SAVE_VECTOR_REGISTERS_MAYBE_INHIBIT) || \ + !defined(RESTORE_VECTOR_REGISTERS_MAYBE_INHIBITED))) #error WOLFSSL_USE_SAVE_VECTOR_REGISTERS is set for an unimplemented architecture. #endif /* WOLFSSL_USE_SAVE_VECTOR_REGISTERS */ @@ -1247,12 +1277,12 @@ #ifdef WOLFSSL_USE_SAVE_VECTOR_REGISTERS #ifdef CONFIG_X86 - typeof(allocate_wolfcrypt_linuxkm_fpu_states) *allocate_wolfcrypt_linuxkm_fpu_states; + typeof(wc_linuxkm_allocate_svr_states) *wc_linuxkm_allocate_svr_states; typeof(wc_can_save_vector_registers_x86) *wc_can_save_vector_registers_x86; - typeof(free_wolfcrypt_linuxkm_fpu_states) *free_wolfcrypt_linuxkm_fpu_states; + typeof(wc_linuxkm_free_svr_states) *wc_linuxkm_free_svr_states; typeof(wc_restore_vector_registers_x86) *wc_restore_vector_registers_x86; typeof(wc_save_vector_registers_x86) *wc_save_vector_registers_x86; - #else /* !CONFIG_X86 */ + #elif !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) /* !CONFIG_X86 */ #error WOLFSSL_USE_SAVE_VECTOR_REGISTERS is set for an unimplemented architecture. #endif /* arch */ @@ -1606,12 +1636,12 @@ #define get_current WC_PIE_INDIRECT_SYM(get_current) #if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(CONFIG_X86) - #define allocate_wolfcrypt_linuxkm_fpu_states WC_PIE_INDIRECT_SYM(allocate_wolfcrypt_linuxkm_fpu_states) + #define wc_linuxkm_allocate_svr_states WC_PIE_INDIRECT_SYM(wc_linuxkm_allocate_svr_states) #define wc_can_save_vector_registers_x86 WC_PIE_INDIRECT_SYM(wc_can_save_vector_registers_x86) - #define free_wolfcrypt_linuxkm_fpu_states WC_PIE_INDIRECT_SYM(free_wolfcrypt_linuxkm_fpu_states) + #define wc_linuxkm_free_svr_states WC_PIE_INDIRECT_SYM(wc_linuxkm_free_svr_states) #define wc_restore_vector_registers_x86 WC_PIE_INDIRECT_SYM(wc_restore_vector_registers_x86) #define wc_save_vector_registers_x86 WC_PIE_INDIRECT_SYM(wc_save_vector_registers_x86) - #elif defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) + #elif defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) #error WOLFSSL_USE_SAVE_VECTOR_REGISTERS is set for an unimplemented architecture. #endif /* WOLFSSL_USE_SAVE_VECTOR_REGISTERS */ @@ -1737,10 +1767,10 @@ #if defined(WOLFSSL_KERNEL_STACK_DEBUG) || defined(WC_LINUXKM_STACK_DEBUG) - #ifndef CONFIG_THREAD_INFO_IN_TASK + #if !defined(CONFIG_THREAD_INFO_IN_TASK) && !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) #error WC_LINUXKM_STACK_DEBUG requires CONFIG_THREAD_INFO_IN_TASK #endif - #ifdef CONFIG_STACK_GROWSUP + #if defined(CONFIG_STACK_GROWSUP) && !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) #error WC_LINUXKM_STACK_DEBUG requires !CONFIG_STACK_GROWSUP #endif @@ -1960,7 +1990,7 @@ #ifndef REENABLE_VECTOR_REGISTERS #define REENABLE_VECTOR_REGISTERS() wc_restore_vector_registers_x86(WC_SVR_FLAG_INHIBIT) #endif - #else /* !CONFIG_X86 */ + #elif !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) /* !CONFIG_X86 */ #error WOLFSSL_USE_SAVE_VECTOR_REGISTERS is set for an unimplemented architecture. #endif /* !CONFIG_X86 */ #endif /* WOLFSSL_USE_SAVE_VECTOR_REGISTERS */ @@ -1984,7 +2014,7 @@ #ifdef WOLFSSL_LINUXKM_USE_MUTEXES #define WC_MUTEX_OPS_INLINE - #ifdef LINUXKM_LKCAPI_REGISTER + #if defined(LINUXKM_LKCAPI_REGISTER) && !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) /* must use spin locks when registering implementations with the * kernel, because mutexes are forbidden when calling with nonzero * irq_count(). @@ -2196,23 +2226,23 @@ #endif #ifdef WOLFSSL_TRACK_MEMORY - #define XMALLOC(s, h, t) ({(void)(h); (void)(t); wolfSSL_Malloc(s);}) + #define XMALLOC(s, h, t) __extension__ ({(void)(h); (void)(t); wolfSSL_Malloc(s);}) #ifdef WOLFSSL_XFREE_NO_NULLNESS_CHECK - #define XFREE(p, h, t) ({(void)(h); (void)(t); wolfSSL_Free(p);}) + #define XFREE(p, h, t) __extension__ ({(void)(h); (void)(t); wolfSSL_Free(p);}) #else - #define XFREE(p, h, t) ({void* _xp; (void)(h); _xp = (p); if(_xp) wolfSSL_Free(_xp);}) + #define XFREE(p, h, t) __extension__ ({void* _xp; (void)(h); _xp = (p); if(_xp) wolfSSL_Free(_xp);}) #endif - #define XREALLOC(p, n, h, t) ({(void)(h); (void)(t); wolfSSL_Realloc(p, n);}) + #define XREALLOC(p, n, h, t) __extension__ ({(void)(h); (void)(t); wolfSSL_Realloc(p, n);}) #else #if !defined(XMALLOC_USER) && !defined(XMALLOC_OVERRIDE) - #define XMALLOC(s, h, t) ({(void)(h); (void)(t); malloc(s);}) + #define XMALLOC(s, h, t) __extension__ ({(void)(h); (void)(t); malloc(s);}) #ifdef WOLFSSL_XFREE_NO_NULLNESS_CHECK - #define XFREE(p, h, t) ({(void)(h); (void)(t); free(p);}) + #define XFREE(p, h, t) __extension__ ({(void)(h); (void)(t); free(p);}) #else - #define XFREE(p, h, t) ({void* _xp; (void)(h); (void)(t); _xp = (p); if(_xp) free(_xp);}) + #define XFREE(p, h, t) __extension__ ({void* _xp; (void)(h); (void)(t); _xp = (p); if(_xp) free(_xp);}) #endif #if defined(USE_KVREALLOC) || !defined(USE_KVMALLOC) - #define XREALLOC(p, n, h, t) ({(void)(h); (void)(t); realloc(p, n);}) + #define XREALLOC(p, n, h, t) __extension__ ({(void)(h); (void)(t); realloc(p, n);}) #endif #endif /* !XMALLOC_USER && !XMALLOC_OVERRIDE */ #endif diff --git a/linuxkm/lkcapi_aes_glue.c b/linuxkm/lkcapi_aes_glue.c index 578c6210d3..5abbbba4c9 100644 --- a/linuxkm/lkcapi_aes_glue.c +++ b/linuxkm/lkcapi_aes_glue.c @@ -1170,6 +1170,24 @@ static int km_AesGcmSetAuthsize_Rfc4106(struct crypto_aead *tfm, unsigned int au typeof(wc_AesGcmEncryptUpdate_fips) wc_AesGcmEncryptUpdate; #endif +#ifdef WOLFSSL_USE_SAVE_VECTOR_REGISTERS + #ifndef WC_LINUXKM_GCM_SVR_BATCH + #define WC_LINUXKM_GCM_SVR_BATCH (16 * 4096) + #endif + #if WC_LINUXKM_GCM_SVR_BATCH > 0 + /* If we're batching multiple chunks in a sequence wrapped in an outer + * SAVE_VECTOR_REGISTERS2(), we need to make sure the sk walk machinery + * doesn't try to yield. */ + #define WC_LINUXKM_GCM_WALK_ATOMIC true + #else + #define WC_LINUXKM_GCM_WALK_ATOMIC false + #endif +#else + #undef WC_LINUXKM_GCM_SVR_BATCH + #define WC_LINUXKM_GCM_SVR_BATCH 0 + #define WC_LINUXKM_GCM_WALK_ATOMIC false +#endif + static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) { struct crypto_aead * tfm = NULL; @@ -1182,6 +1200,9 @@ static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) u8 * assoc = NULL; u8 * assocmem = NULL; Aes *aes_copy = NULL; +#if WC_LINUXKM_GCM_SVR_BATCH > 0 + unsigned int svr_batch_left = 0; +#endif tfm = crypto_aead_reqtfm(req); ctx = crypto_aead_ctx(tfm); @@ -1199,10 +1220,10 @@ static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) scatterwalk_map_and_copy(authTag, req->src, req->assoclen + req->cryptlen - tfm->authsize, tfm->authsize, 0); - err = skcipher_walk_aead_decrypt(&walk, req, false); + err = skcipher_walk_aead_decrypt(&walk, req, WC_LINUXKM_GCM_WALK_ATOMIC); } else { - err = skcipher_walk_aead_encrypt(&walk, req, false); + err = skcipher_walk_aead_encrypt(&walk, req, WC_LINUXKM_GCM_WALK_ATOMIC); } if (unlikely(err)) { @@ -1218,6 +1239,16 @@ static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) goto out; } +#if WC_LINUXKM_GCM_SVR_BATCH > 0 + if (SAVE_VECTOR_REGISTERS2() == 0) { + svr_batch_left = WC_LINUXKM_GCM_SVR_BATCH; + /* all returns henceforth must be via the out: label. */ + } + /* else on failure, proceed unbatched -- per-call SVRs still work (or C + * fallback engages). + */ +#endif + #ifdef LINUXKM_LKCAPI_REGISTER_AESGCM_RFC4106 if (rfc4106_p) { byte rfc4106_iv[12]; @@ -1307,6 +1338,15 @@ static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) } while (walk.nbytes) { +#if WC_LINUXKM_GCM_SVR_BATCH > 0 + if (svr_batch_left == 0) { + if (SAVE_VECTOR_REGISTERS2() == 0) + svr_batch_left = WC_LINUXKM_GCM_SVR_BATCH; + /* else on failure, continue unbatched -- per-Update SVRs still work + * (or C fallback engages). + */ + } +#endif if (decrypt_p) { err = wc_AesGcmDecryptUpdate( aes_copy, @@ -1333,6 +1373,14 @@ static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) goto out; } +#if WC_LINUXKM_GCM_SVR_BATCH > 0 + if (svr_batch_left) { + svr_batch_left = (walk.nbytes >= svr_batch_left) ? 0 : svr_batch_left - walk.nbytes; + if (svr_batch_left == 0) + RESTORE_VECTOR_REGISTERS(); + } +#endif + err = skcipher_walk_done(&walk, 0); if (unlikely(err)) { @@ -1375,6 +1423,11 @@ static int AesGcmCrypt_1(struct aead_request *req, int decrypt_p, int rfc4106_p) out: +#if WC_LINUXKM_GCM_SVR_BATCH > 0 + if (svr_batch_left) + RESTORE_VECTOR_REGISTERS(); +#endif + if (err && walk.nbytes) (void)skcipher_walk_done(&walk, err); @@ -2183,7 +2236,7 @@ static int ccmAesAead_rfc4309_loaded = 0; #error LKCAPI registration of AES-XTS requires WOLFSSL_AESXTS_STREAM (--enable-aesxts-stream). #endif -#if defined(WOLFSSL_AESNI) && !defined(WC_C_DYNAMIC_FALLBACK) +#if defined(WOLFSSL_AESNI) && !defined(WC_C_DYNAMIC_FALLBACK) && !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) #error LKCAPI registration of AES-XTS with AESNI requires WC_C_DYNAMIC_FALLBACK. #endif @@ -2269,6 +2322,24 @@ static int km_AesXtsSetKey(struct crypto_skcipher *tfm, const u8 *in_key, typeof(wc_AesXtsEncryptUpdate_fips) wc_AesXtsEncryptUpdate; #endif +#ifdef WOLFSSL_USE_SAVE_VECTOR_REGISTERS + #ifndef WC_LINUXKM_XTS_SVR_BATCH + #define WC_LINUXKM_XTS_SVR_BATCH (16 * 4096) + #endif + #if WC_LINUXKM_XTS_SVR_BATCH > 0 + /* If we're batching multiple chunks in a sequence wrapped in an outer + * SAVE_VECTOR_REGISTERS2(), we need to make sure the sk walk machinery + * doesn't try to yield. */ + #define WC_LINUXKM_XTS_WALK_ATOMIC true + #else + #define WC_LINUXKM_XTS_WALK_ATOMIC false + #endif +#else + #undef WC_LINUXKM_XTS_SVR_BATCH + #define WC_LINUXKM_XTS_SVR_BATCH 0 + #define WC_LINUXKM_XTS_WALK_ATOMIC false +#endif + static int km_AesXtsEncrypt(struct skcipher_request *req) { int err; @@ -2276,6 +2347,9 @@ static int km_AesXtsEncrypt(struct skcipher_request *req) struct km_AesXtsCtx * ctx = NULL; struct skcipher_walk walk; unsigned int nbytes = 0; +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + unsigned int svr_batch_left = 0; +#endif tfm = crypto_skcipher_reqtfm(req); ctx = crypto_skcipher_ctx(tfm); @@ -2283,7 +2357,7 @@ static int km_AesXtsEncrypt(struct skcipher_request *req) if (req->cryptlen < WC_AES_BLOCK_SIZE) return -EINVAL; - err = skcipher_walk_virt(&walk, req, false); + err = skcipher_walk_virt(&walk, req, WC_LINUXKM_XTS_WALK_ATOMIC); if (unlikely(err)) { pr_err("%s: skcipher_walk_virt failed: %d\n", @@ -2291,6 +2365,16 @@ static int km_AesXtsEncrypt(struct skcipher_request *req) return err; } +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + if (SAVE_VECTOR_REGISTERS2() == 0) { + svr_batch_left = WC_LINUXKM_XTS_SVR_BATCH; + /* all returns henceforth must be via the out: label. */ + } + /* else on failure, proceed unbatched -- per-call SVRs still work (or C + * fallback engages). + */ +#endif + if (walk.nbytes == walk.total) { err = wc_AesXtsEncrypt(ctx->aesXts, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, walk.iv, walk.ivsize); @@ -2316,15 +2400,22 @@ static int km_AesXtsEncrypt(struct skcipher_request *req) skcipher_request_set_tfm(&subreq, tfm); skcipher_request_set_callback(&subreq, +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + skcipher_request_flags(req) & ~CRYPTO_TFM_REQ_MAY_SLEEP, +#else skcipher_request_flags(req), +#endif NULL, NULL); skcipher_request_set_crypt(&subreq, req->src, req->dst, blocks * WC_AES_BLOCK_SIZE, req->iv); req = &subreq; - err = skcipher_walk_virt(&walk, req, false); - if (!walk.nbytes) - return err ? : -EINVAL; + err = skcipher_walk_virt(&walk, req, WC_LINUXKM_XTS_WALK_ATOMIC); + if (!walk.nbytes) { + if (! err) + err = -EINVAL; + goto out; + } } else { tail = 0; } @@ -2345,6 +2436,15 @@ static int km_AesXtsEncrypt(struct skcipher_request *req) if (nbytes < walk.total) nbytes &= ~(WC_AES_BLOCK_SIZE - 1); +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + if (svr_batch_left == 0) { + if (SAVE_VECTOR_REGISTERS2() == 0) + svr_batch_left = WC_LINUXKM_XTS_SVR_BATCH; + /* else on failure, proceed unbatched -- per-Update SVRs still + * work (or C fallback engages). + */ + } +#endif if (nbytes & ((unsigned int)WC_AES_BLOCK_SIZE - 1U)) err = wc_AesXtsEncryptFinal(ctx->aesXts, walk.dst.virt.addr, walk.src.virt.addr, nbytes, @@ -2366,8 +2466,16 @@ static int km_AesXtsEncrypt(struct skcipher_request *req) if (unlikely(err)) { pr_err("%s: skcipher_walk_done failed: %d\n", crypto_tfm_alg_driver_name(crypto_skcipher_tfm(tfm)), err); - return err; + goto out; } + +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + if (svr_batch_left) { + svr_batch_left = (nbytes >= svr_batch_left) ? 0 : svr_batch_left - nbytes; + if (svr_batch_left == 0) + RESTORE_VECTOR_REGISTERS(); + } +#endif } if (unlikely(tail > 0)) { @@ -2381,9 +2489,9 @@ static int km_AesXtsEncrypt(struct skcipher_request *req) skcipher_request_set_crypt(req, src, dst, WC_AES_BLOCK_SIZE + tail, req->iv); - err = skcipher_walk_virt(&walk, &subreq, false); + err = skcipher_walk_virt(&walk, &subreq, WC_LINUXKM_XTS_WALK_ATOMIC); if (err) - return err; + goto out; err = wc_AesXtsEncryptFinal(ctx->aesXts, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, @@ -2414,6 +2522,11 @@ static int km_AesXtsEncrypt(struct skcipher_request *req) out: +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + if (svr_batch_left) + RESTORE_VECTOR_REGISTERS(); +#endif + if (err && walk.nbytes) (void)skcipher_walk_done(&walk, err); @@ -2427,6 +2540,9 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) struct km_AesXtsCtx * ctx = NULL; struct skcipher_walk walk; unsigned int nbytes = 0; +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + unsigned int svr_batch_left = 0; +#endif tfm = crypto_skcipher_reqtfm(req); ctx = crypto_skcipher_ctx(tfm); @@ -2434,7 +2550,7 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) if (req->cryptlen < WC_AES_BLOCK_SIZE) return -EINVAL; - err = skcipher_walk_virt(&walk, req, false); + err = skcipher_walk_virt(&walk, req, WC_LINUXKM_XTS_WALK_ATOMIC); if (unlikely(err)) { pr_err("%s: skcipher_walk_virt failed: %d\n", @@ -2442,6 +2558,16 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) return err; } +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + if (SAVE_VECTOR_REGISTERS2() == 0) { + svr_batch_left = WC_LINUXKM_XTS_SVR_BATCH; + /* all returns henceforth must be via the out: label. */ + } + /* else on failure, proceed unbatched -- per-call SVRs still work (or C + * fallback engages). + */ +#endif + if (walk.nbytes == walk.total) { err = wc_AesXtsDecrypt(ctx->aesXts, walk.dst.virt.addr, walk.src.virt.addr, @@ -2466,16 +2592,24 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) skcipher_walk_abort(&walk); skcipher_request_set_tfm(&subreq, tfm); - skcipher_request_set_callback(&subreq, - skcipher_request_flags(req), - NULL, NULL); + skcipher_request_set_callback( + &subreq, +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + skcipher_request_flags(req) & ~CRYPTO_TFM_REQ_MAY_SLEEP, +#else + skcipher_request_flags(req), +#endif + NULL, NULL); skcipher_request_set_crypt(&subreq, req->src, req->dst, blocks * WC_AES_BLOCK_SIZE, req->iv); req = &subreq; - err = skcipher_walk_virt(&walk, req, false); - if (!walk.nbytes) - return err ? : -EINVAL; + err = skcipher_walk_virt(&walk, req, WC_LINUXKM_XTS_WALK_ATOMIC); + if (!walk.nbytes) { + if (! err) + err = -EINVAL; + goto out; + } } else { tail = 0; } @@ -2496,6 +2630,14 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) if (nbytes < walk.total) nbytes &= ~(WC_AES_BLOCK_SIZE - 1); +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + if (svr_batch_left == 0) { + if (SAVE_VECTOR_REGISTERS2() == 0) + svr_batch_left = WC_LINUXKM_XTS_SVR_BATCH; + /* else on failure, continue unbatched -- per-Update SVRs still + * work (or C fallback engages). */ + } +#endif if (nbytes & ((unsigned int)WC_AES_BLOCK_SIZE - 1U)) err = wc_AesXtsDecryptFinal(ctx->aesXts, walk.dst.virt.addr, walk.src.virt.addr, nbytes, @@ -2517,8 +2659,16 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) if (unlikely(err)) { pr_err("%s: skcipher_walk_done failed: %d\n", crypto_tfm_alg_driver_name(crypto_skcipher_tfm(tfm)), err); - return err; + goto out; + } + +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + if (svr_batch_left) { + svr_batch_left = (nbytes >= svr_batch_left) ? 0 : svr_batch_left - nbytes; + if (svr_batch_left == 0) + RESTORE_VECTOR_REGISTERS(); } +#endif } if (unlikely(tail > 0)) { @@ -2532,9 +2682,9 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) skcipher_request_set_crypt(req, src, dst, WC_AES_BLOCK_SIZE + tail, req->iv); - err = skcipher_walk_virt(&walk, &subreq, false); + err = skcipher_walk_virt(&walk, &subreq, WC_LINUXKM_XTS_WALK_ATOMIC); if (err) - return err; + goto out; err = wc_AesXtsDecryptFinal(ctx->aesXts, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, @@ -2565,6 +2715,11 @@ static int km_AesXtsDecrypt(struct skcipher_request *req) out: +#if WC_LINUXKM_XTS_SVR_BATCH > 0 + if (svr_batch_left) + RESTORE_VECTOR_REGISTERS(); +#endif + if (err && walk.nbytes) (void)skcipher_walk_done(&walk, err); diff --git a/linuxkm/lkcapi_ecdh_glue.c b/linuxkm/lkcapi_ecdh_glue.c index 78f485221a..017ece5c3e 100644 --- a/linuxkm/lkcapi_ecdh_glue.c +++ b/linuxkm/lkcapi_ecdh_glue.c @@ -82,6 +82,9 @@ #define WOLFKM_ECDH_P384_NAME ("ecdh-nist-p384") #define WOLFKM_ECDH_P384_DRIVER ("ecdh-nist-p384" WOLFKM_ECDH_DRIVER_SUFFIX) +#define WOLFKM_ECDH_P521_NAME ("ecdh-nist-p521") +#define WOLFKM_ECDH_P521_DRIVER ("ecdh-nist-p521" WOLFKM_ECDH_DRIVER_SUFFIX) + static int linuxkm_test_ecdh_nist_driver(const char * driver, const byte * b_pub, const byte * expected_a_pub, @@ -96,6 +99,9 @@ static int ecdh_nist_p192_loaded = 0; #endif /* LINUXKM_ECC192 */ static int ecdh_nist_p256_loaded = 0; static int ecdh_nist_p384_loaded = 0; +#if defined(LINUXKM_ECC521) +static int ecdh_nist_p521_loaded = 0; +#endif /* LINUXKM_ECC521 */ struct km_ecdh_ctx { WC_RNG rng; /* needed for keypair gen and timing resistance*/ @@ -118,6 +124,9 @@ static int km_ecdh_nist_p192_init(struct crypto_kpp *tfm); #endif /* LINUXKM_ECC192 */ static int km_ecdh_nist_p256_init(struct crypto_kpp *tfm); static int km_ecdh_nist_p384_init(struct crypto_kpp *tfm); +#if defined(LINUXKM_ECC521) +static int km_ecdh_nist_p521_init(struct crypto_kpp *tfm); +#endif /* LINUXKM_ECC521 */ #if defined(LINUXKM_ECC192) static struct kpp_alg ecdh_nist_p192 = { @@ -163,6 +172,27 @@ static struct kpp_alg ecdh_nist_p384 = { .exit = km_ecdh_exit, }; +#if defined(LINUXKM_ECC521) +/* Note, the upstream kernel implementation (crypto/ecdh.c) has no + * P-521 arm, so the "ecdh-nist-p521" cra_name is unknown to + * crypto/testmgr.c: alg_test() takes its "notest" path and returns + * success at registration time, with or without fips_enabled. KATs + * are instead supplied by linuxkm_test_ecdh_nist_p521() below. */ +static struct kpp_alg ecdh_nist_p521 = { + .base.cra_name = WOLFKM_ECDH_P521_NAME, + .base.cra_driver_name = WOLFKM_ECDH_P521_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ecdh_ctx), + .set_secret = km_ecdh_set_secret, + .generate_public_key = km_ecdh_gen_pub, + .compute_shared_secret = km_ecdh_compute_shared_secret, + .max_size = km_ecdh_max_size, + .init = km_ecdh_nist_p521_init, + .exit = km_ecdh_exit, +}; +#endif /* LINUXKM_ECC521 */ + /* The ecdh secret is passed in this format: * __________________________________________________________ * | secret hdr | key_size | key | @@ -251,7 +281,7 @@ static int km_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, #endif case 32: /* p256 */ case 48: /* p384 */ - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) case 66: /* p521 */ #endif break; @@ -468,6 +498,13 @@ static int km_ecdh_nist_p384_init(struct crypto_kpp *tfm) return km_ecdh_init(tfm, ECC_SECP384R1); } +#if defined(LINUXKM_ECC521) +static int km_ecdh_nist_p521_init(struct crypto_kpp *tfm) +{ + return km_ecdh_init(tfm, ECC_SECP521R1); +} +#endif /* LINUXKM_ECC521 */ + /* * Generate the ecc public key: * - req->src should be null @@ -497,7 +534,7 @@ static int km_ecdh_gen_pub(struct kpp_request *req) #endif case 32: /* p256 */ case 48: /* p384 */ - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) case 66: /* p521 */ #endif break; @@ -600,7 +637,7 @@ static int km_ecdh_compute_shared_secret(struct kpp_request *req) #endif case 32: /* p256 */ case 48: /* p384 */ - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) case 66: /* p521 */ #endif break; @@ -884,6 +921,100 @@ static int linuxkm_test_ecdh_nist_p384(void) return rc; } + +#if defined(LINUXKM_ECC521) +static int linuxkm_test_ecdh_nist_p521(void) +{ + int rc = 0; + /* No reference values exist in kernel crypto/testmgr.h (the + * upstream kernel has no P-521 ECDH); these vectors were generated + * with wolfCrypt, with the shared secret computed through the same + * import-private-only + wc_ecc_make_pub + wc_ecc_shared_secret + * sequence the glue uses. */ + static const byte secret[] = { +#ifdef LITTLE_ENDIAN_ORDER + 0x02, 0x00, /* type */ + 0x48, 0x00, /* len */ + 0x42, 0x00, /* key_size */ +#else + 0x00, 0x02, /* type */ + 0x00, 0x48, /* len */ + 0x00, 0x42, /* key_size */ +#endif + 0x00, 0x09, 0xF0, 0x7E, 0xCA, 0xD3, 0xD6, 0xE1, + 0xCA, 0x8C, 0x7A, 0x12, 0xE5, 0x11, 0x66, 0x25, + 0x72, 0x70, 0xCC, 0xBF, 0x38, 0x22, 0x99, 0xE9, + 0x0C, 0x67, 0xFF, 0x36, 0x3E, 0x39, 0xE6, 0x0D, + 0xA2, 0xCA, 0xAF, 0xF2, 0x2E, 0x3C, 0x24, 0x66, + 0xC3, 0x7C, 0xB2, 0xE8, 0x34, 0x66, 0x35, 0xEB, + 0x3C, 0x2B, 0xDF, 0xBF, 0x27, 0x01, 0xF0, 0x74, + 0x2F, 0x74, 0x93, 0x42, 0x29, 0xE2, 0x5B, 0x20, + 0xED, 0xEB + }; + + /* 132 byte pub key */ + static const byte b_pub[] = { + 0x01, 0x09, 0x23, 0x72, 0xB7, 0x0B, 0x9A, 0x0E, + 0xDC, 0xC2, 0xC3, 0xE5, 0xC4, 0xEF, 0x2C, 0x82, + 0xD0, 0xC2, 0xC0, 0x1A, 0x27, 0xC9, 0xCD, 0x87, + 0x08, 0xFC, 0x63, 0x67, 0x14, 0x8B, 0x70, 0x48, + 0x17, 0x65, 0x07, 0xF8, 0x8E, 0x7F, 0x88, 0xD6, + 0x61, 0xD8, 0x5E, 0x3B, 0x82, 0x3A, 0x60, 0x66, + 0xE6, 0xF9, 0xFF, 0x4D, 0x86, 0xA3, 0x6E, 0x0B, + 0xA1, 0xCE, 0x2A, 0x16, 0x1E, 0x23, 0x73, 0xDA, + 0x3D, 0x6C, 0x00, 0x85, 0xA3, 0x4B, 0xB2, 0x7E, + 0xAF, 0xB2, 0xD6, 0x6F, 0xB4, 0x1B, 0x84, 0x77, + 0x26, 0xC9, 0x67, 0x57, 0x93, 0x67, 0x7A, 0x32, + 0x85, 0xE0, 0x6B, 0xA9, 0x58, 0xDC, 0x2D, 0x79, + 0x8E, 0xE1, 0x88, 0x45, 0x98, 0x5F, 0x47, 0x73, + 0xF0, 0x62, 0x7A, 0xC5, 0xD1, 0xD9, 0xAC, 0x25, + 0x64, 0xAE, 0xD2, 0x53, 0x46, 0x97, 0x31, 0x75, + 0x0E, 0x6E, 0x5A, 0xEB, 0x57, 0xD0, 0x58, 0xD5, + 0xDD, 0xC3, 0x32, 0x8E + }; + + /* 132 byte pub key */ + static const byte expected_a_pub[] = { + 0x00, 0x90, 0xF5, 0x3C, 0x1A, 0xE3, 0xAF, 0x05, + 0x1E, 0xD7, 0xDB, 0xDA, 0x3C, 0x50, 0xC8, 0x8F, + 0x32, 0x1F, 0x3F, 0x29, 0xE3, 0x3C, 0xFF, 0xCD, + 0x3A, 0xE9, 0x30, 0x69, 0x5A, 0x09, 0xA6, 0xAC, + 0xD7, 0x61, 0x25, 0xB0, 0xD5, 0x54, 0xDA, 0xC8, + 0x0A, 0x8E, 0xB9, 0x63, 0x32, 0x04, 0xAF, 0x82, + 0x2C, 0x99, 0xE9, 0x68, 0xE9, 0xF1, 0x53, 0xE7, + 0x03, 0xB3, 0x6D, 0x45, 0xB1, 0x4D, 0xBB, 0xEF, + 0xC5, 0xA8, 0x01, 0x07, 0x4F, 0xB4, 0x6E, 0x43, + 0x2D, 0x82, 0xB0, 0xF0, 0xAF, 0x6B, 0x77, 0x9E, + 0x9A, 0x7F, 0xDD, 0x53, 0x3F, 0xB8, 0x4A, 0xF8, + 0x60, 0x81, 0xBA, 0x88, 0x6E, 0x84, 0x14, 0xB1, + 0xA5, 0x28, 0xCD, 0xF4, 0x2C, 0x87, 0x26, 0x04, + 0x7C, 0x51, 0x46, 0x0E, 0x24, 0x5A, 0x75, 0xE3, + 0xE8, 0xB6, 0xA1, 0x1D, 0x31, 0x01, 0xDB, 0x12, + 0x24, 0xEC, 0xF1, 0x1A, 0x4A, 0x1A, 0xFD, 0x5C, + 0x5F, 0x33, 0x5A, 0xC0 + }; + + /* 66 byte shared secret */ + static const byte shared_secret[] = { + 0x01, 0xBC, 0x92, 0xA0, 0xE5, 0x47, 0x6F, 0xB7, + 0xEF, 0xE3, 0xB7, 0x2D, 0xB6, 0x52, 0xC2, 0x4D, + 0xD8, 0xD1, 0x37, 0xD0, 0xA7, 0x5C, 0x34, 0x02, + 0x7E, 0xAA, 0xC2, 0xD0, 0x94, 0x11, 0x3C, 0xCB, + 0x4F, 0xBF, 0x23, 0xBB, 0x23, 0x8E, 0xC0, 0x74, + 0x52, 0x55, 0x22, 0xF9, 0xBC, 0xBD, 0xBD, 0xE5, + 0x96, 0x05, 0x56, 0xE0, 0x4F, 0x5F, 0xF6, 0x5B, + 0x06, 0xAA, 0xE5, 0x09, 0xD4, 0xB1, 0x7C, 0x86, + 0x75, 0x00 + }; + + rc = linuxkm_test_ecdh_nist_driver(WOLFKM_ECDH_P521_DRIVER, + b_pub, expected_a_pub, sizeof(b_pub), + secret, sizeof(secret), + shared_secret, sizeof(shared_secret)); + return rc; +} +#endif /* LINUXKM_ECC521 */ + static int linuxkm_test_ecdh_nist_driver(const char * driver, const byte * b_pub, const byte * expected_a_pub, diff --git a/linuxkm/lkcapi_ecdsa_glue.c b/linuxkm/lkcapi_ecdsa_glue.c index c32b5e8a54..52e84f459d 100644 --- a/linuxkm/lkcapi_ecdsa_glue.c +++ b/linuxkm/lkcapi_ecdsa_glue.c @@ -38,14 +38,6 @@ #undef LINUXKM_LKCAPI_REGISTER_ECDSA #endif -#if defined (LINUXKM_LKCAPI_REGISTER_ECDSA) - #if (defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)) && \ - ECC_MIN_KEY_SZ <= 192 && !defined(CONFIG_CRYPTO_FIPS) - /* only register p192 if specifically enabled, and if not fips. */ - #define LINUXKM_ECC192 - #endif -#endif /* LINUXKM_LKCAPI_REGISTER_ECDSA */ - #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) /* * note: In linux 6.13 the sign/verify callbacks were removed from @@ -127,9 +119,9 @@ static int ecdsa_nist_p192_loaded = 0; #endif /* LINUXKM_ECC192 */ static int ecdsa_nist_p256_loaded = 0; static int ecdsa_nist_p384_loaded = 0; -#if defined(HAVE_ECC521) +#if defined(LINUXKM_ECC521) static int ecdsa_nist_p521_loaded = 0; -#endif /* HAVE_ECC521 */ +#endif /* LINUXKM_ECC521 */ struct km_ecdsa_ctx { ecc_key * key; @@ -161,9 +153,9 @@ static int km_ecdsa_nist_p192_init(struct ecdsa_tfm_type *tfm); #endif /* LINUXKM_ECC192 */ static int km_ecdsa_nist_p256_init(struct ecdsa_tfm_type *tfm); static int km_ecdsa_nist_p384_init(struct ecdsa_tfm_type *tfm); -#if defined(HAVE_ECC521) +#if defined(LINUXKM_ECC521) static int km_ecdsa_nist_p521_init(struct ecdsa_tfm_type *tfm); -#endif /* HAVE_ECC521 */ +#endif /* LINUXKM_ECC521 */ #if defined(LINUXKM_ECC192) #ifdef LINUXKM_ECDSA_SIG_ALG @@ -254,7 +246,7 @@ static struct akcipher_alg ecdsa_nist_p384 = { }; #endif /* !LINUXKM_ECDSA_SIG_ALG */ -#if defined(HAVE_ECC521) +#if defined(LINUXKM_ECC521) #ifdef LINUXKM_ECDSA_SIG_ALG static struct sig_alg ecdsa_nist_p521 = { .base.cra_name = WOLFKM_ECDSA_P521_NAME, @@ -283,7 +275,7 @@ static struct akcipher_alg ecdsa_nist_p521 = { .exit = km_ecdsa_exit, }; #endif /* !LINUXKM_ECDSA_SIG_ALG */ -#endif /* HAVE_ECC521 */ +#endif /* LINUXKM_ECC521 */ /** * Decodes and sets the ECDSA pub key. @@ -310,7 +302,7 @@ static int km_ecdsa_set_pub(struct ecdsa_tfm_type *tfm, const void *key, #endif case 32: /* p256 */ case 48: /* p384 */ - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) case 66: /* p521 */ #endif break; @@ -481,12 +473,12 @@ static int km_ecdsa_nist_p384_init(struct ecdsa_tfm_type *tfm) return km_ecdsa_init(tfm, ECC_SECP384R1); } -#if defined(HAVE_ECC521) +#if defined(LINUXKM_ECC521) static int km_ecdsa_nist_p521_init(struct ecdsa_tfm_type *tfm) { return km_ecdsa_init(tfm, ECC_SECP521R1); } -#endif /* HAVE_ECC521 */ +#endif /* LINUXKM_ECC521 */ #ifdef LINUXKM_ECDSA_SIG_ALG @@ -912,7 +904,7 @@ static int linuxkm_test_ecdsa_nist_p384(void) return rc; } -#if defined(HAVE_ECC521) +#if defined(LINUXKM_ECC521) static int linuxkm_test_ecdsa_nist_p521(void) { int rc = 0; @@ -987,7 +979,7 @@ static int linuxkm_test_ecdsa_nist_p521(void) return rc; } -#endif /* HAVE_ECC521 */ +#endif /* LINUXKM_ECC521 */ #ifdef LINUXKM_ECDSA_SIG_ALG diff --git a/linuxkm/lkcapi_ed_glue.c b/linuxkm/lkcapi_ed_glue.c new file mode 100644 index 0000000000..dbaba6fd6c --- /dev/null +++ b/linuxkm/lkcapi_ed_glue.c @@ -0,0 +1,2034 @@ +/* lkcapi_ed_glue.c -- glue logic to register ED25519 and ED448 wolfCrypt + * implementations with the Linux Kernel Cryptosystem + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* included by linuxkm/lkcapi_glue.c */ +#ifndef WC_SKIP_INCLUDED_C_FILES + +#ifndef LINUXKM_LKCAPI_REGISTER + #error lkcapi_ed_glue.c included in non-LINUXKM_LKCAPI_REGISTER project. +#endif + +/* Note: the kernel has no in-tree EdDSA implementation on any version, hence + * no CONFIG_CRYPTO_ED25519/CONFIG_CRYPTO_ED448 to pivot on for + * LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG, and no config-conflict check either -- + * the EdDSA algs are registered for LINUXKM_LKCAPI_REGISTER_ALL, or by + * explicit request only. + * + * Because the cra_names registered here are unknown to crypto/testmgr.c, + * alg_test() takes its "notest" path for them and returns success at + * registration time, with or without fips_enabled. KATs are instead + * supplied by linuxkm_test_ed25519()/linuxkm_test_ed448() below. + */ + +#if defined(HAVE_ED25519) && defined(HAVE_ED25519_VERIFY) && \ + defined(HAVE_ED25519_KEY_IMPORT) + #if (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ + defined(LINUXKM_LKCAPI_REGISTER_ED)) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_ED) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_ED25519) && \ + !defined(LINUXKM_LKCAPI_REGISTER_ED25519) + #define LINUXKM_LKCAPI_REGISTER_ED25519 + #endif +#else + #undef LINUXKM_LKCAPI_REGISTER_ED25519 +#endif + +#if defined(HAVE_ED448) && defined(HAVE_ED448_VERIFY) && \ + defined(HAVE_ED448_KEY_IMPORT) + #if (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ + defined(LINUXKM_LKCAPI_REGISTER_ED)) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_ED) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_ED448) && \ + !defined(LINUXKM_LKCAPI_REGISTER_ED448) + #define LINUXKM_LKCAPI_REGISTER_ED448 + #endif +#else + #undef LINUXKM_LKCAPI_REGISTER_ED448 +#endif + +#if defined(LINUXKM_LKCAPI_REGISTER_ED25519) && defined(HAVE_ED25519_SIGN) + #define LINUXKM_ED25519_SIGN +#else + #undef LINUXKM_ED25519_SIGN +#endif +#if defined(LINUXKM_LKCAPI_REGISTER_ED448) && defined(HAVE_ED448_SIGN) + #define LINUXKM_ED448_SIGN +#else + #undef LINUXKM_ED448_SIGN +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) + /* + * Note: In linux 6.13 the sign/verify callbacks were removed from + * akcipher_alg, and asymmetric signature algorithms moved to the new + * struct sig_alg type. As with ecdsa (see lkcapi_ecdsa_glue.c), the + * EdDSA algs are registered as struct sig_alg on 6.13+, and as + * verify-capable struct akcipher_alg on earlier kernels. + * + * Unlike ecdsa, no in-tree implementation constrains the calling + * conventions, which are therefore wolfSSL-defined: + * - set_pub_key takes the raw RFC 8032 compressed public key + * (32 bytes for ed25519, 57 bytes for ed448). + * - verify takes the raw RFC 8032 signature (R || S, 64 bytes for + * ed25519, 114 bytes for ed448) as src, and the raw unhashed + * message, of any length, as the "digest" argument -- pure + * Ed25519/Ed448, i.e. no prehashing, and for ed448 the default + * (empty) context. + * - set_priv_key takes the raw RFC 8032 private key (the 32-byte + * ed25519 / 57-byte ed448 "seed"), matching OpenSSL's raw + * private key format; the public key is derived and installed + * internally. + * - sign takes the raw message (any length) as src and writes the + * raw RFC 8032 signature (R || S) to dst, returning the + * signature size per the crypto_sig_sign() contract. EdDSA + * signing is deterministic (RFC 8032), so no RNG is involved. + * + * The kernel patch to enable EdDSA for module signatures is trivial -- + * contact wolfSSL for more info. + */ + #define LINUXKM_EDDSA_SIG_ALG +#endif + +#if defined(LINUXKM_LKCAPI_REGISTER_ED25519) || \ + defined(LINUXKM_LKCAPI_REGISTER_ED448) + +#ifdef LINUXKM_LKCAPI_REGISTER_ED25519 + #include +#endif +#ifdef LINUXKM_LKCAPI_REGISTER_ED448 + #include +#endif + +#ifdef LINUXKM_EDDSA_SIG_ALG + #define eddsa_tfm_type crypto_sig + #define eddsa_tfm_ctx_cb crypto_sig_ctx +#else + #define eddsa_tfm_type crypto_akcipher + #define eddsa_tfm_ctx_cb akcipher_tfm_ctx +#endif /* !LINUXKM_EDDSA_SIG_ALG */ + +#if defined(CURVED25519_X64) && !defined(NO_AVX2_SUPPORT) + #define WOLFKM_ED25519_DRIVER_ISA_EXT "-avx2" +#else + #define WOLFKM_ED25519_DRIVER_ISA_EXT "" +#endif +#define WOLFKM_ED25519_DRIVER_SUFFIX WOLFKM_ED25519_DRIVER_ISA_EXT \ + WOLFKM_DRIVER_SUFFIX_BASE + +/* no x86-64 asm covers ed448 in wolfCrypt. */ +#define WOLFKM_ED448_DRIVER_ISA_EXT "" +#define WOLFKM_ED448_DRIVER_SUFFIX WOLFKM_ED448_DRIVER_ISA_EXT \ + WOLFKM_DRIVER_SUFFIX_BASE + +#define WOLFKM_ED25519_NAME ("ed25519") +#define WOLFKM_ED25519_DRIVER ("ed25519" WOLFKM_ED25519_DRIVER_SUFFIX) + +#define WOLFKM_ED448_NAME ("ed448") +#define WOLFKM_ED448_DRIVER ("ed448" WOLFKM_ED448_DRIVER_SUFFIX) + + +static int linuxkm_test_eddsa_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * priv, word32 priv_len, + int expect_sign, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len); + +#ifdef LINUXKM_LKCAPI_REGISTER_ED25519 +static int ed25519_loaded = 0; +#endif /* LINUXKM_LKCAPI_REGISTER_ED25519 */ +#ifdef LINUXKM_LKCAPI_REGISTER_ED448 +static int ed448_loaded = 0; +#endif /* LINUXKM_LKCAPI_REGISTER_ED448 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED25519 +struct km_ed25519_ctx { + ed25519_key * key; +}; + +static void km_ed25519_exit(struct eddsa_tfm_type *tfm); +static int km_ed25519_init(struct eddsa_tfm_type *tfm); +static int km_ed25519_set_pub(struct eddsa_tfm_type *tfm, + const void *key, unsigned int keylen); +static int km_ed25519_set_priv(struct eddsa_tfm_type *tfm, + const void *key, unsigned int keylen); +#ifdef LINUXKM_EDDSA_SIG_ALG +static unsigned int km_ed25519_key_size(struct crypto_sig *tfm); +static unsigned int km_ed25519_digest_size(struct crypto_sig *tfm); +static unsigned int km_ed25519_max_size(struct crypto_sig *tfm); +static int km_ed25519_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen); +static int km_ed25519_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); +#else +static unsigned int km_ed25519_max_size(struct crypto_akcipher *tfm); +static int km_ed25519_verify(struct akcipher_request *req); +static int km_ed25519_sign(struct akcipher_request *req); +#endif /* !LINUXKM_EDDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_ED25519 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED448 +struct km_ed448_ctx { + ed448_key * key; +}; + +static void km_ed448_exit(struct eddsa_tfm_type *tfm); +static int km_ed448_init(struct eddsa_tfm_type *tfm); +static int km_ed448_set_pub(struct eddsa_tfm_type *tfm, + const void *key, unsigned int keylen); +static int km_ed448_set_priv(struct eddsa_tfm_type *tfm, + const void *key, unsigned int keylen); +#ifdef LINUXKM_EDDSA_SIG_ALG +static unsigned int km_ed448_key_size(struct crypto_sig *tfm); +static unsigned int km_ed448_digest_size(struct crypto_sig *tfm); +static unsigned int km_ed448_max_size(struct crypto_sig *tfm); +static int km_ed448_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen); +static int km_ed448_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); +#else +static unsigned int km_ed448_max_size(struct crypto_akcipher *tfm); +static int km_ed448_verify(struct akcipher_request *req); +static int km_ed448_sign(struct akcipher_request *req); +#endif /* !LINUXKM_EDDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_ED448 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED25519 +#ifdef LINUXKM_EDDSA_SIG_ALG +static struct sig_alg ed25519 = { + .base.cra_name = WOLFKM_ED25519_NAME, + .base.cra_driver_name = WOLFKM_ED25519_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ed25519_ctx), + .sign = km_ed25519_sign, + .verify = km_ed25519_verify, + .set_pub_key = km_ed25519_set_pub, + .set_priv_key = km_ed25519_set_priv, + .key_size = km_ed25519_key_size, + .digest_size = km_ed25519_digest_size, + .max_size = km_ed25519_max_size, + .init = km_ed25519_init, + .exit = km_ed25519_exit, +}; +#else /* !LINUXKM_EDDSA_SIG_ALG */ +static struct akcipher_alg ed25519 = { + .base.cra_name = WOLFKM_ED25519_NAME, + .base.cra_driver_name = WOLFKM_ED25519_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ed25519_ctx), + .sign = km_ed25519_sign, + .verify = km_ed25519_verify, + .set_pub_key = km_ed25519_set_pub, + .set_priv_key = km_ed25519_set_priv, + .max_size = km_ed25519_max_size, + .init = km_ed25519_init, + .exit = km_ed25519_exit, +}; +#endif /* !LINUXKM_EDDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_ED25519 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED448 +#ifdef LINUXKM_EDDSA_SIG_ALG +static struct sig_alg ed448 = { + .base.cra_name = WOLFKM_ED448_NAME, + .base.cra_driver_name = WOLFKM_ED448_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ed448_ctx), + .sign = km_ed448_sign, + .verify = km_ed448_verify, + .set_pub_key = km_ed448_set_pub, + .set_priv_key = km_ed448_set_priv, + .key_size = km_ed448_key_size, + .digest_size = km_ed448_digest_size, + .max_size = km_ed448_max_size, + .init = km_ed448_init, + .exit = km_ed448_exit, +}; +#else /* !LINUXKM_EDDSA_SIG_ALG */ +static struct akcipher_alg ed448 = { + .base.cra_name = WOLFKM_ED448_NAME, + .base.cra_driver_name = WOLFKM_ED448_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_ed448_ctx), + .sign = km_ed448_sign, + .verify = km_ed448_verify, + .set_pub_key = km_ed448_set_pub, + .set_priv_key = km_ed448_set_priv, + .max_size = km_ed448_max_size, + .init = km_ed448_init, + .exit = km_ed448_exit, +}; +#endif /* !LINUXKM_EDDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_ED448 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED25519 + +/* + * Decodes and sets the ED25519 pub key. + * + * param tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * param key raw RFC 8032 compressed public key, + * ED25519_PUB_KEY_SIZE (32) bytes + * param keylen key length + */ +static int km_ed25519_set_pub(struct eddsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + int err = 0; + struct km_ed25519_ctx * ctx = NULL; + + ctx = eddsa_tfm_ctx_cb(tfm); + + if (ctx->key == NULL) + return -EINVAL; + + if (keylen != ED25519_PUB_KEY_SIZE) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: ed25519_set_pub: invalid pub len: got %d, " + " expected %d\n", + WOLFKM_ED25519_DRIVER, keylen, + (int)ED25519_PUB_KEY_SIZE); + #endif + return -EINVAL; + } + + /* import, and as an untrusted import validate, the compressed public + * key. */ + err = wc_ed25519_import_public((const byte *)key, keylen, ctx->key); + + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: wc_ed25519_import_public failed: %d\n", + WOLFKM_ED25519_DRIVER, err); + #endif + return -EINVAL; + } + + if (! ctx->key->pubKeySet) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: wc_ed25519_import_public: pubKeySet not set\n", + WOLFKM_ED25519_DRIVER); + #endif + return -EINVAL; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed25519_set_pub %d\n", keylen); + #endif + return err; +} + +/* + * Sets the ED25519 private key, deriving and installing the public key. + * + * param tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * param key raw RFC 8032 private key (the "seed"), ED25519_KEY_SIZE + * (32) bytes -- OpenSSL's raw private key format + * param keylen key length + */ +#ifdef LINUXKM_ED25519_SIGN +static int km_ed25519_set_priv(struct eddsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + int err = 0; + struct km_ed25519_ctx * ctx = NULL; + byte pub[ED25519_PUB_KEY_SIZE]; + + ctx = eddsa_tfm_ctx_cb(tfm); + + if (ctx->key == NULL) + return -EINVAL; + + if (keylen != ED25519_KEY_SIZE) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: ed25519_set_priv: invalid priv len: got %d, " + " expected %d\n", + WOLFKM_ED25519_DRIVER, keylen, + (int)ED25519_KEY_SIZE); + #endif + return -EINVAL; + } + + err = wc_ed25519_import_private_only((const byte *)key, keylen, + ctx->key); + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: wc_ed25519_import_private_only failed: %d\n", + WOLFKM_ED25519_DRIVER, err); + #endif + return -EINVAL; + } + + /* Ed25519 signing binds the public key into the hash (RFC 8032 + * section 5.1.6 step 2), so derive and install it. The derived + * key is trusted by construction. */ + err = wc_ed25519_make_public(ctx->key, pub, (word32)sizeof(pub)); + if (err == 0) + err = wc_ed25519_import_public_ex(pub, (word32)sizeof(pub), + ctx->key, 1 /* trusted */); + + if ((err == 0) && + ((! ctx->key->privKeySet) || (! ctx->key->pubKeySet))) + { + err = WC_NO_ERR_TRACE(WC_FAILURE); + } + + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: ed25519 public key derivation failed: %d\n", + WOLFKM_ED25519_DRIVER, err); + #endif + /* don't leave the key half-set. */ + wc_ed25519_free(ctx->key); + (void)wc_ed25519_init(ctx->key); + return -EINVAL; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed25519_set_priv %d\n", keylen); + #endif + return 0; +} +#else /* !LINUXKM_ED25519_SIGN */ +static int km_ed25519_set_priv(struct eddsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + (void)tfm; + (void)key; + (void)keylen; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_ED25519_SIGN */ + +#ifdef LINUXKM_EDDSA_SIG_ALG +/* Mirrors the size convention of the kernel's key_size callbacks (see e.g. + * ecdsa_key_size()): + * linux kernel version < 6.15.3: key size in bytes. + * linux kernel version >= 6.15.3: key size in bits. + * The bit size reported is the RFC 8032 "b" parameter (the public key + * encoding size in bits): 256 for ed25519, 456 for ed448. + * */ +static unsigned int km_ed25519_key_size(struct crypto_sig *tfm) +{ + (void)tfm; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + return ED25519_PUB_KEY_SIZE * WOLFSSL_BIT_SIZE; + #else + return ED25519_PUB_KEY_SIZE; + #endif +} + +/* Pure Ed25519/Ed448 have no digest -- km_ed25519_verify() and + * km_ed448_verify() take the raw message, with no fixed or maximum length + * -- so advertise 0. digest_size is advisory-only in crypto/sig.c; + * nothing in the kernel constrains verify's dlen with it. + * */ +static unsigned int km_ed25519_digest_size(struct crypto_sig *tfm) +{ + (void)tfm; + return 0; +} + +static unsigned int km_ed25519_max_size(struct crypto_sig *tfm) +{ + (void)tfm; + return ED25519_SIG_SIZE; +} +#else /* !LINUXKM_EDDSA_SIG_ALG */ +static unsigned int km_ed25519_max_size(struct crypto_akcipher *tfm) +{ + (void)tfm; + return ED25519_SIG_SIZE; +} +#endif /* !LINUXKM_EDDSA_SIG_ALG */ + +static void km_ed25519_exit(struct eddsa_tfm_type *tfm) +{ + struct km_ed25519_ctx * ctx = NULL; + + ctx = eddsa_tfm_ctx_cb(tfm); + + if (ctx->key) { + wc_ed25519_free(ctx->key); + free(ctx->key); + ctx->key = NULL; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed25519_exit\n"); + #endif + return; +} + +static int km_ed25519_init(struct eddsa_tfm_type *tfm) +{ + struct km_ed25519_ctx *ctx = eddsa_tfm_ctx_cb(tfm); + int ret = 0; + + XMEMSET(ctx, 0, sizeof(struct km_ed25519_ctx)); + + ctx->key = (ed25519_key *)malloc(sizeof(ed25519_key)); + if (!ctx->key) + return -ENOMEM; + + ret = wc_ed25519_init(ctx->key); + if (ret < 0) { + free(ctx->key); + ctx->key = NULL; + return -ENOMEM; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed25519_init\n"); + #endif + return 0; +} + +#ifdef LINUXKM_EDDSA_SIG_ALG + +/* + * Verify an ed25519 signature (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw RFC 8032 signature, R || S. + * - slen must == ED25519_SIG_SIZE (64). + * + * digest: + * - the raw message. Pure Ed25519 verifies the message itself -- no + * prehashing occurs, and dlen is unrestricted. + * + * See kernel (6.13 or later): + * - include/crypto/sig.h + */ +static int km_ed25519_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct km_ed25519_ctx *ctx = crypto_sig_ctx(tfm); +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + ed25519_key key_copy; +#endif + ed25519_key *key = NULL; + int result = -1; + int err = -1; + + if (src == NULL || digest == NULL) + return -EINVAL; + + if ((ctx->key == NULL) || (! ctx->key->pubKeySet)) + return -EINVAL; + + if (slen != ED25519_SIG_SIZE) + return -EINVAL; + +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + #if defined(WOLFSSL_SMALL_STACK_CACHE) && !defined(WC_SHA2_NO_SMALL_STACK) + #error Unsupported kernel module configuration -- missing WC_SHA2_NO_SMALL_STACK. + #endif + /* wc_ed25519_verify_msg() advances the key's persistent SHA-512 state, + * but callers of the kernel crypto API are entitled to issue concurrent + * verifies on a single tfm, so operate on a transient copy of the + * tfm's imported key. ed25519_key is pure POD as configured for + * linuxkm (no owned allocations), making the struct copy sound, and + * the copy holds only public material, so it's simply discarded. + */ + key_copy = *ctx->key; + key = &key_copy; +#else + key = ctx->key; +#endif + + err = wc_ed25519_verify_msg((const byte *)src, (word32)slen, + (const byte *)digest, (word32)dlen, + &result, key); + + if (err) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("error: %s: ed25519 verify: verify_msg returned: %d\n", + WOLFKM_ED25519_DRIVER, err); + #endif + err = -EBADMSG; + goto ed25519_verify_end; + } + + if (result != 1) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("info: %s: ed25519 verify: verify fail: %d\n", + WOLFKM_ED25519_DRIVER, result); + #endif + err = -EBADMSG; + goto ed25519_verify_end; + } + +ed25519_verify_end: + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed25519_verify dlen %d, slen %d, " + "err %d, result %d\n", dlen, slen, err, result); + #endif + return err; +} + +/* + * Sign a message with ED25519 (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw message. Pure Ed25519 signs the message itself -- no + * prehashing occurs, and slen is unrestricted. + * + * dst: + * - receives the raw RFC 8032 signature, R || S. + * - dlen must be >= ED25519_SIG_SIZE (64), else -EOVERFLOW (following the + * convention of rsassa_pkcs1_sign()). + * + * Returns the signature size on success, per the crypto_sig_sign() + * contract. Ed25519 signing is deterministic (RFC 8032) -- no RNG is + * involved. + */ +#ifdef LINUXKM_ED25519_SIGN +static int km_ed25519_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct km_ed25519_ctx *ctx = crypto_sig_ctx(tfm); +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + ed25519_key key_copy; +#endif + ed25519_key *key = NULL; + word32 out_len = ED25519_SIG_SIZE; + int err = -1; + + if (src == NULL || dst == NULL) + return -EINVAL; + + if ((ctx->key == NULL) || + (! ctx->key->privKeySet) || + (! ctx->key->pubKeySet)) + { + return -EINVAL; + } + + if (dlen < ED25519_SIG_SIZE) + return -EOVERFLOW; + +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + /* as in km_ed25519_verify(), wc_ed25519_sign_msg() advances the key's + * persistent SHA-512 state, so operate on a transient copy of the + * tfm's key. Unlike the verify path, the copy holds private + * material, so it's zeroized before return. + */ + key_copy = *ctx->key; + key = &key_copy; +#else + /* without a persistent SHA-512, wc_ed25519_sign_msg() leaves the key + * unmodified, so the shared tfm key can be used directly. */ + key = ctx->key; +#endif + + err = wc_ed25519_sign_msg((const byte *)src, (word32)slen, + (byte *)dst, &out_len, key); + +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + ForceZero(&key_copy, sizeof(key_copy)); +#endif + + if (err || (out_len != ED25519_SIG_SIZE)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("error: %s: ed25519 sign: sign_msg returned: %d, " + "out_len %u\n", WOLFKM_ED25519_DRIVER, err, out_len); + #endif + return -EINVAL; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed25519_sign slen %d\n", slen); + #endif + return (int)out_len; +} +#else /* !LINUXKM_ED25519_SIGN */ +static int km_ed25519_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + (void)tfm; + (void)src; + (void)slen; + (void)dst; + (void)dlen; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_ED25519_SIGN */ + +#else /* !LINUXKM_EDDSA_SIG_ALG */ + +/* + * Verify an ed25519 signature. + * + * The total size of req->src is src_len + dst_len: + * - src_len: signature (raw RFC 8032 R || S, must be ED25519_SIG_SIZE) + * - dst_len: message (raw, unhashed, any length) + * + * dst should be null. + * See kernel: + * - include/crypto/akcipher.h + */ +static int km_ed25519_verify(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_ed25519_ctx * ctx = NULL; +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + ed25519_key key_copy; +#endif + ed25519_key * key = NULL; + byte * sig = NULL; + word32 sig_len = 0; + byte * msg = NULL; + word32 msg_len = 0; + int result = -1; + int err = -1; + + if (req->src == NULL || req->dst != NULL) { + return -EINVAL; + } + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + if ((ctx->key == NULL) || (! ctx->key->pubKeySet)) { + return -EINVAL; + } + + sig_len = req->src_len; + msg_len = req->dst_len; + + if (sig_len != ED25519_SIG_SIZE) { + err = -EINVAL; + goto ed25519_verify_end; + } + + if ((sig_len + msg_len) != ((word64)sig_len + (word64)msg_len)) { + err = -EINVAL; + goto ed25519_verify_end; + } + + sig = malloc(sig_len + msg_len); + if (unlikely(sig == NULL)) { + err = -ENOMEM; + goto ed25519_verify_end; + } + + msg = sig + sig_len; + + XMEMSET(sig, 0, sig_len + msg_len); + + /* copy sig and msg from req->src to sig and contiguous msg buffer. */ + scatterwalk_map_and_copy(sig, req->src, 0, sig_len + msg_len, 0); + +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + /* see the analogous comment in the sig_alg edition of + * km_ed25519_verify(). */ + key_copy = *ctx->key; + key = &key_copy; +#else + key = ctx->key; +#endif + + err = wc_ed25519_verify_msg(sig, sig_len, msg, msg_len, &result, key); + + if (err) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("error: %s: ed25519 verify: verify_msg returned: %d\n", + WOLFKM_ED25519_DRIVER, err); + #endif + err = -EBADMSG; + goto ed25519_verify_end; + } + + if (result != 1) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("info: %s: ed25519 verify: verify fail: %d\n", + WOLFKM_ED25519_DRIVER, result); + #endif + err = -EBADMSG; + goto ed25519_verify_end; + } + +ed25519_verify_end: + + free(sig); + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed25519_verify msg_len %d, sig_len %d, " + "err %d, result %d\n", msg_len, sig_len, err, result); + #endif + return err; +} + +/* + * Sign a message with ed25519. + * + * req->src: the raw message (src_len bytes, unrestricted). + * req->dst: receives the raw RFC 8032 signature, R || S + * (ED25519_SIG_SIZE bytes). Per include/crypto/akcipher.h, if + * dst_len is insufficient it's updated to the required size + * and -EOVERFLOW is returned; on success it's updated to the + * actual size. + * + * Ed25519 signing is deterministic (RFC 8032) -- no RNG is involved. + */ +#ifdef LINUXKM_ED25519_SIGN +static int km_ed25519_sign(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_ed25519_ctx * ctx = NULL; +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + ed25519_key key_copy; +#endif + ed25519_key * key = NULL; + byte * msg = NULL; + word32 msg_len = 0; + byte sig[ED25519_SIG_SIZE]; + word32 out_len = ED25519_SIG_SIZE; + int err = -1; + + if (req->src == NULL || req->dst == NULL) + return -EINVAL; + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + if ((ctx->key == NULL) || + (! ctx->key->privKeySet) || + (! ctx->key->pubKeySet)) + { + return -EINVAL; + } + + if (req->dst_len < ED25519_SIG_SIZE) { + req->dst_len = ED25519_SIG_SIZE; + return -EOVERFLOW; + } + + msg_len = req->src_len; + + /* allocate at least 1 byte, to assure a non-null msg pointer for + * zero-length messages (msg_len 0 is legal for pure Ed25519). */ + msg = malloc(msg_len ? msg_len : 1); + if (unlikely(msg == NULL)) { + err = -ENOMEM; + goto ed25519_sign_end; + } + + /* copy the message from req->src to the contiguous msg buffer. */ + scatterwalk_map_and_copy(msg, req->src, 0, msg_len, 0); + +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + /* see the analogous comment in the sig_alg edition of + * km_ed25519_sign(). */ + key_copy = *ctx->key; + key = &key_copy; +#else + key = ctx->key; +#endif + + err = wc_ed25519_sign_msg(msg, msg_len, sig, &out_len, key); + +#ifdef WOLFSSL_ED25519_PERSISTENT_SHA + ForceZero(&key_copy, sizeof(key_copy)); +#endif + + if (err || (out_len != ED25519_SIG_SIZE)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("error: %s: ed25519 sign: sign_msg returned: %d, " + "out_len %u\n", WOLFKM_ED25519_DRIVER, err, out_len); + #endif + err = -EINVAL; + goto ed25519_sign_end; + } + + /* copy the signature out to req->dst. */ + scatterwalk_map_and_copy(sig, req->dst, 0, out_len, 1); + req->dst_len = out_len; + err = 0; + +ed25519_sign_end: + + free(msg); + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed25519_sign msg_len %d, err %d\n", + msg_len, err); + #endif + return err; +} +#else /* !LINUXKM_ED25519_SIGN */ +static int km_ed25519_sign(struct akcipher_request *req) +{ + (void)req; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_ED25519_SIGN */ + +#endif /* !LINUXKM_EDDSA_SIG_ALG */ + +#endif /* LINUXKM_LKCAPI_REGISTER_ED25519 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED448 + +/* + * Decodes and sets the ED448 pub key. + * + * param tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * param key raw RFC 8032 compressed public key, + * ED448_PUB_KEY_SIZE (57) bytes + * param keylen key length + */ +static int km_ed448_set_pub(struct eddsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + int err = 0; + struct km_ed448_ctx * ctx = NULL; + + ctx = eddsa_tfm_ctx_cb(tfm); + + if (ctx->key == NULL) + return -EINVAL; + + if (keylen != ED448_PUB_KEY_SIZE) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: ed448_set_pub: invalid pub len: got %d, " + " expected %d\n", + WOLFKM_ED448_DRIVER, keylen, + (int)ED448_PUB_KEY_SIZE); + #endif + return -EINVAL; + } + + /* import, and as an untrusted import validate, the compressed public + * key. */ + err = wc_ed448_import_public((const byte *)key, keylen, ctx->key); + + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: wc_ed448_import_public failed: %d\n", + WOLFKM_ED448_DRIVER, err); + #endif + return -EINVAL; + } + + if (! ctx->key->pubKeySet) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: wc_ed448_import_public: pubKeySet not set\n", + WOLFKM_ED448_DRIVER); + #endif + return -EINVAL; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed448_set_pub %d\n", keylen); + #endif + return err; +} + +/* + * Sets the ED448 private key, deriving and installing the public key. + * + * param tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * param key raw RFC 8032 private key (the "seed"), ED448_KEY_SIZE + * (57) bytes -- OpenSSL's raw private key format + * param keylen key length + */ +#ifdef LINUXKM_ED448_SIGN +static int km_ed448_set_priv(struct eddsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + int err = 0; + struct km_ed448_ctx * ctx = NULL; + byte pub[ED448_PUB_KEY_SIZE]; + + ctx = eddsa_tfm_ctx_cb(tfm); + + if (ctx->key == NULL) + return -EINVAL; + + if (keylen != ED448_KEY_SIZE) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: ed448_set_priv: invalid priv len: got %d, " + " expected %d\n", + WOLFKM_ED448_DRIVER, keylen, + (int)ED448_KEY_SIZE); + #endif + return -EINVAL; + } + + err = wc_ed448_import_private_only((const byte *)key, keylen, + ctx->key); + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: wc_ed448_import_private_only failed: %d\n", + WOLFKM_ED448_DRIVER, err); + #endif + return -EINVAL; + } + + /* Ed25519 signing binds the public key into the hash (RFC 8032 + * section 5.2.6 step 2), so derive and install it. The derived + * key is trusted by construction. */ + err = wc_ed448_make_public(ctx->key, pub, (word32)sizeof(pub)); + if (err == 0) + err = wc_ed448_import_public_ex(pub, (word32)sizeof(pub), + ctx->key, 1 /* trusted */); + + if ((err == 0) && + ((! ctx->key->privKeySet) || (! ctx->key->pubKeySet))) + { + err = WC_NO_ERR_TRACE(WC_FAILURE); + } + + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("%s: ed448 public key derivation failed: %d\n", + WOLFKM_ED448_DRIVER, err); + #endif + /* don't leave the key half-set. */ + wc_ed448_free(ctx->key); + (void)wc_ed448_init(ctx->key); + return -EINVAL; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed448_set_priv %d\n", keylen); + #endif + return 0; +} +#else /* !LINUXKM_ED448_SIGN */ +static int km_ed448_set_priv(struct eddsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + (void)tfm; + (void)key; + (void)keylen; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_ED448_SIGN */ + +#ifdef LINUXKM_EDDSA_SIG_ALG +/* see km_ed25519_key_size(). */ +static unsigned int km_ed448_key_size(struct crypto_sig *tfm) +{ + (void)tfm; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + return ED448_PUB_KEY_SIZE * WOLFSSL_BIT_SIZE; + #else + return ED448_PUB_KEY_SIZE; + #endif +} + +/* see km_ed25519_digest_size(). */ +static unsigned int km_ed448_digest_size(struct crypto_sig *tfm) +{ + (void)tfm; + return 0; +} + +static unsigned int km_ed448_max_size(struct crypto_sig *tfm) +{ + (void)tfm; + return ED448_SIG_SIZE; +} +#else /* !LINUXKM_EDDSA_SIG_ALG */ +static unsigned int km_ed448_max_size(struct crypto_akcipher *tfm) +{ + (void)tfm; + return ED448_SIG_SIZE; +} +#endif /* !LINUXKM_EDDSA_SIG_ALG */ + +static void km_ed448_exit(struct eddsa_tfm_type *tfm) +{ + struct km_ed448_ctx * ctx = NULL; + + ctx = eddsa_tfm_ctx_cb(tfm); + + if (ctx->key) { + wc_ed448_free(ctx->key); + free(ctx->key); + ctx->key = NULL; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed448_exit\n"); + #endif + return; +} + +static int km_ed448_init(struct eddsa_tfm_type *tfm) +{ + struct km_ed448_ctx *ctx = eddsa_tfm_ctx_cb(tfm); + int ret = 0; + + XMEMSET(ctx, 0, sizeof(struct km_ed448_ctx)); + + ctx->key = (ed448_key *)malloc(sizeof(ed448_key)); + if (!ctx->key) + return -ENOMEM; + + ret = wc_ed448_init(ctx->key); + if (ret < 0) { + free(ctx->key); + ctx->key = NULL; + return -ENOMEM; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed448_init\n"); + #endif + return 0; +} + +#ifdef LINUXKM_EDDSA_SIG_ALG + +/* + * Verify an ed448 signature (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw RFC 8032 signature, R || S. + * - slen must == ED448_SIG_SIZE (114). + * + * digest: + * - the raw message. Pure Ed448 with the default (empty) context + * verifies the message itself -- no prehashing occurs, and dlen is + * unrestricted. + * + * See kernel (6.13 or later): + * - include/crypto/sig.h + */ +static int km_ed448_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct km_ed448_ctx *ctx = crypto_sig_ctx(tfm); +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + ed448_key key_copy; +#endif + ed448_key *key = NULL; + int result = -1; + int err = -1; + + if (src == NULL || digest == NULL) + return -EINVAL; + + if ((ctx->key == NULL) || (! ctx->key->pubKeySet)) + return -EINVAL; + + if (slen != ED448_SIG_SIZE) + return -EINVAL; + +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + /* wc_ed448_verify_msg() advances the key's persistent SHAKE256 state, + * but callers of the kernel crypto API are entitled to issue concurrent + * verifies on a single tfm, so operate on a transient copy of the + * tfm's imported key. ed448_key is pure POD as configured for linuxkm + * (no owned allocations), making the struct copy sound, and the copy + * holds only public material, so it's simply discarded. + * + * Note that wc_Sha3 has no suballocated members, so the transient copy here + * is unconditionally safe. + */ + key_copy = *ctx->key; + key = &key_copy; +#else + key = ctx->key; +#endif + + /* NULL/0: the RFC 8032 default (empty) Ed448 context. */ + err = wc_ed448_verify_msg((const byte *)src, (word32)slen, + (const byte *)digest, (word32)dlen, + &result, key, NULL, 0); + + if (err) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("error: %s: ed448 verify: verify_msg returned: %d\n", + WOLFKM_ED448_DRIVER, err); + #endif + err = -EBADMSG; + goto ed448_verify_end; + } + + if (result != 1) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("info: %s: ed448 verify: verify fail: %d\n", + WOLFKM_ED448_DRIVER, result); + #endif + err = -EBADMSG; + goto ed448_verify_end; + } + +ed448_verify_end: + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed448_verify dlen %d, slen %d, " + "err %d, result %d\n", dlen, slen, err, result); + #endif + return err; +} + +/* + * Sign a message with ED448 (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw message. Pure Ed448 signs the message itself -- no + * prehashing occurs, and slen is unrestricted. + * The default (empty) Ed448 context is used. + * + * dst: + * - receives the raw RFC 8032 signature, R || S. + * - dlen must be >= ED448_SIG_SIZE (114), else -EOVERFLOW (following the + * convention of rsassa_pkcs1_sign()). + * + * Returns the signature size on success, per the crypto_sig_sign() + * contract. Ed448 signing is deterministic (RFC 8032) -- no RNG is + * involved. + */ +#ifdef LINUXKM_ED448_SIGN +static int km_ed448_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct km_ed448_ctx *ctx = crypto_sig_ctx(tfm); +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + ed448_key key_copy; +#endif + ed448_key *key = NULL; + word32 out_len = ED448_SIG_SIZE; + int err = -1; + + if (src == NULL || dst == NULL) + return -EINVAL; + + if ((ctx->key == NULL) || + (! ctx->key->privKeySet) || + (! ctx->key->pubKeySet)) + { + return -EINVAL; + } + + if (dlen < ED448_SIG_SIZE) + return -EOVERFLOW; + +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + /* as in km_ed448_verify(), wc_ed448_sign_msg() advances the key's + * persistent SHAKE256 state, so operate on a transient copy of the + * tfm's key. Unlike the verify path, the copy holds private + * material, so it's zeroized before return. + */ + key_copy = *ctx->key; + key = &key_copy; +#else + /* without a persistent SHAKE256, wc_ed448_sign_msg() leaves the key + * unmodified, so the shared tfm key can be used directly. */ + key = ctx->key; +#endif + + err = wc_ed448_sign_msg((const byte *)src, (word32)slen, + (byte *)dst, &out_len, key, + NULL, 0); + +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + ForceZero(&key_copy, sizeof(key_copy)); +#endif + + if (err || (out_len != ED448_SIG_SIZE)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("error: %s: ed448 sign: sign_msg returned: %d, " + "out_len %u\n", WOLFKM_ED448_DRIVER, err, out_len); + #endif + return -EINVAL; + } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed448_sign slen %d\n", slen); + #endif + return (int)out_len; +} +#else /* !LINUXKM_ED448_SIGN */ +static int km_ed448_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + (void)tfm; + (void)src; + (void)slen; + (void)dst; + (void)dlen; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_ED448_SIGN */ + +#else /* !LINUXKM_EDDSA_SIG_ALG */ + +/* + * Verify an ed448 signature. + * + * The total size of req->src is src_len + dst_len: + * - src_len: signature (raw RFC 8032 R || S, must be ED448_SIG_SIZE) + * - dst_len: message (raw, unhashed, any length) + * + * dst should be null. + * See kernel: + * - include/crypto/akcipher.h + */ +static int km_ed448_verify(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_ed448_ctx * ctx = NULL; +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + ed448_key key_copy; +#endif + ed448_key * key = NULL; + byte * sig = NULL; + word32 sig_len = 0; + byte * msg = NULL; + word32 msg_len = 0; + int result = -1; + int err = -1; + + if (req->src == NULL || req->dst != NULL) { + return -EINVAL; + } + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + if ((ctx->key == NULL) || (! ctx->key->pubKeySet)) { + return -EINVAL; + } + + sig_len = req->src_len; + msg_len = req->dst_len; + + if (sig_len != ED448_SIG_SIZE) { + err = -EINVAL; + goto ed448_verify_end; + } + + if ((sig_len + msg_len) != ((word64)sig_len + (word64)msg_len)) { + err = -EINVAL; + goto ed448_verify_end; + } + + sig = malloc(sig_len + msg_len); + if (unlikely(sig == NULL)) { + err = -ENOMEM; + goto ed448_verify_end; + } + + msg = sig + sig_len; + + XMEMSET(sig, 0, sig_len + msg_len); + + /* copy sig and msg from req->src to sig and contiguous msg buffer. */ + scatterwalk_map_and_copy(sig, req->src, 0, sig_len + msg_len, 0); + +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + /* see the analogous comment in the sig_alg edition of + * km_ed448_verify(). */ + key_copy = *ctx->key; + key = &key_copy; +#else + key = ctx->key; +#endif + + /* NULL/0: the RFC 8032 default (empty) Ed448 context. */ + err = wc_ed448_verify_msg(sig, sig_len, msg, msg_len, &result, key, + NULL, 0); + + if (err) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("error: %s: ed448 verify: verify_msg returned: %d\n", + WOLFKM_ED448_DRIVER, err); + #endif + err = -EBADMSG; + goto ed448_verify_end; + } + + if (result != 1) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("info: %s: ed448 verify: verify fail: %d\n", + WOLFKM_ED448_DRIVER, result); + #endif + err = -EBADMSG; + goto ed448_verify_end; + } + +ed448_verify_end: + + free(sig); + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed448_verify msg_len %d, sig_len %d, " + "err %d, result %d\n", msg_len, sig_len, err, result); + #endif + return err; +} + +/* + * Sign a message with ed448. + * + * req->src: the raw message (src_len bytes, unrestricted). + * The default (empty) Ed448 context is used. + * req->dst: receives the raw RFC 8032 signature, R || S + * (ED448_SIG_SIZE bytes). Per include/crypto/akcipher.h, if + * dst_len is insufficient it's updated to the required size + * and -EOVERFLOW is returned; on success it's updated to the + * actual size. + * + * Ed448 signing is deterministic (RFC 8032) -- no RNG is involved. + */ +#ifdef LINUXKM_ED448_SIGN +static int km_ed448_sign(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_ed448_ctx * ctx = NULL; +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + ed448_key key_copy; +#endif + ed448_key * key = NULL; + byte * msg = NULL; + word32 msg_len = 0; + byte sig[ED448_SIG_SIZE]; + word32 out_len = ED448_SIG_SIZE; + int err = -1; + + if (req->src == NULL || req->dst == NULL) + return -EINVAL; + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + if ((ctx->key == NULL) || + (! ctx->key->privKeySet) || + (! ctx->key->pubKeySet)) + { + return -EINVAL; + } + + if (req->dst_len < ED448_SIG_SIZE) { + req->dst_len = ED448_SIG_SIZE; + return -EOVERFLOW; + } + + msg_len = req->src_len; + + /* allocate at least 1 byte, to assure a non-null msg pointer for + * zero-length messages (msg_len 0 is legal for pure Ed448). */ + msg = malloc(msg_len ? msg_len : 1); + if (unlikely(msg == NULL)) { + err = -ENOMEM; + goto ed448_sign_end; + } + + /* copy the message from req->src to the contiguous msg buffer. */ + scatterwalk_map_and_copy(msg, req->src, 0, msg_len, 0); + +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + /* see the analogous comment in the sig_alg edition of + * km_ed448_sign(). */ + key_copy = *ctx->key; + key = &key_copy; +#else + key = ctx->key; +#endif + + err = wc_ed448_sign_msg(msg, msg_len, sig, &out_len, key, + NULL, 0); + +#ifdef WOLFSSL_ED448_PERSISTENT_SHA + ForceZero(&key_copy, sizeof(key_copy)); +#endif + + if (err || (out_len != ED448_SIG_SIZE)) { + #ifdef WOLFKM_DEBUG_EDDSA + pr_err("error: %s: ed448 sign: sign_msg returned: %d, " + "out_len %u\n", WOLFKM_ED448_DRIVER, err, out_len); + #endif + err = -EINVAL; + goto ed448_sign_end; + } + + /* copy the signature out to req->dst. */ + scatterwalk_map_and_copy(sig, req->dst, 0, out_len, 1); + req->dst_len = out_len; + err = 0; + +ed448_sign_end: + + free(msg); + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: exiting km_ed448_sign msg_len %d, err %d\n", + msg_len, err); + #endif + return err; +} +#else /* !LINUXKM_ED448_SIGN */ +static int km_ed448_sign(struct akcipher_request *req) +{ + (void)req; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_ED448_SIGN */ + +#endif /* !LINUXKM_EDDSA_SIG_ALG */ + +#endif /* LINUXKM_LKCAPI_REGISTER_ED448 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED25519 +static int linuxkm_test_ed25519(void) +{ + int rc = 0; + /* reference value from RFC 8032 section 7.1 (TEST 2) */ + /* 32 byte pub key */ + static const byte ed25519_pub[] = { + 0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a, + 0x92, 0xb7, 0x0a, 0xa7, 0x4d, 0x1b, 0x7e, 0xbc, + 0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c, + 0xc0, 0xcd, 0x55, 0xf1, 0x2a, 0xf4, 0x66, 0x0c + }; + + /* 1 byte msg */ + static const byte msg[] = { + 0x72 + }; + + /* 64 byte sig */ + static const byte sig[] = { + 0x92, 0xa0, 0x09, 0xa9, 0xf0, 0xd4, 0xca, 0xb8, + 0x72, 0x0e, 0x82, 0x0b, 0x5f, 0x64, 0x25, 0x40, + 0xa2, 0xb2, 0x7b, 0x54, 0x16, 0x50, 0x3f, 0x8f, + 0xb3, 0x76, 0x22, 0x23, 0xeb, 0xdb, 0x69, 0xda, + 0x08, 0x5a, 0xc1, 0xe4, 0x3e, 0x15, 0x99, 0x6e, + 0x45, 0x8f, 0x36, 0x13, 0xd0, 0xf1, 0x1d, 0x8c, + 0x38, 0x7b, 0x2e, 0xae, 0xb4, 0x30, 0x2a, 0xee, + 0xb0, 0x0d, 0x29, 0x16, 0x12, 0xbb, 0x0c, 0x00 + }; + /* 32 byte private key (the RFC 8032 "seed") */ + static const byte ed25519_priv[] = { + 0x4c, 0xcd, 0x08, 0x9b, 0x28, 0xff, 0x96, 0xda, + 0x9d, 0xb6, 0xc3, 0x46, 0xec, 0x11, 0x4e, 0x0f, + 0x5b, 0x8a, 0x31, 0x9f, 0x35, 0xab, 0xa6, 0x24, + 0xda, 0x8c, 0xf6, 0xed, 0x4f, 0xb8, 0xa6, 0xfb + }; + word32 pub_len = 0; + word32 sig_len = 0; + word32 msg_len = 0; + + pub_len = sizeof(ed25519_pub); + msg_len = sizeof(msg); + sig_len = sizeof(sig); + + rc = linuxkm_test_eddsa_driver(WOLFKM_ED25519_DRIVER, + ed25519_pub, pub_len, + ed25519_priv, + (word32)sizeof(ed25519_priv), +#ifdef LINUXKM_ED25519_SIGN + 1, +#else + 0, +#endif + sig, sig_len, + msg, msg_len); + return rc; +} +#endif /* LINUXKM_LKCAPI_REGISTER_ED25519 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED448 +static int linuxkm_test_ed448(void) +{ + int rc = 0; + /* reference value from RFC 8032 section 7.4 (1 octet) */ + /* 57 byte pub key */ + static const byte ed448_pub[] = { + 0x43, 0xba, 0x28, 0xf4, 0x30, 0xcd, 0xff, 0x45, + 0x6a, 0xe5, 0x31, 0x54, 0x5f, 0x7e, 0xcd, 0x0a, + 0xc8, 0x34, 0xa5, 0x5d, 0x93, 0x58, 0xc0, 0x37, + 0x2b, 0xfa, 0x0c, 0x6c, 0x67, 0x98, 0xc0, 0x86, + 0x6a, 0xea, 0x01, 0xeb, 0x00, 0x74, 0x28, 0x02, + 0xb8, 0x43, 0x8e, 0xa4, 0xcb, 0x82, 0x16, 0x9c, + 0x23, 0x51, 0x60, 0x62, 0x7b, 0x4c, 0x3a, 0x94, + 0x80 + }; + + /* 1 byte msg */ + static const byte msg[] = { + 0x03 + }; + + /* 114 byte sig */ + static const byte sig[] = { + 0x26, 0xb8, 0xf9, 0x17, 0x27, 0xbd, 0x62, 0x89, + 0x7a, 0xf1, 0x5e, 0x41, 0xeb, 0x43, 0xc3, 0x77, + 0xef, 0xb9, 0xc6, 0x10, 0xd4, 0x8f, 0x23, 0x35, + 0xcb, 0x0b, 0xd0, 0x08, 0x78, 0x10, 0xf4, 0x35, + 0x25, 0x41, 0xb1, 0x43, 0xc4, 0xb9, 0x81, 0xb7, + 0xe1, 0x8f, 0x62, 0xde, 0x8c, 0xcd, 0xf6, 0x33, + 0xfc, 0x1b, 0xf0, 0x37, 0xab, 0x7c, 0xd7, 0x79, + 0x80, 0x5e, 0x0d, 0xbc, 0xc0, 0xaa, 0xe1, 0xcb, + 0xce, 0xe1, 0xaf, 0xb2, 0xe0, 0x27, 0xdf, 0x36, + 0xbc, 0x04, 0xdc, 0xec, 0xbf, 0x15, 0x43, 0x36, + 0xc1, 0x9f, 0x0a, 0xf7, 0xe0, 0xa6, 0x47, 0x29, + 0x05, 0xe7, 0x99, 0xf1, 0x95, 0x3d, 0x2a, 0x0f, + 0xf3, 0x34, 0x8a, 0xb2, 0x1a, 0xa4, 0xad, 0xaf, + 0xd1, 0xd2, 0x34, 0x44, 0x1c, 0xf8, 0x07, 0xc0, + 0x3a, 0x00 + }; + /* 57 byte private key (the RFC 8032 "seed") */ + static const byte ed448_priv[] = { + 0xc4, 0xea, 0xb0, 0x5d, 0x35, 0x70, 0x07, 0xc6, + 0x32, 0xf3, 0xdb, 0xb4, 0x84, 0x89, 0x92, 0x4d, + 0x55, 0x2b, 0x08, 0xfe, 0x0c, 0x35, 0x3a, 0x0d, + 0x4a, 0x1f, 0x00, 0xac, 0xda, 0x2c, 0x46, 0x3a, + 0xfb, 0xea, 0x67, 0xc5, 0xe8, 0xd2, 0x87, 0x7c, + 0x5e, 0x3b, 0xc3, 0x97, 0xa6, 0x59, 0x94, 0x9e, + 0xf8, 0x02, 0x1e, 0x95, 0x4e, 0x0a, 0x12, 0x27, + 0x4e + }; + word32 pub_len = 0; + word32 sig_len = 0; + word32 msg_len = 0; + + pub_len = sizeof(ed448_pub); + msg_len = sizeof(msg); + sig_len = sizeof(sig); + + rc = linuxkm_test_eddsa_driver(WOLFKM_ED448_DRIVER, + ed448_pub, pub_len, + ed448_priv, + (word32)sizeof(ed448_priv), +#ifdef LINUXKM_ED448_SIGN + 1, +#else + 0, +#endif + sig, sig_len, + msg, msg_len); + return rc; +} +#endif /* LINUXKM_LKCAPI_REGISTER_ED448 */ + +#ifdef LINUXKM_EDDSA_SIG_ALG + +static int linuxkm_test_eddsa_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * priv, word32 priv_len, + int expect_sign, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_sig * tfm = NULL; + byte * sig_copy = NULL; + + /* allocate a mutable copy of the signature, for the corruption test. */ + sig_copy = (byte *)malloc(sig_len); + if (! sig_copy) { + pr_err("error: allocating sig_copy buffer failed.\n"); + test_rc = MEMORY_E; + goto test_eddsa_end; + } + XMEMCPY(sig_copy, sig, sig_len); + + /* + * Allocate the sig transform. + */ + tfm = crypto_alloc_sig(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating sig algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_eddsa_end; + } + + /* now set pub key for verify test. */ + ret = crypto_sig_set_pubkey(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_sig_set_pubkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + { + /* The behavior of crypto_sig_Xsize (X= max, key, digest) changed + * at linux kernel v6.15.3: + * < 6.15.3: keysize is in bytes. + * >= 6.15.3: keysize is in bits, maxsize and digestsize in + * bytes. */ + unsigned int maxsize = crypto_sig_maxsize(tfm); + unsigned int keysize = crypto_sig_keysize(tfm); + unsigned int digestsize = crypto_sig_digestsize(tfm); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + keysize = ((keysize + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE); + #endif /* linux >= 6.15.3 */ + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: crypto_sig_{max, key, digest}size: " + "{%d, %d, %d}\n", + maxsize, keysize, digestsize); + #endif + + if ((keysize != pub_len) || + (maxsize != sig_len) || + (digestsize != 0U)) + { + pr_err("error: crypto_sig_{max, key, digest}size " + "returned {%u, %u, %u}, expected {%u, %u, %u}\n", + maxsize, keysize, digestsize, + sig_len, pub_len, 0U); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + } + + ret = crypto_sig_verify(tfm, sig_copy, sig_len, msg, msg_len); + if (ret) { + pr_err("error: crypto_sig_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + /* corrupt the signature -- verify should now fail. */ + sig_copy[0] ^= 1U; + + ret = crypto_sig_verify(tfm, sig_copy, sig_len, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify returned %d, expected %d\n", + ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + /* sign tests. set the priv key; on verify-only builds of this glue + * the set_priv_key callback is an -EOPNOTSUPP stub (per the + * convention of the in-tree ML-DSA), which is itself checked. */ + ret = crypto_sig_set_privkey(tfm, priv, priv_len); + if (! expect_sign) { + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_sig_set_privkey returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + } + else { + byte * sig_out = NULL; + + if (ret) { + pr_err("error: crypto_sig_set_privkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + sig_out = (byte *)malloc(sig_len); + if (! sig_out) { + pr_err("error: allocating sig_out buffer failed.\n"); + test_rc = MEMORY_E; + goto test_eddsa_end; + } + + /* EdDSA signing is deterministic (RFC 8032) -- the signature + * must match the KAT value byte-exactly. */ + ret = crypto_sig_sign(tfm, msg, msg_len, sig_out, sig_len); + if (ret != (int)sig_len) { + pr_err("error: crypto_sig_sign returned %d, expected %d\n", + ret, (int)sig_len); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + if (XMEMCMP(sig_out, sig, sig_len) != 0) { + pr_err("error: crypto_sig_sign produced wrong signature\n"); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + /* a short dst must be rejected with -EOVERFLOW. */ + ret = crypto_sig_sign(tfm, msg, msg_len, sig_out, sig_len - 1); + free(sig_out); + if (ret != -EOVERFLOW) { + pr_err("error: crypto_sig_sign returned %d, expected %d\n", + ret, -EOVERFLOW); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + } + + test_rc = 0; +test_eddsa_end: + if (tfm) + crypto_free_sig(tfm); + free(sig_copy); + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#else /* !LINUXKM_EDDSA_SIG_ALG */ + +static int linuxkm_test_eddsa_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * priv, word32 priv_len, + int expect_sign, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_akcipher * tfm = NULL; + struct akcipher_request * req = NULL; + struct scatterlist src_tab[2]; + byte * param_copy = NULL; + byte * bad_sig = NULL; + + /* Allocate param_copy -- scatterwalk_map_and_copy() unmaps the buffers in + * the sg list, so we can't safely use the passed pointers directly. + */ + param_copy = (byte *)malloc(sig_len + msg_len); + if (! param_copy) { + pr_err("error: allocating param_copy buffer failed.\n"); + test_rc = MEMORY_E; + goto test_eddsa_end; + } + XMEMCPY(param_copy, sig, sig_len); + sig = param_copy; + XMEMCPY(param_copy + sig_len, msg, msg_len); + msg = param_copy + sig_len; + + /* + * Allocate the akcipher transform, and set up + * the akcipher request. + */ + tfm = crypto_alloc_akcipher(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating akcipher algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_eddsa_end; + } + + req = akcipher_request_alloc(tfm, GFP_KERNEL); + if (! req) { + test_rc = -ENOMEM; + pr_err("error: allocating akcipher request %s failed\n", + driver); + goto test_eddsa_end; + } + + /* now set pub key for verify test. */ + ret = crypto_akcipher_set_pub_key(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_akcipher_set_pub_key returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + { + unsigned int maxsize = crypto_akcipher_maxsize(tfm); + if ((int) maxsize <= 0) { + pr_err("error: crypto_akcipher_maxsize " + "returned %d\n", maxsize); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + } + + /* + * Set sig as src, and null as dst. + * src_tab is: + * src_tab[0]: signature + * src_tab[1]: message + * + * src_len is sig size + * dst_len is msg size. + */ + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], sig, sig_len); + sg_set_buf(&src_tab[1], msg, msg_len); + + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret) { + pr_err("error: crypto_akcipher_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + /* prepare a bad signature */ + bad_sig = malloc(sig_len); + if (bad_sig == NULL) { + pr_err("error: alloc sig failed\n"); + test_rc = MEMORY_E; + goto test_eddsa_end; + } + + XMEMCPY(bad_sig, sig, sig_len); + bad_sig[sig_len/2] ^= 1; + + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], bad_sig, sig_len); + sg_set_buf(&src_tab[1], msg, msg_len); + + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + /* it should fail */ + ret = crypto_akcipher_verify(req); + if (ret != -EBADMSG) { + pr_err("error: crypto_akcipher_verify returned %d, expected %d\n", + ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + /* sign tests. set the priv key; on verify-only builds of this glue + * the set_priv_key callback is an -EOPNOTSUPP stub (per the + * convention of the in-tree ML-DSA), which is itself checked. */ + ret = crypto_akcipher_set_priv_key(tfm, priv, priv_len); + if (! expect_sign) { + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_akcipher_set_priv_key returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + } + else { + byte * sig_out = NULL; + struct scatterlist sign_src[1]; + struct scatterlist sign_dst[1]; + + if (ret) { + pr_err("error: crypto_akcipher_set_priv_key returned: %d\n", + ret); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + sig_out = (byte *)malloc(sig_len); + if (! sig_out) { + pr_err("error: allocating sig_out buffer failed.\n"); + test_rc = MEMORY_E; + goto test_eddsa_end; + } + + /* msg still points into param_copy. */ + sg_init_table(sign_src, 1); + sg_set_buf(&sign_src[0], msg, msg_len); + sg_init_table(sign_dst, 1); + sg_set_buf(&sign_dst[0], sig_out, sig_len); + + akcipher_request_set_crypt(req, sign_src, sign_dst, msg_len, + sig_len); + + /* EdDSA signing is deterministic (RFC 8032) -- the signature + * must match the KAT value byte-exactly. */ + ret = crypto_akcipher_sign(req); + if ((ret != 0) || (req->dst_len != sig_len)) { + pr_err("error: crypto_akcipher_sign returned %d, " + "dst_len %u\n", ret, req->dst_len); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + if (XMEMCMP(sig_out, sig, sig_len) != 0) { + pr_err("error: crypto_akcipher_sign produced wrong " + "signature\n"); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + + /* a short dst must be rejected with -EOVERFLOW, with dst_len + * updated to the required size. */ + akcipher_request_set_crypt(req, sign_src, sign_dst, msg_len, + sig_len - 1); + ret = crypto_akcipher_sign(req); + free(sig_out); + if ((ret != -EOVERFLOW) || (req->dst_len != sig_len)) { + pr_err("error: crypto_akcipher_sign returned %d, " + "dst_len %u, expected %d, %u\n", + ret, req->dst_len, -EOVERFLOW, sig_len); + test_rc = BAD_FUNC_ARG; + goto test_eddsa_end; + } + } + + test_rc = 0; +test_eddsa_end: + if (req) { akcipher_request_free(req); req = NULL; } + if (tfm) { crypto_free_akcipher(tfm); tfm = NULL; } + if (param_copy) { free(param_copy); } + if (bad_sig) { free(bad_sig); bad_sig = NULL; } + + #ifdef WOLFKM_DEBUG_EDDSA + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#endif /* !LINUXKM_EDDSA_SIG_ALG */ + +#endif /* LINUXKM_LKCAPI_REGISTER_ED25519 || LINUXKM_LKCAPI_REGISTER_ED448 */ + +#endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/linuxkm/lkcapi_glue.c b/linuxkm/lkcapi_glue.c index d4b9c70d0d..6ecf24fda0 100644 --- a/linuxkm/lkcapi_glue.c +++ b/linuxkm/lkcapi_glue.c @@ -215,12 +215,33 @@ WC_MAYBE_UNUSED static int check_shash_driver_masking(struct crypto_shash *tfm, static wolfSSL_Atomic_Int linuxkm_lkcapi_registering_now = WOLFSSL_ATOMIC_INITIALIZER(0); +/* Default builds define HAVE_ALL_CURVES rather than the individual HAVE_ECC192 + * and HAVE_ECC521, so keying on HAVE_ECC192 and HAVE_ECC521 alone would leave + * those curves out of default builds. */ +#if (defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)) && \ + ECC_MIN_KEY_SZ <= 192 && !defined(CONFIG_CRYPTO_FIPS) && \ + !defined(LINUXKM_ECC192) + /* only register p192 if enabled specifically or via _ALL, and not if the + * target kernel is FIPS. */ + #define LINUXKM_ECC192 +#endif +#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + (ECC_MIN_KEY_SZ <= 521) && !defined(LINUXKM_ECC521) + #define LINUXKM_ECC521 +#endif + #include "lkcapi_aes_glue.c" #include "lkcapi_sha_glue.c" /* must be included before the PK glue, to make the * crypto_default_rng usable therein when * LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT. */ #include "lkcapi_ecdsa_glue.c" +#include "lkcapi_ed_glue.c" +#include "lkcapi_mldsa_glue.c" +#include "lkcapi_slhdsa_glue.c" +#include "lkcapi_lms_glue.c" +#include "lkcapi_xmss_glue.c" +#include "lkcapi_mlkem_glue.c" #include "lkcapi_ecdh_glue.c" #include "lkcapi_rsa_glue.c" #include "lkcapi_dh_glue.c" @@ -573,10 +594,10 @@ static int linuxkm_lkcapi_register(void) REGISTER_ALG(ecdsa_nist_p384, sig, linuxkm_test_ecdsa_nist_p384); - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) REGISTER_ALG(ecdsa_nist_p521, sig, linuxkm_test_ecdsa_nist_p521); - #endif /* HAVE_ECC521 */ + #endif /* LINUXKM_ECC521 */ #elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) && \ defined(HAVE_FIPS) && defined(CONFIG_CRYPTO_FIPS) && \ defined(WC_LINUX_CONFIG_SELFTESTS) @@ -595,10 +616,10 @@ static int linuxkm_lkcapi_register(void) REGISTER_ALG_OPTIONAL(ecdsa_nist_p384, akcipher, linuxkm_test_ecdsa_nist_p384); - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) REGISTER_ALG_OPTIONAL(ecdsa_nist_p521, akcipher, linuxkm_test_ecdsa_nist_p521); - #endif /* HAVE_ECC521 */ + #endif /* LINUXKM_ECC521 */ #else /* kernel 6.3-6.12 */ #if defined(LINUXKM_ECC192) REGISTER_ALG(ecdsa_nist_p192, akcipher, @@ -611,10 +632,10 @@ static int linuxkm_lkcapi_register(void) REGISTER_ALG(ecdsa_nist_p384, akcipher, linuxkm_test_ecdsa_nist_p384); - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) REGISTER_ALG(ecdsa_nist_p521, akcipher, linuxkm_test_ecdsa_nist_p521); - #endif /* HAVE_ECC521 */ + #endif /* LINUXKM_ECC521 */ #endif /* kernel 6.3-6.12 */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) && \ @@ -624,6 +645,175 @@ static int linuxkm_lkcapi_register(void) #endif /* LINUXKM_LKCAPI_REGISTER_ECDSA */ +#ifdef LINUXKM_LKCAPI_REGISTER_ED25519 + /* the "ed25519"/"ed448" cra_names have no crypto/testmgr.c entries, so + * alg_test() takes its "notest" path and passes them, with or without + * fips_enabled -- no REGISTER_ALG_OPTIONAL needed. + */ + #ifdef LINUXKM_EDDSA_SIG_ALG + REGISTER_ALG(ed25519, sig, linuxkm_test_ed25519); + #else /* !LINUXKM_EDDSA_SIG_ALG */ + REGISTER_ALG(ed25519, akcipher, linuxkm_test_ed25519); + #endif /* !LINUXKM_EDDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_ED25519 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED448 + #ifdef LINUXKM_EDDSA_SIG_ALG + REGISTER_ALG(ed448, sig, linuxkm_test_ed448); + #else /* !LINUXKM_EDDSA_SIG_ALG */ + REGISTER_ALG(ed448, akcipher, linuxkm_test_ed448); + #endif /* !LINUXKM_EDDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_ED448 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_MLDSA + /* the "mldsa44"/"mldsa65"/"mldsa87" cra_names currently have no + * crypto/testmgr.c entries, so alg_test() takes its "notest" path and + * passes them, with or without fips_enabled -- no REGISTER_ALG_OPTIONAL + * needed. If/when testmgr vectors land upstream, registration will + * transparently become subject to them. + */ + #ifdef LINUXKM_MLDSA_SIG_ALG + #ifdef LINUXKM_MLDSA44 + REGISTER_ALG(mldsa44, sig, linuxkm_test_mldsa44); + #endif /* LINUXKM_MLDSA44 */ + #ifdef LINUXKM_MLDSA65 + REGISTER_ALG(mldsa65, sig, linuxkm_test_mldsa65); + #endif /* LINUXKM_MLDSA65 */ + #ifdef LINUXKM_MLDSA87 + REGISTER_ALG(mldsa87, sig, linuxkm_test_mldsa87); + #endif /* LINUXKM_MLDSA87 */ + #else /* !LINUXKM_MLDSA_SIG_ALG */ + #ifdef LINUXKM_MLDSA44 + REGISTER_ALG(mldsa44, akcipher, linuxkm_test_mldsa44); + #endif /* LINUXKM_MLDSA44 */ + #ifdef LINUXKM_MLDSA65 + REGISTER_ALG(mldsa65, akcipher, linuxkm_test_mldsa65); + #endif /* LINUXKM_MLDSA65 */ + #ifdef LINUXKM_MLDSA87 + REGISTER_ALG(mldsa87, akcipher, linuxkm_test_mldsa87); + #endif /* LINUXKM_MLDSA87 */ + #endif /* !LINUXKM_MLDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_MLDSA */ + +#ifdef LINUXKM_LKCAPI_REGISTER_SLHDSA + /* as with mldsa, the slh-dsa-* cra_names have no crypto/testmgr.c + * entries on any kernel version, so alg_test() takes its "notest" + * path and passes them, with or without fips_enabled. */ + #ifdef LINUXKM_SLHDSA_SIG_ALG + #ifdef LINUXKM_SLHDSA_SHAKE_128S + REGISTER_ALG(slhdsa_shake_128s, sig, linuxkm_test_slhdsa_shake_128s); + #endif /* LINUXKM_SLHDSA_SHAKE_128S */ + #ifdef LINUXKM_SLHDSA_SHAKE_128F + REGISTER_ALG(slhdsa_shake_128f, sig, linuxkm_test_slhdsa_shake_128f); + #endif /* LINUXKM_SLHDSA_SHAKE_128F */ + #ifdef LINUXKM_SLHDSA_SHAKE_192S + REGISTER_ALG(slhdsa_shake_192s, sig, linuxkm_test_slhdsa_shake_192s); + #endif /* LINUXKM_SLHDSA_SHAKE_192S */ + #ifdef LINUXKM_SLHDSA_SHAKE_192F + REGISTER_ALG(slhdsa_shake_192f, sig, linuxkm_test_slhdsa_shake_192f); + #endif /* LINUXKM_SLHDSA_SHAKE_192F */ + #ifdef LINUXKM_SLHDSA_SHAKE_256S + REGISTER_ALG(slhdsa_shake_256s, sig, linuxkm_test_slhdsa_shake_256s); + #endif /* LINUXKM_SLHDSA_SHAKE_256S */ + #ifdef LINUXKM_SLHDSA_SHAKE_256F + REGISTER_ALG(slhdsa_shake_256f, sig, linuxkm_test_slhdsa_shake_256f); + #endif /* LINUXKM_SLHDSA_SHAKE_256F */ + #ifdef LINUXKM_SLHDSA_SHA2_128S + REGISTER_ALG(slhdsa_sha2_128s, sig, linuxkm_test_slhdsa_sha2_128s); + #endif /* LINUXKM_SLHDSA_SHA2_128S */ + #ifdef LINUXKM_SLHDSA_SHA2_128F + REGISTER_ALG(slhdsa_sha2_128f, sig, linuxkm_test_slhdsa_sha2_128f); + #endif /* LINUXKM_SLHDSA_SHA2_128F */ + #ifdef LINUXKM_SLHDSA_SHA2_192S + REGISTER_ALG(slhdsa_sha2_192s, sig, linuxkm_test_slhdsa_sha2_192s); + #endif /* LINUXKM_SLHDSA_SHA2_192S */ + #ifdef LINUXKM_SLHDSA_SHA2_192F + REGISTER_ALG(slhdsa_sha2_192f, sig, linuxkm_test_slhdsa_sha2_192f); + #endif /* LINUXKM_SLHDSA_SHA2_192F */ + #ifdef LINUXKM_SLHDSA_SHA2_256S + REGISTER_ALG(slhdsa_sha2_256s, sig, linuxkm_test_slhdsa_sha2_256s); + #endif /* LINUXKM_SLHDSA_SHA2_256S */ + #ifdef LINUXKM_SLHDSA_SHA2_256F + REGISTER_ALG(slhdsa_sha2_256f, sig, linuxkm_test_slhdsa_sha2_256f); + #endif /* LINUXKM_SLHDSA_SHA2_256F */ + #else /* !LINUXKM_SLHDSA_SIG_ALG */ + #ifdef LINUXKM_SLHDSA_SHAKE_128S + REGISTER_ALG(slhdsa_shake_128s, akcipher, linuxkm_test_slhdsa_shake_128s); + #endif /* LINUXKM_SLHDSA_SHAKE_128S */ + #ifdef LINUXKM_SLHDSA_SHAKE_128F + REGISTER_ALG(slhdsa_shake_128f, akcipher, linuxkm_test_slhdsa_shake_128f); + #endif /* LINUXKM_SLHDSA_SHAKE_128F */ + #ifdef LINUXKM_SLHDSA_SHAKE_192S + REGISTER_ALG(slhdsa_shake_192s, akcipher, linuxkm_test_slhdsa_shake_192s); + #endif /* LINUXKM_SLHDSA_SHAKE_192S */ + #ifdef LINUXKM_SLHDSA_SHAKE_192F + REGISTER_ALG(slhdsa_shake_192f, akcipher, linuxkm_test_slhdsa_shake_192f); + #endif /* LINUXKM_SLHDSA_SHAKE_192F */ + #ifdef LINUXKM_SLHDSA_SHAKE_256S + REGISTER_ALG(slhdsa_shake_256s, akcipher, linuxkm_test_slhdsa_shake_256s); + #endif /* LINUXKM_SLHDSA_SHAKE_256S */ + #ifdef LINUXKM_SLHDSA_SHAKE_256F + REGISTER_ALG(slhdsa_shake_256f, akcipher, linuxkm_test_slhdsa_shake_256f); + #endif /* LINUXKM_SLHDSA_SHAKE_256F */ + #ifdef LINUXKM_SLHDSA_SHA2_128S + REGISTER_ALG(slhdsa_sha2_128s, akcipher, linuxkm_test_slhdsa_sha2_128s); + #endif /* LINUXKM_SLHDSA_SHA2_128S */ + #ifdef LINUXKM_SLHDSA_SHA2_128F + REGISTER_ALG(slhdsa_sha2_128f, akcipher, linuxkm_test_slhdsa_sha2_128f); + #endif /* LINUXKM_SLHDSA_SHA2_128F */ + #ifdef LINUXKM_SLHDSA_SHA2_192S + REGISTER_ALG(slhdsa_sha2_192s, akcipher, linuxkm_test_slhdsa_sha2_192s); + #endif /* LINUXKM_SLHDSA_SHA2_192S */ + #ifdef LINUXKM_SLHDSA_SHA2_192F + REGISTER_ALG(slhdsa_sha2_192f, akcipher, linuxkm_test_slhdsa_sha2_192f); + #endif /* LINUXKM_SLHDSA_SHA2_192F */ + #ifdef LINUXKM_SLHDSA_SHA2_256S + REGISTER_ALG(slhdsa_sha2_256s, akcipher, linuxkm_test_slhdsa_sha2_256s); + #endif /* LINUXKM_SLHDSA_SHA2_256S */ + #ifdef LINUXKM_SLHDSA_SHA2_256F + REGISTER_ALG(slhdsa_sha2_256f, akcipher, linuxkm_test_slhdsa_sha2_256f); + #endif /* LINUXKM_SLHDSA_SHA2_256F */ + #endif /* !LINUXKM_SLHDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_SLHDSA */ + +#ifdef LINUXKM_LKCAPI_REGISTER_LMS + #ifdef LINUXKM_LMS_SIG_ALG + REGISTER_ALG(lms, sig, linuxkm_test_lms); + #else + REGISTER_ALG(lms, akcipher, linuxkm_test_lms); + #endif +#endif /* LINUXKM_LKCAPI_REGISTER_LMS */ + +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS + #ifdef LINUXKM_XMSS_SIG_ALG + REGISTER_ALG(xmss, sig, linuxkm_test_xmss); + #else + REGISTER_ALG(xmss, akcipher, linuxkm_test_xmss); + #endif +#endif /* LINUXKM_LKCAPI_REGISTER_XMSS */ + +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT + #ifdef LINUXKM_XMSS_SIG_ALG + REGISTER_ALG(xmssmt, sig, linuxkm_test_xmssmt); + #else + REGISTER_ALG(xmssmt, akcipher, linuxkm_test_xmssmt); + #endif +#endif /* LINUXKM_LKCAPI_REGISTER_XMSS_MT */ + +#ifdef LINUXKM_LKCAPI_REGISTER_MLKEM + /* kpp: single arm, no sig/akcipher edition fork (kpp is + * version-stable). */ + #ifdef LINUXKM_MLKEM512 + REGISTER_ALG(mlkem512, kpp, linuxkm_test_mlkem512); + #endif + #ifdef LINUXKM_MLKEM768 + REGISTER_ALG(mlkem768, kpp, linuxkm_test_mlkem768); + #endif + #ifdef LINUXKM_MLKEM1024 + REGISTER_ALG(mlkem1024, kpp, linuxkm_test_mlkem1024); + #endif +#endif /* LINUXKM_LKCAPI_REGISTER_MLKEM */ + #ifdef LINUXKM_LKCAPI_REGISTER_ECDH /* In kernels before 5.13.0, ecdh-nist-p256 was not recognized as @@ -654,6 +844,11 @@ static int linuxkm_lkcapi_register(void) REGISTER_ALG(ecdh_nist_p256, kpp, linuxkm_test_ecdh_nist_p256); REGISTER_ALG(ecdh_nist_p384, kpp, linuxkm_test_ecdh_nist_p384); #endif /* CONFIG_CRYPTO_FIPS && etc.. */ + #ifdef LINUXKM_ECC521 + /* no upstream P-521 ECDH, hence no testmgr entry: alg_test() takes + * its "notest" path (PQC-glue precedent). */ + REGISTER_ALG(ecdh_nist_p521, kpp, linuxkm_test_ecdh_nist_p521); + #endif /* LINUXKM_ECC521 */ #endif /* LINUXKM_LKCAPI_REGISTER_ECDH */ #ifdef LINUXKM_LKCAPI_REGISTER_RSA @@ -962,28 +1157,184 @@ static int linuxkm_lkcapi_unregister(void) #endif /* LINUXKM_ECC192 */ UNREGISTER_ALG(ecdsa_nist_p256, sig); UNREGISTER_ALG(ecdsa_nist_p384, sig); - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) UNREGISTER_ALG(ecdsa_nist_p521, sig); - #endif /* HAVE_ECC521 */ + #endif /* LINUXKM_ECC521 */ #else /* !LINUXKM_ECDSA_SIG_ALG */ #if defined(LINUXKM_ECC192) UNREGISTER_ALG(ecdsa_nist_p192, akcipher); #endif /* LINUXKM_ECC192 */ UNREGISTER_ALG(ecdsa_nist_p256, akcipher); UNREGISTER_ALG(ecdsa_nist_p384, akcipher); - #if defined(HAVE_ECC521) + #if defined(LINUXKM_ECC521) UNREGISTER_ALG(ecdsa_nist_p521, akcipher); - #endif /* HAVE_ECC521 */ + #endif /* LINUXKM_ECC521 */ #endif /* !LINUXKM_ECDSA_SIG_ALG */ #endif /* LINUXKM_LKCAPI_REGISTER_ECDSA */ +#ifdef LINUXKM_LKCAPI_REGISTER_ED25519 + #ifdef LINUXKM_EDDSA_SIG_ALG + UNREGISTER_ALG(ed25519, sig); + #else /* !LINUXKM_EDDSA_SIG_ALG */ + UNREGISTER_ALG(ed25519, akcipher); + #endif /* !LINUXKM_EDDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_ED25519 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_ED448 + #ifdef LINUXKM_EDDSA_SIG_ALG + UNREGISTER_ALG(ed448, sig); + #else /* !LINUXKM_EDDSA_SIG_ALG */ + UNREGISTER_ALG(ed448, akcipher); + #endif /* !LINUXKM_EDDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_ED448 */ + +#ifdef LINUXKM_LKCAPI_REGISTER_MLDSA + #ifdef LINUXKM_MLDSA_SIG_ALG + #ifdef LINUXKM_MLDSA44 + UNREGISTER_ALG(mldsa44, sig); + #endif /* LINUXKM_MLDSA44 */ + #ifdef LINUXKM_MLDSA65 + UNREGISTER_ALG(mldsa65, sig); + #endif /* LINUXKM_MLDSA65 */ + #ifdef LINUXKM_MLDSA87 + UNREGISTER_ALG(mldsa87, sig); + #endif /* LINUXKM_MLDSA87 */ + #else /* !LINUXKM_MLDSA_SIG_ALG */ + #ifdef LINUXKM_MLDSA44 + UNREGISTER_ALG(mldsa44, akcipher); + #endif /* LINUXKM_MLDSA44 */ + #ifdef LINUXKM_MLDSA65 + UNREGISTER_ALG(mldsa65, akcipher); + #endif /* LINUXKM_MLDSA65 */ + #ifdef LINUXKM_MLDSA87 + UNREGISTER_ALG(mldsa87, akcipher); + #endif /* LINUXKM_MLDSA87 */ + #endif /* !LINUXKM_MLDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_MLDSA */ + +#ifdef LINUXKM_LKCAPI_REGISTER_SLHDSA + #ifdef LINUXKM_SLHDSA_SIG_ALG + #ifdef LINUXKM_SLHDSA_SHAKE_128S + UNREGISTER_ALG(slhdsa_shake_128s, sig); + #endif /* LINUXKM_SLHDSA_SHAKE_128S */ + #ifdef LINUXKM_SLHDSA_SHAKE_128F + UNREGISTER_ALG(slhdsa_shake_128f, sig); + #endif /* LINUXKM_SLHDSA_SHAKE_128F */ + #ifdef LINUXKM_SLHDSA_SHAKE_192S + UNREGISTER_ALG(slhdsa_shake_192s, sig); + #endif /* LINUXKM_SLHDSA_SHAKE_192S */ + #ifdef LINUXKM_SLHDSA_SHAKE_192F + UNREGISTER_ALG(slhdsa_shake_192f, sig); + #endif /* LINUXKM_SLHDSA_SHAKE_192F */ + #ifdef LINUXKM_SLHDSA_SHAKE_256S + UNREGISTER_ALG(slhdsa_shake_256s, sig); + #endif /* LINUXKM_SLHDSA_SHAKE_256S */ + #ifdef LINUXKM_SLHDSA_SHAKE_256F + UNREGISTER_ALG(slhdsa_shake_256f, sig); + #endif /* LINUXKM_SLHDSA_SHAKE_256F */ + #ifdef LINUXKM_SLHDSA_SHA2_128S + UNREGISTER_ALG(slhdsa_sha2_128s, sig); + #endif /* LINUXKM_SLHDSA_SHA2_128S */ + #ifdef LINUXKM_SLHDSA_SHA2_128F + UNREGISTER_ALG(slhdsa_sha2_128f, sig); + #endif /* LINUXKM_SLHDSA_SHA2_128F */ + #ifdef LINUXKM_SLHDSA_SHA2_192S + UNREGISTER_ALG(slhdsa_sha2_192s, sig); + #endif /* LINUXKM_SLHDSA_SHA2_192S */ + #ifdef LINUXKM_SLHDSA_SHA2_192F + UNREGISTER_ALG(slhdsa_sha2_192f, sig); + #endif /* LINUXKM_SLHDSA_SHA2_192F */ + #ifdef LINUXKM_SLHDSA_SHA2_256S + UNREGISTER_ALG(slhdsa_sha2_256s, sig); + #endif /* LINUXKM_SLHDSA_SHA2_256S */ + #ifdef LINUXKM_SLHDSA_SHA2_256F + UNREGISTER_ALG(slhdsa_sha2_256f, sig); + #endif /* LINUXKM_SLHDSA_SHA2_256F */ + #else /* !LINUXKM_SLHDSA_SIG_ALG */ + #ifdef LINUXKM_SLHDSA_SHAKE_128S + UNREGISTER_ALG(slhdsa_shake_128s, akcipher); + #endif /* LINUXKM_SLHDSA_SHAKE_128S */ + #ifdef LINUXKM_SLHDSA_SHAKE_128F + UNREGISTER_ALG(slhdsa_shake_128f, akcipher); + #endif /* LINUXKM_SLHDSA_SHAKE_128F */ + #ifdef LINUXKM_SLHDSA_SHAKE_192S + UNREGISTER_ALG(slhdsa_shake_192s, akcipher); + #endif /* LINUXKM_SLHDSA_SHAKE_192S */ + #ifdef LINUXKM_SLHDSA_SHAKE_192F + UNREGISTER_ALG(slhdsa_shake_192f, akcipher); + #endif /* LINUXKM_SLHDSA_SHAKE_192F */ + #ifdef LINUXKM_SLHDSA_SHAKE_256S + UNREGISTER_ALG(slhdsa_shake_256s, akcipher); + #endif /* LINUXKM_SLHDSA_SHAKE_256S */ + #ifdef LINUXKM_SLHDSA_SHAKE_256F + UNREGISTER_ALG(slhdsa_shake_256f, akcipher); + #endif /* LINUXKM_SLHDSA_SHAKE_256F */ + #ifdef LINUXKM_SLHDSA_SHA2_128S + UNREGISTER_ALG(slhdsa_sha2_128s, akcipher); + #endif /* LINUXKM_SLHDSA_SHA2_128S */ + #ifdef LINUXKM_SLHDSA_SHA2_128F + UNREGISTER_ALG(slhdsa_sha2_128f, akcipher); + #endif /* LINUXKM_SLHDSA_SHA2_128F */ + #ifdef LINUXKM_SLHDSA_SHA2_192S + UNREGISTER_ALG(slhdsa_sha2_192s, akcipher); + #endif /* LINUXKM_SLHDSA_SHA2_192S */ + #ifdef LINUXKM_SLHDSA_SHA2_192F + UNREGISTER_ALG(slhdsa_sha2_192f, akcipher); + #endif /* LINUXKM_SLHDSA_SHA2_192F */ + #ifdef LINUXKM_SLHDSA_SHA2_256S + UNREGISTER_ALG(slhdsa_sha2_256s, akcipher); + #endif /* LINUXKM_SLHDSA_SHA2_256S */ + #ifdef LINUXKM_SLHDSA_SHA2_256F + UNREGISTER_ALG(slhdsa_sha2_256f, akcipher); + #endif /* LINUXKM_SLHDSA_SHA2_256F */ + #endif /* !LINUXKM_SLHDSA_SIG_ALG */ +#endif /* LINUXKM_LKCAPI_REGISTER_SLHDSA */ + +#ifdef LINUXKM_LKCAPI_REGISTER_LMS + #ifdef LINUXKM_LMS_SIG_ALG + UNREGISTER_ALG(lms, sig); + #else + UNREGISTER_ALG(lms, akcipher); + #endif +#endif /* LINUXKM_LKCAPI_REGISTER_LMS */ + +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS + #ifdef LINUXKM_XMSS_SIG_ALG + UNREGISTER_ALG(xmss, sig); + #else + UNREGISTER_ALG(xmss, akcipher); + #endif +#endif /* LINUXKM_LKCAPI_REGISTER_XMSS */ + +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT + #ifdef LINUXKM_XMSS_SIG_ALG + UNREGISTER_ALG(xmssmt, sig); + #else + UNREGISTER_ALG(xmssmt, akcipher); + #endif +#endif /* LINUXKM_LKCAPI_REGISTER_XMSS_MT */ + +#ifdef LINUXKM_LKCAPI_REGISTER_MLKEM + #ifdef LINUXKM_MLKEM512 + UNREGISTER_ALG(mlkem512, kpp); + #endif + #ifdef LINUXKM_MLKEM768 + UNREGISTER_ALG(mlkem768, kpp); + #endif + #ifdef LINUXKM_MLKEM1024 + UNREGISTER_ALG(mlkem1024, kpp); + #endif +#endif /* LINUXKM_LKCAPI_REGISTER_MLKEM */ + #ifdef LINUXKM_LKCAPI_REGISTER_ECDH #if defined(LINUXKM_ECC192) UNREGISTER_ALG(ecdh_nist_p192, kpp); #endif /* LINUXKM_ECC192 */ UNREGISTER_ALG(ecdh_nist_p256, kpp); UNREGISTER_ALG(ecdh_nist_p384, kpp); - /* no ecdh p521 in kernel. */ + #ifdef LINUXKM_ECC521 + UNREGISTER_ALG(ecdh_nist_p521, kpp); + #endif /* LINUXKM_ECC521 */ #endif /* LINUXKM_LKCAPI_REGISTER_ECDH */ #ifdef LINUXKM_LKCAPI_REGISTER_RSA diff --git a/linuxkm/lkcapi_lms_glue.c b/linuxkm/lkcapi_lms_glue.c new file mode 100644 index 0000000000..be5d44e12c --- /dev/null +++ b/linuxkm/lkcapi_lms_glue.c @@ -0,0 +1,952 @@ +/* lkcapi_lms_glue.c -- glue logic to register LMS/HSS (RFC 8554, SP 800-208) + * wolfCrypt implementations with the Linux Kernel Cryptosystem + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* included by linuxkm/lkcapi_glue.c */ +#ifndef WC_SKIP_INCLUDED_C_FILES + +#ifndef LINUXKM_LKCAPI_REGISTER + #error lkcapi_lms_glue.c included in non-LINUXKM_LKCAPI_REGISTER project. +#endif + +/* LMS/HSS (RFC 8554, NIST SP 800-208) glue. VERIFY-ONLY, deliberately: + * LMS is a stateful hash-based signature scheme -- each signing operation + * consumes a one-time-signature key, and reusing one voids all security. + * Safe signing therefore requires durable, synchronized private-key state + * (wc_LmsKey signing requires read/write state callbacks), for which the + * kernel crypto API has no contract, and mismanaged state in-kernel would + * be an OTS-reuse hazard. SP 800-208 confines signing to controlled + * (hardware) modules; verification has no state. The sign/set_priv_key + * callbacks are -EOPNOTSUPP stubs, following the convention of the + * in-tree ML-DSA implementation (crypto/mldsa.c) for unsupported + * operations. + * + * The kernel has no in-tree LMS implementation on any version, hence no + * CONFIG_CRYPTO_LMS to pivot on for LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG, + * and no config-conflict check either -- the alg is registered for + * LINUXKM_LKCAPI_REGISTER_ALL, or by explicit request only. + * + * Calling conventions (wolfSSL-defined -- no in-tree or OpenSSL + * precedent for kernel LMS): + * - the cra_name is "lms"; the key and signature formats are the HSS + * forms of RFC 8554 (a 1-level HSS key/signature wraps a plain LMS + * key/signature), which self-describe the parameter set: set_pub_key + * takes the raw HSS public key (levels || lms_type || ots_type || + * I || T[root]), from which the parameters are derived and + * validated by wc_LmsKey_ImportPubRaw(). + * - verify takes the raw HSS signature as src and the raw unhashed + * message, of any length, as the "digest" argument. Signature size + * mismatches and verification failures both return -EBADMSG, + * following the convention of the in-tree ML-DSA. + * - key_size returns the public key size in BYTES on all kernel + * versions, and digest_size is not set, both mirroring the in-tree + * ML-DSA conventions for the PQC signature family. + * + * Because the "lms" cra_name is unknown to crypto/testmgr.c, alg_test() + * takes its "notest" path and returns success at registration time, with + * or without fips_enabled. KATs are instead supplied by + * linuxkm_test_lms() below. + */ + +#if defined(WOLFSSL_HAVE_LMS) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_LMS) && \ + !defined(LINUXKM_LKCAPI_REGISTER_LMS) + #define LINUXKM_LKCAPI_REGISTER_LMS + #endif +#else + #undef LINUXKM_LKCAPI_REGISTER_LMS +#endif + +#ifdef LINUXKM_LKCAPI_REGISTER_LMS + +#include + +/* The LMS acceleration qualifier is borrowed from that of the underlying hash + * functions. + */ +#if defined(USE_INTEL_SPEEDUP) + #ifndef NO_AVX2_SUPPORT + #define WOLFKM_LMS_DRIVER_ISA_EXT "-avx2" + #else + #define WOLFKM_LMS_DRIVER_ISA_EXT "-avx" + #endif +#else + #define WOLFKM_LMS_DRIVER_ISA_EXT "" +#endif + +#define WOLFKM_LMS_DRIVER_SUFFIX \ + WOLFKM_LMS_DRIVER_ISA_EXT WOLFKM_DRIVER_SUFFIX_BASE + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) + /* as with ecdsa (see lkcapi_ecdsa_glue.c), registered as struct + * sig_alg on linux 6.13+, and as a verify-capable struct + * akcipher_alg on earlier kernels. */ + #define LINUXKM_LMS_SIG_ALG +#endif + +#ifdef LINUXKM_LMS_SIG_ALG + #define lms_tfm_type crypto_sig + #define lms_tfm_ctx_cb crypto_sig_ctx +#else + #define lms_tfm_type crypto_akcipher + #define lms_tfm_ctx_cb akcipher_tfm_ctx +#endif /* !LINUXKM_LMS_SIG_ALG */ + +#define WOLFKM_LMS_NAME ("lms") +#define WOLFKM_LMS_DRIVER ("lms" WOLFKM_LMS_DRIVER_SUFFIX) + +static int linuxkm_test_lms(void); + +static int lms_loaded = 0; + +/* wc_LmsKey_Verify() is read-only on the key -- it allocates and frees + * its own transient working state (LmsState) internally -- so a single + * imported key per tfm is safe under the kernel crypto API's concurrent + * use of a tfm, and no per-operation key reconstruction is needed. */ +struct km_lms_ctx { + LmsKey * key; + int pub_set; +}; + +static void km_lms_exit(struct lms_tfm_type *tfm); +static int km_lms_init(struct lms_tfm_type *tfm); +static int km_lms_set_pub(struct lms_tfm_type *tfm, + const void *key, unsigned int keylen); +static int km_lms_set_priv(struct lms_tfm_type *tfm, + const void *key, unsigned int keylen); +#ifdef LINUXKM_LMS_SIG_ALG +static unsigned int km_lms_key_size(struct crypto_sig *tfm); +static unsigned int km_lms_max_size(struct crypto_sig *tfm); +static int km_lms_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen); +static int km_lms_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); +#else +static unsigned int km_lms_max_size(struct crypto_akcipher *tfm); +static int km_lms_verify(struct akcipher_request *req); +static int km_lms_sign(struct akcipher_request *req); +#endif /* !LINUXKM_LMS_SIG_ALG */ + +#ifdef LINUXKM_LMS_SIG_ALG +static struct sig_alg lms = { + .base.cra_name = WOLFKM_LMS_NAME, + .base.cra_driver_name = WOLFKM_LMS_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_lms_ctx), + .sign = km_lms_sign, + .verify = km_lms_verify, + .set_pub_key = km_lms_set_pub, + .set_priv_key = km_lms_set_priv, + .key_size = km_lms_key_size, + /* no .digest_size: crypto/sig.c defaults it (key_size on + * < 6.15.3; keysize-bits/8 on >= 6.15.3) -- pub bytes in + * both eras given km_lms_key_size() above. */ + .max_size = km_lms_max_size, + .init = km_lms_init, + .exit = km_lms_exit, +}; +#else /* !LINUXKM_LMS_SIG_ALG */ +static struct akcipher_alg lms = { + .base.cra_name = WOLFKM_LMS_NAME, + .base.cra_driver_name = WOLFKM_LMS_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_lms_ctx), + .sign = km_lms_sign, + .verify = km_lms_verify, + .set_pub_key = km_lms_set_pub, + .set_priv_key = km_lms_set_priv, + .max_size = km_lms_max_size, + .init = km_lms_init, + .exit = km_lms_exit, +}; +#endif /* !LINUXKM_LMS_SIG_ALG */ + +static int km_lms_init(struct lms_tfm_type *tfm) +{ + struct km_lms_ctx *ctx = lms_tfm_ctx_cb(tfm); + int ret; + + XMEMSET(ctx, 0, sizeof(struct km_lms_ctx)); + + ctx->key = (LmsKey *)malloc(sizeof(LmsKey)); + if (! ctx->key) + return -ENOMEM; + + ret = wc_LmsKey_Init(ctx->key, NULL /* heap */, INVALID_DEVID); + if (ret < 0) { + free(ctx->key); + ctx->key = NULL; + return -ENOMEM; + } + + #ifdef WOLFKM_DEBUG_LMS + pr_info("info: exiting km_lms_init\n"); + #endif + return 0; +} + +static void km_lms_exit(struct lms_tfm_type *tfm) +{ + struct km_lms_ctx *ctx = lms_tfm_ctx_cb(tfm); + + if (ctx->key) { + wc_LmsKey_Free(ctx->key); + free(ctx->key); + ctx->key = NULL; + } + + #ifdef WOLFKM_DEBUG_LMS + pr_info("info: exiting km_lms_exit\n"); + #endif + return; +} + +/* + * Sets the LMS/HSS public key. + * + * tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * key raw RFC 8554 HSS public key (levels || lms_type || + * ots_type || I || T[root]); the parameter set is derived + * from, and validated against, the encoded fields + * keylen key length + */ +static int km_lms_set_pub(struct lms_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + struct km_lms_ctx * ctx = lms_tfm_ctx_cb(tfm); + int err; + + if (key == NULL) + return -EINVAL; + + if (ctx->key == NULL) + return -EINVAL; + + /* Reset the key for (re)import. */ + wc_LmsKey_Free(ctx->key); + ctx->pub_set = 0; + err = wc_LmsKey_Init(ctx->key, NULL /* heap */, INVALID_DEVID); + if (err != 0) + return -ENOMEM; + + /* Derives and validates the parameter set from the raw key + * (NOT_COMPILED_IN if the set isn't built in). */ + err = wc_LmsKey_ImportPubRaw(ctx->key, (const byte *)key, keylen); + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_LMS + pr_err("%s: wc_LmsKey_ImportPubRaw failed: %d\n", + WOLFKM_LMS_DRIVER, err); + #endif + return -EINVAL; + } + + ctx->pub_set = 1; + + #ifdef WOLFKM_DEBUG_LMS + pr_info("info: exiting km_lms_set_pub %d\n", keylen); + #endif + return 0; +} + +/* LMS signing is stateful and unsupported here -- see the header + * comment. Stub convention per the in-tree ML-DSA (crypto/mldsa.c). + */ +static int km_lms_set_priv(struct lms_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + (void)tfm; + (void)key; + (void)keylen; + return -EOPNOTSUPP; +} + +#ifdef LINUXKM_LMS_SIG_ALG +/* The public key size (0 before set_pub_key): BYTES on kernels + * < 6.15.3, BITS on >= 6.15.3 (crypto_sig_keysize() semantics changed; + * crypto_sig_digestsize() then derives bytes as keysize/8 -- see + * lkcapi_ed_glue.c). */ +static unsigned int km_lms_key_size(struct crypto_sig *tfm) +{ + struct km_lms_ctx *ctx = crypto_sig_ctx(tfm); + word32 len = 0; + + if ((! ctx->pub_set) || + (wc_LmsKey_GetPubLen(ctx->key, &len) != 0)) + { + return 0; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + return (unsigned int)len * 8U; /* bits */ + #else + return (unsigned int)len; /* bytes */ + #endif +} + +static unsigned int km_lms_max_size(struct crypto_sig *tfm) +{ + struct km_lms_ctx *ctx = crypto_sig_ctx(tfm); + word32 len = 0; + + if ((! ctx->pub_set) || + (wc_LmsKey_GetSigLen(ctx->key, &len) != 0)) + { + return 0; + } + return len; +} +#else /* !LINUXKM_LMS_SIG_ALG */ +static unsigned int km_lms_max_size(struct crypto_akcipher *tfm) +{ + struct km_lms_ctx *ctx = akcipher_tfm_ctx(tfm); + word32 len = 0; + + if ((! ctx->pub_set) || + (wc_LmsKey_GetSigLen(ctx->key, &len) != 0)) + { + return 0; + } + return len; +} +#endif /* !LINUXKM_LMS_SIG_ALG */ + +/* Shared verify core. returns 0, -EBADMSG (size mismatch or + * verification failure, per the in-tree ML-DSA convention), or + * -EINVAL. + */ +static int km_lms_verify_common(struct km_lms_ctx *ctx, + const byte *sig, word32 sig_len, + const byte *msg, word32 msg_len) +{ + word32 exp_sig_len = 0; + int err; + + if (! ctx->pub_set) + return -EINVAL; + + if (wc_LmsKey_GetSigLen(ctx->key, &exp_sig_len) != 0) + return -EINVAL; + + if (sig_len != exp_sig_len) + return -EBADMSG; + + /* wc_LmsKey_Verify()'s message length parameter is an int. */ + if (msg_len > (word32)INT_MAX) + return -EINVAL; + + err = wc_LmsKey_Verify(ctx->key, sig, sig_len, msg, (int)msg_len); + + if (err) { + #ifdef WOLFKM_DEBUG_LMS + pr_err("error: %s: lms verify returned: %d\n", + WOLFKM_LMS_DRIVER, err); + #endif + return -EBADMSG; + } + return 0; +} + +#ifdef LINUXKM_LMS_SIG_ALG + +/* + * Verify an LMS/HSS signature (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw RFC 8554 HSS signature; slen must equal the signature + * size for the imported public key's parameter set. + * + * digest: + * - the raw message; no prehashing occurs, and dlen is unrestricted + * (up to INT_MAX). + */ +static int km_lms_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct km_lms_ctx *ctx = crypto_sig_ctx(tfm); + int err; + + if (src == NULL || digest == NULL) + return -EINVAL; + + err = km_lms_verify_common(ctx, (const byte *)src, (word32)slen, + (const byte *)digest, (word32)dlen); + + #ifdef WOLFKM_DEBUG_LMS + pr_info("info: exiting km_lms_verify dlen %d, slen %d, err %d\n", + dlen, slen, err); + #endif + return err; +} + +/* LMS signing is stateful and unsupported here -- see the header + * comment. */ +static int km_lms_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + (void)tfm; + (void)src; + (void)slen; + (void)dst; + (void)dlen; + return -EOPNOTSUPP; +} + +#else /* !LINUXKM_LMS_SIG_ALG */ + +/* + * Verify an LMS/HSS signature. + * + * The total size of req->src is src_len + dst_len: + * - src_len: signature (raw RFC 8554 HSS form, exact size for the + * imported public key's parameter set) + * - dst_len: message (raw, unhashed, any length up to INT_MAX) + * + * dst should be null. + */ +static int km_lms_verify(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_lms_ctx * ctx = NULL; + byte * sig = NULL; + word32 sig_len = 0; + byte * msg = NULL; + word32 msg_len = 0; + int err = -1; + + if (req->src == NULL || req->dst != NULL) + return -EINVAL; + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + sig_len = req->src_len; + msg_len = req->dst_len; + + if ((sig_len + msg_len) != ((word64)sig_len + (word64)msg_len)) + return -EINVAL; + + sig = malloc(sig_len + msg_len); + if (unlikely(sig == NULL)) + return -ENOMEM; + + msg = sig + sig_len; + + XMEMSET(sig, 0, sig_len + msg_len); + + scatterwalk_map_and_copy(sig, req->src, 0, sig_len + msg_len, 0); + + err = km_lms_verify_common(ctx, sig, sig_len, msg, msg_len); + + free(sig); + + #ifdef WOLFKM_DEBUG_LMS + pr_info("info: exiting km_lms_verify msg_len %d, sig_len %d, " + "err %d\n", msg_len, sig_len, err); + #endif + return err; +} + +/* LMS signing is stateful and unsupported here -- see the header + * comment. + */ +static int km_lms_sign(struct akcipher_request *req) +{ + (void)req; + return -EOPNOTSUPP; +} + +#endif /* !LINUXKM_LMS_SIG_ALG */ + +#ifdef LINUXKM_LMS_SIG_ALG + +static int linuxkm_test_lms_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_sig * tfm = NULL; + byte * sig_copy = NULL; + byte dummy[1] = { 0 }; + + sig_copy = (byte *)malloc(sig_len); + if (! sig_copy) { + pr_err("error: allocating sig_copy buffer failed.\n"); + test_rc = MEMORY_E; + goto test_lms_end; + } + XMEMCPY(sig_copy, sig, sig_len); + + tfm = crypto_alloc_sig(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating sig algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_lms_end; + } + + ret = crypto_sig_set_pubkey(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_sig_set_pubkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + + { + /* keysize is bits on >= 6.15.3, bytes before (see + * km_lms_key_size()); digestsize resolves to the pub key + * size in bytes in both eras (no digest_size callback). */ + unsigned int maxsize = crypto_sig_maxsize(tfm); + unsigned int keysize = crypto_sig_keysize(tfm); + unsigned int digestsize = crypto_sig_digestsize(tfm); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + unsigned int exp_keysize = pub_len * 8U; + #else + unsigned int exp_keysize = pub_len; + #endif + + if ((keysize != exp_keysize) || (maxsize != sig_len) || + (digestsize != pub_len)) + { + pr_err("error: crypto_sig_{max, key, digest}size returned " + "{%u, %u, %u}, expected {%u, %u, %u}\n", + maxsize, keysize, digestsize, sig_len, exp_keysize, + pub_len); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + } + + ret = crypto_sig_verify(tfm, sig_copy, sig_len, msg, msg_len); + if (ret) { + pr_err("error: crypto_sig_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + + /* corrupt the signature -- verify should now fail. */ + sig_copy[sig_len / 2] ^= 1U; + + ret = crypto_sig_verify(tfm, sig_copy, sig_len, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify returned %d, expected %d\n", + ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + sig_copy[sig_len / 2] ^= 1U; + + /* a wrong-size signature must also fail with -EBADMSG. */ + ret = crypto_sig_verify(tfm, sig_copy, sig_len - 1, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify (short sig) returned %d, " + "expected %d\n", ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + + /* signing is stateful and unsupported -- the stubs must report + * -EOPNOTSUPP. */ + ret = crypto_sig_set_privkey(tfm, dummy, sizeof(dummy)); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_sig_set_privkey returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + ret = crypto_sig_sign(tfm, msg, msg_len, sig_copy, sig_len); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_sig_sign returned %d, expected %d\n", + ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + + test_rc = 0; +test_lms_end: + if (tfm) + crypto_free_sig(tfm); + free(sig_copy); + + #ifdef WOLFKM_DEBUG_LMS + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#else /* !LINUXKM_LMS_SIG_ALG */ + +static int linuxkm_test_lms_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_akcipher * tfm = NULL; + struct akcipher_request * req = NULL; + struct scatterlist src_tab[2]; + byte * param_copy = NULL; + byte * bad_sig = NULL; + byte dummy[1] = { 0 }; + + param_copy = (byte *)malloc(sig_len + msg_len); + if (! param_copy) { + pr_err("error: allocating param_copy buffer failed.\n"); + test_rc = MEMORY_E; + goto test_lms_end; + } + XMEMCPY(param_copy, sig, sig_len); + sig = param_copy; + XMEMCPY(param_copy + sig_len, msg, msg_len); + msg = param_copy + sig_len; + + tfm = crypto_alloc_akcipher(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating akcipher algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_lms_end; + } + + req = akcipher_request_alloc(tfm, GFP_KERNEL); + if (! req) { + test_rc = -ENOMEM; + pr_err("error: allocating akcipher request %s failed\n", + driver); + goto test_lms_end; + } + + ret = crypto_akcipher_set_pub_key(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_akcipher_set_pub_key returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + + { + unsigned int maxsize = crypto_akcipher_maxsize(tfm); + if (maxsize != sig_len) { + pr_err("error: crypto_akcipher_maxsize returned %u, " + "expected %u\n", maxsize, sig_len); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + } + + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], sig, sig_len); + sg_set_buf(&src_tab[1], msg, msg_len); + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret) { + pr_err("error: crypto_akcipher_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + + bad_sig = malloc(sig_len); + if (bad_sig == NULL) { + pr_err("error: alloc sig failed\n"); + test_rc = MEMORY_E; + goto test_lms_end; + } + + XMEMCPY(bad_sig, sig, sig_len); + bad_sig[sig_len / 2] ^= 1; + + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], bad_sig, sig_len); + sg_set_buf(&src_tab[1], msg, msg_len); + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret != -EBADMSG) { + pr_err("error: crypto_akcipher_verify returned %d, expected " + "%d\n", ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + + /* signing is stateful and unsupported -- the stubs must report + * -EOPNOTSUPP. */ + ret = crypto_akcipher_set_priv_key(tfm, dummy, sizeof(dummy)); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_akcipher_set_priv_key returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + ret = crypto_akcipher_sign(req); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_akcipher_sign returned %d, expected %d\n", + ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_lms_end; + } + + test_rc = 0; +test_lms_end: + if (req) { akcipher_request_free(req); req = NULL; } + if (tfm) { crypto_free_akcipher(tfm); tfm = NULL; } + if (param_copy) { free(param_copy); } + if (bad_sig) { free(bad_sig); bad_sig = NULL; } + + #ifdef WOLFKM_DEBUG_LMS + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#endif /* !LINUXKM_LMS_SIG_ALG */ + +static int linuxkm_test_lms(void) +{ + /* reference vectors from wolfcrypt/test/test.c (lms_L1H10W8_*): + * HSS with levels=1, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W8. */ + static const byte lms_pub[] = { + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x04, 0xa1, 0x26, 0x76, 0xf8, + 0xbb, 0x0b, 0xc0, 0x82, 0x21, 0x71, 0x0b, 0x2e, + 0x8c, 0xa6, 0xef, 0x12, 0xed, 0x41, 0x0e, 0x8c, + 0xaf, 0x11, 0x93, 0x34, 0x7b, 0x49, 0x79, 0xb7, + 0xde, 0x63, 0x1c, 0xfe, 0x1f, 0xd1, 0x17, 0x49, + 0xcd, 0x5c, 0xd4, 0x26, 0xa0, 0x53, 0x26, 0x1a, + 0xc5, 0xb4, 0x8f, 0x23 + }; + + static const byte lms_msg_a[] = { + 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, + 0x4c, 0x4d, 0x53, 0x20, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x21 + }; + + static const byte lms_sig[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x18, 0x70, 0x09, 0x2e, + 0x21, 0xc9, 0x6a, 0xc9, 0x5c, 0xb6, 0xb0, 0xaa, + 0xc3, 0xed, 0x6e, 0x66, 0x2f, 0xcc, 0x45, 0x81, + 0xbc, 0xba, 0x44, 0x96, 0x1c, 0xbf, 0x4e, 0xfb, + 0x7a, 0x46, 0xfb, 0xbe, 0x9a, 0x0c, 0xe4, 0x50, + 0x90, 0xc7, 0x92, 0xac, 0x53, 0xae, 0x53, 0x76, + 0x29, 0xa6, 0x65, 0xf1, 0x09, 0xed, 0x1a, 0x8e, + 0x03, 0x2e, 0x5a, 0x06, 0x51, 0xe3, 0x1e, 0xe6, + 0xf6, 0xfe, 0x3a, 0x6e, 0xd1, 0x92, 0x31, 0x1d, + 0xa1, 0x6a, 0x5c, 0x30, 0x3a, 0xc7, 0xfd, 0x5b, + 0xfe, 0x71, 0x2c, 0x5c, 0x2f, 0x5b, 0x5b, 0xcf, + 0xbc, 0x7f, 0xbf, 0x6c, 0xaf, 0x44, 0x8a, 0xae, + 0x14, 0x60, 0xab, 0x88, 0xed, 0x0e, 0x4f, 0xf8, + 0xc7, 0x1b, 0x74, 0x28, 0x72, 0xb3, 0x96, 0xa6, + 0xe6, 0x46, 0x22, 0x82, 0xcf, 0x1f, 0x4d, 0xa6, + 0xea, 0x22, 0x06, 0x07, 0x52, 0xf5, 0x26, 0x16, + 0x0b, 0x90, 0xe3, 0xff, 0x64, 0xa9, 0xe4, 0x61, + 0x1e, 0x9c, 0x12, 0x9c, 0xf6, 0xd4, 0x63, 0x29, + 0xea, 0x02, 0xf7, 0x18, 0x52, 0x79, 0x6c, 0x43, + 0xdc, 0xcf, 0x43, 0x23, 0xb9, 0xcc, 0x4a, 0x25, + 0x9d, 0x10, 0xaf, 0xa3, 0xe6, 0x47, 0x5a, 0x1c, + 0xfe, 0x68, 0x89, 0xaf, 0x1b, 0x2d, 0x88, 0x3e, + 0xca, 0xdc, 0x70, 0xea, 0xac, 0x11, 0x00, 0x8a, + 0x6e, 0xe0, 0xc7, 0xd0, 0xd2, 0x1a, 0x36, 0x18, + 0x97, 0xb3, 0x5f, 0x0e, 0x75, 0x48, 0x28, 0xf8, + 0xa8, 0xf5, 0x90, 0xd1, 0xa1, 0x84, 0xfb, 0xa4, + 0xad, 0x50, 0xbe, 0xe9, 0x39, 0x8c, 0xc5, 0xa1, + 0x67, 0x51, 0xa1, 0x8c, 0xd6, 0x6b, 0x97, 0x1f, + 0x47, 0x99, 0xee, 0xe0, 0x70, 0x01, 0xc7, 0x07, + 0x50, 0xf3, 0x5e, 0x3f, 0xe7, 0x06, 0xd6, 0x8d, + 0x26, 0xd6, 0x5a, 0x59, 0x18, 0x72, 0x6b, 0x12, + 0xd2, 0xaf, 0x9b, 0xb4, 0x2b, 0xd0, 0xb2, 0xf2, + 0x96, 0x2f, 0x40, 0xea, 0xbe, 0xe6, 0xac, 0x1f, + 0xb8, 0x33, 0xc2, 0x76, 0xdc, 0x8c, 0xac, 0xc1, + 0x46, 0x5e, 0x04, 0x84, 0x1b, 0xc8, 0xb9, 0x65, + 0x8d, 0xad, 0x96, 0xb5, 0xb1, 0xf6, 0x17, 0x4a, + 0x19, 0x87, 0xe7, 0xbf, 0x29, 0xc7, 0x9b, 0xb9, + 0xd6, 0x11, 0x2c, 0x92, 0x2f, 0xb7, 0x24, 0xd5, + 0x01, 0x1d, 0x80, 0x37, 0x54, 0xed, 0x33, 0x32, + 0xab, 0x7a, 0x12, 0xd4, 0x02, 0x1d, 0x27, 0x52, + 0x89, 0xdb, 0x32, 0xbf, 0x61, 0xd4, 0xbb, 0xb4, + 0x46, 0x78, 0x1b, 0x64, 0x17, 0x84, 0x4b, 0x8a, + 0xba, 0xc6, 0xc1, 0xcf, 0xc7, 0x5d, 0x8f, 0x93, + 0xc5, 0x9a, 0x27, 0x90, 0xac, 0x17, 0x98, 0xff, + 0xc8, 0x22, 0x59, 0x55, 0x90, 0xb2, 0x29, 0x39, + 0xa0, 0xbe, 0x00, 0x23, 0x55, 0x6b, 0xda, 0x83, + 0xd8, 0x5b, 0x57, 0x7c, 0x67, 0x1b, 0xc3, 0x6b, + 0x6d, 0xc7, 0x9b, 0x2b, 0x9e, 0xb7, 0x95, 0xb3, + 0xf0, 0x1b, 0x89, 0x5a, 0xd7, 0x4b, 0x67, 0xaf, + 0xdc, 0x9e, 0xcf, 0x7e, 0x1a, 0xba, 0x1b, 0xb9, + 0x3b, 0x7a, 0xdd, 0x3f, 0x0d, 0xee, 0x4c, 0x0b, + 0xd1, 0x4f, 0x34, 0xf2, 0x93, 0xf7, 0x21, 0x64, + 0x2c, 0x07, 0x00, 0x15, 0x4f, 0xe3, 0x6a, 0x9f, + 0x08, 0x52, 0xc2, 0x65, 0x47, 0x1f, 0x34, 0x64, + 0x66, 0x07, 0xbc, 0xea, 0xaf, 0x9b, 0xaa, 0x39, + 0x15, 0x8b, 0x08, 0x8c, 0x24, 0x41, 0x9b, 0x46, + 0x1b, 0x5b, 0x91, 0x11, 0xc4, 0xfd, 0xa9, 0x88, + 0x35, 0x0e, 0x7d, 0xaf, 0xfd, 0xb7, 0x90, 0x7e, + 0xd7, 0x29, 0x02, 0x0a, 0xdc, 0xc8, 0x3f, 0xc0, + 0xfd, 0x97, 0xaf, 0x50, 0x49, 0xa6, 0x5e, 0x12, + 0xc1, 0xcd, 0xec, 0x52, 0xc5, 0x51, 0xf2, 0x80, + 0x17, 0x61, 0xc7, 0x7e, 0xbe, 0xd1, 0x1b, 0x65, + 0xa4, 0xab, 0x92, 0x8d, 0x89, 0xb2, 0xc5, 0x8f, + 0xff, 0xa5, 0x6f, 0xfa, 0x62, 0x75, 0xe4, 0xa1, + 0xd4, 0x22, 0xa8, 0x9e, 0x40, 0x04, 0x27, 0x1f, + 0xcc, 0x81, 0xba, 0x28, 0x67, 0xa0, 0x1c, 0x80, + 0xeb, 0xca, 0xb0, 0x61, 0xa5, 0x48, 0xd0, 0x8a, + 0x25, 0xeb, 0x9e, 0x67, 0x8c, 0x8e, 0x9b, 0xd1, + 0xad, 0xbb, 0xc3, 0xea, 0xd3, 0xd4, 0xc5, 0x12, + 0x7b, 0xdd, 0x00, 0x57, 0x7f, 0xf6, 0xf7, 0xf6, + 0x3c, 0x05, 0xcf, 0xfc, 0x12, 0xe1, 0x93, 0x05, + 0xe5, 0x9b, 0x79, 0x87, 0x69, 0xd8, 0x82, 0xd9, + 0xd7, 0x1d, 0x41, 0x73, 0xe4, 0x52, 0x1d, 0x3e, + 0xe5, 0x8c, 0x8d, 0x34, 0xe1, 0x75, 0xa9, 0xf1, + 0x9d, 0x09, 0xa2, 0x5b, 0xef, 0xda, 0x96, 0x6e, + 0x76, 0x3d, 0xea, 0x50, 0xd9, 0xcf, 0x4f, 0xac, + 0xad, 0x1d, 0x35, 0x72, 0x1b, 0x88, 0x8b, 0xcd, + 0x8c, 0x8a, 0x8a, 0xe0, 0x96, 0x04, 0xd8, 0xbb, + 0x28, 0x43, 0x16, 0x77, 0x60, 0x98, 0x63, 0xf9, + 0xb9, 0x71, 0x46, 0xb7, 0xe1, 0xa7, 0xa9, 0x84, + 0xc3, 0x65, 0x82, 0xe1, 0x1b, 0x67, 0x04, 0x2d, + 0x55, 0x6b, 0xf9, 0xc0, 0x79, 0x09, 0x09, 0xe7, + 0xfd, 0x06, 0x4d, 0x09, 0x9b, 0x1a, 0xce, 0x35, + 0xfa, 0x27, 0x6f, 0x2f, 0x01, 0x65, 0x0d, 0xa0, + 0x97, 0x59, 0x11, 0xf0, 0x48, 0xd2, 0xe7, 0x46, + 0xbe, 0xb4, 0x0a, 0xa3, 0xe2, 0x75, 0x0e, 0x09, + 0x94, 0xd9, 0x69, 0x28, 0xd4, 0xda, 0x64, 0xba, + 0xfe, 0xa4, 0xb9, 0xf0, 0xba, 0xeb, 0xba, 0xac, + 0xa8, 0xf9, 0xd3, 0x82, 0x4c, 0x36, 0x80, 0xfa, + 0xe5, 0xf6, 0x76, 0xc3, 0x80, 0xfa, 0x90, 0x29, + 0xf4, 0x85, 0xa4, 0xc6, 0x25, 0x22, 0x79, 0x7e, + 0x39, 0x1e, 0x30, 0xb8, 0x65, 0x72, 0xcf, 0xe1, + 0x99, 0xf0, 0x75, 0xe8, 0x09, 0xb4, 0x92, 0x96, + 0x1b, 0x68, 0x50, 0x88, 0xf1, 0x2c, 0x97, 0xe3, + 0x2d, 0x26, 0x8f, 0xc5, 0x30, 0xcf, 0x24, 0xcb, + 0xb2, 0x60, 0x77, 0xdc, 0x02, 0x72, 0x0d, 0xd9, + 0x2e, 0xf2, 0x52, 0xea, 0x00, 0xf6, 0x32, 0x65, + 0xa5, 0xc6, 0x43, 0x29, 0x29, 0x69, 0xab, 0x27, + 0x0c, 0x39, 0xdf, 0x76, 0x3e, 0x93, 0x95, 0xb1, + 0x2c, 0xa2, 0x0d, 0x18, 0xce, 0xa0, 0x97, 0x10, + 0x3c, 0x90, 0xc0, 0xef, 0x0e, 0x04, 0xa6, 0xc8, + 0xa0, 0x21, 0x3c, 0x0b, 0x22, 0x77, 0x7a, 0x66, + 0xa5, 0x90, 0x25, 0xa4, 0x09, 0x3e, 0xd5, 0x27, + 0x1f, 0x6c, 0x99, 0x85, 0x5c, 0xa2, 0x99, 0x7a, + 0x25, 0xee, 0x8d, 0x32, 0x3d, 0xd3, 0xdc, 0xf5, + 0x00, 0x5a, 0x34, 0x61, 0xb6, 0xcd, 0x4e, 0xbc, + 0x26, 0x36, 0xfb, 0x44, 0x97, 0x35, 0xbd, 0x06, + 0x7d, 0x2e, 0x4a, 0xa2, 0xdc, 0x24, 0xfe, 0x70, + 0x0a, 0xf9, 0x57, 0xe3, 0xee, 0xab, 0xd1, 0x17, + 0xf3, 0x7c, 0xd6, 0x37, 0x26, 0xfa, 0x83, 0x9f, + 0xdd, 0xb2, 0xe1, 0xd7, 0xf9, 0xc7, 0x0e, 0x15, + 0x01, 0xa6, 0x58, 0x32, 0x98, 0x04, 0x32, 0xd4, + 0xde, 0xb9, 0xef, 0x09, 0xfa, 0xe4, 0x5a, 0xd7, + 0xdd, 0x09, 0x1c, 0xc9, 0xac, 0xb8, 0x6a, 0xf5, + 0x00, 0x5d, 0x6b, 0x95, 0x12, 0x8c, 0x2f, 0xcc, + 0xd8, 0xb9, 0x50, 0x3a, 0xeb, 0x74, 0x86, 0xd2, + 0x3f, 0xa1, 0x05, 0x8f, 0x6e, 0xef, 0xf5, 0xa4, + 0xd6, 0x6e, 0x53, 0xfa, 0x9e, 0xfa, 0xce, 0xdb, + 0x99, 0x46, 0xe7, 0xc5, 0xda, 0x92, 0x51, 0x4f, + 0x22, 0x07, 0xf3, 0xa5, 0x38, 0x26, 0xd3, 0xec, + 0xd6, 0x01, 0xdd, 0x31, 0x3a, 0x48, 0x93, 0xf6, + 0x69, 0x4f, 0xd8, 0xf6, 0xc2, 0x91, 0xa5, 0x7c, + 0xdf, 0x51, 0x64, 0xf1, 0x3b, 0x79, 0xbc, 0x0a, + 0x2c, 0xdc, 0x33, 0x5a, 0x29, 0xf6, 0xb2, 0x09, + 0x66, 0xca, 0x24, 0x9f, 0x1a, 0x18, 0xf3, 0x76, + 0x4c, 0x5e, 0x0b, 0x81, 0x7f, 0x29, 0x84, 0xd8, + 0x7a, 0xa8, 0xd6, 0x11, 0xac, 0xec, 0xd9, 0x07, + 0x91, 0xec, 0xb6, 0x6d, 0xec, 0xdb, 0xbe, 0x6f, + 0x9f, 0xc5, 0x19, 0x5e, 0x56, 0x87, 0x20, 0x80, + 0x75, 0xd5, 0x64, 0xe9, 0x80, 0xbf, 0x2d, 0xd5, + 0x94, 0x9f, 0x8c, 0xa4, 0x54, 0x41, 0xab, 0xb1, + 0x8e, 0xad, 0x51, 0xe4, 0x3c, 0x24, 0xf7, 0x1d, + 0xfe, 0x02, 0x48, 0x7c, 0x6d, 0xed, 0xf1, 0xac, + 0xd9, 0x79, 0x42, 0xe5, 0x3a, 0xcf, 0x6a, 0x4c, + 0x6d, 0xe2, 0x13, 0xd2, 0x2b, 0x9d, 0xab, 0x1f, + 0x70, 0xd3, 0xc0, 0x6f, 0x81, 0xe9, 0x9a, 0x86, + 0x33, 0x39, 0x60, 0xe7, 0x6a, 0x00, 0x1f, 0x97, + 0xeb, 0xe5, 0x1d, 0x0d, 0x66, 0x15, 0xc9, 0xa2, + 0xb1, 0xc0, 0xf0, 0x2e, 0xf4, 0x07, 0xa2, 0x2e, + 0x49, 0x92, 0x95, 0x13, 0xa3, 0x18, 0x46, 0x25, + 0xb9, 0x3c, 0xa1, 0x4b, 0x00, 0x00, 0x00, 0x06, + 0xab, 0xaa, 0xf9, 0x3f, 0x7e, 0x21, 0xf4, 0x0e, + 0xce, 0xfd, 0xe0, 0x44, 0xac, 0xc7, 0x1a, 0x30, + 0x22, 0x9d, 0x0a, 0xd7, 0x96, 0x2d, 0x8f, 0x9a, + 0x99, 0x1f, 0x40, 0x75, 0x7f, 0x62, 0xf9, 0xc1, + 0x81, 0x7b, 0x4a, 0x1b, 0xfa, 0xd6, 0x87, 0xb9, + 0xef, 0x58, 0x48, 0xe4, 0x5c, 0x79, 0xe5, 0xb1, + 0x2c, 0x59, 0xa4, 0x42, 0xdb, 0xa6, 0x53, 0x70, + 0x80, 0x61, 0x17, 0xd4, 0xd3, 0x77, 0xbd, 0x53, + 0x26, 0x7c, 0x0e, 0x0e, 0xff, 0x30, 0x4b, 0xd0, + 0x86, 0xfc, 0x02, 0x20, 0x24, 0x46, 0x5b, 0xf5, + 0xe3, 0x99, 0x73, 0x85, 0x60, 0x00, 0x36, 0x47, + 0x17, 0xee, 0x0c, 0xd2, 0x80, 0x71, 0x46, 0x0e, + 0x2b, 0xb0, 0xef, 0x7f, 0xfe, 0x3b, 0xe5, 0xe1, + 0x87, 0xc2, 0xaf, 0x1a, 0x6f, 0x63, 0xf4, 0x5a, + 0xc4, 0x16, 0xf7, 0xad, 0x07, 0x70, 0x71, 0x85, + 0x7d, 0x3d, 0x67, 0x08, 0xb8, 0xd8, 0xe2, 0xf0, + 0xa1, 0xac, 0xd2, 0x94, 0x7d, 0x93, 0x03, 0xdd, + 0x54, 0xf9, 0x64, 0x19, 0xb3, 0xed, 0x24, 0x22, + 0x01, 0xd7, 0x12, 0x5e, 0xc1, 0x2b, 0x39, 0x10, + 0x13, 0xe2, 0x56, 0x1c, 0xee, 0xf4, 0x2a, 0x49, + 0x7b, 0xfb, 0x36, 0x8d, 0xf8, 0xaf, 0x60, 0xdf, + 0x10, 0xf0, 0x72, 0xa2, 0xed, 0xb6, 0x53, 0x88, + 0xa9, 0x0c, 0xed, 0x9c, 0x18, 0x33, 0x7d, 0x65, + 0x9b, 0xb2, 0x9c, 0x3e, 0xe9, 0x1e, 0x43, 0x51, + 0x7e, 0xbe, 0x01, 0x95, 0xf6, 0x60, 0x65, 0xbe, + 0xd1, 0xf4, 0xe2, 0x83, 0x6b, 0xca, 0x7a, 0x70, + 0x41, 0x83, 0x72, 0xc0, 0x23, 0x51, 0x13, 0x11, + 0x2d, 0xf9, 0xc0, 0x0d, 0x7d, 0x73, 0x76, 0xa5, + 0x30, 0x83, 0x68, 0x10, 0x35, 0xa2, 0x18, 0x22, + 0x4e, 0x21, 0x93, 0x27, 0x6a, 0x19, 0x28, 0x83, + 0x7f, 0xdd, 0xdd, 0xff, 0xc3, 0x8a, 0x64, 0x00, + 0x5f, 0x1c, 0x0d, 0xf8, 0xbb, 0xd7, 0x15, 0xb9, + 0xef, 0xe0, 0x07, 0x62, 0x05, 0x9e, 0xcf, 0xfc, + 0x08, 0x52, 0x1e, 0x65, 0x41, 0x56, 0x6a, 0xeb, + 0x81, 0x53, 0x30, 0x7b, 0xf2, 0xfd, 0x65, 0xff, + 0xa2, 0x14, 0xf5, 0x62, 0x1e, 0x24, 0x48, 0x47, + 0xa5, 0x41, 0x80, 0xb4, 0xc5, 0xdc, 0xb2, 0xb4, + 0x2d, 0x17, 0xe7, 0xbe, 0x49, 0x53, 0x7a, 0x25, + 0xc5, 0x0d, 0x19, 0x59, 0xf4, 0x88, 0x59, 0xed, + 0x92, 0x13, 0xee, 0x7a, 0x4f, 0x12, 0x98, 0x4c + }; + + return linuxkm_test_lms_driver(WOLFKM_LMS_DRIVER, + lms_pub, (word32)sizeof(lms_pub), + lms_sig, (word32)sizeof(lms_sig), + lms_msg_a, (word32)sizeof(lms_msg_a)); +} + +#endif /* LINUXKM_LKCAPI_REGISTER_LMS */ + +#endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/linuxkm/lkcapi_mldsa_glue.c b/linuxkm/lkcapi_mldsa_glue.c new file mode 100644 index 0000000000..18526e370d --- /dev/null +++ b/linuxkm/lkcapi_mldsa_glue.c @@ -0,0 +1,3525 @@ +/* lkcapi_mldsa_glue.c -- glue logic to register ML-DSA wolfCrypt + * implementations with the Linux Kernel Cryptosystem + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* included by linuxkm/lkcapi_glue.c */ +#ifndef WC_SKIP_INCLUDED_C_FILES + +#ifndef LINUXKM_LKCAPI_REGISTER + #error lkcapi_mldsa_glue.c included in non-LINUXKM_LKCAPI_REGISTER project. +#endif + +/* This glue shadows the in-tree ML-DSA implementation (crypto/mldsa.c, + * CONFIG_CRYPTO_MLDSA, drivers mldsa44-lib/mldsa65-lib/mldsa87-lib, + * cra_priority 5000), where present, and its calling conventions are + * those of the in-tree implementation: + * - cra_names are "mldsa44", "mldsa65", "mldsa87". + * - set_pub_key takes the raw FIPS 204 public key, exact length for + * the level (1312/1952/2592 bytes). + * - verify takes the raw FIPS 204 signature, exact length for the + * level (2420/3309/4627 bytes), as src, and the raw unhashed + * message, of any length, as the "digest" argument -- pure ML-DSA + * with the default (empty) context, no prehashing (cf. the + * mldsa_verify() kdoc in crypto/mldsa.c and lib/crypto/mldsa.c). + * Size mismatches and verification failures both return -EBADMSG, + * as in-tree. + * - key_size returns the public key size in BYTES on all kernel + * versions, mirroring the in-tree mldsa key_size callback (which, + * unlike ecdsa, did not move to bits at linux 6.15.3). + * - digest_size is not set, so crypto/sig.c defaults it to key_size, + * again mirroring the in-tree implementation. + * + * The in-tree implementation is verify-only, with sign/set_priv_key + * callbacks that return -EOPNOTSUPP. This glue additionally implements + * signing when the wolfCrypt build allows it (see LINUXKM_MLDSA_SIGN + * below); the sign-side conventions are wolfSSL-defined: + * - set_priv_key takes either the 32-byte FIPS 204 seed (xi) or the + * raw FIPS 204 private key, exact length for the level + * (2560/4032/4896 bytes), distinguished by length -- matching + * OpenSSL, which accepts both raw private key forms. A seed is + * expanded via ML-DSA.KeyGen_internal, and also installs the + * derived public key. + * - sign takes the raw message (any length) as src and writes the raw + * FIPS 204 signature to dst, returning the signature size per the + * crypto_sig_sign() contract; short dst is rejected with -EOVERFLOW + * (following the convention of rsassa_pkcs1_sign()). Signing is + * hedged per FIPS 204, with rng drawn from the module's default RNG + * (LKCAPI_INITRNG). + * + * Because the kernel's crypto/testmgr.c currently has no test vectors + * for the mldsa* cra_names, alg_test() takes its "notest" path for them + * and returns success at registration time, with or without + * fips_enabled. KATs are instead supplied by linuxkm_test_mldsa44()/ + * linuxkm_test_mldsa65()/linuxkm_test_mldsa87() below. If/when testmgr + * vectors land upstream, registration will transparently become subject + * to them. + */ + +#if defined(WOLFSSL_HAVE_MLDSA) && defined(WOLFSSL_MLDSA_PUBLIC_KEY) && \ + (!defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_65) || \ + !defined(WOLFSSL_NO_ML_DSA_87)) + #if (defined(LINUXKM_LKCAPI_REGISTER_ALL) || \ + (defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && defined(CONFIG_CRYPTO_MLDSA))) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_MLDSA) && \ + !defined(LINUXKM_LKCAPI_REGISTER_MLDSA) + #define LINUXKM_LKCAPI_REGISTER_MLDSA + #endif +#else + #undef LINUXKM_LKCAPI_REGISTER_MLDSA +#endif + +#if defined(LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG) && \ + defined(CONFIG_CRYPTO_MLDSA) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_MLDSA) && \ + !defined(LINUXKM_LKCAPI_REGISTER_MLDSA) + #error Config conflict: target kernel has CONFIG_CRYPTO_MLDSA, but module is missing LINUXKM_LKCAPI_REGISTER_MLDSA. +#endif + +#ifdef LINUXKM_LKCAPI_REGISTER_MLDSA + +#include + +/* per-level availability. */ +#ifndef WOLFSSL_NO_ML_DSA_44 + #define LINUXKM_MLDSA44 +#endif +#ifndef WOLFSSL_NO_ML_DSA_65 + #define LINUXKM_MLDSA65 +#endif +#ifndef WOLFSSL_NO_ML_DSA_87 + #define LINUXKM_MLDSA87 +#endif + +#if defined(USE_INTEL_SPEEDUP) + #ifdef WOLFSSL_MLDSA_HAVE_INTEL_AVX512 + #define WOLFKM_MLDSA_DRIVER_ISA_EXT "-avx512" + #else + #define WOLFKM_MLDSA_DRIVER_ISA_EXT "-avx2" + #endif +#else + #define WOLFKM_MLDSA_DRIVER_ISA_EXT "" +#endif + +#define WOLFKM_MLDSA_DRIVER_SUFFIX \ + WOLFKM_MLDSA_DRIVER_ISA_EXT WOLFKM_DRIVER_SUFFIX_BASE + +/* Sign support additionally requires the wolfCrypt sign side + * (wc_MlDsaKey_SignCtx()/wc_MlDsaKey_MakeKeyFromSeed(), gated by + * !WOLFSSL_MLDSA_VERIFY_ONLY) and raw private key import/export + * (wc_MlDsaKey_ImportPrivRaw()/wc_MlDsaKey_ExportPrivRaw(), gated by + * WOLFSSL_MLDSA_PRIVATE_KEY). When either is absent the algs are + * registered verify-only, with sign/set_priv_key callbacks returning + * -EOPNOTSUPP -- which is also the in-tree ML-DSA behavior on all + * configurations. + */ +#if !defined(WOLFSSL_MLDSA_VERIFY_ONLY) && defined(WOLFSSL_MLDSA_PRIVATE_KEY) + #define LINUXKM_MLDSA_SIGN +#else + #undef LINUXKM_MLDSA_SIGN +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) + /* As with ecdsa and eddsa (see lkcapi_ecdsa_glue.c), the ML-DSA algs + * are registered as struct sig_alg on linux 6.13+, and as + * verify/sign-capable struct akcipher_alg on earlier kernels. + */ + #define LINUXKM_MLDSA_SIG_ALG +#endif + +#ifdef LINUXKM_MLDSA_SIG_ALG + #define mldsa_tfm_type crypto_sig + #define mldsa_tfm_ctx_cb crypto_sig_ctx +#else + #define mldsa_tfm_type crypto_akcipher + #define mldsa_tfm_ctx_cb akcipher_tfm_ctx +#endif + +#define WOLFKM_MLDSA44_NAME ("mldsa44") +#define WOLFKM_MLDSA44_DRIVER ("mldsa44" WOLFKM_MLDSA_DRIVER_SUFFIX) +#define WOLFKM_MLDSA65_NAME ("mldsa65") +#define WOLFKM_MLDSA65_DRIVER ("mldsa65" WOLFKM_MLDSA_DRIVER_SUFFIX) +#define WOLFKM_MLDSA87_NAME ("mldsa87") +#define WOLFKM_MLDSA87_DRIVER ("mldsa87" WOLFKM_MLDSA_DRIVER_SUFFIX) + +static int linuxkm_test_mldsa_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * seed, word32 seed_len, + int expect_sign, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len); + +#ifdef LINUXKM_MLDSA44 +static int mldsa44_loaded = 0; +#endif +#ifdef LINUXKM_MLDSA65 +static int mldsa65_loaded = 0; +#endif +#ifdef LINUXKM_MLDSA87 +static int mldsa87_loaded = 0; +#endif + +/* All three levels share one tfm context type, sized for the largest, + * mirroring the fixed-array context of the in-tree implementation. The + * imported keys are kept as raw FIPS 204 byte strings; a transient + * wc_MlDsaKey is built on the heap for each operation, because + * wc_MlDsaKey embeds live SHAKE state (key->shake) that wolfCrypt + * advances during both sign and verify, while callers of the kernel + * crypto API are entitled to issue concurrent operations on a single + * tfm. The per-operation setup cost is noise against the algorithm + * itself (tens to hundreds of thousands of cycles per op). + */ +struct km_mldsa_ctx { + byte level; /* WC_ML_DSA_44 / WC_ML_DSA_65 / WC_ML_DSA_87 */ + byte pub_set; +#ifdef LINUXKM_MLDSA_SIGN + byte priv_set; +#endif + byte pub[WC_MLDSA_87_PUB_KEY_SIZE]; +#ifdef LINUXKM_MLDSA_SIGN + /* raw FIPS 204 private key (seed form is expanded and normalized to + * this at set_priv_key time). */ + byte priv[WC_MLDSA_87_KEY_SIZE]; +#endif +}; + +/* Fixed sizes for the level; returns 0 or -EINVAL. */ +static int km_mldsa_sizes(byte level, word32 *pub_len, word32 *sig_len, + word32 *priv_len) +{ + word32 pub_l, sig_l, priv_l; + + switch (level) { + case WC_ML_DSA_44: + pub_l = WC_MLDSA_44_PUB_KEY_SIZE; + sig_l = WC_MLDSA_44_SIG_SIZE; + priv_l = WC_MLDSA_44_KEY_SIZE; + break; + case WC_ML_DSA_65: + pub_l = WC_MLDSA_65_PUB_KEY_SIZE; + sig_l = WC_MLDSA_65_SIG_SIZE; + priv_l = WC_MLDSA_65_KEY_SIZE; + break; + case WC_ML_DSA_87: + pub_l = WC_MLDSA_87_PUB_KEY_SIZE; + sig_l = WC_MLDSA_87_SIG_SIZE; + priv_l = WC_MLDSA_87_KEY_SIZE; + break; + default: + return -EINVAL; + } + if (pub_len) + *pub_len = pub_l; + if (sig_len) + *sig_len = sig_l; + if (priv_len) + *priv_len = priv_l; + return 0; +} + +/* Build a transient wc_MlDsaKey for one operation. Returns the key, or + * NULL. The caller must pass it to km_mldsa_del_key() when done. */ +static wc_MlDsaKey *km_mldsa_new_key(byte level) +{ + wc_MlDsaKey *key = (wc_MlDsaKey *)malloc(sizeof(*key)); + + if (key == NULL) + return NULL; + if (wc_MlDsaKey_Init(key, NULL /* heap */, INVALID_DEVID) != 0) { + free(key); + return NULL; + } + if (wc_MlDsaKey_SetParams(key, level) != 0) { + wc_MlDsaKey_Free(key); + free(key); + return NULL; + } + return key; +} + +/* wc_MlDsaKey_Free() zeroizes the key material it owns; the additional + * ForceZero covers the embedded SHAKE state and any stack-of-struct + * residue, and is noise against the operation cost. */ +static void km_mldsa_del_key(wc_MlDsaKey *key) +{ + if (key == NULL) + return; + wc_MlDsaKey_Free(key); + ForceZero(key, sizeof(*key)); + free(key); +} + +/* mldsa callbacks (shared by all three levels; the level is taken from + * the tfm context, set at init time by the per-level init callbacks + * below). */ +static void km_mldsa_exit(struct mldsa_tfm_type *tfm); +#ifdef LINUXKM_MLDSA44 +static int km_mldsa44_init(struct mldsa_tfm_type *tfm); +#endif +#ifdef LINUXKM_MLDSA65 +static int km_mldsa65_init(struct mldsa_tfm_type *tfm); +#endif +#ifdef LINUXKM_MLDSA87 +static int km_mldsa87_init(struct mldsa_tfm_type *tfm); +#endif +static int km_mldsa_set_pub(struct mldsa_tfm_type *tfm, + const void *key, unsigned int keylen); +static int km_mldsa_set_priv(struct mldsa_tfm_type *tfm, + const void *key, unsigned int keylen); +#ifdef LINUXKM_MLDSA_SIG_ALG +static unsigned int km_mldsa_key_size(struct crypto_sig *tfm); +static unsigned int km_mldsa_max_size(struct crypto_sig *tfm); +static int km_mldsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen); +static int km_mldsa_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); +#else /* !LINUXKM_MLDSA_SIG_ALG */ +static unsigned int km_mldsa_max_size(struct crypto_akcipher *tfm); +static int km_mldsa_verify(struct akcipher_request *req); +static int km_mldsa_sign(struct akcipher_request *req); +#endif /* !LINUXKM_MLDSA_SIG_ALG */ + +#ifdef LINUXKM_MLDSA_SIG_ALG + +#define KM_MLDSA_SIG_ALG_DEF(level_num) \ +static struct sig_alg mldsa ## level_num = { \ + .base.cra_name = WOLFKM_MLDSA ## level_num ## _NAME, \ + .base.cra_driver_name = WOLFKM_MLDSA ## level_num ## _DRIVER, \ + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, \ + .base.cra_module = THIS_MODULE, \ + .base.cra_ctxsize = sizeof(struct km_mldsa_ctx), \ + .sign = km_mldsa_sign, \ + .verify = km_mldsa_verify, \ + .set_pub_key = km_mldsa_set_pub, \ + .set_priv_key = km_mldsa_set_priv, \ + .key_size = km_mldsa_key_size, \ + /* no .digest_size: crypto/sig.c defaults it (key_size on \ + * < 6.15.3; keysize-bits/8 on >= 6.15.3): pub bytes both eras \ + * given km_mldsa_key_size() above. */ \ + .max_size = km_mldsa_max_size, \ + .init = km_mldsa ## level_num ## _init, \ + .exit = km_mldsa_exit, \ +} + +#else /* !LINUXKM_MLDSA_SIG_ALG */ + +#define KM_MLDSA_SIG_ALG_DEF(level_num) \ +static struct akcipher_alg mldsa ## level_num = { \ + .base.cra_name = WOLFKM_MLDSA ## level_num ## _NAME, \ + .base.cra_driver_name = WOLFKM_MLDSA ## level_num ## _DRIVER, \ + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, \ + .base.cra_module = THIS_MODULE, \ + .base.cra_ctxsize = sizeof(struct km_mldsa_ctx), \ + .sign = km_mldsa_sign, \ + .verify = km_mldsa_verify, \ + .set_pub_key = km_mldsa_set_pub, \ + .set_priv_key = km_mldsa_set_priv, \ + .max_size = km_mldsa_max_size, \ + .init = km_mldsa ## level_num ## _init, \ + .exit = km_mldsa_exit, \ +} + +#endif /* !LINUXKM_MLDSA_SIG_ALG */ + +#ifdef LINUXKM_MLDSA44 +KM_MLDSA_SIG_ALG_DEF(44); +#endif +#ifdef LINUXKM_MLDSA65 +KM_MLDSA_SIG_ALG_DEF(65); +#endif +#ifdef LINUXKM_MLDSA87 +KM_MLDSA_SIG_ALG_DEF(87); +#endif + +static int km_mldsa_init_common(struct mldsa_tfm_type *tfm, byte level) +{ + struct km_mldsa_ctx *ctx = mldsa_tfm_ctx_cb(tfm); + + XMEMSET(ctx, 0, sizeof(struct km_mldsa_ctx)); + ctx->level = level; + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: exiting km_mldsa_init_common (level %d)\n", level); + #endif + return 0; +} + +#ifdef LINUXKM_MLDSA44 +static int km_mldsa44_init(struct mldsa_tfm_type *tfm) +{ + return km_mldsa_init_common(tfm, WC_ML_DSA_44); +} +#endif /* LINUXKM_MLDSA44 */ +#ifdef LINUXKM_MLDSA65 +static int km_mldsa65_init(struct mldsa_tfm_type *tfm) +{ + return km_mldsa_init_common(tfm, WC_ML_DSA_65); +} +#endif /* LINUXKM_MLDSA65 */ +#ifdef LINUXKM_MLDSA87 +static int km_mldsa87_init(struct mldsa_tfm_type *tfm) +{ + return km_mldsa_init_common(tfm, WC_ML_DSA_87); +} +#endif /* LINUXKM_MLDSA87 */ + +static void km_mldsa_exit(struct mldsa_tfm_type *tfm) +{ + struct km_mldsa_ctx *ctx = mldsa_tfm_ctx_cb(tfm); + + /* The context may hold raw private key material. */ + ForceZero(ctx, sizeof(struct km_mldsa_ctx)); + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: exiting km_mldsa_exit\n"); + #endif + return; +} + +/* + * Sets the ML-DSA public key. + * + * tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * key raw FIPS 204 public key, exact length for the level + * (1312/1952/2592 bytes) + * keylen key length + */ +static int km_mldsa_set_pub(struct mldsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + struct km_mldsa_ctx * ctx = mldsa_tfm_ctx_cb(tfm); + word32 pub_len = 0; + + if (key == NULL) + return -EINVAL; + + if (km_mldsa_sizes(ctx->level, &pub_len, NULL, NULL) != 0) + return -EINVAL; + + if (keylen != pub_len) { + #ifdef WOLFKM_DEBUG_MLDSA + pr_err("%s: mldsa_set_pub: invalid pub len: got %d, expected %d\n", + "mldsa", keylen, pub_len); + #endif /* WOLFKM_DEBUG_MLDSA */ + return -EINVAL; + } + + /* The raw public key is opaque bytes at this point (as in the + * in-tree implementation, which likewise just stores it); it's + * interpreted by wc_MlDsaKey_ImportPubRaw() per operation. */ + XMEMCPY(ctx->pub, key, keylen); + ctx->pub_set = 1; + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: exiting km_mldsa_set_pub %d\n", keylen); + #endif + return 0; +} + +/* + * Sets the ML-DSA private key. + * + * tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * key either the 32-byte FIPS 204 seed (xi), or the raw + * FIPS 204 private key, exact length for the level + * (2560/4032/4896 bytes) -- matching OpenSSL, which + * accepts both raw forms. A seed is expanded via + * ML-DSA.KeyGen_internal, and also installs the derived + * public key. + * keylen key length + */ +#ifdef LINUXKM_MLDSA_SIGN +static int km_mldsa_set_priv(struct mldsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + struct km_mldsa_ctx * ctx = mldsa_tfm_ctx_cb(tfm); + wc_MlDsaKey * tmp_key = NULL; + word32 pub_len = 0; + word32 priv_len = 0; + word32 out_len = 0; + int err = -1; + + if (key == NULL) + return -EINVAL; + + if (km_mldsa_sizes(ctx->level, &pub_len, NULL, &priv_len) != 0) + return -EINVAL; + + if ((keylen != MLDSA_SEED_SZ) && (keylen != priv_len)) { + #ifdef WOLFKM_DEBUG_MLDSA + pr_err("%s: mldsa_set_priv: invalid priv len: got %d, " + "expected %d or %d\n", + "mldsa", keylen, (int)MLDSA_SEED_SZ, priv_len); + #endif + return -EINVAL; + } + + tmp_key = km_mldsa_new_key(ctx->level); + if (tmp_key == NULL) + return -ENOMEM; + + if (keylen == MLDSA_SEED_SZ) { + /* Seed form: expand, then normalize the context to the raw + * private key, and install the derived public key too. */ + err = wc_MlDsaKey_MakeKeyFromSeed(tmp_key, (const byte *)key); + if (err == 0) { + out_len = priv_len; + PRIVATE_KEY_UNLOCK(); + err = wc_MlDsaKey_ExportPrivRaw(tmp_key, ctx->priv, &out_len); + PRIVATE_KEY_LOCK(); + } + if ((err == 0) && (out_len != priv_len)) + err = WC_NO_ERR_TRACE(WC_FAILURE); + if (err == 0) { + out_len = pub_len; + err = wc_MlDsaKey_ExportPubRaw(tmp_key, ctx->pub, &out_len); + } + if ((err == 0) && (out_len != pub_len)) + err = WC_NO_ERR_TRACE(WC_FAILURE); + if (err == 0) { + ctx->priv_set = 1; + ctx->pub_set = 1; + } + } + else { + /* Raw private key form: import to validate (range checks on the + * encoded s1/s2), then store the raw bytes. */ + err = wc_MlDsaKey_ImportPrivRaw(tmp_key, (const byte *)key, keylen); + if (err == 0) { + XMEMCPY(ctx->priv, key, keylen); + ctx->priv_set = 1; + } + } + + km_mldsa_del_key(tmp_key); + + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_MLDSA + pr_err("%s: mldsa_set_priv failed: %d\n", "mldsa", err); + #endif + /* don't leave the key half-set. */ + ForceZero(ctx->priv, sizeof(ctx->priv)); + ctx->priv_set = 0; + ctx->pub_set = 0; + return -EINVAL; + } + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: exiting km_mldsa_set_priv %d\n", keylen); + #endif + return 0; +} +#else /* !LINUXKM_MLDSA_SIGN */ +static int km_mldsa_set_priv(struct mldsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + (void)tfm; + (void)key; + (void)keylen; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_MLDSA_SIGN */ + +#ifdef LINUXKM_MLDSA_SIG_ALG +/* The public key size: BYTES on kernels < 6.15.3, BITS on >= 6.15.3, + * per the crypto_sig_keysize() contract (crypto/sig.h documents bits, + * and crypto/sig.c derives the digest_size default as keysize/8 -- + * returning bytes there yields a nonsense digestsize of pub_len/8). + * NOTE this deliberately DIVERGES from the in-tree mldsa key_size + * callback, which as of this writing still returns bytes in violation + * of the sig.h contract (and consequently misreports its own + * digestsize on >= 6.15.3); we follow the contract, as ecdsa/rsa and + * lkcapi_ed_glue.c do. + */ +static unsigned int km_mldsa_key_size(struct crypto_sig *tfm) +{ + struct km_mldsa_ctx *ctx = crypto_sig_ctx(tfm); + word32 pub_len = 0; + + if (km_mldsa_sizes(ctx->level, &pub_len, NULL, NULL) != 0) + return 0; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + return (unsigned int)pub_len * 8U; /* bits */ + #else + return (unsigned int)pub_len; /* bytes */ + #endif +} + +static unsigned int km_mldsa_max_size(struct crypto_sig *tfm) +{ + struct km_mldsa_ctx *ctx = crypto_sig_ctx(tfm); + word32 sig_len = 0; + + if (km_mldsa_sizes(ctx->level, NULL, &sig_len, NULL) != 0) + return 0; + return sig_len; +} +#else /* !LINUXKM_MLDSA_SIG_ALG */ +static unsigned int km_mldsa_max_size(struct crypto_akcipher *tfm) +{ + struct km_mldsa_ctx *ctx = akcipher_tfm_ctx(tfm); + word32 sig_len = 0; + + if (km_mldsa_sizes(ctx->level, NULL, &sig_len, NULL) != 0) + return 0; + return sig_len; +} +#endif /* !LINUXKM_MLDSA_SIG_ALG */ + +/* Shared verify core: raw sig + raw msg against the tfm's stored raw + * public key, on a transient wc_MlDsaKey. + * returns: + * 0 -- success + * -EBADMSG -- size mismatch or verification failure, as in-tree) + * -ENOMEM -- heap failure + * -EINVAL -- any other failure + */ +static int km_mldsa_verify_common(struct km_mldsa_ctx *ctx, + const byte *sig, word32 sig_len, + const byte *msg, word32 msg_len) +{ + wc_MlDsaKey * key = NULL; + word32 pub_len = 0; + word32 exp_sig_len = 0; + int result = 0; + int err = -1; + + if (! ctx->pub_set) + return -EINVAL; + + if (km_mldsa_sizes(ctx->level, &pub_len, &exp_sig_len, NULL) != 0) + return -EINVAL; + + /* exact signature size, as in-tree (-EBADMSG on mismatch). */ + if (sig_len != exp_sig_len) + return -EBADMSG; + + key = km_mldsa_new_key(ctx->level); + if (key == NULL) + return -ENOMEM; + + err = wc_MlDsaKey_ImportPubRaw(key, ctx->pub, pub_len); + + if (err == 0) { + /* NULL/0: the default (empty) FIPS 204 context. */ + err = wc_MlDsaKey_VerifyCtx(key, sig, sig_len, NULL, 0, + msg, msg_len, &result); + } + + km_mldsa_del_key(key); + + if (err) { + #ifdef WOLFKM_DEBUG_MLDSA + pr_err("error: mldsa verify: VerifyCtx returned: %d\n", err); + #endif + return -EBADMSG; + } + if (result != 1) { + #ifdef WOLFKM_DEBUG_MLDSA + pr_err("info: mldsa verify: verify fail: %d\n", result); + #endif + return -EBADMSG; + } + return 0; +} + +#ifdef LINUXKM_MLDSA_SIGN +/* Shared sign core: raw msg in, raw sig out, on a transient + * wc_MlDsaKey built from the tfm's stored raw private key. Hedged per + * FIPS 204, with rng drawn from the module's default RNG. + * returns: + * 0 -- success + * -ENOMEM -- heap failure + * -EINVAL -- any other failure. + * + * *out_len is set to the signature size. + */ +static int km_mldsa_sign_common(struct km_mldsa_ctx *ctx, + const byte *msg, word32 msg_len, + byte *sig, word32 *out_len) +{ + wc_MlDsaKey * key = NULL; + WC_RNG rng; + int rng_inited = 0; + word32 priv_len = 0; + word32 exp_sig_len = 0; + int err = -1; + + if (! ctx->priv_set) + return -EINVAL; + + if (km_mldsa_sizes(ctx->level, NULL, &exp_sig_len, &priv_len) != 0) + return -EINVAL; + + key = km_mldsa_new_key(ctx->level); + if (key == NULL) + return -ENOMEM; + + err = wc_MlDsaKey_ImportPrivRaw(key, ctx->priv, priv_len); + + if (err == 0) { + err = LKCAPI_INITRNG(&rng); + if (err == 0) + rng_inited = 1; + } + + if (err == 0) { + *out_len = exp_sig_len; + /* NULL/0: the default (empty) FIPS 204 context. */ + err = wc_MlDsaKey_SignCtx(key, NULL, 0, sig, out_len, + msg, msg_len, &rng); + } + + if (rng_inited) + wc_FreeRng(&rng); + + km_mldsa_del_key(key); + + if (err || (*out_len != exp_sig_len)) { + #ifdef WOLFKM_DEBUG_MLDSA + pr_err("error: mldsa sign: SignCtx returned: %d, out_len %u\n", + err, *out_len); + #endif + return -EINVAL; + } + return 0; +} +#endif /* LINUXKM_MLDSA_SIGN */ + +#ifdef LINUXKM_MLDSA_SIG_ALG + +/* + * Verify an ML-DSA signature (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw FIPS 204 signature; slen must equal the signature size + * for the level (2420/3309/4627). + * + * digest: + * - the raw message. Pure ML-DSA with the default (empty) context + * verifies the message itself -- no prehashing occurs, and dlen is + * unrestricted. + * + * As in the in-tree implementation, both a size mismatch and a + * verification failure return -EBADMSG. + */ +static int km_mldsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct km_mldsa_ctx *ctx = crypto_sig_ctx(tfm); + int err; + + if (src == NULL || digest == NULL) + return -EINVAL; + + err = km_mldsa_verify_common(ctx, (const byte *)src, (word32)slen, + (const byte *)digest, (word32)dlen); + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: exiting km_mldsa_verify dlen %d, slen %d, err %d\n", + dlen, slen, err); + #endif + return err; +} + +/* + * Sign a message with ML-DSA (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw message. Pure ML-DSA with the default (empty) context + * signs the message itself -- no prehashing occurs, and slen is + * unrestricted. + * + * dst: + * - receives the raw FIPS 204 signature. + * - dlen must be >= the signature size for the level, else -EOVERFLOW + * (following the convention of rsassa_pkcs1_sign()). + * + * Returns the signature size on success, per the crypto_sig_sign() + * contract. Signing is hedged per FIPS 204, with rng drawn from the + * module's default RNG. + */ +#ifdef LINUXKM_MLDSA_SIGN +static int km_mldsa_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct km_mldsa_ctx *ctx = crypto_sig_ctx(tfm); + word32 sig_len = 0; + word32 out_len = 0; + int err; + + if (src == NULL || dst == NULL) + return -EINVAL; + + if (km_mldsa_sizes(ctx->level, NULL, &sig_len, NULL) != 0) + return -EINVAL; + + if (dlen < sig_len) + return -EOVERFLOW; + + err = km_mldsa_sign_common(ctx, (const byte *)src, (word32)slen, + (byte *)dst, &out_len); + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: exiting km_mldsa_sign slen %d, err %d\n", slen, err); + #endif + if (err) + return err; + return (int)out_len; +} +#else /* !LINUXKM_MLDSA_SIGN */ +static int km_mldsa_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + (void)tfm; + (void)src; + (void)slen; + (void)dst; + (void)dlen; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_MLDSA_SIGN */ + +#else /* !LINUXKM_MLDSA_SIG_ALG */ + +/* + * Verify an ML-DSA signature. + * + * The total size of req->src is src_len + dst_len: + * - src_len: signature (raw FIPS 204, exact size for the level) + * - dst_len: message (raw, unhashed, any length) + * + * dst should be null. + * See kernel: + * - include/crypto/akcipher.h + */ +static int km_mldsa_verify(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_mldsa_ctx * ctx = NULL; + byte * sig = NULL; + word32 sig_len = 0; + byte * msg = NULL; + word32 msg_len = 0; + int err = -1; + + if (req->src == NULL || req->dst != NULL) + return -EINVAL; + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + sig_len = req->src_len; + msg_len = req->dst_len; + + if ((sig_len + msg_len) != ((word64)sig_len + (word64)msg_len)) + return -EINVAL; + + sig = malloc(sig_len + msg_len); + if (unlikely(sig == NULL)) + return -ENOMEM; + + msg = sig + sig_len; + + XMEMSET(sig, 0, sig_len + msg_len); + + /* copy sig and msg from req->src to sig and contiguous msg buffer. */ + scatterwalk_map_and_copy(sig, req->src, 0, sig_len + msg_len, 0); + + err = km_mldsa_verify_common(ctx, sig, sig_len, msg, msg_len); + + free(sig); + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: exiting km_mldsa_verify msg_len %d, sig_len %d, " + "err %d\n", msg_len, sig_len, err); + #endif + return err; +} + +/* + * Sign a message with ML-DSA. + * + * req->src: the raw message (src_len bytes, unrestricted). + * req->dst: receives the raw FIPS 204 signature (exact size for the + * level). Per include/crypto/akcipher.h, if dst_len is + * insufficient it's updated to the required size and + * -EOVERFLOW is returned; on success it's updated to the + * actual size. + * + * Signing is hedged per FIPS 204, with rng drawn from the module's + * default RNG. + */ +#ifdef LINUXKM_MLDSA_SIGN +static int km_mldsa_sign(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_mldsa_ctx * ctx = NULL; + byte * msg = NULL; + word32 msg_len = 0; + byte * sig = NULL; + word32 sig_len = 0; + word32 out_len = 0; + int err = -1; + + if (req->src == NULL || req->dst == NULL) + return -EINVAL; + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + if (km_mldsa_sizes(ctx->level, NULL, &sig_len, NULL) != 0) + return -EINVAL; + + if (req->dst_len < sig_len) { + req->dst_len = sig_len; + return -EOVERFLOW; + } + + msg_len = req->src_len; + + /* one buffer for the contiguous message copy and the signature; + * allocate at least 1 message byte, to assure well-defined pointer + * arithmetic for zero-length messages (msg_len 0 is legal). */ + msg = malloc((msg_len ? msg_len : 1) + sig_len); + if (unlikely(msg == NULL)) + return -ENOMEM; + sig = msg + (msg_len ? msg_len : 1); + + /* copy the message from req->src to the contiguous msg buffer. */ + scatterwalk_map_and_copy(msg, req->src, 0, msg_len, 0); + + err = km_mldsa_sign_common(ctx, msg, msg_len, sig, &out_len); + + if (err == 0) { + /* copy the signature out to req->dst. */ + scatterwalk_map_and_copy(sig, req->dst, 0, out_len, 1); + req->dst_len = out_len; + } + + free(msg); + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: exiting km_mldsa_sign msg_len %d, err %d\n", + msg_len, err); + #endif + return err; +} +#else /* !LINUXKM_MLDSA_SIGN */ +static int km_mldsa_sign(struct akcipher_request *req) +{ + (void)req; + /* verify-only build -- stub convention per the in-tree ML-DSA + * implementation (crypto/mldsa.c). */ + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_MLDSA_SIGN */ + +#endif /* !LINUXKM_MLDSA_SIG_ALG */ + + +/* 16 byte test message shared by all three levels. */ +static const byte linuxkm_mldsa_test_msg[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; + + +#ifdef LINUXKM_MLDSA_SIG_ALG + +static int linuxkm_test_mldsa_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * seed, word32 seed_len, + int expect_sign, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_sig * tfm = NULL; + byte * sig_copy = NULL; + + /* allocate a mutable copy of the signature, for the corruption test. */ + sig_copy = (byte *)malloc(sig_len); + if (! sig_copy) { + pr_err("error: allocating sig_copy buffer failed.\n"); + test_rc = MEMORY_E; + goto test_mldsa_end; + } + XMEMCPY(sig_copy, sig, sig_len); + + tfm = crypto_alloc_sig(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating sig algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_mldsa_end; + } + + /* now set pub key for verify test. */ + ret = crypto_sig_set_pubkey(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_sig_set_pubkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + { + /* keysize is bits on >= 6.15.3, bytes before (see + * km_mldsa_key_size()); digestsize resolves to the pub key + * size in bytes in both eras (no digest_size callback). */ + unsigned int maxsize = crypto_sig_maxsize(tfm); + unsigned int keysize = crypto_sig_keysize(tfm); + unsigned int digestsize = crypto_sig_digestsize(tfm); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + unsigned int exp_keysize = pub_len * 8U; + #else + unsigned int exp_keysize = pub_len; + #endif + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: crypto_sig_{max, key, digest}size: " + "{%d, %d, %d}\n", + maxsize, keysize, digestsize); + #endif + + if ((keysize != exp_keysize) || + (maxsize != sig_len) || + (digestsize != pub_len)) + { + pr_err("error: crypto_sig_{max, key, digest}size " + "returned {%u, %u, %u}, expected {%u, %u, %u}\n", + maxsize, keysize, digestsize, + sig_len, exp_keysize, pub_len); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + } + + ret = crypto_sig_verify(tfm, sig_copy, sig_len, msg, msg_len); + if (ret) { + pr_err("error: crypto_sig_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + /* corrupt the signature -- verify should now fail. */ + sig_copy[0] ^= 1U; + + ret = crypto_sig_verify(tfm, sig_copy, sig_len, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify returned %d, expected %d\n", + ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + sig_copy[0] ^= 1U; + + /* a wrong-size signature must also fail with -EBADMSG (as + * in-tree). */ + ret = crypto_sig_verify(tfm, sig_copy, sig_len - 1, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify (short sig) returned %d, " + "expected %d\n", ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + /* sign tests. set the priv key (seed form); on verify-only builds + * of this glue the set_priv_key callback is an -EOPNOTSUPP stub + * (matching the in-tree ML-DSA), which is itself checked. */ + ret = crypto_sig_set_privkey(tfm, seed, seed_len); + if (! expect_sign) { + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_sig_set_privkey returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + } + else { + byte * sig_out = NULL; + + if (ret) { + pr_err("error: crypto_sig_set_privkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + sig_out = (byte *)malloc(sig_len); + if (! sig_out) { + pr_err("error: allocating sig_out buffer failed.\n"); + test_rc = MEMORY_E; + goto test_mldsa_end; + } + + /* ML-DSA signing is hedged (nondeterministic), so the produced + * signature can't be compared to a KAT value; round-trip it + * through verify instead (the seed-derived public key equals + * the KAT public key set above). */ + ret = crypto_sig_sign(tfm, msg, msg_len, sig_out, sig_len); + if (ret != (int)sig_len) { + pr_err("error: crypto_sig_sign returned %d, expected %d\n", + ret, (int)sig_len); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + ret = crypto_sig_verify(tfm, sig_out, sig_len, msg, msg_len); + if (ret) { + pr_err("error: crypto_sig_verify of own signature " + "returned: %d\n", ret); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + sig_out[0] ^= 1U; + ret = crypto_sig_verify(tfm, sig_out, sig_len, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify of corrupted own " + "signature returned %d, expected %d\n", + ret, -EBADMSG); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + /* a short dst must be rejected with -EOVERFLOW. */ + ret = crypto_sig_sign(tfm, msg, msg_len, sig_out, sig_len - 1); + free(sig_out); + if (ret != -EOVERFLOW) { + pr_err("error: crypto_sig_sign returned %d, expected %d\n", + ret, -EOVERFLOW); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + } + + test_rc = 0; +test_mldsa_end: + if (tfm) + crypto_free_sig(tfm); + free(sig_copy); + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#else /* !LINUXKM_MLDSA_SIG_ALG */ + +static int linuxkm_test_mldsa_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * seed, word32 seed_len, + int expect_sign, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_akcipher * tfm = NULL; + struct akcipher_request * req = NULL; + struct scatterlist src_tab[2]; + byte * param_copy = NULL; + byte * bad_sig = NULL; + + /* Allocate param_copy -- scatterwalk_map_and_copy() unmaps the buffers in + * the sg list, so we can't safely use the passed pointers directly. + */ + param_copy = (byte *)malloc(sig_len + msg_len); + if (! param_copy) { + pr_err("error: allocating param_copy buffer failed.\n"); + test_rc = MEMORY_E; + goto test_mldsa_end; + } + XMEMCPY(param_copy, sig, sig_len); + sig = param_copy; + XMEMCPY(param_copy + sig_len, msg, msg_len); + msg = param_copy + sig_len; + + tfm = crypto_alloc_akcipher(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating akcipher algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_mldsa_end; + } + + req = akcipher_request_alloc(tfm, GFP_KERNEL); + if (! req) { + test_rc = -ENOMEM; + pr_err("error: allocating akcipher request %s failed\n", + driver); + goto test_mldsa_end; + } + + /* now set pub key for verify test. */ + ret = crypto_akcipher_set_pub_key(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_akcipher_set_pub_key returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + { + unsigned int maxsize = crypto_akcipher_maxsize(tfm); + if (maxsize != sig_len) { + pr_err("error: crypto_akcipher_maxsize " + "returned %u, expected %u\n", maxsize, sig_len); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + } + + /* + * Set sig as src, and null as dst. + * src_tab is: + * src_tab[0]: signature + * src_tab[1]: message + * + * src_len is sig size + * dst_len is msg size. + */ + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], sig, sig_len); + sg_set_buf(&src_tab[1], msg, msg_len); + + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret) { + pr_err("error: crypto_akcipher_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + /* prepare a bad signature */ + bad_sig = malloc(sig_len); + if (bad_sig == NULL) { + pr_err("error: alloc sig failed\n"); + test_rc = MEMORY_E; + goto test_mldsa_end; + } + + XMEMCPY(bad_sig, sig, sig_len); + bad_sig[sig_len/2] ^= 1; + + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], bad_sig, sig_len); + sg_set_buf(&src_tab[1], msg, msg_len); + + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + /* it should fail */ + ret = crypto_akcipher_verify(req); + if (ret != -EBADMSG) { + pr_err("error: crypto_akcipher_verify returned %d, expected %d\n", + ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + /* sign tests. set the priv key (seed form); on verify-only builds + * of this glue the set_priv_key callback is an -EOPNOTSUPP stub + * (matching the in-tree ML-DSA), which is itself checked. */ + ret = crypto_akcipher_set_priv_key(tfm, seed, seed_len); + if (! expect_sign) { + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_akcipher_set_priv_key returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + } + else { + byte * sig_out = NULL; + struct scatterlist sign_src[1]; + struct scatterlist sign_dst[1]; + struct scatterlist rt_src[2]; + + if (ret) { + pr_err("error: crypto_akcipher_set_priv_key returned: %d\n", + ret); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + sig_out = (byte *)malloc(sig_len); + if (! sig_out) { + pr_err("error: allocating sig_out buffer failed.\n"); + test_rc = MEMORY_E; + goto test_mldsa_end; + } + + /* msg still points into param_copy. */ + sg_init_table(sign_src, 1); + sg_set_buf(&sign_src[0], msg, msg_len); + sg_init_table(sign_dst, 1); + sg_set_buf(&sign_dst[0], sig_out, sig_len); + + akcipher_request_set_crypt(req, sign_src, sign_dst, msg_len, + sig_len); + + /* ML-DSA signing is hedged (nondeterministic), so the produced + * signature can't be compared to a KAT value; round-trip it + * through verify instead (the seed-derived public key equals + * the KAT public key set above). */ + ret = crypto_akcipher_sign(req); + if ((ret != 0) || (req->dst_len != sig_len)) { + pr_err("error: crypto_akcipher_sign returned %d, " + "dst_len %u\n", ret, req->dst_len); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + sg_init_table(rt_src, 2); + sg_set_buf(&rt_src[0], sig_out, sig_len); + sg_set_buf(&rt_src[1], msg, msg_len); + akcipher_request_set_crypt(req, rt_src, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret) { + pr_err("error: crypto_akcipher_verify of own signature " + "returned: %d\n", ret); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + + sig_out[0] ^= 1U; + sg_init_table(rt_src, 2); + sg_set_buf(&rt_src[0], sig_out, sig_len); + sg_set_buf(&rt_src[1], msg, msg_len); + akcipher_request_set_crypt(req, rt_src, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret != -EBADMSG) { + pr_err("error: crypto_akcipher_verify of corrupted own " + "signature returned %d, expected %d\n", + ret, -EBADMSG); + free(sig_out); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + sig_out[0] ^= 1U; + + /* a short dst must be rejected with -EOVERFLOW, with dst_len + * updated to the required size. */ + sg_init_table(sign_src, 1); + sg_set_buf(&sign_src[0], msg, msg_len); + sg_init_table(sign_dst, 1); + sg_set_buf(&sign_dst[0], sig_out, sig_len); + akcipher_request_set_crypt(req, sign_src, sign_dst, msg_len, + sig_len - 1); + ret = crypto_akcipher_sign(req); + free(sig_out); + if ((ret != -EOVERFLOW) || (req->dst_len != sig_len)) { + pr_err("error: crypto_akcipher_sign returned %d, " + "dst_len %u, expected %d, %u\n", + ret, req->dst_len, -EOVERFLOW, sig_len); + test_rc = BAD_FUNC_ARG; + goto test_mldsa_end; + } + } + + test_rc = 0; +test_mldsa_end: + if (req) { akcipher_request_free(req); req = NULL; } + if (tfm) { crypto_free_akcipher(tfm); tfm = NULL; } + if (param_copy) { free(param_copy); } + if (bad_sig) { free(bad_sig); bad_sig = NULL; } + + #ifdef WOLFKM_DEBUG_MLDSA + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#endif /* !LINUXKM_MLDSA_SIG_ALG */ + + +#ifdef LINUXKM_MLDSA44 +static int linuxkm_test_mldsa44(void) +{ + /* reference values generated with two independent implementations + * in agreement (OpenSSL master and dilithium-py), from the seed + * below: seed -> (pub, priv) per FIPS 204 ML-DSA.KeyGen_internal, + * and sig = deterministic-variant signature over msg with the + * default (empty) context. */ + static const byte mldsa44_seed[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + + static const byte mldsa44_pub[] = { + 0xd7, 0xb2, 0xb4, 0x72, 0x54, 0xaa, 0xe0, 0xdb, + 0x45, 0xe7, 0x93, 0x0d, 0x4a, 0x98, 0xd2, 0xc9, + 0x7d, 0x8f, 0x13, 0x97, 0xd1, 0x78, 0x9d, 0xaf, + 0xa1, 0x70, 0x24, 0xb3, 0x16, 0xe9, 0xbe, 0xc9, + 0x4f, 0xc9, 0x94, 0x6d, 0x42, 0xf1, 0x9b, 0x79, + 0xa7, 0x41, 0x3b, 0xba, 0xa3, 0x3e, 0x71, 0x49, + 0xcb, 0x42, 0xed, 0x51, 0x15, 0x69, 0x3a, 0xc0, + 0x41, 0xfa, 0xcb, 0x98, 0x8a, 0xde, 0xb5, 0xfe, + 0x0e, 0x1d, 0x86, 0x31, 0x18, 0x49, 0x95, 0xb5, + 0x92, 0xc3, 0x97, 0xd2, 0x29, 0x4e, 0x2e, 0x14, + 0xf9, 0x0a, 0xa4, 0x14, 0xba, 0x38, 0x26, 0x89, + 0x9a, 0xc4, 0x3f, 0x4c, 0xcc, 0xac, 0xbc, 0x26, + 0xe9, 0xa8, 0x32, 0xb9, 0x51, 0x18, 0xd5, 0xcb, + 0x43, 0x3c, 0xbe, 0xf9, 0x66, 0x0b, 0x00, 0x13, + 0x8e, 0x08, 0x17, 0xf6, 0x1e, 0x76, 0x2c, 0xa2, + 0x74, 0xc3, 0x6a, 0xd5, 0x54, 0xeb, 0x22, 0xaa, + 0xc1, 0x16, 0x2e, 0x4a, 0xb0, 0x1a, 0xcb, 0xa1, + 0xe3, 0x8c, 0x4e, 0xfd, 0x8f, 0x80, 0xb6, 0x5b, + 0x33, 0x3d, 0x0f, 0x72, 0xe5, 0x5d, 0xfe, 0x71, + 0xce, 0x9c, 0x1e, 0xbb, 0x98, 0x89, 0xe7, 0xc5, + 0x61, 0x06, 0xc0, 0xfd, 0x73, 0x80, 0x3a, 0x2a, + 0xec, 0xfe, 0xaf, 0xde, 0xd7, 0xaa, 0x3c, 0xb2, + 0xce, 0xda, 0x54, 0xd1, 0x2b, 0xd8, 0xcd, 0x36, + 0xa7, 0x8c, 0xf9, 0x75, 0x94, 0x3b, 0x47, 0xab, + 0xd2, 0x5e, 0x88, 0x0a, 0xc4, 0x52, 0xe5, 0x74, + 0x2e, 0xd1, 0xe8, 0xd1, 0xa8, 0x2a, 0xfa, 0x86, + 0xe5, 0x90, 0xc7, 0x58, 0xc1, 0x5a, 0xe4, 0xd2, + 0x84, 0x0d, 0x92, 0xbc, 0xa1, 0xa5, 0x09, 0x0f, + 0x40, 0x49, 0x65, 0x97, 0xfc, 0xa7, 0xd8, 0xb9, + 0x51, 0x3f, 0x1a, 0x1b, 0xda, 0x6e, 0x95, 0x0a, + 0xaa, 0x98, 0xde, 0x46, 0x75, 0x07, 0xd4, 0xa4, + 0xf5, 0xa4, 0xf0, 0x59, 0x92, 0x16, 0x58, 0x2c, + 0x35, 0x72, 0xf6, 0x2e, 0xda, 0x89, 0x05, 0xab, + 0x35, 0x81, 0x67, 0x0c, 0x4a, 0x02, 0x77, 0x7a, + 0x33, 0xe0, 0xca, 0x72, 0x95, 0xfd, 0x8f, 0x4f, + 0xf6, 0xd1, 0xa0, 0xa3, 0xa7, 0x68, 0x3d, 0x65, + 0xf5, 0xf5, 0xf7, 0xfc, 0x60, 0xda, 0x02, 0x3e, + 0x82, 0x6c, 0x5f, 0x92, 0x14, 0x4c, 0x02, 0xf7, + 0xd1, 0xba, 0x10, 0x75, 0x98, 0x75, 0x53, 0xea, + 0x93, 0x67, 0xfc, 0xd7, 0x6d, 0x99, 0x0b, 0x7f, + 0xa9, 0x9c, 0xd4, 0x5a, 0xfd, 0xb8, 0x83, 0x6d, + 0x43, 0xe4, 0x59, 0xf5, 0x18, 0x7d, 0xf0, 0x58, + 0x47, 0x97, 0x09, 0xa0, 0x1e, 0xa6, 0x83, 0x59, + 0x35, 0xfa, 0x70, 0x46, 0x09, 0x90, 0xcd, 0x3d, + 0xc1, 0xba, 0x40, 0x1b, 0xa9, 0x4b, 0xab, 0x1d, + 0xde, 0x41, 0xac, 0x67, 0xab, 0x33, 0x19, 0xdc, + 0xac, 0xa0, 0x60, 0x48, 0xd4, 0xc4, 0xee, 0xf2, + 0x7e, 0xe1, 0x3a, 0x9c, 0x17, 0xd0, 0x53, 0x8f, + 0x43, 0x0f, 0x2d, 0x64, 0x2d, 0xc2, 0x41, 0x56, + 0x60, 0xde, 0x78, 0x87, 0x7d, 0x8d, 0x8a, 0xbc, + 0x72, 0x52, 0x39, 0x78, 0xc0, 0x42, 0xe4, 0x28, + 0x5f, 0x43, 0x19, 0x84, 0x6c, 0x44, 0x12, 0x62, + 0x42, 0x97, 0x68, 0x44, 0xc1, 0x0e, 0x55, 0x6b, + 0xa2, 0x15, 0xb5, 0xa7, 0x19, 0xe5, 0x9d, 0x0c, + 0x6b, 0x2a, 0x96, 0xd3, 0x98, 0x59, 0x07, 0x1f, + 0xdc, 0xc2, 0xcd, 0xe7, 0x52, 0x4a, 0x7b, 0xed, + 0xae, 0x54, 0xe8, 0x5b, 0x31, 0x8e, 0x85, 0x4e, + 0x8f, 0xe2, 0xb2, 0xf3, 0xed, 0xfa, 0xc9, 0x71, + 0x91, 0x28, 0x27, 0x0a, 0xaf, 0xd1, 0xe5, 0x04, + 0x4c, 0x3a, 0x4f, 0xda, 0xfd, 0x9f, 0xf3, 0x1f, + 0x90, 0x78, 0x4b, 0x8e, 0x8e, 0x45, 0x96, 0x14, + 0x4a, 0x0d, 0xaf, 0x58, 0x65, 0x11, 0xd3, 0xd9, + 0x96, 0x2b, 0x9e, 0xa9, 0x5a, 0xf1, 0x97, 0xb4, + 0xe5, 0xfc, 0x60, 0xf2, 0xb1, 0xed, 0x15, 0xde, + 0x3a, 0x5b, 0xef, 0x5f, 0x89, 0xbd, 0xc7, 0x9d, + 0x91, 0x05, 0x1d, 0x9b, 0x28, 0x16, 0xe7, 0x4f, + 0xa5, 0x45, 0x31, 0xef, 0xdc, 0x1c, 0xbe, 0x74, + 0xd4, 0x48, 0x85, 0x7f, 0x47, 0x6b, 0xcd, 0x58, + 0xf2, 0x1c, 0x0b, 0x65, 0x3b, 0x3b, 0x76, 0xa4, + 0xe0, 0x76, 0xa6, 0x55, 0x9a, 0x30, 0x27, 0x18, + 0x55, 0x5c, 0xc6, 0x3f, 0x74, 0x85, 0x9a, 0xab, + 0xab, 0x92, 0x5f, 0x02, 0x38, 0x61, 0xca, 0x8c, + 0xd0, 0xf7, 0xba, 0xdb, 0x28, 0x71, 0xf6, 0x7d, + 0x55, 0x32, 0x6d, 0x74, 0x51, 0x13, 0x5a, 0xd4, + 0x5f, 0x4a, 0x1b, 0xa6, 0x91, 0x18, 0xfb, 0xb2, + 0xc8, 0xa3, 0x0e, 0xec, 0x93, 0x92, 0xef, 0x3f, + 0x97, 0x70, 0x66, 0xc9, 0xad, 0xd5, 0xc7, 0x10, + 0xcc, 0x64, 0x7b, 0x15, 0x14, 0xd2, 0x17, 0xd9, + 0x58, 0xc7, 0x01, 0x7c, 0x3e, 0x90, 0xfd, 0x20, + 0xc0, 0x4e, 0x67, 0x4b, 0x90, 0x48, 0x6e, 0x93, + 0x70, 0xa3, 0x1a, 0x00, 0x1d, 0x32, 0xf4, 0x73, + 0x97, 0x9e, 0x49, 0x06, 0x74, 0x9e, 0x7e, 0x47, + 0x7f, 0xa0, 0xb7, 0x45, 0x08, 0xf8, 0xa5, 0xf2, + 0x37, 0x83, 0x12, 0xb8, 0x3c, 0x25, 0xbd, 0x38, + 0x8c, 0xa0, 0xb0, 0xff, 0xf7, 0x47, 0x8b, 0xaf, + 0x42, 0xb7, 0x16, 0x67, 0xed, 0xaa, 0xc9, 0x7c, + 0x46, 0xb1, 0x29, 0x64, 0x3e, 0x58, 0x6e, 0x5b, + 0x05, 0x5a, 0x0c, 0x21, 0x19, 0x46, 0xd4, 0xf3, + 0x6e, 0x67, 0x5b, 0xed, 0x58, 0x60, 0xfa, 0x04, + 0x2a, 0x31, 0x5d, 0x98, 0x26, 0x16, 0x4d, 0x6a, + 0x92, 0x37, 0xc3, 0x5a, 0x5f, 0xbf, 0x49, 0x54, + 0x90, 0xa5, 0xbd, 0x4d, 0xf2, 0x48, 0xb9, 0x5c, + 0x4a, 0xae, 0x77, 0x84, 0xb6, 0x05, 0x67, 0x31, + 0x66, 0xac, 0x42, 0x45, 0xb5, 0xb4, 0xb0, 0x82, + 0xa0, 0x9e, 0x93, 0x23, 0xe6, 0x2f, 0x20, 0x78, + 0xc5, 0xb7, 0x67, 0x83, 0x44, 0x6d, 0xef, 0xd7, + 0x36, 0xad, 0x3a, 0x37, 0x02, 0xd4, 0x9b, 0x08, + 0x98, 0x44, 0x90, 0x0a, 0x61, 0x83, 0x33, 0x97, + 0xbc, 0x44, 0x19, 0xb3, 0x0d, 0x7a, 0x97, 0xa0, + 0xb3, 0x87, 0xc1, 0x91, 0x14, 0x74, 0xc4, 0xd4, + 0x1b, 0x53, 0xe3, 0x2a, 0x97, 0x7a, 0xcb, 0x6f, + 0x0e, 0xa7, 0x5d, 0xb6, 0x5b, 0xb3, 0x9e, 0x59, + 0xe7, 0x01, 0xe7, 0x69, 0x57, 0xde, 0xf6, 0xf2, + 0xd4, 0x45, 0x59, 0xc3, 0x1a, 0x77, 0x12, 0x2b, + 0x52, 0x04, 0xe3, 0xb5, 0xc2, 0x19, 0xf1, 0x68, + 0x8b, 0x14, 0xed, 0x0b, 0xc0, 0xb8, 0x01, 0xb3, + 0xe6, 0xe8, 0x2d, 0xcd, 0x43, 0xe9, 0xc0, 0xe9, + 0xf4, 0x17, 0x44, 0xcd, 0x98, 0x15, 0xbd, 0x1b, + 0xc8, 0x82, 0x0d, 0x8b, 0xb1, 0x23, 0xf0, 0x4f, + 0xac, 0xd1, 0xb1, 0xb6, 0x85, 0xdd, 0x5a, 0x2b, + 0x1b, 0x8d, 0xbb, 0xf3, 0xed, 0x93, 0x36, 0x70, + 0xf0, 0x95, 0xa1, 0x80, 0xb4, 0xf1, 0x92, 0xd0, + 0x8b, 0x10, 0xb8, 0xfa, 0xbb, 0xdf, 0xcc, 0x2b, + 0x24, 0x51, 0x8e, 0x32, 0xee, 0xa0, 0xa5, 0xe0, + 0xc9, 0x04, 0xca, 0x84, 0x47, 0x80, 0x08, 0x3f, + 0x3b, 0x0c, 0xd2, 0xd0, 0xb8, 0xb6, 0xaf, 0x67, + 0xbc, 0x35, 0x5b, 0x94, 0x94, 0x02, 0x5d, 0xc7, + 0xb0, 0xa7, 0x8f, 0xa8, 0x0e, 0x3a, 0x2d, 0xbf, + 0xeb, 0x51, 0x32, 0x88, 0x51, 0xd6, 0x07, 0x81, + 0x98, 0xe9, 0x49, 0x36, 0x51, 0xae, 0x78, 0x7e, + 0xc0, 0x25, 0x1f, 0x92, 0x2b, 0xa3, 0x0e, 0x9f, + 0x51, 0xdf, 0x62, 0xa6, 0xd7, 0x27, 0x84, 0xcf, + 0x3d, 0xd2, 0x05, 0x39, 0x31, 0x76, 0xdf, 0xa3, + 0x24, 0xa5, 0x12, 0xbd, 0x94, 0x97, 0x0a, 0x36, + 0xdd, 0x34, 0xa5, 0x14, 0xa8, 0x67, 0x91, 0xf0, + 0xeb, 0x36, 0xf0, 0x14, 0x5b, 0x09, 0xab, 0x64, + 0x65, 0x1b, 0x4a, 0x03, 0x13, 0xb2, 0x99, 0x61, + 0x1a, 0x2a, 0x1c, 0x48, 0x89, 0x16, 0x27, 0x59, + 0x87, 0x68, 0xa3, 0x11, 0x40, 0x60, 0xba, 0x44, + 0x43, 0x48, 0x6d, 0xf5, 0x15, 0x22, 0xa1, 0xce, + 0x88, 0xb3, 0x09, 0x85, 0xc2, 0x16, 0xf8, 0xe6, + 0xed, 0x17, 0x8d, 0xd5, 0x67, 0xb3, 0x04, 0xa0, + 0xd4, 0xca, 0xfb, 0xa8, 0x82, 0xa2, 0x83, 0x42, + 0xf1, 0x7a, 0x9a, 0xa2, 0x6a, 0xe5, 0x8d, 0xb6, + 0x30, 0x08, 0x3d, 0x2c, 0x35, 0x8f, 0xdf, 0x56, + 0x6c, 0x3f, 0x5d, 0x62, 0xa4, 0x28, 0x56, 0x7b, + 0xc9, 0xea, 0x8c, 0xe9, 0x5c, 0xaa, 0x0f, 0x35, + 0x47, 0x4b, 0x0b, 0xfa, 0x8f, 0x33, 0x9a, 0x25, + 0x0a, 0xb4, 0xdf, 0xcf, 0x20, 0x83, 0xbe, 0x8e, + 0xef, 0xbc, 0x10, 0x55, 0xe1, 0x8f, 0xe1, 0x53, + 0x70, 0xee, 0xcb, 0x26, 0x05, 0x66, 0xd8, 0x3f, + 0xf0, 0x6b, 0x21, 0x1a, 0xae, 0xc4, 0x3c, 0xa2, + 0x9b, 0x54, 0xcc, 0xd0, 0x0f, 0x88, 0x15, 0xa2, + 0x46, 0x5e, 0xf0, 0xb4, 0x65, 0x15, 0xcc, 0x7e, + 0x41, 0xf3, 0x12, 0x4f, 0x09, 0xef, 0xff, 0x73, + 0x93, 0x09, 0xab, 0x58, 0xb2, 0x9a, 0x14, 0x59, + 0xa0, 0x0b, 0xce, 0x50, 0x38, 0xe9, 0x38, 0xc9, + 0x67, 0x8f, 0x72, 0xeb, 0x0e, 0x4e, 0xe5, 0xfd, + 0xaa, 0xe6, 0x6d, 0x9f, 0x85, 0x73, 0xfc, 0x97, + 0xfc, 0x42, 0xb4, 0x95, 0x9f, 0x4b, 0xf8, 0xb6, + 0x1d, 0x78, 0x43, 0x3e, 0x86, 0xb0, 0x33, 0x5d, + 0x6e, 0x91, 0x91, 0xc4, 0xd8, 0xbf, 0x48, 0x7b, + 0x39, 0x05, 0xc1, 0x08, 0xcf, 0xd6, 0xac, 0x24, + 0xb0, 0xce, 0xb7, 0xdc, 0xb7, 0xcf, 0x51, 0xf8, + 0x4d, 0x0e, 0xd6, 0x87, 0xb9, 0x5e, 0xae, 0xb1, + 0xc5, 0x33, 0xc0, 0x6f, 0x0d, 0x97, 0x02, 0x3d, + 0x92, 0xa7, 0x08, 0x25, 0x83, 0x7b, 0x59, 0xba, + 0x6c, 0xb7, 0xd4, 0xe5, 0x6b, 0x0a, 0x87, 0xc2, + 0x03, 0x86, 0x2a, 0xe8, 0xf3, 0x15, 0xba, 0x59, + 0x25, 0xe8, 0xed, 0xef, 0xa6, 0x79, 0x36, 0x9a, + 0x22, 0x02, 0x76, 0x61, 0x51, 0xf1, 0x6a, 0x96, + 0x5f, 0x9f, 0x81, 0xec, 0xe7, 0x6c, 0xc0, 0x70, + 0xb5, 0x58, 0x69, 0xe4, 0xdb, 0x97, 0x84, 0xcf, + 0x05, 0xc8, 0x30, 0xb3, 0x24, 0x2c, 0x83, 0x12 + }; + + static const byte mldsa44_sig[] = { + 0xd3, 0xc1, 0x57, 0x21, 0xf6, 0x61, 0xc9, 0x54, + 0x7c, 0x2d, 0x24, 0xd3, 0xb3, 0x63, 0x78, 0x03, + 0x47, 0x66, 0xf3, 0xec, 0xe6, 0xd6, 0x3f, 0x8f, + 0xc4, 0xe4, 0x07, 0xe8, 0xe0, 0x12, 0x96, 0xa6, + 0x87, 0xd4, 0xde, 0x8d, 0x55, 0x41, 0xfa, 0x5f, + 0xde, 0x92, 0x0a, 0x1a, 0xc7, 0x9c, 0xff, 0xbc, + 0x0b, 0x68, 0x61, 0xcc, 0x6a, 0x6d, 0xfe, 0x09, + 0x1e, 0x6a, 0x27, 0x82, 0x3e, 0x08, 0x0e, 0x7b, + 0x1d, 0x5c, 0xe8, 0xc0, 0x12, 0x2e, 0x36, 0xa0, + 0x6a, 0x15, 0x2d, 0xfe, 0x21, 0x97, 0xe3, 0xa0, + 0xff, 0x1a, 0x18, 0x0c, 0xcb, 0x03, 0x5e, 0x82, + 0xb6, 0x1a, 0x48, 0x07, 0x53, 0x2f, 0xca, 0xfa, + 0x6c, 0x5d, 0x68, 0x32, 0x1f, 0xcd, 0x66, 0x78, + 0x19, 0x08, 0x8e, 0xf5, 0x46, 0x6b, 0x1f, 0x54, + 0x37, 0xe4, 0xb8, 0x1d, 0x21, 0xe9, 0xe7, 0x96, + 0x15, 0xf7, 0x3b, 0x35, 0xf3, 0x43, 0x7b, 0x7a, + 0x80, 0xee, 0x39, 0x98, 0xd6, 0xa9, 0xb0, 0x75, + 0x93, 0xaa, 0x25, 0x11, 0x8f, 0x65, 0xae, 0x8d, + 0xab, 0x62, 0xf7, 0xb1, 0xc7, 0x04, 0xd6, 0x98, + 0x2a, 0xa0, 0x84, 0x83, 0xf2, 0xec, 0xdc, 0x42, + 0xbd, 0xcb, 0x64, 0xf7, 0xf7, 0xa2, 0xe6, 0x0f, + 0x7f, 0xad, 0x57, 0x53, 0xfe, 0xac, 0x99, 0x0d, + 0x1e, 0xf1, 0xe4, 0x5b, 0xdb, 0xe5, 0x59, 0x78, + 0xa6, 0x54, 0x41, 0x7e, 0x33, 0x71, 0xe3, 0xb8, + 0xde, 0x64, 0xc2, 0x8d, 0x78, 0x5b, 0x8b, 0x48, + 0x86, 0x8f, 0x95, 0x5a, 0xcd, 0xce, 0xd3, 0x1b, + 0xb7, 0x55, 0x12, 0x84, 0x04, 0xe3, 0x42, 0x52, + 0x41, 0xf0, 0xbc, 0x07, 0x7d, 0x86, 0x7d, 0x43, + 0xd6, 0x47, 0x37, 0x13, 0x5a, 0xe6, 0x7d, 0x47, + 0x3e, 0x66, 0x19, 0x0e, 0x2f, 0x3a, 0x0a, 0xfb, + 0xe1, 0x35, 0xde, 0x49, 0x3f, 0x3c, 0x69, 0xcf, + 0x7d, 0xb1, 0x66, 0x2a, 0x2d, 0x2c, 0x6e, 0x3e, + 0xfa, 0x37, 0x26, 0x0b, 0x25, 0x08, 0x96, 0x56, + 0x73, 0x53, 0xd8, 0x5b, 0xb8, 0x0f, 0x24, 0xe4, + 0xb3, 0xe9, 0x31, 0x0f, 0xae, 0x74, 0x4d, 0x75, + 0xd8, 0x51, 0x8d, 0x49, 0x17, 0x03, 0x7b, 0x03, + 0xe5, 0x6b, 0xc2, 0x0e, 0x5c, 0x7e, 0x4b, 0x06, + 0x25, 0xae, 0x46, 0x40, 0xdd, 0xef, 0x5f, 0xd3, + 0x5f, 0x47, 0x0c, 0x51, 0x59, 0xa0, 0x0a, 0x58, + 0x72, 0x6d, 0x73, 0x57, 0x17, 0x36, 0xfd, 0xde, + 0x72, 0x35, 0x8f, 0xf4, 0xab, 0xd5, 0x48, 0x46, + 0xaf, 0x68, 0xd0, 0x64, 0x5f, 0x5f, 0x85, 0xbb, + 0x72, 0x23, 0x8b, 0xba, 0xc6, 0xc9, 0x78, 0x49, + 0x60, 0xa7, 0xdb, 0x98, 0x49, 0x22, 0xe8, 0x9b, + 0xa2, 0xb6, 0x34, 0x04, 0x16, 0xe1, 0x97, 0x40, + 0x2d, 0xa1, 0x49, 0x8a, 0xca, 0x35, 0xda, 0x6f, + 0x79, 0xe1, 0x55, 0x08, 0xf6, 0x23, 0x11, 0x4a, + 0x90, 0xf7, 0x09, 0x04, 0xb5, 0xb2, 0x4f, 0x73, + 0x64, 0xc2, 0x5a, 0x36, 0x77, 0x93, 0x17, 0x8d, + 0xf0, 0x78, 0x8b, 0x8c, 0x9d, 0x4d, 0x60, 0xd5, + 0x1b, 0x0b, 0x0f, 0xba, 0xa3, 0x68, 0x94, 0xde, + 0x9f, 0x62, 0x6d, 0x07, 0xcd, 0x86, 0x53, 0x55, + 0x36, 0xc7, 0x7c, 0x22, 0x6e, 0x39, 0x7b, 0xf3, + 0x09, 0x62, 0x48, 0x1c, 0xaf, 0x12, 0xd2, 0x72, + 0x92, 0x34, 0x34, 0x5f, 0xae, 0x8e, 0xe9, 0x43, + 0xb1, 0x14, 0xa0, 0xa9, 0xec, 0x9e, 0x56, 0xb1, + 0x25, 0x4d, 0xdf, 0xcb, 0x8d, 0x05, 0xce, 0x64, + 0x86, 0x3d, 0xb0, 0x26, 0x39, 0x64, 0x92, 0x81, + 0xf6, 0x7c, 0x35, 0xb0, 0x00, 0x1e, 0x78, 0x39, + 0x37, 0x9e, 0xe1, 0xf3, 0x4c, 0x74, 0xa1, 0x6f, + 0xa5, 0xff, 0x5c, 0x1a, 0xec, 0x3d, 0x57, 0x78, + 0x57, 0xd7, 0xad, 0x78, 0xc4, 0x61, 0xce, 0x70, + 0xd0, 0x29, 0x93, 0x12, 0x80, 0x3c, 0x40, 0x30, + 0x5d, 0x74, 0x1a, 0xf2, 0x5f, 0x48, 0x2c, 0x20, + 0xc6, 0xb3, 0xb4, 0xb1, 0x16, 0x74, 0xc3, 0xb7, + 0x5d, 0x4d, 0x7b, 0x32, 0x24, 0x81, 0xdf, 0x94, + 0xcf, 0x58, 0xb7, 0x0d, 0x4d, 0x7a, 0xd0, 0x58, + 0x49, 0xdf, 0x7f, 0x13, 0x07, 0x4d, 0x35, 0xe9, + 0x01, 0x2d, 0x20, 0x48, 0x49, 0xd7, 0xdb, 0xbd, + 0x49, 0xcf, 0xb3, 0xea, 0x62, 0x92, 0xcd, 0x20, + 0x89, 0xa5, 0x4f, 0x81, 0x4e, 0xf9, 0xa0, 0x23, + 0x05, 0xbc, 0x77, 0xa9, 0x9d, 0xa7, 0x46, 0xf1, + 0x4b, 0x49, 0x19, 0x32, 0xc8, 0x0c, 0x01, 0xe2, + 0x9d, 0x3f, 0x50, 0x9b, 0x33, 0x8f, 0x8c, 0x9c, + 0x8a, 0xee, 0xba, 0xb2, 0x1e, 0xe0, 0x99, 0x8d, + 0x0f, 0x6e, 0x59, 0x58, 0x40, 0x2c, 0xd7, 0x44, + 0x0d, 0x4c, 0xb8, 0xfd, 0x3c, 0xf1, 0xc2, 0xb8, + 0xfa, 0xa4, 0x2d, 0xba, 0x31, 0x2f, 0xa9, 0x84, + 0xd5, 0x02, 0xd8, 0xd0, 0x2b, 0x03, 0x01, 0x00, + 0x84, 0x94, 0x89, 0x59, 0x04, 0x25, 0x2b, 0x6d, + 0xef, 0xe7, 0x67, 0x00, 0x6f, 0x4a, 0xa9, 0xe3, + 0x51, 0xa0, 0xf4, 0x06, 0x16, 0x3c, 0xb0, 0xe6, + 0xe1, 0x0a, 0x37, 0x49, 0xf8, 0xc7, 0x87, 0x19, + 0xd3, 0x84, 0xa7, 0xb4, 0x17, 0xc9, 0x8b, 0x27, + 0x41, 0x43, 0x30, 0x91, 0x39, 0xa2, 0xe0, 0x8e, + 0xea, 0x28, 0x6f, 0x61, 0x2f, 0xe8, 0x8f, 0xb0, + 0x41, 0x51, 0x27, 0xa3, 0xf1, 0x63, 0xcf, 0x37, + 0x2e, 0x1f, 0x00, 0xae, 0x0c, 0x88, 0x51, 0x36, + 0xf5, 0x71, 0xc1, 0x06, 0x1f, 0x55, 0x71, 0x8f, + 0xbb, 0xb8, 0xb1, 0x2d, 0x50, 0xe5, 0x49, 0x5d, + 0xf2, 0xc5, 0xdd, 0x5e, 0xe2, 0x1e, 0xa9, 0xa2, + 0x4a, 0x3c, 0x75, 0xf7, 0x6e, 0x0b, 0xd9, 0x36, + 0x7f, 0xc3, 0x67, 0x0b, 0xbe, 0x09, 0xb8, 0x54, + 0xec, 0x42, 0x43, 0x13, 0x62, 0xe4, 0x04, 0x17, + 0x22, 0xb9, 0x64, 0xe0, 0xe2, 0x67, 0x5c, 0x7f, + 0xff, 0xc9, 0xd9, 0x04, 0xcb, 0x87, 0xb7, 0x55, + 0x88, 0xf0, 0xeb, 0x3e, 0x1b, 0x33, 0x66, 0x63, + 0x7f, 0x3c, 0x32, 0xa0, 0xda, 0x33, 0x8c, 0xeb, + 0x55, 0x55, 0xf5, 0x78, 0xa7, 0xd6, 0x98, 0x87, + 0xf8, 0x7d, 0xde, 0x30, 0xf4, 0x49, 0x65, 0xd8, + 0x97, 0xa0, 0xbe, 0xa4, 0x43, 0x9e, 0x1c, 0xe1, + 0xd2, 0xbb, 0x7d, 0x99, 0x26, 0xd5, 0xc4, 0x66, + 0x4d, 0x6b, 0x83, 0xc6, 0x87, 0x78, 0xca, 0x6a, + 0xfc, 0x07, 0x9b, 0x2a, 0x01, 0x5c, 0x97, 0xe0, + 0x16, 0x84, 0x02, 0xfc, 0xff, 0x6c, 0xcd, 0x98, + 0x46, 0x6d, 0x06, 0x45, 0x92, 0x1c, 0xe9, 0xd8, + 0x9f, 0x20, 0x4a, 0xe3, 0xa7, 0x71, 0x4a, 0xdf, + 0x72, 0x3f, 0x05, 0x4b, 0xfa, 0xba, 0xff, 0x01, + 0xc3, 0xf8, 0xca, 0x4e, 0xeb, 0x71, 0x92, 0xeb, + 0x16, 0xc8, 0x6c, 0xc8, 0xdc, 0x3f, 0xab, 0xa1, + 0xf6, 0x74, 0xaa, 0x5f, 0x76, 0x4b, 0x7d, 0x87, + 0x72, 0x39, 0x7c, 0xc8, 0x3a, 0xf5, 0x3a, 0xe1, + 0xa0, 0x42, 0x16, 0x69, 0xae, 0xc8, 0x5c, 0x16, + 0x92, 0xac, 0x7f, 0xf7, 0xdd, 0xb0, 0x64, 0x7b, + 0x43, 0xe8, 0x86, 0x2d, 0xec, 0x3c, 0x39, 0xb8, + 0xc8, 0x22, 0x88, 0xc8, 0x57, 0xe5, 0x80, 0x7b, + 0xac, 0xfb, 0xd4, 0x85, 0xdb, 0xe6, 0x5a, 0xab, + 0x06, 0x4a, 0xe9, 0x5d, 0x11, 0x97, 0x74, 0x6e, + 0xac, 0xfc, 0x78, 0x70, 0x56, 0x4c, 0xd0, 0x94, + 0x36, 0xe6, 0xe6, 0xbd, 0xeb, 0x56, 0xd8, 0x71, + 0x4b, 0x49, 0xcb, 0x17, 0x8c, 0xef, 0xb8, 0x62, + 0x63, 0x08, 0x88, 0x37, 0x43, 0xe0, 0x78, 0xe8, + 0x0a, 0x5d, 0xe6, 0xd6, 0x42, 0xc3, 0xe5, 0x96, + 0x60, 0xc7, 0x2f, 0x27, 0xc4, 0x8c, 0x13, 0x94, + 0x07, 0xf6, 0x03, 0x72, 0xbd, 0xd3, 0x2b, 0x3a, + 0x9a, 0xcd, 0xc2, 0x3c, 0x3a, 0x72, 0x32, 0xc9, + 0x99, 0x34, 0x96, 0x59, 0x33, 0x2f, 0x76, 0x12, + 0x72, 0xfa, 0x0f, 0x90, 0x81, 0x87, 0x74, 0x7a, + 0xf8, 0x9a, 0x44, 0x55, 0x04, 0x65, 0x41, 0x37, + 0xff, 0x2a, 0xdd, 0x3d, 0x96, 0xcc, 0xf4, 0x94, + 0x0e, 0xbe, 0x55, 0xf0, 0x8b, 0xab, 0x0a, 0x9f, + 0x3b, 0x0a, 0x49, 0xda, 0xef, 0xfd, 0xe0, 0xc7, + 0x8a, 0x06, 0xd1, 0x33, 0xdd, 0x87, 0x59, 0x5e, + 0xb2, 0x9b, 0x28, 0x8b, 0xa9, 0x37, 0xea, 0x77, + 0x39, 0x3e, 0xf3, 0x2d, 0x2a, 0xb6, 0xd5, 0x2c, + 0xc9, 0xaa, 0x2c, 0x25, 0x2b, 0x0e, 0x01, 0x1a, + 0x5d, 0x75, 0xa8, 0x50, 0x62, 0xd8, 0x3f, 0x17, + 0x2c, 0xce, 0x6b, 0x34, 0x63, 0x0f, 0xcf, 0x10, + 0xa6, 0x24, 0xd4, 0x2d, 0x7f, 0xa3, 0x8c, 0x50, + 0x0e, 0x59, 0x53, 0x94, 0xd7, 0xd1, 0xeb, 0x70, + 0xf5, 0x0b, 0x46, 0xef, 0xd4, 0x59, 0x44, 0xa9, + 0x16, 0xcc, 0xa1, 0x71, 0xae, 0xe8, 0xbd, 0xe4, + 0x91, 0x9c, 0x10, 0xd7, 0xc1, 0xe6, 0x92, 0x49, + 0x82, 0xf1, 0xbf, 0xc4, 0x9a, 0x4e, 0xea, 0x1f, + 0x52, 0x95, 0x18, 0x2e, 0x05, 0x84, 0x76, 0xee, + 0xc4, 0x07, 0xa9, 0x35, 0x7e, 0x0c, 0xd8, 0x8a, + 0x8f, 0x7f, 0x8a, 0x16, 0x71, 0x44, 0xec, 0xfc, + 0x4a, 0x02, 0x22, 0xd2, 0x0e, 0x7a, 0x34, 0xf6, + 0x6f, 0xae, 0xc6, 0x81, 0x6d, 0x57, 0xdf, 0xde, + 0x3b, 0x93, 0x39, 0x15, 0x85, 0xe9, 0xbf, 0xb0, + 0x49, 0xa2, 0x7b, 0x37, 0xec, 0x12, 0x4b, 0xb1, + 0xfb, 0xbb, 0x54, 0x61, 0x14, 0x4c, 0x56, 0x42, + 0xd4, 0x8c, 0xb4, 0x34, 0x0c, 0xcd, 0x80, 0x91, + 0x02, 0x72, 0x5c, 0xf2, 0x12, 0x9a, 0x4c, 0x88, + 0x70, 0x56, 0xdb, 0x48, 0x3b, 0xd0, 0x87, 0x73, + 0xb8, 0xfd, 0x33, 0x32, 0x00, 0x95, 0x99, 0xe9, + 0x65, 0x51, 0x2b, 0x24, 0x47, 0x48, 0x82, 0x0e, + 0xca, 0xed, 0xc6, 0x28, 0xfe, 0x0e, 0xc2, 0x5e, + 0x1e, 0x77, 0x51, 0x67, 0x2c, 0x2c, 0xc8, 0xc2, + 0x45, 0x55, 0xc2, 0x13, 0x79, 0xf5, 0x16, 0x0c, + 0x88, 0x02, 0xcd, 0x3d, 0xf1, 0xd1, 0x04, 0xb7, + 0x35, 0x72, 0x9c, 0xec, 0x02, 0x49, 0xab, 0x47, + 0xbc, 0x80, 0x57, 0x1b, 0x20, 0x40, 0x8a, 0x46, + 0x83, 0x26, 0x13, 0x2f, 0xf7, 0xda, 0xee, 0x3e, + 0x66, 0xa2, 0x82, 0x3c, 0xfa, 0x71, 0x5b, 0xfe, + 0xe9, 0x98, 0xf5, 0xac, 0xf4, 0x37, 0x16, 0xd7, + 0x65, 0x39, 0x88, 0xff, 0x4c, 0xd3, 0x7b, 0x64, + 0x76, 0xa9, 0xf1, 0x3a, 0x44, 0x83, 0x93, 0x83, + 0xd5, 0x85, 0x5f, 0x44, 0x00, 0x62, 0x2a, 0x6b, + 0x7c, 0x4f, 0x16, 0x8d, 0x87, 0xcf, 0x29, 0x98, + 0xfb, 0x7e, 0xc1, 0x41, 0x3b, 0x5f, 0x84, 0x6f, + 0xa7, 0x1b, 0x21, 0x50, 0x53, 0x25, 0xe1, 0xf4, + 0x51, 0x0c, 0x57, 0x82, 0x5e, 0xde, 0xd2, 0xfa, + 0x6d, 0x5c, 0xcf, 0x5e, 0x2e, 0xaa, 0x1c, 0x4c, + 0x77, 0x05, 0x30, 0x05, 0x64, 0x6a, 0xe5, 0x1e, + 0x36, 0x8a, 0x3c, 0x4e, 0xe6, 0x5f, 0x11, 0xb5, + 0xf7, 0x39, 0x8c, 0xda, 0xf9, 0xe8, 0x38, 0x0c, + 0x4b, 0x16, 0x1d, 0x06, 0x80, 0x49, 0x83, 0xe1, + 0xa3, 0xb3, 0xcf, 0xc1, 0xcb, 0xfe, 0x25, 0xe1, + 0xa8, 0xa9, 0x0f, 0xc0, 0xb2, 0x75, 0x51, 0x38, + 0xa4, 0xb6, 0xaf, 0x84, 0xbc, 0xb7, 0xc6, 0xdf, + 0x60, 0x0c, 0x95, 0x13, 0x67, 0x4a, 0x04, 0x96, + 0xb9, 0xdf, 0x7c, 0x27, 0xdc, 0x28, 0xf2, 0x82, + 0xda, 0xe7, 0x8c, 0x82, 0xc0, 0xea, 0xd0, 0x5d, + 0xae, 0xc5, 0x1c, 0xad, 0x2e, 0xde, 0x31, 0x2c, + 0x0d, 0x7c, 0x82, 0xc0, 0xcf, 0x42, 0x51, 0x73, + 0x2e, 0x67, 0xa3, 0x32, 0x54, 0xc4, 0xdd, 0xb0, + 0x89, 0x2b, 0xe1, 0x1a, 0x0c, 0xf6, 0x26, 0xeb, + 0x6d, 0x39, 0x7a, 0x1a, 0x7d, 0x90, 0x87, 0x25, + 0xfb, 0x66, 0xaa, 0x1e, 0x3a, 0x2c, 0x36, 0x8c, + 0xed, 0x66, 0xbe, 0x53, 0xab, 0x82, 0xc7, 0xc9, + 0x66, 0xd3, 0x94, 0x91, 0xa7, 0xfd, 0xbb, 0x43, + 0x30, 0x7b, 0xaa, 0xdf, 0xad, 0x8e, 0x77, 0x7b, + 0x4f, 0x51, 0x1b, 0x4d, 0xd6, 0xc5, 0x05, 0x92, + 0xc9, 0x99, 0x2e, 0xc4, 0x64, 0x28, 0x2e, 0x97, + 0xf6, 0x82, 0x4a, 0x50, 0xdd, 0x20, 0x95, 0x63, + 0x2a, 0xc0, 0x0f, 0xb8, 0x45, 0x0d, 0xed, 0x28, + 0xaf, 0x3c, 0x5a, 0xbe, 0x66, 0xfb, 0x3c, 0xe0, + 0x23, 0x8d, 0x7e, 0x2e, 0x79, 0x32, 0xce, 0xd0, + 0x1a, 0x30, 0xca, 0xc7, 0x18, 0x9f, 0xca, 0xea, + 0x20, 0xf6, 0xb1, 0x2e, 0xd3, 0x41, 0xe3, 0x37, + 0xd1, 0x23, 0x99, 0x98, 0x8c, 0x11, 0x05, 0xe3, + 0x96, 0x07, 0x81, 0xb9, 0x9e, 0x4d, 0x4c, 0x45, + 0x16, 0xa8, 0x62, 0x07, 0xe8, 0xb1, 0x98, 0x26, + 0x41, 0x35, 0x87, 0x83, 0x23, 0x08, 0x2d, 0xec, + 0xa4, 0x02, 0x68, 0x4f, 0x2d, 0x19, 0xd7, 0xe1, + 0x38, 0x1d, 0x68, 0x30, 0xfa, 0xb5, 0x18, 0x5e, + 0x63, 0x31, 0xc1, 0x77, 0x98, 0xdd, 0xe3, 0xca, + 0x41, 0x5d, 0x6e, 0xf9, 0x67, 0xd1, 0x54, 0xc2, + 0xf1, 0x4a, 0xa3, 0x1b, 0xf4, 0xdc, 0x6c, 0x7d, + 0xf8, 0x8e, 0x4f, 0xc1, 0x84, 0xec, 0x8c, 0xc6, + 0xe8, 0x29, 0xe8, 0x73, 0x2c, 0xf4, 0xd6, 0x42, + 0x50, 0x46, 0xc8, 0x97, 0x34, 0x82, 0x73, 0xb3, + 0xd9, 0xca, 0x0f, 0xd9, 0x10, 0x63, 0x16, 0x48, + 0xa9, 0xb9, 0x2c, 0x06, 0xd5, 0x7e, 0xf3, 0x00, + 0x33, 0x0c, 0x70, 0xe7, 0x03, 0x29, 0x0f, 0xf7, + 0xd3, 0xcb, 0x23, 0x54, 0x1f, 0xe9, 0xaf, 0xa3, + 0xa4, 0x8d, 0xc2, 0x8a, 0x6c, 0x98, 0xb5, 0x6f, + 0x1c, 0x9d, 0x43, 0x0e, 0x5e, 0xdd, 0x11, 0x77, + 0x1d, 0xe1, 0x6e, 0xa5, 0x70, 0x6a, 0xb9, 0xee, + 0x43, 0x9f, 0xf9, 0xdd, 0xda, 0xe1, 0x8b, 0xfb, + 0x3d, 0x91, 0x33, 0xcc, 0xa1, 0x1b, 0xa4, 0x9e, + 0xd4, 0x1d, 0x39, 0xfd, 0xb9, 0x14, 0xf9, 0x26, + 0x8f, 0x9c, 0xc5, 0xa6, 0x33, 0x32, 0xc6, 0x18, + 0x1b, 0xf1, 0x28, 0xaf, 0x82, 0x02, 0x1f, 0x53, + 0x70, 0x0c, 0xd3, 0x1a, 0x66, 0xaf, 0x67, 0xde, + 0x94, 0x7e, 0x9f, 0x36, 0x0e, 0xf5, 0xdd, 0x45, + 0x02, 0x89, 0x05, 0x25, 0x1e, 0x2a, 0x44, 0xb3, + 0x05, 0xb4, 0xa4, 0x87, 0xb4, 0xc6, 0x20, 0x93, + 0xcd, 0x0c, 0x32, 0x4d, 0xe4, 0x85, 0x27, 0x29, + 0xbd, 0x79, 0x71, 0xf8, 0xc3, 0x95, 0x7d, 0x4a, + 0xb0, 0x34, 0x8b, 0x7f, 0xb2, 0x2b, 0x91, 0x08, + 0x66, 0x8d, 0x7d, 0x07, 0x61, 0x37, 0x8b, 0xa6, + 0x05, 0x24, 0x97, 0x02, 0x4a, 0xcc, 0x71, 0x4d, + 0xe5, 0xa4, 0x85, 0x3a, 0xdb, 0x5a, 0x11, 0xb3, + 0xa1, 0xbb, 0xfe, 0xc6, 0x7b, 0x2e, 0xd9, 0x72, + 0x55, 0xa2, 0x10, 0x58, 0x30, 0xb1, 0x98, 0x3d, + 0x0a, 0x76, 0x04, 0x5e, 0xef, 0x07, 0xb7, 0x5e, + 0x93, 0xb3, 0xee, 0x30, 0xe1, 0x1b, 0x79, 0x47, + 0xed, 0x77, 0x70, 0x00, 0x76, 0xea, 0x54, 0x41, + 0xff, 0xde, 0x4b, 0x7c, 0xdf, 0x82, 0x71, 0x01, + 0xe6, 0x83, 0x51, 0x37, 0x37, 0xeb, 0x31, 0x23, + 0xf4, 0x3a, 0x8d, 0xcc, 0x60, 0x2e, 0x08, 0x41, + 0x13, 0x49, 0xce, 0x36, 0xba, 0x63, 0x6f, 0x13, + 0x1a, 0x35, 0x2f, 0xc4, 0xa4, 0x8e, 0xc1, 0xf7, + 0x17, 0x16, 0xe7, 0xaa, 0xcc, 0xa9, 0x08, 0xe6, + 0xd6, 0x4b, 0xea, 0xdb, 0xbb, 0x88, 0xf4, 0x1c, + 0x4a, 0x25, 0xb9, 0x5b, 0x61, 0x7a, 0xc6, 0xb5, + 0x42, 0x97, 0xae, 0xe1, 0x3d, 0x3a, 0xc1, 0x58, + 0x25, 0x0d, 0xe5, 0x52, 0xb5, 0x8b, 0x16, 0x50, + 0xc0, 0x08, 0x93, 0xe0, 0x3a, 0x59, 0x1b, 0x59, + 0x4f, 0xfc, 0x05, 0x57, 0x06, 0xf1, 0xec, 0xf8, + 0x6a, 0x51, 0x63, 0x5c, 0x9c, 0x70, 0x80, 0xdb, + 0x15, 0xde, 0xdd, 0x46, 0xb2, 0x55, 0xde, 0xd1, + 0x14, 0x8e, 0x75, 0x40, 0xf9, 0x7d, 0x08, 0x67, + 0xac, 0xb6, 0xd9, 0x4d, 0xa0, 0x05, 0x34, 0x4a, + 0xc4, 0xfb, 0x79, 0x55, 0xf2, 0xc1, 0xd4, 0x5b, + 0x99, 0x21, 0x44, 0xca, 0xbf, 0x7d, 0xf8, 0x6e, + 0x1c, 0x3a, 0xe6, 0x0c, 0x38, 0xaa, 0xc7, 0xad, + 0x1e, 0x56, 0x3f, 0xab, 0x00, 0x2c, 0x0a, 0x75, + 0xe6, 0x55, 0x8d, 0x12, 0x3a, 0x3a, 0x21, 0x5d, + 0xd3, 0x87, 0xf0, 0xa3, 0xf7, 0xe1, 0x04, 0x8b, + 0x35, 0x7f, 0x87, 0x0a, 0x80, 0x88, 0xa4, 0xab, + 0x89, 0x29, 0x9d, 0xa2, 0x2b, 0x65, 0x81, 0x6c, + 0x71, 0x7b, 0x60, 0x8c, 0xbf, 0xdd, 0x65, 0x1d, + 0xc6, 0xc7, 0x40, 0x5a, 0x27, 0xe9, 0xc1, 0x1d, + 0x50, 0xee, 0xad, 0x07, 0xac, 0x2a, 0xf1, 0x5f, + 0x90, 0x9a, 0x8b, 0x5c, 0x92, 0x78, 0x44, 0xf8, + 0xfb, 0xd9, 0xcc, 0x4a, 0x3e, 0x84, 0xfa, 0x48, + 0x98, 0x3a, 0x07, 0x8f, 0x14, 0x74, 0x6c, 0x32, + 0xb9, 0x78, 0x92, 0xad, 0x9c, 0x39, 0x83, 0xb2, + 0xc1, 0x50, 0x61, 0x2b, 0xfa, 0xf1, 0x44, 0x52, + 0x78, 0x7a, 0x74, 0x25, 0xf4, 0x82, 0x40, 0x06, + 0xae, 0xde, 0x02, 0xd1, 0x22, 0x5e, 0x73, 0xe2, + 0x58, 0x40, 0x71, 0x2d, 0xc4, 0x79, 0xa9, 0x2b, + 0x41, 0x24, 0x4e, 0x36, 0x67, 0xab, 0xb6, 0x22, + 0xcc, 0x7d, 0x43, 0x39, 0x7c, 0xfa, 0xf8, 0xf2, + 0xcb, 0x05, 0x56, 0xae, 0x46, 0x3f, 0x60, 0xb5, + 0xda, 0xd2, 0x35, 0x6e, 0x78, 0x0a, 0x02, 0x17, + 0x90, 0x37, 0xa3, 0x1f, 0xcc, 0x8c, 0xfb, 0x44, + 0xd5, 0xcb, 0x9a, 0x38, 0x4c, 0x86, 0xf8, 0xa6, + 0xf3, 0x54, 0xa6, 0xb0, 0x7c, 0x7b, 0xff, 0xff, + 0xdf, 0xbe, 0xe9, 0xdd, 0xd2, 0xdc, 0x4b, 0x39, + 0x47, 0x12, 0xe5, 0x87, 0x14, 0x4f, 0x4a, 0x33, + 0x2d, 0x07, 0xc3, 0x85, 0x71, 0xf5, 0x9b, 0x40, + 0x3c, 0xde, 0x93, 0xcb, 0xc1, 0x0a, 0x0a, 0xf9, + 0x5c, 0x97, 0x04, 0x1b, 0x78, 0xbf, 0x27, 0xb2, + 0x7d, 0x85, 0xe3, 0x35, 0xe4, 0x71, 0xa3, 0x9d, + 0x92, 0x50, 0x37, 0xdf, 0xf4, 0x10, 0x53, 0xa3, + 0x84, 0x20, 0x76, 0xe9, 0x38, 0xe7, 0x10, 0x75, + 0x51, 0x02, 0x6f, 0xa6, 0xfb, 0xf2, 0x0e, 0x98, + 0x34, 0x9a, 0x43, 0x38, 0xd9, 0x16, 0x8f, 0xfa, + 0x09, 0x28, 0x2c, 0x42, 0x43, 0x4c, 0x81, 0x87, + 0x94, 0x95, 0xbb, 0xbc, 0xc6, 0xca, 0xd1, 0xdb, + 0xec, 0xf4, 0x09, 0x0a, 0x1a, 0x2c, 0x32, 0x34, + 0x3c, 0x49, 0x69, 0x76, 0x8e, 0x94, 0x9a, 0xa2, + 0xa7, 0xcc, 0xce, 0xd5, 0xeb, 0xed, 0xf6, 0x14, + 0x1c, 0x23, 0x32, 0x36, 0x44, 0x5e, 0x63, 0x6c, + 0x85, 0x8d, 0xa6, 0xb8, 0xb9, 0xe8, 0xeb, 0xf3, + 0x03, 0x1c, 0x21, 0x28, 0x59, 0x5d, 0x66, 0x8a, + 0x9f, 0xa2, 0xc1, 0xcc, 0xd2, 0xee, 0xf5, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x27, 0x38, 0x47 + }; + + return linuxkm_test_mldsa_driver(WOLFKM_MLDSA44_DRIVER, + mldsa44_pub, + (word32)sizeof(mldsa44_pub), + mldsa44_seed, + (word32)sizeof(mldsa44_seed), +#ifdef LINUXKM_MLDSA_SIGN + 1, +#else + 0, +#endif + mldsa44_sig, + (word32)sizeof(mldsa44_sig), + linuxkm_mldsa_test_msg, + (word32)sizeof(linuxkm_mldsa_test_msg)); +} +#endif /* LINUXKM_MLDSA44 */ + + +#ifdef LINUXKM_MLDSA65 +static int linuxkm_test_mldsa65(void) +{ + /* reference values generated with two independent implementations + * in agreement (OpenSSL master and dilithium-py), from the seed + * below: seed -> (pub, priv) per FIPS 204 ML-DSA.KeyGen_internal, + * and sig = deterministic-variant signature over msg with the + * default (empty) context. */ + static const byte mldsa65_seed[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f + }; + + static const byte mldsa65_pub[] = { + 0xc0, 0xf4, 0x84, 0x86, 0x49, 0xb3, 0xb8, 0xe6, + 0x61, 0xde, 0xb1, 0xd0, 0xf5, 0x3a, 0xc8, 0x76, + 0xf3, 0x2b, 0xd5, 0x0e, 0xb8, 0x12, 0xaa, 0xb8, + 0x20, 0x21, 0xfd, 0xa6, 0x5f, 0x3f, 0x15, 0xfa, + 0x42, 0x15, 0xc4, 0xad, 0x08, 0xb8, 0x29, 0xfa, + 0x60, 0xbf, 0x60, 0xa5, 0x93, 0x38, 0xb0, 0xf8, + 0x53, 0xce, 0x59, 0x3f, 0x86, 0x14, 0x7f, 0x42, + 0xc0, 0x36, 0x08, 0x51, 0x64, 0x56, 0x98, 0x04, + 0x28, 0xc7, 0x85, 0xaf, 0x9c, 0x00, 0x38, 0x80, + 0xc4, 0x1f, 0xe3, 0xb4, 0x7f, 0x80, 0x0e, 0xff, + 0x30, 0x33, 0xa8, 0xb6, 0x33, 0x3d, 0x41, 0xbd, + 0x6c, 0x1b, 0x96, 0x79, 0xe5, 0x6c, 0x50, 0x1c, + 0x9d, 0x3a, 0xbd, 0x49, 0x57, 0x3a, 0xc4, 0xe2, + 0x03, 0x27, 0xfd, 0x18, 0x2a, 0x03, 0x17, 0xfb, + 0xb9, 0xf5, 0x5d, 0xac, 0x2b, 0x03, 0xc6, 0xeb, + 0xc3, 0x64, 0x26, 0x3d, 0x8e, 0xe2, 0x4d, 0x3c, + 0x32, 0xde, 0x52, 0x58, 0xd0, 0xe3, 0x97, 0xf4, + 0x00, 0xee, 0x70, 0x22, 0x4a, 0x17, 0x1f, 0x31, + 0x2e, 0x35, 0xbe, 0x26, 0x1c, 0xc1, 0x8d, 0x14, + 0xff, 0x69, 0xbd, 0xaf, 0x11, 0x37, 0xbd, 0x93, + 0x6c, 0x06, 0x09, 0xa8, 0x16, 0xff, 0x1b, 0xe4, + 0xdd, 0xea, 0x9c, 0x3a, 0xd5, 0xd7, 0x94, 0x0e, + 0x45, 0xd1, 0xab, 0x7a, 0x06, 0x02, 0x48, 0xb2, + 0xc4, 0x59, 0x0a, 0xfc, 0x98, 0x2d, 0x0d, 0x11, + 0xa8, 0x40, 0xee, 0x50, 0xfe, 0x32, 0xb3, 0x17, + 0x7b, 0x81, 0xba, 0xc9, 0x81, 0x2f, 0x1c, 0xf4, + 0x23, 0xd1, 0x6b, 0x74, 0x04, 0xff, 0x6c, 0xb1, + 0xa1, 0xb7, 0x7f, 0x21, 0x2d, 0xb9, 0x14, 0x95, + 0xb7, 0x57, 0xf6, 0xec, 0xb3, 0x60, 0x35, 0x9f, + 0x70, 0x4f, 0x69, 0xf8, 0x73, 0xd0, 0xe6, 0x03, + 0x1d, 0x2e, 0x79, 0x73, 0xbd, 0x72, 0xdc, 0x67, + 0xf8, 0x31, 0x53, 0x51, 0x98, 0xfa, 0x80, 0x16, + 0xa0, 0xce, 0x50, 0xf6, 0x5c, 0xc5, 0x9d, 0xd3, + 0x9b, 0x77, 0x72, 0x90, 0x2c, 0xf5, 0x6c, 0x53, + 0x06, 0x57, 0xe1, 0xd3, 0xbb, 0xbc, 0x3e, 0x06, + 0xd5, 0x83, 0x72, 0x64, 0xa4, 0xac, 0x1d, 0x43, + 0xc1, 0xd7, 0xed, 0x6c, 0xad, 0x5c, 0x83, 0xab, + 0xc7, 0x4c, 0xe6, 0xce, 0x37, 0x9d, 0x4e, 0x9d, + 0x36, 0xcc, 0xfd, 0xdd, 0xd5, 0xf1, 0x77, 0x0d, + 0x7d, 0xea, 0x73, 0xd6, 0x2d, 0xce, 0x68, 0xb6, + 0x21, 0x96, 0xd1, 0xb1, 0x75, 0xbd, 0x93, 0xa4, + 0x83, 0xb7, 0x27, 0x4c, 0x29, 0x4b, 0x2b, 0xd4, + 0x2c, 0x75, 0xcc, 0x05, 0xd6, 0x09, 0x56, 0xc9, + 0x7d, 0x9f, 0x11, 0x64, 0xb4, 0xc1, 0x15, 0x15, + 0x7a, 0x58, 0x5a, 0xd2, 0x31, 0x33, 0x4e, 0x5a, + 0xfd, 0x99, 0xfa, 0xe4, 0x56, 0xeb, 0xa1, 0x9e, + 0x57, 0xc1, 0x67, 0xf3, 0x39, 0x48, 0xdd, 0x95, + 0x1f, 0xa6, 0x00, 0xcf, 0x7c, 0x80, 0xf5, 0xd4, + 0x95, 0x50, 0xd9, 0x71, 0xc6, 0x93, 0xe7, 0xa8, + 0x1f, 0xdf, 0x1d, 0xd4, 0x2f, 0x1c, 0x9f, 0x38, + 0x3c, 0xed, 0xe5, 0x0b, 0x86, 0x54, 0x69, 0x93, + 0x85, 0xac, 0xab, 0xfa, 0xab, 0xbd, 0xe2, 0x32, + 0xea, 0xca, 0x05, 0xe5, 0x86, 0x18, 0x95, 0x19, + 0x0f, 0x37, 0xd6, 0x0f, 0x60, 0x53, 0xf0, 0x1b, + 0xc2, 0x4a, 0xd1, 0x0e, 0x4a, 0xb8, 0xe2, 0xeb, + 0x76, 0x7b, 0x2a, 0xbb, 0xe6, 0xc7, 0x35, 0x09, + 0xd6, 0x7a, 0x7b, 0xfa, 0x6c, 0x13, 0x66, 0x46, + 0x5e, 0x5d, 0x3e, 0xd2, 0xd8, 0xda, 0x88, 0x36, + 0x9f, 0xd0, 0x1c, 0xe0, 0xe0, 0xa1, 0xce, 0xad, + 0x01, 0xd9, 0x3b, 0x9d, 0xea, 0xb7, 0xa5, 0xb5, + 0x2f, 0x8e, 0x85, 0x17, 0x29, 0x1c, 0x39, 0x39, + 0x7f, 0xdd, 0x69, 0x53, 0x0a, 0x7d, 0x87, 0x5c, + 0xe3, 0x96, 0x4b, 0x21, 0xbf, 0x6c, 0x3a, 0x24, + 0xcc, 0xf5, 0xc5, 0x2c, 0x21, 0x5a, 0x01, 0x0d, + 0xd2, 0x11, 0x2d, 0x2c, 0x58, 0xd7, 0xcd, 0x78, + 0xce, 0x3f, 0xff, 0x90, 0xeb, 0x32, 0xef, 0x67, + 0x49, 0x01, 0x8f, 0x70, 0x71, 0x70, 0x9a, 0x52, + 0x51, 0x04, 0x70, 0xb8, 0x7a, 0xa4, 0x44, 0x05, + 0x3c, 0xbc, 0x17, 0x62, 0xe6, 0x2f, 0xb4, 0x18, + 0x04, 0x35, 0x16, 0xc0, 0x23, 0x2c, 0x15, 0x09, + 0x36, 0xa8, 0xcc, 0x6f, 0x25, 0x64, 0x3d, 0xea, + 0x5b, 0x19, 0x62, 0xbe, 0x77, 0x01, 0xd2, 0xdd, + 0xfd, 0x08, 0x11, 0xc0, 0x99, 0xdd, 0x3b, 0x31, + 0x14, 0x43, 0xfd, 0x1c, 0x22, 0xde, 0xcd, 0x8c, + 0x77, 0xeb, 0x0c, 0x86, 0x9a, 0xbb, 0x96, 0xae, + 0x9b, 0x76, 0xeb, 0xdd, 0x3e, 0x04, 0x4f, 0x53, + 0xfc, 0xcc, 0x83, 0x28, 0xba, 0x4f, 0xd7, 0x38, + 0x57, 0xc5, 0x2c, 0xe4, 0x2f, 0xaa, 0xab, 0xab, + 0x92, 0x5b, 0x7d, 0xc2, 0xda, 0x5b, 0xbd, 0x2e, + 0x8b, 0xcb, 0xef, 0x2e, 0xa5, 0x35, 0xc2, 0x6f, + 0x53, 0xd9, 0xa6, 0x86, 0xcc, 0xc4, 0xcc, 0xe6, + 0x28, 0x79, 0x81, 0xdc, 0xf4, 0x1e, 0xab, 0x40, + 0x3c, 0xb1, 0x8d, 0x22, 0x4c, 0x5f, 0x24, 0xe5, + 0x64, 0x17, 0x49, 0x6f, 0x0a, 0x15, 0x56, 0xbb, + 0x35, 0xbf, 0x62, 0x21, 0x93, 0xed, 0xbc, 0x11, + 0xb0, 0xf3, 0x3b, 0x8b, 0x4d, 0xb8, 0x21, 0x8c, + 0xbb, 0x3c, 0xd7, 0x56, 0x93, 0xa8, 0xab, 0x49, + 0x84, 0xd8, 0x90, 0xe2, 0xaa, 0x04, 0xad, 0xcd, + 0xa0, 0x99, 0xca, 0xe0, 0x7f, 0x24, 0x1d, 0x70, + 0x6c, 0xf8, 0xb8, 0xfb, 0x16, 0xb8, 0x93, 0xc9, + 0xd0, 0x01, 0x1f, 0xe8, 0xb2, 0x19, 0x33, 0x9c, + 0x8f, 0xe1, 0xa6, 0xd6, 0x30, 0x5d, 0x86, 0x6b, + 0xc0, 0x91, 0x37, 0xfc, 0xdc, 0x31, 0x38, 0xc9, + 0xf7, 0x84, 0x55, 0x58, 0x35, 0xf2, 0x2a, 0xa2, + 0x38, 0x24, 0xbf, 0xa5, 0x17, 0xbd, 0x0b, 0xfb, + 0x24, 0x27, 0x48, 0x2f, 0x3b, 0xb2, 0x97, 0x16, + 0xa2, 0xfa, 0x88, 0x53, 0x4c, 0x56, 0xfc, 0x45, + 0xe6, 0x83, 0xd3, 0x22, 0x70, 0x89, 0x44, 0x47, + 0x6b, 0x09, 0xc6, 0xac, 0xfd, 0x1f, 0xdf, 0xfc, + 0xa5, 0xf7, 0xda, 0x8a, 0xc4, 0xe3, 0x4d, 0x3c, + 0xc0, 0x7a, 0x5a, 0xf2, 0x36, 0xe3, 0x0b, 0x1c, + 0xac, 0xf6, 0xe7, 0x16, 0xe5, 0xfe, 0x65, 0x26, + 0x7f, 0xea, 0x0b, 0x75, 0x0e, 0x24, 0xae, 0x09, + 0xfa, 0x84, 0xca, 0xcf, 0x65, 0x43, 0x78, 0xa2, + 0xe7, 0x2d, 0x37, 0x62, 0xd4, 0xb6, 0x7e, 0xcf, + 0x82, 0x20, 0xa6, 0x97, 0x8f, 0x4b, 0x9e, 0xd9, + 0x9e, 0xda, 0xcd, 0xe4, 0x5d, 0x61, 0xc3, 0x49, + 0x5c, 0xdc, 0x13, 0x82, 0x3d, 0x1b, 0x13, 0xe9, + 0x59, 0x52, 0xa9, 0x5e, 0x2f, 0xf0, 0xde, 0x99, + 0x32, 0xf9, 0xc7, 0x60, 0xfe, 0xb4, 0xfb, 0x27, + 0xc5, 0x99, 0xa0, 0xe7, 0x46, 0xb2, 0x28, 0xcb, + 0x85, 0xdb, 0x5b, 0x82, 0x46, 0x93, 0xf9, 0x35, + 0x89, 0xa5, 0xa2, 0xbe, 0x01, 0xaa, 0x9e, 0x4c, + 0xcb, 0x25, 0xe9, 0xa1, 0xa6, 0x1e, 0xf4, 0x1f, + 0xde, 0x32, 0x74, 0x3f, 0x01, 0x3c, 0x2a, 0x7a, + 0x5b, 0x5f, 0x3a, 0x4f, 0x01, 0xad, 0x7c, 0x41, + 0x1e, 0x29, 0xa9, 0x6c, 0x96, 0x92, 0xf2, 0xc1, + 0xbb, 0xce, 0x8d, 0x0b, 0x72, 0x36, 0x8c, 0xf7, + 0x5a, 0xa5, 0x3d, 0xf0, 0xaa, 0x4b, 0x26, 0xda, + 0xac, 0x48, 0xaf, 0xb3, 0x5e, 0x64, 0xbe, 0x1d, + 0x35, 0x75, 0x5b, 0x49, 0x35, 0x4b, 0x08, 0xa3, + 0xb2, 0xb8, 0x06, 0xa2, 0xf9, 0x9f, 0xfc, 0x8e, + 0xca, 0x69, 0x44, 0xb1, 0x46, 0xc5, 0x26, 0x45, + 0x62, 0x59, 0x3a, 0x74, 0xce, 0xdb, 0xcf, 0xb4, + 0x67, 0x34, 0x8d, 0x89, 0x04, 0x42, 0xf6, 0x2e, + 0x62, 0x02, 0xed, 0x8a, 0x42, 0x8e, 0xd3, 0x3e, + 0x20, 0x75, 0xd5, 0x91, 0x7e, 0x19, 0x3a, 0x20, + 0x2c, 0x0d, 0xe9, 0xf2, 0x5e, 0xde, 0x01, 0xd3, + 0x41, 0xc8, 0xce, 0x72, 0x2f, 0x4e, 0x60, 0x89, + 0x16, 0x10, 0x63, 0x4b, 0x03, 0x14, 0xe9, 0x36, + 0x3a, 0x5a, 0x4f, 0x0b, 0xe8, 0x3d, 0x38, 0x6c, + 0xfd, 0x04, 0x20, 0x7e, 0xf5, 0xe8, 0x49, 0x44, + 0xc1, 0x89, 0xbe, 0x4a, 0x6c, 0xed, 0x82, 0x6c, + 0x5b, 0xea, 0xd5, 0x0f, 0xd3, 0xc6, 0xae, 0x48, + 0x92, 0xb1, 0xd2, 0xcc, 0x76, 0x84, 0xd2, 0xcc, + 0x3d, 0xbe, 0x31, 0x04, 0xf1, 0x86, 0x59, 0x01, + 0xd0, 0x23, 0x62, 0xe3, 0x4f, 0xf2, 0xe7, 0x64, + 0x9e, 0xd3, 0x6c, 0xde, 0xf0, 0x71, 0x01, 0x5b, + 0xcc, 0x62, 0xb5, 0x04, 0xb6, 0x58, 0x7b, 0xcc, + 0xd2, 0xab, 0x37, 0xb2, 0xfd, 0x2b, 0xf6, 0x00, + 0x26, 0xc9, 0x10, 0xfc, 0xad, 0xaa, 0x8b, 0x51, + 0xd1, 0x6c, 0x0e, 0xce, 0x65, 0x52, 0x79, 0x47, + 0x3a, 0x64, 0xba, 0x5a, 0x99, 0x0b, 0x0b, 0x69, + 0xf8, 0x51, 0x08, 0x3d, 0xb9, 0xa4, 0x0f, 0x63, + 0x3a, 0x94, 0x54, 0x0a, 0x90, 0xdd, 0x85, 0x21, + 0xad, 0x0a, 0x58, 0xb7, 0x91, 0xd3, 0x99, 0x69, + 0x9b, 0x43, 0x29, 0xd2, 0xc1, 0x83, 0xfe, 0x6e, + 0x60, 0xb9, 0xdf, 0x44, 0xc2, 0x48, 0x05, 0xc4, + 0x84, 0x74, 0x0e, 0x07, 0x62, 0x92, 0x51, 0x57, + 0x91, 0x24, 0xc0, 0x08, 0x37, 0xac, 0x37, 0x04, + 0x07, 0xf3, 0x9f, 0xe3, 0xfc, 0xaf, 0x06, 0xc8, + 0x6f, 0xa8, 0x24, 0x8f, 0x30, 0xa3, 0x08, 0xb8, + 0xe4, 0xcb, 0x34, 0x83, 0xf1, 0x47, 0xc4, 0xd3, + 0xe6, 0x77, 0xbf, 0x54, 0x25, 0xbc, 0x5e, 0x4a, + 0xb3, 0x89, 0x73, 0xb8, 0x75, 0x5c, 0x92, 0x10, + 0x68, 0x14, 0x16, 0xf0, 0x0b, 0x93, 0xa4, 0xc5, + 0xde, 0x62, 0xb2, 0x32, 0x3a, 0xcf, 0x6c, 0x4e, + 0x17, 0x3e, 0x0f, 0xc2, 0x40, 0x22, 0x46, 0xb5, + 0x78, 0xec, 0xae, 0x6f, 0x05, 0xfe, 0x48, 0x54, + 0x9a, 0x6d, 0x4b, 0xf1, 0x1f, 0x37, 0xa4, 0x13, + 0x21, 0x3e, 0x35, 0xdf, 0x54, 0x48, 0xf0, 0x5f, + 0xe3, 0xaa, 0xc1, 0x0f, 0x0a, 0x74, 0x24, 0x9d, + 0xce, 0xf3, 0x3e, 0xe9, 0xcc, 0xc4, 0x7e, 0xe8, + 0x9a, 0x3b, 0xed, 0xef, 0x7d, 0x17, 0xd3, 0xb6, + 0x94, 0x0f, 0x7b, 0x76, 0xa5, 0xa0, 0xb9, 0xfc, + 0x66, 0x3e, 0x36, 0x53, 0xb6, 0x7d, 0x63, 0x9a, + 0x38, 0x6f, 0x0d, 0x17, 0x7c, 0xfd, 0xdb, 0x62, + 0x33, 0x8c, 0x91, 0x4c, 0x95, 0xfd, 0x01, 0xe8, + 0x39, 0x21, 0xbf, 0xe0, 0x69, 0x8b, 0x20, 0xad, + 0xec, 0x0d, 0xa8, 0xdd, 0xec, 0x3f, 0x2c, 0xe1, + 0x38, 0x19, 0x9c, 0x57, 0x63, 0x04, 0x3b, 0x02, + 0xe3, 0x3b, 0xc9, 0x17, 0x65, 0x92, 0x22, 0x29, + 0x33, 0x78, 0x9a, 0x41, 0x81, 0x95, 0x35, 0xb2, + 0xa6, 0x95, 0xcb, 0x0f, 0xa5, 0xa1, 0xd6, 0xe1, + 0x31, 0xa6, 0x8e, 0x37, 0x62, 0xc8, 0x70, 0x35, + 0xa9, 0x9a, 0x7e, 0xd9, 0x73, 0xb6, 0xde, 0x93, + 0x51, 0xaf, 0x10, 0x0c, 0x48, 0x44, 0xe4, 0x88, + 0x48, 0xc6, 0x28, 0xbf, 0xd9, 0x74, 0xb8, 0x3b, + 0x0e, 0x46, 0x8a, 0xd7, 0xa4, 0x8b, 0x03, 0x3a, + 0xd4, 0x91, 0xdd, 0x73, 0x60, 0x17, 0x72, 0xdd, + 0x14, 0x67, 0xec, 0x1a, 0x28, 0x9e, 0x81, 0x51, + 0x5e, 0xfa, 0x17, 0x09, 0xbd, 0x23, 0xbf, 0x42, + 0x00, 0xfc, 0x9e, 0xca, 0x98, 0x5a, 0x19, 0xef, + 0x66, 0x44, 0x55, 0x07, 0x0c, 0xfd, 0xa1, 0x34, + 0x89, 0xed, 0x06, 0xbc, 0x9c, 0x25, 0x5c, 0x1b, + 0x5d, 0xae, 0x2f, 0x56, 0x0b, 0x5e, 0xff, 0xa4, + 0x35, 0x39, 0xa3, 0xf2, 0xdf, 0x3d, 0xe0, 0x1a, + 0xcf, 0xdf, 0xfb, 0xd1, 0x12, 0xed, 0x4c, 0x49, + 0xc1, 0x5c, 0x3d, 0xbc, 0x63, 0x21, 0xf6, 0x92, + 0x74, 0x7d, 0xa8, 0x5f, 0x33, 0xe1, 0x29, 0xbd, + 0x65, 0x5c, 0x69, 0x8b, 0x78, 0xfb, 0x60, 0x8f, + 0xcc, 0x02, 0x6c, 0xee, 0x86, 0x54, 0x76, 0x01, + 0x1f, 0x8f, 0x77, 0xe1, 0x49, 0xec, 0x9a, 0x3d, + 0x87, 0x82, 0xa6, 0xd2, 0x34, 0x0c, 0x0d, 0xb6, + 0x92, 0x20, 0x04, 0xaf, 0x59, 0xd3, 0xdb, 0x4a, + 0xc7, 0xfd, 0x88, 0x1e, 0xf6, 0x47, 0xc8, 0xf8, + 0x87, 0x74, 0x39, 0xa5, 0x03, 0x36, 0xc7, 0x02, + 0x09, 0xb9, 0x37, 0x34, 0xb1, 0x4d, 0x4f, 0xf2, + 0x89, 0x45, 0x47, 0x1b, 0x31, 0xfc, 0x32, 0xb0, + 0x30, 0xf2, 0x22, 0x40, 0xd2, 0xca, 0x27, 0x14, + 0xa4, 0x82, 0xc3, 0x9c, 0xa3, 0x6d, 0x46, 0x46, + 0x7c, 0x48, 0x4d, 0xfb, 0x96, 0x6b, 0xb8, 0x35, + 0x48, 0xa4, 0x57, 0x10, 0xbd, 0xaa, 0xce, 0xe0, + 0x3b, 0x4d, 0x35, 0x32, 0xb5, 0x41, 0xd1, 0x6f, + 0x48, 0x22, 0x2b, 0x9c, 0xc9, 0x1d, 0x47, 0x38, + 0x11, 0xf3, 0x01, 0xe9, 0x13, 0x83, 0xfb, 0x57, + 0x95, 0x78, 0xc3, 0x05, 0x03, 0xee, 0x91, 0x26, + 0x2c, 0xae, 0xec, 0x2f, 0x74, 0xaf, 0xd2, 0x93, + 0x11, 0x2d, 0x0f, 0x82, 0xf0, 0x5f, 0x2b, 0xb8, + 0x5b, 0x1f, 0x2e, 0x51, 0x0b, 0xad, 0x10, 0x1e, + 0x21, 0xb0, 0x05, 0xa6, 0xea, 0x1c, 0xda, 0xed, + 0xf5, 0x41, 0xe0, 0x30, 0xfc, 0xab, 0xcb, 0x31, + 0x52, 0x22, 0x3a, 0x28, 0x57, 0x67, 0x85, 0xa1, + 0xc4, 0x9c, 0xbc, 0x9c, 0xb2, 0xc8, 0xdb, 0x4c, + 0xe7, 0xab, 0x82, 0x8f, 0xa7, 0x69, 0x0d, 0xe9, + 0x05, 0xd1, 0xc3, 0x8d, 0xfe, 0x68, 0xa4, 0x4d, + 0x80, 0x61, 0xce, 0x4a, 0x93, 0x76, 0x33, 0x5c, + 0xd0, 0x00, 0x1d, 0x8b, 0x8a, 0x5d, 0x1f, 0x81, + 0x9e, 0x91, 0x9f, 0x2b, 0xc5, 0x2e, 0x5f, 0x3b, + 0x25, 0xa2, 0x4f, 0xa8, 0x62, 0xcd, 0x94, 0xa2, + 0x05, 0x2e, 0xba, 0x9e, 0xd4, 0x16, 0x14, 0xd4, + 0xb0, 0x7b, 0x38, 0x16, 0x5b, 0x76, 0x84, 0x6d, + 0x84, 0x28, 0x2f, 0x3d, 0xf9, 0x20, 0xd0, 0xce, + 0x19, 0xaf, 0x8b, 0x1f, 0xf1, 0x88, 0x90, 0xe9, + 0x71, 0x7f, 0xd9, 0xe2, 0x55, 0x68, 0x18, 0x5a, + 0x66, 0x3c, 0xca, 0xcb, 0x84, 0x62, 0xf1, 0x6c, + 0x47, 0x1e, 0xfc, 0x99, 0xf3, 0xb4, 0x89, 0x2b, + 0xae, 0x85, 0xee, 0x71, 0x43, 0x4e, 0x59, 0xe2, + 0x4b, 0xda, 0x03, 0x05, 0x5f, 0xb0, 0x3e, 0xc0, + 0x57, 0xc7, 0x70, 0x07, 0x9a, 0x5d, 0xdc, 0xfe, + 0x2d, 0xd5, 0x41, 0x86, 0x20, 0x2d, 0x20, 0x3a, + 0xe4, 0xbb, 0x43, 0x35, 0x54, 0x3c, 0xb0, 0x5e, + 0xc6, 0xc2, 0xca, 0x82, 0xe6, 0x23, 0x48, 0x89, + 0xfa, 0x44, 0xc0, 0xa1, 0x8b, 0x59, 0xc6, 0x59, + 0xa7, 0xe3, 0x0e, 0xae, 0xbc, 0x9a, 0x83, 0x95, + 0xae, 0x40, 0x6a, 0x70, 0x7d, 0x15, 0x65, 0x4d, + 0x14, 0x28, 0xd9, 0x64, 0x7a, 0x4e, 0x03, 0xc8, + 0xaa, 0x98, 0xf4, 0xbc, 0x49, 0xe0, 0xd2, 0x24, + 0x0d, 0x77, 0x88, 0xdc, 0x07, 0x2c, 0x86, 0x93, + 0x0e, 0xc5, 0xa3, 0x10, 0x33, 0x30, 0x56, 0x55, + 0xd7, 0x06, 0xdd, 0xee, 0xe2, 0x57, 0x7e, 0x9a, + 0x5d, 0x33, 0x5b, 0xfb, 0x60, 0x14, 0xb2, 0x05, + 0x51, 0x2e, 0x7d, 0xa4, 0x32, 0x7c, 0xce, 0x92, + 0xd9, 0x9e, 0x13, 0xdb, 0xcd, 0x80, 0xf3, 0x2c + }; + + static const byte mldsa65_sig[] = { + 0x29, 0xb1, 0x4a, 0x38, 0x8e, 0xf3, 0x1b, 0xdf, + 0xb6, 0xd1, 0x5f, 0x69, 0x4a, 0x06, 0x27, 0x50, + 0x9b, 0x7f, 0xd5, 0xc1, 0x9e, 0x44, 0x9f, 0x41, + 0x3f, 0xd4, 0x23, 0x3d, 0x83, 0x42, 0x39, 0x9b, + 0x6c, 0xbf, 0xc9, 0xf9, 0x7b, 0xee, 0x6a, 0xb0, + 0xb0, 0x59, 0x57, 0xe7, 0xe3, 0x7e, 0xce, 0x50, + 0xa5, 0x8e, 0x22, 0xc9, 0x88, 0x39, 0x88, 0x67, + 0xe2, 0x4a, 0x8e, 0xc1, 0x6f, 0x4a, 0x78, 0x4a, + 0xd9, 0xa1, 0x4b, 0x0c, 0x49, 0xde, 0x2d, 0xa4, + 0x80, 0x8d, 0x00, 0x33, 0x27, 0x7d, 0x2d, 0xed, + 0xfe, 0x98, 0xab, 0x7e, 0x8d, 0x89, 0x53, 0x58, + 0xe2, 0x1e, 0xc9, 0xcc, 0x53, 0x4d, 0xab, 0xf2, + 0xbf, 0x86, 0xb0, 0x6d, 0x8c, 0x2f, 0x0e, 0xee, + 0x92, 0xc8, 0x2f, 0xec, 0x2d, 0x9e, 0xcf, 0x8e, + 0xaf, 0x3d, 0xfc, 0x28, 0xbf, 0x5e, 0xd6, 0xf2, + 0xc5, 0x9c, 0xfa, 0xeb, 0x1b, 0x1e, 0x12, 0x9c, + 0x60, 0xc2, 0x8a, 0x39, 0x11, 0x2e, 0x1e, 0x3b, + 0x5e, 0x57, 0x86, 0x62, 0x8c, 0x8c, 0x79, 0x6c, + 0x89, 0xfc, 0x5b, 0x65, 0xf8, 0x86, 0x8b, 0xd4, + 0xd9, 0x14, 0x37, 0xbc, 0x9c, 0xdd, 0xbd, 0x60, + 0xaf, 0x24, 0x36, 0x87, 0x34, 0x50, 0x9c, 0xfb, + 0x30, 0xee, 0x43, 0x38, 0xd4, 0x81, 0x05, 0xb9, + 0xa0, 0xf4, 0x02, 0xfb, 0x3b, 0x5f, 0x40, 0x78, + 0x2f, 0xf9, 0xe9, 0xd3, 0xc2, 0x96, 0xc7, 0xd8, + 0xdf, 0xb0, 0xe6, 0x18, 0xd1, 0x04, 0x12, 0x32, + 0x06, 0x9a, 0xdb, 0x74, 0x79, 0x66, 0xb5, 0x72, + 0x63, 0xbb, 0xd5, 0x34, 0x24, 0xcf, 0x16, 0x8a, + 0x49, 0x01, 0x30, 0x48, 0x31, 0x06, 0xaf, 0x65, + 0x55, 0x73, 0x23, 0x6c, 0xd3, 0x73, 0x82, 0x88, + 0x6b, 0x12, 0xa8, 0x80, 0x78, 0xa9, 0x19, 0x52, + 0x0c, 0x2b, 0xe3, 0x8e, 0x79, 0x0d, 0xec, 0x04, + 0x54, 0x20, 0x6d, 0x56, 0x5a, 0x62, 0x03, 0xe3, + 0x10, 0x2b, 0x70, 0xc0, 0x00, 0x6f, 0x8a, 0xd3, + 0x7c, 0x54, 0x8b, 0x94, 0xfd, 0x55, 0xfa, 0x77, + 0x13, 0x11, 0xaf, 0x7d, 0x27, 0xf5, 0x33, 0xc0, + 0x21, 0xad, 0x4f, 0x6a, 0xc4, 0x3a, 0xec, 0x4c, + 0xd6, 0xae, 0x17, 0x33, 0xba, 0x5c, 0x0c, 0x60, + 0xfd, 0x37, 0x1a, 0x59, 0x83, 0xdb, 0x14, 0x0b, + 0xe1, 0x7a, 0x07, 0x21, 0x21, 0x8c, 0x38, 0xfd, + 0xdd, 0xcb, 0x78, 0x39, 0xc8, 0x56, 0xd7, 0x29, + 0x25, 0x14, 0xc5, 0x88, 0x4b, 0x88, 0xf1, 0x65, + 0x8f, 0x9d, 0x00, 0x7e, 0x32, 0xe3, 0x07, 0xd7, + 0xd7, 0xb2, 0x11, 0x70, 0x2e, 0x60, 0x2d, 0x59, + 0xb9, 0x16, 0x95, 0x32, 0x47, 0xc5, 0x7f, 0xee, + 0x6f, 0x60, 0x42, 0x23, 0x07, 0xf2, 0x68, 0xfb, + 0x8a, 0x6c, 0xdd, 0x0c, 0xf5, 0x10, 0xf3, 0xe7, + 0x46, 0x83, 0x16, 0x23, 0x64, 0x2a, 0xa0, 0x81, + 0x26, 0xdb, 0x79, 0xb7, 0xff, 0x32, 0x25, 0x32, + 0xdb, 0x0e, 0x35, 0xf6, 0xfa, 0xd0, 0xc3, 0xc9, + 0x43, 0x78, 0x02, 0xb3, 0x57, 0x60, 0x82, 0x1c, + 0x05, 0xe1, 0xde, 0x81, 0x49, 0x0b, 0x2f, 0xbf, + 0x17, 0xec, 0xb4, 0x83, 0x04, 0xc0, 0x83, 0x89, + 0xd4, 0x9f, 0x21, 0xe1, 0x22, 0xcb, 0x18, 0x15, + 0x27, 0x24, 0xe8, 0x4e, 0x22, 0xb1, 0x16, 0xdc, + 0x7b, 0x6c, 0x69, 0xf9, 0x1c, 0xa8, 0xb9, 0x23, + 0x5a, 0xd7, 0x7a, 0xec, 0xff, 0x89, 0x9d, 0xd7, + 0x32, 0x72, 0x60, 0x7e, 0xa2, 0x61, 0x8e, 0x53, + 0xc6, 0x41, 0x19, 0x54, 0x53, 0x7e, 0xee, 0x09, + 0x65, 0x07, 0x50, 0x92, 0xfa, 0xf2, 0x06, 0x48, + 0xd1, 0xe8, 0x40, 0xb0, 0xa6, 0xf0, 0x45, 0x67, + 0x0d, 0x86, 0xd1, 0xc6, 0x84, 0x6f, 0x3c, 0x67, + 0x9c, 0x6a, 0xbf, 0x10, 0xd4, 0x17, 0x21, 0x6f, + 0x3b, 0x5c, 0x38, 0x0c, 0xd4, 0xe6, 0xa3, 0xd7, + 0x51, 0xb4, 0x49, 0x7b, 0x88, 0x6c, 0xea, 0x94, + 0x8b, 0xee, 0xf3, 0x0f, 0xa3, 0x83, 0x9e, 0x27, + 0x32, 0xf7, 0x72, 0xfe, 0x31, 0x7e, 0xf1, 0xd0, + 0xed, 0xf6, 0x5d, 0xe2, 0xb9, 0x4d, 0x8e, 0x30, + 0x34, 0x5f, 0xef, 0x4a, 0x20, 0x88, 0x5f, 0xe1, + 0x6c, 0x8d, 0x6e, 0xc1, 0x3b, 0x75, 0x53, 0x6c, + 0x01, 0x09, 0xd8, 0xf2, 0xb7, 0x57, 0x4e, 0x04, + 0x42, 0xcd, 0xc2, 0x31, 0x6e, 0x7e, 0x0a, 0x81, + 0x14, 0xcc, 0x8a, 0x6e, 0x03, 0x6d, 0xdd, 0xaf, + 0xf1, 0x0b, 0x5f, 0xcf, 0x2e, 0xf4, 0x60, 0x9d, + 0x72, 0x62, 0x33, 0xce, 0x5e, 0x10, 0xa7, 0x30, + 0x14, 0x2c, 0x40, 0x1a, 0xef, 0xf9, 0x00, 0x60, + 0xfd, 0xdc, 0xda, 0xbd, 0x99, 0x58, 0x21, 0xe9, + 0x68, 0x18, 0x4d, 0x05, 0x58, 0x30, 0x99, 0x45, + 0xe8, 0xba, 0x4b, 0x79, 0x20, 0x26, 0xf9, 0x22, + 0x47, 0x3e, 0xcd, 0x1c, 0x96, 0x05, 0xe9, 0xd8, + 0x90, 0x53, 0xcc, 0xbb, 0xd0, 0xf0, 0x40, 0x3a, + 0x09, 0x2a, 0x5f, 0xd3, 0x44, 0x6e, 0xfd, 0x36, + 0x8e, 0x6b, 0xb9, 0x17, 0xea, 0x01, 0x49, 0x17, + 0x1b, 0x85, 0x2e, 0x75, 0x16, 0x22, 0x95, 0x31, + 0xcb, 0x33, 0xaf, 0xf2, 0x01, 0x99, 0xb3, 0xc9, + 0xd7, 0x2e, 0x02, 0xbf, 0xe4, 0xd9, 0xd5, 0xd3, + 0x4b, 0x72, 0x75, 0xbd, 0xd4, 0xb9, 0xe5, 0xc1, + 0x71, 0x0a, 0x46, 0xce, 0x82, 0x0f, 0x23, 0xdc, + 0xe9, 0xc4, 0x65, 0x7f, 0x78, 0xca, 0x7c, 0x15, + 0xcc, 0x17, 0x30, 0xe3, 0xfc, 0x39, 0xce, 0xe3, + 0xc5, 0x3a, 0x25, 0xc4, 0xb1, 0xf5, 0x0f, 0x79, + 0x29, 0xf2, 0x2d, 0xbb, 0xcb, 0xc5, 0xdc, 0x16, + 0xfb, 0xc4, 0x3f, 0x7a, 0xbf, 0x8f, 0xe0, 0xfe, + 0x3f, 0x6d, 0x7a, 0x0f, 0x49, 0x70, 0xcb, 0x70, + 0x30, 0x62, 0xea, 0x30, 0xa0, 0x8f, 0xf5, 0x57, + 0x91, 0x2a, 0x2d, 0x6d, 0xec, 0xa5, 0x7b, 0xf5, + 0xe0, 0xa9, 0x84, 0x08, 0x25, 0x8c, 0x30, 0xda, + 0x7c, 0xe4, 0x44, 0x8c, 0xb7, 0xed, 0xfa, 0x87, + 0x84, 0xcf, 0x47, 0xfc, 0xef, 0x04, 0x5c, 0xd4, + 0xf8, 0xb3, 0xb6, 0xdf, 0x5d, 0x4b, 0x4d, 0x0b, + 0xe9, 0x96, 0x25, 0xe5, 0x01, 0x47, 0x69, 0x84, + 0x89, 0x61, 0xf7, 0xca, 0x74, 0xae, 0x29, 0xe5, + 0x5c, 0xdb, 0x6a, 0x4d, 0x29, 0xb7, 0x4e, 0xc7, + 0xa1, 0x60, 0xea, 0xdb, 0x8a, 0x01, 0xd5, 0xb7, + 0x4c, 0x8d, 0xff, 0xe7, 0xd7, 0xd6, 0xe6, 0x2c, + 0x95, 0xdd, 0x67, 0x0b, 0xa2, 0x56, 0x33, 0x68, + 0x92, 0x88, 0xb0, 0xa5, 0xe5, 0x68, 0xf0, 0xfc, + 0xcb, 0x03, 0x6c, 0x76, 0xa7, 0xaf, 0xe9, 0xc2, + 0x9b, 0x95, 0x74, 0x71, 0xba, 0xe4, 0xa5, 0x57, + 0x8f, 0xdb, 0x7b, 0x65, 0x4f, 0xe9, 0x5d, 0x34, + 0x7c, 0x6e, 0x04, 0x18, 0x28, 0x20, 0x93, 0x9b, + 0x95, 0x1a, 0x44, 0x28, 0xa2, 0x8b, 0x7b, 0x8a, + 0xdd, 0xfc, 0x7a, 0x83, 0x8e, 0xb3, 0x82, 0x68, + 0x1f, 0x3d, 0x1e, 0xcb, 0xb2, 0x6a, 0x52, 0x3f, + 0xdf, 0x6c, 0x08, 0x98, 0x7a, 0x68, 0xab, 0xca, + 0x46, 0xa0, 0xbe, 0x26, 0x85, 0x1c, 0xd5, 0xbf, + 0xce, 0x61, 0x47, 0x8c, 0x94, 0x38, 0xe3, 0x89, + 0xfc, 0x61, 0xf9, 0x30, 0x44, 0x52, 0x98, 0x42, + 0x44, 0xa8, 0x88, 0x8a, 0x30, 0xb1, 0x26, 0xd6, + 0x89, 0xdf, 0x4d, 0x80, 0x17, 0x7b, 0xeb, 0x4b, + 0x98, 0x06, 0x0e, 0x98, 0xdf, 0xfa, 0xa1, 0x90, + 0xbe, 0x93, 0x21, 0xb1, 0x2e, 0xfe, 0x84, 0x53, + 0x59, 0x68, 0x82, 0xdb, 0x48, 0xe1, 0x3d, 0xb2, + 0xf5, 0x02, 0xa5, 0x23, 0x46, 0xf5, 0x9c, 0x4a, + 0xd3, 0xa2, 0x07, 0xe4, 0x5f, 0x4b, 0xab, 0xf1, + 0x99, 0x11, 0x3f, 0xc4, 0x71, 0x19, 0xb1, 0xd1, + 0x21, 0xf1, 0x46, 0xc1, 0x38, 0xf2, 0x4b, 0x89, + 0x19, 0xcb, 0x11, 0x6b, 0xf3, 0xf4, 0x92, 0xf8, + 0x27, 0x68, 0x86, 0x34, 0x04, 0xee, 0x8a, 0x71, + 0x89, 0xee, 0x93, 0x3d, 0x83, 0xf0, 0x41, 0x8d, + 0x0a, 0x6d, 0xf5, 0xb6, 0x40, 0x03, 0x71, 0x1c, + 0xc8, 0x3f, 0x6a, 0x6e, 0xa2, 0x7a, 0x8f, 0x26, + 0xd9, 0x7a, 0x4d, 0x27, 0x19, 0x5b, 0x60, 0x2b, + 0xef, 0x93, 0x09, 0xcc, 0xc5, 0xf2, 0x28, 0x58, + 0x87, 0x07, 0xd6, 0x5c, 0x5b, 0xc6, 0xd9, 0x58, + 0x78, 0xb2, 0x63, 0x73, 0x65, 0x8c, 0xc5, 0x67, + 0xc0, 0x73, 0xfd, 0x12, 0x12, 0x45, 0x7e, 0x25, + 0xfd, 0x96, 0xd1, 0x55, 0xc9, 0x3a, 0x78, 0x4b, + 0xf8, 0x4d, 0xa7, 0xc6, 0xe3, 0x63, 0x58, 0xfc, + 0x04, 0xbc, 0xf1, 0x55, 0x1d, 0x40, 0x8b, 0x67, + 0x35, 0x68, 0x6e, 0x0f, 0x86, 0x21, 0x5c, 0x9b, + 0xc6, 0xad, 0xfb, 0x69, 0xa6, 0x22, 0x69, 0x48, + 0x1e, 0x52, 0x34, 0x33, 0x6a, 0x61, 0x52, 0x67, + 0x3d, 0xe2, 0xd5, 0xdb, 0x53, 0xe0, 0xea, 0x6e, + 0x70, 0x0a, 0xae, 0x17, 0x4b, 0xbc, 0x57, 0x60, + 0x7e, 0x28, 0xee, 0x1e, 0x7a, 0x18, 0x2e, 0x47, + 0x13, 0xbe, 0xd7, 0x83, 0x5e, 0xa1, 0x10, 0x2b, + 0x0e, 0x3a, 0x85, 0xd9, 0x0e, 0x6c, 0x31, 0x2a, + 0x1b, 0xf5, 0x60, 0x1f, 0x6a, 0xdc, 0xd7, 0x2b, + 0x33, 0x7b, 0x1b, 0xda, 0x36, 0xaa, 0x6c, 0xd1, + 0x03, 0x9c, 0x48, 0xb1, 0xb3, 0x28, 0x62, 0x9e, + 0xef, 0x4f, 0x1d, 0x24, 0x48, 0xac, 0x36, 0x41, + 0xed, 0x91, 0xc8, 0x87, 0xc5, 0x61, 0x0c, 0x86, + 0x27, 0x20, 0x25, 0xe6, 0xe1, 0x03, 0x46, 0xd6, + 0xa4, 0xb7, 0x4c, 0xab, 0x8d, 0x6d, 0x03, 0x28, + 0x00, 0x19, 0x12, 0xfd, 0xc1, 0x8b, 0x2e, 0x78, + 0x8e, 0xb6, 0x33, 0x96, 0x13, 0xb4, 0x97, 0x90, + 0x76, 0xce, 0x98, 0x05, 0xd2, 0xd2, 0x72, 0x6a, + 0x13, 0xea, 0x69, 0x53, 0xcc, 0xe2, 0x91, 0x1a, + 0xde, 0x0a, 0xe6, 0xb1, 0xcd, 0x84, 0x46, 0x97, + 0x12, 0x24, 0xb5, 0xcb, 0x2f, 0xca, 0xae, 0xe5, + 0xd8, 0x61, 0xa8, 0xac, 0x68, 0x62, 0x4f, 0x73, + 0x30, 0xb2, 0x6c, 0xa7, 0xe4, 0x7d, 0x69, 0x69, + 0x3f, 0x9f, 0x3a, 0x89, 0x92, 0xce, 0x87, 0x11, + 0x81, 0x0d, 0x16, 0xad, 0x3b, 0x98, 0x55, 0x1e, + 0x19, 0xf7, 0x81, 0xb3, 0xfa, 0x35, 0xfd, 0x0d, + 0x6c, 0x10, 0xe7, 0x7b, 0xf1, 0x6e, 0x20, 0xa6, + 0x0d, 0x9b, 0x96, 0x94, 0xac, 0xa0, 0x4c, 0xe8, + 0x10, 0xf9, 0x9c, 0x59, 0xb7, 0x9b, 0xf9, 0xb3, + 0xee, 0x97, 0x8c, 0x30, 0xaa, 0xf2, 0x14, 0x2d, + 0x52, 0xa6, 0x20, 0xf7, 0x39, 0xc9, 0x23, 0x69, + 0x01, 0xe8, 0x2d, 0xa4, 0xae, 0x7f, 0x88, 0x39, + 0x6a, 0x75, 0x26, 0x44, 0x3f, 0xdc, 0xe3, 0x29, + 0xc9, 0xdc, 0x2d, 0xac, 0xa6, 0xc6, 0x08, 0xde, + 0xc4, 0x05, 0x7b, 0x79, 0xcd, 0xa1, 0x90, 0x18, + 0xfb, 0xf8, 0x52, 0xa0, 0x35, 0xea, 0xc4, 0x0b, + 0xa4, 0xcc, 0xd3, 0x54, 0xcf, 0xba, 0x4d, 0x9f, + 0x39, 0x5a, 0x19, 0xf4, 0x12, 0x02, 0xa8, 0x2b, + 0x39, 0x83, 0x34, 0xcf, 0x3a, 0x03, 0xf6, 0xd7, + 0x16, 0x74, 0x5e, 0xbd, 0xc1, 0x2b, 0x0d, 0x63, + 0xf8, 0x96, 0x09, 0x3d, 0xa4, 0xff, 0xfc, 0x4e, + 0xdf, 0x0c, 0xc6, 0x61, 0x1a, 0x67, 0x40, 0xec, + 0x0f, 0x61, 0xfa, 0xbb, 0xee, 0x7d, 0x71, 0xb3, + 0x3c, 0xcc, 0x6a, 0xd2, 0xb8, 0xe3, 0x5f, 0x00, + 0x2c, 0x4f, 0x6e, 0xc6, 0x4b, 0xb7, 0x6f, 0xc2, + 0xe6, 0x27, 0xe8, 0x35, 0xcd, 0x10, 0x0d, 0x91, + 0x4f, 0x49, 0x5d, 0x4f, 0xb1, 0x93, 0x30, 0x3e, + 0x1d, 0xf5, 0x4a, 0x93, 0xd6, 0x84, 0x72, 0x7f, + 0x40, 0x27, 0xe7, 0x15, 0x96, 0x05, 0x16, 0xb8, + 0x6f, 0x04, 0x34, 0x61, 0x9c, 0x95, 0x9f, 0x44, + 0xc5, 0xe2, 0xe8, 0x59, 0x88, 0x6e, 0x92, 0x3a, + 0x02, 0x33, 0xee, 0x94, 0xbc, 0xca, 0x97, 0x0b, + 0x00, 0x97, 0x91, 0xe4, 0x89, 0x2c, 0x99, 0x1e, + 0x86, 0x32, 0x6d, 0xbd, 0x4c, 0x70, 0x71, 0x05, + 0x1c, 0xfe, 0x2b, 0xfd, 0x92, 0x4d, 0xb5, 0xf7, + 0x8b, 0x37, 0x19, 0x71, 0x9a, 0xd0, 0x9d, 0x17, + 0x13, 0x9e, 0x0c, 0x46, 0xae, 0x51, 0x04, 0x81, + 0x19, 0xff, 0x3e, 0x3e, 0x59, 0x3c, 0xaf, 0xe2, + 0xc0, 0x03, 0xf9, 0x98, 0xfd, 0x31, 0x47, 0xc9, + 0x32, 0x71, 0x19, 0x45, 0x9f, 0x05, 0x2b, 0x72, + 0x08, 0x47, 0x8b, 0xea, 0x09, 0x7d, 0x8e, 0x9d, + 0x9c, 0x73, 0x5d, 0x45, 0x7f, 0x01, 0x4e, 0xd0, + 0x4d, 0x52, 0x87, 0x04, 0x3d, 0x2f, 0xc1, 0x95, + 0xfd, 0x88, 0x53, 0xb4, 0x62, 0x3d, 0x53, 0x68, + 0xef, 0x32, 0x5a, 0xd4, 0xbd, 0x77, 0x54, 0x49, + 0x4d, 0x36, 0x09, 0x59, 0x57, 0x72, 0x1c, 0xde, + 0x76, 0x1a, 0x31, 0x22, 0xb4, 0x66, 0x50, 0x50, + 0x23, 0x3f, 0x93, 0xd2, 0xf3, 0x91, 0x52, 0x76, + 0x87, 0x5e, 0x9b, 0xba, 0x80, 0xef, 0xc2, 0x28, + 0x45, 0x9c, 0x6b, 0x0f, 0xb4, 0xe9, 0x40, 0x6a, + 0x64, 0x90, 0x68, 0x47, 0x34, 0xca, 0x6e, 0x22, + 0x6f, 0x06, 0x47, 0x66, 0x7c, 0x94, 0x8a, 0x18, + 0x07, 0x1b, 0x16, 0x64, 0xc2, 0x87, 0x4d, 0x5c, + 0x9a, 0xbd, 0xe2, 0x34, 0xc5, 0xcd, 0x6c, 0xe9, + 0xa0, 0x0b, 0x69, 0xdc, 0x3d, 0x00, 0x86, 0x68, + 0x37, 0xcf, 0xa3, 0x8b, 0xe2, 0x04, 0x4e, 0x23, + 0xfc, 0x87, 0xfb, 0xdc, 0x0e, 0x12, 0x1c, 0x5f, + 0xde, 0x6c, 0x58, 0xda, 0x0a, 0xc2, 0xd5, 0x5f, + 0x3b, 0x94, 0x87, 0xb7, 0x3f, 0x2e, 0x8e, 0x84, + 0x22, 0xf1, 0xf0, 0x48, 0x4b, 0x98, 0x47, 0xaf, + 0x8c, 0x8a, 0x15, 0xf7, 0xb0, 0x3f, 0x23, 0xe1, + 0x40, 0xb8, 0xbe, 0xe6, 0xfb, 0xa4, 0xdf, 0xeb, + 0x13, 0xf9, 0x09, 0x58, 0xac, 0xca, 0xa1, 0xba, + 0x84, 0x0d, 0x50, 0x31, 0x43, 0xd8, 0xcc, 0x00, + 0xf7, 0xbd, 0x23, 0xb2, 0x1a, 0x28, 0xdd, 0x23, + 0x19, 0x87, 0x28, 0xdb, 0xb9, 0x9a, 0x2c, 0x92, + 0x2b, 0xe9, 0x67, 0x88, 0x48, 0x82, 0xbe, 0x32, + 0xec, 0xf5, 0x61, 0x76, 0x32, 0x8c, 0xcc, 0x99, + 0xea, 0xad, 0x4d, 0x92, 0x28, 0x4f, 0x7c, 0x9a, + 0x6a, 0x8e, 0x7e, 0x0b, 0x16, 0x5c, 0x30, 0x93, + 0x55, 0x06, 0x17, 0x76, 0x70, 0x02, 0x6d, 0xee, + 0x11, 0xbf, 0x89, 0xca, 0xcd, 0x57, 0xaa, 0x67, + 0xd5, 0xa9, 0x4e, 0x73, 0xa7, 0x82, 0x35, 0x83, + 0x6b, 0x83, 0xc5, 0x83, 0xcc, 0x3a, 0xc3, 0x19, + 0x00, 0x4d, 0x0f, 0x68, 0x85, 0x8f, 0x55, 0xe0, + 0xe8, 0x55, 0x9e, 0x78, 0x8e, 0xfc, 0xc7, 0xd2, + 0x6d, 0x0f, 0x3e, 0xc9, 0x12, 0xd1, 0xc7, 0x99, + 0x6f, 0xf9, 0x42, 0x12, 0xbb, 0xc5, 0x16, 0x6b, + 0x44, 0x61, 0xdd, 0xa9, 0x5e, 0x12, 0x2b, 0x6f, + 0x11, 0x81, 0x99, 0xda, 0x8a, 0xcb, 0x17, 0xfb, + 0x93, 0xaf, 0x98, 0x25, 0x72, 0x39, 0xec, 0x3a, + 0x40, 0xed, 0x46, 0x31, 0xb9, 0x30, 0x7b, 0x4a, + 0x4b, 0xa2, 0x64, 0xa6, 0x60, 0x5e, 0xd5, 0x63, + 0x17, 0xbf, 0xda, 0x96, 0x1e, 0x70, 0x15, 0x86, + 0x93, 0xae, 0xb9, 0xda, 0xe3, 0xef, 0x4a, 0xeb, + 0x4f, 0xa4, 0xed, 0x3f, 0xff, 0x07, 0x1a, 0x4b, + 0x93, 0x42, 0xd7, 0x44, 0x92, 0x68, 0xaa, 0xbe, + 0x5f, 0x58, 0xc6, 0x2b, 0xbd, 0xe2, 0xbd, 0xe0, + 0x04, 0x63, 0xf9, 0x96, 0x1d, 0xdd, 0xd5, 0x8a, + 0x4e, 0x24, 0xa0, 0xdd, 0x87, 0x78, 0x6d, 0x2f, + 0xac, 0xc4, 0x0a, 0x4c, 0x85, 0x1f, 0x2f, 0xe6, + 0x66, 0xdb, 0x17, 0x8a, 0x6a, 0xcd, 0xc2, 0x40, + 0xb1, 0xb3, 0x7f, 0x3d, 0x5b, 0x73, 0x25, 0x10, + 0xdc, 0xd2, 0x48, 0x80, 0x03, 0xf4, 0xbf, 0x87, + 0xd0, 0x5c, 0xc2, 0x51, 0x5d, 0xc1, 0x05, 0x9f, + 0x0e, 0xf3, 0xb6, 0xfc, 0x68, 0x8c, 0x69, 0xf5, + 0xd5, 0xef, 0xbb, 0x25, 0xf4, 0xe6, 0x40, 0x0f, + 0x59, 0xa8, 0x1c, 0xc3, 0x62, 0x15, 0x8d, 0x93, + 0x00, 0x4f, 0x87, 0xcb, 0x3b, 0x44, 0xfe, 0xb4, + 0x40, 0xaf, 0x9b, 0xfc, 0x26, 0xde, 0x20, 0xb4, + 0x51, 0x7c, 0x79, 0x74, 0xdc, 0xe8, 0x84, 0xa3, + 0x81, 0x2f, 0x2a, 0xea, 0xbf, 0x35, 0xbb, 0x83, + 0x50, 0x0b, 0x68, 0x06, 0x05, 0x22, 0xc7, 0x31, + 0x47, 0x05, 0xf0, 0x9e, 0xeb, 0x9d, 0xa2, 0x2e, + 0x29, 0x94, 0xa3, 0x2f, 0x76, 0x7b, 0x2f, 0x4f, + 0xa9, 0x83, 0x37, 0xd8, 0x6e, 0x90, 0xff, 0x29, + 0x67, 0xa3, 0xb5, 0x95, 0x47, 0xe3, 0xb9, 0xa8, + 0x31, 0xfb, 0xb9, 0x7b, 0xcb, 0x99, 0x72, 0x7f, + 0x81, 0xed, 0x6f, 0x89, 0x2b, 0xd2, 0x76, 0xd8, + 0x11, 0x6b, 0x8a, 0xbc, 0xc6, 0xc5, 0x97, 0xdf, + 0x29, 0x69, 0x70, 0xe1, 0x9e, 0xf9, 0xb6, 0x2c, + 0xeb, 0x7a, 0x81, 0xae, 0x21, 0xa5, 0x26, 0x9b, + 0x4e, 0xb2, 0xf8, 0x93, 0x55, 0x01, 0x85, 0x8a, + 0x76, 0xa9, 0x44, 0xe7, 0x64, 0xd2, 0xa5, 0xd6, + 0x3a, 0x6c, 0x0e, 0xce, 0xc9, 0x92, 0x8f, 0x67, + 0x4a, 0x42, 0x52, 0xa7, 0xc6, 0x41, 0x2d, 0x63, + 0xb9, 0xb9, 0x60, 0x98, 0x4b, 0x6f, 0x69, 0xae, + 0xc1, 0xbd, 0x6c, 0x28, 0x44, 0xdb, 0x3f, 0x1f, + 0x1c, 0xbf, 0xd4, 0xbf, 0x10, 0x99, 0x41, 0x96, + 0x3d, 0x42, 0xa7, 0xec, 0x54, 0xc9, 0xdf, 0x55, + 0xd5, 0x78, 0x91, 0x87, 0x8d, 0x07, 0x6d, 0x73, + 0x6c, 0x09, 0x66, 0xbd, 0xc7, 0x85, 0xff, 0xe8, + 0x1a, 0x34, 0x14, 0x64, 0x74, 0xe4, 0x1f, 0xf4, + 0x87, 0xef, 0x96, 0xa1, 0xc8, 0x47, 0x28, 0xc9, + 0x96, 0x86, 0x16, 0x37, 0xca, 0x90, 0x60, 0xf9, + 0xb2, 0xea, 0x6b, 0x64, 0x4e, 0x05, 0xf7, 0x28, + 0x07, 0x76, 0xd3, 0x28, 0x16, 0xde, 0x7c, 0x51, + 0x42, 0xc8, 0x04, 0xd3, 0xb9, 0x7c, 0xe3, 0xfd, + 0xd6, 0xe6, 0x2e, 0xf3, 0xe9, 0x27, 0xa6, 0xd2, + 0x9d, 0x76, 0x38, 0xa9, 0x4b, 0xf3, 0xde, 0xa4, + 0x38, 0x3b, 0x4b, 0xb1, 0x54, 0xf3, 0x49, 0x2b, + 0x68, 0xcc, 0x3d, 0x01, 0x22, 0x7d, 0xf5, 0x5c, + 0xe7, 0xc7, 0x50, 0x17, 0xe1, 0xac, 0xba, 0x9f, + 0xe2, 0x04, 0x25, 0xec, 0x8a, 0x83, 0xe5, 0xae, + 0x50, 0xd8, 0x78, 0x81, 0x05, 0x57, 0x6b, 0xea, + 0x15, 0x5c, 0xf5, 0x90, 0xd3, 0xa5, 0x24, 0x0b, + 0x0e, 0xfc, 0x5c, 0xaf, 0x0e, 0x7d, 0x4f, 0x01, + 0xdc, 0xd9, 0xb7, 0x72, 0x12, 0x5f, 0xd3, 0xe7, + 0xc9, 0x70, 0xff, 0xcd, 0x3e, 0xbd, 0x17, 0xc0, + 0xff, 0x74, 0x48, 0x52, 0xc3, 0xfe, 0xd3, 0xf2, + 0x6c, 0x51, 0x2b, 0xf1, 0xb3, 0x00, 0xa7, 0x9b, + 0x3d, 0x8b, 0x9f, 0xe7, 0x22, 0x18, 0x90, 0xc1, + 0x8a, 0x75, 0x54, 0x29, 0x54, 0x0e, 0x0d, 0x11, + 0xb3, 0xa5, 0x3c, 0xca, 0x87, 0xe1, 0x37, 0x38, + 0x0b, 0xff, 0xdc, 0x20, 0x15, 0xc3, 0x48, 0x3c, + 0x2b, 0x7f, 0x71, 0xeb, 0x1b, 0x3c, 0xd1, 0xf0, + 0xa7, 0x57, 0xb3, 0x44, 0x97, 0x2c, 0x08, 0x34, + 0xb7, 0x47, 0x2a, 0x03, 0x84, 0x8c, 0xf7, 0x7e, + 0xb8, 0xdd, 0x87, 0xa5, 0x79, 0xef, 0xcd, 0x3a, + 0x38, 0x68, 0x11, 0xed, 0xb0, 0xc0, 0x8a, 0x48, + 0x10, 0x03, 0x71, 0x61, 0x5e, 0x9f, 0x3f, 0x0d, + 0x22, 0x4f, 0x87, 0x02, 0x8a, 0x1e, 0xfe, 0x03, + 0xd4, 0x21, 0x49, 0xfa, 0xb1, 0x98, 0x40, 0x63, + 0xca, 0x6a, 0x9d, 0x40, 0x16, 0xfe, 0xb2, 0xe2, + 0xb5, 0x1d, 0xc9, 0x55, 0x10, 0x43, 0x48, 0xcb, + 0xab, 0x43, 0x94, 0x2f, 0xe3, 0x3d, 0xcb, 0x47, + 0x6c, 0xc2, 0x10, 0x67, 0xcd, 0xb8, 0xc1, 0x74, + 0x85, 0x58, 0x30, 0x3b, 0x43, 0xc4, 0x57, 0xfe, + 0x1a, 0x7d, 0xfb, 0xd9, 0x71, 0xf9, 0x41, 0x4f, + 0xf9, 0xa8, 0xb0, 0xb2, 0xed, 0xe3, 0xc4, 0xca, + 0xea, 0xa3, 0x1b, 0x12, 0x95, 0x6a, 0x4b, 0xc9, + 0x1d, 0x45, 0xb1, 0x15, 0x44, 0x90, 0x1d, 0x84, + 0x78, 0x8d, 0xa8, 0xaa, 0xa2, 0xa2, 0x50, 0x2a, + 0x59, 0x5f, 0x7a, 0x53, 0x00, 0x3f, 0x7a, 0x01, + 0xc7, 0xff, 0x41, 0xb4, 0xa9, 0xd6, 0x6e, 0xed, + 0x0b, 0x88, 0x21, 0x8a, 0x9d, 0xbe, 0x10, 0xec, + 0xbe, 0x31, 0xcf, 0x95, 0x34, 0x35, 0x53, 0x70, + 0x96, 0xdc, 0xea, 0x59, 0x61, 0x58, 0x19, 0x70, + 0xc3, 0xab, 0x50, 0xfc, 0xf3, 0xe4, 0x99, 0xaf, + 0xac, 0xf5, 0x9f, 0x1a, 0x17, 0x9c, 0xaf, 0xbb, + 0xb1, 0xee, 0x66, 0xcd, 0xf0, 0xbd, 0xdb, 0x44, + 0x87, 0xc5, 0x46, 0x14, 0xbd, 0x56, 0x7c, 0xd0, + 0x60, 0x9f, 0x6d, 0xdc, 0x0e, 0x80, 0xcb, 0x85, + 0xbf, 0x20, 0x93, 0xf5, 0xbc, 0x11, 0x00, 0xbf, + 0xfd, 0x73, 0x11, 0x2a, 0x13, 0xfe, 0xf8, 0x44, + 0x9f, 0x6f, 0x84, 0xee, 0xbe, 0xfc, 0x37, 0x10, + 0x18, 0x93, 0xcb, 0x5b, 0x02, 0xd5, 0x2f, 0xb2, + 0x85, 0x23, 0xaf, 0x20, 0xdf, 0x13, 0xbb, 0xca, + 0x31, 0x71, 0x0f, 0x19, 0x2b, 0xc5, 0x14, 0x0e, + 0x62, 0x8b, 0x1d, 0x1b, 0xd7, 0xb6, 0xd9, 0x2b, + 0x87, 0x91, 0x34, 0x1d, 0x96, 0xa2, 0xd9, 0x31, + 0xa3, 0xf3, 0x4f, 0xc8, 0x83, 0x7f, 0xaf, 0xa4, + 0xf7, 0x78, 0x79, 0xb9, 0x43, 0x92, 0xfa, 0x7f, + 0xd7, 0x9b, 0x49, 0x9e, 0x3f, 0xd9, 0x81, 0x32, + 0x9b, 0x0b, 0xd4, 0x6f, 0xfe, 0x69, 0x4a, 0x43, + 0xeb, 0x84, 0x7f, 0x23, 0xa4, 0xb7, 0x8f, 0x48, + 0x31, 0x50, 0xfd, 0x4b, 0xdf, 0x6e, 0x59, 0x75, + 0x08, 0xb5, 0xac, 0x5f, 0xa7, 0x32, 0x8d, 0xa6, + 0x31, 0x59, 0x2d, 0x0f, 0x9c, 0x3b, 0x65, 0xc8, + 0xe7, 0x4e, 0x75, 0x4f, 0x30, 0x24, 0x3a, 0x7c, + 0x93, 0xa9, 0xf0, 0x5b, 0xfe, 0x81, 0xc1, 0x44, + 0x83, 0xdf, 0x12, 0xe9, 0x9f, 0xa4, 0x9e, 0x2e, + 0x6a, 0xfc, 0x0f, 0x8b, 0xbf, 0xcc, 0x2f, 0xc2, + 0xd4, 0xf4, 0xe7, 0x35, 0xf6, 0xcb, 0x36, 0x2b, + 0xd4, 0x21, 0x6f, 0x5a, 0x59, 0x42, 0x2d, 0xb3, + 0xc7, 0xd1, 0xba, 0xb5, 0x4f, 0xae, 0xfa, 0xc6, + 0xce, 0xd3, 0x34, 0xa9, 0x11, 0xab, 0x1e, 0x1c, + 0xda, 0xd1, 0x9f, 0xae, 0x9b, 0xf1, 0xc5, 0x82, + 0xa4, 0xf2, 0xb2, 0x8b, 0x21, 0xf5, 0x9d, 0xd2, + 0xe5, 0xe7, 0x69, 0x4d, 0xb4, 0x0d, 0x31, 0xed, + 0xa7, 0x37, 0x8b, 0xa6, 0x56, 0x9a, 0x7a, 0x9f, + 0x67, 0x9d, 0xbf, 0x72, 0x1d, 0x89, 0xe4, 0x03, + 0xcd, 0x06, 0x57, 0x68, 0x28, 0xaf, 0x83, 0xdf, + 0xbc, 0xa9, 0xb4, 0xe5, 0x73, 0xe2, 0x4c, 0x4e, + 0xea, 0x52, 0xc8, 0x60, 0x10, 0xfc, 0x29, 0x66, + 0x7a, 0x55, 0xfd, 0x94, 0xd7, 0xb3, 0xf1, 0x46, + 0xd2, 0x37, 0xa9, 0xe9, 0x6f, 0x93, 0x87, 0x46, + 0xb2, 0xc5, 0x4b, 0x44, 0x68, 0xbf, 0x9e, 0xc2, + 0x81, 0x16, 0x90, 0x30, 0xf0, 0x16, 0xe7, 0x1b, + 0x59, 0xc0, 0xde, 0xb3, 0x26, 0x77, 0x52, 0xae, + 0x04, 0x01, 0x0f, 0x18, 0x57, 0x85, 0xec, 0xdd, + 0x78, 0x25, 0x1d, 0xd2, 0xff, 0xd8, 0x0c, 0x79, + 0x65, 0x81, 0x6f, 0xa3, 0x2d, 0x03, 0x63, 0xb6, + 0x28, 0xd8, 0x24, 0xe7, 0x75, 0x05, 0xfe, 0x8d, + 0xd8, 0xea, 0x5e, 0x45, 0x6a, 0xe1, 0x92, 0x8c, + 0xd2, 0x7f, 0xa8, 0x96, 0xc9, 0x75, 0x3f, 0xa6, + 0xcd, 0x69, 0xb8, 0xb4, 0x89, 0x33, 0x0a, 0xca, + 0xae, 0x0f, 0x5b, 0x2d, 0x96, 0xd5, 0xcd, 0xf8, + 0x18, 0x4e, 0x33, 0x68, 0x7d, 0x11, 0x46, 0x7f, + 0x2e, 0x15, 0x2a, 0xe9, 0xd6, 0x8f, 0x9c, 0x89, + 0xd6, 0x1b, 0x9d, 0x52, 0xe0, 0x54, 0x4d, 0xdf, + 0x66, 0xd8, 0x33, 0xf2, 0xeb, 0x5b, 0xe6, 0x69, + 0x4f, 0x27, 0xdc, 0x61, 0x7e, 0x35, 0x6e, 0xb5, + 0x8f, 0xa8, 0x7b, 0xa0, 0xf6, 0x6e, 0xf5, 0x8c, + 0x43, 0xbd, 0xd3, 0xf6, 0x82, 0x09, 0x73, 0xeb, + 0xb5, 0xce, 0x7e, 0xc9, 0x50, 0xc3, 0xdf, 0x8a, + 0x13, 0x60, 0x1c, 0xb0, 0x60, 0x70, 0x4f, 0xa4, + 0x1c, 0x06, 0xc6, 0xd7, 0x9b, 0x53, 0x77, 0x2a, + 0x62, 0xcd, 0xce, 0x5c, 0x80, 0x6a, 0x13, 0x18, + 0x87, 0xf0, 0x24, 0xaf, 0x90, 0x80, 0x14, 0xf4, + 0x4a, 0xf6, 0xa7, 0x37, 0xac, 0x57, 0x20, 0xfa, + 0x4d, 0x72, 0x10, 0x4d, 0xee, 0x93, 0xd1, 0x84, + 0xc7, 0x3e, 0x75, 0xc5, 0x7e, 0x0d, 0xb7, 0x6c, + 0x8e, 0x49, 0x54, 0xe4, 0x9f, 0xa1, 0x53, 0xdb, + 0x4c, 0x32, 0xad, 0xbd, 0x7b, 0x01, 0x6f, 0xcf, + 0xe8, 0xfc, 0x7f, 0x45, 0xc9, 0x96, 0xa3, 0x61, + 0x58, 0x8e, 0xf2, 0x86, 0x2a, 0x37, 0xce, 0x29, + 0x98, 0x04, 0x32, 0x2b, 0x3f, 0x8f, 0x81, 0xed, + 0xe1, 0xf0, 0x7b, 0xc2, 0x13, 0x11, 0xc4, 0x31, + 0x5d, 0x4c, 0x6e, 0x3f, 0x14, 0x8f, 0xa5, 0x55, + 0xe4, 0x17, 0xf4, 0x80, 0x91, 0xe1, 0x89, 0xfe, + 0xbf, 0xca, 0x67, 0xfa, 0x5b, 0xd0, 0x02, 0x91, + 0x60, 0x1d, 0x50, 0xc0, 0xd1, 0xa6, 0x38, 0x9a, + 0xec, 0xd6, 0xfe, 0x8b, 0x27, 0x6e, 0xbb, 0x2d, + 0x50, 0x7d, 0x51, 0x5b, 0x28, 0x43, 0x19, 0xfc, + 0x1a, 0x2b, 0x19, 0xa2, 0x35, 0x50, 0xe9, 0xec, + 0xc0, 0x10, 0x1e, 0x36, 0x03, 0xc5, 0x00, 0x9d, + 0x11, 0x16, 0x53, 0x5f, 0xde, 0xe8, 0x0d, 0x93, + 0xb5, 0xf7, 0x45, 0x50, 0x72, 0xf9, 0x28, 0x6d, + 0xc3, 0xd0, 0x1e, 0x1f, 0x39, 0x3e, 0xcb, 0x61, + 0x83, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x0a, 0x0e, 0x12, 0x17, 0x1a + }; + + return linuxkm_test_mldsa_driver(WOLFKM_MLDSA65_DRIVER, + mldsa65_pub, + (word32)sizeof(mldsa65_pub), + mldsa65_seed, + (word32)sizeof(mldsa65_seed), +#ifdef LINUXKM_MLDSA_SIGN + 1, +#else + 0, +#endif + mldsa65_sig, + (word32)sizeof(mldsa65_sig), + linuxkm_mldsa_test_msg, + (word32)sizeof(linuxkm_mldsa_test_msg)); +} +#endif /* LINUXKM_MLDSA65 */ + + +#ifdef LINUXKM_MLDSA87 +static int linuxkm_test_mldsa87(void) +{ + /* reference values generated with two independent implementations + * in agreement (OpenSSL master and dilithium-py), from the seed + * below: seed -> (pub, priv) per FIPS 204 ML-DSA.KeyGen_internal, + * and sig = deterministic-variant signature over msg with the + * default (empty) context. */ + static const byte mldsa87_seed[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + }; + + static const byte mldsa87_pub[] = { + 0xb9, 0x30, 0x54, 0xaa, 0x8d, 0xd1, 0xd8, 0xd5, + 0xc1, 0x6a, 0x3a, 0x95, 0x9f, 0x6f, 0x79, 0xd1, + 0x82, 0x7c, 0x4f, 0x02, 0x24, 0x44, 0x01, 0xdf, + 0xf8, 0x72, 0xbe, 0xe5, 0x0b, 0xb6, 0x9d, 0xd2, + 0xc2, 0xc1, 0x0f, 0x2b, 0xc2, 0x7d, 0x5a, 0x7e, + 0x24, 0x44, 0x6a, 0xa5, 0x29, 0xfe, 0xeb, 0x13, + 0x60, 0x66, 0x88, 0x8d, 0x60, 0x92, 0x21, 0x96, + 0x75, 0xd6, 0x7f, 0x88, 0x32, 0xa7, 0xd2, 0x54, + 0xd9, 0x06, 0x2a, 0x48, 0x1f, 0x30, 0x1d, 0xf0, + 0x8a, 0xd1, 0x59, 0xce, 0x0d, 0xd2, 0x21, 0xbb, + 0xbd, 0x17, 0x10, 0x84, 0x14, 0x18, 0x08, 0xda, + 0xad, 0x3d, 0x7d, 0x37, 0x9f, 0x5c, 0xe4, 0x61, + 0xdb, 0x40, 0x21, 0x81, 0xd0, 0xb2, 0x80, 0xd2, + 0x23, 0x6c, 0xc1, 0x8f, 0x33, 0x66, 0x7c, 0x77, + 0x0f, 0x4a, 0x7c, 0x53, 0x59, 0xf1, 0xbb, 0xee, + 0x49, 0xcd, 0xb3, 0xf2, 0x02, 0x5e, 0xc3, 0x78, + 0xc2, 0x24, 0x16, 0x2b, 0x6a, 0x7d, 0xb6, 0x1a, + 0xc5, 0x37, 0x23, 0x71, 0xa4, 0x3c, 0xb3, 0x1c, + 0x4d, 0x6d, 0x8a, 0x6c, 0x7d, 0x66, 0x85, 0x1d, + 0x79, 0x8b, 0x0a, 0x30, 0x04, 0xad, 0x65, 0x08, + 0x77, 0x19, 0x66, 0x1e, 0xf1, 0x08, 0x99, 0x87, + 0xdb, 0x62, 0x54, 0xb0, 0x57, 0x34, 0x16, 0x6d, + 0xf4, 0xd1, 0x59, 0xba, 0x96, 0x6b, 0xf6, 0xf6, + 0xca, 0x67, 0x66, 0xc2, 0xdf, 0xfd, 0x0f, 0x2f, + 0xc9, 0xaf, 0x10, 0xcd, 0x38, 0xd6, 0x84, 0xa8, + 0xd1, 0x04, 0xba, 0x8f, 0x96, 0xad, 0x4c, 0xd9, + 0xc0, 0x57, 0xf6, 0x41, 0x5a, 0xce, 0xcb, 0x68, + 0xd3, 0x98, 0xf7, 0xb3, 0xf9, 0x4c, 0x95, 0x13, + 0x1a, 0x51, 0xf7, 0x4d, 0xd4, 0x4d, 0x62, 0x78, + 0x0d, 0xea, 0x0d, 0x96, 0x0c, 0x2d, 0x71, 0x79, + 0x69, 0xce, 0x5c, 0x63, 0x83, 0x70, 0xa7, 0x31, + 0x11, 0x13, 0x16, 0x94, 0xd8, 0x18, 0x63, 0x2e, + 0xf0, 0x61, 0x7f, 0x0f, 0x97, 0x04, 0x2f, 0x71, + 0x7a, 0x42, 0x44, 0x81, 0x9d, 0xe3, 0x51, 0xc1, + 0x47, 0x68, 0xb3, 0xd8, 0x06, 0xb6, 0x79, 0xeb, + 0xf0, 0xbb, 0x3f, 0xfc, 0xe4, 0x1f, 0xdf, 0x32, + 0x55, 0x90, 0xb5, 0xa3, 0xc6, 0xdb, 0x47, 0x30, + 0xd7, 0xdb, 0x15, 0x68, 0xf9, 0xfe, 0xa5, 0x74, + 0x4a, 0xe3, 0x09, 0x91, 0x20, 0x0a, 0x20, 0x2e, + 0xa7, 0x47, 0x46, 0xd2, 0x24, 0xfa, 0xdd, 0xf5, + 0x54, 0xd5, 0x0c, 0x1e, 0x71, 0x99, 0x37, 0xac, + 0x01, 0xa0, 0x41, 0x2a, 0xe9, 0xd7, 0x18, 0x2d, + 0xdb, 0x67, 0x81, 0xa1, 0xf8, 0x1d, 0x60, 0x5a, + 0x6d, 0xc9, 0xf2, 0xa6, 0xdd, 0xfc, 0xdc, 0x7e, + 0xa8, 0x1c, 0x09, 0xb6, 0x94, 0xf2, 0x41, 0xfb, + 0x1d, 0xf1, 0xa5, 0x1e, 0xee, 0x63, 0x2e, 0x78, + 0x93, 0x8a, 0x51, 0xdb, 0xbc, 0x9a, 0x90, 0x58, + 0x96, 0xc1, 0x8a, 0xbf, 0xfb, 0xd8, 0x16, 0x91, + 0xfd, 0x26, 0xf8, 0xe3, 0x4f, 0xac, 0xdf, 0xbe, + 0x99, 0xf1, 0x62, 0x1c, 0xe8, 0x88, 0xff, 0xed, + 0x11, 0xa8, 0xd6, 0x35, 0x06, 0x41, 0xdb, 0x36, + 0x47, 0xf9, 0x85, 0xd9, 0x3a, 0x38, 0xd2, 0x39, + 0xa4, 0xa6, 0x67, 0x50, 0xcf, 0xa4, 0xb6, 0x1c, + 0x4f, 0x7d, 0x4a, 0x6f, 0x49, 0xaa, 0x2a, 0x7c, + 0x3b, 0x09, 0x06, 0x7f, 0x33, 0xc3, 0xfb, 0x18, + 0x89, 0x60, 0x42, 0x05, 0xac, 0x8b, 0x08, 0xab, + 0x35, 0x6f, 0x2c, 0xdf, 0x64, 0x40, 0xec, 0x80, + 0xf4, 0x14, 0x01, 0x32, 0x99, 0x29, 0xc7, 0x0f, + 0xfb, 0x15, 0x4a, 0x86, 0x29, 0x99, 0x3a, 0xac, + 0xbf, 0x26, 0x9f, 0xce, 0xec, 0xfa, 0x22, 0x06, + 0xa3, 0x65, 0xf5, 0xaa, 0xd6, 0xd4, 0xa4, 0x9c, + 0xd5, 0xdf, 0x62, 0x9f, 0x9f, 0xdb, 0x66, 0x2d, + 0x62, 0xd0, 0x39, 0xae, 0x40, 0xf3, 0xd5, 0xc6, + 0xa3, 0x2d, 0x91, 0xbb, 0x42, 0x6d, 0x61, 0xf2, + 0x39, 0x18, 0x78, 0x1e, 0xb0, 0x77, 0x24, 0x41, + 0x9a, 0x95, 0xc3, 0xd6, 0x3e, 0x72, 0x4d, 0xb8, + 0x33, 0xe0, 0x1f, 0x33, 0xe1, 0xf1, 0x4d, 0x31, + 0x67, 0x08, 0xaf, 0xc5, 0xe8, 0xef, 0x06, 0x3d, + 0x5f, 0x4e, 0x96, 0xe9, 0xc3, 0x09, 0x6a, 0xc1, + 0xd0, 0x4f, 0xc9, 0x0f, 0xe2, 0x5f, 0x68, 0x52, + 0x4b, 0xba, 0x86, 0x52, 0x01, 0x23, 0x29, 0xda, + 0x60, 0x75, 0x47, 0x06, 0x31, 0x41, 0x43, 0x14, + 0xbf, 0x62, 0x12, 0x88, 0xfa, 0x2b, 0xb6, 0x0c, + 0x32, 0x85, 0x7a, 0x48, 0x59, 0x29, 0xb4, 0x0e, + 0x25, 0x3b, 0x53, 0xe5, 0x15, 0x51, 0xe0, 0x0a, + 0xf9, 0x13, 0x3a, 0x86, 0xe4, 0x5d, 0x12, 0xe1, + 0x00, 0x03, 0x90, 0x01, 0x5f, 0x1f, 0x20, 0x7d, + 0x08, 0xa3, 0x83, 0xe3, 0x82, 0xef, 0x9f, 0x05, + 0xf2, 0xe6, 0x6d, 0x3a, 0xa4, 0x41, 0xd8, 0x2c, + 0x2e, 0xd5, 0xcf, 0x90, 0x9b, 0x84, 0x51, 0xb5, + 0xd1, 0x05, 0x75, 0xbd, 0x65, 0xaa, 0x27, 0x59, + 0xb2, 0xbd, 0x75, 0x59, 0x89, 0xde, 0x5e, 0x62, + 0x7c, 0x53, 0x6d, 0x45, 0xc6, 0xd8, 0x75, 0xca, + 0xd1, 0xf7, 0x6a, 0x57, 0xa1, 0x5b, 0xc9, 0x07, + 0xc5, 0x7f, 0xa8, 0x5e, 0xad, 0x00, 0x0a, 0x5d, + 0x70, 0x63, 0x4c, 0x01, 0x5c, 0x1e, 0xfc, 0xd1, + 0xa1, 0xfc, 0x82, 0x56, 0x55, 0xe8, 0xa7, 0x9a, + 0x15, 0x1c, 0x61, 0x68, 0x94, 0xfb, 0x67, 0x7e, + 0x0b, 0x01, 0xe5, 0x10, 0xb8, 0xd4, 0xbe, 0xd4, + 0x0a, 0x73, 0x57, 0x4a, 0x82, 0xd7, 0xfc, 0xd7, + 0xe9, 0xb8, 0x5a, 0xe4, 0x26, 0x35, 0x51, 0xd4, + 0x4d, 0xb8, 0x82, 0xa6, 0xb5, 0x32, 0x93, 0xe7, + 0xc2, 0x51, 0xe5, 0x1d, 0xed, 0x7a, 0xda, 0x16, + 0x2b, 0xe1, 0x55, 0x76, 0xae, 0x25, 0xb3, 0x75, + 0xf5, 0x52, 0xc6, 0x3b, 0x4a, 0x08, 0x56, 0x9e, + 0xdb, 0x2a, 0x96, 0xc9, 0xf3, 0xcb, 0xb6, 0x7a, + 0xad, 0x0e, 0xc7, 0x5f, 0x0e, 0x92, 0x6d, 0x54, + 0x37, 0x98, 0x1b, 0x51, 0xa0, 0x56, 0xe3, 0xc3, + 0xb8, 0x14, 0x0d, 0x78, 0xc2, 0xa2, 0x7a, 0x23, + 0x1a, 0xc4, 0x7c, 0x14, 0x00, 0x1a, 0x53, 0xe9, + 0xdb, 0xef, 0xdc, 0xeb, 0xf9, 0x13, 0xe6, 0xcb, + 0xef, 0xf3, 0xe7, 0x81, 0xee, 0x77, 0x30, 0x4d, + 0x8b, 0x71, 0xa7, 0x40, 0xa2, 0x7e, 0x8d, 0xcd, + 0xe4, 0x69, 0x36, 0x9a, 0xdb, 0x8e, 0xd0, 0xc8, + 0x8b, 0x0a, 0x5d, 0xeb, 0xdf, 0x00, 0x18, 0xef, + 0x85, 0x14, 0x8a, 0x90, 0x56, 0xff, 0x79, 0xd6, + 0xa1, 0x0c, 0x12, 0x2d, 0x67, 0x66, 0xc9, 0xa3, + 0x6e, 0x3d, 0x38, 0x31, 0x21, 0x0e, 0x06, 0x0b, + 0x22, 0xbc, 0x42, 0xfb, 0x7f, 0x74, 0xcb, 0x64, + 0x23, 0xdc, 0xe5, 0xb5, 0x5e, 0x15, 0x45, 0x75, + 0xf3, 0x0e, 0xd7, 0xec, 0x3c, 0x2a, 0x2d, 0x3b, + 0x24, 0xaa, 0x29, 0xc7, 0x48, 0xd7, 0x74, 0x3a, + 0x17, 0x31, 0x22, 0x6e, 0x9a, 0xa3, 0x13, 0xcc, + 0x59, 0x27, 0x44, 0x92, 0x31, 0xb4, 0x81, 0x31, + 0xf5, 0x95, 0x44, 0xfb, 0xc2, 0x94, 0x06, 0xde, + 0x56, 0x99, 0x92, 0x59, 0x92, 0xfa, 0x96, 0x2b, + 0xf2, 0x83, 0xc2, 0x9d, 0xed, 0xc7, 0x14, 0x5b, + 0xe9, 0xa0, 0xc3, 0x02, 0x31, 0x7c, 0xec, 0x26, + 0xb3, 0x47, 0x68, 0x93, 0x4a, 0xed, 0x47, 0x69, + 0xcd, 0x3d, 0x13, 0xef, 0x27, 0x63, 0xe6, 0xc3, + 0xee, 0xbd, 0x04, 0xfa, 0xe1, 0xf0, 0x9b, 0x75, + 0xe1, 0x14, 0xf6, 0x7e, 0x4f, 0x5c, 0x04, 0x99, + 0x85, 0xd4, 0x71, 0x3a, 0x67, 0x1f, 0xaa, 0x00, + 0x19, 0x87, 0x43, 0x13, 0x52, 0x14, 0x9e, 0x7e, + 0x00, 0x9e, 0x2a, 0x4d, 0x2c, 0xd0, 0x94, 0xaa, + 0xbb, 0xd9, 0x71, 0xcc, 0x29, 0x6e, 0x9e, 0x6b, + 0xde, 0x93, 0x02, 0x9b, 0xba, 0x7f, 0xd7, 0x99, + 0xfb, 0xcd, 0xd8, 0x73, 0xd5, 0x7c, 0x05, 0x55, + 0x2e, 0x02, 0xde, 0xb2, 0xa3, 0xbd, 0x62, 0x3d, + 0x7e, 0xe7, 0x13, 0xad, 0x5c, 0xcc, 0xac, 0xfd, + 0xea, 0xbb, 0x73, 0x66, 0xc6, 0x77, 0xba, 0xf1, + 0xf4, 0x3e, 0x3f, 0x08, 0x49, 0xf3, 0x18, 0x87, + 0x37, 0xb8, 0x9d, 0xe3, 0x62, 0xe9, 0xf9, 0x99, + 0x5b, 0x5d, 0x87, 0x18, 0x23, 0x62, 0x23, 0x57, + 0xe8, 0x83, 0xf0, 0xe6, 0xc0, 0x35, 0x83, 0x28, + 0xee, 0x6d, 0x22, 0x78, 0xe6, 0x03, 0xc4, 0xc6, + 0x8a, 0x87, 0x50, 0x29, 0xf3, 0x4d, 0xde, 0x3c, + 0x9c, 0x37, 0x15, 0x32, 0x7b, 0xc4, 0xf9, 0xba, + 0xe8, 0x9e, 0x99, 0xcc, 0xe6, 0x5c, 0x67, 0x6a, + 0x97, 0x67, 0x14, 0x55, 0x6f, 0x08, 0x08, 0x08, + 0x19, 0xa9, 0x06, 0x2c, 0x22, 0x8f, 0xc9, 0x44, + 0xb0, 0xe7, 0xa4, 0xe8, 0xe2, 0x62, 0x18, 0xd1, + 0x54, 0xfd, 0xab, 0x88, 0xe9, 0x1f, 0x09, 0x41, + 0x2f, 0x35, 0xe1, 0xbc, 0xcb, 0x46, 0x44, 0xe6, + 0xdf, 0xe9, 0x68, 0x53, 0xf8, 0xfa, 0x8e, 0x13, + 0x9a, 0x30, 0xca, 0x00, 0xb3, 0x7f, 0xbb, 0xc9, + 0x81, 0x5f, 0xc6, 0x74, 0xfc, 0xcd, 0xa7, 0x6d, + 0x24, 0x55, 0x77, 0xa9, 0xc2, 0xfc, 0xfc, 0x81, + 0xf0, 0x73, 0xa8, 0x7d, 0x3b, 0x04, 0x2a, 0xdd, + 0x84, 0x14, 0x87, 0xbd, 0x91, 0x25, 0xfb, 0x44, + 0x13, 0x92, 0x69, 0x46, 0x88, 0xa0, 0x64, 0xc9, + 0x39, 0xf7, 0x56, 0xc4, 0xa5, 0x50, 0x23, 0xca, + 0xe8, 0xa3, 0x05, 0x8d, 0x64, 0x92, 0x26, 0xb9, + 0x9d, 0x12, 0x19, 0x3f, 0x0e, 0x1b, 0x21, 0x3b, + 0x55, 0x83, 0x1f, 0xf0, 0xbd, 0x3e, 0x35, 0x81, + 0x2e, 0x0d, 0x6b, 0x68, 0xcf, 0x24, 0x17, 0x56, + 0xb8, 0xec, 0xf5, 0x9f, 0x15, 0xe1, 0x11, 0xdc, + 0x4d, 0xec, 0xd0, 0x50, 0xdf, 0xd8, 0xb7, 0x9f, + 0x10, 0xf8, 0xfc, 0x75, 0x81, 0xd4, 0x6b, 0xac, + 0xce, 0xd5, 0xb3, 0xd0, 0xf3, 0x3f, 0x7c, 0x3a, + 0x1b, 0xa5, 0x31, 0xdd, 0x8b, 0x46, 0x69, 0x13, + 0x5d, 0x9b, 0xbf, 0x92, 0x37, 0x48, 0x89, 0xfd, + 0xc0, 0x1c, 0x9c, 0x81, 0x29, 0x6f, 0xbd, 0x60, + 0xb9, 0x90, 0xb3, 0x87, 0x85, 0x2a, 0x67, 0xe7, + 0x82, 0x93, 0x41, 0x6f, 0x0c, 0x35, 0x80, 0x16, + 0xdc, 0xb3, 0x87, 0x2f, 0xc5, 0xe4, 0xe4, 0xc1, + 0xb7, 0xf4, 0xcd, 0x84, 0x50, 0xa9, 0xfc, 0xcb, + 0xd0, 0xfb, 0xa5, 0xc6, 0x7d, 0x16, 0x08, 0xeb, + 0x4c, 0x1f, 0x0a, 0x02, 0x0e, 0x0c, 0xb5, 0x11, + 0x97, 0x63, 0x48, 0x7d, 0x0c, 0xe7, 0xea, 0x6e, + 0x64, 0x98, 0x11, 0x00, 0xfb, 0x7e, 0x29, 0xc1, + 0x18, 0x9a, 0xc3, 0x5d, 0x2c, 0x79, 0x8f, 0xdd, + 0x9d, 0xa5, 0x41, 0xe5, 0x54, 0xb5, 0xb4, 0xca, + 0x56, 0x26, 0x03, 0xb4, 0x1a, 0x52, 0xd3, 0x12, + 0x5f, 0xc8, 0xef, 0x77, 0x7f, 0x92, 0x1a, 0x0e, + 0x4f, 0x3c, 0x9f, 0x2b, 0x7c, 0x5a, 0x14, 0x61, + 0xef, 0xc2, 0xce, 0x63, 0xf4, 0x65, 0x02, 0x5a, + 0x4c, 0x47, 0x7a, 0xa7, 0xf1, 0x36, 0x99, 0xf7, + 0xdc, 0x24, 0x88, 0xff, 0xa1, 0xd9, 0x77, 0xf0, + 0xf4, 0xe2, 0x2c, 0xbc, 0x8a, 0xc1, 0x5e, 0xd1, + 0x89, 0x56, 0x5f, 0x7e, 0xf3, 0x86, 0xf4, 0xf0, + 0x9b, 0x44, 0x6c, 0xaf, 0x55, 0x87, 0x89, 0x33, + 0x65, 0x4c, 0xe5, 0x36, 0x3e, 0x25, 0x9c, 0x28, + 0xb5, 0x4f, 0xe1, 0x0d, 0xcc, 0x14, 0x40, 0x76, + 0x81, 0xf1, 0xea, 0x61, 0x5a, 0x12, 0xe9, 0x23, + 0x94, 0xf7, 0xc9, 0xba, 0xde, 0xee, 0xf3, 0x55, + 0xb2, 0x6a, 0x84, 0x06, 0xcb, 0x48, 0x60, 0x66, + 0x67, 0x1b, 0x7d, 0x15, 0xaa, 0x38, 0x09, 0xf0, + 0x4c, 0x6e, 0x2e, 0x3a, 0x09, 0xb8, 0x75, 0x69, + 0x7f, 0x25, 0x61, 0xd4, 0x34, 0xe5, 0x9b, 0x2c, + 0xab, 0x6b, 0xc4, 0xbd, 0x07, 0xab, 0x7e, 0x69, + 0x8f, 0xad, 0xa3, 0xfa, 0xff, 0x02, 0x4a, 0xb1, + 0x58, 0x7b, 0x55, 0xbb, 0x18, 0x92, 0x2d, 0x95, + 0x31, 0xf3, 0xb8, 0x75, 0xc7, 0x7e, 0xef, 0x50, + 0xc1, 0x38, 0xd7, 0x18, 0x05, 0x47, 0x16, 0x04, + 0x2b, 0xc8, 0x16, 0x70, 0x45, 0xe9, 0x60, 0xc4, + 0x1c, 0x89, 0x79, 0xd1, 0x06, 0x29, 0xa8, 0xec, + 0x20, 0x09, 0xb2, 0x5e, 0xd8, 0xcb, 0x30, 0x17, + 0x2f, 0x83, 0x7c, 0x1e, 0xef, 0x52, 0xb5, 0xc7, + 0x68, 0x65, 0xf6, 0xa1, 0x4b, 0xde, 0xbc, 0xb8, + 0xe0, 0x1e, 0xfb, 0x6b, 0xfa, 0x93, 0x87, 0xa7, + 0x09, 0x17, 0x27, 0x4c, 0x78, 0xf4, 0x29, 0xc9, + 0x03, 0x25, 0x31, 0x01, 0x06, 0x22, 0x5d, 0x43, + 0xe3, 0x86, 0xe5, 0xa6, 0xc1, 0x7b, 0x6c, 0xee, + 0xe7, 0x81, 0x64, 0x4e, 0xa7, 0x93, 0x1d, 0x0d, + 0x68, 0x96, 0xbb, 0xb7, 0x2f, 0x2c, 0x0b, 0xbb, + 0x8c, 0xd0, 0x23, 0xcb, 0xc3, 0xe8, 0xf3, 0xcb, + 0x5e, 0xce, 0x22, 0xe8, 0x6a, 0x7d, 0xb2, 0x03, + 0x3c, 0x7a, 0x62, 0xaf, 0x5a, 0xe4, 0xe1, 0x54, + 0x9f, 0x05, 0xe3, 0xca, 0xfa, 0xad, 0x25, 0xf7, + 0xfe, 0x7c, 0x18, 0x2b, 0x5e, 0x63, 0x22, 0x96, + 0xc0, 0xbf, 0xda, 0x9c, 0x5b, 0x28, 0xb0, 0x8c, + 0xc9, 0xc9, 0xb1, 0xc3, 0xbc, 0x15, 0x96, 0xcd, + 0x57, 0xcd, 0x69, 0xc7, 0x3d, 0xfa, 0xde, 0xc8, + 0x0c, 0x73, 0xa5, 0xe6, 0x7c, 0x9f, 0x4c, 0xb0, + 0x40, 0x5c, 0xc1, 0x0f, 0x0e, 0xdf, 0xe9, 0x91, + 0x91, 0x3f, 0x27, 0x13, 0xd8, 0x6b, 0xd0, 0x9d, + 0x58, 0x17, 0x10, 0xe1, 0x8c, 0xc8, 0x89, 0x31, + 0xa0, 0x07, 0xa7, 0x5e, 0x98, 0x40, 0x0c, 0xbc, + 0xcd, 0xd6, 0x0f, 0x39, 0xd8, 0x2b, 0x54, 0x75, + 0x8a, 0x99, 0xe7, 0x2e, 0x55, 0x9f, 0x81, 0xd8, + 0xfb, 0xb3, 0xe9, 0x9b, 0xb7, 0xed, 0x8c, 0x2e, + 0xe1, 0x7c, 0xb3, 0xcd, 0x6d, 0x8d, 0x5b, 0x78, + 0x7e, 0xcc, 0xba, 0xb6, 0xd4, 0x6b, 0x62, 0xe8, + 0xee, 0xd7, 0xdd, 0x29, 0x5b, 0xe4, 0x17, 0xf2, + 0x12, 0x6e, 0x3a, 0xfa, 0x03, 0x69, 0x83, 0xa3, + 0x3c, 0x06, 0x7a, 0xbe, 0x3a, 0x19, 0x84, 0x00, + 0xe4, 0xb8, 0x5b, 0x94, 0xd1, 0xd3, 0x63, 0xe2, + 0x11, 0x18, 0x9a, 0x19, 0x07, 0x8d, 0xc4, 0x9f, + 0x87, 0xc0, 0x2a, 0x94, 0x9c, 0xd2, 0xf7, 0x62, + 0xfb, 0xb5, 0xd2, 0xdc, 0x2a, 0xb8, 0x61, 0xa2, + 0x9f, 0x31, 0x3b, 0x21, 0x3e, 0x2c, 0x4f, 0x66, + 0xfc, 0xe7, 0x6f, 0xa1, 0xdf, 0x84, 0xd4, 0xc2, + 0xfe, 0x13, 0xf3, 0x9f, 0xe9, 0x7c, 0xc7, 0xfe, + 0x6f, 0x72, 0x41, 0x7f, 0xf4, 0xf4, 0x22, 0x9b, + 0x52, 0x7b, 0x1d, 0xea, 0xf3, 0x68, 0x02, 0x7c, + 0x0e, 0x9c, 0x7b, 0xe4, 0x8b, 0xf5, 0x96, 0x6e, + 0x6c, 0x60, 0x9d, 0x97, 0x11, 0xae, 0xab, 0xac, + 0x61, 0x39, 0xcd, 0x57, 0x8e, 0x4a, 0x4f, 0xd0, + 0x5b, 0x1e, 0x00, 0x3d, 0xd1, 0x17, 0xed, 0x9a, + 0x51, 0x3f, 0x46, 0x10, 0xa1, 0x9f, 0x05, 0x7b, + 0x03, 0x84, 0xdf, 0x2c, 0x28, 0x3c, 0x9c, 0xc6, + 0xf8, 0xf5, 0xc9, 0x22, 0xac, 0xa2, 0x3e, 0xe9, + 0x19, 0xd7, 0x67, 0x48, 0x1a, 0xdd, 0xe5, 0x4c, + 0xc4, 0xdf, 0x26, 0x44, 0x70, 0xaa, 0x41, 0x49, + 0xcf, 0x43, 0x35, 0xa5, 0x58, 0xbb, 0xf6, 0x73, + 0x44, 0x0d, 0xb4, 0xf5, 0x48, 0xdb, 0x2c, 0x01, + 0x25, 0x8d, 0x5d, 0xdf, 0xd9, 0x4d, 0x1d, 0x2a, + 0x05, 0x39, 0x92, 0x66, 0xb0, 0x48, 0x58, 0xdc, + 0x1a, 0x7f, 0x11, 0x2e, 0x23, 0x3c, 0xba, 0x0b, + 0x27, 0x3a, 0xd4, 0x31, 0x71, 0x6d, 0xeb, 0x31, + 0xdf, 0xae, 0x71, 0xb9, 0x07, 0x8b, 0xdc, 0xf9, + 0xf5, 0xe7, 0x13, 0xe8, 0x37, 0x38, 0x93, 0x22, + 0x5a, 0x39, 0x12, 0x8a, 0x25, 0x7a, 0xca, 0x53, + 0x8d, 0xe3, 0x9c, 0x9c, 0x8d, 0xc2, 0x4c, 0x7d, + 0x05, 0xf5, 0xa5, 0x2d, 0x0f, 0x8e, 0x3e, 0x3e, + 0x91, 0x8e, 0x3c, 0x44, 0x67, 0xb7, 0x8b, 0x99, + 0xad, 0xe3, 0x81, 0x0d, 0x4f, 0xc7, 0x8a, 0x7e, + 0xc9, 0x29, 0x78, 0x53, 0x93, 0x3d, 0x6c, 0x67, + 0x3c, 0x9c, 0xbe, 0x64, 0x94, 0xaf, 0x26, 0xb8, + 0xc2, 0x52, 0xa8, 0x70, 0x27, 0x52, 0x08, 0x55, + 0x68, 0x8f, 0x3a, 0xaf, 0x97, 0x7a, 0xec, 0xd8, + 0x1f, 0x46, 0xe5, 0xa5, 0x9b, 0xef, 0x85, 0x37, + 0x71, 0x99, 0x34, 0x27, 0x95, 0x21, 0x26, 0x54, + 0xa3, 0x12, 0x8e, 0xc1, 0x4f, 0x41, 0xf4, 0x23, + 0xb2, 0x75, 0x5e, 0x1f, 0x12, 0xd5, 0xaf, 0x48, + 0x07, 0x0e, 0xd7, 0x45, 0x48, 0xc9, 0x3b, 0xbb, + 0xbd, 0x0d, 0x09, 0x4e, 0x24, 0xd2, 0x3d, 0x52, + 0xed, 0xda, 0xe4, 0x80, 0x32, 0x78, 0x20, 0x93, + 0xa9, 0x4b, 0x6c, 0x50, 0x27, 0xfd, 0xbb, 0xa5, + 0xa8, 0x48, 0x61, 0xc2, 0x55, 0x2f, 0x53, 0x7f, + 0x6a, 0xa7, 0xdc, 0x43, 0xf8, 0xef, 0x57, 0x32, + 0x48, 0xee, 0xcb, 0xc2, 0x1b, 0xf2, 0xb4, 0x1a, + 0x63, 0x5d, 0x29, 0x2a, 0x1f, 0xba, 0x6e, 0xe8, + 0x44, 0xd9, 0xfc, 0x4a, 0x38, 0xbc, 0xd1, 0x5d, + 0xcc, 0x8a, 0xe8, 0xe0, 0x9d, 0xba, 0xe9, 0x4e, + 0x20, 0xd1, 0x26, 0x82, 0x6a, 0x6b, 0xd5, 0x57, + 0xc1, 0xca, 0x54, 0xc4, 0x32, 0xe6, 0xc6, 0xe4, + 0x13, 0xd5, 0xa5, 0xf7, 0x45, 0x2d, 0x7c, 0x22, + 0x84, 0x92, 0x2a, 0xd2, 0x97, 0x29, 0x3a, 0x19, + 0x03, 0xcf, 0xf2, 0x03, 0x94, 0x97, 0xff, 0x3f, + 0xde, 0x63, 0xe7, 0x65, 0xa0, 0xa7, 0x76, 0x15, + 0x37, 0xc8, 0xf1, 0x67, 0x46, 0x0a, 0x90, 0x53, + 0x4f, 0x08, 0xd7, 0xbe, 0x07, 0x9f, 0x36, 0x9f, + 0x47, 0x24, 0xda, 0x12, 0x1e, 0x9e, 0xb2, 0xcb, + 0x8a, 0x46, 0x64, 0x02, 0xc7, 0x31, 0x51, 0x9b, + 0x99, 0xe8, 0x94, 0x6a, 0xcf, 0x71, 0x0a, 0x02, + 0x0b, 0x60, 0x99, 0xca, 0xde, 0xb8, 0x56, 0xae, + 0xbf, 0x1f, 0x44, 0x5f, 0xc8, 0x70, 0x57, 0x6e, + 0x65, 0xa6, 0x73, 0x2f, 0x5d, 0xd9, 0x52, 0x15, + 0xff, 0x66, 0xcc, 0x8b, 0x7e, 0x28, 0xae, 0x53, + 0x2b, 0x80, 0x83, 0x2a, 0xd5, 0x22, 0xbc, 0xfe, + 0x67, 0x2c, 0xbf, 0x53, 0x40, 0x1a, 0xa5, 0xa3, + 0x54, 0x87, 0x12, 0x85, 0x7b, 0xe8, 0xc5, 0xf9, + 0x1d, 0x7f, 0xfb, 0xfa, 0x76, 0x89, 0x1d, 0x69, + 0xb9, 0x33, 0x3e, 0xee, 0x10, 0xa8, 0x86, 0x45, + 0xd1, 0xc7, 0x74, 0x8e, 0x2d, 0xcf, 0x25, 0xcc, + 0xe2, 0x43, 0x24, 0xe2, 0x8a, 0xc2, 0x67, 0x3e, + 0xf8, 0xc9, 0xaf, 0x86, 0xa8, 0x63, 0x82, 0x8b, + 0x2f, 0x9e, 0xf8, 0x3b, 0x60, 0xc7, 0x78, 0x71, + 0xdd, 0xd0, 0xb0, 0x90, 0x5a, 0xc6, 0x11, 0x1c, + 0x73, 0xb3, 0x74, 0x8f, 0x71, 0xb8, 0x0f, 0x0d, + 0x69, 0xaa, 0x19, 0xd4, 0x3e, 0x6c, 0x9a, 0x73, + 0x46, 0xcc, 0x50, 0x80, 0x1a, 0x09, 0x22, 0x32, + 0x71, 0x72, 0x5a, 0xef, 0x54, 0x6d, 0x88, 0x49, + 0x48, 0x3a, 0xbd, 0x3a, 0xc2, 0xd1, 0xd0, 0xc5, + 0x70, 0x16, 0x84, 0x84, 0x14, 0x73, 0x8b, 0x3d, + 0x60, 0xa9, 0x96, 0xae, 0x6a, 0x67, 0x7b, 0xcb, + 0x49, 0xa6, 0x6b, 0xd6, 0x76, 0x3a, 0x3c, 0xbc, + 0x22, 0xaf, 0x42, 0xe0, 0xd4, 0x0b, 0xc7, 0x0d, + 0xd7, 0x43, 0x57, 0x66, 0xb6, 0x98, 0xe9, 0x4b, + 0x3e, 0x50, 0xa4, 0xc5, 0x1c, 0x83, 0xaf, 0x9e, + 0x4f, 0x2f, 0x98, 0x4c, 0x5c, 0x8c, 0x32, 0x7c, + 0x58, 0x98, 0xdb, 0x0a, 0xdd, 0x8a, 0x98, 0x48, + 0xf1, 0x1e, 0xfe, 0x3d, 0x64, 0x95, 0x08, 0x9c, + 0x50, 0x3d, 0xdf, 0xca, 0xe4, 0xfe, 0x45, 0xf3, + 0x8e, 0x67, 0x1e, 0x59, 0x2c, 0x14, 0xa4, 0xe7, + 0xd6, 0x66, 0x3e, 0x88, 0x96, 0x57, 0xaf, 0xde, + 0xd9, 0xfe, 0x34, 0x34, 0x35, 0x2d, 0x47, 0x56, + 0x87, 0x71, 0x17, 0x6a, 0x89, 0xdf, 0xaf, 0x82, + 0xf9, 0xbd, 0x19, 0x6a, 0xad, 0x37, 0xdd, 0xee, + 0xe8, 0x76, 0x41, 0x6b, 0xda, 0x76, 0x38, 0xf2, + 0x51, 0xa2, 0x2d, 0x51, 0x4d, 0x3f, 0x31, 0x12, + 0x42, 0xa8, 0xbd, 0x82, 0x79, 0x6f, 0x96, 0x67 + }; + + static const byte mldsa87_sig[] = { + 0x89, 0xd5, 0x59, 0x36, 0xb8, 0xa1, 0xc5, 0x29, + 0x2d, 0xe0, 0x6e, 0x77, 0x65, 0x23, 0x5b, 0x2a, + 0x9a, 0xbb, 0x79, 0x41, 0xdf, 0x3c, 0x40, 0x9f, + 0xd9, 0x81, 0x75, 0x93, 0x1a, 0xc0, 0x8b, 0x6f, + 0xc3, 0x9b, 0x61, 0xfc, 0xa5, 0x0a, 0xcd, 0x65, + 0x40, 0x28, 0xfb, 0x8c, 0x9e, 0xe3, 0x30, 0x87, + 0x5f, 0x09, 0xec, 0x3f, 0xa3, 0xee, 0x70, 0x47, + 0x77, 0x1f, 0x9d, 0x65, 0x73, 0xfc, 0xd2, 0xc1, + 0x33, 0x66, 0x42, 0xd0, 0x4f, 0x32, 0x7c, 0x05, + 0x58, 0x5b, 0xe0, 0x29, 0x74, 0x05, 0x05, 0xa3, + 0x68, 0xc2, 0x13, 0xd2, 0xf8, 0x38, 0xc5, 0xaf, + 0x7e, 0x92, 0x23, 0xca, 0xf0, 0x46, 0x8f, 0xcb, + 0x7f, 0xc5, 0x8b, 0xaa, 0xd8, 0x6a, 0xef, 0xaa, + 0x19, 0x01, 0x91, 0x68, 0x8c, 0xd2, 0xce, 0xb3, + 0xe2, 0x49, 0xa6, 0x2e, 0x10, 0x8f, 0xc5, 0xe9, + 0x5f, 0x7a, 0xa8, 0x0e, 0xf1, 0x25, 0x73, 0x9f, + 0xa8, 0xa3, 0x3c, 0xb8, 0x0f, 0xba, 0x2c, 0x6f, + 0x75, 0x33, 0xc0, 0x7c, 0xc4, 0x56, 0xc7, 0x49, + 0xcd, 0x68, 0xda, 0x57, 0x0f, 0xc9, 0x50, 0x0b, + 0xd1, 0xea, 0x05, 0x22, 0x1b, 0x35, 0x5b, 0x7d, + 0xd4, 0x96, 0x82, 0xa6, 0xb0, 0x3e, 0x4b, 0xe6, + 0xb3, 0x72, 0x44, 0xd9, 0xc8, 0xbd, 0xbf, 0xef, + 0x1b, 0x23, 0xd8, 0x08, 0xc1, 0x61, 0x33, 0x81, + 0xff, 0x9c, 0x61, 0xab, 0x35, 0x83, 0x3a, 0x62, + 0xb5, 0xb1, 0x9b, 0x46, 0x99, 0xf1, 0x76, 0x19, + 0x89, 0xd2, 0x46, 0x13, 0x21, 0x92, 0x7b, 0xe8, + 0x3c, 0xc9, 0x96, 0x62, 0x44, 0x48, 0x5b, 0xea, + 0x07, 0x88, 0xf7, 0xdd, 0x10, 0x37, 0xba, 0x11, + 0x09, 0x19, 0x24, 0x6d, 0x6d, 0x19, 0xc7, 0xc8, + 0xbb, 0xb6, 0x4e, 0x10, 0x80, 0x98, 0x72, 0xbb, + 0x37, 0x6c, 0xf3, 0x4a, 0xbd, 0x93, 0x00, 0x6e, + 0x79, 0xc4, 0x25, 0x0b, 0x43, 0x5b, 0xee, 0x7c, + 0x92, 0x93, 0x90, 0x2a, 0x87, 0xe8, 0xb9, 0xb2, + 0xa8, 0x4f, 0xba, 0x0b, 0x72, 0xbc, 0x37, 0xf8, + 0xf5, 0x90, 0x99, 0x16, 0x95, 0xb5, 0x0f, 0x2d, + 0xd6, 0x72, 0x0f, 0x31, 0x6b, 0xb8, 0x24, 0xf2, + 0x07, 0xbe, 0xf5, 0x4c, 0xf8, 0x69, 0x77, 0x8c, + 0xd9, 0x02, 0x91, 0xb7, 0xc5, 0x9c, 0x75, 0x9b, + 0xc6, 0xa9, 0xe2, 0x1f, 0x16, 0x9a, 0x65, 0x20, + 0x0e, 0x9a, 0xc2, 0x11, 0x38, 0xe4, 0xb8, 0x45, + 0xec, 0x96, 0x80, 0x4c, 0x31, 0x1d, 0x1d, 0xde, + 0xfd, 0xf6, 0x7b, 0x54, 0x3a, 0xce, 0xc4, 0x71, + 0xb5, 0x75, 0x74, 0xfb, 0x00, 0x38, 0x25, 0xbc, + 0x55, 0xa8, 0xd6, 0xc1, 0xec, 0x5a, 0x9d, 0x42, + 0xe3, 0x15, 0x27, 0x73, 0xe7, 0xda, 0x35, 0x84, + 0x23, 0xce, 0xeb, 0x7b, 0xcb, 0x20, 0x95, 0xda, + 0x24, 0x39, 0x8b, 0xcc, 0x68, 0x05, 0x7c, 0x58, + 0x05, 0xa1, 0x40, 0x87, 0x66, 0x36, 0xa1, 0xd5, + 0x2e, 0x2b, 0x8c, 0xd1, 0xbb, 0x42, 0x11, 0x57, + 0x52, 0xe2, 0xdb, 0xae, 0x1f, 0xa6, 0x80, 0xa9, + 0xca, 0x4b, 0xdf, 0x8c, 0xc9, 0x19, 0x07, 0x91, + 0xe1, 0xb4, 0xff, 0x8d, 0x4f, 0xfe, 0x40, 0xef, + 0x71, 0x57, 0x31, 0x30, 0xf3, 0x50, 0xa2, 0xd2, + 0x53, 0xcd, 0x61, 0xfb, 0x55, 0x02, 0xb3, 0xe4, + 0xd1, 0x8a, 0x8f, 0x9f, 0xe5, 0xb0, 0x53, 0x83, + 0x6b, 0x32, 0xb1, 0x1f, 0x7b, 0x83, 0xc0, 0x61, + 0x4b, 0xa8, 0x2b, 0xde, 0x93, 0x92, 0xe6, 0xb8, + 0x01, 0x9a, 0xd2, 0xf6, 0x8f, 0xa9, 0xaa, 0xd2, + 0xce, 0xcf, 0x3d, 0xc1, 0xd2, 0xb9, 0x38, 0x94, + 0x51, 0x2c, 0xf8, 0xce, 0x4e, 0xa9, 0x2b, 0x02, + 0x12, 0x07, 0x6c, 0x56, 0xfa, 0xb2, 0x83, 0x7a, + 0x33, 0x00, 0x40, 0x31, 0xb7, 0x11, 0xd7, 0xc0, + 0x41, 0x01, 0xe5, 0xfc, 0xb9, 0x39, 0x4f, 0x12, + 0xb4, 0xad, 0x9d, 0x39, 0xd5, 0x57, 0x50, 0x83, + 0x4b, 0xde, 0xb1, 0x53, 0x3c, 0x70, 0xbc, 0x9d, + 0x29, 0x56, 0x77, 0x51, 0x23, 0xc9, 0x93, 0x66, + 0x7a, 0x7f, 0xb8, 0x84, 0x95, 0x87, 0xf2, 0x99, + 0x77, 0x12, 0xdd, 0xb0, 0x3f, 0x8c, 0x18, 0x61, + 0x86, 0xf6, 0x92, 0x15, 0x77, 0xf2, 0x1a, 0xf9, + 0x70, 0x85, 0xa7, 0x06, 0xb9, 0xfc, 0xfb, 0x03, + 0xbc, 0x69, 0xd0, 0xb6, 0xf1, 0xce, 0x84, 0xb0, + 0xf5, 0xe3, 0x21, 0x93, 0xd9, 0xf6, 0x5f, 0x39, + 0xbd, 0xf4, 0x88, 0x31, 0xf7, 0x06, 0xff, 0x9d, + 0x09, 0xcc, 0x8e, 0x36, 0xe3, 0xda, 0xbd, 0x0e, + 0x5c, 0x6d, 0x14, 0xd1, 0xb7, 0x2f, 0xb9, 0x8c, + 0x1b, 0x17, 0x1d, 0x0c, 0x71, 0xd6, 0x1c, 0xbb, + 0x51, 0xe5, 0x1f, 0x7b, 0xe0, 0x83, 0xd1, 0x07, + 0x0f, 0xd3, 0x7f, 0x4f, 0x71, 0xfd, 0x29, 0x4d, + 0x4d, 0xd1, 0xdd, 0xc3, 0x35, 0x3c, 0x15, 0x38, + 0x9d, 0xa6, 0x6d, 0xe2, 0x1c, 0x1e, 0x3b, 0xc8, + 0xd7, 0xc1, 0x97, 0x44, 0xe9, 0x4c, 0xa0, 0x67, + 0x7d, 0x75, 0xac, 0x74, 0x24, 0x7f, 0x63, 0x0a, + 0x11, 0x3e, 0x22, 0xcc, 0x9d, 0x1f, 0x13, 0x01, + 0x23, 0xf6, 0xf4, 0xc2, 0xff, 0xbe, 0x3c, 0xda, + 0x0d, 0xfb, 0x04, 0x2c, 0xcb, 0x1e, 0xf8, 0x3b, + 0xc5, 0x57, 0x13, 0xc7, 0x10, 0x0d, 0xdf, 0x52, + 0x61, 0x5d, 0xf6, 0x7f, 0x21, 0x8a, 0xfc, 0xb3, + 0xa0, 0x76, 0xc1, 0x23, 0xa8, 0xba, 0xb3, 0xfa, + 0x7b, 0xc9, 0x31, 0x42, 0x2c, 0x05, 0x94, 0x31, + 0x0b, 0x3a, 0x52, 0x25, 0x79, 0x67, 0x54, 0x5b, + 0x23, 0x97, 0xbb, 0x9b, 0x4f, 0x79, 0x99, 0xfc, + 0x8e, 0xb0, 0x6a, 0xf2, 0x60, 0xfe, 0x6e, 0x2e, + 0x3f, 0xe5, 0x27, 0x25, 0xb2, 0xa9, 0x1e, 0x6d, + 0x6a, 0xdd, 0xf1, 0xf9, 0xbe, 0x5e, 0x7b, 0xc5, + 0x51, 0x68, 0xec, 0xe8, 0x0d, 0x31, 0xe8, 0x42, + 0x85, 0xf1, 0x68, 0xb4, 0xcd, 0x53, 0xe7, 0x73, + 0x03, 0xd2, 0xc1, 0xd1, 0xbd, 0xbc, 0xff, 0x8b, + 0x58, 0x0d, 0x17, 0x8c, 0x55, 0xfd, 0xb8, 0xde, + 0x52, 0x09, 0x9e, 0xd3, 0x07, 0x81, 0xdd, 0x0d, + 0x5d, 0x8d, 0xd3, 0x70, 0x5e, 0x85, 0xe0, 0x3c, + 0xde, 0x49, 0x33, 0x54, 0xd9, 0xc5, 0xc6, 0x5f, + 0x0b, 0xef, 0x01, 0xb5, 0x27, 0xc4, 0xe2, 0xd8, + 0x98, 0x4e, 0x0c, 0x2e, 0xdb, 0xe1, 0xb7, 0xd4, + 0x2a, 0x4e, 0xe9, 0xcf, 0xe4, 0x58, 0x87, 0x46, + 0x9a, 0x67, 0xd9, 0x17, 0x40, 0x80, 0xed, 0x47, + 0x51, 0xcf, 0xad, 0xf7, 0x5d, 0x8b, 0x4d, 0x0e, + 0xdd, 0xfc, 0xe9, 0x28, 0x1a, 0xfd, 0xfb, 0x74, + 0x55, 0x9a, 0xf3, 0xf3, 0x98, 0x3b, 0xc8, 0x1c, + 0x41, 0x20, 0x93, 0x71, 0xc8, 0x0b, 0xb1, 0xde, + 0xdb, 0x91, 0x4d, 0x35, 0x6c, 0xad, 0xbc, 0xaa, + 0x65, 0xde, 0x1a, 0x3d, 0x76, 0xb4, 0xa0, 0xc7, + 0x4d, 0x0c, 0x88, 0xbd, 0xfc, 0x38, 0x92, 0x46, + 0xa9, 0xa4, 0xa7, 0x25, 0xcb, 0x14, 0x21, 0x28, + 0xda, 0xbd, 0x21, 0x23, 0x40, 0xf5, 0x31, 0x64, + 0x89, 0xdf, 0x03, 0xb0, 0x19, 0x9f, 0xbd, 0x52, + 0x5d, 0x95, 0x6b, 0xfb, 0x04, 0x48, 0xd5, 0x94, + 0xd7, 0xea, 0xd9, 0xad, 0x78, 0xa2, 0xef, 0x03, + 0x99, 0xed, 0x41, 0x4b, 0xd7, 0x2a, 0x25, 0xc3, + 0xb9, 0xdd, 0x30, 0x97, 0xb5, 0x27, 0x62, 0x00, + 0x40, 0x49, 0xcf, 0xa1, 0xf5, 0x94, 0x09, 0xa9, + 0x92, 0xf1, 0x43, 0x67, 0xd9, 0x17, 0x5f, 0xbc, + 0xf9, 0xc7, 0xe4, 0x8e, 0x3d, 0x0f, 0x16, 0x7f, + 0x6a, 0xfb, 0x13, 0xc2, 0x08, 0xd7, 0xdd, 0x42, + 0xb9, 0x9e, 0xf6, 0xd5, 0x3b, 0xdb, 0x05, 0xd5, + 0x90, 0xaa, 0xe2, 0x27, 0xb2, 0x01, 0x25, 0x27, + 0x0d, 0x60, 0x3b, 0xdf, 0x18, 0x29, 0xda, 0x3c, + 0xf7, 0x3c, 0x75, 0x3a, 0xc9, 0x8c, 0x0f, 0x6a, + 0xcd, 0x8c, 0x06, 0x48, 0x30, 0xe7, 0xf7, 0xf2, + 0xb0, 0x29, 0x67, 0x6d, 0x01, 0x53, 0x8d, 0x37, + 0x39, 0x23, 0xca, 0xbe, 0x88, 0xcf, 0xa3, 0x87, + 0x06, 0x4c, 0x17, 0x6f, 0x6a, 0x6c, 0x32, 0x90, + 0xa7, 0x17, 0xa3, 0x01, 0x76, 0x3e, 0x89, 0x55, + 0xe1, 0x1f, 0x17, 0x1f, 0x70, 0x51, 0x10, 0x3d, + 0x52, 0x63, 0x14, 0x29, 0xb0, 0x13, 0x80, 0x94, + 0x8d, 0x13, 0x74, 0xa4, 0x2a, 0xff, 0x84, 0x5c, + 0x1e, 0xee, 0x69, 0x87, 0x5b, 0x8c, 0x81, 0x38, + 0x01, 0xd5, 0x83, 0x08, 0xa6, 0xc7, 0x40, 0xc3, + 0x1a, 0x70, 0x87, 0x55, 0x6a, 0x3a, 0x3e, 0x60, + 0x8c, 0x31, 0x51, 0x12, 0xf7, 0x12, 0x39, 0x53, + 0x4c, 0x69, 0xad, 0x6a, 0x1b, 0x2e, 0x8e, 0x25, + 0x31, 0xd0, 0xe8, 0x04, 0xaf, 0xf4, 0x6d, 0x03, + 0xa5, 0x75, 0x1c, 0xe0, 0xea, 0x1b, 0x8b, 0x88, + 0xea, 0xd9, 0xfc, 0xae, 0x56, 0x96, 0x19, 0x25, + 0x56, 0xdb, 0xbc, 0x65, 0x65, 0x46, 0xbf, 0xb8, + 0x85, 0x07, 0x0e, 0x5a, 0x7b, 0xa5, 0x25, 0x63, + 0xcf, 0xeb, 0x2f, 0xad, 0xb6, 0x30, 0xbb, 0x2c, + 0x13, 0x93, 0x18, 0x0b, 0x60, 0x51, 0x5f, 0x30, + 0x01, 0xff, 0xd9, 0xfe, 0x56, 0x91, 0x7f, 0xfc, + 0x3e, 0xbb, 0x8f, 0x1b, 0xb8, 0x3d, 0x8e, 0x4e, + 0x50, 0x2c, 0x42, 0x6b, 0x26, 0xc4, 0xce, 0x19, + 0x60, 0x6b, 0x58, 0x80, 0xc0, 0xa0, 0x66, 0x73, + 0xa5, 0xd2, 0x33, 0x27, 0x46, 0xec, 0xdd, 0xda, + 0xcb, 0x39, 0x51, 0xee, 0x51, 0x7d, 0xd2, 0xdd, + 0xf3, 0x32, 0x8f, 0x02, 0x02, 0x22, 0xcf, 0xf6, + 0xd1, 0x70, 0x41, 0x0a, 0x34, 0x43, 0x2d, 0xe9, + 0xef, 0xbb, 0xd2, 0x0e, 0xb6, 0x62, 0x88, 0x1c, + 0x67, 0xc5, 0x2b, 0xe4, 0x45, 0x02, 0x0d, 0xf8, + 0xbf, 0x28, 0x34, 0xa8, 0x58, 0x10, 0xae, 0xda, + 0x47, 0xf4, 0x5e, 0x9a, 0x48, 0xdf, 0x3a, 0x00, + 0xec, 0x55, 0x59, 0x8e, 0x98, 0xdf, 0x26, 0xd1, + 0xb0, 0x06, 0xbd, 0xfb, 0x92, 0x11, 0x61, 0x77, + 0x58, 0x60, 0x1b, 0x89, 0x6d, 0x1a, 0xfb, 0xe7, + 0x7b, 0x3d, 0x60, 0x75, 0x3a, 0xcb, 0x03, 0x37, + 0xfe, 0xb0, 0x96, 0xae, 0x87, 0x9d, 0xcc, 0xa3, + 0xf2, 0xf4, 0x7c, 0xd6, 0x68, 0xf4, 0x9a, 0xb7, + 0x70, 0x60, 0x22, 0x71, 0x6a, 0x12, 0xa8, 0x83, + 0xb6, 0xd1, 0x97, 0x1f, 0x63, 0xa0, 0x61, 0xca, + 0xc7, 0x45, 0xb8, 0x8c, 0x9d, 0x61, 0xf1, 0x32, + 0x26, 0x7d, 0xa0, 0x7b, 0x9f, 0x14, 0x95, 0xd3, + 0xa0, 0x7c, 0x43, 0x95, 0xe6, 0xd0, 0xc3, 0xb1, + 0x48, 0xd5, 0xe3, 0x07, 0x51, 0x15, 0x4b, 0x2d, + 0xe6, 0x19, 0x12, 0x65, 0xb6, 0x98, 0x23, 0xe9, + 0x0c, 0x4c, 0x08, 0x4a, 0x03, 0xb3, 0x85, 0xcf, + 0xd8, 0x1e, 0xa4, 0xc6, 0xe5, 0x8a, 0x3c, 0x4f, + 0x23, 0x39, 0x44, 0x11, 0x3b, 0x79, 0x73, 0x35, + 0xfa, 0x4a, 0x83, 0xee, 0x51, 0x7b, 0x8c, 0x10, + 0x58, 0xd8, 0x93, 0xa5, 0x19, 0xc6, 0x17, 0x83, + 0x45, 0x25, 0x92, 0xfe, 0xde, 0xf2, 0x17, 0x83, + 0x08, 0xbc, 0x9c, 0x5a, 0x2e, 0xef, 0x05, 0x02, + 0x2e, 0x97, 0x52, 0x3b, 0xa1, 0x14, 0xdb, 0x01, + 0x12, 0xd4, 0x02, 0x5f, 0xb1, 0x8c, 0x4b, 0xd2, + 0xbf, 0xc2, 0xe8, 0xf4, 0x2e, 0x9b, 0x6d, 0x12, + 0x07, 0x6a, 0xa8, 0x86, 0x67, 0x28, 0xb1, 0x56, + 0x7d, 0x0e, 0x47, 0x4e, 0x85, 0xa1, 0xad, 0xb9, + 0x92, 0xdf, 0xcc, 0x1a, 0xb5, 0x18, 0xa3, 0x3a, + 0x39, 0x93, 0x2b, 0xa0, 0x61, 0x8d, 0xe2, 0x02, + 0x34, 0xe6, 0x0e, 0xa8, 0xc0, 0x65, 0x6d, 0xfa, + 0xa2, 0x12, 0x98, 0xc2, 0xf3, 0xa6, 0x0b, 0x60, + 0x29, 0x07, 0xbd, 0xfe, 0x3b, 0xed, 0xbb, 0xb6, + 0x91, 0x62, 0x12, 0xfb, 0x3b, 0x9f, 0x8c, 0x1d, + 0xc2, 0x97, 0x2b, 0x33, 0x56, 0xbb, 0xc0, 0xf5, + 0x64, 0xd2, 0xc4, 0x2c, 0xf6, 0xf4, 0xa6, 0x4b, + 0x65, 0x1a, 0xa2, 0x63, 0xef, 0x6f, 0xd8, 0x9d, + 0xd0, 0x49, 0x93, 0x86, 0xd0, 0x95, 0xbe, 0xd6, + 0xb7, 0x3b, 0xe5, 0x1f, 0x9e, 0xc1, 0x91, 0xfd, + 0x26, 0xc9, 0xe6, 0x7d, 0xc8, 0xe1, 0x2b, 0xb4, + 0xe7, 0xa8, 0xfa, 0x30, 0xb9, 0xcb, 0x1d, 0x5e, + 0x51, 0x71, 0x54, 0x3c, 0xe1, 0xd9, 0x82, 0x35, + 0x32, 0xdf, 0xfb, 0xda, 0x34, 0x88, 0xcc, 0x97, + 0xfd, 0x30, 0x01, 0x27, 0x6e, 0x00, 0x27, 0x00, + 0xbe, 0x33, 0xce, 0x1a, 0x24, 0x29, 0xb1, 0x60, + 0x1b, 0x94, 0x45, 0x33, 0x70, 0xfe, 0xa9, 0xe9, + 0x62, 0xde, 0x57, 0x1a, 0x90, 0x72, 0x10, 0x19, + 0x42, 0xd8, 0x30, 0x21, 0xb5, 0x00, 0x6d, 0x77, + 0xc4, 0xd9, 0xfc, 0xde, 0x04, 0xd7, 0xe9, 0xc7, + 0x0f, 0xd7, 0xce, 0xdf, 0x25, 0xda, 0xb2, 0xf2, + 0xf4, 0x31, 0x01, 0xe1, 0x71, 0xe6, 0x1c, 0x13, + 0x2c, 0x86, 0xd8, 0xdc, 0x77, 0xdf, 0x70, 0x0f, + 0x29, 0x51, 0x8d, 0xa5, 0x7e, 0x20, 0x5c, 0x6f, + 0x46, 0x8c, 0xd5, 0xfe, 0xba, 0x2d, 0xbc, 0x00, + 0xfa, 0xe6, 0xb3, 0x50, 0x22, 0x57, 0xeb, 0xc7, + 0x53, 0xf3, 0x21, 0x55, 0xf0, 0x61, 0x26, 0xc9, + 0xae, 0x65, 0x1d, 0xfc, 0x61, 0x5e, 0x6e, 0x8e, + 0xdc, 0x2f, 0x95, 0xe8, 0x34, 0x03, 0x6e, 0xc0, + 0xfb, 0x8d, 0x54, 0xb3, 0x9f, 0xf5, 0x18, 0x0f, + 0xf3, 0x0b, 0xa3, 0xbf, 0x9c, 0x27, 0xd0, 0x55, + 0x76, 0xa4, 0x2a, 0xd9, 0xc1, 0xf5, 0x12, 0x91, + 0x05, 0x82, 0x45, 0x1b, 0x21, 0x94, 0xaa, 0x76, + 0xbe, 0xb0, 0x10, 0x5d, 0x9d, 0x6f, 0x13, 0xbe, + 0xf7, 0xda, 0x7e, 0x38, 0xad, 0x55, 0x60, 0x3a, + 0x7f, 0xfd, 0xad, 0x06, 0x4f, 0x08, 0x38, 0x6d, + 0xc5, 0x48, 0xb2, 0x59, 0x59, 0xb0, 0xd9, 0xa3, + 0x1a, 0x62, 0x8b, 0x73, 0x8f, 0x13, 0xa3, 0xee, + 0x3c, 0x8d, 0xd2, 0x5d, 0xd8, 0xe0, 0x03, 0x9d, + 0x0d, 0x76, 0x33, 0xe0, 0xc5, 0x3e, 0x43, 0x6d, + 0x05, 0xbe, 0xca, 0x2b, 0x16, 0xf1, 0x59, 0xa2, + 0x1c, 0x84, 0xaf, 0x10, 0x58, 0xa4, 0x46, 0xa1, + 0x71, 0x91, 0x5f, 0x4d, 0x0f, 0xb3, 0xab, 0x42, + 0x6c, 0x83, 0x94, 0xd4, 0xad, 0x48, 0xb6, 0xab, + 0x56, 0xe1, 0x8a, 0x6f, 0x5a, 0x6d, 0x64, 0x83, + 0x3b, 0x38, 0x60, 0xa1, 0x6c, 0xc8, 0xe7, 0x29, + 0x17, 0x58, 0xa1, 0x02, 0x47, 0x3c, 0x5d, 0x9f, + 0x59, 0xe7, 0xca, 0xec, 0x3b, 0xc0, 0x2c, 0x1c, + 0x3c, 0x48, 0xf4, 0x2f, 0x3c, 0x54, 0x1f, 0x95, + 0xd6, 0x5a, 0x83, 0x6e, 0x7b, 0x3a, 0x63, 0x25, + 0x94, 0xd1, 0x7e, 0x67, 0x14, 0x20, 0x72, 0x42, + 0x54, 0xed, 0x6d, 0x7e, 0xa2, 0xcd, 0x77, 0x1a, + 0x1d, 0xd7, 0x01, 0xa9, 0xa0, 0xa2, 0xdd, 0xda, + 0x92, 0x29, 0x1e, 0x20, 0x7b, 0xf3, 0xc7, 0xd9, + 0x92, 0x2b, 0xdb, 0x63, 0x1a, 0xa8, 0xdc, 0xaa, + 0x98, 0x0f, 0xe5, 0xa9, 0x9b, 0x44, 0x8d, 0x1d, + 0x46, 0x07, 0x1b, 0xac, 0x70, 0x6c, 0xe6, 0xad, + 0x3e, 0x51, 0xe1, 0x3b, 0x91, 0xb8, 0xd6, 0x1c, + 0x87, 0x08, 0xae, 0xb4, 0x3c, 0xfb, 0x5e, 0x9d, + 0x33, 0xce, 0x50, 0x9f, 0x04, 0xc1, 0x44, 0xc7, + 0xd6, 0x73, 0xde, 0xd3, 0xb4, 0x55, 0x7d, 0x65, + 0x0d, 0x8c, 0xb2, 0x63, 0x7a, 0x1e, 0x10, 0xb0, + 0xb5, 0x75, 0x82, 0xbe, 0x84, 0x94, 0xc9, 0xab, + 0x88, 0x58, 0x1b, 0x85, 0x00, 0x37, 0xe5, 0xba, + 0x18, 0x1c, 0x23, 0x18, 0x34, 0x05, 0xa2, 0xa6, + 0x9a, 0x65, 0x8f, 0xae, 0xca, 0xc4, 0xfc, 0xf9, + 0xc8, 0xd5, 0x3b, 0xb7, 0x38, 0xcb, 0x1b, 0x46, + 0x60, 0x14, 0x4f, 0x59, 0x83, 0x99, 0x63, 0x88, + 0x4b, 0x44, 0x81, 0xd8, 0x76, 0x8f, 0xeb, 0xf9, + 0xee, 0x31, 0xc5, 0x75, 0x82, 0x22, 0xc5, 0x31, + 0x8c, 0x3a, 0x2e, 0x4c, 0x87, 0x8d, 0x2e, 0x04, + 0xd6, 0xd6, 0x2a, 0xd3, 0xaa, 0x5b, 0x90, 0x9c, + 0x7a, 0x21, 0xe9, 0x97, 0x13, 0x93, 0xec, 0xe6, + 0x8c, 0xbe, 0xdd, 0xb1, 0xc7, 0x68, 0x1b, 0xdf, + 0x0f, 0xe5, 0xbf, 0xa6, 0xe4, 0xc1, 0x14, 0x82, + 0x1e, 0xc9, 0xe7, 0xbd, 0xe6, 0x5b, 0x6e, 0x20, + 0x42, 0xc1, 0xb7, 0xf9, 0xe6, 0x7c, 0x90, 0xbd, + 0x73, 0x57, 0x53, 0xd6, 0xac, 0xf0, 0x2c, 0x4c, + 0x26, 0xaf, 0xfc, 0x55, 0xb3, 0xc3, 0x48, 0x1d, + 0xad, 0xb7, 0xad, 0xe3, 0x74, 0x7e, 0xe4, 0x89, + 0xfa, 0x4d, 0x6f, 0x68, 0x78, 0xbf, 0x5c, 0xc3, + 0xa1, 0x79, 0x1c, 0x18, 0x52, 0xf1, 0x56, 0x4d, + 0xc7, 0xae, 0x0e, 0x6c, 0x68, 0x01, 0x15, 0xd0, + 0x83, 0x50, 0xff, 0x98, 0x41, 0xf0, 0x05, 0x37, + 0xb2, 0x23, 0x67, 0xaf, 0x37, 0x4a, 0xd6, 0xda, + 0x36, 0x14, 0x3c, 0xa4, 0xb5, 0xbc, 0x4c, 0xd3, + 0xe8, 0xdc, 0x62, 0x26, 0xb0, 0x95, 0x23, 0xe9, + 0xfc, 0x2f, 0x97, 0xcf, 0x8b, 0xbc, 0x76, 0xa5, + 0xf1, 0xb4, 0x0c, 0xa0, 0xe3, 0x35, 0xd2, 0x15, + 0xa7, 0xc9, 0xeb, 0xbb, 0xc2, 0xa1, 0x1f, 0xfd, + 0x09, 0xa2, 0xd4, 0x8b, 0x9c, 0x48, 0x14, 0x22, + 0xf6, 0x4e, 0xf8, 0x0a, 0xae, 0x62, 0x8c, 0x1d, + 0x26, 0xd7, 0x33, 0xb4, 0x78, 0x1f, 0x14, 0x3b, + 0x20, 0xa6, 0xb7, 0xb5, 0x22, 0x6a, 0xcc, 0xd6, + 0x39, 0x80, 0x8e, 0x7e, 0x17, 0xd4, 0xf3, 0x2e, + 0xa3, 0x6c, 0xf4, 0x05, 0xb2, 0xdc, 0x62, 0x80, + 0x16, 0x1e, 0x5d, 0x4f, 0x87, 0x3d, 0xc5, 0xd5, + 0x4d, 0x61, 0xd0, 0xc7, 0xb6, 0x3f, 0xd7, 0x72, + 0xcb, 0x60, 0x77, 0x1b, 0x8a, 0xc1, 0x8d, 0x10, + 0xf2, 0x9f, 0x20, 0xec, 0x83, 0xa6, 0xc1, 0x92, + 0x53, 0x00, 0x94, 0x1b, 0xf3, 0x39, 0x8f, 0xa6, + 0x27, 0x0d, 0xde, 0x51, 0x04, 0x4f, 0x5d, 0xf4, + 0x74, 0x95, 0x00, 0xc9, 0xe7, 0x7d, 0xbd, 0x45, + 0x02, 0x4f, 0xbd, 0x6f, 0x15, 0x82, 0xd8, 0x16, + 0xea, 0x27, 0x12, 0x53, 0xda, 0x64, 0x0b, 0xf7, + 0xce, 0x3c, 0xe1, 0x42, 0xf6, 0x3b, 0x33, 0xf3, + 0xf5, 0x69, 0xf4, 0xe7, 0xc8, 0xf4, 0xb5, 0xe8, + 0xbc, 0x7e, 0x6c, 0xd5, 0x18, 0xa9, 0x62, 0x3e, + 0x81, 0xd0, 0x21, 0xb5, 0x32, 0xfe, 0x30, 0x2e, + 0x74, 0xe9, 0x1c, 0x60, 0xfc, 0xd2, 0xae, 0x72, + 0x29, 0x87, 0xd5, 0x19, 0xc8, 0x8d, 0x2c, 0xba, + 0x9f, 0xd2, 0x80, 0x45, 0x24, 0xfa, 0xe9, 0xaf, + 0x86, 0xe9, 0x41, 0xa5, 0xf1, 0xad, 0x89, 0x5d, + 0x91, 0xf2, 0x0f, 0xc1, 0xa4, 0x0e, 0xa8, 0x29, + 0x04, 0xb7, 0xe4, 0xc1, 0x47, 0x40, 0x66, 0x68, + 0xd1, 0xec, 0x71, 0x19, 0x71, 0xec, 0x27, 0x41, + 0x6f, 0x17, 0x62, 0x6a, 0x2e, 0x04, 0x97, 0x22, + 0x6f, 0x96, 0x8a, 0xaa, 0x86, 0xde, 0x98, 0xe9, + 0xa9, 0x0b, 0x32, 0x87, 0x68, 0x1f, 0x54, 0xf6, + 0xf1, 0x52, 0xda, 0x7f, 0x03, 0x18, 0xb5, 0xda, + 0x11, 0xd0, 0x45, 0x82, 0xb2, 0xf3, 0x34, 0x35, + 0xd5, 0x7b, 0x82, 0xbb, 0xd5, 0xcc, 0x93, 0x42, + 0xd1, 0xf6, 0xfb, 0x49, 0x33, 0xd9, 0x59, 0x1d, + 0x65, 0x5c, 0x86, 0x70, 0x94, 0x79, 0x34, 0xd8, + 0xa0, 0x38, 0x3f, 0xfe, 0xa4, 0xeb, 0x6b, 0x97, + 0x37, 0x45, 0xfa, 0x48, 0xae, 0x2e, 0xef, 0x41, + 0xd9, 0x3c, 0x93, 0x22, 0x0b, 0x5d, 0xf7, 0xd9, + 0x01, 0xef, 0x2e, 0x46, 0x97, 0xca, 0xec, 0xc3, + 0x33, 0xf0, 0xb4, 0x26, 0x50, 0x2c, 0x69, 0x9e, + 0xe8, 0xf3, 0x08, 0x7b, 0xa1, 0xa7, 0xe8, 0xdb, + 0x3b, 0x52, 0x8f, 0xfb, 0x38, 0x55, 0x35, 0x2d, + 0x3e, 0xa4, 0x3d, 0xf3, 0x1e, 0x55, 0x0d, 0x15, + 0x39, 0xdc, 0x2b, 0xc9, 0x2c, 0x09, 0xf1, 0xa1, + 0x2b, 0xce, 0x28, 0xa6, 0x7c, 0x4f, 0x39, 0x1a, + 0x63, 0x6c, 0x6c, 0xb7, 0x51, 0xb7, 0x6e, 0x87, + 0xb0, 0xf2, 0xbe, 0x90, 0xd4, 0x95, 0x46, 0xc4, + 0x2e, 0xe9, 0x18, 0xe2, 0xd6, 0x88, 0xea, 0x98, + 0xf1, 0x14, 0x72, 0x2d, 0xf8, 0x4d, 0x24, 0x0c, + 0xad, 0x0a, 0xd4, 0x51, 0xe4, 0x13, 0x6f, 0xc2, + 0x67, 0xc1, 0xa0, 0x3a, 0x5c, 0x5c, 0xc1, 0x08, + 0xbd, 0x08, 0x07, 0xb2, 0x00, 0xed, 0x9d, 0xe2, + 0x63, 0x95, 0x59, 0x67, 0x5c, 0xfb, 0x15, 0x20, + 0x73, 0xa6, 0xe3, 0xf7, 0xbb, 0xa2, 0x0e, 0x45, + 0xaa, 0x67, 0x15, 0x69, 0xa0, 0x7f, 0xe8, 0x44, + 0x8a, 0xe1, 0x7d, 0xeb, 0xbb, 0x63, 0x96, 0xc3, + 0x7e, 0xcf, 0x25, 0x0e, 0x34, 0x9b, 0x67, 0xd5, + 0x08, 0x76, 0x6c, 0xcf, 0x69, 0xf9, 0xb3, 0x17, + 0x79, 0xe6, 0xdd, 0xfc, 0x99, 0x2d, 0x61, 0x05, + 0x79, 0x32, 0xbd, 0x42, 0x3f, 0x0d, 0xdd, 0x9b, + 0x80, 0x3f, 0xf8, 0x09, 0x67, 0xc0, 0x8d, 0x38, + 0x96, 0xc8, 0x0a, 0xbf, 0xd0, 0x12, 0x56, 0x2c, + 0x81, 0xfc, 0x06, 0xfb, 0x2d, 0xbd, 0x07, 0xa9, + 0x9b, 0x1f, 0x5a, 0x2d, 0xcc, 0x78, 0x17, 0xd7, + 0x9d, 0x2b, 0x98, 0x6a, 0x35, 0xbc, 0x37, 0x19, + 0x7a, 0x47, 0x32, 0x20, 0xd3, 0xe7, 0xb0, 0xd3, + 0x32, 0x8e, 0xa1, 0x4f, 0xc2, 0x70, 0x25, 0x3e, + 0x81, 0x26, 0x02, 0x3d, 0x4d, 0x23, 0xaf, 0xdd, + 0x91, 0xe9, 0xfd, 0xec, 0xcb, 0xae, 0x28, 0xcd, + 0x99, 0x80, 0x4b, 0x24, 0x98, 0xfb, 0xaa, 0xff, + 0x7a, 0x97, 0xae, 0x2b, 0xf3, 0xe4, 0x13, 0xb9, + 0x31, 0xf3, 0x30, 0x99, 0x2e, 0x00, 0xd1, 0x0d, + 0x7e, 0x01, 0x54, 0xcf, 0x4d, 0xe7, 0x3a, 0xa7, + 0x83, 0xa8, 0x2a, 0x10, 0xb8, 0x2d, 0xa9, 0xb5, + 0x8a, 0x0f, 0x6b, 0x0e, 0x60, 0xef, 0x35, 0x3a, + 0xf0, 0x27, 0xf2, 0x29, 0x21, 0x3a, 0x6c, 0xb7, + 0xee, 0xbe, 0x75, 0xb8, 0x2f, 0x21, 0xc1, 0x8a, + 0x90, 0xbb, 0xb0, 0x15, 0xe2, 0xc4, 0x7f, 0x33, + 0xde, 0x22, 0xd7, 0x14, 0xda, 0xfc, 0xf5, 0x89, + 0x3d, 0x5e, 0xde, 0x26, 0x6b, 0xf2, 0x67, 0xbf, + 0x57, 0x3f, 0x65, 0x77, 0xc7, 0x90, 0xdd, 0xc6, + 0x72, 0xc3, 0x55, 0x5c, 0x26, 0xd0, 0x34, 0x9c, + 0x66, 0xf1, 0xde, 0x17, 0x4c, 0xb1, 0x5d, 0x31, + 0x18, 0x3f, 0xee, 0x29, 0x55, 0xf4, 0x79, 0xa8, + 0x4a, 0xb3, 0x46, 0xf2, 0x59, 0x3a, 0x9e, 0x65, + 0x8a, 0x72, 0xc1, 0x9b, 0x8f, 0x61, 0x27, 0x77, + 0xa2, 0x4e, 0x86, 0x52, 0xef, 0x51, 0xc9, 0x43, + 0x02, 0x78, 0xc8, 0x08, 0x1d, 0x92, 0x8f, 0x3f, + 0xc5, 0x94, 0x58, 0x8e, 0x93, 0x10, 0xd0, 0x4e, + 0xcb, 0x22, 0x87, 0xc2, 0x65, 0xa4, 0x9e, 0x43, + 0x2e, 0x00, 0xb4, 0xed, 0x32, 0x85, 0x36, 0xda, + 0xe4, 0x4c, 0x11, 0x4d, 0x55, 0x20, 0xf8, 0xbf, + 0x40, 0x49, 0x14, 0xeb, 0x44, 0x0c, 0x53, 0xd3, + 0x08, 0x42, 0x89, 0x0e, 0x43, 0x7f, 0x9e, 0x5e, + 0x88, 0xf7, 0xdb, 0xc7, 0x65, 0x2b, 0xea, 0x25, + 0x8e, 0x4d, 0x1d, 0xc6, 0x54, 0x22, 0x39, 0x21, + 0xf9, 0x1f, 0x58, 0x9d, 0x0a, 0x9f, 0xef, 0x8d, + 0x70, 0x8e, 0xdb, 0x55, 0xc9, 0xdf, 0xc6, 0x6a, + 0x85, 0x26, 0x15, 0xca, 0x0f, 0x8e, 0xc2, 0x70, + 0xaa, 0x09, 0x01, 0xc4, 0x79, 0xa6, 0x76, 0x77, + 0xcf, 0xf6, 0x1e, 0x97, 0xd0, 0x72, 0x2d, 0x5f, + 0x5b, 0xce, 0x8d, 0x78, 0x4b, 0x87, 0x2e, 0xe1, + 0x7a, 0xf8, 0xae, 0xa5, 0x2c, 0x4c, 0x3f, 0xd9, + 0x98, 0x6e, 0xa4, 0xdb, 0x85, 0xaf, 0x5b, 0xfd, + 0xe3, 0xf0, 0xd2, 0xa6, 0xe8, 0xd3, 0xae, 0xcd, + 0x97, 0xc3, 0x2b, 0x2f, 0x4d, 0x51, 0xfb, 0xd9, + 0xa4, 0x9e, 0xf0, 0xe0, 0x74, 0xdb, 0xc9, 0x04, + 0xe6, 0xc3, 0x14, 0x20, 0x45, 0x96, 0x4f, 0x4e, + 0xfe, 0x19, 0x65, 0x28, 0x86, 0x00, 0x70, 0x4f, + 0x2d, 0x2b, 0x5f, 0xb8, 0x6a, 0xa2, 0x65, 0xf8, + 0xcc, 0x26, 0x8d, 0xc8, 0x20, 0xd9, 0xbe, 0x7c, + 0xff, 0x61, 0xa0, 0xe1, 0x80, 0xf3, 0x6a, 0x0d, + 0xb6, 0xd3, 0xe8, 0x1d, 0x58, 0x16, 0x3d, 0x40, + 0xdc, 0x4e, 0x13, 0x1d, 0x74, 0xd6, 0x36, 0xf6, + 0x08, 0x54, 0x86, 0xdf, 0xd3, 0x45, 0x69, 0xf4, + 0x05, 0xbc, 0xb3, 0x66, 0x3a, 0x61, 0xbf, 0xc0, + 0x94, 0x67, 0x7c, 0xae, 0x7e, 0xac, 0x41, 0x48, + 0x8c, 0x22, 0x78, 0x7d, 0x5c, 0x41, 0xcb, 0x11, + 0x55, 0x6f, 0xf2, 0x39, 0xbd, 0x16, 0x34, 0xdf, + 0x66, 0x10, 0xb4, 0x5d, 0x70, 0x8b, 0xaf, 0x45, + 0x15, 0x4e, 0x5b, 0xf7, 0xe6, 0x9a, 0x41, 0xaf, + 0xc8, 0xf0, 0xd5, 0x29, 0x0a, 0x47, 0xed, 0xcb, + 0x2d, 0x21, 0x5b, 0x02, 0x00, 0x7c, 0xaf, 0x3d, + 0xd1, 0xde, 0x93, 0x64, 0xe2, 0x3f, 0xf7, 0x21, + 0xb4, 0x36, 0x89, 0xe5, 0x88, 0xa6, 0x01, 0xad, + 0xda, 0xb2, 0xed, 0x44, 0xc5, 0xa4, 0x19, 0x27, + 0xfd, 0x2f, 0xcc, 0xdc, 0x81, 0xed, 0x17, 0x3d, + 0x24, 0x44, 0x2f, 0x90, 0x91, 0x06, 0x97, 0x9a, + 0xef, 0x37, 0x7a, 0xde, 0xe6, 0xc5, 0xa4, 0xbd, + 0x96, 0x41, 0x2e, 0xee, 0xdd, 0x3a, 0x78, 0x71, + 0xac, 0x3c, 0xf3, 0x74, 0x5a, 0x21, 0x22, 0x67, + 0x54, 0x6c, 0x05, 0x1a, 0x95, 0x7c, 0x9c, 0x7c, + 0x9b, 0xfd, 0xa3, 0xa2, 0xcd, 0xda, 0x3b, 0x59, + 0x8b, 0xb8, 0x2d, 0x26, 0x12, 0xbd, 0x7b, 0xff, + 0xba, 0x94, 0x65, 0x8a, 0xc1, 0x03, 0xf3, 0xc9, + 0x56, 0x18, 0xd8, 0xc1, 0xb8, 0xf9, 0x0c, 0x01, + 0x66, 0xf5, 0x63, 0x9a, 0xd5, 0x44, 0x5c, 0xd1, + 0x70, 0x7d, 0x9d, 0x9d, 0x6a, 0x45, 0xc9, 0x51, + 0xb2, 0xd1, 0xec, 0x2f, 0x3b, 0xde, 0x67, 0x6f, + 0x79, 0x90, 0xa7, 0x02, 0x20, 0x07, 0x81, 0x8d, + 0x7e, 0x86, 0x53, 0x21, 0xfd, 0x58, 0xed, 0xce, + 0x7a, 0x53, 0x73, 0x37, 0x73, 0x87, 0xfa, 0xec, + 0x94, 0x0a, 0x87, 0x17, 0x86, 0xbe, 0xb0, 0x69, + 0xd8, 0xc8, 0x97, 0x69, 0x24, 0x3f, 0x8a, 0xee, + 0x78, 0x40, 0x0b, 0x6d, 0x47, 0x2d, 0x0e, 0xeb, + 0x1b, 0x68, 0x6e, 0x0f, 0x1b, 0x05, 0xf6, 0x92, + 0xfe, 0x12, 0x77, 0x00, 0x1f, 0x48, 0x9b, 0x4d, + 0x41, 0x91, 0xe6, 0x04, 0x35, 0x7e, 0xbf, 0x16, + 0x13, 0xae, 0x1a, 0x71, 0x52, 0xbb, 0x95, 0x7d, + 0x9e, 0xb3, 0xd1, 0x96, 0x3c, 0x8e, 0xbb, 0xd1, + 0xc4, 0x05, 0xf7, 0x0d, 0xf2, 0x8d, 0x93, 0x7d, + 0xc4, 0xbb, 0x2b, 0xf5, 0xd1, 0xf7, 0x99, 0x51, + 0x38, 0x9a, 0x77, 0xcf, 0x59, 0x1b, 0xa4, 0x47, + 0xa7, 0x4a, 0xf3, 0xbd, 0xa6, 0x59, 0x7f, 0xff, + 0x83, 0x4c, 0x53, 0x25, 0x7f, 0x2a, 0x5a, 0x97, + 0xfa, 0x05, 0x6d, 0x40, 0xac, 0xba, 0xb4, 0x31, + 0xeb, 0x99, 0xc4, 0x28, 0x36, 0x6a, 0xd4, 0x2c, + 0x66, 0x43, 0x02, 0x09, 0xfd, 0x72, 0xe1, 0x23, + 0x18, 0xa8, 0xc4, 0x5c, 0xf6, 0x2f, 0xbe, 0xf3, + 0x5a, 0x7e, 0xf3, 0x98, 0x2f, 0x37, 0x39, 0x06, + 0x9a, 0x07, 0x44, 0x8a, 0xc3, 0x6f, 0x11, 0xb4, + 0xb2, 0xe8, 0x07, 0xd2, 0x03, 0x1a, 0x6c, 0x40, + 0xcb, 0x0b, 0xeb, 0xe8, 0x8b, 0x92, 0x44, 0xbf, + 0x99, 0xcf, 0x36, 0x65, 0xdf, 0x41, 0x09, 0x4e, + 0x9d, 0x2d, 0xd1, 0xef, 0x5f, 0xd9, 0xe1, 0xf6, + 0xc7, 0x27, 0xb7, 0x56, 0x53, 0x99, 0x0b, 0x7d, + 0xa9, 0xa4, 0xcf, 0x2b, 0x45, 0x7e, 0x7b, 0x4d, + 0x12, 0x9d, 0xd9, 0x7c, 0xdc, 0x4c, 0x79, 0x80, + 0x3b, 0xb2, 0x18, 0x14, 0x83, 0xe6, 0xbe, 0x74, + 0xa6, 0xb4, 0x5a, 0x63, 0x18, 0x52, 0x22, 0x1f, + 0xe1, 0xd1, 0xf9, 0x73, 0x3d, 0x5f, 0x7c, 0xe7, + 0xa5, 0xec, 0xf4, 0x8d, 0xba, 0x9d, 0x8c, 0x97, + 0x7d, 0x34, 0x57, 0x15, 0xff, 0xaa, 0x81, 0xcb, + 0xd7, 0xc5, 0x75, 0x3b, 0x6b, 0x34, 0x70, 0xbd, + 0xce, 0xb8, 0x2b, 0xe9, 0xc4, 0x97, 0x45, 0xcf, + 0xcb, 0x21, 0xe8, 0x79, 0x5c, 0xbf, 0x95, 0x56, + 0x21, 0x35, 0xeb, 0x20, 0x25, 0x76, 0xf5, 0xd3, + 0x3b, 0x2c, 0x81, 0x57, 0xec, 0xc1, 0x5f, 0xe5, + 0x49, 0x5f, 0x2c, 0x79, 0x14, 0x9f, 0xb8, 0x01, + 0x38, 0x9f, 0xbd, 0xa8, 0x30, 0x28, 0xcc, 0x7d, + 0xde, 0x50, 0x3f, 0x1a, 0x18, 0x0a, 0x78, 0xc5, + 0x92, 0xc1, 0x1e, 0xd4, 0x4b, 0xb9, 0x2d, 0x00, + 0x82, 0x4c, 0x86, 0x86, 0xea, 0x6e, 0xb9, 0x32, + 0x61, 0xed, 0x9a, 0x70, 0x65, 0x1f, 0xd7, 0xb4, + 0x5a, 0x59, 0xbc, 0x7f, 0x76, 0x60, 0xc2, 0xbd, + 0x20, 0xcd, 0x14, 0x24, 0xa7, 0x50, 0x2d, 0xec, + 0x07, 0xea, 0x67, 0xc2, 0x1c, 0xc8, 0xba, 0x80, + 0x85, 0xd9, 0x19, 0x3d, 0xdc, 0x92, 0x5d, 0x57, + 0x91, 0xfc, 0xd5, 0xb4, 0x40, 0x86, 0x59, 0xbb, + 0x83, 0x91, 0x1f, 0x07, 0xc1, 0xb2, 0x8d, 0xb8, + 0x88, 0xb7, 0xca, 0x7c, 0xc3, 0xd4, 0xf7, 0x1f, + 0xe8, 0xbd, 0x45, 0xca, 0x5b, 0xd0, 0x4c, 0x73, + 0x99, 0x56, 0x6e, 0x61, 0x83, 0x8b, 0x1b, 0xa1, + 0x8e, 0x58, 0xc2, 0x84, 0x55, 0xcf, 0x67, 0xdc, + 0x4b, 0x64, 0xe2, 0x6e, 0x42, 0xcd, 0x7a, 0x28, + 0xf4, 0x69, 0xba, 0xb3, 0xfb, 0xab, 0xa4, 0x08, + 0x1a, 0x81, 0x72, 0x0f, 0xed, 0x98, 0x69, 0x6c, + 0x7b, 0xd8, 0x8d, 0x64, 0x5a, 0x4b, 0x01, 0xc2, + 0x76, 0x0e, 0xcf, 0xfd, 0xe2, 0x6c, 0xcf, 0x13, + 0xb6, 0x30, 0x5f, 0x92, 0xfc, 0xff, 0xcb, 0x4f, + 0xb9, 0x22, 0xec, 0x9f, 0xfc, 0x83, 0xf3, 0xb3, + 0xe4, 0x6d, 0x16, 0x14, 0xb3, 0x03, 0x72, 0x4e, + 0x71, 0x13, 0x75, 0x34, 0xa5, 0x55, 0x48, 0x44, + 0xe5, 0x45, 0xc5, 0x59, 0x09, 0x94, 0x66, 0x19, + 0xe9, 0x1a, 0xbc, 0xbe, 0x0a, 0x26, 0x39, 0x29, + 0x71, 0xb1, 0xed, 0x92, 0x67, 0x2a, 0xc4, 0x2a, + 0x1d, 0x85, 0xe6, 0xe5, 0x52, 0x8d, 0xb6, 0xad, + 0x40, 0xc3, 0x51, 0x8c, 0xf1, 0x4c, 0xe0, 0xe1, + 0x98, 0x52, 0x91, 0xea, 0x2c, 0xd4, 0xf4, 0x2b, + 0x19, 0x78, 0x6e, 0x92, 0x5b, 0xc3, 0x1d, 0x65, + 0x46, 0xc6, 0xf0, 0x8f, 0xc4, 0x82, 0xfe, 0xbc, + 0x8d, 0x9a, 0x90, 0x33, 0xaf, 0x33, 0xfb, 0xc0, + 0xa4, 0x3f, 0x2b, 0x77, 0x66, 0xc4, 0x52, 0x36, + 0x58, 0x18, 0x46, 0xac, 0x4f, 0xdd, 0x06, 0x93, + 0x23, 0x99, 0xde, 0x6d, 0x1c, 0xa7, 0x85, 0xb0, + 0xe8, 0x0f, 0x23, 0xc6, 0x42, 0x0d, 0xab, 0xa2, + 0x75, 0x57, 0xef, 0xc2, 0x97, 0x22, 0x3c, 0x7d, + 0x15, 0x45, 0x0c, 0x4a, 0xe9, 0x67, 0x2a, 0xa3, + 0x5a, 0x83, 0x09, 0xa8, 0x75, 0xc0, 0x96, 0x14, + 0x77, 0xa6, 0x3d, 0x5f, 0xac, 0x64, 0xd7, 0x01, + 0x85, 0xc1, 0x4f, 0x0d, 0x84, 0xab, 0x3d, 0xe3, + 0x37, 0x8a, 0x34, 0xd6, 0x4b, 0xde, 0x5f, 0xdd, + 0xd8, 0xc0, 0xb7, 0xcd, 0x91, 0xff, 0x87, 0x9a, + 0xf3, 0xe6, 0x71, 0x43, 0x53, 0x75, 0xd5, 0x1c, + 0xd1, 0x79, 0x19, 0xd7, 0x97, 0x06, 0xd2, 0x9b, + 0xe4, 0xd6, 0x19, 0x7e, 0x54, 0x2b, 0x94, 0x28, + 0x68, 0xa0, 0x2a, 0x67, 0x23, 0xb3, 0x31, 0x34, + 0x7d, 0xdc, 0xb9, 0xe5, 0x48, 0x17, 0x0e, 0xe0, + 0x0f, 0x4b, 0x90, 0xa1, 0x83, 0x7f, 0xa7, 0x3c, + 0x03, 0xf7, 0x82, 0x2a, 0xcc, 0x8f, 0x64, 0xd5, + 0xe5, 0xf9, 0x64, 0xe9, 0x9e, 0x09, 0xe2, 0xda, + 0x74, 0x71, 0xaf, 0x4b, 0x8a, 0xc3, 0x0c, 0x41, + 0x29, 0xfe, 0x48, 0xa2, 0x8e, 0x2f, 0xb5, 0xfe, + 0x84, 0x54, 0x2f, 0x4c, 0x23, 0xaa, 0x64, 0xaf, + 0x34, 0x29, 0x87, 0xcd, 0x1e, 0x4c, 0xbc, 0x22, + 0x1f, 0x83, 0xc1, 0x11, 0xdf, 0x1a, 0x38, 0xbc, + 0x44, 0x4d, 0x4f, 0x47, 0xcb, 0x5f, 0x6d, 0x11, + 0x31, 0xe7, 0x2b, 0xc8, 0x63, 0xc7, 0xc0, 0xe8, + 0xee, 0x4d, 0x9d, 0x0e, 0x5c, 0x8a, 0xc1, 0xb0, + 0x5a, 0xa6, 0x3b, 0x79, 0x52, 0x5a, 0xf1, 0xa9, + 0x16, 0x7b, 0x6a, 0x79, 0x7e, 0x4d, 0x9a, 0x82, + 0x2a, 0x24, 0x4d, 0x57, 0xa0, 0x70, 0x10, 0x01, + 0x62, 0xf0, 0x89, 0xcf, 0xce, 0xba, 0xed, 0x1c, + 0x1a, 0x2b, 0xec, 0xb1, 0x6c, 0xeb, 0xe2, 0x29, + 0x5f, 0x57, 0x92, 0x88, 0x80, 0xc3, 0x5a, 0x5c, + 0x44, 0x3b, 0x5e, 0x39, 0x2d, 0x2c, 0xe5, 0x1e, + 0xd4, 0xbb, 0xe7, 0xb9, 0x43, 0x8b, 0x98, 0xb5, + 0x86, 0x2d, 0x20, 0xc7, 0x70, 0x0e, 0x82, 0xcd, + 0x92, 0x8e, 0x04, 0x0e, 0x9f, 0x80, 0xec, 0x7a, + 0xcf, 0x2f, 0xcb, 0x3e, 0x44, 0x46, 0x79, 0x30, + 0x9b, 0x8a, 0x1e, 0x0e, 0x4a, 0x63, 0xd8, 0x0d, + 0xcc, 0x93, 0xed, 0x3e, 0x52, 0xde, 0x4c, 0x05, + 0x40, 0xe5, 0x08, 0xf0, 0x9c, 0xa4, 0x9c, 0xd2, + 0xfa, 0xea, 0xef, 0x36, 0xf5, 0x20, 0xf3, 0x5d, + 0x77, 0x07, 0x88, 0xf8, 0x9b, 0x46, 0x30, 0x33, + 0x5e, 0xa4, 0xa7, 0x0a, 0xcc, 0x97, 0x87, 0x47, + 0xb1, 0x91, 0x96, 0x93, 0x28, 0xdf, 0xa4, 0x50, + 0xc6, 0x90, 0x11, 0x10, 0x73, 0xad, 0x3f, 0xa9, + 0x9a, 0xfb, 0xda, 0x87, 0x72, 0x01, 0x76, 0x37, + 0xcd, 0xf0, 0x41, 0x0a, 0xf7, 0x63, 0x12, 0x72, + 0x38, 0xf0, 0xf7, 0x22, 0x1a, 0x1a, 0x1d, 0x0c, + 0x26, 0x67, 0x4c, 0x46, 0xd3, 0xc1, 0x55, 0x6c, + 0xc0, 0x1e, 0x32, 0x7b, 0xbe, 0xef, 0xcf, 0xdb, + 0xae, 0x72, 0x9c, 0xe5, 0x5c, 0xed, 0xe7, 0x8e, + 0x6a, 0x3c, 0x0c, 0x75, 0x00, 0x27, 0xf2, 0x8b, + 0xd6, 0xe6, 0x5f, 0x66, 0xfc, 0x3a, 0xa9, 0xae, + 0x93, 0xb8, 0xb9, 0x49, 0x3e, 0x08, 0x81, 0x83, + 0x09, 0xfd, 0x35, 0x03, 0xcf, 0x42, 0x5d, 0xd4, + 0xc1, 0xfc, 0xda, 0x85, 0xaf, 0xcb, 0x24, 0x6f, + 0x5d, 0x50, 0x4e, 0xb7, 0xa6, 0x60, 0xf5, 0xa2, + 0xd7, 0xac, 0xbb, 0x88, 0xeb, 0xfc, 0x60, 0x42, + 0x32, 0x37, 0xbe, 0xad, 0x4d, 0x33, 0x0f, 0xb5, + 0x43, 0x0c, 0x9f, 0xfc, 0x10, 0x8a, 0x39, 0xb3, + 0x36, 0x04, 0x65, 0x52, 0x91, 0xb7, 0x5b, 0xe5, + 0x71, 0xf2, 0x07, 0xf9, 0x1d, 0x3c, 0xf3, 0x16, + 0x4f, 0x20, 0x24, 0x12, 0xc6, 0xd6, 0xf4, 0x64, + 0x2d, 0x72, 0x74, 0xc9, 0x35, 0x36, 0x67, 0x62, + 0xa4, 0xe6, 0x80, 0x60, 0xa4, 0x95, 0x29, 0x99, + 0xb5, 0xd6, 0xdd, 0x98, 0xe8, 0xaf, 0xaa, 0x35, + 0x8d, 0x11, 0xfa, 0xc3, 0x64, 0x32, 0xd7, 0xc0, + 0xa6, 0x9d, 0x7c, 0xbf, 0xd7, 0x75, 0x65, 0x46, + 0x20, 0xf8, 0x67, 0x34, 0x03, 0x9f, 0xaf, 0xba, + 0x00, 0xfe, 0x1f, 0x59, 0x1b, 0x6c, 0xef, 0x7f, + 0x54, 0x56, 0xa0, 0x27, 0x2b, 0x1b, 0xf6, 0x6d, + 0x7f, 0x26, 0x2b, 0x85, 0xb4, 0x90, 0x92, 0x42, + 0x20, 0x11, 0x85, 0x79, 0x1c, 0x56, 0x23, 0xc7, + 0x8c, 0x06, 0xac, 0x8e, 0xad, 0x8b, 0x92, 0x0d, + 0xcb, 0x6c, 0x76, 0x77, 0x05, 0x9d, 0x7e, 0x0d, + 0x40, 0x37, 0x28, 0xee, 0x17, 0xfb, 0xcd, 0xbe, + 0x3d, 0x9a, 0x5f, 0x8c, 0x54, 0xcf, 0x0c, 0x03, + 0xd0, 0x46, 0xa5, 0x4c, 0x80, 0xf6, 0x7d, 0x0e, + 0x14, 0xf7, 0x39, 0xa2, 0xdf, 0x0e, 0xe2, 0xdf, + 0x6d, 0x51, 0x3c, 0x44, 0x41, 0xd3, 0x7b, 0x87, + 0xc6, 0xe8, 0x67, 0x14, 0xfa, 0xb3, 0x78, 0x66, + 0x69, 0x94, 0xae, 0xb3, 0xba, 0xe7, 0x19, 0x59, + 0x7f, 0x90, 0xc1, 0xf0, 0x01, 0x04, 0x7e, 0x8a, + 0xc9, 0xd1, 0x03, 0x17, 0x22, 0x39, 0x49, 0x56, + 0x82, 0x9a, 0xa3, 0xad, 0xda, 0xdf, 0xea, 0x76, + 0x77, 0x91, 0x9a, 0xf1, 0xff, 0x06, 0x17, 0x36, + 0x57, 0x5f, 0x6c, 0x71, 0x73, 0x88, 0xb9, 0xdd, + 0x09, 0x33, 0x37, 0x4e, 0x5e, 0x60, 0xa3, 0xa8, + 0xab, 0xee, 0xef, 0x0d, 0xd6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x12, 0x1f, 0x25, + 0x30, 0x3b, 0x3d + }; + + return linuxkm_test_mldsa_driver(WOLFKM_MLDSA87_DRIVER, + mldsa87_pub, + (word32)sizeof(mldsa87_pub), + mldsa87_seed, + (word32)sizeof(mldsa87_seed), +#ifdef LINUXKM_MLDSA_SIGN + 1, +#else + 0, +#endif + mldsa87_sig, + (word32)sizeof(mldsa87_sig), + linuxkm_mldsa_test_msg, + (word32)sizeof(linuxkm_mldsa_test_msg)); +} +#endif /* LINUXKM_MLDSA87 */ + +#endif /* LINUXKM_LKCAPI_REGISTER_MLDSA */ + +#endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/linuxkm/lkcapi_mlkem_glue.c b/linuxkm/lkcapi_mlkem_glue.c new file mode 100644 index 0000000000..33a4addd73 --- /dev/null +++ b/linuxkm/lkcapi_mlkem_glue.c @@ -0,0 +1,1226 @@ +/* lkcapi_mlkem_glue.c -- glue logic to register ML-KEM (FIPS 203) wolfCrypt + * implementations with the Linux Kernel Cryptosystem, as kpp + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* included by linuxkm/lkcapi_glue.c */ +#ifndef WC_SKIP_INCLUDED_C_FILES + +#ifndef LINUXKM_LKCAPI_REGISTER + #error lkcapi_mlkem_glue.c included in non-LINUXKM_LKCAPI_REGISTER project. +#endif + +/* EXPERIMENTAL: full ML-KEM (FIPS 203) glue -- decapsulation AND + * encapsulation -- registered as struct kpp_alg. + * + * The kernel has no KEM algorithm type (and no in-tree ML-KEM); kpp + * models symmetric key agreement (DH/ECDH), in which every operation is + * one-input/one-output and deterministic given set_secret state, and + * every in-tree kpp implementation keeps its tfm ctx read-only during + * request operations. ML-KEM encapsulation is a randomized + * one-input/TWO-output operation (ek -> ciphertext + shared secret, + * with the secret bound to fresh internal randomness), so it cannot be + * expressed as a single read-only kpp op. + * + * It CAN, however, be expressed as two, using the strategy of + * lkcapi_sha_glue.c's SHA-3/HMAC state-overflow machinery (a lock and + * list_heads in the persistent transform context, dynamically + * allocated per-operation state nodes, and garbage collection of + * abandoned nodes at .exit) -- with the association handle adapted to + * kpp's handleless request model: the pairing key is the ciphertext + * itself, which the caller necessarily round-trips. + * + * Roles. A tfm takes its role from set_secret(): + * - DECAPSULATION (responder): set_secret is the raw FIPS 203 dk + * (exact size for the set), the 64-byte d||z keygen seed, or + * NULL/empty to generate a fresh key (the empty-secret-keygen + * convention follows ecdh_set_secret()). generate_public_key + * emits the raw encapsulation key ek. compute_shared_secret takes + * the peer's ciphertext as src and emits ss by decapsulation. + * - ENCAPSULATION (initiator): set_secret is the peer's raw ek + * (exact size for the set; all four accepted set_secret lengths + * are pairwise distinct for every parameter set, so the length + * dictates the role unambiguously). Note this means that the + * peer's public ek appears where the local private key appears + * in a DH/ECDH KEM exchange. The inversion is intentional so the + * subsequent generate_public_key / compute_shared_secret ops + * retain the same "emit what you transmit / combine peer material + * -> ss" shape. + * generate_public_key runs a + * fresh encapsulation: the ciphertext is written to req->dst (the + * op's output is "your transmissible public contribution", which + * for an encapsulator IS the ciphertext), and a pending node + * {SHA-256(ct), ss} is parked on a lock-guarded list in the tfm + * ctx. compute_shared_secret takes that ciphertext as src, looks + * up the pending node by ciphertext digest, and CLAIMS it: the + * shared secret is emitted and the node destroyed (one-shot; a + * second claim of the same ciphertext fails -ENOKEY). + * Note the symmetry: in both roles, generate_public_key emits the + * value you transmit to the peer, and compute_shared_secret combines + * the peer-associated ciphertext with local secret state to yield ss + * -- the same shape those ops have in DH. + * + * Bookkeeping (per the lkcapi_sha_glue.c HMAC export-list design): + * - the pending list is BOUNDED (WC_LINUXKM_MLKEM_PENDING_MAX, + * default 16): at capacity, the oldest unclaimed node is evicted, + * and a later claim of its ciphertext degrades to a graceful + * -ENOKEY, never corruption. Encapsulations should be claimed + * promptly. + * - claim lookup and shared-secret copyout happen under a single + * lock hold; eviction unlinks under the lock and frees outside it + * -- so a concurrent evictor and claimant cannot race a node into + * use-after-free. + * - nodes hold live shared secrets: every teardown path (claim, + * eviction, role switch, .exit reaper) ForceZero()s the node. + * - any set_secret() resets the role and reaps all pending nodes. + * + * Association-by-digest has no ABA hazard: ciphertexts from fresh + * encapsulation randomness are unique with overwhelming probability, + * and nodes are destroyed on claim. + * + * Per FIPS 203 implicit rejection, decapsulation of any + * correctly-sized ciphertext SUCCEEDS; an invalid ciphertext yields a + * pseudorandom shared secret rather than an error. Only malformed + * lengths fail. (This applies to the decapsulation role; + * encapsulation-role claims of unknown ciphertexts fail -ENOKEY.) + * + * Because the mlkem* cra_names are unknown to crypto/testmgr.c, + * alg_test() takes its "notest" path and returns success at + * registration time, with or without fips_enabled. Self-tests are + * supplied by the linuxkm_test_mlkem*() functions below (zero KAT + * rodata: vectors are generated at test time from a fixed keygen + * seed); algorithm-correctness KATs live in wolfcrypt/test/test.c + * and, in full FIPS embodiment, in wolfcrypt/src/fips_test.c. + */ + +#if defined(WOLFSSL_HAVE_MLKEM) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_MLKEM) && \ + !defined(LINUXKM_LKCAPI_REGISTER_MLKEM) + #define LINUXKM_LKCAPI_REGISTER_MLKEM + #endif +#else + #undef LINUXKM_LKCAPI_REGISTER_MLKEM +#endif + +#ifdef LINUXKM_LKCAPI_REGISTER_MLKEM + +#include +#include + +#ifdef NO_SHA256 + #error lkcapi_mlkem_glue.c encapsulation support requires SHA-256 \ +for pending-node association. +#endif + +#ifdef WOLFSSL_WC_ML_KEM_512 + #define LINUXKM_MLKEM512 +#endif +#ifdef WOLFSSL_WC_ML_KEM_768 + #define LINUXKM_MLKEM768 +#endif +#ifdef WOLFSSL_WC_ML_KEM_1024 + #define LINUXKM_MLKEM1024 +#endif + +#if defined(USE_INTEL_SPEEDUP) + #ifdef WOLFSSL_MLKEM_HAVE_INTEL_AVX512 + #define WOLFKM_MLKEM_DRIVER_ISA_EXT "-avx512" + #else + #define WOLFKM_MLKEM_DRIVER_ISA_EXT "-avx2" + #endif +#else + #define WOLFKM_MLKEM_DRIVER_ISA_EXT "" +#endif + +#define WOLFKM_MLKEM_DRIVER_SUFFIX \ + WOLFKM_MLKEM_DRIVER_ISA_EXT WOLFKM_DRIVER_SUFFIX_BASE + +/* max_size() reports the encapsulation key size for both roles, which + * is correct only because ct <= ek for every ML-KEM parameter set. + * Check that assumption. */ +#ifdef WOLFSSL_WC_ML_KEM_512 +wc_static_assert(WC_ML_KEM_512_CIPHER_TEXT_SIZE <= + WC_ML_KEM_512_PUBLIC_KEY_SIZE); +#endif +#ifdef WOLFSSL_WC_ML_KEM_768 +wc_static_assert(WC_ML_KEM_768_CIPHER_TEXT_SIZE <= + WC_ML_KEM_768_PUBLIC_KEY_SIZE); +#endif +#ifdef WOLFSSL_WC_ML_KEM_1024 +wc_static_assert(WC_ML_KEM_1024_CIPHER_TEXT_SIZE <= + WC_ML_KEM_1024_PUBLIC_KEY_SIZE); +#endif + +/* Bound on unclaimed encapsulations per tfm; oldest evicted at + * capacity. */ +#ifdef WC_LINUXKM_MLKEM_PENDING_MAX + wc_static_assert_if_const(WC_LINUXKM_MLKEM_PENDING_MAX > 0); +#else + #define WC_LINUXKM_MLKEM_PENDING_MAX 16 +#endif + +/* The kernel list macros provoke "pointer of type `void *' used in arithmetic", + * and on older kernels, "nested extern declaration of + * `__compiletime_assert_foo'". + */ +PRAGMA_DIAG_PUSH +PRAGMA("GCC diagnostic ignored \"-Wpointer-arith\""); +PRAGMA("GCC diagnostic ignored \"-Wnested-externs\""); + +#include + +/* An unclaimed encapsulation: SHA-256 of the emitted ciphertext, and + * the shared secret awaiting claim. */ +struct km_mlkem_pending_node { + struct list_head ent; + byte ct_digest[WC_SHA256_DIGEST_SIZE]; + byte ss[WC_ML_KEM_SS_SZ]; +}; + +/* struct MlKemKey embeds working state mutated during operations, so, + * as with slh-dsa (see lkcapi_slhdsa_glue.c), the tfm ctx stores only + * raw key octets and each operation runs on a transient + * heap-allocated MlKemKey. The pending list and its lock are the one + * deliberate exception to read-only-ctx-during-ops -- see the header + * comment. */ +struct km_mlkem_ctx { + int type; /* WC_ML_KEM_512 / _768 / _1024 */ + int dk_set; /* decapsulation role */ + int ek_set; /* encapsulation role */ + byte dk[WC_ML_KEM_MAX_PRIVATE_KEY_SIZE]; + byte ek[WC_ML_KEM_MAX_PUBLIC_KEY_SIZE]; + wolfSSL_Mutex pending_lock; + struct list_head pending_list; + unsigned int pending_count; +}; + +static MlKemKey * km_mlkem_new_wc_key(int type) +{ + MlKemKey *key = (MlKemKey *)malloc(sizeof(MlKemKey)); + if (key) { + if (wc_MlKemKey_Init(key, type, NULL /* heap */, + INVALID_DEVID) != 0) + { + free(key); + key = NULL; + } + } + return key; +} + +static void km_mlkem_del_wc_key(MlKemKey *key) +{ + if (key) { + wc_MlKemKey_Free(key); + ForceZero(key, sizeof(MlKemKey)); + free(key); + } +} + +/* Reap every pending node. Caller must not hold pending_lock. */ +static void km_mlkem_reap_pending(struct km_mlkem_ctx *ctx) +{ + struct list_head reaped; + struct km_mlkem_pending_node *node, *tmp; + + INIT_LIST_HEAD(&reaped); + + if (wc_LockMutex(&ctx->pending_lock) == 0) { + list_for_each_entry_safe(node, tmp, &ctx->pending_list, ent) { + list_del(&node->ent); + list_add(&node->ent, &reaped); + } + ctx->pending_count = 0; + wc_UnLockMutex(&ctx->pending_lock); + } + + list_for_each_entry_safe(node, tmp, &reaped, ent) { + list_del(&node->ent); + ForceZero(node, sizeof(*node)); + free(node); + } +} + +static int km_mlkem_init_common(struct crypto_kpp *tfm, int type) +{ + struct km_mlkem_ctx *ctx = kpp_tfm_ctx(tfm); + + XMEMSET(ctx, 0, sizeof(struct km_mlkem_ctx)); + ctx->type = type; + if (wc_InitMutex(&ctx->pending_lock) != 0) + return -ENOMEM; + INIT_LIST_HEAD(&ctx->pending_list); + + #ifdef WOLFKM_DEBUG_MLKEM + pr_info("info: exiting km_mlkem_init_common (type %d)\n", type); + #endif /* WOLFKM_DEBUG_MLKEM */ + return 0; +} + +static void km_mlkem_exit(struct crypto_kpp *tfm) +{ + struct km_mlkem_ctx *ctx = kpp_tfm_ctx(tfm); + + km_mlkem_reap_pending(ctx); + wc_FreeMutex(&ctx->pending_lock); + ForceZero(ctx, sizeof(struct km_mlkem_ctx)); + + #ifdef WOLFKM_DEBUG_MLKEM + pr_info("info: exiting km_mlkem_exit\n"); + #endif /* WOLFKM_DEBUG_MLKEM */ + return; +} + +/* + * Sets the key, and thereby the role -- see the header comment. + * + * tfm The crypto_kpp transform + * buffer The raw FIPS 203 dk, the 64-byte d||z keygen seed, or + * NULL/empty to generate a fresh key (all: decapsulation + * role); or the peer's raw ek (encapsulation role). The + * four lengths are pairwise distinct for every set. + * len Buffer length + */ +static int km_mlkem_set_secret(struct crypto_kpp *tfm, const void *buffer, + unsigned int len) +{ + struct km_mlkem_ctx * ctx = kpp_tfm_ctx(tfm); + MlKemKey * wc_key = NULL; + word32 dk_len = 0; + word32 ek_len = 0; + int err; + + /* Any (re)key resets the role and reaps pending encapsulations. */ + if (ctx->dk_set) { + ForceZero(ctx->dk, sizeof ctx->dk); + ctx->dk_set = 0; + } + if (ctx->ek_set) { + XMEMSET(ctx->ek, 0, sizeof ctx->ek); + ctx->ek_set = 0; + } + km_mlkem_reap_pending(ctx); + + wc_key = km_mlkem_new_wc_key(ctx->type); + if (! wc_key) + return -ENOMEM; + + err = wc_MlKemKey_PrivateKeySize(wc_key, &dk_len); + if (err == 0) + err = wc_MlKemKey_PublicKeySize(wc_key, &ek_len); + if (err != 0) { + km_mlkem_del_wc_key(wc_key); + return -EINVAL; + } + + if ((buffer == NULL) || (len == 0)) { + /* Decapsulation role: generate a fresh key. */ + WC_RNG rng; + err = LKCAPI_INITRNG(&rng); + if (err == 0) { + err = wc_MlKemKey_MakeKey(wc_key, &rng); + wc_FreeRng(&rng); + } + else { + err = -ENODEV; + goto out; + } + if (err == 0) { + PRIVATE_KEY_UNLOCK(); + err = wc_MlKemKey_EncodePrivateKey(wc_key, ctx->dk, dk_len); + PRIVATE_KEY_LOCK(); + } + if (err == 0) + ctx->dk_set = 1; + } + else if (len == (unsigned int)WC_ML_KEM_MAKEKEY_RAND_SZ) { + /* Decapsulation role: deterministic keygen from the d||z seed. */ + err = wc_MlKemKey_MakeKeyWithRandom(wc_key, (const byte *)buffer, + (int)len); + if (err == 0) { + PRIVATE_KEY_UNLOCK(); + err = wc_MlKemKey_EncodePrivateKey(wc_key, ctx->dk, dk_len); + PRIVATE_KEY_LOCK(); + } + if (err == 0) + ctx->dk_set = 1; + } + else if (len == (unsigned int)dk_len) { + /* Decapsulation role: import dk. */ + err = wc_MlKemKey_DecodePrivateKey(wc_key, (const byte *)buffer, + len); + if (err == 0) { + PRIVATE_KEY_UNLOCK(); + err = wc_MlKemKey_EncodePrivateKey(wc_key, ctx->dk, dk_len); + PRIVATE_KEY_LOCK(); + } + if (err == 0) + ctx->dk_set = 1; + } + else if (len == (unsigned int)ek_len) { + /* Encapsulation role: import the peer's ek (validated by decode). */ + err = wc_MlKemKey_DecodePublicKey(wc_key, (const byte *)buffer, + len); + if (err == 0) { + XMEMCPY(ctx->ek, buffer, ek_len); + ctx->ek_set = 1; + } + } + else { + err = BAD_FUNC_ARG; + } + +out: + km_mlkem_del_wc_key(wc_key); + + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_MLKEM + pr_err("error: km_mlkem_set_secret (len %u): %d\n", len, err); + #endif + return (err < -1000 || err > 0) ? err : -EINVAL; + } + + #ifdef WOLFKM_DEBUG_MLKEM + pr_info("info: exiting km_mlkem_set_secret %u (role %s)\n", len, + ctx->ek_set ? "encap" : "decap"); + #endif + return 0; +} + +/* The largest kpp output for this tfm. ek for the decapsulation role; + * ct for the encapsulation role -- but ct <= ek for every parameter + * set (statically asserted above), so ek covers both. + */ +static unsigned int km_mlkem_max_size(struct crypto_kpp *tfm) +{ + struct km_mlkem_ctx * ctx = kpp_tfm_ctx(tfm); + MlKemKey * wc_key; + word32 len = 0; + + wc_key = km_mlkem_new_wc_key(ctx->type); + if (! wc_key) + return 0; + if (wc_MlKemKey_PublicKeySize(wc_key, &len) != 0) + len = 0; + km_mlkem_del_wc_key(wc_key); + return len; +} + +/* Decapsulation role: emit the raw FIPS 203 ek to req->dst. */ +static int km_mlkem_generate_ek(struct km_mlkem_ctx *ctx, + struct kpp_request *req) +{ + MlKemKey * wc_key = NULL; + byte * ek = NULL; + word32 ek_len = 0; + word32 dk_len = 0; + int err; + + wc_key = km_mlkem_new_wc_key(ctx->type); + if (! wc_key) + return -ENOMEM; + + err = wc_MlKemKey_PublicKeySize(wc_key, &ek_len); + if (err == 0) + err = wc_MlKemKey_PrivateKeySize(wc_key, &dk_len); + if (err != 0) { + km_mlkem_del_wc_key(wc_key); + return -EINVAL; + } + + if (req->dst_len < ek_len) { + km_mlkem_del_wc_key(wc_key); + return -EOVERFLOW; + } + + ek = (byte *)malloc(ek_len); + if (! ek) { + km_mlkem_del_wc_key(wc_key); + return -ENOMEM; + } + + /* The FIPS 203 dk contains ek; DecodePrivateKey recovers it. */ + err = wc_MlKemKey_DecodePrivateKey(wc_key, ctx->dk, dk_len); + if (err == 0) + err = wc_MlKemKey_EncodePublicKey(wc_key, ek, ek_len); + + if (err == 0) { + scatterwalk_map_and_copy(ek, req->dst, 0, ek_len, 1); + req->dst_len = ek_len; + } + + free(ek); + km_mlkem_del_wc_key(wc_key); + return err ? -EINVAL : 0; +} + +/* Encapsulation role: run a fresh encapsulation against the installed + * peer ek. The ciphertext goes to req->dst; the shared secret is + * parked on the pending list, keyed by SHA-256(ct), awaiting claim by + * compute_shared_secret. + */ +static int km_mlkem_generate_ct(struct km_mlkem_ctx *ctx, + struct kpp_request *req) +{ + MlKemKey * wc_key = NULL; + struct km_mlkem_pending_node * node = NULL; + struct km_mlkem_pending_node * evicted = NULL; + byte * ct = NULL; + word32 ct_len = 0; + word32 ek_len = 0; + int err; + + wc_key = km_mlkem_new_wc_key(ctx->type); + if (! wc_key) + return -ENOMEM; + + err = wc_MlKemKey_CipherTextSize(wc_key, &ct_len); + if (err == 0) + err = wc_MlKemKey_PublicKeySize(wc_key, &ek_len); + if (err != 0) { + km_mlkem_del_wc_key(wc_key); + return -EINVAL; + } + + if (req->dst_len < ct_len) { + km_mlkem_del_wc_key(wc_key); + return -EOVERFLOW; + } + + ct = (byte *)malloc(ct_len); + node = (struct km_mlkem_pending_node *) + malloc(sizeof(struct km_mlkem_pending_node)); + if ((! ct) || (! node)) { + err = -ENOMEM; + goto out; + } + XMEMSET(node, 0, sizeof(*node)); + + err = wc_MlKemKey_DecodePublicKey(wc_key, ctx->ek, ek_len); + + if (err == 0) { + WC_RNG rng; + err = LKCAPI_INITRNG(&rng); + if (err == 0) { + err = wc_MlKemKey_Encapsulate(wc_key, ct, node->ss, &rng); + wc_FreeRng(&rng); + } + else { + err = -ENODEV; + goto out; + } + } + + if (err == 0) + err = wc_Sha256Hash(ct, ct_len, node->ct_digest); + + if (err != 0) + goto out; + + /* Publish the pending node; at capacity, evict the oldest + * (list_add prepends, so the oldest is the tail). Unlink under + * the lock, free outside it. + */ + if (wc_LockMutex(&ctx->pending_lock) != 0) { + err = -EINVAL; + goto out; + } + if (ctx->pending_count >= WC_LINUXKM_MLKEM_PENDING_MAX) { + evicted = list_last_entry(&ctx->pending_list, + struct km_mlkem_pending_node, ent); + list_del(&evicted->ent); + ctx->pending_count--; + } + list_add(&node->ent, &ctx->pending_list); + ctx->pending_count++; + wc_UnLockMutex(&ctx->pending_lock); + node = NULL; /* Owned by the list now. */ + + scatterwalk_map_and_copy(ct, req->dst, 0, ct_len, 1); + req->dst_len = ct_len; + +out: + if (evicted) { + ForceZero(evicted, sizeof(*evicted)); + free(evicted); + } + if (node) { + ForceZero(node, sizeof(*node)); + free(node); + } + if (ct) { + ForceZero(ct, ct_len); + free(ct); + } + km_mlkem_del_wc_key(wc_key); + return (err > 0) ? -EINVAL : err; +} + +static int km_mlkem_generate_public_key(struct kpp_request *req) +{ + struct crypto_kpp * tfm = crypto_kpp_reqtfm(req); + struct km_mlkem_ctx * ctx = kpp_tfm_ctx(tfm); + int err; + + if (req->dst == NULL) + return -EINVAL; + + if (ctx->dk_set) + err = km_mlkem_generate_ek(ctx, req); + else if (ctx->ek_set) + err = km_mlkem_generate_ct(ctx, req); + else + err = -EINVAL; + + #ifdef WOLFKM_DEBUG_MLKEM + pr_info("info: exiting km_mlkem_generate_public_key (role %s), " + "err %d\n", ctx->ek_set ? "encap" : "decap", err); + #endif + return err; +} + +/* Decapsulation role: req->src is the peer's ciphertext (exact size); + * ss to req->dst. Per FIPS 203 implicit rejection, any + * correctly-sized ciphertext decapsulates successfully. + */ +static int km_mlkem_ss_decap(struct km_mlkem_ctx *ctx, + struct kpp_request *req) +{ + MlKemKey * wc_key = NULL; + byte * work = NULL; + byte * ct; + byte * ss; + word32 ct_len = 0; + word32 ss_len = 0; + word32 dk_len = 0; + int err; + + wc_key = km_mlkem_new_wc_key(ctx->type); + if (! wc_key) + return -ENOMEM; + + err = wc_MlKemKey_CipherTextSize(wc_key, &ct_len); + if (err == 0) + err = wc_MlKemKey_SharedSecretSize(wc_key, &ss_len); + if (err == 0) + err = wc_MlKemKey_PrivateKeySize(wc_key, &dk_len); + if (err != 0) { + km_mlkem_del_wc_key(wc_key); + return -EINVAL; + } + + if (req->src_len != ct_len) { + km_mlkem_del_wc_key(wc_key); + return -EINVAL; + } + if (req->dst_len < ss_len) { + km_mlkem_del_wc_key(wc_key); + return -EOVERFLOW; + } + + work = (byte *)malloc(ct_len + ss_len); + if (! work) { + km_mlkem_del_wc_key(wc_key); + return -ENOMEM; + } + ct = work; + ss = work + ct_len; + + scatterwalk_map_and_copy(ct, req->src, 0, ct_len, 0); + + err = wc_MlKemKey_DecodePrivateKey(wc_key, ctx->dk, dk_len); + if (err == 0) { + PRIVATE_KEY_UNLOCK(); + err = wc_MlKemKey_Decapsulate(wc_key, ss, ct, ct_len); + PRIVATE_KEY_LOCK(); + } + + if (err == 0) { + scatterwalk_map_and_copy(ss, req->dst, 0, ss_len, 1); + req->dst_len = ss_len; + } + + ForceZero(work, ct_len + ss_len); + free(work); + km_mlkem_del_wc_key(wc_key); + return err ? -EINVAL : 0; +} + +/* Encapsulation role: claim the pending shared secret for the + * ciphertext in req->src. Lookup and secret copyout happen under one + * lock hold; the node is destroyed on claim (one-shot). Unknown + * (never-generated, already-claimed, or evicted) ciphertexts fail + * with -ENOKEY. + */ +static int km_mlkem_ss_claim(struct km_mlkem_ctx *ctx, + struct kpp_request *req) +{ + MlKemKey * wc_key = NULL; + struct km_mlkem_pending_node * node = NULL; + struct km_mlkem_pending_node * found = NULL; + byte * ct = NULL; + byte digest[WC_SHA256_DIGEST_SIZE]; + byte ss[WC_ML_KEM_SS_SZ]; + word32 ct_len = 0; + word32 ss_len = 0; + int err; + + wc_key = km_mlkem_new_wc_key(ctx->type); + if (! wc_key) + return -ENOMEM; + + err = wc_MlKemKey_CipherTextSize(wc_key, &ct_len); + if (err == 0) + err = wc_MlKemKey_SharedSecretSize(wc_key, &ss_len); + km_mlkem_del_wc_key(wc_key); + wc_key = NULL; + if ((err != 0) || (ss_len > (word32)sizeof(ss))) + return -EINVAL; + + if (req->src_len != ct_len) + return -EINVAL; + /* Check dst space BEFORE claiming, so a short dst doesn't consume + * the node. + */ + if (req->dst_len < ss_len) + return -EOVERFLOW; + + ct = (byte *)malloc(ct_len); + if (! ct) + return -ENOMEM; + + scatterwalk_map_and_copy(ct, req->src, 0, ct_len, 0); + + err = wc_Sha256Hash(ct, ct_len, digest); + free(ct); + ct = NULL; + if (err != 0) + return -EINVAL; + + if (wc_LockMutex(&ctx->pending_lock) != 0) + return -EINVAL; + list_for_each_entry(node, &ctx->pending_list, ent) { + if (XMEMCMP(node->ct_digest, digest, + WC_SHA256_DIGEST_SIZE) == 0) + { + found = node; + break; + } + } + if (found) { + XMEMCPY(ss, found->ss, ss_len); + list_del(&found->ent); + ctx->pending_count--; + } + wc_UnLockMutex(&ctx->pending_lock); + + if (! found) + return -ENOKEY; + + ForceZero(found, sizeof(*found)); + free(found); + + scatterwalk_map_and_copy(ss, req->dst, 0, ss_len, 1); + req->dst_len = ss_len; + ForceZero(ss, sizeof(ss)); + return 0; +} + +PRAGMA_DIAG_POP /* -Wno-pointer-arith -Wno-nested-externs, for linux/list.h */ + +static int km_mlkem_compute_shared_secret(struct kpp_request *req) +{ + struct crypto_kpp * tfm = crypto_kpp_reqtfm(req); + struct km_mlkem_ctx * ctx = kpp_tfm_ctx(tfm); + int err; + + if ((req->src == NULL) || (req->dst == NULL)) + return -EINVAL; + + if (ctx->dk_set) + err = km_mlkem_ss_decap(ctx, req); + else if (ctx->ek_set) + err = km_mlkem_ss_claim(ctx, req); + else + err = -EINVAL; + + #ifdef WOLFKM_DEBUG_MLKEM + pr_info("info: exiting km_mlkem_compute_shared_secret (role %s), " + "err %d\n", ctx->ek_set ? "encap" : "decap", err); + #endif + return err; +} + +#define KM_MLKEM_DEFINE_ALG(stem, cra_name_str, type_enum) \ + static int km_ ## stem ## _init(struct crypto_kpp *tfm) \ + { \ + return km_mlkem_init_common(tfm, (int)(type_enum)); \ + } \ + static int stem ## _loaded = 0; \ + static struct kpp_alg stem = { \ + .base.cra_name = (cra_name_str), \ + .base.cra_driver_name = cra_name_str WOLFKM_MLKEM_DRIVER_SUFFIX,\ + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, \ + .base.cra_module = THIS_MODULE, \ + .base.cra_ctxsize = sizeof(struct km_mlkem_ctx), \ + .set_secret = km_mlkem_set_secret, \ + .generate_public_key = km_mlkem_generate_public_key, \ + .compute_shared_secret = km_mlkem_compute_shared_secret, \ + .max_size = km_mlkem_max_size, \ + .init = km_ ## stem ## _init, \ + .exit = km_mlkem_exit, \ + } + +#ifdef LINUXKM_MLKEM512 +KM_MLKEM_DEFINE_ALG(mlkem512, "mlkem512", WC_ML_KEM_512); +static int linuxkm_test_mlkem512(void); +#endif +#ifdef LINUXKM_MLKEM768 +KM_MLKEM_DEFINE_ALG(mlkem768, "mlkem768", WC_ML_KEM_768); +static int linuxkm_test_mlkem768(void); +#endif +#ifdef LINUXKM_MLKEM1024 +KM_MLKEM_DEFINE_ALG(mlkem1024, "mlkem1024", WC_ML_KEM_1024); +static int linuxkm_test_mlkem1024(void); +#endif + +/* self-test, zero KAT rodata: a fixed d||z seed drives deterministic + * keygen both through the glue (decapsulation role) and in a local + * wolfCrypt key, so the two provably hold the same keypair; each side + * then encapsulates for the other: + * - decap direction: wolfCrypt encapsulates against the + * glue-exported ek; the glue decapsulates; secrets must match. + * - encap direction: the tfm is re-keyed with the ek (role switch), + * the glue encapsulates; wolfCrypt decapsulates the emitted + * ciphertext; the claimed and decapsulated secrets must match. + * plus negatives: length checks, one-shot claim, unknown-ct claim, + * pending-list eviction at capacity, and role-switch reaping. + */ +static int linuxkm_test_mlkem_driver(const char * driver, int type) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_kpp * tfm = NULL; + struct kpp_request * req = NULL; + MlKemKey * wc_key = NULL; + byte * work = NULL; + byte * ek; + byte * ct; + byte * ct_first; + byte * ss_a; + byte * ss_b; + word32 ek_len = 0; + word32 ct_len = 0; + word32 ss_len = 0; + struct scatterlist src_sg; + struct scatterlist dst_sg; + byte seed[WC_ML_KEM_MAKEKEY_RAND_SZ]; + word32 i; + + /* Fixed test seed for keygen. */ + for (i = 0; i < (word32)sizeof(seed); i++) + seed[i] = (byte)(0xa0U ^ i); + + wc_key = km_mlkem_new_wc_key(type); + if (! wc_key) { + test_rc = MEMORY_E; + goto test_mlkem_end; + } + if ((wc_MlKemKey_PublicKeySize(wc_key, &ek_len) != 0) || + (wc_MlKemKey_CipherTextSize(wc_key, &ct_len) != 0) || + (wc_MlKemKey_SharedSecretSize(wc_key, &ss_len) != 0)) + { + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* The local wolfCrypt keypair, from the same seed the glue will use. */ + ret = wc_MlKemKey_MakeKeyWithRandom(wc_key, seed, + (int)sizeof(seed)); + if (ret != 0) { + pr_err("error: wc_MlKemKey_MakeKeyWithRandom returned: %d\n", + ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + work = (byte *)malloc(ek_len + (2 * ct_len) + (2 * ss_len)); + if (! work) { + test_rc = MEMORY_E; + goto test_mlkem_end; + } + ek = work; + ct = work + ek_len; + ct_first = work + ek_len + ct_len; + ss_a = work + ek_len + (2 * ct_len); + ss_b = work + ek_len + (2 * ct_len) + ss_len; + + tfm = crypto_alloc_kpp(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating kpp algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_mlkem_end; + } + + req = kpp_request_alloc(tfm, GFP_KERNEL); + if (! req) { + test_rc = -ENOMEM; + pr_err("error: allocating kpp request %s failed\n", driver); + goto test_mlkem_end; + } + + /* ==== decapsulation role ==== */ + + ret = crypto_kpp_set_secret(tfm, seed, (unsigned int)sizeof(seed)); + if (ret) { + pr_err("error: crypto_kpp_set_secret (seed, %u) returned: %d\n", + (unsigned int)sizeof(seed), ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + { + unsigned int maxsize = crypto_kpp_maxsize(tfm); + if (maxsize != ek_len) { + pr_err("error: crypto_kpp_maxsize returned %u, expected " + "%u\n", maxsize, ek_len); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + } + + sg_init_one(&dst_sg, ek, ek_len); + kpp_request_set_output(req, &dst_sg, ek_len); + ret = crypto_kpp_generate_public_key(req); + if (ret) { + pr_err("error: crypto_kpp_generate_public_key returned: %d\n", + ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* the glue's seed-derived ek must equal the local one. */ + { + byte *ek_chk = (byte *)malloc(ek_len); + if (! ek_chk) { + test_rc = MEMORY_E; + goto test_mlkem_end; + } + ret = wc_MlKemKey_EncodePublicKey(wc_key, ek_chk, ek_len); + if ((ret != 0) || (XMEMCMP(ek, ek_chk, ek_len) != 0)) { + pr_err("error: glue ek != wolfCrypt ek (ret %d)\n", ret); + free(ek_chk); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + free(ek_chk); + } + + /* short ek dst must fail with -EOVERFLOW. */ + sg_init_one(&dst_sg, ek, ek_len - 1); + kpp_request_set_output(req, &dst_sg, ek_len - 1); + ret = crypto_kpp_generate_public_key(req); + if (ret != -EOVERFLOW) { + pr_err("error: crypto_kpp_generate_public_key (short dst) " + "returned %d, expected %d\n", ret, -EOVERFLOW); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* wolfCrypt encapsulates; the glue decapsulates. */ + { + WC_RNG rng; + ret = LKCAPI_INITRNG(&rng); + if (ret != 0) { + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + ret = wc_MlKemKey_Encapsulate(wc_key, ct, ss_a, &rng); + wc_FreeRng(&rng); + if (ret != 0) { + pr_err("error: wc_MlKemKey_Encapsulate returned: %d\n", + ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + } + + sg_init_one(&src_sg, ct, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if (ret) { + pr_err("error: crypto_kpp_compute_shared_secret returned: " + "%d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + if (XMEMCMP(ss_a, ss_b, ss_len) != 0) { + pr_err("error: decapsulated secret != encapsulated secret\n"); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* implicit rejection: a corrupted ciphertext must decapsulate + * SUCCESSFULLY, to a different secret. + */ + ct[ct_len / 2] ^= 1U; + sg_init_one(&src_sg, ct, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if (ret) { + pr_err("error: crypto_kpp_compute_shared_secret (corrupt ct) " + "returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + if (XMEMCMP(ss_a, ss_b, ss_len) == 0) { + pr_err("error: corrupt ct decapsulated to the SAME secret\n"); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + ct[ct_len / 2] ^= 1U; + + /* wrong-size ct must fail with -EINVAL. */ + sg_init_one(&src_sg, ct, ct_len - 1); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len - 1); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if (ret != -EINVAL) { + pr_err("error: crypto_kpp_compute_shared_secret (short ct) " + "returned %d, expected %d\n", ret, -EINVAL); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* ==== encapsulation role (role switch by ek-length secret) ==== */ + + ret = crypto_kpp_set_secret(tfm, ek, ek_len); + if (ret) { + pr_err("error: crypto_kpp_set_secret (ek, %u) returned: %d\n", + ek_len, ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* glue encapsulates; wolfCrypt decapsulates. */ + sg_init_one(&dst_sg, ct, ct_len); + kpp_request_set_output(req, &dst_sg, ct_len); + ret = crypto_kpp_generate_public_key(req); + if (ret) { + pr_err("error: crypto_kpp_generate_public_key (encap) " + "returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + PRIVATE_KEY_UNLOCK(); + ret = wc_MlKemKey_Decapsulate(wc_key, ss_a, ct, ct_len); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + pr_err("error: wc_MlKemKey_Decapsulate returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* short ss dst must fail with -EOVERFLOW, without consuming the + * pending node. + */ + sg_init_one(&src_sg, ct, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len - 1); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len - 1); + ret = crypto_kpp_compute_shared_secret(req); + if (ret != -EOVERFLOW) { + pr_err("error: crypto_kpp_compute_shared_secret (short ss " + "dst) returned %d, expected %d\n", ret, -EOVERFLOW); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* claim: the pending secret must match wolfCrypt's decapsulation. */ + sg_init_one(&src_sg, ct, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if (ret) { + pr_err("error: crypto_kpp_compute_shared_secret (claim) " + "returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + if (XMEMCMP(ss_a, ss_b, ss_len) != 0) { + pr_err("error: claimed secret != decapsulated secret\n"); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* one-shot: a second claim of the same ciphertext must fail. */ + sg_init_one(&src_sg, ct, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if (ret != -ENOKEY) { + pr_err("error: double-claim returned %d, expected %d\n", ret, + -ENOKEY); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* unknown ct must fail. */ + ct[0] ^= 1U; + sg_init_one(&src_sg, ct, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if (ret != -ENOKEY) { + pr_err("error: unknown-ct claim returned %d, expected %d\n", + ret, -ENOKEY); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + ct[0] ^= 1U; + + /* eviction: overfill the pending list; the first ciphertext's node + * must be evicted, the last still claimable. + */ + for (i = 0; i <= (word32)WC_LINUXKM_MLKEM_PENDING_MAX; i++) { + byte *dst = (i == 0) ? ct_first : ct; + sg_init_one(&dst_sg, dst, ct_len); + kpp_request_set_output(req, &dst_sg, ct_len); + ret = crypto_kpp_generate_public_key(req); + if (ret) { + pr_err("error: generate #%u returned: %d\n", i, ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + } + sg_init_one(&src_sg, ct_first, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if (ret != -ENOKEY) { + pr_err("error: evicted-ct claim returned %d, expected %d\n", + ret, -ENOKEY); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + PRIVATE_KEY_UNLOCK(); + ret = wc_MlKemKey_Decapsulate(wc_key, ss_a, ct, ct_len); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + sg_init_one(&src_sg, ct, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if ((ret != 0) || (XMEMCMP(ss_a, ss_b, ss_len) != 0)) { + pr_err("error: newest-ct claim after eviction failed (ret " + "%d)\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + /* role-switch reaping: park an encapsulation, switch roles away + * and back; the pending node must be gone. + */ + sg_init_one(&dst_sg, ct, ct_len); + kpp_request_set_output(req, &dst_sg, ct_len); + ret = crypto_kpp_generate_public_key(req); + if (ret) { + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + ret = crypto_kpp_set_secret(tfm, seed, (unsigned int)sizeof(seed)); + if (ret == 0) + ret = crypto_kpp_set_secret(tfm, ek, ek_len); + if (ret) { + pr_err("error: role-switch set_secret returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + sg_init_one(&src_sg, ct, ct_len); + sg_init_one(&dst_sg, ss_b, ss_len); + kpp_request_set_input(req, &src_sg, ct_len); + kpp_request_set_output(req, &dst_sg, ss_len); + ret = crypto_kpp_compute_shared_secret(req); + if (ret != -ENOKEY) { + pr_err("error: claim after role-switch reap returned %d, " + "expected %d\n", ret, -ENOKEY); + test_rc = BAD_FUNC_ARG; + goto test_mlkem_end; + } + + test_rc = 0; +test_mlkem_end: + if (req) { kpp_request_free(req); req = NULL; } + if (tfm) { crypto_free_kpp(tfm); tfm = NULL; } + if (wc_key) { km_mlkem_del_wc_key(wc_key); wc_key = NULL; } + if (work) { ForceZero(work, ek_len + (2 * ct_len) + (2 * ss_len)); + free(work); work = NULL; } + + #ifdef WOLFKM_DEBUG_MLKEM + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#ifdef LINUXKM_MLKEM512 +static int linuxkm_test_mlkem512(void) +{ + return linuxkm_test_mlkem_driver("mlkem512" WOLFKM_MLKEM_DRIVER_SUFFIX, + (int)WC_ML_KEM_512); +} +#endif +#ifdef LINUXKM_MLKEM768 +static int linuxkm_test_mlkem768(void) +{ + return linuxkm_test_mlkem_driver("mlkem768" WOLFKM_MLKEM_DRIVER_SUFFIX, + (int)WC_ML_KEM_768); +} +#endif +#ifdef LINUXKM_MLKEM1024 +static int linuxkm_test_mlkem1024(void) +{ + return linuxkm_test_mlkem_driver("mlkem1024" WOLFKM_MLKEM_DRIVER_SUFFIX, + (int)WC_ML_KEM_1024); +} +#endif + +#endif /* LINUXKM_LKCAPI_REGISTER_MLKEM */ + +#endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index 414f9d718a..8115bf951e 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -26,7 +26,7 @@ #error lkcapi_sha_glue.c included in non-LINUXKM_LKCAPI_REGISTER project. #endif -#if defined(WC_LINUXKM_C_FALLBACK_IN_SHIMS) && defined(USE_INTEL_SPEEDUP) +#if defined(WC_LINUXKM_C_FALLBACK_IN_SHIMS) && defined(USE_INTEL_SPEEDUP) && !defined(WC_DEBUG_FORCE_KERNEL_SETTINGS) #error SHA* WC_LINUXKM_C_FALLBACK_IN_SHIMS is not currently supported. #endif @@ -1927,7 +1927,7 @@ WC_MAYBE_UNUSED static int km_hmac_test_export_import( return ret; } -PRAGMA_DIAG_POP +PRAGMA_DIAG_POP /* -Wno-pointer-arith -Wno-nested-externs, for linux/list.h */ WC_MAYBE_UNUSED static int hmac_sha3_test_once(void) { static int once = 0; @@ -2221,10 +2221,10 @@ static struct wc_rng_bank_inst *linuxkm_get_drbg(struct wc_rng_bank *ctx) { return ret; } -static void linuxkm_put_drbg(struct wc_rng_bank *ctx, struct wc_rng_bank_inst **drbg) { - int ret = wc_rng_bank_checkin(ctx, drbg); +static void linuxkm_put_drbg(struct wc_rng_bank_inst **drbg) { + int ret = wc_rng_bank_inst_checkin(drbg); if (ret != 0) { - pr_err("ERROR: wc_rng_bank_checkin() in linuxkm_put_drbg() returned err %d.\n", ret); + pr_err("ERROR: wc_rng_bank_inst_checkin() in linuxkm_put_drbg() returned err %d.\n", ret); WC_DUMP_BACKTRACE_NONDEBUG; } } @@ -2267,6 +2267,46 @@ WC_MAYBE_UNUSED static int linuxkm_InitRng_DefaultRef(WC_RNG* rng) { #endif /* LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT && HAVE_HASHDRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(NO_SHA256) + /* Both DRBGs compiled in: dispatch on the runtime drbgType. */ + #define WC_RNG_BANK_RESEED_CTR(rng_ptr) \ + (((rng_ptr)->drbgType == WC_DRBG_SHA512) \ + ? ((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr \ + : ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr) + #define WC_RNG_BANK_SET_RESEED_CTR(rng_ptr, val) \ + do { \ + if ((rng_ptr)->drbgType == WC_DRBG_SHA512) \ + ((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr \ + = (val); \ + else \ + ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr = (val); \ + } while (0) + #define WC_RNG_BANK_DRBG_NULL(rng_ptr) \ + ((rng_ptr)->drbg == NULL && (rng_ptr)->drbg512 == NULL) +#elif defined(WOLFSSL_DRBG_SHA512) + /* SHA-512 DRBG only (NO_SHA256 defined); the SHA-256 struct and + * rng->drbg field do not exist in this build. */ + #define WC_RNG_BANK_RESEED_CTR(rng_ptr) \ + (((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr) + #define WC_RNG_BANK_SET_RESEED_CTR(rng_ptr, val) \ + do { \ + ((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr \ + = (val); \ + } while (0) + #define WC_RNG_BANK_DRBG_NULL(rng_ptr) \ + ((rng_ptr)->drbg512 == NULL) +#else + /* SHA-256 DRBG only (the historical default). */ + #define WC_RNG_BANK_RESEED_CTR(rng_ptr) \ + (((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr) + #define WC_RNG_BANK_SET_RESEED_CTR(rng_ptr, val) \ + do { \ + ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr = (val); \ + } while (0) + #define WC_RNG_BANK_DRBG_NULL(rng_ptr) \ + ((rng_ptr)->drbg == NULL) +#endif + static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx, const u8 *src, unsigned int slen, u8 *dst, unsigned int dlen) @@ -2287,6 +2327,20 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx, goto out; } } + else if ((! WC_RNG_BANK_DRBG_NULL(WC_RNG_BANK_INST_TO_RNG(drbg))) && + (WC_RNG_BANK_RESEED_CTR(WC_RNG_BANK_INST_TO_RNG(drbg)) > WC_RESEED_INTERVAL / 2) && + wc_linuxkm_can_block()) + { + byte scratch[4]; + word64 cur_counter = WC_RNG_BANK_RESEED_CTR(WC_RNG_BANK_INST_TO_RNG(drbg)); + WC_RNG_BANK_SET_RESEED_CTR(WC_RNG_BANK_INST_TO_RNG(drbg), WC_RESEED_INTERVAL); + ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(drbg), scratch, + (word32)sizeof scratch); + if ((ret != 0) && (WC_RNG_BANK_RESEED_CTR(WC_RNG_BANK_INST_TO_RNG(drbg)) >= WC_RESEED_INTERVAL)) { + WC_RNG_BANK_SET_RESEED_CTR(WC_RNG_BANK_INST_TO_RNG(drbg), cur_counter + 1); + } + ForceZero(scratch, sizeof scratch); + } for (;;) { #define RNG_MAX_BLOCK_LEN_ROUNDED (RNG_MAX_BLOCK_LEN & ~0xfU) @@ -2318,8 +2372,10 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx, break; retried = 1; - ret = wc_rng_bank_inst_reinit(ctx, - drbg, + if (! wc_linuxkm_can_block()) + break; + + ret = wc_rng_bank_inst_reinit(NULL, drbg, WC_LINUXKM_INITRNG_TIMEOUT_SEC, WC_RNG_BANK_FLAG_CAN_WAIT); @@ -2343,7 +2399,7 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx, out: - linuxkm_put_drbg(ctx, &drbg); + linuxkm_put_drbg(&drbg); return ret; } @@ -2579,15 +2635,22 @@ static ssize_t wc_extract_crng_user(void __user *buf, size_t nbytes) { __builtin_unreachable(); } +/* Note, wc_mix_pool_bytes() only injects the supplied entropy into one RNG, + * CPU-local when uncontended. This routine can be pegged by unprivileged + * users, so its impact needs to stay as CPU-local as possible. */ static int wc_mix_pool_bytes(const void *buf, size_t len) { int ret; - struct wc_rng_bank *ctx; - size_t i; - int n; - int can_sleep = wc_linuxkm_can_block(); + struct wc_rng_bank *ctx = NULL; + word32 flags = + WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST | + WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST; + struct wc_rng_bank_inst *drbg = NULL; + word64 cur_counter; - if (len == 0) - return 0; + if (len > WC_MAX_UINT_OF(word32)) + return -EFBIG; + + /* Continue even if len == 0 -- churning the DRBG is still meaningful. */ ret = wc_rng_bank_default_checkout(&ctx); if (ret) { @@ -2597,45 +2660,38 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) { return -EFAULT; } - ret = 0; + if (wc_linuxkm_can_block()) + flags |= WC_RNG_BANK_FLAG_AFFINITY_LOCK; + else + flags |= WC_RNG_BANK_FLAG_NO_VECTOR_OPS; - for (n = ctx->n_rngs - 1; n >= 0; --n) { - struct wc_rng_bank_inst *drbg; + ret = wc_rng_bank_checkout(ctx, &drbg, 0, 0, flags); + if (ret != 0) { + ret = -EINVAL; + goto out; + } - int V_offset; + if (WC_RNG_BANK_DRBG_NULL(WC_RNG_BANK_INST_TO_RNG(drbg))) { + ret = 0; /* consistent with wc_RNG_DRBG_Reseed() behavior in RDRAND configs. */ + goto out; + } - if (wc_rng_bank_checkout(ctx, &drbg, n, 0, WC_RNG_BANK_FLAG_NONE) != 0) - continue; + cur_counter = WC_RNG_BANK_RESEED_CTR(WC_RNG_BANK_INST_TO_RNG(drbg)); -#ifdef WOLFSSL_DRBG_SHA512 - if (WC_RNG_BANK_INST_TO_RNG(drbg)->drbgType == WC_DRBG_SHA512) { - for (i = 0, V_offset = 0; i < len; ++i) { - ((struct DRBG_SHA512_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg512)->V[V_offset++] += ((byte *)buf)[i]; - if (V_offset == (int)sizeof ((struct DRBG_SHA512_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg512)->V) - V_offset = 0; - } - } - else -#endif /* WOLFSSL_DRBG_SHA512 */ - { - for (i = 0, V_offset = 0; i < len; ++i) { - ((struct DRBG_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg)->V[V_offset++] += ((byte *)buf)[i]; - if (V_offset == (int)sizeof ((struct DRBG_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg)->V) - V_offset = 0; - } - } + ret = wc_RNG_DRBG_Reseed(WC_RNG_BANK_INST_TO_RNG(drbg), buf, (word32)len); + if (ret != 0) + ret = -EINVAL; - wc_rng_bank_checkin(ctx, &drbg); - if (can_sleep) { - if (signal_pending(current)) { - ret = -EINTR; - break; - } - cond_resched(); - } - } + /* Unconditionally restore the reseed counter -- don't credit the + * contributed entropy. */ + WC_RNG_BANK_SET_RESEED_CTR(WC_RNG_BANK_INST_TO_RNG(drbg), cur_counter); - (void)wc_rng_bank_default_checkin(&ctx); +out: + + if (drbg) + (void)wc_rng_bank_inst_checkin(&drbg); + if (ctx) + (void)wc_rng_bank_default_checkin(&ctx); return ret; } diff --git a/linuxkm/lkcapi_slhdsa_glue.c b/linuxkm/lkcapi_slhdsa_glue.c new file mode 100644 index 0000000000..bb2faa5a79 --- /dev/null +++ b/linuxkm/lkcapi_slhdsa_glue.c @@ -0,0 +1,2409 @@ +/* lkcapi_slhdsa_glue.c -- glue logic to register SLH-DSA (FIPS 205) + * wolfCrypt implementations with the Linux Kernel Cryptosystem + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* included by linuxkm/lkcapi_glue.c */ +#ifndef WC_SKIP_INCLUDED_C_FILES + +#ifndef LINUXKM_LKCAPI_REGISTER + #error lkcapi_slhdsa_glue.c included in non-LINUXKM_LKCAPI_REGISTER project. +#endif + +/* SLH-DSA (FIPS 205) glue, covering all twelve parameter sets, each + * individually gated on its wolfCrypt WOLFSSL_SLHDSA_PARAM_NO_* / + * WOLFSSL_SLHDSA_SHA2 configuration. + * + * The kernel has no in-tree SLH-DSA implementation on any version (the + * only in-tree PQC signature is ML-DSA, crypto/mldsa.c), hence no + * CONFIG_CRYPTO_SLHDSA to pivot on for + * LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG, and no config-conflict check + * either -- the algs are registered for LINUXKM_LKCAPI_REGISTER_ALL, or + * by explicit request only. + * + * Calling conventions (wolfSSL-defined; the out-of-tree leancrypto + * kernel module registers SLH-DSA sigver with the same + * signature-then-message akcipher src convention): + * - cra_names are the FIPS 205 parameter set names, lowercased: + * "slh-dsa-shake-128s" ... "slh-dsa-sha2-256f". + * - set_pub_key takes the raw public key (PK.seed || PK.root, 2*n + * bytes exactly); set_priv_key takes the raw FIPS 205 private key + * (SK.seed || SK.prf || PK.seed || PK.root, 4*n bytes exactly), + * which contains the public key, so set_priv_key also installs the + * public half (matching the in-tree ML-DSA, where set_pub is + * likewise optional after set_priv). + * - verify takes the raw signature as src and the raw unhashed + * message as the "digest" argument: the pure SLH-DSA.Verify of + * FIPS 205 algorithm 24, with an empty context string. Signature + * size mismatches and verification failures both return -EBADMSG. + * - sign is the hedged (randomized) pure SLH-DSA.Sign of FIPS 205 + * algorithm 22, with an empty context string, per the FIPS 205 + * section 9.2 default; -EOVERFLOW on insufficient dst, per the + * kernel's rsassa-pkcs1 convention. + * - key_size returns the public key size in BYTES on all kernel + * versions, and digest_size is not set, both mirroring the in-tree + * ML-DSA conventions for the PQC signature family. + * + * Because these cra_names are unknown to crypto/testmgr.c, alg_test() + * takes its "notest" path and returns success at registration time, + * with or without fips_enabled. Self-tests are instead supplied by + * the linuxkm_test_slhdsa_*() functions below, which test the LKCAPI + * plumbing; algorithm-correctness KATs live in wolfcrypt/test/test.c's + * slhdsa_test(), which is built into the module whenever + * LINUXKM_LKCAPI_REGISTER is (see the self-test comment below). + */ + +#if defined(WOLFSSL_HAVE_SLHDSA) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_SLHDSA) && \ + !defined(LINUXKM_LKCAPI_REGISTER_SLHDSA) + #define LINUXKM_LKCAPI_REGISTER_SLHDSA + #endif +#else + #undef LINUXKM_LKCAPI_REGISTER_SLHDSA +#endif + +#ifdef LINUXKM_LKCAPI_REGISTER_SLHDSA + +#include + +/* Per-parameter-set registration gates. wc_slhdsa.h canonicalizes the + * parameter-set configuration into the positive WOLFSSL_SLHDSA_PARAM_* + * macros (deriving them from the WOLFSSL_SLHDSA_PARAM_NO_* family when + * only exclusions are given, and giving explicit positives precedence + * over exclusions), so those, evaluated after the header include, are + * the authoritative signal. */ +#ifdef WOLFSSL_SLHDSA_PARAM_128S + #define LINUXKM_SLHDSA_SHAKE_128S +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_128F + #define LINUXKM_SLHDSA_SHAKE_128F +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192S + #define LINUXKM_SLHDSA_SHAKE_192S +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192F + #define LINUXKM_SLHDSA_SHAKE_192F +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256S + #define LINUXKM_SLHDSA_SHAKE_256S +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256F + #define LINUXKM_SLHDSA_SHAKE_256F +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + #define LINUXKM_SLHDSA_SHA2_128S +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + #define LINUXKM_SLHDSA_SHA2_128F +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + #define LINUXKM_SLHDSA_SHA2_192S +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + #define LINUXKM_SLHDSA_SHA2_192F +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + #define LINUXKM_SLHDSA_SHA2_256S +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + #define LINUXKM_SLHDSA_SHA2_256F +#endif + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + #define LINUXKM_SLHDSA_SIGN +#endif + +#if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) + #define WOLFKM_SLHDSA_DRIVER_ISA_EXT "-avx2" +#else + #define WOLFKM_SLHDSA_DRIVER_ISA_EXT "" +#endif + +#define WOLFKM_SLHDSA_DRIVER_SUFFIX \ + WOLFKM_SLHDSA_DRIVER_ISA_EXT WOLFKM_DRIVER_SUFFIX_BASE + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) + /* As with ecdsa (see lkcapi_ecdsa_glue.c), registered as struct + * sig_alg on linux 6.13+, and as a sign/verify-capable struct + * akcipher_alg on earlier kernels. */ + #define LINUXKM_SLHDSA_SIG_ALG +#endif + +#ifdef LINUXKM_SLHDSA_SIG_ALG + #define slhdsa_tfm_type crypto_sig + #define slhdsa_tfm_ctx_cb crypto_sig_ctx +#else + #define slhdsa_tfm_type crypto_akcipher + #define slhdsa_tfm_ctx_cb akcipher_tfm_ctx +#endif /* !LINUXKM_SLHDSA_SIG_ALG */ + +#define WOLFKM_SLHDSA_MAX_PUB_LEN (2 * 32) +#define WOLFKM_SLHDSA_MAX_PRIV_LEN (4 * 32) + +/* Struct SlhDsaKey embeds live hash state that is mutated during both + * sign and verify, so, as with ecdsa/ecdh (see lkcapi_ecdsa_glue.c), a + * long-lived wolfCrypt key would be raceable under the kernel crypto + * API's concurrent use of a tfm. The tfm ctx therefore stores only the + * raw key octets, and each operation runs on a transient heap-allocated + * SlhDsaKey. */ +struct km_slhdsa_ctx { + int param; /* enum SlhDsaParam */ + int pub_set; + int priv_set; + byte pub[WOLFKM_SLHDSA_MAX_PUB_LEN]; +#ifdef LINUXKM_SLHDSA_SIGN + byte priv[WOLFKM_SLHDSA_MAX_PRIV_LEN]; +#endif +}; + +static SlhDsaKey * km_slhdsa_new_wc_key(int param) +{ + SlhDsaKey *key = (SlhDsaKey *)malloc(sizeof(SlhDsaKey)); + if (key) { + if (wc_SlhDsaKey_Init(key, (enum SlhDsaParam)param, NULL /* heap */, + INVALID_DEVID) != 0) + { + free(key); + key = NULL; + } + } + return key; +} + +static void km_slhdsa_del_wc_key(SlhDsaKey *key) +{ + if (key) { + wc_SlhDsaKey_Free(key); + ForceZero(key, sizeof(SlhDsaKey)); + free(key); + } +} + +static int km_slhdsa_init_common(struct slhdsa_tfm_type *tfm, int param) +{ + struct km_slhdsa_ctx *ctx = slhdsa_tfm_ctx_cb(tfm); + + XMEMSET(ctx, 0, sizeof(struct km_slhdsa_ctx)); + ctx->param = param; + + /* Confirm at first use that the fixed ctx buffers fit this set. */ + if ((wc_SlhDsaKey_PublicSizeFromParam((enum SlhDsaParam)param) > + (int)sizeof(ctx->pub)) +#ifdef LINUXKM_SLHDSA_SIGN + || (wc_SlhDsaKey_PrivateSizeFromParam((enum SlhDsaParam)param) > + (int)sizeof(ctx->priv)) +#endif + ) + { + return -EINVAL; + } + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: exiting km_slhdsa_init_common (param %d)\n", param); + #endif + return 0; +} + +static void km_slhdsa_exit(struct slhdsa_tfm_type *tfm) +{ + struct km_slhdsa_ctx *ctx = slhdsa_tfm_ctx_cb(tfm); + + ForceZero(ctx, sizeof(struct km_slhdsa_ctx)); + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: exiting km_slhdsa_exit\n"); + #endif + return; +} + +/* + * Sets the SLH-DSA public key. + * + * param tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * param key raw public key (PK.seed || PK.root), exactly 2*n bytes + * param keylen key length + */ +static int km_slhdsa_set_pub(struct slhdsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + struct km_slhdsa_ctx * ctx = slhdsa_tfm_ctx_cb(tfm); + int pub_len; + + if (key == NULL) + return -EINVAL; + + pub_len = wc_SlhDsaKey_PublicSizeFromParam((enum SlhDsaParam)ctx->param); + if ((pub_len <= 0) || (keylen != (unsigned int)pub_len)) + return -EINVAL; + + XMEMCPY(ctx->pub, key, pub_len); + ctx->pub_set = 1; + ctx->priv_set = 0; + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: exiting km_slhdsa_set_pub %d\n", keylen); + #endif + return 0; +} + +#ifdef LINUXKM_SLHDSA_SIGN +/* + * Sets the SLH-DSA private key, and installs the contained public key. + * + * param tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * param key raw FIPS 205 private key (SK.seed || SK.prf || PK.seed || + * PK.root), exactly 4*n bytes + * param keylen key length + */ +static int km_slhdsa_set_priv(struct slhdsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + struct km_slhdsa_ctx * ctx = slhdsa_tfm_ctx_cb(tfm); + SlhDsaKey * wc_key = NULL; + int priv_len; + word32 pub_len_w; + int err; + + if (key == NULL) + return -EINVAL; + + priv_len = wc_SlhDsaKey_PrivateSizeFromParam((enum SlhDsaParam)ctx->param); + if ((priv_len <= 0) || (keylen != (unsigned int)priv_len)) + return -EINVAL; + + /* validate the key octets through a transient wolfCrypt key, and + * extract the contained public key from it, rather than assuming + * the octet layout here. (wc_SlhDsaKey_CheckKey(), which + * regenerates PK.root from SK.seed at keygen cost, is deliberately + * not called -- consistency failures surface as verification + * failures of generated signatures.) */ + wc_key = km_slhdsa_new_wc_key(ctx->param); + if (! wc_key) + return -ENOMEM; + + err = wc_SlhDsaKey_ImportPrivate(wc_key, (const byte *)key, keylen); + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_SLHDSA + pr_err("error: wc_SlhDsaKey_ImportPrivate failed: %d\n", err); + #endif + km_slhdsa_del_wc_key(wc_key); + return -EINVAL; + } + + pub_len_w = (word32)sizeof(ctx->pub); + err = wc_SlhDsaKey_ExportPublic(wc_key, ctx->pub, &pub_len_w); + km_slhdsa_del_wc_key(wc_key); + if (unlikely(err)) + return -EINVAL; + + XMEMCPY(ctx->priv, key, priv_len); + ctx->priv_set = 1; + ctx->pub_set = 1; + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: exiting km_slhdsa_set_priv %d\n", keylen); + #endif + return 0; +} +#else /* !LINUXKM_SLHDSA_SIGN */ +static int km_slhdsa_set_priv(struct slhdsa_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + (void)tfm; + (void)key; + (void)keylen; + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_SLHDSA_SIGN */ + +/* Shared verify core. returns 0, -EBADMSG (size mismatch or + * verification failure, per the in-tree ML-DSA convention), -EINVAL, + * or -ENOMEM. + */ +static int km_slhdsa_verify_common(struct km_slhdsa_ctx *ctx, + const byte *sig, word32 sig_len, + const byte *msg, word32 msg_len) +{ + SlhDsaKey * wc_key = NULL; + int exp_sig_len; + int pub_len; + int err; + + if (! ctx->pub_set) + return -EINVAL; + + exp_sig_len = wc_SlhDsaKey_SigSizeFromParam((enum SlhDsaParam)ctx->param); + if (exp_sig_len <= 0) + return -EINVAL; + + if (sig_len != (word32)exp_sig_len) + return -EBADMSG; + + pub_len = wc_SlhDsaKey_PublicSizeFromParam((enum SlhDsaParam)ctx->param); + if (pub_len <= 0) + return -EINVAL; + + wc_key = km_slhdsa_new_wc_key(ctx->param); + if (! wc_key) + return -ENOMEM; + + err = wc_SlhDsaKey_ImportPublic(wc_key, ctx->pub, (word32)pub_len); + if (err == 0) { + err = wc_SlhDsaKey_Verify(wc_key, NULL /* ctx */, 0 /* ctxSz */, + msg, msg_len, sig, sig_len); + if (err) { + #ifdef WOLFKM_DEBUG_SLHDSA + pr_err("error: wc_SlhDsaKey_Verify returned: %d\n", err); + #endif + err = -EBADMSG; + } + } + else { + err = -EINVAL; + } + + km_slhdsa_del_wc_key(wc_key); + return err; +} + +#ifdef LINUXKM_SLHDSA_SIGN +/* Shared sign core. Writes the signature to sig and returns its size, + * or a negative error (-EOVERFLOW if sig_space is insufficient, per the + * kernel's rsassa-pkcs1 convention). */ +static int km_slhdsa_sign_common(struct km_slhdsa_ctx *ctx, + byte *sig, word32 sig_space, + const byte *msg, word32 msg_len) +{ + SlhDsaKey * wc_key = NULL; + int exp_sig_len; + int priv_len; + word32 sig_len_w; + int err; + WC_RNG rng; + int rng_inited = 0; + + if (! ctx->priv_set) + return -EINVAL; + + exp_sig_len = wc_SlhDsaKey_SigSizeFromParam((enum SlhDsaParam)ctx->param); + if (exp_sig_len <= 0) + return -EINVAL; + + if (sig_space < (word32)exp_sig_len) + return -EOVERFLOW; + + priv_len = wc_SlhDsaKey_PrivateSizeFromParam((enum SlhDsaParam)ctx->param); + if (priv_len <= 0) + return -EINVAL; + + wc_key = km_slhdsa_new_wc_key(ctx->param); + if (! wc_key) + return -ENOMEM; + + err = wc_SlhDsaKey_ImportPrivate(wc_key, ctx->priv, (word32)priv_len); + if (err != 0) { + km_slhdsa_del_wc_key(wc_key); + return -EINVAL; + } + + err = LKCAPI_INITRNG(&rng); + if (err != 0) { + km_slhdsa_del_wc_key(wc_key); + return -ENODEV; + } + rng_inited = 1; + (void)rng_inited; + + sig_len_w = sig_space; + /* hedged signing per the FIPS 205 section 9.2 default. */ + err = wc_SlhDsaKey_Sign(wc_key, NULL /* ctx */, 0 /* ctxSz */, + msg, msg_len, sig, &sig_len_w, &rng); + + wc_FreeRng(&rng); + km_slhdsa_del_wc_key(wc_key); + + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_SLHDSA + pr_err("error: wc_SlhDsaKey_Sign returned: %d\n", err); + #endif + return -EINVAL; + } + + if (sig_len_w != (word32)exp_sig_len) + return -EINVAL; + + return (int)sig_len_w; +} +#endif /* LINUXKM_SLHDSA_SIGN */ + +#ifdef LINUXKM_SLHDSA_SIG_ALG + +/* Mirrors the size convention of the kernel's key_size callbacks (see + * lkcapi_ed_glue.c and, e.g., ecdsa_key_size()): + * linux kernel version < 6.15.3: key size in BYTES; + * linux kernel version >= 6.15.3: key size in BITS (crypto_sig_keysize() + * semantics changed; crypto_sig_digestsize() then derives bytes as + * keysize/8, so the digestsize seen by callers is the public key size + * in bytes in both eras). + */ +static unsigned int km_slhdsa_key_size(struct crypto_sig *tfm) +{ + struct km_slhdsa_ctx *ctx = crypto_sig_ctx(tfm); + int len = wc_SlhDsaKey_PublicSizeFromParam((enum SlhDsaParam)ctx->param); + if (len <= 0) + return 0; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + return (unsigned int)len * 8U; /* bits */ + #else + return (unsigned int)len; /* bytes */ + #endif +} + +static unsigned int km_slhdsa_max_size(struct crypto_sig *tfm) +{ + struct km_slhdsa_ctx *ctx = crypto_sig_ctx(tfm); + int len = wc_SlhDsaKey_SigSizeFromParam((enum SlhDsaParam)ctx->param); + return (len > 0) ? (unsigned int)len : 0; +} + +/* + * Verify an SLH-DSA signature (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw signature; slen must equal the parameter set's signature + * size. + * + * digest: + * - the raw message; no prehashing occurs, and dlen is unrestricted. + */ +static int km_slhdsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct km_slhdsa_ctx *ctx = crypto_sig_ctx(tfm); + int err; + + if (src == NULL || digest == NULL) + return -EINVAL; + + err = km_slhdsa_verify_common(ctx, (const byte *)src, (word32)slen, + (const byte *)digest, (word32)dlen); + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: exiting km_slhdsa_verify dlen %d, slen %d, err %d\n", + dlen, slen, err); + #endif + return err; +} + +#ifdef LINUXKM_SLHDSA_SIGN +/* + * Sign a message with SLH-DSA (linux 6.13+ struct sig_alg edition). + * + * src is the raw message (unrestricted length); the signature is + * written to dst, and its size returned, following the convention of + * rsassa_pkcs1_sign(). Signing is hedged per FIPS 205 section 9.2, + * with the addrnd drawn from the module's default RNG + * (LKCAPI_INITRNG). + */ +static int km_slhdsa_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct km_slhdsa_ctx *ctx = crypto_sig_ctx(tfm); + int err; + + if (src == NULL || dst == NULL) + return -EINVAL; + + err = km_slhdsa_sign_common(ctx, (byte *)dst, (word32)dlen, + (const byte *)src, (word32)slen); + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: exiting km_slhdsa_sign slen %d, dlen %d, err %d\n", + slen, dlen, err); + #endif + return err; +} +#else /* !LINUXKM_SLHDSA_SIGN */ +static int km_slhdsa_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + (void)tfm; + (void)src; + (void)slen; + (void)dst; + (void)dlen; + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_SLHDSA_SIGN */ + +#else /* !LINUXKM_SLHDSA_SIG_ALG */ + +static unsigned int km_slhdsa_max_size(struct crypto_akcipher *tfm) +{ + struct km_slhdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + int len = wc_SlhDsaKey_SigSizeFromParam((enum SlhDsaParam)ctx->param); + return (len > 0) ? (unsigned int)len : 0; +} + +/* + * Verify an SLH-DSA signature. + * + * The total size of req->src is src_len + dst_len: + * - src_len: signature (exact size for the parameter set) + * - dst_len: message (raw, unhashed, unrestricted length) + * + * dst should be null. + */ +static int km_slhdsa_verify(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_slhdsa_ctx * ctx = NULL; + byte * sig = NULL; + word32 sig_len = 0; + byte * msg = NULL; + word32 msg_len = 0; + int err = -1; + + if (req->src == NULL || req->dst != NULL) + return -EINVAL; + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + sig_len = req->src_len; + msg_len = req->dst_len; + + if ((sig_len + msg_len) != ((word64)sig_len + (word64)msg_len)) + return -EINVAL; + + sig = malloc(sig_len + msg_len); + if (unlikely(sig == NULL)) + return -ENOMEM; + + msg = sig + sig_len; + + XMEMSET(sig, 0, sig_len + msg_len); + + scatterwalk_map_and_copy(sig, req->src, 0, sig_len + msg_len, 0); + + err = km_slhdsa_verify_common(ctx, sig, sig_len, msg, msg_len); + + free(sig); + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: exiting km_slhdsa_verify msg_len %d, sig_len %d, " + "err %d\n", msg_len, sig_len, err); + #endif + return err; +} + +#ifdef LINUXKM_SLHDSA_SIGN +/* + * Sign a message with SLH-DSA. + * + * req->src is the raw message (src_len); the signature is written to + * req->dst, and req->dst_len updated, per pre-6.13 akcipher sign + * semantics. -EOVERFLOW on insufficient dst space. Signing is hedged + * per FIPS 205 section 9.2, with the addrnd drawn from the module's + * default RNG (LKCAPI_INITRNG). + */ +static int km_slhdsa_sign(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_slhdsa_ctx * ctx = NULL; + byte * msg = NULL; + byte * sig = NULL; + word32 msg_len = 0; + int err = -1; + + if (req->src == NULL || req->dst == NULL) + return -EINVAL; + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + msg_len = req->src_len; + + msg = malloc(msg_len + req->dst_len); + if (unlikely(msg == NULL)) + return -ENOMEM; + sig = msg + msg_len; + + scatterwalk_map_and_copy(msg, req->src, 0, msg_len, 0); + + err = km_slhdsa_sign_common(ctx, sig, (word32)req->dst_len, + msg, msg_len); + if (err >= 0) { + scatterwalk_map_and_copy(sig, req->dst, 0, (unsigned int)err, 1); + req->dst_len = (unsigned int)err; + err = 0; + } + + free(msg); + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: exiting km_slhdsa_sign msg_len %d, err %d\n", + msg_len, err); + #endif + return err; +} +#else /* !LINUXKM_SLHDSA_SIGN */ +static int km_slhdsa_sign(struct akcipher_request *req) +{ + (void)req; + return -EOPNOTSUPP; +} +#endif /* !LINUXKM_SLHDSA_SIGN */ + +#endif /* !LINUXKM_SLHDSA_SIG_ALG */ + +/* stamp out the per-parameter-set alg structs and init callbacks. all + * callbacks other than init are shared, with the parameter set carried + * in the tfm ctx. */ + +#ifdef LINUXKM_SLHDSA_SIG_ALG + +#define KM_SLHDSA_DEFINE_ALG(stem, cra_name_str, param_enum) \ + static int km_ ## stem ## _init(struct crypto_sig *tfm) \ + { \ + return km_slhdsa_init_common(tfm, (int)(param_enum)); \ + } \ + static int stem ## _loaded = 0; \ + static struct sig_alg stem = { \ + .base.cra_name = (cra_name_str), \ + .base.cra_driver_name = cra_name_str WOLFKM_SLHDSA_DRIVER_SUFFIX, \ + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, \ + .base.cra_module = THIS_MODULE, \ + .base.cra_ctxsize = sizeof(struct km_slhdsa_ctx), \ + .sign = km_slhdsa_sign, \ + .verify = km_slhdsa_verify, \ + .set_pub_key = km_slhdsa_set_pub, \ + .set_priv_key = km_slhdsa_set_priv, \ + .key_size = km_slhdsa_key_size, \ + /* no .digest_size: crypto/sig.c defaults it (key_size on */ \ + /* < 6.15.3; keysize-bits/8 on >= 6.15.3): pub bytes both. */ \ + .max_size = km_slhdsa_max_size, \ + .init = km_ ## stem ## _init, \ + .exit = km_slhdsa_exit, \ + } + +#else /* !LINUXKM_SLHDSA_SIG_ALG */ + +#define KM_SLHDSA_DEFINE_ALG(stem, cra_name_str, param_enum) \ + static int km_ ## stem ## _init(struct crypto_akcipher *tfm) \ + { \ + return km_slhdsa_init_common(tfm, (int)(param_enum)); \ + } \ + static int stem ## _loaded = 0; \ + static struct akcipher_alg stem = { \ + .base.cra_name = (cra_name_str), \ + .base.cra_driver_name = cra_name_str WOLFKM_SLHDSA_DRIVER_SUFFIX, \ + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, \ + .base.cra_module = THIS_MODULE, \ + .base.cra_ctxsize = sizeof(struct km_slhdsa_ctx), \ + .sign = km_slhdsa_sign, \ + .verify = km_slhdsa_verify, \ + .set_pub_key = km_slhdsa_set_pub, \ + .set_priv_key = km_slhdsa_set_priv, \ + .max_size = km_slhdsa_max_size, \ + .init = km_ ## stem ## _init, \ + .exit = km_slhdsa_exit, \ + } + +#endif /* !LINUXKM_SLHDSA_SIG_ALG */ + +#ifdef LINUXKM_SLHDSA_SHAKE_128S +KM_SLHDSA_DEFINE_ALG(slhdsa_shake_128s, "slh-dsa-shake-128s", SLHDSA_SHAKE128S); +static int linuxkm_test_slhdsa_shake_128s(void); +#endif +#ifdef LINUXKM_SLHDSA_SHAKE_128F +KM_SLHDSA_DEFINE_ALG(slhdsa_shake_128f, "slh-dsa-shake-128f", SLHDSA_SHAKE128F); +static int linuxkm_test_slhdsa_shake_128f(void); +#endif +#ifdef LINUXKM_SLHDSA_SHAKE_192S +KM_SLHDSA_DEFINE_ALG(slhdsa_shake_192s, "slh-dsa-shake-192s", SLHDSA_SHAKE192S); +static int linuxkm_test_slhdsa_shake_192s(void); +#endif +#ifdef LINUXKM_SLHDSA_SHAKE_192F +KM_SLHDSA_DEFINE_ALG(slhdsa_shake_192f, "slh-dsa-shake-192f", SLHDSA_SHAKE192F); +static int linuxkm_test_slhdsa_shake_192f(void); +#endif +#ifdef LINUXKM_SLHDSA_SHAKE_256S +KM_SLHDSA_DEFINE_ALG(slhdsa_shake_256s, "slh-dsa-shake-256s", SLHDSA_SHAKE256S); +static int linuxkm_test_slhdsa_shake_256s(void); +#endif +#ifdef LINUXKM_SLHDSA_SHAKE_256F +KM_SLHDSA_DEFINE_ALG(slhdsa_shake_256f, "slh-dsa-shake-256f", SLHDSA_SHAKE256F); +static int linuxkm_test_slhdsa_shake_256f(void); +#endif +#ifdef LINUXKM_SLHDSA_SHA2_128S +KM_SLHDSA_DEFINE_ALG(slhdsa_sha2_128s, "slh-dsa-sha2-128s", SLHDSA_SHA2_128S); +static int linuxkm_test_slhdsa_sha2_128s(void); +#endif +#ifdef LINUXKM_SLHDSA_SHA2_128F +KM_SLHDSA_DEFINE_ALG(slhdsa_sha2_128f, "slh-dsa-sha2-128f", SLHDSA_SHA2_128F); +static int linuxkm_test_slhdsa_sha2_128f(void); +#endif +#ifdef LINUXKM_SLHDSA_SHA2_192S +KM_SLHDSA_DEFINE_ALG(slhdsa_sha2_192s, "slh-dsa-sha2-192s", SLHDSA_SHA2_192S); +static int linuxkm_test_slhdsa_sha2_192s(void); +#endif +#ifdef LINUXKM_SLHDSA_SHA2_192F +KM_SLHDSA_DEFINE_ALG(slhdsa_sha2_192f, "slh-dsa-sha2-192f", SLHDSA_SHA2_192F); +static int linuxkm_test_slhdsa_sha2_192f(void); +#endif +#ifdef LINUXKM_SLHDSA_SHA2_256S +KM_SLHDSA_DEFINE_ALG(slhdsa_sha2_256s, "slh-dsa-sha2-256s", SLHDSA_SHA2_256S); +static int linuxkm_test_slhdsa_sha2_256s(void); +#endif +#ifdef LINUXKM_SLHDSA_SHA2_256F +KM_SLHDSA_DEFINE_ALG(slhdsa_sha2_256f, "slh-dsa-sha2-256f", SLHDSA_SHA2_256F); +static int linuxkm_test_slhdsa_sha2_256f(void); +#endif + +/* Self-tests. + * + * Algorithm-correctness KATs are deliberately NOT duplicated here: + * when LINUXKM_LKCAPI_REGISTER, wolfcrypt/test/test.c is built into the + * module and its slhdsa_test() supplies per-set keygen KATs, a + * SHAKE-128S deterministic-signature KAT (verify-reachable even in + * WOLFSSL_SLHDSA_VERIFY_ONLY builds), and per-set sign/verify + * roundtrips, all inside the module boundary. The tests here exercise + * the LKCAPI plumbing per registered set: + * + * - sign-capable builds: a transient wolfCrypt keypair is generated + * tester-side (wc_SlhDsaKey_MakeKey), then fed through the glue -- + * set_pub/set_priv key-size discipline, size callbacks, glue sign, + * glue verify, corrupt-signature and truncated-signature -EBADMSG, + * and short-dst -EOVERFLOW. No KAT rodata. + * + * - WOLFSSL_SLHDSA_VERIFY_ONLY builds have no in-module signer, so + * the accept path is covered by one embedded (pub, msg, sig) KAT + * for SHAKE-128S only (~7.9 KB, mirroring test.c's economy; + * wolfCrypt-generated, cross-validated byte-exact against OpenSSL + * master). All other sets exercise set_pub, the size callbacks, + * the reject path (a garbage signature of correct length -- this + * executes the full verification computation against the garbage + * public key, differing from the accept path only in the final + * comparison), wrong-size -EBADMSG, and the -EOPNOTSUPP sign-side + * stubs. A VERIFY_ONLY build with SHAKE-128S excluded therefore + * has no glue-level accept-path KAT (the same residual applies to + * test.c's own VERIFY_ONLY coverage, whose signature KAT is also + * 128S-only). + */ + +static const byte slhdsa_test_msg[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; + +#ifndef LINUXKM_SLHDSA_SIGN +#ifdef LINUXKM_SLHDSA_SHAKE_128S +/* the embedded VERIFY_ONLY accept-path KAT (SHAKE-128S). */ +static const byte slhdsa_shake_128s_kat_pub[] = { + 0x80, 0xcb, 0x67, 0x28, 0xec, 0xc4, 0xa6, 0xd1, + 0x93, 0xc0, 0x89, 0x6c, 0x07, 0x1c, 0x1c, 0xae, + 0xc8, 0x79, 0x1b, 0x9f, 0xc3, 0x36, 0x3c, 0x24, + 0x95, 0x3b, 0x48, 0xfb, 0x76, 0x4e, 0x5b, 0xf4 +}; + +static const byte slhdsa_shake_128s_kat_sig[] = { + 0x0b, 0x76, 0xd0, 0xb3, 0xcd, 0x2c, 0xbc, 0x02, + 0xb0, 0xc8, 0x23, 0x50, 0x1f, 0xb8, 0xbe, 0xa7, + 0x52, 0xe1, 0x97, 0x7e, 0xb8, 0xb3, 0xb2, 0xc9, + 0x7b, 0xbb, 0xba, 0x26, 0xdb, 0xbc, 0x77, 0x6d, + 0xe0, 0x90, 0x9e, 0x8d, 0xc0, 0x1b, 0x89, 0xb4, + 0x8d, 0x1b, 0xbe, 0xed, 0x9f, 0x3e, 0x15, 0xfd, + 0xba, 0xee, 0xfc, 0xdb, 0xed, 0xe2, 0x25, 0x92, + 0x53, 0x92, 0x5b, 0x61, 0x3d, 0xff, 0xe0, 0x40, + 0xd2, 0x08, 0xd1, 0x1b, 0x89, 0x7e, 0x67, 0x48, + 0x8f, 0x42, 0xad, 0xba, 0x8a, 0x20, 0x59, 0xbd, + 0xb0, 0x57, 0x46, 0x85, 0x1c, 0xf6, 0xd3, 0x89, + 0xe6, 0x5e, 0x4a, 0x26, 0xed, 0xd9, 0x57, 0xa7, + 0x97, 0x85, 0x93, 0x04, 0x32, 0x5b, 0x02, 0x32, + 0x24, 0xc0, 0x11, 0x07, 0x95, 0x9f, 0x98, 0xeb, + 0x52, 0xd0, 0xc7, 0xfb, 0x5c, 0xad, 0x2a, 0x4e, + 0x2d, 0xaf, 0x99, 0x18, 0x8b, 0xa0, 0x25, 0x18, + 0x3f, 0xba, 0x95, 0x50, 0x32, 0xb9, 0xe8, 0x04, + 0x03, 0xfb, 0x32, 0xb3, 0xdf, 0x7d, 0x9e, 0xe8, + 0x55, 0xb6, 0x48, 0xdd, 0x66, 0x6c, 0x33, 0xe3, + 0x69, 0xde, 0x0c, 0xc7, 0xa0, 0xbe, 0xc1, 0xba, + 0x8c, 0xaa, 0x03, 0xb7, 0x54, 0xaa, 0x80, 0x8d, + 0x56, 0x6a, 0x9a, 0x58, 0x15, 0xfa, 0xd5, 0xab, + 0xa4, 0x7f, 0xf4, 0x1e, 0xc3, 0x87, 0xf8, 0xea, + 0x6d, 0x53, 0x65, 0x8c, 0x53, 0x98, 0xaf, 0x5a, + 0x96, 0xbd, 0x87, 0x44, 0x0d, 0xf4, 0x8b, 0xc5, + 0xc9, 0xab, 0xe9, 0xfa, 0x51, 0x39, 0x89, 0x33, + 0xf2, 0xa5, 0x35, 0xf7, 0xb6, 0xe1, 0xd8, 0x31, + 0x51, 0x04, 0x2c, 0x02, 0x2a, 0x9a, 0x45, 0x9b, + 0x22, 0xbb, 0xc7, 0xa4, 0x2b, 0x6a, 0x4d, 0x71, + 0x79, 0xe8, 0xe1, 0x97, 0x69, 0x5d, 0xa1, 0x05, + 0x21, 0xc5, 0x4b, 0xae, 0xf7, 0xf7, 0xb3, 0x0a, + 0xf8, 0x4e, 0xd3, 0x8e, 0xb9, 0x51, 0x13, 0xab, + 0xb8, 0xbf, 0x35, 0x97, 0x33, 0x3b, 0x61, 0xc5, + 0x41, 0xa1, 0x70, 0xc9, 0x8c, 0x26, 0xa6, 0xc2, + 0xb6, 0x52, 0xf1, 0xbd, 0x36, 0xdf, 0x68, 0xbe, + 0x92, 0x7d, 0x91, 0xba, 0xd0, 0xd0, 0x2a, 0xef, + 0x35, 0x84, 0x11, 0x27, 0xc5, 0x38, 0xfd, 0x64, + 0xdf, 0x15, 0x57, 0xb3, 0x75, 0x1f, 0xcd, 0xd3, + 0x1f, 0x49, 0x6e, 0xbe, 0xa1, 0x48, 0xc9, 0x1b, + 0xb6, 0x68, 0xfa, 0x6a, 0xd1, 0xea, 0xa2, 0x4c, + 0xe5, 0x10, 0x4c, 0xa0, 0x48, 0x7f, 0xf6, 0x31, + 0x78, 0xfd, 0xb6, 0x5e, 0xc5, 0x74, 0xb6, 0x6f, + 0x38, 0xf0, 0x56, 0x38, 0xb4, 0x36, 0x81, 0x64, + 0x58, 0xc4, 0x36, 0x14, 0xc4, 0x79, 0x35, 0x84, + 0xc3, 0x7a, 0xb8, 0xcb, 0x8e, 0x70, 0x32, 0x03, + 0x2b, 0x18, 0x33, 0x5b, 0x7c, 0xa9, 0xcc, 0xa7, + 0x42, 0x98, 0x48, 0x49, 0xdc, 0x9a, 0xb9, 0x75, + 0x34, 0xab, 0xd6, 0x3c, 0x54, 0x4c, 0x83, 0xd2, + 0xdc, 0x3a, 0xaa, 0x61, 0x6d, 0x2b, 0xe9, 0xc7, + 0x9f, 0x30, 0x18, 0xfe, 0xff, 0x66, 0x21, 0x3b, + 0xac, 0x21, 0xee, 0x0a, 0x8b, 0x2a, 0xaa, 0x72, + 0x64, 0xfb, 0xb4, 0x90, 0xf4, 0xd1, 0x31, 0xf1, + 0x06, 0x3d, 0x0d, 0xaa, 0x78, 0xe8, 0x97, 0xaa, + 0x4c, 0x03, 0x3d, 0xd4, 0x4b, 0xde, 0x61, 0xe3, + 0xce, 0xc9, 0xe8, 0x14, 0x23, 0xe7, 0xdf, 0x1e, + 0x8c, 0x40, 0x1c, 0x0c, 0xb4, 0x3e, 0x96, 0x99, + 0x8f, 0x44, 0xc2, 0xfc, 0xce, 0xb2, 0xa4, 0x7b, + 0xd1, 0xf3, 0xdb, 0xc4, 0xd9, 0x3d, 0xaa, 0x31, + 0x54, 0x36, 0x4f, 0xc7, 0x26, 0x13, 0x1c, 0x8f, + 0xce, 0x4c, 0xe0, 0xd3, 0x66, 0x54, 0xd0, 0x42, + 0x3f, 0xd9, 0xc8, 0x25, 0x57, 0xc5, 0xac, 0xff, + 0xe0, 0xf8, 0x79, 0xdb, 0x03, 0x3e, 0x5e, 0x77, + 0xef, 0x4f, 0x9f, 0x6c, 0x5f, 0xe9, 0x67, 0x87, + 0x2c, 0xe0, 0x84, 0x5e, 0x64, 0xfa, 0x49, 0xd1, + 0x25, 0xe1, 0xca, 0x31, 0x6a, 0xa9, 0xb5, 0x32, + 0xdd, 0xe5, 0xfe, 0x3b, 0x7b, 0xde, 0xa2, 0x7a, + 0xb7, 0x51, 0x92, 0x08, 0x4a, 0x52, 0x4c, 0xc2, + 0xd0, 0x96, 0x99, 0x8f, 0x30, 0x7c, 0xf3, 0xa6, + 0x26, 0xc0, 0x40, 0x90, 0xa2, 0x8b, 0xfa, 0xb6, + 0x2d, 0x84, 0xa8, 0x5a, 0x1b, 0x46, 0x04, 0x99, + 0x59, 0x3e, 0xb9, 0xaf, 0xeb, 0x3d, 0xef, 0x3f, + 0x5a, 0xa1, 0x3f, 0xda, 0xfa, 0x07, 0xf1, 0x80, + 0x93, 0xaf, 0x47, 0x30, 0x03, 0xc0, 0x25, 0x1b, + 0x7c, 0x80, 0xc2, 0x3e, 0x6c, 0xc3, 0xbe, 0x83, + 0x2f, 0x86, 0xec, 0x1e, 0x88, 0x6d, 0x71, 0xaa, + 0x0b, 0x56, 0xe6, 0x53, 0x35, 0x73, 0x3d, 0x92, + 0x9c, 0x17, 0x78, 0xb0, 0x31, 0x42, 0xdb, 0x6a, + 0xb5, 0x59, 0x40, 0x66, 0x99, 0xe4, 0xad, 0xb9, + 0xb6, 0x00, 0xda, 0x5b, 0xdf, 0x5c, 0x73, 0xe9, + 0x0d, 0xea, 0x62, 0x7e, 0xe3, 0x6b, 0xff, 0xaf, + 0x30, 0x25, 0x36, 0xae, 0x60, 0xc1, 0xd2, 0x74, + 0xb1, 0xa1, 0x50, 0x59, 0xee, 0x7f, 0x2a, 0x70, + 0x0f, 0x61, 0x8f, 0xcb, 0x19, 0x71, 0xa6, 0x8a, + 0xae, 0xe2, 0x1a, 0x1a, 0xb6, 0xab, 0x42, 0x96, + 0xa6, 0x7c, 0x6e, 0xc5, 0x14, 0xbc, 0xf2, 0x5e, + 0xdc, 0x24, 0x3e, 0x2e, 0xb3, 0x24, 0x19, 0x30, + 0xdc, 0x55, 0xf6, 0x80, 0xed, 0x5a, 0x1e, 0x0f, + 0xe9, 0xe3, 0xb7, 0x10, 0xa3, 0xa1, 0xd1, 0x86, + 0x63, 0xe7, 0x14, 0xeb, 0x27, 0xd0, 0x7b, 0xdc, + 0x58, 0x16, 0xd7, 0xdc, 0x03, 0x96, 0xe4, 0x31, + 0x25, 0xb2, 0x99, 0xf1, 0x94, 0x24, 0x40, 0xe9, + 0x02, 0xc5, 0x0d, 0x64, 0xed, 0xb3, 0xcc, 0x23, + 0xf0, 0x51, 0xc4, 0x14, 0x53, 0x78, 0xd0, 0x3a, + 0xfb, 0x46, 0xe4, 0x44, 0x20, 0x76, 0xe7, 0x6b, + 0xd0, 0x29, 0x52, 0x44, 0xfb, 0x98, 0xfa, 0xc5, + 0xd9, 0x1d, 0x47, 0xa1, 0xe2, 0x31, 0xee, 0xae, + 0x95, 0xb4, 0x36, 0x8d, 0x37, 0xfe, 0xea, 0x6f, + 0xd9, 0x79, 0x7a, 0x2c, 0x18, 0x62, 0x43, 0x1e, + 0x58, 0xb8, 0x2d, 0xa6, 0x9f, 0xae, 0x6c, 0x0e, + 0x7e, 0xc5, 0xad, 0x9a, 0xfc, 0xf0, 0xb6, 0xbd, + 0xfc, 0x1c, 0x0d, 0xf5, 0x83, 0xac, 0x6d, 0x21, + 0x56, 0xd5, 0xa4, 0x3a, 0xa8, 0xc3, 0xea, 0xb8, + 0x65, 0x5c, 0x95, 0x4f, 0x9d, 0x03, 0x33, 0x57, + 0xdb, 0xb5, 0xd4, 0xb0, 0x94, 0x73, 0xaf, 0xaf, + 0xa4, 0x24, 0xda, 0xe8, 0x95, 0x00, 0xfc, 0x76, + 0x3c, 0x51, 0x95, 0x4a, 0xbb, 0x02, 0x09, 0x1b, + 0xe1, 0xf7, 0x57, 0xe9, 0x58, 0xe0, 0xb4, 0x20, + 0xfa, 0x37, 0xe4, 0x9e, 0x68, 0x84, 0xff, 0xbe, + 0xa6, 0x50, 0x81, 0x5e, 0xac, 0x62, 0x66, 0x1e, + 0x78, 0x19, 0xda, 0xc1, 0x2a, 0x57, 0xf1, 0xfc, + 0xd3, 0x2e, 0xe0, 0xec, 0x0e, 0xb2, 0x3f, 0x92, + 0x5d, 0xb8, 0x13, 0x21, 0xba, 0x79, 0xda, 0x69, + 0x83, 0x47, 0x2a, 0x42, 0xcc, 0xfd, 0x85, 0x2d, + 0xe9, 0x44, 0xbb, 0xdb, 0x0d, 0xdc, 0x4c, 0xb6, + 0x6e, 0xdc, 0x69, 0x2f, 0x1a, 0x1d, 0x6a, 0x7d, + 0x5b, 0x17, 0x71, 0x59, 0x24, 0x1b, 0x9e, 0xcc, + 0xec, 0x85, 0x49, 0xe5, 0x9d, 0xd7, 0xeb, 0x15, + 0xb6, 0xc3, 0xe9, 0x54, 0xb1, 0x4d, 0x94, 0xe8, + 0xc6, 0xdc, 0xd6, 0x47, 0xfe, 0x0f, 0x40, 0x9e, + 0x0b, 0xb5, 0x62, 0xff, 0x17, 0xa4, 0xea, 0x02, + 0xbe, 0xe1, 0x2d, 0x27, 0xe5, 0x54, 0xb9, 0x39, + 0x2c, 0x62, 0xe1, 0x1d, 0xef, 0x46, 0xcf, 0x58, + 0x55, 0x22, 0x36, 0xef, 0xe2, 0xc1, 0x95, 0x24, + 0x96, 0x75, 0xaf, 0x26, 0x23, 0x28, 0x00, 0xde, + 0xee, 0x1a, 0xcc, 0xe7, 0x5d, 0x25, 0xcd, 0xb5, + 0xaf, 0x24, 0x87, 0x53, 0xa1, 0x59, 0x98, 0x85, + 0x72, 0x90, 0x92, 0x98, 0x59, 0x5f, 0xc9, 0xbe, + 0x70, 0x4d, 0xe8, 0x6d, 0xa3, 0xbb, 0x53, 0x64, + 0x98, 0xf4, 0xba, 0xde, 0xac, 0x65, 0x88, 0x8e, + 0xca, 0xcd, 0x45, 0xfb, 0x32, 0x7e, 0xa0, 0xd1, + 0x5b, 0xb9, 0x46, 0x74, 0x5f, 0x20, 0xb0, 0xf0, + 0xd0, 0x48, 0x6e, 0xcc, 0x00, 0x92, 0xd9, 0x15, + 0xb8, 0x74, 0x38, 0xa5, 0x2f, 0x90, 0xf6, 0xb9, + 0xc7, 0x28, 0x36, 0xdc, 0xc4, 0x40, 0xd4, 0x06, + 0x59, 0x88, 0xa4, 0x66, 0x94, 0x22, 0x3c, 0xbd, + 0xd6, 0xfe, 0x37, 0x44, 0x16, 0x99, 0x6a, 0xc1, + 0xd3, 0x7d, 0xa8, 0x6f, 0x57, 0x88, 0x1b, 0x9d, + 0x72, 0xc3, 0x3f, 0xab, 0x9b, 0x34, 0x69, 0xeb, + 0x0c, 0x2f, 0x92, 0xcf, 0xbb, 0xf8, 0xba, 0x65, + 0x34, 0xae, 0xc8, 0x74, 0xaa, 0xf6, 0xde, 0x6a, + 0xc2, 0xe5, 0x83, 0xfa, 0xe9, 0x16, 0x6a, 0xf4, + 0x1a, 0x54, 0x51, 0x7e, 0x48, 0x2c, 0x7a, 0xf2, + 0xf0, 0x7c, 0xb5, 0x8c, 0xf9, 0x1f, 0x47, 0x5f, + 0x7a, 0xb4, 0xb8, 0x1b, 0x0f, 0x6f, 0x7a, 0xbc, + 0x52, 0xb0, 0x9b, 0x96, 0xee, 0x04, 0x31, 0x5c, + 0xf9, 0x58, 0xb5, 0x36, 0x1d, 0x5f, 0xe1, 0x7d, + 0x3e, 0x73, 0xc9, 0x42, 0x61, 0x44, 0x95, 0x05, + 0x9b, 0xbc, 0x7f, 0xf7, 0xff, 0xe8, 0x1c, 0xfc, + 0x77, 0xf2, 0x6e, 0xa7, 0x33, 0x61, 0xd9, 0xd3, + 0x16, 0xe6, 0x66, 0x66, 0x34, 0x85, 0xe4, 0xa7, + 0x3f, 0xb5, 0x70, 0xd0, 0x87, 0xa7, 0xf4, 0xf4, + 0xa5, 0x42, 0x33, 0x2a, 0xfc, 0x84, 0x13, 0x1c, + 0xb8, 0x2a, 0x69, 0xf3, 0x5c, 0x7d, 0x3b, 0x1f, + 0xb0, 0x03, 0xfa, 0xa7, 0x1d, 0x86, 0x09, 0x87, + 0xfb, 0x87, 0x98, 0xd1, 0xfe, 0x86, 0xbb, 0x98, + 0xe2, 0x6b, 0xbf, 0xe7, 0x1e, 0x66, 0xd6, 0x4c, + 0x39, 0xd8, 0x69, 0x7e, 0xcb, 0x61, 0x62, 0xeb, + 0x88, 0xf0, 0x71, 0x51, 0x0f, 0xd4, 0x37, 0x8b, + 0x3c, 0x97, 0x97, 0x0d, 0xa6, 0x91, 0x79, 0xf0, + 0x96, 0x90, 0xac, 0x97, 0x87, 0xf4, 0xbb, 0x05, + 0xac, 0xe2, 0x8b, 0xe7, 0x1a, 0x5c, 0x7d, 0x01, + 0xbc, 0x8a, 0x06, 0x0b, 0xe4, 0x9e, 0xb7, 0x05, + 0x70, 0x61, 0x23, 0xcf, 0x48, 0xc2, 0x62, 0xb2, + 0xa1, 0x7f, 0xde, 0x85, 0xcd, 0x4f, 0x82, 0x47, + 0x31, 0x1d, 0x58, 0xfe, 0x5b, 0xd2, 0x3e, 0xec, + 0x4b, 0xd2, 0xc8, 0x1b, 0xe9, 0x2e, 0x77, 0x64, + 0xc7, 0x18, 0x8f, 0xf5, 0xfe, 0x43, 0xe0, 0x5f, + 0x9e, 0xd6, 0x85, 0xfb, 0x7d, 0x0d, 0xc6, 0x28, + 0xae, 0x72, 0xa0, 0xc3, 0xe4, 0x44, 0xaa, 0xa1, + 0xbb, 0x4b, 0x60, 0x76, 0x78, 0x72, 0x87, 0x11, + 0xab, 0xe9, 0xe1, 0x44, 0xd7, 0xd3, 0xdb, 0xdf, + 0xae, 0x30, 0xe6, 0xb1, 0x58, 0xa3, 0x24, 0xdd, + 0xfb, 0x91, 0xe7, 0x74, 0xff, 0x7f, 0xda, 0x37, + 0xfb, 0x91, 0x3b, 0x92, 0x25, 0x37, 0x59, 0xda, + 0xf5, 0xe8, 0xea, 0x46, 0xa1, 0x3b, 0xef, 0x79, + 0x1e, 0x44, 0x73, 0xcc, 0xaf, 0xf5, 0x7c, 0xb8, + 0xf8, 0x70, 0x23, 0x6b, 0x24, 0x6b, 0x1e, 0x90, + 0x53, 0x21, 0x53, 0x8f, 0x76, 0x2a, 0x80, 0xe4, + 0xb4, 0xb4, 0x06, 0x8d, 0x03, 0x1d, 0x03, 0xdd, + 0x06, 0x8c, 0x36, 0x67, 0xa6, 0xfd, 0x04, 0x2b, + 0x8e, 0x04, 0xf0, 0xdf, 0x81, 0x9e, 0xc8, 0x09, + 0xec, 0x0d, 0x34, 0xae, 0x42, 0x2b, 0x5b, 0xaa, + 0xb4, 0x50, 0x95, 0x73, 0x8e, 0xa7, 0xd0, 0x91, + 0xfe, 0xa9, 0xcb, 0x8e, 0x3e, 0x01, 0x49, 0x64, + 0x89, 0x4c, 0x20, 0x74, 0xec, 0x7e, 0x76, 0xfe, + 0x81, 0xc2, 0x5b, 0x89, 0x63, 0xc0, 0xf5, 0x6a, + 0x99, 0x61, 0x83, 0xa5, 0x8d, 0x9d, 0x8e, 0x2a, + 0xef, 0x2d, 0x94, 0x57, 0x3d, 0x55, 0x2b, 0x8c, + 0x48, 0x9c, 0x99, 0x49, 0xe6, 0xb2, 0xff, 0x39, + 0xb3, 0xfe, 0x1e, 0xc7, 0x62, 0x08, 0x8f, 0x48, + 0x40, 0x5c, 0xff, 0x38, 0x4f, 0xef, 0xed, 0x7f, + 0xbd, 0x83, 0x46, 0x41, 0xe8, 0xb4, 0xfe, 0x26, + 0x64, 0xc7, 0xb9, 0x29, 0x3b, 0x92, 0xb3, 0x47, + 0x18, 0x34, 0xf6, 0x3a, 0xde, 0xc5, 0x1c, 0x5e, + 0x0f, 0x1c, 0x8b, 0xe1, 0xf7, 0xb7, 0xe3, 0x29, + 0xf1, 0x80, 0x77, 0x1a, 0x9c, 0x81, 0x01, 0x4a, + 0x91, 0xea, 0x4a, 0x22, 0x2e, 0x22, 0xf3, 0xe2, + 0x6b, 0x26, 0x4f, 0xe7, 0xf5, 0x29, 0xc9, 0xc8, + 0x93, 0xda, 0xfe, 0x69, 0x08, 0x63, 0x6c, 0x9c, + 0xac, 0x7b, 0x84, 0x10, 0xc2, 0x2d, 0xef, 0xad, + 0x85, 0x6c, 0xbe, 0x5f, 0xcd, 0x28, 0x17, 0x92, + 0x57, 0x1b, 0x99, 0xc8, 0x22, 0x30, 0x63, 0xcb, + 0x8f, 0xfd, 0x0c, 0x58, 0xd4, 0xfe, 0x29, 0xfe, + 0x24, 0x0e, 0x8b, 0x3f, 0xc7, 0xad, 0x01, 0xaa, + 0xcf, 0xdf, 0xaa, 0x8b, 0x15, 0xc7, 0x27, 0x37, + 0x1e, 0x60, 0x97, 0x90, 0x78, 0x91, 0x26, 0x3e, + 0xec, 0xf1, 0x7d, 0x51, 0x2f, 0x61, 0x51, 0xcd, + 0x6a, 0xa3, 0xd3, 0x62, 0x1a, 0x6b, 0x79, 0x81, + 0x7a, 0xac, 0xdc, 0x17, 0xb0, 0xb3, 0xe0, 0x36, + 0xee, 0xcc, 0x56, 0x96, 0xfc, 0x84, 0xd6, 0x7d, + 0x95, 0x82, 0xc3, 0xa7, 0x09, 0x65, 0x69, 0xc5, + 0x61, 0xf2, 0xfb, 0x0d, 0x2c, 0x99, 0xd7, 0xa6, + 0x36, 0x13, 0x0e, 0x70, 0x96, 0xb7, 0xe9, 0x6f, + 0x6a, 0x2c, 0xd3, 0xea, 0xb8, 0x31, 0xab, 0x0a, + 0xf4, 0x51, 0x00, 0x3f, 0xa9, 0xdc, 0x81, 0x0c, + 0x57, 0x9e, 0x84, 0x97, 0xc0, 0x86, 0xca, 0xdd, + 0xd2, 0xa5, 0x8d, 0x0d, 0x09, 0xbf, 0x6c, 0x97, + 0xa6, 0x74, 0x11, 0x9c, 0x75, 0xba, 0x54, 0x75, + 0x7b, 0x5d, 0x7d, 0xe5, 0xc4, 0x64, 0x76, 0x14, + 0xc0, 0x53, 0x2b, 0x2a, 0x97, 0xa4, 0x21, 0x3d, + 0xbc, 0xd7, 0xc0, 0xe4, 0xea, 0x9d, 0xe9, 0xde, + 0x13, 0xa6, 0x04, 0xb0, 0x11, 0x47, 0xca, 0x9c, + 0xf8, 0xea, 0x4a, 0xfc, 0x97, 0x24, 0xa6, 0x4a, + 0x3e, 0x77, 0xb0, 0x95, 0x71, 0xd6, 0x6b, 0x44, + 0x3e, 0x5c, 0x98, 0x6f, 0xc0, 0xda, 0xf4, 0xdb, + 0x0a, 0x4b, 0xd3, 0xc7, 0xbb, 0x3d, 0xf8, 0xd9, + 0xb0, 0x1c, 0x7e, 0x02, 0x44, 0x9b, 0x8d, 0x79, + 0x6f, 0xa4, 0x7c, 0x58, 0x3c, 0xa6, 0x87, 0x26, + 0xf1, 0xe4, 0x73, 0x0f, 0xeb, 0x06, 0x66, 0x50, + 0xb1, 0xe9, 0xb6, 0x90, 0x2f, 0xf2, 0x6d, 0x3f, + 0xdc, 0xb6, 0xe7, 0x79, 0x07, 0x13, 0xc8, 0x2a, + 0x71, 0x2b, 0x32, 0x29, 0x7a, 0x18, 0xc0, 0x5e, + 0x2a, 0x77, 0xc1, 0xce, 0x27, 0x69, 0xd1, 0xc3, + 0xe2, 0xd7, 0xa3, 0xe9, 0x10, 0xec, 0xd0, 0xb3, + 0xa0, 0x21, 0x05, 0x40, 0xa9, 0x7d, 0xcd, 0x3a, + 0x38, 0x8f, 0xc8, 0x0d, 0x8c, 0xd1, 0xf9, 0x1b, + 0xbd, 0x1a, 0x64, 0xf6, 0x61, 0x7e, 0x69, 0x13, + 0x84, 0xde, 0x15, 0x61, 0x91, 0xc0, 0x5d, 0x95, + 0x7f, 0xec, 0x5f, 0x20, 0xc5, 0xb7, 0xea, 0xd8, + 0x85, 0xfd, 0xf7, 0x97, 0x95, 0xb4, 0xdf, 0x07, + 0xb1, 0xd9, 0xac, 0x7a, 0x65, 0x77, 0x4a, 0x89, + 0x79, 0xb4, 0xb7, 0xcb, 0xfd, 0xd7, 0x4e, 0x43, + 0x66, 0x17, 0x66, 0x94, 0x5d, 0x45, 0x45, 0x22, + 0x9e, 0x9e, 0x74, 0x01, 0x15, 0x46, 0x42, 0xe2, + 0x66, 0xa0, 0xed, 0x2e, 0x06, 0x71, 0x93, 0xf1, + 0x84, 0xec, 0x53, 0xf5, 0xb7, 0xda, 0x73, 0x6b, + 0xd2, 0x13, 0x3e, 0xc5, 0x8f, 0xda, 0xf0, 0xa7, + 0xf8, 0x75, 0x00, 0x88, 0x6c, 0x03, 0xe3, 0x02, + 0x2d, 0xc9, 0xb0, 0x35, 0x2f, 0xa6, 0x52, 0x75, + 0x66, 0xcd, 0x18, 0xba, 0xb2, 0x97, 0xf6, 0xfd, + 0x1f, 0xcc, 0xc8, 0xb2, 0x6d, 0x7d, 0x96, 0x6d, + 0xa6, 0xac, 0xec, 0xe1, 0xe1, 0x3e, 0xe9, 0xdb, + 0x34, 0xf4, 0x48, 0x8c, 0xb8, 0x69, 0xec, 0xba, + 0x33, 0xa1, 0x65, 0x20, 0x13, 0x18, 0xb9, 0xfc, + 0x03, 0x69, 0x08, 0x8d, 0xa9, 0xe7, 0x34, 0x8a, + 0xc5, 0xfc, 0xcb, 0xbc, 0x68, 0x4e, 0xde, 0x55, + 0x6c, 0x9a, 0xd7, 0x7e, 0x9b, 0xb8, 0xb2, 0x3b, + 0x95, 0xfd, 0xbe, 0x7a, 0xa4, 0xec, 0x5c, 0x8e, + 0xcc, 0xaf, 0x83, 0xa4, 0x0d, 0x30, 0x54, 0x5a, + 0xf3, 0x06, 0xf7, 0x4e, 0xa4, 0x86, 0xab, 0xdd, + 0x56, 0xd2, 0x99, 0x9b, 0x99, 0xaa, 0xb3, 0xf2, + 0xa2, 0x6f, 0xdd, 0xa0, 0x5b, 0xde, 0x7c, 0x25, + 0xf9, 0xd0, 0xc8, 0xa9, 0x38, 0x3b, 0xaf, 0x90, + 0x97, 0x80, 0x2f, 0xe1, 0x73, 0x2d, 0x3f, 0x82, + 0x30, 0x4d, 0x30, 0xd3, 0xdf, 0x5a, 0x74, 0x64, + 0xfa, 0xbf, 0x82, 0x75, 0xc9, 0xfe, 0xeb, 0x69, + 0x13, 0x17, 0xc1, 0xed, 0xbb, 0xd8, 0x0d, 0x21, + 0x65, 0x49, 0x57, 0x2f, 0x7a, 0xb5, 0xcd, 0x3f, + 0xfe, 0xbd, 0xa3, 0x61, 0x48, 0x9c, 0xaf, 0xb9, + 0xa8, 0x0d, 0xd4, 0x88, 0xa3, 0xcc, 0x1f, 0x80, + 0x0e, 0xb4, 0x2e, 0x48, 0xaf, 0x7f, 0xde, 0xa8, + 0x95, 0x1e, 0xfa, 0x58, 0x11, 0x64, 0x92, 0x88, + 0x35, 0x78, 0x09, 0xfa, 0x2c, 0xbf, 0x8e, 0xcb, + 0xd7, 0x5c, 0x91, 0xba, 0x02, 0x6c, 0x3d, 0x62, + 0xd9, 0x86, 0xb6, 0x25, 0x97, 0xfd, 0x20, 0x5a, + 0xe2, 0x7a, 0xcb, 0x88, 0xd3, 0x7a, 0xcb, 0x4e, + 0x0e, 0xe4, 0x4a, 0x36, 0x1b, 0x76, 0x0d, 0x75, + 0x05, 0x15, 0xeb, 0x37, 0x79, 0x14, 0xdb, 0x78, + 0x7b, 0x09, 0xd3, 0x57, 0xdf, 0x12, 0xdf, 0x11, + 0x75, 0xaa, 0xd0, 0x67, 0x66, 0xb7, 0x29, 0x3d, + 0xa3, 0xbf, 0x5b, 0xb2, 0xf5, 0x5e, 0x10, 0x59, + 0xd6, 0xe7, 0x05, 0x35, 0x52, 0x9b, 0xe1, 0x0d, + 0xe6, 0x9d, 0x22, 0x09, 0xeb, 0xeb, 0x90, 0x86, + 0x83, 0xb4, 0x65, 0x56, 0xd4, 0xfb, 0x1f, 0x3f, + 0x0c, 0x53, 0x7c, 0xeb, 0x9e, 0x75, 0xdb, 0x0a, + 0x3b, 0x15, 0x54, 0x55, 0xcb, 0x79, 0x8f, 0x67, + 0x25, 0xbe, 0xca, 0x82, 0x08, 0x3f, 0x14, 0xcc, + 0xa3, 0x2e, 0x0c, 0x59, 0xb4, 0xa9, 0xbe, 0xe8, + 0x63, 0x96, 0xc5, 0xa9, 0xc7, 0xbf, 0xb4, 0x07, + 0x75, 0x2a, 0xd9, 0x6f, 0x71, 0x67, 0x6e, 0xa5, + 0x18, 0x37, 0x5b, 0x34, 0xd7, 0x93, 0xb6, 0x72, + 0xe3, 0x0d, 0x44, 0xad, 0xb8, 0x11, 0xbf, 0xb1, + 0xcf, 0x9e, 0xca, 0x7d, 0x05, 0xad, 0x69, 0x8a, + 0x1e, 0x4c, 0x43, 0x4a, 0xbd, 0x3e, 0x58, 0x82, + 0x51, 0x16, 0x84, 0x61, 0x5d, 0x28, 0x9f, 0x99, + 0x71, 0x50, 0x19, 0x0e, 0x49, 0x42, 0x6b, 0xd7, + 0x80, 0xe5, 0xad, 0xc7, 0x88, 0x37, 0x55, 0xa3, + 0x4e, 0xeb, 0xb6, 0x96, 0xfa, 0xc5, 0x05, 0x02, + 0xc7, 0x24, 0x10, 0xb3, 0x99, 0x77, 0xe6, 0x7a, + 0x4c, 0x70, 0x4f, 0x95, 0xe0, 0x9e, 0x42, 0xbe, + 0x3c, 0x21, 0xd2, 0x80, 0xf5, 0xd8, 0xba, 0xaf, + 0x19, 0x22, 0x36, 0x8a, 0x03, 0x43, 0xd7, 0xba, + 0xb8, 0x2e, 0x17, 0x1c, 0x73, 0x3b, 0xb2, 0x97, + 0x39, 0xda, 0xd3, 0x77, 0x2b, 0xdb, 0x68, 0x43, + 0x4d, 0x3c, 0x42, 0x30, 0x7f, 0xe4, 0x28, 0x03, + 0x3e, 0xb8, 0x73, 0x65, 0x82, 0xda, 0x40, 0x3d, + 0xc3, 0x09, 0x9d, 0xdb, 0x31, 0xcd, 0xd0, 0xeb, + 0x5d, 0x7b, 0xb9, 0x73, 0xea, 0xfb, 0x25, 0xd1, + 0x35, 0x26, 0xed, 0xf9, 0xcd, 0xfe, 0x4e, 0xbf, + 0x66, 0x56, 0xa5, 0x2f, 0x82, 0x6a, 0x46, 0x43, + 0x79, 0xa9, 0xcc, 0x18, 0x60, 0x24, 0x92, 0xe5, + 0x94, 0x72, 0xa8, 0x37, 0x39, 0x57, 0xd6, 0xd7, + 0xa1, 0x7c, 0xb0, 0x8c, 0xc2, 0xfa, 0x03, 0xa0, + 0x48, 0xa6, 0x16, 0xcb, 0xb6, 0x52, 0xf9, 0x7f, + 0x27, 0xff, 0x17, 0x58, 0xc1, 0xf3, 0x68, 0x4a, + 0xe8, 0x7f, 0x38, 0x61, 0x46, 0xe2, 0x27, 0x79, + 0x3a, 0x8f, 0x36, 0x95, 0x60, 0x56, 0x92, 0xf9, + 0x1d, 0xe1, 0x27, 0xdf, 0xf0, 0x1e, 0x89, 0xb8, + 0x69, 0xe2, 0x7f, 0x63, 0xe2, 0x3c, 0x39, 0x06, + 0x70, 0xb8, 0x35, 0x0e, 0xd1, 0x6e, 0xcb, 0x1b, + 0x35, 0x9f, 0xc4, 0x3a, 0x68, 0x6a, 0x58, 0x59, + 0xe8, 0xa1, 0x22, 0x10, 0x32, 0xc3, 0x4b, 0xdb, + 0x3a, 0xf8, 0x57, 0x3d, 0xc0, 0x34, 0xe0, 0xd8, + 0x49, 0x37, 0xd4, 0xc6, 0xe2, 0xed, 0x60, 0x5e, + 0x1e, 0x43, 0x3d, 0x77, 0x9f, 0x25, 0xdc, 0x49, + 0xe0, 0xdb, 0x3e, 0xcd, 0x26, 0x27, 0x6e, 0x83, + 0xf9, 0x13, 0xc1, 0x9f, 0x22, 0x57, 0x23, 0xda, + 0x62, 0x48, 0x13, 0x82, 0x4a, 0x44, 0x95, 0x59, + 0x6f, 0xd4, 0x7c, 0x08, 0x95, 0x8e, 0x36, 0x8b, + 0x3c, 0x91, 0x2f, 0x36, 0x04, 0xd6, 0x8f, 0xa8, + 0xc5, 0xea, 0xa6, 0xec, 0x22, 0xb1, 0xc5, 0xc9, + 0xed, 0x9b, 0x0b, 0xe9, 0x5a, 0xcd, 0x7b, 0x97, + 0x7e, 0xcd, 0x24, 0x9d, 0xd4, 0x23, 0xaa, 0xfb, + 0x70, 0xcd, 0x7b, 0xfc, 0xe3, 0xaf, 0xd7, 0xa0, + 0x2b, 0xd5, 0x7e, 0x05, 0x8d, 0x65, 0xff, 0x1e, + 0xd0, 0x89, 0x9a, 0xd6, 0xc8, 0x8e, 0x6b, 0x10, + 0xc2, 0xc9, 0x0b, 0xa0, 0xfb, 0xfb, 0xcb, 0x84, + 0x44, 0x21, 0x9b, 0x29, 0xfe, 0xcc, 0xcb, 0xba, + 0x15, 0xcd, 0x6c, 0x94, 0xd0, 0x7f, 0xfc, 0x83, + 0xdd, 0x82, 0x24, 0x08, 0x3b, 0x02, 0xb0, 0x6e, + 0x3b, 0x8b, 0x84, 0xb8, 0x81, 0x35, 0x23, 0xc1, + 0x7e, 0xfb, 0x29, 0x0b, 0xe9, 0x03, 0xb1, 0x24, + 0x99, 0x72, 0x61, 0x16, 0x9d, 0x71, 0xdb, 0x88, + 0x39, 0xee, 0xef, 0xc4, 0x64, 0xa0, 0xc9, 0xc0, + 0x96, 0xc5, 0xd1, 0xca, 0x35, 0xae, 0x9b, 0x97, + 0x6b, 0x81, 0xa8, 0x7c, 0x80, 0x8c, 0xc0, 0xbc, + 0xc3, 0x79, 0x49, 0xb0, 0x57, 0x9e, 0x27, 0x3f, + 0xd3, 0x81, 0x84, 0xe4, 0x04, 0x1f, 0xd3, 0xad, + 0x3b, 0xa6, 0x81, 0x2e, 0x1d, 0xc7, 0x3f, 0x1f, + 0xdc, 0x5e, 0x8e, 0x03, 0xc3, 0xaf, 0xf9, 0x7a, + 0xfa, 0x54, 0xa4, 0x57, 0x3f, 0xc0, 0xfe, 0x9a, + 0x18, 0x90, 0xb2, 0x56, 0x7b, 0xa0, 0x4e, 0x78, + 0x76, 0x02, 0x47, 0x01, 0xa4, 0x33, 0x09, 0xee, + 0x69, 0x73, 0xbf, 0x93, 0x30, 0x53, 0xc0, 0x08, + 0x5a, 0x86, 0x6c, 0x99, 0xcf, 0xa3, 0x35, 0x8e, + 0x7b, 0xf4, 0x7d, 0xc5, 0x44, 0xda, 0x5a, 0x36, + 0x02, 0xba, 0x02, 0xc7, 0xea, 0x7a, 0x34, 0x2f, + 0x57, 0x51, 0xa5, 0x6f, 0x7b, 0xe1, 0xe3, 0x54, + 0x07, 0xab, 0x58, 0xf8, 0x35, 0xe2, 0x9a, 0x17, + 0x55, 0xe4, 0x38, 0x21, 0xf1, 0x3d, 0x6d, 0x8f, + 0x1f, 0xf3, 0x2b, 0x40, 0xa6, 0xba, 0x78, 0xca, + 0xec, 0x72, 0x4c, 0xb2, 0x9e, 0x3a, 0x2f, 0x69, + 0xbe, 0x00, 0xd9, 0x3d, 0xe0, 0x6b, 0xae, 0x81, + 0x78, 0xbf, 0xd7, 0x90, 0x31, 0xe5, 0xb0, 0x3b, + 0x1f, 0xd0, 0x74, 0x0c, 0x8a, 0xd3, 0x68, 0x34, + 0x9a, 0x70, 0x88, 0x2d, 0xbe, 0xf1, 0x2d, 0x89, + 0x3b, 0x74, 0x13, 0x95, 0x3c, 0xf2, 0x39, 0x5b, + 0xfc, 0x6d, 0xaf, 0xe9, 0x96, 0xfd, 0x97, 0x45, + 0xc0, 0xae, 0xcf, 0xd9, 0xbc, 0xd6, 0xd8, 0xa3, + 0x6d, 0x6f, 0x39, 0xf7, 0xf6, 0xc7, 0x48, 0x14, + 0xe9, 0xfc, 0xd0, 0xd8, 0xa7, 0xe5, 0xdd, 0xda, + 0xd9, 0x56, 0x97, 0x88, 0xfa, 0xea, 0xb8, 0xd6, + 0xf8, 0xc4, 0x69, 0x34, 0xda, 0xf1, 0x74, 0x5b, + 0xe4, 0x2b, 0x5f, 0x1d, 0x93, 0xfb, 0x39, 0x50, + 0x25, 0xc7, 0x96, 0xf2, 0xf2, 0x48, 0x3b, 0x76, + 0x64, 0xea, 0x95, 0x66, 0x00, 0x18, 0xb3, 0xe4, + 0x0c, 0x9d, 0xe4, 0xe6, 0xe6, 0xf7, 0xcf, 0x68, + 0x66, 0x38, 0xa3, 0x8c, 0xd8, 0x80, 0xcd, 0x73, + 0x6c, 0x7c, 0xc9, 0x31, 0xa9, 0x5b, 0x02, 0x84, + 0x9f, 0x80, 0xd0, 0xbd, 0x12, 0x4d, 0xad, 0xb8, + 0x77, 0x03, 0x60, 0xd5, 0x63, 0xfc, 0x71, 0x9e, + 0x9e, 0xc0, 0x99, 0x03, 0x44, 0x0c, 0x93, 0x15, + 0xb9, 0x14, 0x6d, 0xa2, 0x25, 0x5e, 0x06, 0xec, + 0x03, 0xe3, 0xad, 0x82, 0xdf, 0xe6, 0xc7, 0x83, + 0x3b, 0x69, 0xe1, 0x4b, 0x96, 0x4b, 0x6c, 0xbe, + 0x76, 0xee, 0xaa, 0x11, 0xfb, 0xfa, 0xcc, 0x3a, + 0x29, 0x6a, 0x17, 0x6d, 0xfb, 0x8f, 0xc6, 0x3b, + 0x46, 0x81, 0x42, 0x1c, 0xbc, 0x33, 0xfa, 0x6a, + 0xb2, 0x69, 0x3f, 0xe6, 0x1b, 0x56, 0x00, 0x08, + 0x41, 0xf3, 0xa8, 0x52, 0x26, 0x24, 0xe7, 0xef, + 0xda, 0x07, 0xe1, 0x73, 0xf0, 0xb2, 0xbd, 0x70, + 0x6e, 0x72, 0x1d, 0x4b, 0x13, 0xe6, 0xbc, 0x63, + 0xfa, 0x59, 0x78, 0x9d, 0xc1, 0x7f, 0x95, 0x72, + 0xa5, 0x2e, 0x88, 0x49, 0xe6, 0xf2, 0xdd, 0x0b, + 0xff, 0x80, 0x98, 0xe4, 0x77, 0xf6, 0x81, 0xc3, + 0x6c, 0xf1, 0x25, 0x2f, 0x13, 0x92, 0x7c, 0xcb, + 0x7f, 0xcb, 0x6d, 0x08, 0xc6, 0xf5, 0x9c, 0x96, + 0x3d, 0x8b, 0xe6, 0xaa, 0xbd, 0xb3, 0xaa, 0x4e, + 0x38, 0x4f, 0x53, 0xf4, 0xc9, 0x6c, 0x1d, 0x5e, + 0x74, 0x89, 0x46, 0xa7, 0x03, 0xdc, 0x4d, 0x03, + 0x41, 0x5c, 0x64, 0xc4, 0x02, 0x40, 0xb5, 0xf2, + 0xd5, 0x43, 0x19, 0x47, 0x18, 0x42, 0xfa, 0x6a, + 0x1e, 0x3a, 0x1d, 0x9c, 0xa3, 0xbb, 0x70, 0xc0, + 0x63, 0x81, 0x13, 0xd3, 0xb2, 0x2d, 0x75, 0x51, + 0x09, 0x97, 0x73, 0xe6, 0x6f, 0xbd, 0x8a, 0xd0, + 0x5c, 0x4f, 0x77, 0x3f, 0x21, 0xa9, 0xe1, 0xfb, + 0x99, 0x40, 0xd7, 0xa5, 0x0a, 0x92, 0x30, 0x7d, + 0x24, 0xe6, 0xb2, 0xf2, 0x73, 0x6b, 0x67, 0x16, + 0xb9, 0x6f, 0x1c, 0x01, 0x04, 0x1b, 0x6a, 0xb1, + 0xa1, 0xb6, 0xdd, 0xe0, 0x66, 0xf9, 0x81, 0x6b, + 0x39, 0xec, 0x50, 0x1d, 0xf5, 0x01, 0x14, 0xcc, + 0xc1, 0x73, 0x67, 0x65, 0x73, 0x77, 0x66, 0x5a, + 0x9d, 0x3c, 0xa3, 0xc8, 0xf9, 0x77, 0xd1, 0xc0, + 0xf2, 0x61, 0x60, 0x49, 0x64, 0x3a, 0xfd, 0x14, + 0x3c, 0xb9, 0x63, 0xa5, 0x29, 0x95, 0x85, 0xd5, + 0xb9, 0xe5, 0xfe, 0x92, 0x44, 0xfa, 0x24, 0x6a, + 0x8d, 0x66, 0xd0, 0xcb, 0xa5, 0x99, 0x36, 0xb1, + 0x72, 0x9e, 0xd9, 0x85, 0xdb, 0x2d, 0x57, 0x46, + 0x93, 0x29, 0xa1, 0x72, 0xa4, 0x64, 0x65, 0xa1, + 0x91, 0x4b, 0xe1, 0xbd, 0xfe, 0xa1, 0x1b, 0x63, + 0x32, 0xe3, 0xf7, 0x7c, 0xb6, 0xa3, 0x08, 0xc5, + 0x4d, 0x71, 0xc2, 0xae, 0x11, 0xc7, 0x79, 0xf5, + 0x02, 0x0a, 0x72, 0xc9, 0xf0, 0x2b, 0xd4, 0x68, + 0x35, 0x25, 0x3f, 0xcc, 0x70, 0xe2, 0x87, 0xde, + 0xe7, 0xd6, 0xad, 0x45, 0x8c, 0x5e, 0x29, 0x6c, + 0xdd, 0xcc, 0x3b, 0x41, 0x16, 0x66, 0x41, 0x2a, + 0x12, 0xf1, 0x43, 0x67, 0x03, 0xa9, 0x20, 0xfd, + 0xba, 0x15, 0x99, 0xa3, 0x12, 0xa0, 0xac, 0x90, + 0x83, 0xb8, 0x85, 0x89, 0x40, 0xf8, 0xe9, 0xc9, + 0xf8, 0xc5, 0x0d, 0x94, 0x93, 0x7d, 0x9d, 0x20, + 0x16, 0x0d, 0x2e, 0x62, 0x61, 0x56, 0x39, 0xb5, + 0x80, 0xd0, 0x05, 0x00, 0x1b, 0x0e, 0xa6, 0x56, + 0x71, 0xca, 0xa5, 0x4f, 0xd7, 0xb0, 0xa5, 0x5c, + 0x61, 0xcd, 0xad, 0x66, 0xa1, 0x3a, 0x38, 0xb6, + 0x4c, 0xd9, 0xc7, 0xd2, 0xe9, 0x0d, 0x06, 0xab, + 0x5c, 0x7a, 0x17, 0x4f, 0x39, 0x30, 0x32, 0x7c, + 0x90, 0xbb, 0xdc, 0xad, 0x87, 0x7c, 0xb0, 0x3e, + 0xd2, 0xae, 0xd0, 0x1f, 0x07, 0x22, 0x63, 0xed, + 0x97, 0x30, 0x51, 0x70, 0x6e, 0x84, 0x6d, 0x8f, + 0xf2, 0xec, 0xe3, 0x73, 0x96, 0x55, 0x7a, 0x51, + 0xa1, 0x1e, 0x77, 0xcc, 0x8b, 0xd3, 0x11, 0x52, + 0x8a, 0xcb, 0xda, 0x13, 0x19, 0x85, 0x6f, 0x4d, + 0xa6, 0x76, 0x38, 0xed, 0x83, 0xa5, 0x00, 0x32, + 0x34, 0x24, 0xa5, 0xd1, 0x40, 0x01, 0x85, 0x79, + 0xbc, 0x02, 0xa7, 0x53, 0x02, 0x28, 0x92, 0x05, + 0x4a, 0x41, 0x78, 0x7d, 0x6e, 0xc5, 0xa3, 0x45, + 0x02, 0x49, 0xd1, 0x4c, 0x20, 0x28, 0x51, 0x7e, + 0x4b, 0xe4, 0x4b, 0xf3, 0xc4, 0x56, 0x09, 0xbf, + 0x28, 0x72, 0xe2, 0x4d, 0x22, 0xb0, 0x5a, 0x28, + 0xab, 0x85, 0xab, 0xdc, 0x2b, 0xc8, 0x34, 0x88, + 0xf3, 0x4d, 0x97, 0xac, 0xf7, 0x09, 0xdb, 0x2b, + 0x01, 0xa2, 0x08, 0xd3, 0x56, 0x49, 0xd8, 0xcd, + 0xc1, 0xb0, 0x9b, 0x92, 0xd3, 0xa3, 0x3c, 0x80, + 0x6a, 0x20, 0x60, 0x94, 0x5a, 0xbc, 0x25, 0x7a, + 0xdb, 0x88, 0xee, 0x02, 0x9f, 0x31, 0xe8, 0x02, + 0x65, 0x93, 0xf2, 0x5c, 0x18, 0x27, 0xcf, 0xfe, + 0x2b, 0x1c, 0x59, 0xc2, 0x2e, 0xb2, 0xad, 0xc6, + 0x62, 0x17, 0x36, 0x8f, 0xcf, 0xa6, 0xf7, 0xfa, + 0x0b, 0xbd, 0x1e, 0xc3, 0x79, 0xc6, 0xc8, 0x7e, + 0xad, 0x14, 0x50, 0xd7, 0x01, 0x0c, 0x93, 0x20, + 0x4c, 0x96, 0xb8, 0x13, 0x12, 0x22, 0x94, 0xfc, + 0x41, 0xbf, 0x62, 0x9d, 0x7f, 0xd1, 0x0e, 0xde, + 0x37, 0x9f, 0xcb, 0x66, 0xc3, 0x58, 0x85, 0x23, + 0x66, 0x0e, 0x61, 0x2b, 0xab, 0xf3, 0x85, 0x89, + 0x65, 0x20, 0xb3, 0x6b, 0x43, 0xc4, 0xc3, 0x50, + 0x5c, 0x3a, 0x3c, 0x9d, 0x9a, 0x58, 0x8b, 0x8c, + 0x97, 0x3c, 0xfd, 0x87, 0x66, 0x02, 0xac, 0xd9, + 0xa2, 0xfe, 0xcb, 0x63, 0x33, 0x51, 0x3f, 0x50, + 0xdf, 0xb1, 0xb8, 0x16, 0x59, 0x14, 0xee, 0xc4, + 0xa5, 0xdf, 0x3e, 0x86, 0x72, 0x87, 0xc6, 0xd1, + 0x38, 0x5e, 0x5d, 0x97, 0x04, 0x69, 0x76, 0x3c, + 0x3b, 0xb7, 0x51, 0x91, 0x4d, 0x41, 0xeb, 0x01, + 0x66, 0xfa, 0xd0, 0xb8, 0x8a, 0x63, 0x6b, 0x9c, + 0x0f, 0x73, 0xb4, 0xa4, 0x3b, 0xaa, 0xe2, 0x33, + 0x8b, 0xbc, 0x3e, 0x59, 0x91, 0xb3, 0x58, 0x87, + 0x48, 0x7a, 0xad, 0x08, 0x6e, 0x9e, 0x76, 0x45, + 0xe5, 0x89, 0xd4, 0x3e, 0xb2, 0x90, 0x74, 0xb7, + 0xbb, 0x37, 0x24, 0xe0, 0x9d, 0x86, 0x7e, 0x56, + 0x30, 0x27, 0xb4, 0xc1, 0xa7, 0xe8, 0xae, 0x48, + 0x56, 0x98, 0x68, 0xc1, 0x1f, 0x2d, 0xa5, 0x5c, + 0xbf, 0x16, 0x0a, 0x4e, 0xf8, 0x84, 0x67, 0x2a, + 0x12, 0x5a, 0x9d, 0x50, 0x6d, 0x86, 0x67, 0xda, + 0xaf, 0x93, 0xe7, 0x93, 0x96, 0xc2, 0xc0, 0x1f, + 0x1c, 0x00, 0xc5, 0xbc, 0x53, 0x28, 0x6e, 0xc3, + 0xe2, 0xfd, 0x5d, 0xbe, 0xd8, 0x3b, 0x13, 0x04, + 0x77, 0xd9, 0x47, 0x4e, 0x83, 0xec, 0x23, 0xb7, + 0x14, 0xe1, 0x78, 0x42, 0xe0, 0x3f, 0x78, 0x6e, + 0x89, 0xdc, 0xfe, 0xef, 0x95, 0xd7, 0x9a, 0xf1, + 0xb3, 0xf2, 0x53, 0xf1, 0xeb, 0xf0, 0x2a, 0x93, + 0x47, 0x0c, 0x30, 0x3b, 0x6c, 0xd1, 0x2d, 0xf5, + 0xb9, 0xba, 0xb4, 0x84, 0x35, 0xbc, 0x89, 0xc4, + 0x54, 0xa1, 0x45, 0x69, 0xab, 0xd6, 0x2e, 0xaa, + 0xd1, 0x80, 0x35, 0x32, 0x16, 0x54, 0x74, 0x6f, + 0xdf, 0xbb, 0xa0, 0xc0, 0x8f, 0x91, 0x67, 0xf9, + 0x93, 0x7b, 0x07, 0x5a, 0x10, 0xb2, 0x92, 0x67, + 0xdd, 0x77, 0xb3, 0x3c, 0x01, 0x33, 0xd7, 0x01, + 0xa3, 0xb3, 0x42, 0x41, 0xd3, 0x07, 0xf9, 0xde, + 0xac, 0xd3, 0xf2, 0xde, 0xfa, 0x8a, 0x5e, 0xee, + 0xa6, 0x46, 0xb9, 0xf5, 0xdd, 0xcd, 0xcf, 0xd8, + 0x35, 0xa1, 0x8a, 0xf2, 0x42, 0x89, 0x26, 0x80, + 0xc5, 0xa6, 0x14, 0x7e, 0xd4, 0xf4, 0xe6, 0x1d, + 0x19, 0xa8, 0xba, 0x4b, 0x7a, 0xe0, 0x50, 0xac, + 0xe0, 0x1c, 0x92, 0xe7, 0x81, 0x6b, 0x1e, 0x8b, + 0x6c, 0xfb, 0xc7, 0x4e, 0xed, 0x7d, 0x03, 0x22, + 0x0b, 0xe1, 0x93, 0xc3, 0xf8, 0x1e, 0xce, 0x87, + 0x99, 0x22, 0xd5, 0xf3, 0xf3, 0xbd, 0x01, 0x42, + 0x93, 0x5a, 0x30, 0x15, 0x9d, 0xda, 0xb9, 0xfd, + 0x3b, 0x63, 0x1f, 0x1e, 0xd4, 0x3b, 0xba, 0x89, + 0xd3, 0xa3, 0xe9, 0xaa, 0xed, 0xf2, 0x09, 0x3f, + 0x80, 0x5d, 0x96, 0xd6, 0x65, 0x72, 0xfc, 0xd1, + 0xbc, 0xb6, 0xb6, 0x8c, 0xf0, 0x45, 0x39, 0x0b, + 0xbf, 0xb0, 0xfa, 0xf2, 0x27, 0x98, 0xd8, 0x7d, + 0xa1, 0xee, 0xfa, 0x0e, 0xcc, 0x98, 0xce, 0x89, + 0x50, 0xff, 0x02, 0xe0, 0x83, 0x12, 0xa3, 0x15, + 0x47, 0xd6, 0x42, 0x93, 0x7c, 0xd1, 0xaf, 0x13, + 0xb2, 0xbe, 0xf3, 0xb8, 0x33, 0x7f, 0xd5, 0xa2, + 0x1f, 0x06, 0x1e, 0xc7, 0x5e, 0x03, 0x12, 0xed, + 0x94, 0x4a, 0xe8, 0x65, 0xd7, 0x26, 0xe6, 0xa6, + 0xd1, 0x52, 0xf1, 0x1f, 0x4b, 0x2d, 0xdb, 0x30, + 0x00, 0xa7, 0x40, 0xc2, 0x6c, 0x0e, 0xfb, 0x7b, + 0xe6, 0x1c, 0x34, 0xb4, 0xa4, 0xae, 0x02, 0xbd, + 0x34, 0x77, 0x57, 0x99, 0x00, 0xef, 0x3f, 0x75, + 0x63, 0x89, 0xe4, 0xc0, 0x3c, 0xce, 0x81, 0xe7, + 0xad, 0xc2, 0xb0, 0x13, 0x37, 0xeb, 0x92, 0x9f, + 0x37, 0x17, 0xde, 0x41, 0x43, 0x70, 0x16, 0x7e, + 0x69, 0x9d, 0xfe, 0xf0, 0x93, 0x30, 0xa1, 0xcc, + 0x50, 0xa0, 0x1e, 0x50, 0x71, 0x64, 0x80, 0xdb, + 0xfd, 0x7b, 0x52, 0x46, 0x07, 0x8c, 0x75, 0xbb, + 0x26, 0xec, 0xf8, 0x45, 0x85, 0x80, 0x0b, 0x38, + 0x2b, 0x57, 0x24, 0x20, 0x8e, 0x43, 0x4f, 0x22, + 0xae, 0x9e, 0xef, 0xa1, 0xa3, 0x62, 0x70, 0xc9, + 0x3e, 0x23, 0x8c, 0x81, 0x02, 0x33, 0x2d, 0xc5, + 0x81, 0x5a, 0x26, 0xa2, 0x9f, 0xcc, 0x3d, 0x3b, + 0x3c, 0xce, 0x53, 0x78, 0x90, 0x1b, 0x7c, 0x5a, + 0xe1, 0xd3, 0xf3, 0xa5, 0xfb, 0x6b, 0xaa, 0xa5, + 0xdc, 0x3c, 0x16, 0x50, 0x12, 0x6e, 0xb5, 0x6d, + 0x99, 0xf5, 0x66, 0xa0, 0x31, 0xcf, 0x75, 0x5e, + 0xe6, 0x18, 0x62, 0x4a, 0xcd, 0xef, 0xaa, 0xcd, + 0x5a, 0x78, 0x47, 0x77, 0x88, 0xc1, 0x2e, 0x92, + 0x1b, 0x9d, 0xe1, 0x1a, 0x56, 0x68, 0x01, 0x03, + 0xbc, 0x2c, 0x67, 0xfa, 0x8c, 0x69, 0xfa, 0xb9, + 0xda, 0xa1, 0xd6, 0xf2, 0xc2, 0x2a, 0x99, 0xc9, + 0x4c, 0xc2, 0x3c, 0x2d, 0x0f, 0xcf, 0x6f, 0x0f, + 0x16, 0xa2, 0x04, 0x39, 0xce, 0x49, 0xb2, 0xfa, + 0x8b, 0x4a, 0xf4, 0x51, 0x54, 0x38, 0xb0, 0x78, + 0xe1, 0x50, 0x71, 0xcc, 0xe2, 0x16, 0x9e, 0x7b, + 0x0f, 0x9b, 0x8e, 0x7c, 0x19, 0xf4, 0xd4, 0x9e, + 0xf9, 0x01, 0x01, 0x01, 0x26, 0x6f, 0xc6, 0x0d, + 0xed, 0xcc, 0x2a, 0x91, 0x7a, 0xd9, 0x6c, 0xa7, + 0xa4, 0x61, 0xff, 0xf1, 0xe3, 0xcc, 0x36, 0xcf, + 0x6b, 0x9f, 0x98, 0xba, 0xbe, 0xe2, 0x7d, 0x2a, + 0x19, 0xb4, 0x68, 0x9b, 0x9c, 0x12, 0x96, 0xd3, + 0x6c, 0x6a, 0xd9, 0x53, 0xde, 0x7c, 0xa4, 0x39, + 0xb6, 0x9e, 0x96, 0x5f, 0x8d, 0x03, 0x0d, 0xb9, + 0x58, 0x64, 0x55, 0x88, 0xc1, 0xbf, 0x09, 0xd6, + 0xa7, 0x74, 0x4a, 0x2e, 0xa4, 0x4d, 0x4f, 0xa5, + 0x5d, 0x86, 0xa4, 0xdf, 0x0c, 0xc8, 0xa0, 0x69, + 0x0b, 0x34, 0xa3, 0x34, 0xb7, 0x89, 0x02, 0xf8, + 0xbb, 0xbe, 0x23, 0x68, 0x5f, 0x9c, 0xd2, 0x58, + 0xef, 0x7d, 0x78, 0x68, 0x34, 0xd0, 0xe2, 0xac, + 0xc5, 0xaa, 0x3b, 0xdf, 0x61, 0xc4, 0x35, 0x3f, + 0x58, 0x22, 0xf9, 0xef, 0xb0, 0xbb, 0xc7, 0x1e, + 0x35, 0x71, 0x71, 0x6d, 0xfb, 0xd7, 0xa8, 0x8a, + 0xb2, 0x80, 0xb1, 0xbe, 0x9a, 0x75, 0xc2, 0xff, + 0x51, 0xea, 0xc9, 0x7b, 0x39, 0x03, 0x6e, 0xcf, + 0x0f, 0x86, 0x46, 0xf6, 0x82, 0xf6, 0xc0, 0x88, + 0xb6, 0x04, 0xf0, 0xbf, 0xf9, 0x8e, 0xa6, 0x48, + 0xef, 0x36, 0xea, 0xbd, 0xdb, 0x95, 0xc9, 0x54, + 0x08, 0xd3, 0x76, 0xce, 0x0c, 0x76, 0x19, 0xb5, + 0x80, 0x94, 0x5a, 0x74, 0x0b, 0x72, 0x64, 0x91, + 0x83, 0xd0, 0x10, 0x04, 0xd6, 0x6b, 0x34, 0x3b, + 0x42, 0x51, 0x5d, 0x2f, 0xf2, 0xe4, 0xd0, 0xd8, + 0xfa, 0xf0, 0xdb, 0x96, 0x88, 0xcd, 0xf8, 0xd5, + 0xad, 0x84, 0xa8, 0xce, 0x87, 0x6d, 0x30, 0xdb, + 0x11, 0xf7, 0xab, 0x28, 0xd5, 0x2b, 0x64, 0x1f, + 0xea, 0xda, 0x86, 0x15, 0xd9, 0x8e, 0x67, 0xe9, + 0x6d, 0xca, 0x13, 0xf8, 0xa7, 0x4b, 0xa1, 0x44, + 0xf0, 0xaa, 0x5b, 0xd7, 0xe3, 0x97, 0xa5, 0x6a, + 0x2d, 0xb3, 0xbb, 0x0d, 0x7a, 0x90, 0x84, 0x3c, + 0xe9, 0xca, 0x73, 0x94, 0xa2, 0xc1, 0x31, 0xb7, + 0xeb, 0xae, 0x49, 0x6a, 0xb9, 0x55, 0x63, 0xd2, + 0x22, 0xb7, 0xf5, 0xa4, 0xea, 0x8e, 0xc7, 0x2a, + 0x48, 0x49, 0x89, 0x8b, 0x3c, 0x33, 0xd0, 0x6c, + 0x92, 0x99, 0xf4, 0xc6, 0x5a, 0xeb, 0x5d, 0xef, + 0x5b, 0x82, 0xb3, 0x95, 0xbc, 0xed, 0x50, 0x6f, + 0x6d, 0x49, 0xaf, 0x63, 0xb8, 0xa7, 0x08, 0xa8, + 0x56, 0xec, 0x9d, 0xb9, 0x00, 0x6b, 0xc7, 0x02, + 0x3e, 0xee, 0xb1, 0x04, 0x80, 0x89, 0x6c, 0xbf, + 0x18, 0x0a, 0x42, 0xb7, 0x9c, 0x84, 0xc6, 0xda, + 0x65, 0x25, 0xa3, 0x24, 0xb8, 0x62, 0x34, 0x4f, + 0xf4, 0xbf, 0x50, 0x27, 0xd4, 0x04, 0xfd, 0xf1, + 0x87, 0x3d, 0x62, 0x82, 0xf2, 0x24, 0xcd, 0xac, + 0x79, 0xf3, 0xde, 0xdd, 0xd7, 0xc9, 0x62, 0xf4, + 0x3d, 0x2d, 0xe4, 0x41, 0x83, 0x57, 0xac, 0x37, + 0x41, 0xbf, 0x46, 0x2d, 0x61, 0x06, 0x9b, 0x82, + 0x3c, 0x53, 0x51, 0xbe, 0xfa, 0xc3, 0x2f, 0x0b, + 0x7f, 0xf3, 0x70, 0xbf, 0x18, 0x70, 0xd6, 0x3a, + 0x06, 0xe7, 0x85, 0x64, 0xfa, 0x3f, 0x34, 0x0c, + 0x74, 0xab, 0x53, 0x32, 0xba, 0x8e, 0x89, 0x79, + 0x09, 0x4c, 0xe2, 0x43, 0xa0, 0x77, 0x47, 0xe9, + 0x84, 0x30, 0x1f, 0x3d, 0x37, 0xaf, 0xf6, 0x75, + 0x8f, 0x66, 0xac, 0xc6, 0xd4, 0x2a, 0xb8, 0xad, + 0x17, 0xd6, 0x04, 0x67, 0xc4, 0xa6, 0xc7, 0x98, + 0x8e, 0x9b, 0x63, 0x73, 0x65, 0x5f, 0xd0, 0xb2, + 0xe0, 0x8d, 0x59, 0x1c, 0x01, 0xe0, 0xe6, 0xe8, + 0xde, 0xe3, 0x15, 0xee, 0x13, 0x7b, 0xb2, 0x05, + 0x23, 0x07, 0xf5, 0x46, 0x21, 0x83, 0x7c, 0xc3, + 0x22, 0xd3, 0xb9, 0x44, 0xc1, 0xec, 0xe7, 0x75, + 0xf0, 0x92, 0xbf, 0x76, 0xb4, 0xef, 0x36, 0xcf, + 0x6a, 0x52, 0x17, 0xf0, 0xee, 0x88, 0xd2, 0x6a, + 0x9c, 0x9a, 0x64, 0x64, 0xa8, 0xdb, 0x64, 0x44, + 0x11, 0x41, 0x6d, 0x33, 0xd6, 0xb9, 0x55, 0x14, + 0x55, 0xa6, 0xc2, 0x9c, 0x26, 0xf2, 0x0c, 0x50, + 0x17, 0x86, 0x6f, 0x75, 0x63, 0xd4, 0x76, 0x43, + 0xfa, 0xa5, 0x06, 0x9e, 0x33, 0xe8, 0xba, 0xb9, + 0x59, 0x06, 0x0f, 0xe8, 0x34, 0xb6, 0xd4, 0xa7, + 0xb1, 0xb1, 0xbc, 0xf1, 0x97, 0xae, 0x49, 0x6a, + 0x4b, 0xc7, 0x8f, 0x55, 0x59, 0xdb, 0x36, 0xc8, + 0xb2, 0x1b, 0x87, 0xf4, 0xd0, 0x1b, 0x52, 0x42, + 0xc0, 0xee, 0xc4, 0x75, 0x6e, 0x81, 0x5d, 0x2e, + 0xcc, 0x1e, 0xa8, 0x1d, 0x26, 0x57, 0x39, 0xd2, + 0x6a, 0xb4, 0x6a, 0x18, 0x95, 0x8d, 0x6e, 0xee, + 0x38, 0x7c, 0xae, 0xbf, 0xf1, 0x08, 0xad, 0xaa, + 0x63, 0xee, 0xac, 0x64, 0xf4, 0x9f, 0x1c, 0xb4, + 0x28, 0xa3, 0x0a, 0xab, 0xac, 0x42, 0x7c, 0x4b, + 0x6b, 0xe4, 0x4a, 0x64, 0x4b, 0x98, 0x4d, 0xae, + 0x65, 0xe9, 0x84, 0xb7, 0x75, 0x2e, 0xa6, 0x7a, + 0x41, 0x26, 0xf2, 0x32, 0xf0, 0x3a, 0x26, 0x30, + 0x67, 0xd7, 0xbf, 0xe6, 0x5c, 0x7c, 0xa7, 0x7c, + 0x09, 0xf3, 0xbb, 0x93, 0x78, 0xbd, 0xdc, 0xe8, + 0xa4, 0xa8, 0x1f, 0x69, 0x34, 0x88, 0x7e, 0xfb, + 0x5c, 0xe9, 0x26, 0x4d, 0x79, 0x5e, 0x0c, 0xd0, + 0x56, 0xd1, 0x35, 0x4e, 0x8b, 0x1a, 0xb2, 0x62, + 0xf5, 0x13, 0xd2, 0x31, 0x44, 0xfb, 0xef, 0xfd, + 0xca, 0x7f, 0x98, 0x0d, 0xdf, 0x1f, 0x2a, 0xd0, + 0x46, 0x16, 0x41, 0xfb, 0x70, 0xf0, 0xf8, 0x9d, + 0x83, 0xdc, 0x6f, 0x9e, 0x98, 0xbd, 0x6e, 0x2d, + 0x85, 0x18, 0x6a, 0x6d, 0x53, 0xc1, 0xf5, 0xca, + 0x2f, 0x65, 0x1d, 0x67, 0xe8, 0xe2, 0xcd, 0xc7, + 0xba, 0xb0, 0x61, 0x36, 0xf1, 0xa7, 0x19, 0xf1, + 0xcc, 0xc2, 0x43, 0xa5, 0x50, 0xd7, 0xba, 0x6b, + 0x34, 0xf8, 0xa1, 0x1a, 0x82, 0xd6, 0xb1, 0x81, + 0x6d, 0x35, 0x8c, 0xe5, 0x32, 0x04, 0xd6, 0x2e, + 0x24, 0xec, 0x3b, 0xef, 0xe7, 0x13, 0xa7, 0xd1, + 0x8a, 0x9e, 0xf8, 0x6f, 0xd3, 0x80, 0x68, 0xf9, + 0x9c, 0x06, 0x49, 0x0e, 0x36, 0xfb, 0x32, 0xce, + 0xce, 0xdc, 0x8c, 0xb4, 0x51, 0x91, 0x9a, 0x28, + 0x15, 0xa2, 0x15, 0x3b, 0x50, 0x3d, 0xca, 0xf7, + 0x35, 0x89, 0x35, 0x48, 0x40, 0x4a, 0xc8, 0x17, + 0x18, 0x71, 0xe1, 0xbb, 0x89, 0xcc, 0xd9, 0x26, + 0x45, 0xc7, 0x83, 0x24, 0x2a, 0xef, 0x50, 0xb8, + 0x11, 0x30, 0x8f, 0x7b, 0xf1, 0xe7, 0x0b, 0x13, + 0x07, 0x10, 0xdb, 0xfc, 0x27, 0xfc, 0xe2, 0x6a, + 0xfd, 0x81, 0xe8, 0xc8, 0x81, 0xf4, 0x8e, 0xd6, + 0xd8, 0x18, 0xc7, 0x50, 0x68, 0x40, 0x0f, 0x63, + 0xb6, 0x79, 0x05, 0x40, 0xcf, 0x8f, 0xa3, 0x5a, + 0xd5, 0x57, 0x3f, 0x04, 0xd3, 0x63, 0x44, 0x02, + 0x2c, 0xeb, 0x25, 0x08, 0xe6, 0xd9, 0x1e, 0x3b, + 0xee, 0x92, 0xb4, 0xeb, 0x93, 0xa2, 0x1d, 0x74, + 0xd4, 0x84, 0xb3, 0x4a, 0x15, 0x81, 0xe8, 0x68, + 0xae, 0xd6, 0x3b, 0x34, 0x50, 0x08, 0x76, 0xf6, + 0x76, 0x4c, 0x7d, 0xb5, 0xbc, 0xa7, 0x38, 0x06, + 0x48, 0x66, 0xe5, 0xa4, 0xdd, 0xa7, 0x40, 0x03, + 0xff, 0x9e, 0xdf, 0x08, 0x4c, 0xd3, 0xc6, 0x17, + 0x7b, 0x9f, 0xc0, 0xb0, 0xb2, 0xd6, 0x20, 0xa8, + 0x89, 0xf4, 0x07, 0x9b, 0x88, 0x1f, 0x0c, 0x85, + 0x42, 0x5f, 0x8e, 0xf1, 0x18, 0x1c, 0xe3, 0x4e, + 0xcd, 0xa3, 0x1f, 0x87, 0x0e, 0x8b, 0xd1, 0x2e, + 0x6b, 0x86, 0x84, 0xa9, 0x64, 0xa2, 0xde, 0x27, + 0xf5, 0x4e, 0x14, 0xda, 0x6f, 0x46, 0xe7, 0x71, + 0xbe, 0xf9, 0xe2, 0x8c, 0xfe, 0xc0, 0xa7, 0x4f, + 0x87, 0xfb, 0x7b, 0xfd, 0x8f, 0xaa, 0x4f, 0x6b, + 0x54, 0x39, 0x76, 0x97, 0xe4, 0xb0, 0x00, 0xf7, + 0x4d, 0xb5, 0x56, 0xbb, 0x0d, 0x45, 0x00, 0xeb, + 0xfa, 0x08, 0x78, 0xda, 0xb1, 0x53, 0x23, 0xb3, + 0x02, 0x6f, 0xef, 0xf6, 0xa5, 0xfd, 0x3f, 0x73, + 0xfe, 0x4f, 0xac, 0xfa, 0x48, 0xfd, 0x20, 0xea, + 0x1e, 0xb4, 0x31, 0x2f, 0x9d, 0x43, 0x6c, 0x77, + 0xc3, 0x68, 0x40, 0x0f, 0x3f, 0x36, 0x4a, 0x05, + 0x96, 0x34, 0xbd, 0x37, 0xee, 0x02, 0x39, 0xe7, + 0x8c, 0xf7, 0xb3, 0x26, 0x14, 0xf3, 0x5b, 0xe6, + 0x55, 0xe6, 0x2d, 0x56, 0x10, 0xc2, 0xb6, 0x0f, + 0x07, 0xf6, 0x5e, 0xaa, 0xf4, 0x8b, 0x68, 0x31, + 0xc4, 0x3b, 0x53, 0x0c, 0xfd, 0xc0, 0x53, 0x1b, + 0x67, 0x78, 0x4c, 0x79, 0xde, 0xc7, 0xe9, 0xc0, + 0xae, 0x59, 0xa2, 0xfc, 0xa7, 0x46, 0x15, 0xca, + 0x45, 0xc3, 0xab, 0xf3, 0xc1, 0x80, 0x00, 0xa4, + 0x42, 0xaf, 0x47, 0x88, 0x43, 0x85, 0x6c, 0x7a, + 0xfb, 0x00, 0xe3, 0x7f, 0x8c, 0x51, 0xb4, 0x55, + 0xaa, 0x8d, 0x47, 0x5a, 0xf0, 0xcd, 0x45, 0x09, + 0x89, 0x8f, 0x58, 0xc5, 0x32, 0x69, 0x90, 0x88, + 0x6f, 0x98, 0x60, 0x66, 0x51, 0x30, 0xb6, 0x3b, + 0xec, 0x02, 0x18, 0x02, 0x2a, 0xc2, 0x7c, 0xaa, + 0xbd, 0xf7, 0x52, 0xa8, 0x2f, 0x75, 0xe5, 0x47, + 0x52, 0xfd, 0x68, 0x75, 0x17, 0x8b, 0xd9, 0x27, + 0x0d, 0x82, 0xe0, 0xdd, 0x25, 0xd8, 0xd0, 0xc4, + 0x7d, 0x4a, 0xc1, 0xe5, 0x17, 0xe8, 0xdb, 0x0f, + 0x6d, 0xdf, 0x81, 0x5a, 0x71, 0xbc, 0xa7, 0xff, + 0x06, 0xf2, 0x5f, 0x0d, 0xf0, 0x7d, 0x56, 0xd3, + 0xfd, 0x57, 0xac, 0xec, 0xb3, 0xa8, 0xf3, 0x55, + 0xde, 0x2b, 0x32, 0x4b, 0x6a, 0x77, 0x2c, 0x45, + 0x14, 0x91, 0xba, 0xff, 0x1a, 0x81, 0xf3, 0xf1, + 0x2e, 0x13, 0xed, 0x1d, 0x27, 0xbd, 0x77, 0xaf, + 0x74, 0x55, 0x1a, 0x99, 0x5f, 0x5f, 0x75, 0xb1, + 0xaf, 0x8d, 0x02, 0x43, 0x57, 0x29, 0x97, 0xf6, + 0x60, 0xb0, 0xc4, 0x1b, 0x05, 0xc0, 0xc6, 0x73, + 0x09, 0x5c, 0x40, 0x75, 0xfe, 0x68, 0x32, 0xbd, + 0x14, 0xb9, 0x25, 0x5c, 0xed, 0xb5, 0xe8, 0x31, + 0xa2, 0x12, 0x78, 0xe9, 0xed, 0x8d, 0x13, 0xe8, + 0x2f, 0x17, 0x2c, 0xb6, 0xbc, 0x13, 0x1c, 0xc0, + 0xd3, 0xa0, 0x42, 0xde, 0xe3, 0x20, 0x56, 0xf8, + 0xa6, 0xd4, 0x71, 0x8e, 0x67, 0x58, 0x1d, 0xf9, + 0xd0, 0x29, 0x67, 0x38, 0x42, 0xcb, 0xac, 0x3e, + 0x7c, 0x55, 0x60, 0xf3, 0x36, 0xf1, 0x4f, 0x88, + 0xdd, 0x71, 0xf8, 0xd4, 0x64, 0xa1, 0xe7, 0x86, + 0x3e, 0xed, 0x7c, 0xf0, 0x4e, 0x18, 0x59, 0xeb, + 0xa6, 0x7b, 0x7f, 0x02, 0xee, 0xc1, 0x48, 0x55, + 0xad, 0xb8, 0x11, 0xa0, 0xe1, 0x87, 0xa4, 0x4c, + 0xc4, 0xb7, 0xf0, 0x56, 0x1d, 0x0d, 0x31, 0x65, + 0x91, 0x06, 0x48, 0x3f, 0x38, 0x69, 0xf0, 0x83, + 0x05, 0x7f, 0x65, 0xe4, 0xa5, 0xc0, 0x77, 0x56, + 0x5d, 0x3e, 0x3d, 0x82, 0xd5, 0x47, 0xdb, 0x62, + 0xd3, 0x7c, 0xa3, 0xd1, 0x17, 0x25, 0x10, 0xec, + 0xb6, 0xfb, 0x31, 0xa8, 0xa5, 0x7f, 0xa5, 0x31, + 0xe9, 0x70, 0x08, 0xea, 0x42, 0xa3, 0x3d, 0x3f, + 0xb2, 0xfd, 0xe0, 0x61, 0x45, 0x9d, 0xcd, 0x14, + 0xea, 0xb8, 0xbb, 0xd6, 0x09, 0x19, 0x09, 0x30, + 0xee, 0xcb, 0x8d, 0xc7, 0x36, 0x48, 0xcd, 0xa8, + 0x5e, 0xe4, 0xc9, 0xbd, 0xd2, 0xd4, 0x3c, 0x35, + 0x23, 0xf1, 0x99, 0x62, 0x50, 0xfe, 0x0e, 0xbe, + 0x2c, 0x5b, 0x2b, 0x73, 0x13, 0x6e, 0x4e, 0x4c, + 0x8e, 0xb3, 0xae, 0xfb, 0xe7, 0x3a, 0xae, 0x2c, + 0xb3, 0xcf, 0x97, 0xac, 0x54, 0xf1, 0x81, 0xb3, + 0x34, 0x7d, 0xfd, 0x4c, 0x0b, 0x13, 0xa3, 0xeb, + 0x33, 0xcc, 0x88, 0x65, 0xa4, 0xa4, 0xc5, 0x83, + 0x3f, 0x4c, 0xbc, 0x08, 0xf7, 0x7f, 0x93, 0x09, + 0x2e, 0xda, 0x36, 0x48, 0xcb, 0x14, 0x19, 0xe8, + 0x5a, 0xcf, 0xe1, 0xb4, 0x39, 0xaa, 0x79, 0x06, + 0x85, 0xa1, 0x04, 0x9a, 0x15, 0x41, 0x58, 0x29, + 0xf2, 0xc3, 0xc1, 0xbb, 0xc1, 0xd9, 0x0d, 0xd2, + 0x29, 0x2d, 0x81, 0x57, 0x0f, 0x0a, 0xb6, 0xb1, + 0x3e, 0x6f, 0x85, 0x8d, 0x94, 0x17, 0xcd, 0x04, + 0x5d, 0xad, 0xaa, 0xd1, 0x99, 0xc3, 0x52, 0x17, + 0x88, 0x09, 0x5f, 0x3d, 0x2e, 0xe8, 0x90, 0x80, + 0x7e, 0x4e, 0xee, 0xb6, 0x06, 0x01, 0xd4, 0xc8, + 0xfc, 0x26, 0x81, 0x77, 0x71, 0xe2, 0x65, 0xa1, + 0x9b, 0x62, 0x12, 0x78, 0x49, 0x39, 0x5e, 0xd1, + 0xc6, 0x57, 0x0f, 0x81, 0x13, 0x2d, 0x29, 0xec, + 0x63, 0x72, 0x6e, 0x93, 0x7a, 0xeb, 0x2c, 0x07, + 0x77, 0x97, 0x7b, 0x91, 0x71, 0x7e, 0xd0, 0x90, + 0xac, 0x68, 0xfe, 0x02, 0x42, 0x10, 0x32, 0xab, + 0x11, 0xfd, 0x37, 0xbc, 0xb0, 0xe7, 0xa5, 0x4f, + 0x21, 0x3d, 0x46, 0x24, 0x2c, 0x86, 0xf3, 0xae, + 0x91, 0xa7, 0x32, 0x65, 0xbb, 0xd0, 0xa6, 0x78, + 0x8c, 0x71, 0x17, 0x47, 0xaf, 0xfc, 0x4f, 0x18, + 0x55, 0xc9, 0xbd, 0x37, 0xf6, 0x02, 0x50, 0xa8, + 0x0d, 0x93, 0x61, 0xe4, 0x54, 0x01, 0x20, 0x54, + 0x37, 0xca, 0x3c, 0x20, 0x31, 0x7e, 0xda, 0xf3, + 0x5a, 0x3d, 0x4c, 0x0c, 0x3f, 0x41, 0xa5, 0x93, + 0x23, 0x64, 0x3b, 0xc3, 0xf8, 0xff, 0x40, 0x86, + 0x9e, 0x15, 0x15, 0x26, 0x66, 0x9e, 0xd8, 0x5e, + 0xbf, 0xda, 0xfc, 0x8b, 0x73, 0x71, 0x14, 0xa6, + 0x94, 0x37, 0xd7, 0x94, 0xb2, 0xf6, 0x3e, 0x2a, + 0xe7, 0xe7, 0xf7, 0x24, 0x58, 0x0c, 0xd6, 0xe0, + 0xb0, 0xed, 0xcd, 0x8a, 0xcf, 0xea, 0x9f, 0xa5, + 0x8a, 0xf2, 0x4b, 0xba, 0x12, 0x58, 0x7c, 0x3d, + 0xe4, 0x97, 0x79, 0xe2, 0x5e, 0x57, 0xbb, 0x1f, + 0x2d, 0xcd, 0x3f, 0xdf, 0xc8, 0x26, 0x0b, 0x0a, + 0x13, 0xc4, 0xac, 0xee, 0x2f, 0x85, 0xa9, 0x23, + 0x88, 0x22, 0x57, 0xbf, 0x99, 0x2d, 0xdf, 0x10, + 0xeb, 0x81, 0x7e, 0x29, 0xcd, 0x96, 0xbd, 0x75, + 0xcc, 0x1e, 0x18, 0x92, 0x89, 0x49, 0xc1, 0x88, + 0x53, 0x34, 0x06, 0x90, 0xa3, 0x3d, 0x34, 0x15, + 0x6a, 0xf9, 0x59, 0x11, 0xf2, 0x38, 0xee, 0xd8, + 0xa2, 0xd9, 0xdd, 0xe5, 0x2a, 0xf6, 0x87, 0x93, + 0x2b, 0x7d, 0x81, 0x91, 0xcf, 0xeb, 0xd7, 0xdd, + 0x4e, 0xc7, 0x08, 0xcb, 0x90, 0xea, 0x6c, 0x87, + 0xf3, 0x9a, 0x43, 0xaf, 0x76, 0x6c, 0x01, 0xd0, + 0xf9, 0x37, 0xbd, 0xec, 0x06, 0x3b, 0xc8, 0x42, + 0xe7, 0xa9, 0x91, 0x22, 0xbc, 0xef, 0x47, 0x48, + 0x9e, 0x63, 0x51, 0x55, 0x69, 0xbf, 0x24, 0xa3, + 0xaa, 0x18, 0x79, 0x4f, 0xf6, 0x99, 0x1c, 0xca, + 0x90, 0x25, 0x8f, 0x1c, 0xe9, 0x78, 0x31, 0xd6, + 0xe2, 0x18, 0x35, 0x9f, 0xe7, 0xfa, 0xb0, 0x61, + 0x52, 0x42, 0xcf, 0x5e, 0x03, 0xe0, 0xd4, 0x0a, + 0x55, 0x2f, 0x73, 0x49, 0x75, 0x63, 0x93, 0x2e, + 0xba, 0x9d, 0xca, 0x09, 0xe3, 0xe9, 0x6b, 0xd0, + 0x64, 0x32, 0x48, 0x03, 0x85, 0x86, 0x18, 0x3c, + 0xd3, 0x8a, 0x8b, 0xa4, 0x92, 0x04, 0xa7, 0xf5, + 0x7e, 0xc0, 0xf6, 0x74, 0x09, 0xa5, 0x20, 0x39, + 0x36, 0xf5, 0x31, 0x2b, 0x49, 0x2a, 0xf2, 0x3d, + 0x1d, 0x0a, 0xba, 0xa6, 0x96, 0xf9, 0x0d, 0x00, + 0x20, 0xf0, 0xf6, 0x8c, 0x96, 0x9e, 0x64, 0x26, + 0xca, 0x04, 0x98, 0x30, 0xd5, 0xcc, 0xc0, 0xb2, + 0xa8, 0x24, 0x7b, 0x46, 0x5d, 0xf5, 0x97, 0xa8, + 0x0a, 0xd0, 0x60, 0xb0, 0x6d, 0x64, 0x41, 0xe2, + 0x4f, 0xc4, 0x5d, 0xea, 0xce, 0xb7, 0x01, 0x0c, + 0xf1, 0x0d, 0x96, 0x9c, 0x1e, 0xc9, 0x0c, 0xe0, + 0x38, 0x1e, 0x9d, 0x6c, 0x86, 0xfc, 0x4c, 0x8f, + 0x45, 0x59, 0xbb, 0xb9, 0x75, 0xd2, 0xad, 0x70, + 0xdf, 0x46, 0x03, 0x3a, 0x3a, 0xe5, 0x28, 0x91, + 0x98, 0x8a, 0x4c, 0x80, 0x7e, 0xd8, 0xff, 0x2c, + 0x47, 0xf2, 0xdf, 0xde, 0x61, 0x2b, 0xfe, 0xe5, + 0x91, 0xe1, 0xae, 0x58, 0x4f, 0xe5, 0xa6, 0x08, + 0x1d, 0xdd, 0xb6, 0xab, 0x16, 0x85, 0x70, 0xc4, + 0x99, 0x80, 0xdd, 0xc6, 0xa1, 0x85, 0x08, 0x9d, + 0xa9, 0x67, 0xc3, 0x8f, 0x6a, 0xaf, 0xec, 0x90, + 0x2e, 0x8a, 0x3f, 0xd2, 0x36, 0xf6, 0xbc, 0x54, + 0x2e, 0xd9, 0x89, 0x2c, 0xec, 0xab, 0xf4, 0x6e, + 0x6f, 0x7a, 0x8b, 0x17, 0x63, 0x42, 0x13, 0x6d, + 0x55, 0x86, 0x4d, 0x7f, 0x8f, 0x39, 0xde, 0x1c, + 0x19, 0xa5, 0x92, 0x23, 0xb0, 0x5c, 0x28, 0xed, + 0x42, 0x27, 0x86, 0x85, 0x4f, 0xc4, 0xa6, 0x98, + 0xd7, 0xad, 0xc1, 0x5f, 0x34, 0x26, 0x5b, 0x26, + 0xbd, 0x41, 0xe3, 0x92, 0x9c, 0xf0, 0x36, 0xe9, + 0x13, 0x1d, 0xf2, 0x3d, 0xe9, 0xbd, 0x6d, 0xff, + 0xb4, 0x8f, 0x4b, 0x20, 0x28, 0xc2, 0xb2, 0x9a, + 0xc5, 0x66, 0x38, 0x3f, 0x0c, 0xbf, 0xc9, 0x5a, + 0xe1, 0xbe, 0xf7, 0xd5, 0x35, 0xab, 0xc5, 0xea, + 0x3b, 0x97, 0x2b, 0x94, 0xb2, 0xa5, 0xd5, 0x7e, + 0xac, 0x62, 0xb3, 0xd3, 0x29, 0xe4, 0xaf, 0x06, + 0x35, 0xc7, 0x97, 0x11, 0x3c, 0xc6, 0x88, 0x76, + 0x0a, 0xc4, 0x48, 0x98, 0x0f, 0xaf, 0xb8, 0xeb, + 0x4d, 0x2d, 0xa9, 0x57, 0xf8, 0xb1, 0xea, 0x08, + 0x3e, 0xef, 0x4e, 0x11, 0x1c, 0x95, 0xfa, 0x4e, + 0xb4, 0x05, 0x4d, 0xc8, 0x30, 0xdd, 0xbe, 0x86, + 0x1a, 0x47, 0x4f, 0x2e, 0x32, 0x16, 0x06, 0x44, + 0xbb, 0x8c, 0xbc, 0x7c, 0x75, 0x94, 0x40, 0x70, + 0x02, 0x8c, 0x05, 0xc9, 0x66, 0xa5, 0x83, 0xe7, + 0x82, 0x9c, 0x8a, 0x31, 0x6c, 0xcd, 0x7c, 0x65, + 0x5e, 0x22, 0xc5, 0xb8, 0x3b, 0x9a, 0xe1, 0x34, + 0x3d, 0x3b, 0x18, 0x46, 0xdc, 0x53, 0x59, 0xa7, + 0xe7, 0x26, 0xa9, 0x8f, 0xd1, 0xef, 0x32, 0xba, + 0xee, 0x4d, 0x75, 0x07, 0xa4, 0x23, 0x61, 0x3c, + 0x33, 0x76, 0x8c, 0x36, 0x03, 0x4c, 0x58, 0x45, + 0xad, 0x45, 0xef, 0x11, 0xca, 0xe5, 0x75, 0x15, + 0x3e, 0xa8, 0xc4, 0xac, 0x06, 0xb0, 0xe6, 0x19, + 0x32, 0x19, 0xfa, 0xd7, 0xe4, 0x91, 0xc9, 0x83, + 0x73, 0xf0, 0x3f, 0x6b, 0x00, 0x46, 0x80, 0x1b, + 0xe6, 0x65, 0x27, 0xd6, 0xa4, 0x5a, 0x38, 0x05, + 0xb6, 0x3d, 0xd6, 0x82, 0x92, 0xfc, 0xed, 0x8b, + 0xa0, 0xf4, 0x35, 0x55, 0xaf, 0x3b, 0x44, 0xf8, + 0x55, 0x6d, 0x59, 0x35, 0x04, 0xfb, 0x27, 0x31, + 0x47, 0x51, 0x78, 0x7b, 0xc2, 0x37, 0x5b, 0x83, + 0xa0, 0x08, 0x78, 0xd8, 0xb5, 0x87, 0xe8, 0x12, + 0x58, 0x21, 0xdc, 0xe0, 0xab, 0x12, 0xda, 0x86, + 0x56, 0x11, 0xa4, 0xac, 0xc3, 0xac, 0x14, 0x45, + 0xc3, 0x8f, 0x0b, 0x19, 0x55, 0x16, 0xa9, 0x3f, + 0xa9, 0x9a, 0x61, 0x89, 0x2d, 0x02, 0x61, 0xbd, + 0x4c, 0x1a, 0xf5, 0x51, 0xe5, 0x35, 0xf4, 0x59, + 0x8c, 0x06, 0x03, 0x6e, 0x16, 0x76, 0x37, 0xb8, + 0x32, 0x79, 0x00, 0x59, 0x22, 0x6b, 0x2d, 0xb7, + 0xa0, 0xa1, 0x9e, 0x2e, 0x1c, 0x19, 0x2a, 0x21, + 0xfc, 0x17, 0xc6, 0x37, 0xcf, 0x31, 0x8c, 0x57, + 0x3b, 0xbb, 0xc2, 0x9c, 0xcd, 0xf2, 0x7d, 0x45, + 0x2f, 0x5b, 0x4e, 0x7a, 0xa3, 0x41, 0x0c, 0xaf, + 0x16, 0xb1, 0x09, 0x16, 0xe7, 0xc0, 0xa5, 0x3b, + 0x84, 0x64, 0x1a, 0xfa, 0xaf, 0x31, 0xd1, 0x9a, + 0x24, 0xc9, 0xe6, 0xbe, 0x44, 0xed, 0xd4, 0xc2, + 0x0d, 0x32, 0xa6, 0xbf, 0x5f, 0x24, 0xef, 0xcb, + 0xaf, 0x60, 0x07, 0x85, 0x22, 0x94, 0xb5, 0xd8, + 0xcb, 0x5a, 0xd3, 0x4c, 0xf5, 0x7f, 0x71, 0x7c, + 0x28, 0x1b, 0x15, 0x8e, 0x7e, 0x3c, 0xc9, 0x4a, + 0x65, 0xdb, 0x8c, 0xc6, 0xca, 0x28, 0x0d, 0xfc, + 0xdf, 0xe9, 0x69, 0x05, 0xde, 0x0d, 0xa8, 0x62, + 0x36, 0xdc, 0xa4, 0x0a, 0xd7, 0xfb, 0x63, 0xa7, + 0xa7, 0xa5, 0x67, 0xab, 0x8d, 0xf8, 0xd6, 0x78, + 0x0a, 0xa4, 0x56, 0xa0, 0x1f, 0xe3, 0x32, 0x2e, + 0xe0, 0x57, 0xbe, 0x66, 0x2f, 0x23, 0x00, 0xdc, + 0x28, 0xf4, 0x04, 0xda, 0x6e, 0x46, 0xbb, 0x0e, + 0x85, 0x58, 0xd1, 0xc5, 0x03, 0xd5, 0xf8, 0x2f, + 0xee, 0x9e, 0x1b, 0x53, 0x9f, 0x11, 0x4d, 0xe7, + 0xb0, 0x30, 0xd3, 0xd2, 0x49, 0x28, 0x4e, 0x61, + 0x9d, 0xbd, 0xe2, 0x4c, 0xee, 0x3c, 0x6d, 0x24, + 0x0c, 0x8e, 0xd1, 0xdd, 0x63, 0x6f, 0x7c, 0xbb, + 0x9f, 0x0b, 0xbf, 0x3b, 0x2c, 0x4c, 0x6a, 0xac, + 0x15, 0xf5, 0xc7, 0x55, 0xaa, 0xa6, 0x8a, 0x65, + 0x9b, 0xad, 0xbf, 0xa5, 0xab, 0xdf, 0xdd, 0x24, + 0x5c, 0x43, 0xeb, 0x90, 0xd0, 0x14, 0xc3, 0x49, + 0x2a, 0x6f, 0x97, 0x81, 0x27, 0xc0, 0x26, 0xa6, + 0x1e, 0xae, 0x41, 0x28, 0x13, 0x34, 0xa2, 0x80, + 0xbf, 0x26, 0x87, 0xb4, 0xb3, 0xf0, 0xcf, 0xb0, + 0xa8, 0x98, 0xa2, 0x36, 0x2d, 0x11, 0xff, 0x36, + 0x8b, 0xa2, 0x72, 0xbe, 0xb8, 0xce, 0x0e, 0x50, + 0x78, 0xaa, 0x07, 0xf7, 0xed, 0xce, 0x35, 0x9a, + 0x59, 0xd1, 0x8d, 0xab, 0xae, 0x5f, 0xea, 0x8a, + 0x22, 0xaf, 0x29, 0xd2, 0x28, 0xd2, 0xe5, 0x3d, + 0x5f, 0xcd, 0x7f, 0x3b, 0x85, 0xe5, 0xe6, 0xe3, + 0x38, 0x8b, 0xce, 0x0b, 0xc9, 0x18, 0x6a, 0xb4, + 0xfd, 0xda, 0xaf, 0xca, 0xc7, 0x72, 0x9c, 0x91, + 0x64, 0x2a, 0x94, 0x8a, 0x71, 0xe0, 0x4c, 0xac, + 0x50, 0x5b, 0xbb, 0x10, 0xac, 0x2e, 0xc2, 0xfe, + 0x0e, 0x5e, 0xae, 0x8d, 0x2a, 0xa7, 0xc6, 0x76, + 0x6b, 0xfe, 0xe4, 0x6f, 0x42, 0x3b, 0x40, 0x1b, + 0x8b, 0x40, 0x2e, 0x32, 0x36, 0x76, 0xd9, 0x98, + 0xa4, 0xf4, 0xd3, 0x71, 0x37, 0x81, 0xcd, 0xf4, + 0x79, 0x5b, 0x9d, 0x02, 0x80, 0x0b, 0x9f, 0x0b, + 0xf3, 0xd2, 0xce, 0xca, 0xb6, 0xbb, 0xe9, 0xa4, + 0xce, 0xdf, 0x22, 0x00, 0x96, 0xc8, 0xd2, 0x59, + 0x5b, 0xdf, 0x32, 0xa5, 0xc5, 0x1d, 0xd4, 0x2b, + 0x0e, 0xe7, 0xa5, 0xe4, 0x74, 0xa2, 0x88, 0xd2, + 0x0f, 0xe3, 0x1b, 0xe5, 0x35, 0xe1, 0xcf, 0x7b, + 0x81, 0xf6, 0x59, 0x50, 0x1c, 0x56, 0x41, 0x52, + 0xea, 0xdf, 0x35, 0xae, 0xb6, 0x73, 0xc8, 0x3b, + 0x44, 0x88, 0xa9, 0xc8, 0x9c, 0x5c, 0x4f, 0x04, + 0x53, 0xa1, 0x3d, 0x67, 0xce, 0x91, 0xbe, 0xf0, + 0x68, 0xf7, 0x7a, 0x5b, 0x89, 0xfb, 0x43, 0x31, + 0xe0, 0xf3, 0x6a, 0x0c, 0x9d, 0xcc, 0xdb, 0xb5, + 0x99, 0x1c, 0x0d, 0x56, 0xc6, 0x64, 0x1d, 0xdb, + 0xdb, 0x8c, 0xf9, 0xb5, 0xb3, 0x36, 0xde, 0xee, + 0x0e, 0x1b, 0x88, 0x69, 0x4d, 0x45, 0xe2, 0x7f, + 0x2e, 0x68, 0x67, 0x2e, 0xae, 0xaa, 0xa5, 0x3f, + 0xee, 0xf0, 0x30, 0x6e, 0xb1, 0x64, 0x81, 0xff, + 0x1e, 0xd4, 0x82, 0xf0, 0xcc, 0xfb, 0x4e, 0x5f, + 0xb6, 0x8a, 0xd1, 0xbe, 0xbc, 0x0e, 0x57, 0xa5, + 0x07, 0xec, 0x1e, 0x93, 0xfd, 0x22, 0xcf, 0x78, + 0x27, 0x9a, 0xa9, 0x3e, 0x56, 0x77, 0xa1, 0x45, + 0x6f, 0x54, 0x20, 0x9b, 0x27, 0xd1, 0xe8, 0x93, + 0x5b, 0x8c, 0x6e, 0x1f, 0x32, 0x1e, 0x26, 0x69, + 0x5f, 0xc7, 0x87, 0xfd, 0x98, 0xc7, 0x68, 0xc5, + 0x9d, 0x96, 0x56, 0x4c, 0x7c, 0x02, 0xed, 0x6a, + 0xd9, 0x66, 0xe8, 0x6e, 0xf5, 0xd9, 0x04, 0xea, + 0x76, 0x91, 0xc4, 0xe3, 0xa9, 0x03, 0x53, 0x3a, + 0xc3, 0x27, 0xf2, 0x90, 0x41, 0xef, 0xdd, 0x10, + 0xf0, 0x2d, 0x88, 0x1d, 0xb3, 0xe3, 0xe3, 0x3f, + 0xc5, 0x98, 0x3d, 0xee, 0x7d, 0x84, 0xb3, 0x02, + 0xee, 0x69, 0x60, 0xc7, 0x8c, 0x27, 0x74, 0x5e, + 0xce, 0x45, 0xa3, 0xd2, 0x69, 0xc0, 0x50, 0x8a, + 0xa5, 0x2f, 0x35, 0x21, 0x50, 0x06, 0xf4, 0x2e, + 0x86, 0x89, 0x6e, 0xc7, 0xc6, 0x73, 0x7c, 0x09, + 0xa2, 0xb3, 0xff, 0x54, 0x47, 0x1f, 0xfc, 0x6c, + 0x3a, 0xb4, 0xb5, 0x6f, 0x91, 0x10, 0x6c, 0x56, + 0xc4, 0x7c, 0x73, 0xa2, 0x39, 0xc0, 0x71, 0xbd, + 0x10, 0x5b, 0x22, 0x79, 0x70, 0x28, 0x2a, 0x5e, + 0x43, 0xed, 0x01, 0xc5, 0x12, 0xa4, 0x64, 0x85, + 0x47, 0x35, 0x62, 0x5b, 0x37, 0x58, 0x86, 0xd7, + 0x83, 0x61, 0x3a, 0x7a, 0x4f, 0xd6, 0xf7, 0xd7, + 0x00, 0xab, 0xd8, 0x82, 0xad, 0x9b, 0xdf, 0x29, + 0x22, 0x34, 0xee, 0x8d, 0x8c, 0x05, 0xe6, 0x8c, + 0x4b, 0x47, 0x88, 0xdc, 0x5f, 0x3a, 0xf6, 0x5e, + 0x23, 0x06, 0x18, 0x1f, 0xc0, 0x03, 0x3f, 0x3e, + 0xcc, 0x9d, 0xcd, 0x71, 0x9d, 0x18, 0xf2, 0xec, + 0xec, 0x2c, 0x45, 0xf5, 0xa1, 0x73, 0x7d, 0xdc, + 0x26, 0x8a, 0x87, 0xd8, 0xcf, 0x6a, 0x7d, 0x15, + 0x2e, 0xfc, 0x00, 0x5c, 0x12, 0x2b, 0xa2, 0xb9, + 0xbd, 0xba, 0x15, 0x20, 0xb4, 0xf5, 0xdf, 0xe5, + 0xcd, 0x02, 0x51, 0xb6, 0x7e, 0x67, 0x38, 0x4f, + 0xc7, 0x5f, 0x39, 0x2b, 0xca, 0xc6, 0x2e, 0x14, + 0x0a, 0x02, 0xd3, 0xcb, 0x0c, 0xb2, 0x5e, 0xec, + 0x18, 0x80, 0x71, 0x77, 0x02, 0x0e, 0xd9, 0xc7, + 0xd1, 0x3b, 0xa6, 0xd4, 0x81, 0x48, 0x48, 0xaa, + 0xc2, 0xa1, 0x0e, 0x92, 0x54, 0x4f, 0x3f, 0xe7, + 0xc7, 0xe0, 0x6d, 0xa9, 0x31, 0x15, 0xb0, 0x64, + 0x87, 0xdf, 0x25, 0x8d, 0x99, 0xfa, 0xcb, 0xe2, + 0x0d, 0xaa, 0x82, 0x6c, 0x4d, 0x76, 0xd7, 0x61, + 0x1f, 0x94, 0x7d, 0x62, 0x4d, 0x0a, 0x94, 0xf5, + 0xfd, 0xc6, 0x8b, 0x77, 0x73, 0x7a, 0x53, 0x41, + 0x69, 0xbc, 0xb4, 0xc9, 0xa0, 0x27, 0x78, 0x1b, + 0x6c, 0x6a, 0x1f, 0xac, 0x0d, 0x31, 0x18, 0x7c, + 0xa9, 0x2b, 0x4e, 0x13, 0x35, 0xe1, 0x72, 0x03, + 0x06, 0x3f, 0x01, 0x55, 0xef, 0x98, 0xd0, 0x16, + 0x68, 0x0a, 0xb0, 0x2b, 0xb0, 0xfd, 0xca, 0xda, + 0xce, 0x03, 0x91, 0x25, 0x9e, 0xcc, 0x94, 0xd6, + 0x71, 0x69, 0x02, 0xa3, 0xa9, 0xcf, 0xee, 0x1a, + 0x2a, 0x0f, 0x7e, 0x8f, 0xa2, 0x4f, 0xbd, 0xce, + 0x17, 0x23, 0xd9, 0xd2, 0xc4, 0xbf, 0x43, 0x5c, + 0xa3, 0x48, 0x3d, 0x75, 0x46, 0x85, 0x89, 0x7f, + 0x41, 0x1d, 0xc0, 0x90, 0xd9, 0xba, 0xb9, 0x41, + 0x70, 0xfd, 0x15, 0xaa, 0x64, 0x3e, 0xbd, 0x05, + 0x74, 0x92, 0x34, 0x37, 0x27, 0x5d, 0x4d, 0xad, + 0x9c, 0xa4, 0x4c, 0x58, 0x32, 0x3a, 0xe1, 0x96, + 0x84, 0x07, 0xb7, 0xb7, 0x28, 0x5f, 0x19, 0xd0, + 0x9e, 0x56, 0xf1, 0xd9, 0x49, 0x30, 0x2a, 0x5b, + 0xf3, 0x89, 0xdc, 0x53, 0x7f, 0x7c, 0xd4, 0xfc, + 0x84, 0xf5, 0x1e, 0xbb, 0x42, 0x17, 0xac, 0xa2, + 0x67, 0x75, 0xc3, 0xd9, 0xe4, 0x14, 0x7c, 0x64, + 0x1a, 0xfa, 0x2e, 0x16, 0x6f, 0x20, 0xf2, 0xff, + 0x96, 0x31, 0xdc, 0x62, 0xce, 0x1c, 0x6c, 0xd6, + 0xcb, 0x6e, 0x7c, 0x84, 0x32, 0x8a, 0x24, 0x27, + 0x39, 0x4f, 0x94, 0x41, 0x7e, 0xa8, 0x56, 0x15, + 0xec, 0xe3, 0xbd, 0xce, 0x92, 0x77, 0x5b, 0x2e, + 0xef, 0x5a, 0x2f, 0x59, 0x04, 0x31, 0xff, 0xc1 +}; +#endif /* LINUXKM_SLHDSA_SHAKE_128S */ +#endif /* !LINUXKM_SLHDSA_SIGN */ + +/* obtain test vectors for one set. sign-capable: generate a keypair + * and export it; verify-only: zero (garbage) pub, no priv. *kat_sig is + * non-null only when an embedded accept-path KAT exists for the set. */ +static int linuxkm_test_slhdsa_get_vectors(int param, byte *pub, + word32 pub_len, byte *priv, + word32 priv_len, + const byte **kat_sig) +{ +#ifdef LINUXKM_SLHDSA_SIGN + SlhDsaKey * wc_key = NULL; + WC_RNG rng; + word32 out_len; + int err; + + (void)kat_sig; + + wc_key = km_slhdsa_new_wc_key(param); + if (! wc_key) + return MEMORY_E; + + err = LKCAPI_INITRNG(&rng); + if (err != 0) { + km_slhdsa_del_wc_key(wc_key); + return err; + } + + err = wc_SlhDsaKey_MakeKey(wc_key, &rng); + if (err == 0) { + out_len = pub_len; + err = wc_SlhDsaKey_ExportPublic(wc_key, pub, &out_len); + if ((err == 0) && (out_len != pub_len)) + err = BAD_STATE_E; + } + if (err == 0) { + out_len = priv_len; + PRIVATE_KEY_UNLOCK(); + err = wc_SlhDsaKey_ExportPrivate(wc_key, priv, &out_len); + PRIVATE_KEY_LOCK(); + if ((err == 0) && (out_len != priv_len)) + err = BAD_STATE_E; + } + + wc_FreeRng(&rng); + km_slhdsa_del_wc_key(wc_key); + return err; +#else /* !LINUXKM_SLHDSA_SIGN */ + (void)priv; + (void)priv_len; + XMEMSET(pub, 0, pub_len); + #ifdef LINUXKM_SLHDSA_SHAKE_128S + if (param == (int)SLHDSA_SHAKE128S) { + XMEMCPY(pub, slhdsa_shake_128s_kat_pub, + sizeof(slhdsa_shake_128s_kat_pub)); + *kat_sig = slhdsa_shake_128s_kat_sig; + } + #else + (void)param; + #endif + return 0; +#endif /* !LINUXKM_SLHDSA_SIGN */ +} + +#ifdef LINUXKM_SLHDSA_SIG_ALG + +static int linuxkm_test_slhdsa_driver(const char * driver, int param) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_sig * tfm = NULL; + byte pub[WOLFKM_SLHDSA_MAX_PUB_LEN]; + byte priv[WOLFKM_SLHDSA_MAX_PRIV_LEN]; + const byte * kat_sig = NULL; + byte * sig_buf = NULL; + word32 pub_len; + word32 priv_len; + word32 sig_len; + const byte * msg = slhdsa_test_msg; + const word32 msg_len = (word32)sizeof(slhdsa_test_msg); + + { + int len = wc_SlhDsaKey_PublicSizeFromParam((enum SlhDsaParam)param); + if (len <= 0) { + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + pub_len = (word32)len; + len = wc_SlhDsaKey_SigSizeFromParam((enum SlhDsaParam)param); + if (len <= 0) { + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + sig_len = (word32)len; +#ifdef LINUXKM_SLHDSA_SIGN + len = wc_SlhDsaKey_PrivateSizeFromParam((enum SlhDsaParam)param); + if (len <= 0) { + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + priv_len = (word32)len; +#else + priv_len = 0; +#endif + } + + ret = linuxkm_test_slhdsa_get_vectors(param, pub, pub_len, priv, + priv_len, &kat_sig); + if (ret != 0) { + pr_err("error: slhdsa test vector setup failed: %d\n", ret); + test_rc = ret; + goto test_slhdsa_end; + } + + sig_buf = (byte *)malloc(sig_len); + if (! sig_buf) { + pr_err("error: allocating sig buffer failed.\n"); + test_rc = MEMORY_E; + goto test_slhdsa_end; + } + XMEMSET(sig_buf, 0xa5, sig_len); + if (kat_sig) + XMEMCPY(sig_buf, kat_sig, sig_len); + + tfm = crypto_alloc_sig(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating sig algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_slhdsa_end; + } + + ret = crypto_sig_set_pubkey(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_sig_set_pubkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + { + /* keysize is bits on >= 6.15.3, bytes before (see + * km_slhdsa_key_size()); digestsize resolves to the pub key + * size in bytes in both eras (no digest_size callback). */ + unsigned int maxsize = crypto_sig_maxsize(tfm); + unsigned int keysize = crypto_sig_keysize(tfm); + unsigned int digestsize = crypto_sig_digestsize(tfm); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + unsigned int exp_keysize = pub_len * 8U; + #else + unsigned int exp_keysize = pub_len; + #endif + + if ((keysize != exp_keysize) || (maxsize != sig_len) || + (digestsize != pub_len)) + { + pr_err("error: crypto_sig_{max, key, digest}size returned " + "{%u, %u, %u}, expected {%u, %u, %u}\n", + maxsize, keysize, digestsize, sig_len, exp_keysize, + pub_len); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + } + +#ifdef LINUXKM_SLHDSA_SIGN + ret = crypto_sig_set_privkey(tfm, priv, priv_len); + if (ret) { + pr_err("error: crypto_sig_set_privkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + /* hedged signing is nondeterministic -- test by roundtrip. + * set_privkey installed the matching pub. */ + ret = crypto_sig_sign(tfm, msg, msg_len, sig_buf, sig_len); + if (ret != (int)sig_len) { + pr_err("error: crypto_sig_sign returned %d, expected %d\n", + ret, (int)sig_len); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + ret = crypto_sig_verify(tfm, sig_buf, sig_len, msg, msg_len); + if (ret) { + pr_err("error: crypto_sig_verify of generated signature " + "returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + /* insufficient dst space must fail with -EOVERFLOW. */ + ret = crypto_sig_sign(tfm, msg, msg_len, sig_buf, sig_len - 1); + if (ret != -EOVERFLOW) { + pr_err("error: crypto_sig_sign (short dst) returned %d, " + "expected %d\n", ret, -EOVERFLOW); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + /* regenerate a good signature clobbered by the short-dst check + * being reached with a partially-written buffer. (it isn't -- + * -EOVERFLOW precedes any write -- but don't depend on that.) */ + ret = crypto_sig_sign(tfm, msg, msg_len, sig_buf, sig_len); + if (ret != (int)sig_len) { + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } +#else /* !LINUXKM_SLHDSA_SIGN */ + if (kat_sig) { + /* embedded accept-path KAT. */ + ret = crypto_sig_verify(tfm, sig_buf, sig_len, msg, msg_len); + if (ret) { + pr_err("error: crypto_sig_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + } + + /* sign-side stubs must report -EOPNOTSUPP. */ + ret = crypto_sig_set_privkey(tfm, pub, pub_len); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_sig_set_privkey returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + ret = crypto_sig_sign(tfm, msg, msg_len, sig_buf, sig_len); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_sig_sign returned %d, expected %d\n", + ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } +#endif /* !LINUXKM_SLHDSA_SIGN */ + + /* reject path: corrupt (or garbage) signature of correct length + * must fail with -EBADMSG. this executes the full verification + * computation. */ + sig_buf[sig_len / 2] ^= 1U; + ret = crypto_sig_verify(tfm, sig_buf, sig_len, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify returned %d, expected %d\n", + ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + /* a wrong-size signature must also fail with -EBADMSG. */ + ret = crypto_sig_verify(tfm, sig_buf, sig_len - 1, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify (short sig) returned %d, " + "expected %d\n", ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + test_rc = 0; +test_slhdsa_end: + if (tfm) + crypto_free_sig(tfm); + free(sig_buf); +#ifdef LINUXKM_SLHDSA_SIGN + ForceZero(priv, sizeof(priv)); +#endif + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#else /* !LINUXKM_SLHDSA_SIG_ALG */ + +static int linuxkm_test_slhdsa_driver(const char * driver, int param) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_akcipher * tfm = NULL; + struct akcipher_request * req = NULL; + struct scatterlist src_tab[2]; + struct scatterlist dst_sg; + byte pub[WOLFKM_SLHDSA_MAX_PUB_LEN]; + byte priv[WOLFKM_SLHDSA_MAX_PRIV_LEN]; + const byte * kat_sig = NULL; + byte * work = NULL; + byte * sig_buf = NULL; + byte * msg_buf = NULL; + byte * out_buf = NULL; + word32 pub_len; + word32 priv_len; + word32 sig_len; + const word32 msg_len = (word32)sizeof(slhdsa_test_msg); + + { + int len = wc_SlhDsaKey_PublicSizeFromParam((enum SlhDsaParam)param); + if (len <= 0) { + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + pub_len = (word32)len; + len = wc_SlhDsaKey_SigSizeFromParam((enum SlhDsaParam)param); + if (len <= 0) { + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + sig_len = (word32)len; +#ifdef LINUXKM_SLHDSA_SIGN + len = wc_SlhDsaKey_PrivateSizeFromParam((enum SlhDsaParam)param); + if (len <= 0) { + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + priv_len = (word32)len; +#else + priv_len = 0; +#endif + } + + ret = linuxkm_test_slhdsa_get_vectors(param, pub, pub_len, priv, + priv_len, &kat_sig); + if (ret != 0) { + pr_err("error: slhdsa test vector setup failed: %d\n", ret); + test_rc = ret; + goto test_slhdsa_end; + } + + /* one allocation: mutable signature + message + sign output. */ + work = (byte *)malloc((2 * (size_t)sig_len) + msg_len); + if (! work) { + pr_err("error: allocating work buffer failed.\n"); + test_rc = MEMORY_E; + goto test_slhdsa_end; + } + sig_buf = work; + msg_buf = work + sig_len; + out_buf = work + sig_len + msg_len; + XMEMSET(sig_buf, 0xa5, sig_len); + if (kat_sig) + XMEMCPY(sig_buf, kat_sig, sig_len); + XMEMCPY(msg_buf, slhdsa_test_msg, msg_len); + + tfm = crypto_alloc_akcipher(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating akcipher algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_slhdsa_end; + } + + req = akcipher_request_alloc(tfm, GFP_KERNEL); + if (! req) { + test_rc = -ENOMEM; + pr_err("error: allocating akcipher request %s failed\n", + driver); + goto test_slhdsa_end; + } + + ret = crypto_akcipher_set_pub_key(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_akcipher_set_pub_key returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + { + unsigned int maxsize = crypto_akcipher_maxsize(tfm); + if (maxsize != sig_len) { + pr_err("error: crypto_akcipher_maxsize returned %u, " + "expected %u\n", maxsize, sig_len); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + } + +#ifdef LINUXKM_SLHDSA_SIGN + ret = crypto_akcipher_set_priv_key(tfm, priv, priv_len); + if (ret) { + pr_err("error: crypto_akcipher_set_priv_key returned: %d\n", + ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + /* hedged signing is nondeterministic -- test by roundtrip. */ + sg_init_one(&src_tab[0], msg_buf, msg_len); + sg_init_one(&dst_sg, out_buf, sig_len); + akcipher_request_set_crypt(req, &src_tab[0], &dst_sg, msg_len, + sig_len); + + ret = crypto_akcipher_sign(req); + if (ret) { + pr_err("error: crypto_akcipher_sign returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + if (req->dst_len != sig_len) { + pr_err("error: crypto_akcipher_sign set dst_len %u, expected " + "%u\n", req->dst_len, sig_len); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + XMEMCPY(sig_buf, out_buf, sig_len); + + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], sig_buf, sig_len); + sg_set_buf(&src_tab[1], msg_buf, msg_len); + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret) { + pr_err("error: crypto_akcipher_verify of generated signature " + "returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + /* insufficient dst space must fail with -EOVERFLOW. */ + sg_init_one(&src_tab[0], msg_buf, msg_len); + sg_init_one(&dst_sg, out_buf, sig_len - 1); + akcipher_request_set_crypt(req, &src_tab[0], &dst_sg, msg_len, + sig_len - 1); + ret = crypto_akcipher_sign(req); + if (ret != -EOVERFLOW) { + pr_err("error: crypto_akcipher_sign (short dst) returned %d, " + "expected %d\n", ret, -EOVERFLOW); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } +#else /* !LINUXKM_SLHDSA_SIGN */ + if (kat_sig) { + /* embedded accept-path KAT. */ + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], sig_buf, sig_len); + sg_set_buf(&src_tab[1], msg_buf, msg_len); + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret) { + pr_err("error: crypto_akcipher_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + } + + /* sign-side stubs must report -EOPNOTSUPP. */ + ret = crypto_akcipher_set_priv_key(tfm, pub, pub_len); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_akcipher_set_priv_key returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + sg_init_one(&src_tab[0], msg_buf, msg_len); + sg_init_one(&dst_sg, out_buf, sig_len); + akcipher_request_set_crypt(req, &src_tab[0], &dst_sg, msg_len, + sig_len); + ret = crypto_akcipher_sign(req); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_akcipher_sign returned %d, expected %d\n", + ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } +#endif /* !LINUXKM_SLHDSA_SIGN */ + + /* reject path: corrupt (or garbage) signature of correct length + * must fail with -EBADMSG. */ + sig_buf[sig_len / 2] ^= 1U; + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], sig_buf, sig_len); + sg_set_buf(&src_tab[1], msg_buf, msg_len); + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret != -EBADMSG) { + pr_err("error: crypto_akcipher_verify returned %d, expected " + "%d\n", ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_slhdsa_end; + } + + test_rc = 0; +test_slhdsa_end: + if (req) { akcipher_request_free(req); req = NULL; } + if (tfm) { crypto_free_akcipher(tfm); tfm = NULL; } + if (work) { free(work); work = NULL; } +#ifdef LINUXKM_SLHDSA_SIGN + ForceZero(priv, sizeof(priv)); +#endif + + #ifdef WOLFKM_DEBUG_SLHDSA + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#endif /* !LINUXKM_SLHDSA_SIG_ALG */ + +#ifdef LINUXKM_SLHDSA_SHAKE_128S +static int linuxkm_test_slhdsa_shake_128s(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-shake-128s" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHAKE128S); +} +#endif /* LINUXKM_SLHDSA_SHAKE_128S */ +#ifdef LINUXKM_SLHDSA_SHAKE_128F +static int linuxkm_test_slhdsa_shake_128f(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-shake-128f" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHAKE128F); +} +#endif /* LINUXKM_SLHDSA_SHAKE_128F */ +#ifdef LINUXKM_SLHDSA_SHAKE_192S +static int linuxkm_test_slhdsa_shake_192s(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-shake-192s" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHAKE192S); +} +#endif /* LINUXKM_SLHDSA_SHAKE_192S */ +#ifdef LINUXKM_SLHDSA_SHAKE_192F +static int linuxkm_test_slhdsa_shake_192f(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-shake-192f" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHAKE192F); +} +#endif /* LINUXKM_SLHDSA_SHAKE_192F */ +#ifdef LINUXKM_SLHDSA_SHAKE_256S +static int linuxkm_test_slhdsa_shake_256s(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-shake-256s" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHAKE256S); +} +#endif /* LINUXKM_SLHDSA_SHAKE_256S */ +#ifdef LINUXKM_SLHDSA_SHAKE_256F +static int linuxkm_test_slhdsa_shake_256f(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-shake-256f" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHAKE256F); +} +#endif /* LINUXKM_SLHDSA_SHAKE_256F */ +#ifdef LINUXKM_SLHDSA_SHA2_128S +static int linuxkm_test_slhdsa_sha2_128s(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-sha2-128s" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHA2_128S); +} +#endif /* LINUXKM_SLHDSA_SHA2_128S */ +#ifdef LINUXKM_SLHDSA_SHA2_128F +static int linuxkm_test_slhdsa_sha2_128f(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-sha2-128f" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHA2_128F); +} +#endif /* LINUXKM_SLHDSA_SHA2_128F */ +#ifdef LINUXKM_SLHDSA_SHA2_192S +static int linuxkm_test_slhdsa_sha2_192s(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-sha2-192s" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHA2_192S); +} +#endif /* LINUXKM_SLHDSA_SHA2_192S */ +#ifdef LINUXKM_SLHDSA_SHA2_192F +static int linuxkm_test_slhdsa_sha2_192f(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-sha2-192f" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHA2_192F); +} +#endif /* LINUXKM_SLHDSA_SHA2_192F */ +#ifdef LINUXKM_SLHDSA_SHA2_256S +static int linuxkm_test_slhdsa_sha2_256s(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-sha2-256s" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHA2_256S); +} +#endif /* LINUXKM_SLHDSA_SHA2_256S */ +#ifdef LINUXKM_SLHDSA_SHA2_256F +static int linuxkm_test_slhdsa_sha2_256f(void) +{ + return linuxkm_test_slhdsa_driver("slh-dsa-sha2-256f" WOLFKM_SLHDSA_DRIVER_SUFFIX, + (int)SLHDSA_SHA2_256F); +} +#endif /* LINUXKM_SLHDSA_SHA2_256F */ + +#endif /* LINUXKM_LKCAPI_REGISTER_SLHDSA */ + +#endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/linuxkm/lkcapi_xmss_glue.c b/linuxkm/lkcapi_xmss_glue.c new file mode 100644 index 0000000000..76fb1998e3 --- /dev/null +++ b/linuxkm/lkcapi_xmss_glue.c @@ -0,0 +1,1816 @@ +/* lkcapi_xmss_glue.c -- glue logic to register XMSS/XMSS^MT (RFC 8391, SP + * 800-208) wolfCrypt implementations with the Linux Kernel Cryptosystem + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* included by linuxkm/lkcapi_glue.c */ +#ifndef WC_SKIP_INCLUDED_C_FILES + +#ifndef LINUXKM_LKCAPI_REGISTER + #error lkcapi_xmss_glue.c included in non-LINUXKM_LKCAPI_REGISTER project. +#endif + +/* XMSS/XMSS^MT (RFC 8391, NIST SP 800-208) glue. VERIFY-ONLY, deliberately: + * XMSS is a stateful hash-based signature scheme -- each signing operation + * consumes a one-time-signature key, and reusing one voids all security. Safe + * signing therefore requires durable, synchronized private-key state + * (wc_XmssKey signing requires read/write state callbacks), for which the + * kernel crypto API has no contract, and mismanaged state in-kernel would be an + * OTS-reuse hazard. SP 800-208 confines signing to controlled (hardware) + * modules; verification has no state. The sign/set_priv_key callbacks are + * -EOPNOTSUPP stubs, following the convention of the in-tree ML-DSA + * implementation (crypto/mldsa.c) for unsupported operations. + * + * The kernel has no in-tree XMSS implementation on any version, hence no + * CONFIG_CRYPTO_XMSS to pivot on for LINUXKM_LKCAPI_REGISTER_ALL_KCONFIG, + * and no config-conflict check either -- the alg is registered for + * LINUXKM_LKCAPI_REGISTER_ALL, or by explicit request only. + * + * Calling conventions (wolfSSL-defined -- no in-tree or OpenSSL + * precedent for kernel XMSS): + * - two cra_names are registered, "xmss" (single-tree, RFC 8391 + * section 4) and "xmssmt" (multi-tree, RFC 8391 section 5), which + * use disjoint OID spaces distinguished only by that split: + * set_pub_key takes the raw public key (OID || root || SEED), from + * which the parameter set is derived (using the alg's + * single/multi-tree hint) and validated by + * wc_XmssKey_ImportPubRaw_ex(). + * - verify takes the raw XMSS/XMSS^MT signature as src and the raw unhashed + * message, of any length, as the "digest" argument. Signature size + * mismatches and verification failures both return -EBADMSG, + * following the convention of the in-tree ML-DSA. + * - key_size returns the public key size in BYTES on all kernel + * versions, and digest_size is not set, both mirroring the in-tree + * ML-DSA conventions for the PQC signature family. + * + * Because the "xmss"/"xmssmt" cra_names are unknown to crypto/testmgr.c, alg_test() + * takes its "notest" path and returns success at registration time, with + * or without fips_enabled. KATs are instead supplied by + * linuxkm_test_xmss() below. + */ + +#if defined(WOLFSSL_HAVE_XMSS) + #if defined(LINUXKM_LKCAPI_REGISTER_ALL) && \ + !defined(LINUXKM_LKCAPI_DONT_REGISTER_XMSS) && \ + !defined(LINUXKM_LKCAPI_REGISTER_XMSS) + #define LINUXKM_LKCAPI_REGISTER_XMSS + #ifndef HAVE_FIPS + #define LINUXKM_LKCAPI_REGISTER_XMSS_MT + #endif + #endif +#else + #undef LINUXKM_LKCAPI_REGISTER_XMSS + #undef LINUXKM_LKCAPI_REGISTER_XMSS_MT +#endif + +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS + +#include + +/* The XMSS acceleration qualifier is borrowed from that of the underlying hash + * functions. + */ +#if defined(USE_INTEL_SPEEDUP) + #ifndef NO_AVX2_SUPPORT + #define WOLFKM_XMSS_DRIVER_ISA_EXT "-avx2" + #else + #define WOLFKM_XMSS_DRIVER_ISA_EXT "-avx" + #endif +#else + #define WOLFKM_XMSS_DRIVER_ISA_EXT "" +#endif + +#define WOLFKM_XMSS_DRIVER_SUFFIX \ + WOLFKM_XMSS_DRIVER_ISA_EXT WOLFKM_DRIVER_SUFFIX_BASE + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) + /* as with ecdsa (see lkcapi_ecdsa_glue.c), registered as struct + * sig_alg on linux 6.13+, and as a verify-capable struct + * akcipher_alg on earlier kernels. */ + #define LINUXKM_XMSS_SIG_ALG +#endif + +#ifdef LINUXKM_XMSS_SIG_ALG + #define xmss_tfm_type crypto_sig + #define xmss_tfm_ctx_cb crypto_sig_ctx +#else + #define xmss_tfm_type crypto_akcipher + #define xmss_tfm_ctx_cb akcipher_tfm_ctx +#endif /* !LINUXKM_XMSS_SIG_ALG */ + +#define WOLFKM_XMSS_NAME ("xmss") +#define WOLFKM_XMSS_DRIVER ("xmss" WOLFKM_XMSS_DRIVER_SUFFIX) +#define WOLFKM_XMSSMT_NAME ("xmssmt") +#define WOLFKM_XMSSMT_DRIVER ("xmssmt" WOLFKM_XMSS_DRIVER_SUFFIX) + +static int linuxkm_test_xmss(void); +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT +static int linuxkm_test_xmssmt(void); +#endif + +static int xmss_loaded = 0; +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT +static int xmssmt_loaded = 0; +#endif + +/* wc_XmssKey_Verify() is read-only on the key -- it allocates and frees + * its own transient working state (XmssState) internally -- so a single + * imported key per tfm is safe under the kernel crypto API's concurrent + * use of a tfm, and no per-operation key reconstruction is needed. */ +struct km_xmss_ctx { + XmssKey * key; + int pub_set; + int is_xmssmt; /* set by the per-alg init callback. */ +}; + +static void km_xmss_exit(struct xmss_tfm_type *tfm); +static int km_xmss_init(struct xmss_tfm_type *tfm); +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT +static int km_xmssmt_init(struct xmss_tfm_type *tfm); +#endif +static int km_xmss_set_pub(struct xmss_tfm_type *tfm, + const void *key, unsigned int keylen); +static int km_xmss_set_priv(struct xmss_tfm_type *tfm, + const void *key, unsigned int keylen); +#ifdef LINUXKM_XMSS_SIG_ALG +static unsigned int km_xmss_key_size(struct crypto_sig *tfm); +static unsigned int km_xmss_max_size(struct crypto_sig *tfm); +static int km_xmss_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen); +static int km_xmss_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); +#else +static unsigned int km_xmss_max_size(struct crypto_akcipher *tfm); +static int km_xmss_verify(struct akcipher_request *req); +static int km_xmss_sign(struct akcipher_request *req); +#endif /* !LINUXKM_XMSS_SIG_ALG */ + +#ifdef LINUXKM_XMSS_SIG_ALG +static struct sig_alg xmss = { + .base.cra_name = WOLFKM_XMSS_NAME, + .base.cra_driver_name = WOLFKM_XMSS_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_xmss_ctx), + .sign = km_xmss_sign, + .verify = km_xmss_verify, + .set_pub_key = km_xmss_set_pub, + .set_priv_key = km_xmss_set_priv, + .key_size = km_xmss_key_size, + /* no .digest_size: crypto/sig.c defaults it (key_size on + * < 6.15.3; keysize-bits/8 on >= 6.15.3) -- pub bytes in + * both eras given km_xmss_key_size() above. */ + .max_size = km_xmss_max_size, + .init = km_xmss_init, + .exit = km_xmss_exit, +}; +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT +static struct sig_alg xmssmt = { + .base.cra_name = WOLFKM_XMSSMT_NAME, + .base.cra_driver_name = WOLFKM_XMSSMT_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_xmss_ctx), + .sign = km_xmss_sign, + .verify = km_xmss_verify, + .set_pub_key = km_xmss_set_pub, + .set_priv_key = km_xmss_set_priv, + .key_size = km_xmss_key_size, + /* no .digest_size: crypto/sig.c defaults it (key_size on + * < 6.15.3; keysize-bits/8 on >= 6.15.3) -- pub bytes in + * both eras given km_xmss_key_size() above. */ + .max_size = km_xmss_max_size, + .init = km_xmssmt_init, + .exit = km_xmss_exit, +}; +#endif /* LINUXKM_LKCAPI_REGISTER_XMSS_MT */ +#else /* !LINUXKM_XMSS_SIG_ALG */ +static struct akcipher_alg xmss = { + .base.cra_name = WOLFKM_XMSS_NAME, + .base.cra_driver_name = WOLFKM_XMSS_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_xmss_ctx), + .sign = km_xmss_sign, + .verify = km_xmss_verify, + .set_pub_key = km_xmss_set_pub, + .set_priv_key = km_xmss_set_priv, + .max_size = km_xmss_max_size, + .init = km_xmss_init, + .exit = km_xmss_exit, +}; +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT +static struct akcipher_alg xmssmt = { + .base.cra_name = WOLFKM_XMSSMT_NAME, + .base.cra_driver_name = WOLFKM_XMSSMT_DRIVER, + .base.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, + .base.cra_module = THIS_MODULE, + .base.cra_ctxsize = sizeof(struct km_xmss_ctx), + .sign = km_xmss_sign, + .verify = km_xmss_verify, + .set_pub_key = km_xmss_set_pub, + .set_priv_key = km_xmss_set_priv, + .max_size = km_xmss_max_size, + .init = km_xmssmt_init, + .exit = km_xmss_exit, +}; +#endif /* LINUXKM_LKCAPI_REGISTER_XMSS_MT */ +#endif /* !LINUXKM_XMSS_SIG_ALG */ + +static int km_xmss_init_common(struct xmss_tfm_type *tfm, int is_xmssmt) +{ + struct km_xmss_ctx *ctx = xmss_tfm_ctx_cb(tfm); + int ret; + +#ifndef LINUXKM_LKCAPI_REGISTER_XMSS_MT + if (is_xmssmt) + return -EOPNOTSUPP; +#endif + + XMEMSET(ctx, 0, sizeof(struct km_xmss_ctx)); + ctx->is_xmssmt = is_xmssmt; + + ctx->key = (XmssKey *)malloc(sizeof(XmssKey)); + if (! ctx->key) + return -ENOMEM; + + ret = wc_XmssKey_Init(ctx->key, NULL /* heap */, INVALID_DEVID); + if (ret < 0) { + free(ctx->key); + ctx->key = NULL; + return -ENOMEM; + } + + #ifdef WOLFKM_DEBUG_XMSS + pr_info("info: exiting km_xmss_init_common (xmssmt %d)\n", is_xmssmt); + #endif + return 0; +} + +static int km_xmss_init(struct xmss_tfm_type *tfm) +{ + return km_xmss_init_common(tfm, 0); +} + +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT +static int km_xmssmt_init(struct xmss_tfm_type *tfm) +{ + return km_xmss_init_common(tfm, 1); +} +#endif + +static void km_xmss_exit(struct xmss_tfm_type *tfm) +{ + struct km_xmss_ctx *ctx = xmss_tfm_ctx_cb(tfm); + + if (ctx->key) { + wc_XmssKey_Free(ctx->key); + free(ctx->key); + ctx->key = NULL; + } + + #ifdef WOLFKM_DEBUG_XMSS + pr_info("info: exiting km_xmss_exit\n"); + #endif + return; +} + +/* + * Sets the XMSS/XMSS^MT public key. + * + * tfm the crypto_akcipher (crypto_sig on linux 6.13+) transform + * key raw RFC 8391 public key (OID || root || SEED); the + * parameter set is derived from the OID, using the alg's + * single/multi-tree hint, and validated + * keylen key length + */ +static int km_xmss_set_pub(struct xmss_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + struct km_xmss_ctx * ctx = xmss_tfm_ctx_cb(tfm); + int err; + + if (key == NULL) + return -EINVAL; + + if (ctx->key == NULL) + return -EINVAL; + + /* reset the key for (re)import. */ + wc_XmssKey_Free(ctx->key); + ctx->pub_set = 0; + err = wc_XmssKey_Init(ctx->key, NULL /* heap */, INVALID_DEVID); + if (err != 0) + return -ENOMEM; + + /* Derives and validates the parameter set from the encoded OID + * (NOT_COMPILED_IN / BAD_FUNC_ARG if the set isn't built in). */ + err = wc_XmssKey_ImportPubRaw_ex(ctx->key, (const byte *)key, keylen, + ctx->is_xmssmt); + if (unlikely(err)) { + #ifdef WOLFKM_DEBUG_XMSS + pr_err("%s: wc_XmssKey_ImportPubRaw_ex failed: %d\n", + ctx->is_xmssmt ? WOLFKM_XMSSMT_DRIVER : WOLFKM_XMSS_DRIVER, + err); + #endif + return -EINVAL; + } + + ctx->pub_set = 1; + + #ifdef WOLFKM_DEBUG_XMSS + pr_info("info: exiting km_xmss_set_pub %d\n", keylen); + #endif + return 0; +} + +/* XMSS signing is stateful and unsupported here -- see the header + * comment. Stub convention per the in-tree ML-DSA (crypto/mldsa.c). */ +static int km_xmss_set_priv(struct xmss_tfm_type *tfm, const void *key, + unsigned int keylen) +{ + (void)tfm; + (void)key; + (void)keylen; + return -EOPNOTSUPP; +} + +#ifdef LINUXKM_XMSS_SIG_ALG +/* The public key size (0 before set_pub_key): BYTES on kernels + * < 6.15.3, BITS on >= 6.15.3 (crypto_sig_keysize() semantics changed; + * crypto_sig_digestsize() then derives bytes as keysize/8 -- see + * lkcapi_ed_glue.c). */ +static unsigned int km_xmss_key_size(struct crypto_sig *tfm) +{ + struct km_xmss_ctx *ctx = crypto_sig_ctx(tfm); + word32 len = 0; + + if ((! ctx->pub_set) || + (wc_XmssKey_GetPubLen(ctx->key, &len) != 0)) + { + return 0; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + return (unsigned int)len * 8U; /* bits */ + #else + return (unsigned int)len; /* bytes */ + #endif +} + +static unsigned int km_xmss_max_size(struct crypto_sig *tfm) +{ + struct km_xmss_ctx *ctx = crypto_sig_ctx(tfm); + word32 len = 0; + + if ((! ctx->pub_set) || + (wc_XmssKey_GetSigLen(ctx->key, &len) != 0)) + { + return 0; + } + return len; +} +#else /* !LINUXKM_XMSS_SIG_ALG */ +static unsigned int km_xmss_max_size(struct crypto_akcipher *tfm) +{ + struct km_xmss_ctx *ctx = akcipher_tfm_ctx(tfm); + word32 len = 0; + + if ((! ctx->pub_set) || + (wc_XmssKey_GetSigLen(ctx->key, &len) != 0)) + { + return 0; + } + return len; +} +#endif /* !LINUXKM_XMSS_SIG_ALG */ + +/* Shared verify core. returns 0, -EBADMSG (size mismatch or + * verification failure, per the in-tree ML-DSA convention), or + * -EINVAL. */ +static int km_xmss_verify_common(struct km_xmss_ctx *ctx, + const byte *sig, word32 sig_len, + const byte *msg, word32 msg_len) +{ + word32 exp_sig_len = 0; + int err; + + if (! ctx->pub_set) + return -EINVAL; + + if (wc_XmssKey_GetSigLen(ctx->key, &exp_sig_len) != 0) + return -EINVAL; + + if (sig_len != exp_sig_len) + return -EBADMSG; + + /* wc_XmssKey_Verify()'s message length parameter is an int. */ + if (msg_len > (word32)INT_MAX) + return -EINVAL; + + err = wc_XmssKey_Verify(ctx->key, sig, sig_len, msg, (int)msg_len); + + if (err) { + #ifdef WOLFKM_DEBUG_XMSS + pr_err("error: %s: xmss verify returned: %d\n", + ctx->is_xmssmt ? WOLFKM_XMSSMT_DRIVER : WOLFKM_XMSS_DRIVER, + err); + #endif + return -EBADMSG; + } + return 0; +} + +#ifdef LINUXKM_XMSS_SIG_ALG + +/* + * Verify an XMSS/XMSS^MT signature (linux 6.13+ struct sig_alg edition). + * + * src: + * - the raw RFC 8391 signature; slen must equal the signature size + * for the imported public key's parameter set. + * + * digest: + * - the raw message; no prehashing occurs, and dlen is unrestricted + * (up to INT_MAX). + */ +static int km_xmss_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct km_xmss_ctx *ctx = crypto_sig_ctx(tfm); + int err; + + if (src == NULL || digest == NULL) + return -EINVAL; + + err = km_xmss_verify_common(ctx, (const byte *)src, (word32)slen, + (const byte *)digest, (word32)dlen); + + #ifdef WOLFKM_DEBUG_XMSS + pr_info("info: exiting km_xmss_verify dlen %d, slen %d, err %d\n", + dlen, slen, err); + #endif + return err; +} + +/* XMSS signing is stateful and unsupported here -- see the header + * comment. */ +static int km_xmss_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + (void)tfm; + (void)src; + (void)slen; + (void)dst; + (void)dlen; + return -EOPNOTSUPP; +} + +#else /* !LINUXKM_XMSS_SIG_ALG */ + +/* + * Verify an XMSS/XMSS^MT signature. + * + * The total size of req->src is src_len + dst_len: + * - src_len: signature (raw RFC 8391 form, exact size for the + * imported public key's parameter set) + * - dst_len: message (raw, unhashed, any length up to INT_MAX) + * + * dst should be null. + */ +static int km_xmss_verify(struct akcipher_request *req) +{ + struct crypto_akcipher * tfm = NULL; + struct km_xmss_ctx * ctx = NULL; + byte * sig = NULL; + word32 sig_len = 0; + byte * msg = NULL; + word32 msg_len = 0; + int err = -1; + + if (req->src == NULL || req->dst != NULL) + return -EINVAL; + + tfm = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(tfm); + + sig_len = req->src_len; + msg_len = req->dst_len; + + if ((sig_len + msg_len) != ((word64)sig_len + (word64)msg_len)) + return -EINVAL; + + sig = malloc(sig_len + msg_len); + if (unlikely(sig == NULL)) + return -ENOMEM; + + msg = sig + sig_len; + + XMEMSET(sig, 0, sig_len + msg_len); + + scatterwalk_map_and_copy(sig, req->src, 0, sig_len + msg_len, 0); + + err = km_xmss_verify_common(ctx, sig, sig_len, msg, msg_len); + + free(sig); + + #ifdef WOLFKM_DEBUG_XMSS + pr_info("info: exiting km_xmss_verify msg_len %d, sig_len %d, " + "err %d\n", msg_len, sig_len, err); + #endif + return err; +} + +/* XMSS signing is stateful and unsupported here -- see the header + * comment. */ +static int km_xmss_sign(struct akcipher_request *req) +{ + (void)req; + return -EOPNOTSUPP; +} + +#endif /* !LINUXKM_XMSS_SIG_ALG */ + +#ifdef LINUXKM_XMSS_SIG_ALG + +static int linuxkm_test_xmss_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_sig * tfm = NULL; + byte * sig_copy = NULL; + byte dummy[1] = { 0 }; + + sig_copy = (byte *)malloc(sig_len); + if (! sig_copy) { + pr_err("error: allocating sig_copy buffer failed.\n"); + test_rc = MEMORY_E; + goto test_xmss_end; + } + XMEMCPY(sig_copy, sig, sig_len); + + tfm = crypto_alloc_sig(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating sig algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_xmss_end; + } + + ret = crypto_sig_set_pubkey(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_sig_set_pubkey returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + + { + /* keysize is bits on >= 6.15.3, bytes before (see + * km_xmss_key_size()); digestsize resolves to the pub key + * size in bytes in both eras (no digest_size callback). */ + unsigned int maxsize = crypto_sig_maxsize(tfm); + unsigned int keysize = crypto_sig_keysize(tfm); + unsigned int digestsize = crypto_sig_digestsize(tfm); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 3) + unsigned int exp_keysize = pub_len * 8U; + #else + unsigned int exp_keysize = pub_len; + #endif + + if ((keysize != exp_keysize) || (maxsize != sig_len) || + (digestsize != pub_len)) + { + pr_err("error: crypto_sig_{max, key, digest}size returned " + "{%u, %u, %u}, expected {%u, %u, %u}\n", + maxsize, keysize, digestsize, sig_len, exp_keysize, + pub_len); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + } + + ret = crypto_sig_verify(tfm, sig_copy, sig_len, msg, msg_len); + if (ret) { + pr_err("error: crypto_sig_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + + /* corrupt the signature -- verify should now fail. */ + sig_copy[sig_len / 2] ^= 1U; + + ret = crypto_sig_verify(tfm, sig_copy, sig_len, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify returned %d, expected %d\n", + ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + sig_copy[sig_len / 2] ^= 1U; + + /* a wrong-size signature must also fail with -EBADMSG. */ + ret = crypto_sig_verify(tfm, sig_copy, sig_len - 1, msg, msg_len); + if (ret != -EBADMSG) { + pr_err("error: crypto_sig_verify (short sig) returned %d, " + "expected %d\n", ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + + /* signing is stateful and unsupported -- the stubs must report + * -EOPNOTSUPP. */ + ret = crypto_sig_set_privkey(tfm, dummy, sizeof(dummy)); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_sig_set_privkey returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + ret = crypto_sig_sign(tfm, msg, msg_len, sig_copy, sig_len); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_sig_sign returned %d, expected %d\n", + ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + + test_rc = 0; +test_xmss_end: + if (tfm) + crypto_free_sig(tfm); + free(sig_copy); + + #ifdef WOLFKM_DEBUG_XMSS + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#else /* !LINUXKM_XMSS_SIG_ALG */ + +static int linuxkm_test_xmss_driver(const char * driver, + const byte * pub, word32 pub_len, + const byte * sig, word32 sig_len, + const byte * msg, word32 msg_len) +{ + int test_rc = WC_NO_ERR_TRACE(WC_FAILURE); + int ret = 0; + struct crypto_akcipher * tfm = NULL; + struct akcipher_request * req = NULL; + struct scatterlist src_tab[2]; + byte * param_copy = NULL; + byte * bad_sig = NULL; + byte dummy[1] = { 0 }; + + param_copy = (byte *)malloc(sig_len + msg_len); + if (! param_copy) { + pr_err("error: allocating param_copy buffer failed.\n"); + test_rc = MEMORY_E; + goto test_xmss_end; + } + XMEMCPY(param_copy, sig, sig_len); + sig = param_copy; + XMEMCPY(param_copy + sig_len, msg, msg_len); + msg = param_copy + sig_len; + + tfm = crypto_alloc_akcipher(driver, 0, 0); + if (IS_ERR(tfm)) { + pr_err("error: allocating akcipher algorithm %s failed: %d\n", + driver, (int)PTR_ERR(tfm)); + if (PTR_ERR(tfm) == -ENOMEM) + test_rc = MEMORY_E; + else + test_rc = BAD_FUNC_ARG; + tfm = NULL; + goto test_xmss_end; + } + + req = akcipher_request_alloc(tfm, GFP_KERNEL); + if (! req) { + test_rc = -ENOMEM; + pr_err("error: allocating akcipher request %s failed\n", + driver); + goto test_xmss_end; + } + + ret = crypto_akcipher_set_pub_key(tfm, pub, pub_len); + if (ret) { + pr_err("error: crypto_akcipher_set_pub_key returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + + { + unsigned int maxsize = crypto_akcipher_maxsize(tfm); + if (maxsize != sig_len) { + pr_err("error: crypto_akcipher_maxsize returned %u, " + "expected %u\n", maxsize, sig_len); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + } + + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], sig, sig_len); + sg_set_buf(&src_tab[1], msg, msg_len); + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret) { + pr_err("error: crypto_akcipher_verify returned: %d\n", ret); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + + bad_sig = malloc(sig_len); + if (bad_sig == NULL) { + pr_err("error: alloc sig failed\n"); + test_rc = MEMORY_E; + goto test_xmss_end; + } + + XMEMCPY(bad_sig, sig, sig_len); + bad_sig[sig_len / 2] ^= 1; + + sg_init_table(src_tab, 2); + sg_set_buf(&src_tab[0], bad_sig, sig_len); + sg_set_buf(&src_tab[1], msg, msg_len); + akcipher_request_set_crypt(req, src_tab, NULL, sig_len, msg_len); + + ret = crypto_akcipher_verify(req); + if (ret != -EBADMSG) { + pr_err("error: crypto_akcipher_verify returned %d, expected " + "%d\n", ret, -EBADMSG); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + + /* signing is stateful and unsupported -- the stubs must report + * -EOPNOTSUPP. */ + ret = crypto_akcipher_set_priv_key(tfm, dummy, sizeof(dummy)); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_akcipher_set_priv_key returned %d, " + "expected %d\n", ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + ret = crypto_akcipher_sign(req); + if (ret != -EOPNOTSUPP) { + pr_err("error: crypto_akcipher_sign returned %d, expected %d\n", + ret, -EOPNOTSUPP); + test_rc = BAD_FUNC_ARG; + goto test_xmss_end; + } + + test_rc = 0; +test_xmss_end: + if (req) { akcipher_request_free(req); req = NULL; } + if (tfm) { crypto_free_akcipher(tfm); tfm = NULL; } + if (param_copy) { free(param_copy); } + if (bad_sig) { free(bad_sig); bad_sig = NULL; } + + #ifdef WOLFKM_DEBUG_XMSS + pr_info("info: %s: self test returned: %d\n", driver, test_rc); + #endif + return test_rc; +} + +#endif /* !LINUXKM_XMSS_SIG_ALG */ + +static int linuxkm_test_xmss(void) +{ + /* reference vectors from wolfcrypt/test/test.c (xmss_*): + * XMSS-SHA2_10_256, generated with the unpatched xmss-reference + * implementation (https://github.com/XMSS/xmss-reference). */ + static const byte xmss_kat_pub[] = { + 0x00, 0x00, 0x00, 0x01, 0xa5, 0x41, 0x31, 0x96, + 0x0a, 0xf9, 0xf3, 0xb2, 0x4b, 0x2e, 0x5b, 0x3e, + 0xca, 0x74, 0xad, 0x6c, 0xa5, 0x89, 0xad, 0x2c, + 0x0e, 0x96, 0xb3, 0x54, 0xfb, 0x5b, 0x63, 0x50, + 0x96, 0x81, 0xe2, 0x59, 0x72, 0x10, 0x09, 0x54, + 0xbb, 0x39, 0xac, 0xee, 0x78, 0xef, 0x95, 0xec, + 0x01, 0x1d, 0xf0, 0x36, 0x68, 0xe2, 0xc4, 0xa5, + 0x2f, 0x60, 0x42, 0x7e, 0xd3, 0x8e, 0xaa, 0x27, + 0xc9, 0xb7, 0x39, 0x4e + }; + + static const byte xmss_kat_msg[] = { + 0x07, 0x9f, 0x80, 0x86, 0xdb, 0x76, 0x27, 0xdf, + 0xed, 0x5b, 0x2a, 0x81, 0x60, 0x60, 0x7d, 0xb4, + 0xe8, 0x7a, 0x69, 0x45, 0x20, 0x6b, 0xa2, 0x96, + 0xc0, 0x21, 0xa5, 0x46, 0x29, 0x63, 0x9b, 0x37 + }; + + static const byte xmss_kat_sig[] = { + 0x00, 0x00, 0x00, 0x05, 0xf0, 0x15, 0x34, 0xba, + 0x92, 0x03, 0x6a, 0xb9, 0xa5, 0x23, 0x86, 0x11, + 0xae, 0x65, 0x0a, 0x5c, 0x78, 0x2c, 0xc9, 0xbe, + 0x7e, 0xa6, 0xdc, 0xa2, 0x8b, 0xa9, 0x9c, 0x50, + 0xf6, 0x61, 0x8d, 0x9d, 0xd7, 0xe9, 0xc0, 0xf8, + 0x67, 0xcd, 0x8a, 0xc4, 0x9b, 0x74, 0x96, 0x07, + 0x5d, 0xf2, 0xc9, 0xcc, 0x28, 0x05, 0xb1, 0xbe, + 0x5e, 0xa4, 0xba, 0xbe, 0xab, 0xd8, 0x21, 0x6b, + 0x21, 0x5f, 0xab, 0xb7, 0x6c, 0xec, 0x2f, 0xc8, + 0xc6, 0x74, 0x3e, 0x97, 0x1b, 0xc3, 0x45, 0x57, + 0xaf, 0xaa, 0x1e, 0xa8, 0xf2, 0x86, 0xa8, 0xaa, + 0x43, 0x6d, 0x66, 0xe9, 0x81, 0x14, 0xde, 0x09, + 0x39, 0xd2, 0xaf, 0xd1, 0x4c, 0xe7, 0x75, 0x18, + 0x0d, 0xaa, 0x29, 0xa1, 0x92, 0x53, 0xcc, 0xe9, + 0xf3, 0x0b, 0x1e, 0x3b, 0xe2, 0xae, 0x80, 0x0c, + 0xe7, 0x7a, 0x7c, 0x13, 0x8a, 0x28, 0xc6, 0x5f, + 0x0a, 0xa4, 0xa3, 0x73, 0x0a, 0x3a, 0xc2, 0xa6, + 0x3b, 0xb4, 0x30, 0x67, 0xc0, 0x36, 0x18, 0xa1, + 0x58, 0xcd, 0xad, 0x54, 0x36, 0x64, 0xce, 0xfd, + 0x52, 0xff, 0x70, 0x7e, 0x09, 0xfb, 0x13, 0xa2, + 0xea, 0xdf, 0x67, 0x8d, 0x6c, 0x42, 0xb2, 0x78, + 0xf5, 0x7d, 0x5c, 0x4b, 0xf7, 0x8e, 0xcf, 0x3e, + 0xb7, 0xc6, 0xc1, 0x23, 0xfa, 0x65, 0xde, 0xd2, + 0xfa, 0x40, 0x51, 0x97, 0x0d, 0x52, 0x32, 0x76, + 0x7e, 0x82, 0x8d, 0xd0, 0xb9, 0x1e, 0x62, 0xd9, + 0x1e, 0xc1, 0xdb, 0x40, 0x43, 0x37, 0x4a, 0x23, + 0x8a, 0x1d, 0x35, 0xfa, 0xf4, 0x53, 0x11, 0x5a, + 0xb5, 0x6d, 0x1e, 0x8b, 0x22, 0xc8, 0x7d, 0x2a, + 0xe4, 0x94, 0xaa, 0x25, 0x20, 0x40, 0x96, 0xdb, + 0x82, 0x62, 0xba, 0x8f, 0x8b, 0x45, 0xcb, 0x4f, + 0x35, 0x88, 0x33, 0xeb, 0xef, 0xb3, 0xba, 0xa7, + 0x09, 0x72, 0xb3, 0x4c, 0xec, 0xf2, 0xc3, 0xc7, + 0x5e, 0x02, 0x6c, 0x41, 0x93, 0xcb, 0x3c, 0x89, + 0x12, 0x09, 0x68, 0x54, 0x8e, 0xec, 0x6a, 0x7e, + 0x20, 0xe1, 0x70, 0x3d, 0x8c, 0xeb, 0xb4, 0x36, + 0xbe, 0x91, 0xbe, 0x97, 0xb5, 0xa6, 0x34, 0x16, + 0x95, 0x0f, 0x10, 0x26, 0xa9, 0x13, 0x80, 0x88, + 0x9c, 0xaa, 0x68, 0xec, 0x34, 0x70, 0x4a, 0x15, + 0x9b, 0x5e, 0x57, 0x05, 0x87, 0x1c, 0xf8, 0x35, + 0x45, 0x29, 0xe9, 0x6e, 0xf2, 0x70, 0x13, 0x42, + 0x89, 0x4e, 0x77, 0xc0, 0x18, 0xc7, 0x55, 0x6d, + 0xe7, 0xfa, 0x0d, 0x63, 0x83, 0x16, 0x19, 0x01, + 0x2d, 0xfd, 0x31, 0x14, 0x94, 0xca, 0x3e, 0x0e, + 0xd6, 0x11, 0x34, 0x81, 0x57, 0x58, 0xec, 0x24, + 0xa4, 0x17, 0x63, 0xd3, 0x25, 0x00, 0xbf, 0x7d, + 0x78, 0x5d, 0xc5, 0xd8, 0xc6, 0xc1, 0xbd, 0x8c, + 0xd0, 0x94, 0x0a, 0xb1, 0x33, 0xa5, 0x4b, 0x31, + 0x25, 0xf5, 0xaf, 0xe7, 0x84, 0x26, 0xaa, 0x05, + 0xbb, 0xf3, 0x9a, 0xaf, 0x58, 0x36, 0x40, 0xef, + 0x3d, 0xa2, 0xbd, 0xca, 0xa1, 0x8d, 0x2f, 0x6d, + 0x54, 0xd2, 0x62, 0x33, 0x09, 0xae, 0xe6, 0x73, + 0xd6, 0x44, 0xe8, 0x7c, 0x5c, 0x39, 0x2b, 0x78, + 0x94, 0x14, 0xc7, 0xc9, 0xaf, 0xec, 0x77, 0x36, + 0xa1, 0x61, 0x61, 0xf1, 0xd0, 0x09, 0xa2, 0xee, + 0xe7, 0x55, 0xd7, 0x35, 0x89, 0x89, 0x9b, 0xcf, + 0xfa, 0xa6, 0x09, 0x1e, 0x3b, 0xbd, 0x5d, 0xd9, + 0x25, 0xe7, 0xed, 0xdd, 0x7c, 0xf0, 0x1c, 0x57, + 0xe0, 0x06, 0xbb, 0x08, 0x39, 0x59, 0xdf, 0xd7, + 0xaf, 0x4b, 0x88, 0x0d, 0x87, 0x8f, 0x4a, 0xf3, + 0x1c, 0xd4, 0x4b, 0xb3, 0xe2, 0xf3, 0x1b, 0x86, + 0x4f, 0xcd, 0x35, 0x75, 0xe2, 0x03, 0xf9, 0x1d, + 0xbf, 0x3e, 0xd1, 0x7b, 0xc7, 0x23, 0x11, 0x75, + 0x5f, 0x92, 0x0d, 0x98, 0xee, 0x14, 0xe1, 0xda, + 0x7a, 0x02, 0x17, 0x47, 0x6b, 0x41, 0xea, 0x47, + 0xa1, 0xaf, 0x06, 0x79, 0x1a, 0x52, 0x6f, 0x19, + 0x31, 0x70, 0x71, 0xbd, 0xc2, 0x61, 0x8d, 0xb7, + 0xee, 0x6b, 0x69, 0x2a, 0xe8, 0x21, 0x7a, 0x95, + 0xbe, 0x86, 0x2a, 0xa1, 0xf4, 0xe2, 0x2f, 0x17, + 0x02, 0xfd, 0xad, 0x17, 0x9f, 0x0a, 0x0a, 0x78, + 0xa9, 0x92, 0x30, 0x21, 0x72, 0x2b, 0x28, 0xf8, + 0xf2, 0x3e, 0x05, 0xd5, 0xac, 0xc0, 0x82, 0xf8, + 0xd2, 0xda, 0xd0, 0xa3, 0xbc, 0x93, 0xdb, 0xa5, + 0x46, 0xde, 0x14, 0x1e, 0xd4, 0x3a, 0x5d, 0x79, + 0x3d, 0x31, 0x4b, 0x06, 0xce, 0x22, 0x29, 0x3c, + 0x98, 0xb6, 0x18, 0x8a, 0xae, 0xf7, 0xba, 0x22, + 0x88, 0xa1, 0xee, 0xc0, 0x14, 0x4c, 0x4a, 0xa0, + 0x57, 0x0a, 0xd3, 0x18, 0xa2, 0x3d, 0xdd, 0xc7, + 0x83, 0x73, 0xfc, 0x38, 0x9b, 0x31, 0xa3, 0xe1, + 0x17, 0x76, 0xa1, 0xa2, 0x69, 0xfc, 0xab, 0x08, + 0x80, 0x72, 0x8d, 0xf5, 0xe4, 0x14, 0xb7, 0x6b, + 0x03, 0xff, 0xe8, 0x11, 0x4b, 0x06, 0x55, 0x7e, + 0x36, 0x21, 0x2f, 0xd7, 0x54, 0x82, 0xc9, 0x31, + 0xb4, 0x85, 0x68, 0x41, 0xef, 0x75, 0xb0, 0x3a, + 0xea, 0x4f, 0xe0, 0xec, 0x72, 0xcc, 0x33, 0x96, + 0xce, 0x7d, 0xad, 0xdd, 0x0d, 0x27, 0x05, 0x6e, + 0xa2, 0xd4, 0x11, 0x07, 0xd8, 0x7d, 0x27, 0xd4, + 0x80, 0x8f, 0x00, 0x22, 0xe4, 0xfc, 0x2c, 0x9d, + 0xd5, 0xd8, 0x18, 0x7f, 0x4e, 0xf4, 0xb9, 0x7f, + 0xef, 0xd6, 0x00, 0x08, 0x5c, 0x05, 0x04, 0x1e, + 0x9a, 0xc6, 0x8d, 0xcc, 0x19, 0xd9, 0x0b, 0x06, + 0xcc, 0x6a, 0x17, 0xe2, 0x03, 0x23, 0xdb, 0x1c, + 0xbc, 0xa2, 0xb9, 0xa2, 0x95, 0x3c, 0x73, 0xd8, + 0xff, 0xe6, 0x0e, 0xae, 0x04, 0xb2, 0xfc, 0x91, + 0x4f, 0xef, 0x8a, 0x58, 0xb7, 0x31, 0x68, 0x4c, + 0x1e, 0xd0, 0x5b, 0x85, 0xcc, 0x03, 0xdc, 0xf4, + 0xac, 0xdb, 0x03, 0x9b, 0x35, 0x33, 0x08, 0x71, + 0xd0, 0x50, 0x8d, 0xdc, 0xe3, 0x3a, 0x98, 0x40, + 0x41, 0x80, 0xdd, 0x35, 0xe1, 0xa2, 0xaf, 0x14, + 0x9a, 0xdb, 0xd3, 0x68, 0x14, 0xe2, 0x50, 0x7a, + 0x76, 0x3f, 0xe4, 0xa4, 0x1b, 0xaa, 0xc1, 0x06, + 0x87, 0x9a, 0x92, 0xf9, 0xbe, 0x9e, 0x86, 0x8c, + 0x92, 0x1d, 0x74, 0xb1, 0x7f, 0x27, 0x43, 0xc0, + 0xee, 0x2e, 0xc2, 0x6c, 0x6d, 0xaa, 0x0c, 0x0e, + 0x71, 0xc9, 0x56, 0xd6, 0x3a, 0x56, 0xcb, 0x90, + 0xd1, 0x7e, 0x6e, 0x1c, 0x6a, 0x00, 0x2d, 0x02, + 0x2c, 0x96, 0xf0, 0x2a, 0x37, 0x37, 0x18, 0x07, + 0x0b, 0xf4, 0xb4, 0x8c, 0x30, 0xf2, 0xa4, 0xab, + 0x66, 0xfb, 0x8b, 0x22, 0xc0, 0x00, 0x7e, 0x05, + 0xb6, 0xf9, 0x95, 0x49, 0x33, 0xa1, 0xdc, 0x97, + 0x0c, 0x5c, 0x61, 0x46, 0xe2, 0xd7, 0x87, 0x4b, + 0xc4, 0xc7, 0x5f, 0x26, 0x06, 0x84, 0xd7, 0x47, + 0x05, 0xf1, 0x33, 0xff, 0x85, 0x85, 0xb2, 0xbd, + 0x1f, 0x44, 0xc6, 0xc2, 0x7d, 0x51, 0xbe, 0x0e, + 0xb5, 0xc4, 0x44, 0x2f, 0xfe, 0x73, 0x5f, 0xf4, + 0xa4, 0xef, 0xe2, 0xf1, 0x73, 0x0b, 0xef, 0x3e, + 0x2b, 0xd7, 0xcc, 0x9f, 0xda, 0x1a, 0x7e, 0x92, + 0x39, 0xa1, 0x55, 0xbf, 0x60, 0x0a, 0xdb, 0x23, + 0x74, 0xfe, 0xe7, 0x05, 0x63, 0xa9, 0x85, 0x52, + 0x9f, 0xcc, 0xc3, 0xff, 0xf6, 0x6c, 0x1b, 0x4e, + 0x4f, 0x01, 0xbd, 0xc3, 0xeb, 0x37, 0xec, 0x29, + 0x21, 0x3b, 0x2c, 0xc9, 0x2e, 0x93, 0x20, 0x3e, + 0x19, 0xc0, 0x8b, 0xe8, 0x33, 0xcd, 0xc6, 0x6a, + 0x6e, 0x72, 0x13, 0x15, 0xa1, 0x90, 0x20, 0x0c, + 0x14, 0x66, 0xed, 0xcc, 0xa4, 0xdd, 0x7f, 0x58, + 0x53, 0xbc, 0x4a, 0x68, 0xfc, 0x86, 0x3e, 0xaa, + 0xf1, 0x17, 0x0f, 0x3e, 0x20, 0x54, 0x93, 0xf4, + 0x98, 0xbf, 0xb4, 0x07, 0x05, 0xbd, 0x70, 0xe7, + 0xd7, 0x34, 0xfd, 0xe3, 0x69, 0xdf, 0xcd, 0xf5, + 0x1a, 0x73, 0x6e, 0xc9, 0x2b, 0x21, 0xfb, 0xb8, + 0x7e, 0x44, 0x10, 0x83, 0x56, 0xce, 0xd5, 0x15, + 0x9a, 0x75, 0xfc, 0x91, 0x8e, 0x6b, 0x9e, 0x1a, + 0x3a, 0x33, 0x39, 0x35, 0xb4, 0x0d, 0x74, 0xf4, + 0xfb, 0x4c, 0x0e, 0x37, 0xfe, 0x82, 0x95, 0x46, + 0x6b, 0xd2, 0x6e, 0xee, 0xcd, 0x4d, 0x38, 0xaf, + 0x0a, 0xaa, 0xf1, 0xd5, 0xa4, 0x7c, 0x04, 0xd8, + 0xb9, 0xdb, 0x11, 0x68, 0x88, 0x35, 0x41, 0xde, + 0x31, 0x33, 0x0c, 0xdc, 0x2d, 0x4c, 0xa8, 0x20, + 0xcc, 0x2c, 0x4c, 0x63, 0xab, 0xba, 0xdf, 0x48, + 0x84, 0xd5, 0x25, 0xbc, 0x70, 0xe3, 0x49, 0xaa, + 0x43, 0xca, 0x8b, 0xe7, 0x9f, 0xdd, 0x20, 0x76, + 0x9b, 0x38, 0xf4, 0xba, 0x4d, 0x4e, 0x34, 0x4a, + 0xaf, 0x81, 0xe7, 0x0b, 0xec, 0xe9, 0x59, 0xc1, + 0x35, 0x22, 0x7f, 0x69, 0x46, 0x62, 0xd2, 0x18, + 0x6e, 0x1f, 0x79, 0xd1, 0xad, 0xc3, 0x84, 0x95, + 0x96, 0xb2, 0x18, 0x58, 0x5e, 0x7e, 0x0c, 0x25, + 0x0a, 0x0f, 0x69, 0xa3, 0x1d, 0xec, 0x29, 0xcb, + 0xda, 0xa2, 0xd1, 0x1a, 0x10, 0xa5, 0x52, 0xc3, + 0x62, 0x1e, 0xc5, 0x83, 0xff, 0xa3, 0x56, 0xc2, + 0xfd, 0x87, 0x3b, 0x57, 0x52, 0x98, 0x36, 0x95, + 0x77, 0x6b, 0xe5, 0x49, 0x10, 0x8e, 0x39, 0xdd, + 0xca, 0x4b, 0xb3, 0x9f, 0x4c, 0x0c, 0x11, 0x62, + 0xf3, 0x22, 0x78, 0xdb, 0x48, 0xeb, 0x68, 0xfe, + 0xe4, 0x2a, 0xe9, 0xaa, 0x8f, 0x7a, 0x2f, 0x69, + 0xa5, 0xc5, 0x03, 0x2d, 0xef, 0x62, 0xa8, 0x71, + 0x65, 0x06, 0x40, 0x84, 0x10, 0x0f, 0xf2, 0xed, + 0xbc, 0x70, 0x71, 0x69, 0x24, 0xa2, 0xbf, 0x83, + 0x39, 0xdd, 0xfa, 0xa2, 0x7b, 0xe5, 0xec, 0x3d, + 0xfe, 0x3b, 0x52, 0x6e, 0x3d, 0x82, 0xa6, 0x2a, + 0x86, 0x01, 0x61, 0x51, 0x63, 0xbf, 0xf9, 0x0a, + 0x06, 0x72, 0xf1, 0xd5, 0x39, 0x0c, 0xba, 0xc9, + 0x78, 0xc6, 0x77, 0x22, 0xe4, 0x96, 0x6e, 0xb1, + 0x48, 0x62, 0x84, 0x62, 0x2d, 0xea, 0x49, 0x56, + 0x50, 0x86, 0x3f, 0x90, 0xc3, 0x01, 0x42, 0x45, + 0xed, 0xe6, 0x9a, 0x65, 0x19, 0x93, 0x7f, 0x48, + 0x16, 0xf2, 0x50, 0xa7, 0x70, 0xb3, 0xf5, 0xdb, + 0x0e, 0x5e, 0x22, 0x9e, 0x64, 0x04, 0x26, 0x69, + 0xc1, 0x16, 0xee, 0x65, 0x08, 0x82, 0x27, 0x65, + 0xec, 0x3d, 0xdf, 0x51, 0x5e, 0x2d, 0xe8, 0x76, + 0xf2, 0xe3, 0xe4, 0x24, 0x04, 0x88, 0x06, 0x0f, + 0xb2, 0x7b, 0x9b, 0x72, 0x3d, 0x4c, 0x7d, 0x6a, + 0x1f, 0xb2, 0xa2, 0xd2, 0x35, 0xd6, 0x40, 0x25, + 0xc2, 0x0b, 0x25, 0xf9, 0xdf, 0x26, 0xe4, 0xdc, + 0xfb, 0xb1, 0x84, 0x84, 0x77, 0x1b, 0x45, 0x51, + 0x60, 0xd5, 0xf0, 0xb6, 0x09, 0xe6, 0xbc, 0xe3, + 0x1c, 0x70, 0x96, 0x2c, 0xd3, 0x9d, 0x7d, 0x7f, + 0xb1, 0x70, 0xda, 0x79, 0xb8, 0x74, 0x99, 0xbf, + 0x84, 0x95, 0xcc, 0x93, 0xd7, 0x51, 0xdd, 0x66, + 0xd3, 0x70, 0x0c, 0x75, 0x86, 0x09, 0x06, 0xfd, + 0x66, 0x14, 0x80, 0xcd, 0xf3, 0x59, 0xb4, 0x92, + 0x5f, 0xe4, 0xee, 0x00, 0xa8, 0xb0, 0x8b, 0x5c, + 0x3e, 0xdb, 0x8a, 0x9c, 0x0b, 0xb5, 0x99, 0xc2, + 0x0d, 0x81, 0x09, 0x06, 0x6c, 0x28, 0xc0, 0x7e, + 0xa5, 0x07, 0x70, 0x64, 0xd7, 0x41, 0xf4, 0xc3, + 0x66, 0x61, 0x1c, 0xa8, 0x51, 0xf6, 0x3c, 0xba, + 0xe0, 0x94, 0xa3, 0x11, 0x8c, 0x2e, 0xba, 0x13, + 0xb2, 0x47, 0x48, 0x93, 0xb4, 0x1a, 0x2c, 0x9a, + 0x6e, 0x8e, 0x30, 0x66, 0x7b, 0xd3, 0xbb, 0x3b, + 0x5d, 0x97, 0x0d, 0xe4, 0xea, 0x24, 0x28, 0x9e, + 0xb4, 0x88, 0xce, 0x1d, 0x7d, 0x6f, 0x39, 0xb3, + 0x87, 0x21, 0xe5, 0x08, 0x93, 0xf0, 0xd4, 0x9d, + 0x2d, 0x91, 0xc9, 0xfd, 0x0c, 0x74, 0x34, 0xb4, + 0x1f, 0xfe, 0xda, 0xdc, 0x10, 0x5b, 0x8d, 0x2b, + 0x87, 0xd3, 0x42, 0xb4, 0xae, 0x32, 0x9c, 0xae, + 0x4c, 0x99, 0xd8, 0xed, 0x44, 0x41, 0x07, 0xe0, + 0x8f, 0xbd, 0xa5, 0x7c, 0x5a, 0xdf, 0x91, 0x29, + 0x00, 0xb5, 0x4b, 0xc3, 0x3a, 0x40, 0x6c, 0x48, + 0xab, 0x2a, 0xf3, 0x02, 0xcb, 0xb3, 0x69, 0xda, + 0x06, 0x0c, 0x4d, 0x5c, 0x45, 0xc3, 0x28, 0xac, + 0x7a, 0x01, 0xd4, 0xf8, 0xcb, 0x07, 0x63, 0x89, + 0x09, 0x34, 0x78, 0xa7, 0x14, 0x39, 0xcf, 0x2d, + 0x94, 0x8d, 0x7a, 0x4e, 0x4e, 0xbd, 0xc4, 0x32, + 0xab, 0x21, 0xc9, 0xda, 0x3f, 0x5f, 0x04, 0x6b, + 0x14, 0x40, 0x18, 0x18, 0x2f, 0xf9, 0x46, 0x17, + 0x57, 0x54, 0x9b, 0x28, 0x7b, 0xbd, 0xf9, 0xa2, + 0x13, 0xac, 0x69, 0x24, 0xb1, 0x31, 0x39, 0xbf, + 0x8d, 0x75, 0xc3, 0xfd, 0x03, 0x54, 0x5a, 0xfd, + 0xd4, 0x7a, 0xb7, 0x56, 0x4f, 0x66, 0x43, 0x57, + 0x1b, 0xfb, 0xf9, 0x92, 0x7a, 0x83, 0xe6, 0xff, + 0xb4, 0xba, 0x83, 0xd2, 0x61, 0x8e, 0x4a, 0x82, + 0x82, 0xa8, 0xf5, 0x0c, 0xd2, 0x43, 0x53, 0xa8, + 0x85, 0x0a, 0xd4, 0x69, 0x7b, 0x04, 0x71, 0x3b, + 0x80, 0x49, 0x27, 0x47, 0x12, 0xb6, 0xb0, 0xea, + 0x90, 0x0a, 0xfa, 0xa8, 0xc8, 0x78, 0x61, 0xde, + 0x30, 0x12, 0xbb, 0xdc, 0xa6, 0x57, 0x56, 0x30, + 0x6e, 0xf1, 0xa8, 0x3b, 0xf6, 0x09, 0x07, 0xea, + 0x31, 0xe2, 0x08, 0x23, 0x31, 0x0f, 0xd4, 0x34, + 0xe3, 0x60, 0xc2, 0x2b, 0xdb, 0x5a, 0x99, 0xcf, + 0xd4, 0x6b, 0x4e, 0x75, 0x65, 0x35, 0xe8, 0x8b, + 0x93, 0x7d, 0xca, 0x11, 0x47, 0xf0, 0x3e, 0x11, + 0x5c, 0xd1, 0xee, 0x4b, 0x11, 0xb4, 0x65, 0x2b, + 0x6b, 0x79, 0xc0, 0x86, 0x60, 0xa4, 0x4b, 0x24, + 0xa0, 0x5c, 0x70, 0x34, 0xc3, 0x7c, 0xe7, 0x4f, + 0x97, 0x89, 0x4d, 0xfe, 0x22, 0x89, 0x3a, 0xe9, + 0x07, 0xb9, 0x1a, 0x86, 0xb8, 0x7a, 0x12, 0x38, + 0xe1, 0x24, 0x46, 0xbc, 0x9b, 0x21, 0xcd, 0xac, + 0x30, 0xab, 0x98, 0x21, 0x31, 0xc5, 0x17, 0x3f, + 0x1e, 0x56, 0xc3, 0x18, 0xce, 0xf0, 0xa1, 0xcc, + 0xff, 0x9d, 0xa8, 0x53, 0xaf, 0x74, 0x77, 0x54, + 0x02, 0x9a, 0x8f, 0xa4, 0xd4, 0xbd, 0xb2, 0x1a, + 0xba, 0x52, 0x2e, 0x19, 0xbe, 0x49, 0x11, 0x45, + 0x02, 0x01, 0x7a, 0xbf, 0x28, 0xd6, 0x18, 0xed, + 0xbd, 0xce, 0xe4, 0xde, 0xb5, 0xf1, 0x53, 0x5d, + 0x65, 0xf9, 0x5f, 0x83, 0x8f, 0x2d, 0xf2, 0x82, + 0xa0, 0x2d, 0x28, 0xd3, 0x0a, 0x9e, 0x0f, 0x7f, + 0xc7, 0xc4, 0x43, 0x7f, 0xc3, 0x0e, 0x06, 0xeb, + 0x4e, 0xb4, 0x2d, 0xfa, 0xdd, 0x48, 0xab, 0xf4, + 0x7d, 0x41, 0x48, 0x33, 0x5a, 0xe6, 0x70, 0x02, + 0xe7, 0x71, 0x8d, 0xd9, 0x6b, 0x0c, 0x5a, 0x8f, + 0xa4, 0xc1, 0xb7, 0x4e, 0x96, 0x83, 0xd6, 0xa7, + 0x1d, 0xf1, 0x88, 0xb3, 0x6e, 0xf4, 0x12, 0xa9, + 0xf6, 0x31, 0x69, 0x66, 0xfe, 0xfe, 0x02, 0xf2, + 0x86, 0x6d, 0xbb, 0x57, 0x51, 0x8c, 0x4c, 0xe9, + 0x7c, 0x92, 0x3e, 0x3a, 0xd3, 0x2d, 0xa8, 0x82, + 0x53, 0x84, 0x26, 0x89, 0xbb, 0xcc, 0x13, 0x12, + 0x3d, 0x94, 0xbb, 0xdf, 0x3d, 0x4c, 0xdf, 0x27, + 0x9b, 0x1f, 0xb8, 0xb6, 0xe4, 0xea, 0xa2, 0x07, + 0xf8, 0x4d, 0x42, 0x8f, 0x29, 0x90, 0xfe, 0x21, + 0x20, 0xe9, 0x55, 0x02, 0xad, 0x90, 0xa7, 0x77, + 0x4e, 0x29, 0xb6, 0xd9, 0x14, 0x94, 0xb2, 0x25, + 0xa4, 0xb2, 0x0e, 0x96, 0x31, 0xab, 0x9e, 0x93, + 0x49, 0xac, 0xa9, 0xcb, 0x68, 0x22, 0xba, 0xb8, + 0x57, 0x5c, 0x9d, 0x65, 0xc1, 0xf1, 0xfc, 0x99, + 0x7c, 0x3c, 0xe9, 0xea, 0x4b, 0x29, 0x22, 0x2f, + 0xdb, 0x17, 0x21, 0x8d, 0xb0, 0x13, 0xbf, 0xee, + 0x7d, 0xe4, 0x8b, 0x6d, 0x17, 0xe0, 0x53, 0x92, + 0x0b, 0x32, 0x6b, 0xb1, 0x65, 0x2e, 0xa7, 0x83, + 0xfd, 0x62, 0x62, 0xe3, 0xaa, 0x81, 0xe8, 0xd6, + 0xf7, 0xb1, 0x30, 0x65, 0x80, 0x9f, 0x77, 0x1e, + 0x4a, 0xea, 0xe8, 0x45, 0x32, 0x12, 0x3a, 0xfb, + 0x22, 0xe9, 0xa9, 0xf6, 0xcb, 0xab, 0xa8, 0x0c, + 0x20, 0xa8, 0x7c, 0xf9, 0xf7, 0x53, 0xc1, 0xb4, + 0xc0, 0x5d, 0x06, 0x45, 0xdd, 0x7e, 0xa7, 0x34, + 0xa1, 0x21, 0xc2, 0x62, 0xab, 0x22, 0x45, 0x3d, + 0x73, 0x4c, 0x26, 0xd1, 0x1a, 0xb2, 0xf0, 0xb2, + 0x6d, 0x11, 0x70, 0x58, 0xaa, 0xf5, 0xa4, 0xf5, + 0xf8, 0x0b, 0x3d, 0xc1, 0xf6, 0x17, 0x70, 0x15, + 0xcd, 0x72, 0x02, 0x7e, 0x4e, 0x94, 0x96, 0x0a, + 0x56, 0xcc, 0xa5, 0xa3, 0xb3, 0x7e, 0xdd, 0x5a, + 0x72, 0xd2, 0xfb, 0xac, 0x3d, 0x0e, 0x66, 0x65, + 0xe9, 0x08, 0x6c, 0xb0, 0x1c, 0xe2, 0x1a, 0x82, + 0xf6, 0xf3, 0x34, 0x89, 0x73, 0x02, 0x5b, 0x42, + 0x6d, 0x40, 0x61, 0xb6, 0xe0, 0xe6, 0x53, 0x32, + 0xa5, 0x72, 0x17, 0x4f, 0x3b, 0x51, 0x4f, 0xbc, + 0x00, 0xe0, 0x69, 0x26, 0xa9, 0xae, 0x83, 0xe3, + 0x73, 0x7f, 0x71, 0x97, 0xe0, 0xdc, 0x7c, 0x63, + 0x9c, 0x85, 0x5f, 0xdf, 0x7d, 0xe4, 0x6c, 0xd8, + 0xa9, 0x3a, 0x6f, 0x5e, 0x4a, 0x2e, 0xb0, 0xe7, + 0x8b, 0x45, 0xe2, 0x90, 0x05, 0x37, 0xe8, 0xab, + 0x49, 0x48, 0x4c, 0xc0, 0x59, 0x1d, 0x8c, 0x46, + 0x5b, 0x84, 0xe0, 0x83, 0xce, 0xea, 0x4b, 0xf9, + 0xd4, 0xdc, 0x63, 0xdf, 0x79, 0xb7, 0x5c, 0x11, + 0x25, 0x7f, 0x90, 0x2e, 0x0a, 0x38, 0x03, 0xea, + 0xea, 0xa1, 0x26, 0x52, 0x20, 0x19, 0xa3, 0xbe, + 0xfc, 0x9d, 0xb7, 0x6e, 0xa6, 0x58, 0x8e, 0x6d, + 0xc5, 0x58, 0xe9, 0xed, 0x2f, 0x55, 0x43, 0x8b, + 0x03, 0x8b, 0xe6, 0xa4, 0xc2, 0x25, 0x4b, 0x36, + 0xba, 0xd3, 0x27, 0x48, 0x40, 0x2e, 0x87, 0xa2, + 0xd4, 0x12, 0xc6, 0x05, 0x36, 0x03, 0x11, 0x51, + 0xd1, 0xf2, 0xac, 0x71, 0x2c, 0xb6, 0xc3, 0xa5, + 0x57, 0x0f, 0xaf, 0x4b, 0xbd, 0xcd, 0x47, 0x4c, + 0x3a, 0x52, 0x6f, 0x47, 0xe7, 0x0b, 0xb7, 0xd5, + 0xf7, 0xa6, 0x39, 0x63, 0x82, 0x08, 0x4c, 0x41, + 0x0e, 0x2a, 0x52, 0x42, 0x5a, 0xea, 0x59, 0xc7, + 0x94, 0xfb, 0xd0, 0x88, 0x47, 0x27, 0xf6, 0x97, + 0x03, 0x9e, 0x29, 0xb8, 0x3a, 0x67, 0xe6, 0xf3, + 0x95, 0xa7, 0x42, 0xc1, 0x96, 0xd1, 0x9a, 0xa6, + 0xf0, 0x09, 0x0c, 0xea, 0xe0, 0xab, 0x0f, 0x15, + 0xe9, 0xc3, 0xeb, 0xa5, 0x89, 0x86, 0x98, 0x32, + 0x83, 0xab, 0x30, 0x33, 0xae, 0x90, 0x8d, 0x2e, + 0xb3, 0xaa, 0x91, 0xa6, 0xd9, 0xa4, 0x4a, 0x54, + 0xe0, 0xd3, 0x08, 0xcc, 0x79, 0xce, 0xe4, 0x15, + 0x31, 0xa6, 0xce, 0x61, 0xcf, 0x03, 0x06, 0xee, + 0x8e, 0xe2, 0x64, 0x29, 0xd1, 0x54, 0x9b, 0xd0, + 0x5f, 0x09, 0x2b, 0x8b, 0xd5, 0xf8, 0xd4, 0x7d, + 0xf1, 0x97, 0x32, 0xd9, 0xea, 0x5a, 0x0e, 0x10, + 0x8c, 0x4d, 0xfb, 0x55, 0xe6, 0x27, 0x0c, 0xba, + 0xc1, 0x73, 0xc1, 0x73, 0xe3, 0x1c, 0x09, 0xb3, + 0x6f, 0xb4, 0x12, 0xfa, 0xf3, 0x29, 0xdc, 0x23, + 0x32, 0xed, 0x80, 0x87, 0x83, 0xc2, 0xf6, 0x07, + 0xb5, 0xa9, 0x22, 0xde, 0x66, 0x1a, 0xa7, 0x4a, + 0x86, 0xf1, 0x39, 0x9b, 0xf4, 0xe7, 0x50, 0x15, + 0x4a, 0x55, 0x3c, 0x93, 0xb9, 0xf9, 0xfd, 0xdc, + 0xb3, 0x5d, 0x73, 0x52 + }; + + return linuxkm_test_xmss_driver(WOLFKM_XMSS_DRIVER, + xmss_kat_pub, + (word32)sizeof(xmss_kat_pub), + xmss_kat_sig, + (word32)sizeof(xmss_kat_sig), + xmss_kat_msg, + (word32)sizeof(xmss_kat_msg)); +} + +#ifdef LINUXKM_LKCAPI_REGISTER_XMSS_MT +static int linuxkm_test_xmssmt(void) +{ + /* XMSSMT-SHA2_20/2_256 vectors generated with wolfCrypt itself + * (keygen + sign + independent pub-import verify); unlike the + * single-tree vectors above, these have no external-reference + * provenance. */ + static const byte xmssmt_kat_pub[] = { + 0x00, 0x00, 0x00, 0x01, 0xb1, 0x77, 0xc5, 0x84, + 0xf5, 0xa7, 0xfb, 0x2f, 0x9f, 0xc0, 0x67, 0xca, + 0x6f, 0x61, 0xb0, 0xd0, 0xe4, 0x0d, 0x72, 0x9c, + 0x87, 0xa7, 0x2b, 0x2b, 0x65, 0x19, 0x25, 0xb5, + 0x27, 0xc9, 0xc9, 0xc8, 0xc2, 0xae, 0x24, 0x2d, + 0xbb, 0xa3, 0xcd, 0x3f, 0x0f, 0x5a, 0x02, 0x82, + 0x3a, 0xf4, 0xd3, 0xd7, 0xcf, 0x48, 0x91, 0x62, + 0x5e, 0x5c, 0x06, 0x15, 0x26, 0xa8, 0x66, 0x9e, + 0xb9, 0x90, 0x5c, 0x5a + }; + + static const byte xmssmt_kat_msg[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + + static const byte xmssmt_kat_sig[] = { + 0x00, 0x00, 0x00, 0x6c, 0x38, 0x84, 0xdf, 0xcb, + 0xd4, 0x14, 0xdb, 0x1d, 0x72, 0x37, 0x55, 0xdf, + 0x93, 0x85, 0x75, 0xfd, 0x44, 0x33, 0x0a, 0xcc, + 0x64, 0xc8, 0xbd, 0x23, 0x02, 0x0e, 0x87, 0x56, + 0x1a, 0x93, 0x2c, 0x07, 0xc7, 0xa7, 0x9c, 0xfc, + 0xcd, 0xf0, 0x08, 0x18, 0xa0, 0xde, 0x75, 0xff, + 0x77, 0x55, 0xd8, 0x14, 0xfa, 0x69, 0xc5, 0x97, + 0x59, 0xde, 0x02, 0x0d, 0xf4, 0x6a, 0x46, 0xae, + 0x0e, 0x75, 0x38, 0xf7, 0x25, 0xc7, 0xcd, 0xa2, + 0x9a, 0x5e, 0x65, 0xae, 0xb5, 0x4e, 0x11, 0xfa, + 0x78, 0x38, 0x23, 0x13, 0x1f, 0xf9, 0x86, 0x72, + 0x6b, 0x01, 0x22, 0xe8, 0xe1, 0x53, 0x01, 0x6d, + 0x37, 0x19, 0xeb, 0xcf, 0xdc, 0xce, 0xa2, 0x65, + 0x14, 0x8b, 0x64, 0x7f, 0xd1, 0x5c, 0xf0, 0x3d, + 0x5e, 0xb6, 0x81, 0x5c, 0x68, 0x95, 0x3c, 0x9c, + 0x70, 0x40, 0xb9, 0xd4, 0x20, 0x89, 0x2e, 0x2d, + 0x74, 0x9b, 0xd1, 0x9b, 0x3d, 0x8c, 0x19, 0x57, + 0x0c, 0xaf, 0xec, 0xe5, 0xb1, 0xf3, 0xde, 0x0e, + 0x75, 0xf6, 0x9f, 0x57, 0x30, 0x6a, 0x19, 0xcc, + 0xea, 0x07, 0x9a, 0x3b, 0xd3, 0x07, 0xc6, 0xd2, + 0x9c, 0x18, 0xad, 0x09, 0xf2, 0x64, 0x7c, 0xbb, + 0xce, 0xf0, 0x2a, 0x98, 0xbb, 0x35, 0x45, 0x0a, + 0x01, 0x54, 0x9e, 0xbe, 0x2d, 0xea, 0x3a, 0xb3, + 0xba, 0xfa, 0x3d, 0xe5, 0x6d, 0x11, 0x00, 0x32, + 0x03, 0x72, 0x81, 0xf4, 0x33, 0xb6, 0x97, 0x1f, + 0x20, 0xa7, 0x71, 0xd5, 0x98, 0x7c, 0xa7, 0xe3, + 0x32, 0x7d, 0xfa, 0x0b, 0x21, 0x6a, 0xf6, 0x13, + 0x46, 0xfe, 0x76, 0xed, 0x71, 0x4c, 0x1d, 0xaf, + 0xf2, 0xbb, 0xff, 0x7b, 0x63, 0x44, 0x6c, 0x69, + 0x37, 0x98, 0x1b, 0xa0, 0x6a, 0x75, 0xd2, 0xbc, + 0xc5, 0x93, 0x4e, 0xf5, 0x34, 0x9e, 0x4e, 0x63, + 0xfa, 0xfb, 0x44, 0x70, 0x58, 0xe5, 0x85, 0x25, + 0xfc, 0xab, 0xbd, 0x07, 0xf1, 0x66, 0xf4, 0x29, + 0x17, 0x13, 0x8a, 0x12, 0x33, 0x12, 0x85, 0xf1, + 0x44, 0x71, 0x0e, 0x7e, 0xee, 0xc1, 0x31, 0xf1, + 0x4a, 0x65, 0x43, 0x12, 0xdf, 0x70, 0xd6, 0x67, + 0xc1, 0x3d, 0xb2, 0xff, 0xf3, 0x3e, 0xf6, 0xd7, + 0x26, 0x02, 0x12, 0xa7, 0x12, 0xe4, 0xb0, 0x1c, + 0xfc, 0x89, 0x5a, 0x5b, 0x87, 0x52, 0xc6, 0xc4, + 0x27, 0xe7, 0x92, 0x01, 0x7d, 0x00, 0xdc, 0x77, + 0xbb, 0x68, 0xe4, 0x48, 0x14, 0x9b, 0xb1, 0xf3, + 0x8e, 0x68, 0xd8, 0x80, 0xf2, 0xd1, 0xf2, 0xbc, + 0x61, 0x7d, 0x61, 0x8d, 0x23, 0xbf, 0x27, 0x2f, + 0xf0, 0x39, 0x2b, 0xb3, 0x30, 0xa1, 0x9d, 0x79, + 0x57, 0xd2, 0x8e, 0x3b, 0x2f, 0x6b, 0x66, 0xf0, + 0x29, 0xc3, 0x77, 0xd3, 0xb1, 0x65, 0x5f, 0xbc, + 0x80, 0xa8, 0x36, 0x6f, 0xed, 0xb1, 0xc0, 0xf0, + 0xc4, 0xe3, 0x5f, 0xe5, 0x01, 0x06, 0x1b, 0x92, + 0x4b, 0x8d, 0x96, 0x1d, 0x9a, 0x53, 0x56, 0xc4, + 0x3c, 0x4b, 0x5f, 0xb1, 0x18, 0x05, 0x9b, 0x6c, + 0xa2, 0x7d, 0x33, 0x64, 0x8e, 0x62, 0xa7, 0x67, + 0x9e, 0x40, 0xbe, 0x48, 0x73, 0x74, 0xc5, 0xd5, + 0x34, 0x94, 0xca, 0xcc, 0xe0, 0x69, 0x36, 0x14, + 0x8d, 0x5f, 0x8f, 0x1e, 0x69, 0x76, 0x65, 0xea, + 0x38, 0x99, 0xf3, 0xfb, 0x22, 0x96, 0x7a, 0x64, + 0xd5, 0x2b, 0x7a, 0x8f, 0xd6, 0xa5, 0x21, 0x48, + 0x12, 0x71, 0xbe, 0x3d, 0x6e, 0xfc, 0x9c, 0x22, + 0xba, 0x8a, 0xcd, 0xeb, 0xe9, 0x84, 0xdc, 0xab, + 0x3d, 0x8a, 0x08, 0x90, 0x2f, 0x04, 0x12, 0x9b, + 0x28, 0xdc, 0x99, 0xb6, 0x5e, 0x6c, 0xca, 0xcd, + 0x8a, 0xa7, 0xc3, 0x59, 0xbe, 0xb1, 0x71, 0x26, + 0x1d, 0x94, 0xe5, 0x7e, 0xb2, 0xb3, 0xb7, 0xc0, + 0x10, 0xc9, 0x10, 0x56, 0x56, 0x17, 0x38, 0x06, + 0x5f, 0x4d, 0xc3, 0x6f, 0xf3, 0x32, 0x7d, 0x6d, + 0xe9, 0x7a, 0xa8, 0x60, 0xd7, 0x34, 0xe6, 0xee, + 0xea, 0x35, 0xee, 0xfa, 0x3b, 0xab, 0x6a, 0xa8, + 0xdc, 0x7a, 0x51, 0x48, 0x4d, 0xb7, 0xfa, 0x1a, + 0xdf, 0x98, 0x76, 0xca, 0xcb, 0x49, 0xce, 0x62, + 0xc8, 0x22, 0x82, 0xc1, 0x4c, 0x70, 0x2a, 0x1e, + 0xbf, 0x23, 0xc9, 0x59, 0x76, 0x52, 0x0d, 0x33, + 0x03, 0x68, 0x15, 0xf6, 0x64, 0x99, 0xae, 0xaa, + 0x95, 0xa4, 0x59, 0x31, 0x5c, 0xf1, 0xef, 0x2b, + 0xe4, 0x2d, 0x0e, 0x98, 0xe1, 0x28, 0xbd, 0xcd, + 0xf4, 0x40, 0x4e, 0x92, 0xc1, 0x24, 0xca, 0x3f, + 0x4e, 0x77, 0xcb, 0x51, 0xd0, 0x1d, 0x6b, 0x9c, + 0xd3, 0x49, 0xc4, 0xf3, 0x93, 0xe0, 0xc6, 0xec, + 0x9e, 0xaa, 0x21, 0xa4, 0x5f, 0xa6, 0x9c, 0xea, + 0x88, 0x76, 0x22, 0x1d, 0x93, 0x80, 0xe3, 0x82, + 0x42, 0xa3, 0x67, 0xd5, 0x57, 0x9c, 0x74, 0xaa, + 0xa9, 0xc9, 0xed, 0xf7, 0x95, 0x8c, 0x79, 0x26, + 0x7e, 0x5b, 0x59, 0xba, 0xc5, 0x9a, 0x3e, 0x15, + 0x2c, 0x78, 0x3d, 0x26, 0x22, 0xce, 0x21, 0xc3, + 0x77, 0x8a, 0x29, 0x5f, 0x6d, 0xf0, 0xcd, 0x58, + 0xf1, 0x70, 0x40, 0xda, 0x04, 0xbd, 0xdf, 0x1d, + 0x5b, 0x75, 0x7c, 0xdd, 0x65, 0xdd, 0x2e, 0xb6, + 0x13, 0x08, 0xf1, 0xf3, 0x59, 0x81, 0xb8, 0x90, + 0x12, 0xf9, 0xd9, 0xc8, 0x88, 0x1e, 0x58, 0x86, + 0x79, 0x0d, 0x04, 0xb5, 0xe4, 0xcd, 0x66, 0xec, + 0x8f, 0xfe, 0x9e, 0xea, 0xcb, 0xf5, 0xae, 0x3d, + 0x9e, 0x5c, 0x0e, 0xca, 0x4a, 0x10, 0x86, 0x5f, + 0x3a, 0x89, 0x7a, 0xc7, 0x88, 0x77, 0xbc, 0x6a, + 0x02, 0x7a, 0x2c, 0xd5, 0x6f, 0x52, 0xeb, 0xdd, + 0xc7, 0x62, 0x5f, 0xb0, 0x28, 0x55, 0xc2, 0x77, + 0xc2, 0x8b, 0x56, 0xb8, 0xfd, 0x02, 0x87, 0xf7, + 0xc1, 0x73, 0xee, 0x03, 0x69, 0x3b, 0x12, 0x90, + 0x24, 0x18, 0x37, 0xe3, 0xd8, 0xf2, 0xed, 0x23, + 0x88, 0x1e, 0x2c, 0xd8, 0xf4, 0x10, 0x49, 0x52, + 0xfc, 0x58, 0xa5, 0xf2, 0x91, 0xef, 0x8c, 0x2c, + 0x63, 0xe8, 0x1f, 0xab, 0x57, 0xd9, 0xde, 0xcf, + 0x01, 0x18, 0x17, 0xd5, 0xd3, 0x12, 0x7d, 0x0e, + 0xdb, 0xbc, 0x18, 0xb1, 0x1d, 0x7e, 0x96, 0x49, + 0x8e, 0x22, 0x94, 0xd1, 0x1c, 0x77, 0xa3, 0xc8, + 0xfc, 0x0b, 0x7b, 0xab, 0xfd, 0x58, 0xd9, 0xbb, + 0xc7, 0x14, 0x8c, 0xb3, 0xda, 0x93, 0xe2, 0x6b, + 0x38, 0x23, 0x21, 0x61, 0x0d, 0xd9, 0xc7, 0x96, + 0xce, 0x6a, 0xc4, 0x12, 0xc1, 0xac, 0x75, 0x23, + 0x5a, 0x05, 0xa9, 0x43, 0x3f, 0xa0, 0xae, 0xd4, + 0x20, 0x39, 0x02, 0xc8, 0x7a, 0xa8, 0x4a, 0x04, + 0x91, 0x54, 0x66, 0x06, 0xfd, 0x01, 0x03, 0x4c, + 0xeb, 0xc8, 0xc8, 0x80, 0x28, 0x07, 0x00, 0x74, + 0x5a, 0xac, 0xe3, 0x52, 0xda, 0x59, 0xca, 0x29, + 0xd8, 0xfc, 0x65, 0xfe, 0x03, 0x17, 0x6f, 0xfa, + 0x21, 0x84, 0x29, 0x89, 0xb9, 0x84, 0xed, 0x30, + 0xe5, 0x37, 0xf5, 0xe9, 0x7c, 0x00, 0x0b, 0x33, + 0x3d, 0x73, 0x11, 0x7b, 0x9b, 0x55, 0x3d, 0x76, + 0xe6, 0x88, 0x54, 0xd9, 0xe6, 0xd7, 0x31, 0x35, + 0xe7, 0xa8, 0x8c, 0x59, 0xfa, 0xd1, 0x0c, 0x56, + 0xb5, 0x89, 0x46, 0x86, 0x8b, 0xe1, 0xff, 0x61, + 0xe2, 0xd8, 0xf6, 0x82, 0x66, 0xd6, 0xfa, 0x14, + 0x28, 0x99, 0xa1, 0x76, 0x89, 0xa7, 0x25, 0x4b, + 0x8f, 0x47, 0x83, 0x73, 0x8b, 0xe8, 0x63, 0xc0, + 0xb2, 0xa8, 0x47, 0x53, 0x3f, 0x4f, 0xa0, 0xf0, + 0xf7, 0xcf, 0x00, 0xf7, 0xda, 0x8b, 0x9e, 0x33, + 0xde, 0x58, 0xd4, 0xc7, 0xb5, 0x1a, 0x8f, 0x58, + 0x61, 0x2d, 0xf1, 0x89, 0xfa, 0x4f, 0xdb, 0xdd, + 0xac, 0xef, 0xb7, 0xdb, 0x48, 0x8e, 0xdd, 0xb5, + 0x8a, 0x28, 0x91, 0x02, 0x3b, 0x8f, 0x9b, 0xfe, + 0x23, 0x1b, 0x2b, 0xae, 0xb5, 0x2f, 0xdc, 0x5a, + 0x4b, 0x3d, 0x0b, 0x03, 0xf5, 0x9a, 0x14, 0xe6, + 0x12, 0xb6, 0xa9, 0xd2, 0x8a, 0xbf, 0xaf, 0xb8, + 0x8b, 0xa8, 0x8d, 0x22, 0xe7, 0x7d, 0xd2, 0x14, + 0x64, 0xea, 0x82, 0x30, 0x65, 0x73, 0x4d, 0x39, + 0x11, 0x4c, 0x23, 0x92, 0x65, 0xa1, 0x97, 0x98, + 0xdc, 0x8b, 0xa6, 0xbf, 0xa4, 0x4c, 0x8d, 0x03, + 0x6a, 0xc0, 0x56, 0xc4, 0x8b, 0x62, 0x6c, 0x6d, + 0x33, 0xd4, 0x25, 0x92, 0x4a, 0xe7, 0xd0, 0x06, + 0x9d, 0xaf, 0x78, 0xcd, 0x16, 0x01, 0x44, 0x0a, + 0x74, 0xbf, 0xd3, 0xdc, 0x54, 0xb7, 0x4a, 0x1a, + 0x46, 0x5e, 0x16, 0x52, 0x52, 0xad, 0x7e, 0x6b, + 0xf9, 0xda, 0x3b, 0x8f, 0xea, 0xc3, 0x71, 0x55, + 0xbc, 0x73, 0x7d, 0xc2, 0xde, 0x39, 0xc4, 0x17, + 0x99, 0x41, 0xc6, 0x4a, 0xdc, 0x98, 0x6d, 0x43, + 0xf6, 0x21, 0x8c, 0x20, 0xa1, 0x41, 0x80, 0xca, + 0xb3, 0xeb, 0x15, 0xd1, 0xf1, 0x52, 0x1c, 0xa9, + 0x05, 0x0e, 0xbc, 0x8f, 0x98, 0xd1, 0x7d, 0x77, + 0x8e, 0xc6, 0x67, 0xd9, 0x8e, 0xff, 0xc9, 0xf4, + 0xd8, 0x46, 0xe4, 0xcc, 0xb3, 0x4d, 0xeb, 0x93, + 0x3e, 0x3e, 0x81, 0x87, 0x23, 0x7f, 0xd4, 0xe8, + 0x30, 0xf4, 0x19, 0xce, 0x0d, 0x91, 0x1c, 0xbd, + 0xfd, 0xf5, 0xf3, 0x88, 0x44, 0xc2, 0xd3, 0x13, + 0xff, 0x1e, 0x29, 0xd0, 0x14, 0xe5, 0x14, 0x2f, + 0x84, 0xd2, 0x82, 0xbc, 0x9c, 0x39, 0xf1, 0xf6, + 0xd1, 0x5d, 0x3c, 0x8f, 0xb2, 0xe2, 0xd3, 0x19, + 0x2d, 0xf1, 0xcd, 0x70, 0x4b, 0x18, 0xb8, 0xdc, + 0x3b, 0x14, 0xb4, 0x5e, 0x1f, 0x71, 0x97, 0x50, + 0xf4, 0xf1, 0x5d, 0xe4, 0x64, 0x7a, 0x49, 0x65, + 0xc8, 0xe0, 0x76, 0x39, 0x34, 0xda, 0x30, 0xe2, + 0x6e, 0x53, 0xbd, 0x97, 0xbd, 0x16, 0x69, 0x91, + 0x32, 0x0d, 0xae, 0xbf, 0xa7, 0x65, 0xdd, 0x87, + 0x09, 0x6e, 0xae, 0x4e, 0x64, 0x3b, 0x13, 0x47, + 0xd6, 0x08, 0x2d, 0x45, 0x7c, 0x19, 0x7a, 0x6c, + 0xb4, 0x85, 0x1b, 0xe7, 0xe8, 0x11, 0x3f, 0x30, + 0x21, 0xf7, 0x8e, 0x7b, 0x4f, 0x26, 0x52, 0xcc, + 0xbd, 0xef, 0xf1, 0x82, 0x8d, 0x4f, 0x70, 0x0d, + 0xf6, 0x26, 0xd5, 0x17, 0x87, 0xae, 0xb3, 0x87, + 0x5a, 0x49, 0xf6, 0x57, 0xed, 0x46, 0xab, 0x08, + 0x30, 0x5c, 0xca, 0x62, 0xdf, 0x48, 0xc3, 0xcb, + 0x8b, 0x84, 0xba, 0x2f, 0xdc, 0xc2, 0xbd, 0xb9, + 0x78, 0x51, 0xdf, 0x6a, 0xcc, 0xb3, 0x58, 0xac, + 0xaf, 0x02, 0x94, 0xdc, 0x7c, 0x8c, 0xb7, 0xca, + 0x66, 0xe8, 0xad, 0x45, 0x32, 0x07, 0x41, 0x9f, + 0xff, 0x67, 0x28, 0xed, 0x4a, 0x9f, 0x78, 0x50, + 0x20, 0x51, 0x10, 0x5a, 0xd0, 0x5e, 0xba, 0x8d, + 0xda, 0x3d, 0x11, 0xae, 0x45, 0x42, 0x10, 0x49, + 0x7d, 0x23, 0x66, 0x13, 0x9d, 0x14, 0x43, 0x00, + 0x0a, 0x07, 0x7b, 0x93, 0x88, 0x6e, 0xf8, 0x5f, + 0xf1, 0x11, 0x89, 0xbd, 0xfe, 0x30, 0x21, 0x78, + 0x56, 0x3e, 0xf1, 0xcb, 0x1b, 0x58, 0x7b, 0x72, + 0x71, 0xfe, 0x8e, 0x1e, 0x03, 0xb4, 0x32, 0xfa, + 0x67, 0x0e, 0x1f, 0x39, 0xed, 0xa0, 0x78, 0xf4, + 0x35, 0xe0, 0x47, 0x43, 0x72, 0x29, 0x97, 0x12, + 0x66, 0x1d, 0xc4, 0x89, 0xae, 0x65, 0x6b, 0xcd, + 0x88, 0xfc, 0xdc, 0x93, 0x7a, 0x06, 0xa0, 0xb9, + 0x45, 0xdf, 0x69, 0x70, 0xd5, 0x23, 0x1d, 0xee, + 0x4f, 0x21, 0x65, 0xc2, 0xe4, 0x22, 0xd9, 0x6d, + 0xde, 0x2a, 0x99, 0xd1, 0xb4, 0xbf, 0x36, 0x6f, + 0x16, 0xb9, 0x88, 0x65, 0xb1, 0xeb, 0x1d, 0x25, + 0xe7, 0x32, 0xec, 0xe6, 0x4c, 0x37, 0xe5, 0xe3, + 0x8b, 0x67, 0x2f, 0x36, 0xf3, 0x44, 0x63, 0x0e, + 0xaf, 0x45, 0x62, 0xdf, 0xb3, 0x3b, 0xa7, 0xee, + 0x67, 0x5b, 0x1d, 0xe8, 0xe8, 0x67, 0xc6, 0x6d, + 0x02, 0x65, 0xa7, 0xf7, 0xf1, 0x7b, 0xe6, 0xf5, + 0xa0, 0x7c, 0xbc, 0x90, 0x33, 0xca, 0xd1, 0x8f, + 0xa7, 0xab, 0xca, 0xed, 0x47, 0x2c, 0x40, 0x3e, + 0xea, 0x2e, 0x38, 0xf5, 0x70, 0x0b, 0x0e, 0x2b, + 0x8a, 0x81, 0x5e, 0xc5, 0x3f, 0xc1, 0xdd, 0xef, + 0xfd, 0xd4, 0x96, 0xca, 0x6c, 0x0a, 0x8e, 0xfe, + 0x39, 0xf8, 0x06, 0xbb, 0x3e, 0xaa, 0x18, 0x2e, + 0xdc, 0x95, 0xac, 0x4f, 0x9a, 0x1e, 0x5a, 0xcc, + 0x48, 0x14, 0xf4, 0x41, 0x00, 0x41, 0xb9, 0x72, + 0x1b, 0xc4, 0xcd, 0xfc, 0xd5, 0x5a, 0xfe, 0xd2, + 0x0c, 0x46, 0x36, 0xeb, 0xb8, 0x9d, 0xba, 0x2f, + 0x76, 0x0f, 0x11, 0x3d, 0xcd, 0xe4, 0xad, 0x0b, + 0xb3, 0xc7, 0x0b, 0x02, 0x9a, 0x49, 0xc6, 0xd3, + 0x2f, 0xd1, 0x23, 0x94, 0x67, 0xa9, 0x1d, 0xce, + 0x15, 0x56, 0xd4, 0xd4, 0x93, 0x63, 0x64, 0x64, + 0xbc, 0x55, 0x80, 0x82, 0xe4, 0xef, 0xea, 0xca, + 0x51, 0x0f, 0x4f, 0x03, 0x2b, 0x62, 0x43, 0xca, + 0x16, 0xc1, 0x38, 0x20, 0x73, 0xf1, 0x3f, 0x9e, + 0x42, 0x8f, 0x3c, 0xf0, 0x8e, 0x88, 0xa8, 0x09, + 0x1d, 0xc6, 0x23, 0xab, 0x64, 0xd6, 0xd0, 0xc8, + 0xa1, 0xb1, 0x70, 0x6a, 0x03, 0xb7, 0xab, 0xf6, + 0xe8, 0xdc, 0x1e, 0xc9, 0x4d, 0x86, 0xda, 0xf7, + 0x72, 0x7d, 0xdc, 0x57, 0xcc, 0x1b, 0xa7, 0xeb, + 0x1c, 0x55, 0x5f, 0x3d, 0x65, 0x00, 0xe2, 0x98, + 0x69, 0x4e, 0x1f, 0x47, 0x7c, 0x6a, 0x32, 0xd1, + 0x5b, 0x6c, 0xec, 0x45, 0x64, 0x6d, 0x1a, 0x70, + 0xa4, 0x9f, 0x1b, 0x12, 0x1c, 0xec, 0x00, 0x45, + 0x12, 0x70, 0x39, 0x2a, 0xd2, 0x8b, 0xb0, 0x1a, + 0xfb, 0x14, 0x8c, 0x68, 0x8e, 0x3f, 0xa0, 0xe7, + 0xea, 0x6a, 0xf5, 0xaf, 0xad, 0x12, 0x37, 0xf4, + 0xdf, 0xdb, 0xae, 0xaf, 0x40, 0xac, 0xef, 0xbb, + 0xaa, 0xe2, 0x2e, 0xbc, 0xc8, 0xe3, 0x5c, 0xef, + 0xe6, 0x09, 0x55, 0xe5, 0x0a, 0xfc, 0xb9, 0xb3, + 0x0e, 0x8b, 0xf9, 0x3f, 0x82, 0x42, 0x94, 0xd1, + 0x0e, 0x5a, 0x1b, 0x1b, 0x5e, 0x12, 0x7c, 0xf4, + 0x22, 0x8e, 0x14, 0x6a, 0x14, 0x87, 0xab, 0x8c, + 0x89, 0xf0, 0xb5, 0xbd, 0x19, 0xaf, 0x1e, 0x2f, + 0x59, 0x5a, 0xb5, 0xbb, 0xc5, 0xf9, 0x04, 0x9a, + 0xaa, 0x21, 0x1f, 0xe2, 0xf3, 0xd2, 0x07, 0x07, + 0xfe, 0x14, 0x11, 0xee, 0x4d, 0x78, 0x10, 0xfb, + 0x67, 0x49, 0x16, 0x72, 0x47, 0xe8, 0x89, 0xb0, + 0x61, 0x45, 0x60, 0xaa, 0x61, 0x95, 0xb5, 0x3a, + 0xe1, 0x7d, 0x29, 0x62, 0x89, 0xb3, 0xba, 0xa5, + 0x01, 0xae, 0x90, 0x7b, 0x73, 0x93, 0xbe, 0x40, + 0xff, 0xe0, 0x1f, 0x9b, 0x87, 0xa6, 0x3c, 0x5c, + 0x01, 0xc1, 0x64, 0xa8, 0x47, 0xd9, 0xa9, 0x89, + 0x9b, 0x98, 0x17, 0x74, 0xe3, 0x3a, 0x0a, 0x2b, + 0xb6, 0xf0, 0xc0, 0x41, 0xbb, 0xae, 0x57, 0xbd, + 0xcf, 0x97, 0xe1, 0xdc, 0xc5, 0x1b, 0x2f, 0x18, + 0xea, 0xde, 0x01, 0xce, 0xf7, 0x7a, 0x3e, 0xf5, + 0xcb, 0x81, 0x98, 0x77, 0x0c, 0xb9, 0x34, 0x9e, + 0x6a, 0x11, 0x6f, 0x45, 0x37, 0x6c, 0xd7, 0x3d, + 0xaa, 0x1a, 0xbb, 0xcd, 0x3d, 0xc4, 0x39, 0x06, + 0x87, 0x02, 0xd0, 0x36, 0xa4, 0x93, 0xc5, 0x85, + 0x43, 0x24, 0x8f, 0xf6, 0x8a, 0x0a, 0xe1, 0xc5, + 0xda, 0xc0, 0x32, 0xac, 0x9f, 0xc7, 0xb4, 0xce, + 0x6a, 0xcb, 0x32, 0xe2, 0xd2, 0x26, 0x80, 0xce, + 0x32, 0x7b, 0x14, 0xaa, 0x36, 0x04, 0xec, 0x88, + 0xbb, 0x68, 0x13, 0x9e, 0x75, 0xa3, 0x08, 0x21, + 0xd2, 0x0d, 0x64, 0xe1, 0xe5, 0x61, 0x9b, 0x69, + 0x3f, 0x6f, 0x7b, 0xe6, 0x08, 0x28, 0x54, 0x89, + 0xf6, 0x43, 0x36, 0xe8, 0x9f, 0xa1, 0x98, 0x84, + 0x52, 0xe4, 0xdc, 0xe6, 0x13, 0x4a, 0xd7, 0x34, + 0x91, 0xe9, 0x48, 0x61, 0x51, 0x0c, 0xd5, 0x21, + 0x81, 0x88, 0x11, 0x74, 0x5c, 0xc9, 0x75, 0x96, + 0x12, 0xbb, 0xdb, 0xf5, 0xa5, 0x0f, 0x35, 0xd6, + 0x39, 0x7a, 0x8d, 0x0e, 0x1e, 0x6b, 0xbc, 0x78, + 0x0f, 0x47, 0x77, 0x88, 0x45, 0x1c, 0x4f, 0x2b, + 0x17, 0x7a, 0xd3, 0x24, 0x4c, 0x6c, 0x5d, 0xa5, + 0x3f, 0xca, 0x0f, 0x32, 0x50, 0x6d, 0x60, 0x67, + 0x15, 0x07, 0xff, 0xbe, 0xef, 0xd6, 0x59, 0x1f, + 0xe7, 0x11, 0x6c, 0x6f, 0x1c, 0xde, 0x6a, 0xa9, + 0x77, 0xd2, 0xaf, 0x0e, 0x23, 0x0a, 0x13, 0xfd, + 0x4c, 0x2b, 0xfa, 0x01, 0x90, 0x6e, 0xf8, 0xf4, + 0x47, 0x0d, 0xdb, 0x18, 0x85, 0x8a, 0x02, 0x6b, + 0x16, 0x70, 0x44, 0xd7, 0x9d, 0xe7, 0x27, 0x52, + 0x37, 0x6d, 0x62, 0x08, 0x11, 0xd9, 0xa9, 0xe7, + 0xa6, 0x0b, 0x5e, 0xe0, 0xaf, 0x84, 0xbc, 0x3b, + 0x15, 0x97, 0x11, 0xf5, 0xeb, 0xff, 0x37, 0xc2, + 0xa1, 0xe6, 0x82, 0xac, 0xb2, 0x39, 0xf6, 0x1b, + 0x89, 0x4f, 0xb9, 0xcb, 0x42, 0x33, 0x0a, 0xa4, + 0x8e, 0x94, 0xd3, 0x5b, 0xa7, 0x06, 0x79, 0x04, + 0x2f, 0xe5, 0x97, 0x2c, 0x93, 0x5f, 0xfc, 0x9f, + 0xd2, 0xdc, 0xa6, 0x82, 0xce, 0x97, 0x81, 0xa6, + 0xd8, 0x34, 0xff, 0x18, 0x6b, 0xe0, 0x6d, 0xe8, + 0xaa, 0x36, 0x7c, 0x38, 0x93, 0x93, 0xdc, 0x2c, + 0xbb, 0xa3, 0xba, 0xc4, 0xe5, 0x8d, 0x66, 0x94, + 0x9e, 0x6a, 0x2f, 0x74, 0x42, 0x34, 0x5c, 0xce, + 0x5b, 0x4e, 0x8d, 0xf6, 0x58, 0x5a, 0x51, 0x68, + 0x67, 0x04, 0xc6, 0x5e, 0xfa, 0x87, 0x8b, 0xaf, + 0x13, 0xee, 0xff, 0xec, 0x5e, 0x4c, 0xdd, 0x1e, + 0x39, 0x83, 0x8c, 0x52, 0x5f, 0x29, 0xdb, 0xd8, + 0xfa, 0xd3, 0x03, 0xb6, 0x25, 0x51, 0x79, 0x0d, + 0x14, 0xc9, 0x29, 0x67, 0xa9, 0x65, 0x99, 0x23, + 0xc2, 0xb3, 0xa7, 0x22, 0x2f, 0x33, 0x83, 0x27, + 0xec, 0xd1, 0x6b, 0xf1, 0xf9, 0xa2, 0xcd, 0xfc, + 0xc3, 0x77, 0xe7, 0xf7, 0xaf, 0x2a, 0xe2, 0x1d, + 0xa3, 0xcc, 0xba, 0x29, 0x07, 0x17, 0x78, 0x88, + 0xeb, 0xbf, 0x53, 0xbe, 0xcc, 0x16, 0x83, 0x39, + 0x1a, 0xd6, 0xac, 0xc2, 0x3f, 0x2b, 0xfb, 0x1d, + 0x0b, 0x04, 0xcb, 0x5c, 0x92, 0xab, 0x65, 0x7b, + 0xf8, 0x14, 0x1a, 0xb5, 0x37, 0x10, 0x1d, 0xe3, + 0x47, 0x96, 0xa5, 0x35, 0x87, 0xab, 0x2e, 0x52, + 0xcf, 0xcf, 0xc8, 0x17, 0x88, 0x7a, 0x5c, 0x3a, + 0x0f, 0x81, 0xc7, 0x1c, 0xbd, 0x70, 0xbc, 0x7c, + 0x5f, 0x00, 0x67, 0x76, 0xf8, 0x19, 0xaa, 0x06, + 0xbd, 0xad, 0x99, 0x0c, 0x6e, 0x95, 0xb8, 0x26, + 0x81, 0x0b, 0x62, 0x37, 0x6b, 0xdb, 0xd5, 0x2f, + 0x1a, 0x7e, 0x7f, 0x73, 0xa1, 0x05, 0x7e, 0x24, + 0xc3, 0x3a, 0xb3, 0x81, 0x39, 0xc5, 0xeb, 0x51, + 0xab, 0xa2, 0x71, 0x73, 0xfe, 0x7a, 0xda, 0xf5, + 0xe7, 0x7b, 0xfb, 0x2a, 0x23, 0x4a, 0x68, 0x87, + 0xbc, 0x8d, 0x8d, 0xff, 0x17, 0x70, 0x07, 0x26, + 0xd7, 0xb2, 0xf7, 0x03, 0x02, 0x99, 0x1b, 0x94, + 0x48, 0xf3, 0xce, 0xab, 0x66, 0xf7, 0x53, 0x00, + 0x62, 0xa6, 0x4c, 0xd7, 0xc4, 0x72, 0x7c, 0xc6, + 0x52, 0xf3, 0x92, 0x8a, 0x33, 0x7f, 0xa6, 0x9a, + 0x4c, 0x8c, 0x2a, 0x0e, 0x21, 0x53, 0x04, 0xf0, + 0x26, 0xa0, 0xba, 0x01, 0x9e, 0x85, 0x20, 0xf0, + 0x80, 0x0e, 0x36, 0x32, 0x0c, 0x8d, 0xb0, 0xcf, + 0x30, 0xb9, 0xd4, 0xce, 0x15, 0x3a, 0xf0, 0x09, + 0xbc, 0xba, 0xe0, 0x22, 0x66, 0xd0, 0x72, 0x39, + 0xf1, 0x21, 0xee, 0xfc, 0x40, 0x59, 0x9c, 0x3a, + 0xb9, 0xb7, 0xf7, 0xd7, 0x55, 0xef, 0x12, 0xb3, + 0x47, 0xf4, 0x07, 0x03, 0xb5, 0xb4, 0x23, 0x1d, + 0xab, 0xf1, 0x33, 0x94, 0x92, 0xac, 0xfd, 0x79, + 0x32, 0x92, 0x59, 0xd1, 0x72, 0x74, 0xba, 0xb6, + 0xf4, 0x06, 0x31, 0x2f, 0xa5, 0xb0, 0x53, 0xef, + 0xca, 0x76, 0x46, 0xf4, 0x57, 0xd8, 0xd7, 0x43, + 0x1a, 0x67, 0x48, 0x17, 0xb3, 0x45, 0x8d, 0x19, + 0x80, 0x57, 0x38, 0x33, 0xf2, 0x37, 0x28, 0x59, + 0xfe, 0x8a, 0xdf, 0x4d, 0xf7, 0x7c, 0x7b, 0xdf, + 0x6c, 0x38, 0xa0, 0x32, 0x70, 0xd4, 0x95, 0x08, + 0xfb, 0x08, 0xf4, 0xeb, 0x86, 0x2d, 0x99, 0xb4, + 0x8a, 0x98, 0xd1, 0x77, 0x94, 0x30, 0x02, 0x98, + 0x96, 0x5d, 0xe3, 0x90, 0x29, 0x0a, 0xbe, 0x1b, + 0xe1, 0x1c, 0x74, 0xcc, 0xba, 0x22, 0x4b, 0x19, + 0xbd, 0xea, 0x4e, 0xb2, 0x6c, 0x10, 0x0e, 0x32, + 0xb2, 0xba, 0xea, 0xe4, 0xdb, 0x49, 0x52, 0x31, + 0xd5, 0x7c, 0x63, 0x08, 0x63, 0xee, 0x8c, 0x15, + 0x78, 0xe6, 0x26, 0x4c, 0x58, 0x88, 0xe0, 0xbd, + 0x64, 0x97, 0xe2, 0x6a, 0x10, 0xe9, 0x40, 0x63, + 0xc1, 0x16, 0x28, 0xb0, 0xb4, 0xbd, 0x7f, 0x2e, + 0x80, 0xbc, 0xea, 0xcd, 0xfd, 0x3e, 0x6c, 0xe0, + 0x8b, 0xb0, 0xd6, 0xbc, 0x2b, 0x27, 0x8e, 0x36, + 0xbc, 0xd4, 0xcc, 0xc1, 0xfb, 0xa8, 0x1b, 0xa8, + 0xd1, 0x29, 0xe1, 0xe6, 0x0e, 0xc2, 0xbf, 0x9f, + 0x8c, 0x19, 0xba, 0x2b, 0xd7, 0x76, 0x7b, 0x13, + 0x3f, 0xa0, 0xab, 0xb0, 0x89, 0x18, 0x5d, 0x2e, + 0x95, 0xd5, 0xd6, 0x15, 0x4b, 0x7f, 0x46, 0x6c, + 0xcd, 0xbd, 0x68, 0x60, 0x0b, 0xf9, 0x6e, 0x79, + 0x67, 0x61, 0xb2, 0xbe, 0x8b, 0xa5, 0x61, 0x0f, + 0x96, 0xd0, 0xc3, 0xe7, 0x0d, 0x54, 0x78, 0x92, + 0x9b, 0xa0, 0x1c, 0x39, 0x27, 0xe7, 0x4b, 0xd1, + 0xc2, 0x30, 0xe4, 0xaf, 0x10, 0x0d, 0xe3, 0xca, + 0x88, 0xad, 0x93, 0xc7, 0xc5, 0x48, 0x15, 0x06, + 0x9d, 0x72, 0x1d, 0xed, 0xe1, 0x4d, 0xff, 0x47, + 0x9d, 0x15, 0xef, 0x8d, 0xda, 0x6d, 0x06, 0x44, + 0xe9, 0x7f, 0x68, 0xc9, 0x45, 0xed, 0xca, 0xca, + 0xe0, 0xfa, 0x9c, 0x58, 0x47, 0xc4, 0xbf, 0x26, + 0xbb, 0xc6, 0x04, 0x84, 0xe5, 0x4c, 0x30, 0x40, + 0x07, 0x8d, 0xe0, 0x5d, 0x4b, 0x38, 0x96, 0xd2, + 0xd1, 0xe4, 0x5a, 0x3f, 0x2b, 0x9a, 0x1d, 0x83, + 0xc2, 0xc5, 0xef, 0x7f, 0x3e, 0x75, 0x74, 0xc2, + 0xdd, 0xe5, 0x96, 0x43, 0x86, 0xca, 0x2d, 0x15, + 0x8b, 0x66, 0x28, 0xd6, 0x5a, 0xd3, 0xe4, 0xef, + 0x9e, 0x90, 0x12, 0x97, 0x3d, 0xfc, 0xb8, 0x08, + 0x26, 0x71, 0x9f, 0x08, 0x44, 0x66, 0xcb, 0xe2, + 0x3a, 0x9c, 0x7e, 0x02, 0xd0, 0x4d, 0x43, 0xb0, + 0x72, 0x52, 0xfe, 0xab, 0x42, 0x9f, 0x63, 0x1a, + 0xdb, 0x30, 0x57, 0xcb, 0xd5, 0xfd, 0x19, 0x61, + 0x4d, 0xbf, 0x54, 0x72, 0x18, 0x31, 0x44, 0x99, + 0xb4, 0xfb, 0x4c, 0x92, 0xca, 0xd6, 0xbc, 0x45, + 0x00, 0xe7, 0xc9, 0x44, 0x3f, 0x0a, 0xd9, 0x88, + 0xf1, 0xec, 0x4b, 0xf6, 0x80, 0x68, 0xa9, 0xd2, + 0x89, 0x94, 0xe8, 0xa2, 0x38, 0x7e, 0xdc, 0x50, + 0x75, 0xa9, 0x52, 0xd3, 0x3f, 0xd5, 0x54, 0x49, + 0x04, 0x4a, 0x2e, 0xb0, 0x55, 0x16, 0xfe, 0xb8, + 0x4c, 0x05, 0x9a, 0xef, 0x6c, 0xc3, 0xc6, 0x41, + 0xb9, 0x7b, 0xef, 0x01, 0xc9, 0x6f, 0x27, 0x91, + 0x3d, 0x43, 0xcc, 0xa0, 0xeb, 0xe8, 0x46, 0x1e, + 0xef, 0x5c, 0xb4, 0x0a, 0xeb, 0x8a, 0xc3, 0xcd, + 0xda, 0x2d, 0x09, 0x00, 0x35, 0x5e, 0x3a, 0x88, + 0x83, 0x86, 0xdf, 0xb7, 0xca, 0x8e, 0x52, 0x59, + 0xf2, 0xed, 0xea, 0xf2, 0x7a, 0x94, 0xec, 0x43, + 0xb7, 0xdf, 0x11, 0x9e, 0x77, 0x61, 0x57, 0x96, + 0x36, 0x7e, 0x79, 0x88, 0x23, 0x11, 0x44, 0xb4, + 0x8d, 0x55, 0x3d, 0x13, 0xb3, 0xfe, 0x71, 0xaa, + 0xf0, 0xfa, 0x8c, 0x89, 0xb1, 0x63, 0x70, 0x44, + 0xb4, 0x53, 0xf3, 0xc6, 0xd2, 0x47, 0xe3, 0xd9, + 0x54, 0x24, 0x17, 0xc3, 0x66, 0xed, 0xa6, 0x92, + 0x7d, 0x6c, 0xac, 0x1b, 0x9e, 0x12, 0xb8, 0x2d, + 0x17, 0xdb, 0x7c, 0x89, 0x73, 0xc3, 0x4a, 0xb7, + 0xf5, 0x86, 0x18, 0x84, 0xd5, 0x9c, 0xb1, 0xf8, + 0x2a, 0x68, 0x80, 0x74, 0x70, 0x5b, 0x87, 0x27, + 0x1b, 0xc3, 0x4d, 0xc6, 0xb8, 0x36, 0x6b, 0xb9, + 0x29, 0xfb, 0xc8, 0x26, 0xda, 0xa2, 0xfa, 0x01, + 0xaa, 0x56, 0x10, 0xdc, 0xc0, 0x29, 0xe5, 0x99, + 0xa3, 0xc4, 0xe2, 0x07, 0x93, 0xb0, 0xba, 0x1a, + 0xad, 0xa5, 0xe7, 0x45, 0x37, 0x7d, 0x9d, 0x8f, + 0x6b, 0xe0, 0x5a, 0x63, 0x4a, 0xf0, 0x00, 0x87, + 0x62, 0x90, 0xd6, 0x43, 0x8c, 0xfa, 0x91, 0x26, + 0xd4, 0xb9, 0x73, 0xa0, 0x8e, 0x07, 0x3f, 0xb2, + 0x3e, 0xcd, 0x2f, 0x6f, 0x5c, 0x8b, 0x12, 0xb1, + 0x32, 0xb1, 0x90, 0x1b, 0xb3, 0x28, 0x18, 0x48, + 0x6e, 0x98, 0x4c, 0xc0, 0x86, 0x77, 0x7d, 0xa5, + 0xc5, 0x9c, 0xad, 0xe3, 0xad, 0x6d, 0x0e, 0xe8, + 0x1a, 0xfc, 0x0e, 0x5a, 0x44, 0x2f, 0xd1, 0x0c, + 0x44, 0x88, 0x5c, 0x1c, 0xd4, 0x6a, 0x05, 0x6a, + 0x4d, 0x70, 0xf0, 0x61, 0x1e, 0x72, 0x90, 0xbb, + 0xec, 0xae, 0x67, 0xa1, 0x49, 0xf7, 0x79, 0xe2, + 0x7d, 0x90, 0x8b, 0x81, 0xf0, 0x66, 0xc0, 0x30, + 0x25, 0x61, 0xf2, 0xc6, 0xe7, 0xfe, 0xea, 0xf5, + 0xb2, 0x9e, 0xb7, 0x26, 0x7f, 0xbf, 0xb6, 0x6f, + 0xe1, 0x12, 0x32, 0x39, 0x68, 0xc8, 0x6c, 0x7b, + 0xfd, 0xf8, 0xd5, 0x09, 0x57, 0x74, 0x66, 0x0f, + 0x00, 0x80, 0x3d, 0x43, 0x64, 0x14, 0x59, 0x53, + 0x4d, 0xc7, 0xd4, 0xc8, 0x1f, 0x08, 0xda, 0x56, + 0xc3, 0xc9, 0x7a, 0xa2, 0xc3, 0x7b, 0x6d, 0x8e, + 0x21, 0xfb, 0xa0, 0x88, 0xd3, 0x87, 0x24, 0x94, + 0x40, 0xd1, 0x19, 0x2f, 0xc4, 0x91, 0xcd, 0x9b, + 0x25, 0x89, 0xb9, 0x06, 0xa7, 0x21, 0x49, 0xc3, + 0x12, 0x00, 0xc8, 0x95, 0xd9, 0xc1, 0x01, 0x89, + 0x46, 0x5a, 0x0e, 0x43, 0xd4, 0x17, 0xb7, 0x29, + 0x93, 0x82, 0x5d, 0xc1, 0x97, 0xfe, 0x98, 0x8f, + 0xfa, 0xa5, 0xed, 0x75, 0x54, 0xae, 0x42, 0x30, + 0xdf, 0x4d, 0x2a, 0xed, 0x88, 0xc7, 0x90, 0x2e, + 0x31, 0x71, 0x4f, 0xe2, 0xaa, 0xbd, 0x5d, 0xce, + 0x91, 0xdb, 0x11, 0x25, 0xe4, 0x88, 0xcb, 0x0f, + 0x30, 0x6a, 0x71, 0x9b, 0x00, 0xe9, 0x30, 0xf2, + 0x01, 0x3c, 0xb8, 0xe7, 0x75, 0x77, 0x80, 0xa8, + 0x74, 0xa9, 0x5c, 0x41, 0x43, 0xae, 0xfd, 0x3f, + 0x87, 0x3c, 0x18, 0x5c, 0x13, 0xa9, 0x90, 0xca, + 0x4c, 0x4d, 0x94, 0x3a, 0x78, 0xc9, 0xdd, 0x46, + 0x19, 0x29, 0x67, 0xe7, 0x43, 0xd5, 0xe9, 0x21, + 0xff, 0x67, 0xe3, 0x97, 0x75, 0xf1, 0x3a, 0x30, + 0x50, 0x8d, 0x26, 0x6b, 0xce, 0x49, 0xb8, 0xd6, + 0x6f, 0x7b, 0x56, 0x73, 0x46, 0x68, 0xe2, 0x8b, + 0xa0, 0x1e, 0xea, 0xc1, 0x61, 0x65, 0x11, 0xd1, + 0xc1, 0xd7, 0xa6, 0x52, 0xd9, 0x3e, 0xe5, 0x91, + 0x5e, 0x76, 0x1c, 0x36, 0x91, 0x7c, 0xd4, 0x23, + 0xe0, 0xce, 0xc3, 0xfa, 0x07, 0x30, 0x92, 0xa5, + 0x7a, 0x9d, 0x4e, 0x7a, 0xb0, 0x46, 0x04, 0x32, + 0xd4, 0x91, 0x6b, 0x19, 0xab, 0x73, 0x00, 0xe0, + 0xad, 0x98, 0x77, 0xaf, 0xee, 0x6b, 0x7c, 0x67, + 0x0d, 0x56, 0x60, 0xcd, 0x88, 0xad, 0x82, 0x26, + 0x2d, 0x98, 0x1e, 0x96, 0xb5, 0x0f, 0x32, 0xca, + 0xa1, 0x34, 0xbc, 0x31, 0x80, 0xcd, 0x78, 0x6a, + 0x4a, 0xfa, 0x4e, 0x3b, 0x6b, 0xce, 0xbe, 0x4b, + 0x3a, 0xec, 0x95, 0x61, 0x09, 0xc9, 0x0b, 0x38, + 0x0f, 0xae, 0x9c, 0xa7, 0x7f, 0xc8, 0x42, 0xa3, + 0x3e, 0x91, 0xf7, 0x23, 0xd1, 0x36, 0xcb, 0x11, + 0xcb, 0x18, 0xc6, 0x7f, 0x5f, 0x23, 0x00, 0x7b, + 0xfc, 0xb0, 0x04, 0x9b, 0x63, 0xf8, 0x48, 0x6f, + 0x47, 0xf3, 0x2a, 0x00, 0xfa, 0x5f, 0xe1, 0x6b, + 0xeb, 0x47, 0xcf, 0x1e, 0xdb, 0xbc, 0x78, 0x1b, + 0xea, 0xe3, 0x89, 0x9c, 0x32, 0x86, 0x00, 0xcf, + 0x0b, 0x37, 0x3c, 0xb2, 0x45, 0x45, 0x3a, 0x91, + 0xd8, 0xf3, 0x63, 0xcb, 0xbe, 0x75, 0x00, 0x2e, + 0xa1, 0x6b, 0xb6, 0xfa, 0x86, 0xd9, 0x3b, 0x03, + 0x7f, 0xa6, 0xcc, 0x05, 0x9d, 0xc1, 0x96, 0x81, + 0x9c, 0xc2, 0xcb, 0x12, 0xca, 0xc6, 0xd4, 0x16, + 0xb4, 0xd6, 0xdf, 0x90, 0x39, 0x3f, 0xa6, 0xf2, + 0x6a, 0x56, 0x43, 0x8e, 0x8f, 0xc6, 0xf1, 0x06, + 0xc9, 0xb3, 0x8f, 0x29, 0x25, 0xbe, 0xdf, 0x8d, + 0x6e, 0xe3, 0x19, 0xcd, 0x68, 0xce, 0x44, 0x8a, + 0x6b, 0xdb, 0x56, 0x89, 0x13, 0x35, 0x53, 0x90, + 0x8b, 0x83, 0x36, 0x91, 0x54, 0xbb, 0x4a, 0xc2, + 0x61, 0xf2, 0x7e, 0x91, 0xfc, 0x79, 0xf3, 0x9d, + 0x97, 0xbf, 0x3e, 0x1c, 0xcc, 0x8c, 0x46, 0x62, + 0xdc, 0x83, 0x63, 0x93, 0x3e, 0x9f, 0x57, 0xd4, + 0x38, 0xc3, 0xd9, 0x52, 0x32, 0x9a, 0x16, 0x77, + 0x2d, 0x98, 0x70, 0xa9, 0xc6, 0x4d, 0xc7, 0x55, + 0xbb, 0x7d, 0xf6, 0xab, 0x6c, 0x65, 0x2e, 0xb2, + 0x18, 0xe6, 0x9d, 0x50, 0x88, 0x9e, 0x6b, 0xc2, + 0xb0, 0x97, 0xb2, 0x54, 0x2a, 0x98, 0x22, 0x5d, + 0xfc, 0x8b, 0x0c, 0x9b, 0x18, 0x91, 0x57, 0x09, + 0x33, 0x66, 0x05, 0x4c, 0x8a, 0x4b, 0x25, 0x72, + 0xb1, 0xb3, 0x4f, 0x7a, 0xfb, 0x56, 0xe8, 0xb4, + 0x37, 0x18, 0xb8, 0xe4, 0x78, 0x68, 0x4a, 0x62, + 0xab, 0x82, 0xab, 0xbd, 0x8a, 0x08, 0x5e, 0x81, + 0x6a, 0x6e, 0x98, 0xb4, 0xd3, 0xb4, 0x9f, 0x45, + 0x01, 0xca, 0xdf, 0x53, 0x76, 0xc7, 0xd9, 0xac, + 0xa9, 0x32, 0xaa, 0x00, 0xbc, 0xa4, 0x51, 0x33, + 0x1f, 0x30, 0x30, 0x05, 0x94, 0x22, 0x45, 0xa5, + 0x85, 0xf2, 0x18, 0xde, 0x2e, 0x59, 0x65, 0xe9, + 0x75, 0x6a, 0x1d, 0x7d, 0x2b, 0x40, 0x70, 0x99, + 0xa3, 0x57, 0x26, 0xa6, 0xe2, 0x94, 0x37, 0xf8, + 0x8a, 0x9a, 0x04, 0xc1, 0x3b, 0xaa, 0xb2, 0x01, + 0x54, 0xe8, 0x86, 0x92, 0x5c, 0x13, 0xe1, 0xb0, + 0xe7, 0x54, 0xd2, 0x10, 0x80, 0x95, 0x64, 0x8d, + 0x9e, 0xb3, 0x71, 0xf8, 0xc9, 0x35, 0x74, 0x0f, + 0x9b, 0x45, 0x11, 0x31, 0x97, 0xbc, 0xd0, 0xaa, + 0x84, 0x42, 0x9c, 0x51, 0xe7, 0x98, 0x48, 0xd6, + 0xc4, 0x55, 0xa4, 0x10, 0x48, 0xb2, 0xaf, 0x5d, + 0x8f, 0x93, 0x09, 0x26, 0xd5, 0x6c, 0xa3, 0x6a, + 0x7e, 0x3b, 0x60, 0xae, 0xc0, 0xc7, 0xaf, 0xea, + 0x2f, 0xf7, 0xcd, 0x81, 0xad, 0x66, 0x7b, 0x04, + 0xcc, 0x09, 0xda, 0xc7, 0x1d, 0xb7, 0x44, 0x7f, + 0xbe, 0xc1, 0x51, 0x28, 0x37, 0xcd, 0xa2, 0x5d, + 0xa3, 0xc7, 0x7e, 0x10, 0x63, 0x56, 0x70, 0x47, + 0xc1, 0x99, 0x2c, 0x5e, 0x98, 0xb0, 0x7a, 0xf2, + 0xa4, 0x81, 0x02, 0xd7, 0x75, 0x4f, 0x79, 0xdd, + 0x4a, 0x75, 0x11, 0xc3, 0xa9, 0xf1, 0xf5, 0x6e, + 0x7d, 0xd6, 0xe1, 0x35, 0x39, 0xe1, 0x77, 0x72, + 0xd4, 0x15, 0xaf, 0xf1, 0xc5, 0x01, 0x8c, 0x05, + 0xea, 0xf1, 0x7c, 0x3d, 0x75, 0x79, 0xab, 0xe2, + 0xec, 0x8d, 0x53, 0xff, 0x1e, 0xd4, 0x4f, 0xe8, + 0x4a, 0x3a, 0x9d, 0x99, 0x58, 0x7d, 0x4f, 0x80, + 0xeb, 0x44, 0x30, 0x78, 0x19, 0x3e, 0xa9, 0xbe, + 0xca, 0x29, 0xf9, 0xb4, 0xdf, 0x11, 0x9a, 0xaa, + 0x86, 0xa1, 0xbd, 0x92, 0xf7, 0xbc, 0x3b, 0xb2, + 0xc2, 0x16, 0x1d, 0x60, 0x61, 0x6c, 0x25, 0x02, + 0xba, 0x40, 0xc0, 0xd6, 0x28, 0xea, 0x28, 0xae, + 0x51, 0xcc, 0x21, 0xa8, 0xac, 0xb6, 0x0d, 0x11, + 0x6b, 0x9b, 0xca, 0x8f, 0xb4, 0x3a, 0xc1, 0x0e, + 0x8e, 0x63, 0x63, 0x55, 0x3b, 0x50, 0x73, 0xec, + 0xa5, 0x98, 0x10, 0x18, 0x68, 0xbb, 0xfe, 0xe1, + 0x9e, 0xae, 0xd0, 0xfb, 0x63, 0xf0, 0x92, 0xb5, + 0xcd, 0xad, 0xf1, 0x99, 0x0c, 0xb4, 0x56, 0x3a, + 0x24, 0xe8, 0x33, 0xf6, 0x2f, 0xd5, 0x5f, 0x00, + 0x66, 0xfe, 0x1f, 0xa9, 0x12, 0x28, 0xf7, 0x9b, + 0x84, 0x44, 0x8a, 0x8b, 0x65, 0xba, 0x86, 0x94, + 0xa7, 0xf5, 0x64, 0x93, 0xf3, 0xd4, 0x9e, 0xa3, + 0xe5, 0xf1, 0x52, 0x79, 0x59, 0xe1, 0x3c, 0x68, + 0x8a, 0x0a, 0xf6, 0xa3, 0x06, 0xe4, 0x88, 0xe4, + 0x78, 0x51, 0xa5, 0xf4, 0xe1, 0xbb, 0x76, 0xaf, + 0x49, 0x31, 0x75, 0x40, 0x88, 0x01, 0x55, 0x15, + 0x28, 0x90, 0x5d, 0x43, 0xb3, 0xef, 0x87, 0xfc, + 0xbc, 0x12, 0x44, 0x1f, 0xc5, 0x8f, 0x28, 0x89, + 0xc4, 0xaa, 0x73, 0x29, 0x0a, 0x12, 0x7b, 0x54, + 0x41, 0xeb, 0x96, 0xdc, 0x3a, 0x3e, 0x6e, 0x23, + 0x4c, 0xc5, 0x36, 0x7a, 0x8f, 0x29, 0x92, 0xdd, + 0x37, 0xa5, 0xfd, 0x65, 0x90, 0xde, 0x6a, 0x3f, + 0xd4, 0x7b, 0xd6, 0xec, 0xb5, 0x0d, 0x16, 0xa0, + 0x3a, 0x1b, 0x28, 0xc1, 0x84, 0xfd, 0x20, 0x8b, + 0xfd, 0xd4, 0xb9, 0x53, 0xf9, 0x07, 0x0d, 0x21, + 0x34, 0x7f, 0xb9, 0x40, 0x64, 0x74, 0xc6, 0x04, + 0xe9, 0xbe, 0x2d, 0xd3, 0x5b, 0x43, 0x8b, 0xbb, + 0xb7, 0x64, 0x75, 0xdc, 0x1a, 0x78, 0xd8, 0x35, + 0x38, 0x12, 0xef, 0x59, 0x72, 0x13, 0x3d, 0x57, + 0x76, 0x50, 0x3a, 0x46, 0x86, 0xc7, 0x25, 0x76, + 0xb1, 0x81, 0x0a, 0x8c, 0x21, 0x03, 0xc5, 0x5f, + 0x26, 0x9f, 0x69, 0x06, 0x7c, 0x62, 0x8f, 0x96, + 0xa3, 0x5e, 0x6d, 0x57, 0xcd, 0x8e, 0x0c, 0xc3, + 0xdc, 0x57, 0xeb, 0x29, 0x16, 0x5b, 0x0c, 0xae, + 0x74, 0x9c, 0x3e, 0xec, 0xeb, 0xf2, 0xbb, 0x4b, + 0x58, 0x24, 0x33, 0x05, 0x58, 0xe5, 0x0f, 0x5e, + 0x30, 0x8f, 0xfa, 0xb0, 0xaf, 0x2e, 0x8a, 0xb5, + 0x83, 0xab, 0xab, 0x62, 0x40, 0x9d, 0x56, 0x7a, + 0x4e, 0x54, 0x69, 0x9a, 0x90, 0x63, 0x97, 0xf9, + 0x19, 0x12, 0xb9, 0xf7, 0x17, 0x2e, 0x82, 0x60, + 0x2f, 0x91, 0xb5, 0x32, 0xa1, 0x1d, 0x80, 0x7c, + 0x10, 0x7c, 0xbb, 0xd5, 0x5e, 0x15, 0x84, 0x9d, + 0xda, 0x51, 0xf7, 0xf3, 0xf5, 0x67, 0xfd, 0x3d, + 0x9f, 0x32, 0x65, 0x9a, 0x56, 0x7a, 0xb1, 0x68, + 0xac, 0x98, 0x4b, 0xe3, 0x2b, 0x9d, 0xe0, 0x97, + 0xc3, 0x9c, 0x56, 0x1c, 0xaf, 0x77, 0xfb, 0x44, + 0xab, 0xbe, 0x80, 0xcb, 0xf6, 0x0e, 0x2b, 0xbc, + 0x52, 0x2b, 0x0b, 0x08, 0x69, 0x37, 0x81, 0x90, + 0x13, 0xf8, 0xaa, 0xa2, 0x82, 0x60, 0x3a, 0x9f, + 0x93, 0x4c, 0xb2, 0xf4, 0xe8, 0xe8, 0x27, 0xc7, + 0xeb, 0x04, 0xae, 0x08, 0x29, 0x0a, 0x33, 0xf0, + 0x09, 0x25, 0x66, 0x7a, 0x00, 0xef, 0xd1, 0x72, + 0x8d, 0xe8, 0x42, 0x25, 0xd9, 0x56, 0x49, 0x27, + 0xb8, 0x25, 0xc8, 0x48, 0x69, 0x33, 0xf6, 0x62, + 0x74, 0xa8, 0x3a, 0x67, 0xcf, 0x14, 0x00, 0x5b, + 0x42, 0xdb, 0xc7, 0x97, 0xd1, 0x99, 0xf5, 0x4c, + 0x2e, 0xde, 0x20, 0x8c, 0x45, 0x31, 0x37, 0x64, + 0xe9, 0xf8, 0x94, 0x07, 0xd1, 0x6e, 0x7b, 0x90, + 0xb3, 0x0a, 0xb6, 0xb1, 0xb6, 0x3b, 0xfa, 0x0c, + 0x6b, 0x15, 0x11, 0xf3, 0xe7, 0xdf, 0x3c, 0xe4, + 0x73, 0xe8, 0xc9, 0xa2, 0x9b, 0xf4, 0x9a, 0x42, + 0xb1, 0x7f, 0xf0, 0xac, 0x68, 0x4f, 0x63, 0x55, + 0xdf, 0x49, 0x68, 0xbe, 0x1d, 0xee, 0x69, 0x41, + 0xdd, 0x7b, 0x5d, 0x0d, 0xc1, 0x20, 0x0d, 0x01, + 0xa4, 0x79, 0x6f, 0x0d, 0xd0, 0x5d, 0x3c, 0x14, + 0x25, 0xa4, 0x2c, 0x28, 0x6d, 0x23, 0x8c, 0xba, + 0x69, 0x15, 0x1a, 0x25, 0xf2, 0xf2, 0xd6, 0xf2, + 0x08, 0x51, 0x4a, 0xbd, 0x2f, 0xea, 0xde, 0xb5, + 0x7d, 0xe6, 0x8e, 0x3b, 0xfe, 0x0b, 0x63, 0xbf, + 0xca, 0xbb, 0x56, 0x67, 0x1c, 0x53, 0xcf, 0xea, + 0xd3, 0xb5, 0x3a, 0x56, 0x4c, 0x1e, 0xea, 0x68, + 0x68, 0x9b, 0x27, 0xb8, 0xa2, 0xf1, 0x95, 0x75, + 0x8e, 0xe0, 0xb5, 0xef, 0x0e, 0x83, 0x6c, 0xef, + 0xb9, 0xd1, 0xbe, 0xfd, 0xfa, 0xb4, 0x58, 0x20, + 0x1c, 0xae, 0x86, 0xa0, 0xd7, 0x2e, 0x06, 0xde, + 0xec, 0xf6, 0x7e, 0x56, 0xe3, 0x5a, 0xa1, 0xef, + 0xe5, 0x3d, 0x97, 0x88, 0xca, 0xe5, 0x98, 0x19, + 0xba, 0x64, 0xbd, 0xa6, 0x52, 0xd0, 0x07, 0xac, + 0x4a, 0x35, 0x2c, 0xbb, 0x4e, 0xf4, 0x34, 0x45, + 0xc1, 0x3a, 0xf4, 0xf8, 0x28, 0x33, 0xb2, 0x20, + 0x77, 0xea, 0x07, 0xdf, 0x0e, 0xdf, 0x08, 0x28, + 0x9d, 0xc4, 0xfd, 0x53, 0xb8, 0x1d, 0x10, 0xc7, + 0x63, 0xfb, 0x4d, 0x3a, 0x30, 0xe2, 0xb8, 0xfa, + 0xca, 0x31, 0x02, 0x3e, 0x87, 0x79, 0x21, 0x7e, + 0xc3, 0x08, 0x1b, 0x97, 0x98, 0x50, 0xa2, 0x47, + 0x3e, 0x22, 0xf2, 0xf7, 0x69, 0xcb, 0x9f, 0xb0, + 0x36, 0x64, 0xad, 0x2a, 0x9c, 0x50, 0x89, 0xfd, + 0x5f, 0x50, 0x11, 0xd5, 0x15, 0x36, 0x4e, 0x0a, + 0xc3, 0x8c, 0xa6, 0x8f, 0xab, 0x84, 0xb6, 0x6c, + 0xd3, 0x42, 0xc1, 0xec, 0x3c, 0x49, 0xeb, 0xc1, + 0x88, 0xd8, 0xd2, 0x18, 0x3a, 0xe3, 0x1b, 0x09, + 0xfd, 0x0b, 0xb4, 0xff, 0x66, 0x07, 0x6c, 0x55, + 0x58, 0xa7, 0x8d, 0x7a, 0x6d, 0xd6, 0xb1, 0xc5, + 0xde, 0x91, 0x86, 0x10, 0x5c, 0x54, 0x23, 0xb5, + 0xa2, 0xed, 0x90, 0x5d, 0x6a, 0xbf, 0x07, 0x82, + 0xae, 0xf7, 0xa5, 0x02, 0x1b, 0x35, 0x7a, 0xbf, + 0x63, 0x4b, 0x82, 0x32, 0x10, 0x99, 0x4b, 0x8b, + 0xbc, 0x9f, 0x8a, 0x0f, 0x8f, 0x91, 0x45, 0x6e, + 0x09, 0x5b, 0x4a, 0xa2, 0x2c, 0xd0, 0xf4, 0xb1, + 0x4e, 0x30, 0x8c, 0x9a, 0x51, 0x9a, 0x33, 0x10, + 0x63, 0x63, 0x59, 0x1c, 0xb4, 0x82, 0xe5, 0xac, + 0xab, 0xda, 0x74, 0x1e, 0xf6, 0xca, 0xd7, 0xb8, + 0x57, 0xf0, 0x49, 0x71, 0xf1, 0xa6, 0x76, 0xa1, + 0xf8, 0xdc, 0x4b, 0xd0, 0xdf, 0x6f, 0x72, 0x97, + 0x80, 0x9d, 0x4c, 0x9e, 0xb6, 0x26, 0x99, 0x60, + 0x50, 0x69, 0xbf, 0xc3, 0xef, 0xc2, 0x78, 0xaf, + 0x83, 0x01, 0xf3, 0x55, 0x1d, 0x73, 0xa6, 0x0b, + 0x2e, 0x43, 0x34, 0x7b, 0xc2, 0x68, 0xc3, 0xc0, + 0x27, 0x70, 0xe1, 0xd2, 0x57, 0xc0, 0x7b, 0xec, + 0x48, 0xf7, 0x73, 0x65, 0x45, 0x10, 0x03, 0x8b, + 0x4b, 0x08, 0x44, 0x6e, 0xe2, 0x3e, 0x6e, 0x45, + 0xf8, 0xe5, 0x9b, 0x77, 0x44, 0x01, 0x30, 0x23, + 0x5c, 0x9d, 0xd8, 0x86, 0xf2, 0x6e, 0x2b, 0x17, + 0x1b, 0x7a, 0x61, 0x9c, 0xb2, 0x07, 0xf7, 0x21, + 0x4e, 0xa1, 0x26, 0x63, 0x39, 0x9d, 0x05, 0x84, + 0x0d, 0x8a, 0xcb, 0x45, 0x3e, 0xe8, 0x6c, 0x67, + 0xd7, 0x74, 0x52, 0x09, 0xc3, 0x1a, 0x75, 0x8d, + 0xe4, 0xa6, 0xe3 + }; + + return linuxkm_test_xmss_driver(WOLFKM_XMSSMT_DRIVER, + xmssmt_kat_pub, + (word32)sizeof(xmssmt_kat_pub), + xmssmt_kat_sig, + (word32)sizeof(xmssmt_kat_sig), + xmssmt_kat_msg, + (word32)sizeof(xmssmt_kat_msg)); +} +#endif /* LINUXKM_LKCAPI_REGISTER_XMSS_MT */ + +#endif /* LINUXKM_LKCAPI_REGISTER_XMSS */ + +#endif /* !WC_SKIP_INCLUDED_C_FILES */ diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 888343b9da..dc1da6d98f 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -63,16 +63,61 @@ enum linux_errcodes { my_EINVAL = EINVAL, my_ENOMEM = ENOMEM, - my_EBADMSG = EBADMSG + my_EBADMSG = EBADMSG, + my_ENOKEY = ENOKEY, + my_EFAULT = EFAULT, + my_EAFNOSUPPORT = EAFNOSUPPORT, + my_EOVERFLOW = EOVERFLOW, + my_EOPNOTSUPP = EOPNOTSUPP, + my_EDEADLK = EDEADLK, + my_EAGAIN = EAGAIN, + my_EBUSY = EBUSY, + my_ECANCELED = ECANCELED, + my_EINTR = EINTR, + my_ELIBBAD = ELIBBAD, + my_ENODATA = ENODATA, + my_ENODEV = ENODEV, + my_EPERM = EPERM, + my_EFBIG = EFBIG }; #undef EINVAL #undef ENOMEM #undef EBADMSG + #undef ENOKEY + #undef EFAULT + #undef EAFNOSUPPORT + #undef EOVERFLOW + #undef EOPNOTSUPP + #undef EDEADLK + #undef EAGAIN + #undef EBUSY + #undef ECANCELED + #undef EINTR + #undef ELIBBAD + #undef ENODATA + #undef ENODEV + #undef EPERM + #undef EFBIG #define EINVAL WC_ERR_TRACE(my_EINVAL) #define ENOMEM WC_ERR_TRACE(my_ENOMEM) #define EBADMSG WC_ERR_TRACE(my_EBADMSG) + #define ENOKEY WC_ERR_TRACE(my_ENOKEY) + #define EFAULT WC_ERR_TRACE(my_EFAULT) + #define EAFNOSUPPORT WC_ERR_TRACE(my_EAFNOSUPPORT) + #define EOVERFLOW WC_ERR_TRACE(my_EOVERFLOW) + #define EOPNOTSUPP WC_ERR_TRACE(my_EOPNOTSUPP) + #define EDEADLK WC_ERR_TRACE(my_EDEADLK) + #define EAGAIN WC_ERR_TRACE(my_EAGAIN) + #define EBUSY WC_ERR_TRACE(my_EBUSY) + #define ECANCELED WC_ERR_TRACE(my_ECANCELED) + #define EINTR WC_ERR_TRACE(my_EINTR) + #define ELIBBAD WC_ERR_TRACE(my_ELIBBAD) + #define ENODATA WC_ERR_TRACE(my_ENODATA) + #define ENODEV WC_ERR_TRACE(my_ENODEV) + #define EPERM WC_ERR_TRACE(my_EPERM) + #define EFBIG WC_ERR_TRACE(my_EFBIG) #endif static int libwolfssl_cleanup(void) { @@ -845,6 +890,14 @@ static int wolfssl_init(void) reloc_counts.other = 0; #endif + /* In asm builds, we run the FIPS self-test twice, once via fipsEntry() checking + * afterwards that no C fallbacks occurred, and a second time via + * wolfCrypt_IntegrityTest_fips() with asm disabled. + */ + +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(WC_C_DYNAMIC_FALLBACK) + wc_svr_disallowed_count_reset(); +#endif if (WC_SIG_IGNORE_BEGIN() >= 0) { fipsEntry(); (void)WC_SIG_IGNORE_END(); @@ -874,6 +927,44 @@ static int wolfssl_init(void) } return -ECANCELED; } + +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(WC_C_DYNAMIC_FALLBACK) + { + long long unsigned int svr_disallowed_count = wc_svr_disallowed_count_current(); + if (svr_disallowed_count > 0) { + pr_err("ERROR: wc_svr_disallowed_count_current() returned %llu after fipsEntry().\n", svr_disallowed_count); + return -ECANCELED; + } + + ret = DISABLE_VECTOR_REGISTERS(); + if (ret != 0) { + pr_err("ERROR: DISABLE_VECTOR_REGISTERS() for wolfCrypt_IntegrityTest_fips() returned %d.\n", ret); + return -ECANCELED; + } + + ret = wolfCrypt_IntegrityTest_fips(); + + REENABLE_VECTOR_REGISTERS(); + + svr_disallowed_count = wc_svr_disallowed_count_current(); + if (svr_disallowed_count == 0) { + pr_err("ERROR: wc_svr_disallowed_count_current() returned %llu after DISABLE_VECTOR_REGISTERS().\n", svr_disallowed_count); + return -ECANCELED; + } + + if (ret != 0) { + pr_err("ERROR: wolfCrypt_IntegrityTest_fips() with DISABLE_VECTOR_REGISTERS() returned %d.\n", ret); + return -ECANCELED; + } + + ret = wolfCrypt_GetStatus_fips(); + if (ret != 0) { + pr_err("ERROR: wolfCrypt_GetStatus_fips() failed with code %d: %s\n", ret, wc_GetErrorString(ret)); + return -ECANCELED; + } + } +#endif /* WOLFSSL_USE_SAVE_VECTOR_REGISTERS && WC_C_DYNAMIC_FALLBACK */ + #endif /* HAVE_FIPS */ #ifdef WC_RNG_SEED_CB @@ -911,6 +1002,10 @@ static int wolfssl_init(void) wc_linuxkm_stack_hwm_prepare(0xee); #endif +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(WC_C_DYNAMIC_FALLBACK) + wc_svr_disallowed_count_reset(); +#endif + ret = wc_RunAllCast_fips(); #ifdef WC_LINUXKM_HAVE_STACK_DEBUG @@ -926,6 +1021,58 @@ static int wolfssl_init(void) return -ECANCELED; } +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(WC_C_DYNAMIC_FALLBACK) + { + long long unsigned int svr_disallowed_count = wc_svr_disallowed_count_current(); + if (svr_disallowed_count > 0) { + pr_err("ERROR: wc_svr_disallowed_count_current() returned %llu after wc_RunAllCast_fips().\n", svr_disallowed_count); + return -ECANCELED; + } + + #ifdef WC_LINUXKM_HAVE_STACK_DEBUG + { + unsigned long stack_usage; + wc_linuxkm_stack_hwm_prepare(0xee); + #endif + + ret = DISABLE_VECTOR_REGISTERS(); + if (ret != 0) { + pr_err("ERROR: DISABLE_VECTOR_REGISTERS() for wc_RunAllCast_fips() returned %d.\n", ret); + return -ECANCELED; + } + + ret = wc_RunAllCast_fips(); + + REENABLE_VECTOR_REGISTERS(); + + #ifdef WC_LINUXKM_HAVE_STACK_DEBUG + stack_usage = wc_linuxkm_stack_hwm_measure_rel(0xee); + pr_info("STACK INFO: rel usage by wc_RunAllCast_fips() with DISABLE_VECTOR_REGISTERS(): %lu\n", stack_usage); + /* shush up false stack HWM reading by kernel: */ + wc_linuxkm_stack_hwm_prepare(0); + } + #endif + + svr_disallowed_count = wc_svr_disallowed_count_current(); + if (svr_disallowed_count == 0) { + pr_err("ERROR: wc_svr_disallowed_count_current() returned %llu after DISABLE_VECTOR_REGISTERS().\n", svr_disallowed_count); + return -ECANCELED; + } + + if (ret != 0) { + pr_err("ERROR: wc_RunAllCast_fips() with DISABLE_VECTOR_REGISTERS() returned %d.\n", ret); + return -ECANCELED; + } + + ret = wolfCrypt_GetStatus_fips(); + if (ret != 0) { + pr_err("ERROR: wolfCrypt_GetStatus_fips() failed with code %d: %s\n", ret, wc_GetErrorString(ret)); + return -ECANCELED; + } + } + +#endif /* WOLFSSL_USE_SAVE_VECTOR_REGISTERS && WC_C_DYNAMIC_FALLBACK */ + pr_info("FIPS 140-3 wolfCrypt-fips v%d.%d.%d%s%s startup " "self-test succeeded.\n", #ifdef HAVE_FIPS_VERSION_MAJOR @@ -951,6 +1098,7 @@ static int wolfssl_init(void) "" #endif ); + #endif /* HAVE_FIPS && FIPS_VERSION3_GT(5,2,0) */ #ifdef FIPS_OPTEST @@ -1522,9 +1670,9 @@ static int set_up_wolfssl_linuxkm_pie_redirect_table(void) { wolfssl_linuxkm_pie_redirect_table.get_current = my_get_current_thread; #if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(CONFIG_X86) - wolfssl_linuxkm_pie_redirect_table.allocate_wolfcrypt_linuxkm_fpu_states = allocate_wolfcrypt_linuxkm_fpu_states; + wolfssl_linuxkm_pie_redirect_table.wc_linuxkm_allocate_svr_states = wc_linuxkm_allocate_svr_states; wolfssl_linuxkm_pie_redirect_table.wc_can_save_vector_registers_x86 = wc_can_save_vector_registers_x86; - wolfssl_linuxkm_pie_redirect_table.free_wolfcrypt_linuxkm_fpu_states = free_wolfcrypt_linuxkm_fpu_states; + wolfssl_linuxkm_pie_redirect_table.wc_linuxkm_free_svr_states = wc_linuxkm_free_svr_states; wolfssl_linuxkm_pie_redirect_table.wc_restore_vector_registers_x86 = wc_restore_vector_registers_x86; wolfssl_linuxkm_pie_redirect_table.wc_save_vector_registers_x86 = wc_save_vector_registers_x86; #elif defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) @@ -2037,6 +2185,29 @@ static ssize_t FIPS_rerun_self_test_handler(struct kobject *kobj, struct kobj_at return -EINVAL; } +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(WC_C_DYNAMIC_FALLBACK) + /* Note that wc_svr_disallowed_count*() can't be checked in + * FIPS_rerun_self_test_handler() -- we're already multiuser at this point + * and other threads can and will increment wc_svr_disallowed_count outside + * our control. + */ + + ret = DISABLE_VECTOR_REGISTERS(); + if (ret != 0) { + pr_err("ERROR: DISABLE_VECTOR_REGISTERS() for wc_RunAllCast_fips() returned %d.\n", ret); + return -EINVAL; + } + + ret = wc_RunAllCast_fips(); + + REENABLE_VECTOR_REGISTERS(); + + if (ret != 0) { + pr_err("ERROR: wc_RunAllCast_fips() with DISABLE_VECTOR_REGISTERS() returned %d.\n", ret); + return -EINVAL; + } +#endif /* WOLFSSL_USE_SAVE_VECTOR_REGISTERS && WC_C_DYNAMIC_FALLBACK */ + pr_info("wolfCrypt FIPS re-self-test succeeded: all algorithms verified and available.\n"); return count; diff --git a/linuxkm/x86_vector_register_glue.c b/linuxkm/x86_vector_register_glue.c index 2313cd80d4..5c9e0746a0 100644 --- a/linuxkm/x86_vector_register_glue.c +++ b/linuxkm/x86_vector_register_glue.c @@ -35,77 +35,107 @@ #define VRG_PR_WARN_X pr_warn_once #endif -static unsigned int wc_linuxkm_fpu_states_n_tracked = 0; +static unsigned int wc_linuxkm_svr_states_n_tracked = 0; -struct wc_thread_fpu_count_ent { - volatile pid_t pid; - unsigned int fpu_state; +struct wc_thread_svr_count_ent { + volatile pid_t pid; /* sync pivot, __atomic access only. */ + unsigned int fpu_state; /* plain, owner-private under the nonpreemptibility invariant. */ + volatile unsigned long reserved_at; /* volatile, read live by foreign diagnostics. */ }; -struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_states = NULL; +struct wc_thread_svr_count_ent *wc_linuxkm_svr_states = NULL; -#define WC_FPU_COUNT_MASK 0x3fffffffU -#define WC_FPU_INHIBITED_FLAG 0x40000000U +#define WC_SVR_COUNT_MASK 0x1fffffffU +#define WC_SVR_INHIBITED_FLAG 0x40000000U +#define WC_SVR_BH_HELD_FLAG 0x20000000U -WARN_UNUSED_RESULT int allocate_wolfcrypt_linuxkm_fpu_states(void) +#define WC_SVR_FREE_SLOT_PID 0 +#define WC_SVR_IDLE_PID ((pid_t)(-1)) +#define WC_SVR_PID_SLOT_ID() (__extension__ (task_pid_nr(current) ? : WC_SVR_IDLE_PID)) + +/* On targets with 64 bit longs, jiffies starts at INITIAL_JIFFIES and climbs + * monotonically -- a zero ->reserved_at means that slot has not been reserved + * since wc_linuxkm_allocate_svr_states(). On 32 bit long targets it + * wraps periodically, and WC_SVR_SLOT_AGE_MS() is best effort (used only in log + * messages). + */ +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + #define WC_SVR_SLOT_AGE_MS(slot) ((slot)->reserved_at ? \ + ((long)jiffies - (long)(slot)->reserved_at) * (MSEC_PER_SEC / HZ) : \ + -1L) +#else + #define WC_SVR_SLOT_AGE_MS(slot) ((slot)->reserved_at ? \ + (long)jiffies_to_msecs(jiffies - (slot)->reserved_at) : \ + -1L) +#endif + +WARN_UNUSED_RESULT int wc_linuxkm_allocate_svr_states(void) { - if (wc_linuxkm_fpu_states != NULL) { + if (wc_linuxkm_svr_states != NULL) { #ifdef HAVE_FIPS - /* see note below in wc_linuxkm_fpu_state_assoc_unlikely(). */ + /* see note below in wc_linuxkm_svr_state_assoc_unlikely(). */ return 0; #else static int warned_for_repeat_alloc = 0; if (! warned_for_repeat_alloc) { pr_err("BUG: attempt at repeat allocation" - " in allocate_wolfcrypt_linuxkm_fpu_states.\n"); + " in wc_linuxkm_allocate_svr_states.\n"); warned_for_repeat_alloc = 1; } return BAD_STATE_E; #endif } - wc_linuxkm_fpu_states_n_tracked = nr_cpu_ids; + wc_linuxkm_svr_states_n_tracked = nr_cpu_ids; - wc_linuxkm_fpu_states = - (struct wc_thread_fpu_count_ent *)malloc( - wc_linuxkm_fpu_states_n_tracked * sizeof(wc_linuxkm_fpu_states[0])); + wc_linuxkm_svr_states = + (struct wc_thread_svr_count_ent *)malloc( + wc_linuxkm_svr_states_n_tracked * sizeof(wc_linuxkm_svr_states[0])); - if (! wc_linuxkm_fpu_states) { + if (! wc_linuxkm_svr_states) { pr_err("ERROR: allocation of %lu bytes for " - "wc_linuxkm_fpu_states failed.\n", - nr_cpu_ids * sizeof(wc_linuxkm_fpu_states[0])); + "wc_linuxkm_svr_states failed.\n", + nr_cpu_ids * sizeof(wc_linuxkm_svr_states[0])); return MEMORY_E; } - XMEMSET(wc_linuxkm_fpu_states, 0, wc_linuxkm_fpu_states_n_tracked - * sizeof(wc_linuxkm_fpu_states[0])); + XMEMSET(wc_linuxkm_svr_states, 0, wc_linuxkm_svr_states_n_tracked + * sizeof(wc_linuxkm_svr_states[0])); return 0; } -void free_wolfcrypt_linuxkm_fpu_states(void) { - struct wc_thread_fpu_count_ent *i, *i_endptr; +void wc_linuxkm_free_svr_states(void) { + struct wc_thread_svr_count_ent *i, *i_endptr; pid_t i_pid; + int seen_errors = 0; - if (wc_linuxkm_fpu_states == NULL) + if (wc_linuxkm_svr_states == NULL) return; - for (i = wc_linuxkm_fpu_states, - i_endptr = &wc_linuxkm_fpu_states[wc_linuxkm_fpu_states_n_tracked]; + for (i = wc_linuxkm_svr_states, + i_endptr = &wc_linuxkm_svr_states[wc_linuxkm_svr_states_n_tracked]; i < i_endptr; ++i) { i_pid = __atomic_load_n(&i->pid, __ATOMIC_CONSUME); - if (i_pid == 0) + if (i_pid == WC_SVR_FREE_SLOT_PID) continue; if (i->fpu_state != 0) { - pr_err("ERROR: free_wolfcrypt_linuxkm_fpu_states called" - " with nonzero state 0x%x for PID %d.\n", i->fpu_state, i_pid); - i->fpu_state = 0; + pr_err("ERROR: wc_linuxkm_free_svr_states called" + " with nonzero state 0x%x for PID %d, age %ld ms.\n", i->fpu_state, i_pid, + WC_SVR_SLOT_AGE_MS(i)); + ++seen_errors; } } - free(wc_linuxkm_fpu_states); - wc_linuxkm_fpu_states = NULL; + if (seen_errors > 0) { + pr_crit("ERROR: wc_linuxkm_free_svr_states encountered" + " %d errors -- can't free current wc_linuxkm_svr_states.\n", seen_errors); + return; + } + + free(wc_linuxkm_svr_states); + wc_linuxkm_svr_states = NULL; } /* lock-free O(1)-lookup CPU-local storage facility for tracking recursive fpu @@ -114,14 +144,14 @@ void free_wolfcrypt_linuxkm_fpu_states(void) { * caller must have already locked itself on its CPU before entering this, or * entering the streamlined inline version of it below. */ -static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc_unlikely(int create_p) { +static struct wc_thread_svr_count_ent *wc_linuxkm_svr_state_assoc_unlikely(int create_p) { int my_cpu = raw_smp_processor_id(); - pid_t my_pid = task_pid_nr(current), slot_pid; - struct wc_thread_fpu_count_ent *slot; + pid_t my_pid = WC_SVR_PID_SLOT_ID(), slot_pid; + struct wc_thread_svr_count_ent *slot; { static int _warned_on_null = 0; - if (wc_linuxkm_fpu_states == NULL) + if (wc_linuxkm_svr_states == NULL) { #ifdef HAVE_FIPS /* FIPS needs to use SHA256 for the core verify HMAC, before @@ -129,13 +159,13 @@ static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc_unlikely(int c * dependency loop on intelasm builds, we allocate here. * this is not thread-safe and doesn't need to be. */ - int ret = allocate_wolfcrypt_linuxkm_fpu_states(); + int ret = wc_linuxkm_allocate_svr_states(); if (ret != 0) #endif { if (_warned_on_null == 0) { - pr_err("BUG: wc_linuxkm_fpu_state_assoc called by PID %d" - " before allocate_wolfcrypt_linuxkm_fpu_states.\n", my_pid); + pr_err("BUG: wc_linuxkm_svr_state_assoc called by PID %d" + " before wc_linuxkm_allocate_svr_states.\n", my_pid); #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG dump_stack(); #endif @@ -146,15 +176,15 @@ static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc_unlikely(int c } } - slot = &wc_linuxkm_fpu_states[my_cpu]; + slot = &wc_linuxkm_svr_states[my_cpu]; slot_pid = __atomic_load_n(&slot->pid, __ATOMIC_CONSUME); if (slot_pid == my_pid) { if (create_p) { static int _warned_on_redundant_create_p = 0; if (_warned_on_redundant_create_p < 10) { - pr_err("BUG: wc_linuxkm_fpu_state_assoc called with create_p=1 by" + pr_err("BUG: wc_linuxkm_svr_state_assoc called with create_p=1 by" " PID %d on CPU %d with CPU slot already reserved by" - " said PID.\n", my_pid, my_cpu); + " said PID (age %ld ms).\n", my_pid, my_cpu, WC_SVR_SLOT_AGE_MS(slot)); #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG dump_stack(); #endif @@ -164,21 +194,49 @@ static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc_unlikely(int c return slot; } if (create_p) { - if (slot_pid == 0) { + if (slot_pid == WC_SVR_FREE_SLOT_PID) { __atomic_store_n(&slot->pid, my_pid, __ATOMIC_RELEASE); + slot->reserved_at = jiffies; return slot; + } else if (slot_pid == WC_SVR_IDLE_PID) { + /* A WC_SVR_IDLE_PID reservation on a live system is always a live + * reservation or a bug -- these reservations originate with softirq + * handlers on the idle threads, and crashes in those handlers + * summarily panic the kernel. + * + * If an idle-context cycle nonetheless goes unbalanced, there is + * no way to recover. The exposure is confined to this library -- + * consumers never invoke save/restore directly -- and balance is + * an enforced invariant (single-exit discipline, fuzzer + * coverage); this branch is that invariant's audit, not its + * substitute. + * + * Ultimately, recovery is impossible because WC_SVR_IDLE_PID names a + * context class, not a task, so nothing analogous to find_get_pid() + * below could decide whether this record is a stale leftover or a + * live idle-context bracket. Recovery couldn't close the hazard + * anyway -- the next idle-context save on this CPU fast-path would + * match a stale record as its own live nesting and proceed without + * kernel_fpu_begin(). A record in this state is proof of an + * unbalanced idle-context save/restore; report it and fail. + * Save/restore balance discipline, not runtime recovery, is what + * keeps this branch unreachable. + */ + pr_err_ratelimited("BUG: wc_linuxkm_svr_state_assoc_unlikely found WC_SVR_IDLE_PID in the slot for calling CPU %d PID %d (age %ld ms) requesting outermost vector register save -- CPU is acceleration-degraded.\n", my_cpu, my_pid, WC_SVR_SLOT_AGE_MS(slot)); + return NULL; } else { struct pid *slot_pid_struct; - /* if the slot is already occupied, that can be benign-ish due to a + /* if the slot is already occupied, that can be benign-ish due to an * unwanted migration, or due to a process crashing in kernel mode. * it will require fixup either here, or by the thread that owns the * slot, which will happen when it releases its lock. */ slot_pid_struct = find_get_pid(slot_pid); if (slot_pid_struct == NULL) { - if (__atomic_compare_exchange_n(&slot->pid, &slot_pid, my_pid, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE)) { - pr_warn("WARNING: wc_linuxkm_fpu_state_assoc_unlikely fixed up orphaned slot on CPU %d owned by dead PID %d.\n", my_cpu, slot_pid); + if (__atomic_compare_exchange_n(&slot->pid, &slot_pid, my_pid, 0 /* weak */, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE)) { + pr_warn("WARNING: wc_linuxkm_svr_state_assoc_unlikely fixed up orphaned slot on CPU %d owned by dead PID %d (age %ld ms).\n", my_cpu, slot_pid, WC_SVR_SLOT_AGE_MS(slot)); + slot->reserved_at = jiffies; return slot; } } else { @@ -189,9 +247,9 @@ static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc_unlikely(int c { static int _warned_on_mismatched_pid = 0; if (_warned_on_mismatched_pid < 10) { - pr_warn("WARNING: wc_linuxkm_fpu_state_assoc called by pid %d on CPU %d" - " but CPU slot already reserved by pid %d.\n", - my_pid, my_cpu, slot_pid); + pr_warn("WARNING: wc_linuxkm_svr_state_assoc called by pid %d on CPU %d" + " but CPU slot already reserved by pid %d (age %ld ms).\n", + my_pid, my_cpu, slot_pid, WC_SVR_SLOT_AGE_MS(slot)); #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG dump_stack(); #endif @@ -201,33 +259,41 @@ static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc_unlikely(int c return NULL; } + } else if (my_pid == WC_SVR_IDLE_PID) { + /* unique per value, not per task - all swappers share WC_SVR_IDLE_PID, so a + * scan match may be another CPU's live hold. + */ + return NULL; } else { /* check for migration. this can happen despite our best efforts if any * I/O occurred while locked, e.g. kernel messages like "uninitialized * urandom read". since we're locked now, we can safely migrate the - * entry in wc_linuxkm_fpu_states[], freeing up the slot on the previous + * entry in wc_linuxkm_svr_states[], freeing up the slot on the previous * cpu. */ unsigned int cpu_i; - for (cpu_i = 0; cpu_i < wc_linuxkm_fpu_states_n_tracked; ++cpu_i) { + for (cpu_i = 0; cpu_i < wc_linuxkm_svr_states_n_tracked; ++cpu_i) { if (__atomic_load_n( - &wc_linuxkm_fpu_states[cpu_i].pid, + &wc_linuxkm_svr_states[cpu_i].pid, __ATOMIC_CONSUME) == my_pid) { - wc_linuxkm_fpu_states[my_cpu] = wc_linuxkm_fpu_states[cpu_i]; - __atomic_store_n(&wc_linuxkm_fpu_states[cpu_i].fpu_state, 0, + wc_linuxkm_svr_states[my_cpu] = wc_linuxkm_svr_states[cpu_i]; + __atomic_store_n(&wc_linuxkm_svr_states[cpu_i].fpu_state, 0, __ATOMIC_RELEASE); - __atomic_store_n(&wc_linuxkm_fpu_states[cpu_i].pid, 0, + __atomic_store_n(&wc_linuxkm_svr_states[cpu_i].pid, WC_SVR_FREE_SLOT_PID, __ATOMIC_RELEASE); - return &wc_linuxkm_fpu_states[my_cpu]; + /* don't clear the .reserved_at member -- it's invalidated by + * the .pid assignment, and it might prove useful + * forensically. */ + return &wc_linuxkm_svr_states[my_cpu]; } } return NULL; } } -static inline struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc( +static inline struct wc_thread_svr_count_ent *wc_linuxkm_svr_state_assoc( int create_p, int assume_fpu_began) { int my_cpu = raw_smp_processor_id(); /* my_cpu is only trustworthy if we're @@ -237,9 +303,9 @@ static inline struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc( * failing that, if create_p. */ pid_t my_pid, slot_pid; - struct wc_thread_fpu_count_ent *slot; + struct wc_thread_svr_count_ent *slot; - if (unlikely(wc_linuxkm_fpu_states == NULL)) { + if (unlikely(wc_linuxkm_svr_states == NULL)) { if (! assume_fpu_began) { /* this was just a quick check for whether we're in a recursive * wc_save_vector_registers_x86(). we're not. @@ -247,16 +313,16 @@ static inline struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc( return NULL; } else - return wc_linuxkm_fpu_state_assoc_unlikely(create_p); + return wc_linuxkm_svr_state_assoc_unlikely(create_p); } - my_pid = task_pid_nr(current); + my_pid = WC_SVR_PID_SLOT_ID(); - slot = &wc_linuxkm_fpu_states[my_cpu]; + slot = &wc_linuxkm_svr_states[my_cpu]; slot_pid = __atomic_load_n(&slot->pid, __ATOMIC_CONSUME); if (slot_pid == my_pid) { if (unlikely(create_p)) - return wc_linuxkm_fpu_state_assoc_unlikely(create_p); + return wc_linuxkm_svr_state_assoc_unlikely(create_p); else return slot; } @@ -265,67 +331,99 @@ static inline struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc( * wc_save_vector_registers_x86(). we're not. * * if we're in a softirq context, we'll always wind up here, because - * processes with entries in wc_linuxkm_fpu_states[] always have + * processes with entries in wc_linuxkm_svr_states[] always have * softirqs inhibited. */ return NULL; } if (likely(create_p)) { - if (likely(slot_pid == 0)) { + if (likely(slot_pid == WC_SVR_FREE_SLOT_PID)) { __atomic_store_n(&slot->pid, my_pid, __ATOMIC_RELEASE); + slot->reserved_at = jiffies; return slot; } else { - return wc_linuxkm_fpu_state_assoc_unlikely(create_p); + return wc_linuxkm_svr_state_assoc_unlikely(create_p); } } else { - return wc_linuxkm_fpu_state_assoc_unlikely(create_p); + return wc_linuxkm_svr_state_assoc_unlikely(create_p); } } -static void wc_linuxkm_fpu_state_release_unlikely( - struct wc_thread_fpu_count_ent *ent) +static void wc_linuxkm_svr_state_release_unlikely( + struct wc_thread_svr_count_ent *ent) { if (ent->fpu_state != 0) { static int warned_nonzero_fpu_state = 0; if (! warned_nonzero_fpu_state) { - VRG_PR_ERR_X("ERROR: wc_linuxkm_fpu_state_free for pid %d on CPU %d" - " with nonzero fpu_state 0x%x.\n", ent->pid, raw_smp_processor_id(), ent->fpu_state); + VRG_PR_ERR_X("ERROR: wc_linuxkm_svr_state_release for pid %d on CPU %d" + " with nonzero fpu_state 0x%x (age %ld ms).\n", ent->pid, + raw_smp_processor_id(), ent->fpu_state, WC_SVR_SLOT_AGE_MS(ent)); warned_nonzero_fpu_state = 1; } ent->fpu_state = 0; } - __atomic_store_n(&ent->pid, 0, __ATOMIC_RELEASE); + __atomic_store_n(&ent->pid, WC_SVR_FREE_SLOT_PID, __ATOMIC_RELEASE); } -static inline void wc_linuxkm_fpu_state_release( - struct wc_thread_fpu_count_ent *ent) +static inline void wc_linuxkm_svr_state_release( + struct wc_thread_svr_count_ent *ent) { if (unlikely(ent->fpu_state != 0)) - return wc_linuxkm_fpu_state_release_unlikely(ent); - __atomic_store_n(&ent->pid, 0, __ATOMIC_RELEASE); + return wc_linuxkm_svr_state_release_unlikely(ent); + __atomic_store_n(&ent->pid, WC_SVR_FREE_SLOT_PID, __ATOMIC_RELEASE); +} + +/* Note that a volatile is used here deliberately, rather than an atomic, to + * avoid frivolous overhead. wc_svr_disallowed_count is intrinsically only + * precise and reliable when the module is single-threaded (i.e. during module + * wolfssl_init()). Incrementing it atomically would gain nothing meaningful + * but incur the atomic tax. + */ +static volatile unsigned long long int wc_svr_disallowed_count = 0; + +void wc_svr_disallowed_count_reset(void) { + wc_svr_disallowed_count = 0; +} + +unsigned long long int wc_svr_disallowed_count_current(void) { + return wc_svr_disallowed_count; +} + +static inline void wc_svr_disallowed_count_increment(void) { + wc_svr_disallowed_count = wc_svr_disallowed_count + 1; } WARN_UNUSED_RESULT int wc_can_save_vector_registers_x86(void) { - struct wc_thread_fpu_count_ent *pstate; + struct wc_thread_svr_count_ent *pstate; /* check for hard interrupt context (unusable current->pid) preemptively. * if we're in a softirq context we'll catch that below with * a second preempt_count() check. */ - if (((preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0) || (task_pid_nr(current) == 0)) + if ((preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0) { +#ifdef DEBUG_VECTOR_REGISTER_ACCESS_HARDIRQ_INFO + pr_info("HARDIRQ_INFO: wc_can_save_vector_registers_x86() with preempt_count 0x%x, PID %d, CPU %d\n", + preempt_count(), task_pid_nr(current), raw_smp_processor_id()); + dump_stack(); +#endif + wc_svr_disallowed_count_increment(); return 0; + } - /* Check if we're already saved, per wc_linuxkm_fpu_states. */ - pstate = wc_linuxkm_fpu_state_assoc(0, 0); + /* Check if we're already saved, per wc_linuxkm_svr_states. */ + pstate = wc_linuxkm_svr_state_assoc(0, 0); if ((pstate != NULL) && (pstate->fpu_state != 0U)) { - if (unlikely(pstate->fpu_state & WC_FPU_INHIBITED_FLAG)) + if (unlikely(pstate->fpu_state & WC_SVR_INHIBITED_FLAG)) { + wc_svr_disallowed_count_increment(); return 0; - if (unlikely((pstate->fpu_state & WC_FPU_COUNT_MASK) - == WC_FPU_COUNT_MASK)) + } + if (unlikely((pstate->fpu_state & WC_SVR_COUNT_MASK) + == WC_SVR_COUNT_MASK)) { /* would overflow */ + wc_svr_disallowed_count_increment(); return 0; } else { return 1; @@ -333,65 +431,87 @@ WARN_UNUSED_RESULT int wc_can_save_vector_registers_x86(void) } #ifdef DEBUG_VECTOR_REGISTER_ACCESS_FUZZING - if (SAVE_VECTOR_REGISTERS2_fuzzer() != 0) + if (SAVE_VECTOR_REGISTERS2_fuzzer() != 0) { + wc_svr_disallowed_count_increment(); return 0; + } #endif if ((preempt_count() == 0) || may_use_simd()) return 1; - else + else { + wc_svr_disallowed_count_increment(); return 0; + } } WARN_UNUSED_RESULT int wc_save_vector_registers_x86(enum wc_svr_flags flags) { - struct wc_thread_fpu_count_ent *pstate; + struct wc_thread_svr_count_ent *pstate; + unsigned int new_state_flags = 0; - /* check for hard interrupt context (unusable current->pid) preemptively. - * if we're in a softirq context we'll catch that below with + /* Check for hard interrupt context (unusable current->pid) preemptively. + * If we're in a softirq context we'll catch that below with * a second look at preempt_count(). + * + * Note that this is not actually an abnormal condition in any way -- + * e.g. with LINUXKM_DRBG_GET_RANDOM_BYTES, get_random_u32() and the + * like called from hard IRQ handlers land here, and we return + * WC_ACCEL_INHIBIT_E for graceful fallback to C. */ - if (((preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0) || (task_pid_nr(current) == 0)) { - if (! (flags & (WC_SVR_FLAG_INHIBIT | WC_SVR_FLAG_MAYBE_INHIBIT))) { - VRG_PR_WARN_X("WARNING: wc_save_vector_registers_x86(0x%x) called with preempt_count 0x%x and pid %d on CPU %d.\n", (unsigned)flags, preempt_count(), task_pid_nr(current), raw_smp_processor_id()); - #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG - dump_stack(); - #endif - } + if ((preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0) { +#ifdef DEBUG_VECTOR_REGISTER_ACCESS_HARDIRQ_INFO + pr_info("HARDIRQ_INFO: wc_save_vector_registers_x86() with preempt_count 0x%x, PID %d, CPU %d\n", + preempt_count(), task_pid_nr(current), raw_smp_processor_id()); + dump_stack(); +#endif + wc_svr_disallowed_count_increment(); return WC_ACCEL_INHIBIT_E; } - pstate = wc_linuxkm_fpu_state_assoc(0, 0); + pstate = wc_linuxkm_svr_state_assoc(0, 0); /* allow for nested calls */ if (pstate && (pstate->fpu_state != 0U)) { - if (flags & WC_SVR_FLAG_MAYBE_INHIBIT) { + if (unlikely((pstate->fpu_state & WC_SVR_BH_HELD_FLAG) && (softirq_count() == 0))) { + VRG_PR_ERR_X("BUG: wc_save_vector_registers_x86(): zero softirq_count in nested call (depth %u, age %ld ms) after local_bh_disable() on CPU %d.\n", + (pstate->fpu_state & WC_SVR_COUNT_MASK), + WC_SVR_SLOT_AGE_MS(pstate), + raw_smp_processor_id()); + } + if (unlikely(flags & WC_SVR_FLAG_MAYBE_INHIBIT)) { VRG_PR_WARN_X("BUG: wc_save_vector_registers_x86() called by pid %d on CPU %d " - "with _MAYBE_INHIBIT flag at non-outermost depth %u.\n", task_pid_nr(current), + "with _MAYBE_INHIBIT flag in nested call (depth %u, age %ld ms).\n", task_pid_nr(current), raw_smp_processor_id(), - (pstate->fpu_state & WC_FPU_COUNT_MASK)); + (pstate->fpu_state & WC_SVR_COUNT_MASK), + WC_SVR_SLOT_AGE_MS(pstate)); #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG dump_stack(); #endif + wc_svr_disallowed_count_increment(); return BAD_STATE_E; } - if (pstate->fpu_state & WC_FPU_INHIBITED_FLAG) { + if (unlikely(pstate->fpu_state & WC_SVR_INHIBITED_FLAG)) { /* don't allow recursive inhibit calls when already inhibited -- * it would add no functionality and require keeping a separate * count of inhibit recursions. */ + wc_svr_disallowed_count_increment(); return WC_ACCEL_INHIBIT_E; } - if (unlikely((pstate->fpu_state & WC_FPU_COUNT_MASK) - == WC_FPU_COUNT_MASK)) + if (unlikely((pstate->fpu_state & WC_SVR_COUNT_MASK) + == WC_SVR_COUNT_MASK)) { pr_err("ERROR: wc_save_vector_registers_x86 recursion register overflow for " - "pid %d on CPU %d.\n", pstate->pid, raw_smp_processor_id()); + "pid %d on CPU %d (age %ld ms).\n", pstate->pid, raw_smp_processor_id(), + WC_SVR_SLOT_AGE_MS(pstate)); + wc_svr_disallowed_count_increment(); return BAD_STATE_E; } - if (flags & WC_SVR_FLAG_INHIBIT) { + if (unlikely(flags & WC_SVR_FLAG_INHIBIT)) { ++pstate->fpu_state; - pstate->fpu_state |= WC_FPU_INHIBITED_FLAG; + pstate->fpu_state |= WC_SVR_INHIBITED_FLAG; + wc_svr_disallowed_count_increment(); return 0; } else { @@ -408,8 +528,10 @@ WARN_UNUSED_RESULT int wc_save_vector_registers_x86(enum wc_svr_flags flags) */ { int ret = WC_CHECK_FOR_INTR_SIGNALS(); - if (ret) + if (ret) { + wc_svr_disallowed_count_increment(); return ret; + } } #endif @@ -421,8 +543,10 @@ WARN_UNUSED_RESULT int wc_save_vector_registers_x86(enum wc_svr_flags flags) if (ret != 0) { if (flags & WC_SVR_FLAG_MAYBE_INHIBIT) flags |= WC_SVR_FLAG_INHIBIT; - else + else { + wc_svr_disallowed_count_increment(); return ret; + } } } #endif @@ -430,100 +554,130 @@ WARN_UNUSED_RESULT int wc_save_vector_registers_x86(enum wc_svr_flags flags) if ((flags & WC_SVR_FLAG_MAYBE_INHIBIT) && ((preempt_count() != 0) && !may_use_simd())) { + wc_svr_disallowed_count_increment(); return WC_ACCEL_INHIBIT_E; /* not an error here, just a * short-circuit result. */ } if (flags & WC_SVR_FLAG_INHIBIT) { - if ((preempt_count() != 0) && !may_use_simd()) + if ((preempt_count() != 0) && !may_use_simd()) { + wc_svr_disallowed_count_increment(); return WC_ACCEL_INHIBIT_E; /* not an error here, just a * short-circuit result. */ + } /* we need to inhibit migration and softirqs here to assure that we can * support recursive calls safely, i.e. without mistaking a softirq * context for a recursion. + * + * pre-5.11, migrate_disable() either doesn't exist or is a no-op -- + * there, we lean on pinning from the bh offset or irq disablement. */ #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) migrate_disable(); #endif - local_bh_disable(); - if (preempt_count() == 0) { - VRG_PR_ERR_X("BUG: wc_save_vector_registers_x86(): zero preempt_count after local_bh_disable() on CPU %d.\n", - raw_smp_processor_id()); - #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) - migrate_enable(); - #endif - local_bh_enable(); - return WC_ACCEL_INHIBIT_E; + if (! irqs_disabled()) { + local_bh_disable(); + new_state_flags |= WC_SVR_BH_HELD_FLAG; + + if (softirq_count() == 0) { + VRG_PR_ERR_X("BUG: wc_save_vector_registers_x86(): zero softirq_count in outermost call after local_bh_disable() on CPU %d.\n", + raw_smp_processor_id()); + local_bh_enable(); + #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + migrate_enable(); + #endif + wc_svr_disallowed_count_increment(); + return WC_ACCEL_INHIBIT_E; + } } - pstate = wc_linuxkm_fpu_state_assoc(1, 1); + pstate = wc_linuxkm_svr_state_assoc(1, 1); if (pstate == NULL) { + if (new_state_flags & WC_SVR_BH_HELD_FLAG) + local_bh_enable(); #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) migrate_enable(); #endif - local_bh_enable(); + wc_svr_disallowed_count_increment(); return BAD_STATE_E; } pstate->fpu_state = - WC_FPU_INHIBITED_FLAG + 1U; + (WC_SVR_INHIBITED_FLAG | new_state_flags) + 1U; + wc_svr_disallowed_count_increment(); return 0; } if ((preempt_count() == 0) || may_use_simd()) { /* fpregs_lock() calls either local_bh_disable() or preempt_disable() - * depending on CONFIG_PREEMPT_RT -- we call both, explicitly. + * depending on CONFIG_PREEMPT_RT -- we call both, explicitly, with the + * sole exception that local_bh_disable() is necessarily omitted if the + * caller has irqs_disabled(). This exception is critical: without it, + * a caller in a critical section get local_bh_enable()d when it calls + * wc_restore_vector_registers_x86(), reenabling interrupts during its + * critical section. * - * empirically, on some kernels, kernel_fpu_begin() doesn't reliably - * disable softirqs, indeed doesn't make preempt_count() nonzero, which - * breaks our locking algorithm. we sidestep this completely by - * explicitly disabling softirq's, preemption, and migration. - * helpfully, the calls to do that are all guaranteed recursion-safe. + * Note: pre-6.15, kernel_fpu_begin() is preempt_disable()-only -- it + * never defers softirqs, and on !CONFIG_PREEMPT_COUNT configs it leaves + * preempt_count() zero, which would break our locking algorithm. 6.15+ + * (mainline commit d02198550423) disables bh in kernel_fpu_begin(), + * except for irqs-off callers. We sidestep the variance completely by + * making the disables ourselves; helpfully, all these calls are + * recursion-safe. */ #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) migrate_disable(); #endif - local_bh_disable(); + + if (! irqs_disabled()) { + local_bh_disable(); + new_state_flags |= WC_SVR_BH_HELD_FLAG; + } + #if IS_ENABLED(CONFIG_PREEMPT_RT) preempt_disable(); #endif kernel_fpu_begin(); - pstate = wc_linuxkm_fpu_state_assoc(1, 1); + pstate = wc_linuxkm_svr_state_assoc(1, 1); if (pstate == NULL) { kernel_fpu_end(); #if IS_ENABLED(CONFIG_PREEMPT_RT) preempt_enable(); #endif - local_bh_enable(); + if (new_state_flags & WC_SVR_BH_HELD_FLAG) + local_bh_enable(); #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) migrate_enable(); #endif + wc_svr_disallowed_count_increment(); return BAD_STATE_E; } - /* set msb to 0 to trigger kernel_fpu_end() at cleanup. */ - pstate->fpu_state = 1U; + pstate->fpu_state = new_state_flags | 1U; - if (preempt_count() == 0) { - VRG_PR_ERR_X("BUG: wc_save_vector_registers_x86(): zero preempt_count after kernel_fpu_begin() on CPU %d.\n", + if ((new_state_flags & WC_SVR_BH_HELD_FLAG) && (softirq_count() == 0)) { + VRG_PR_ERR_X("BUG: wc_save_vector_registers_x86(): zero softirq_count after local_bh_disable() on CPU %d.\n", raw_smp_processor_id()); } return 0; - } else { - VRG_PR_WARN_X("WARNING: wc_save_vector_registers_x86 called with no saved state and nonzero preempt_count 0x%x on CPU %d.\n", preempt_count(), raw_smp_processor_id()); - #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG - dump_stack(); - #endif + } else { + if (preempt_count() != 0) { + VRG_PR_WARN_X("WARNING: wc_save_vector_registers_x86 called with no saved state and nonzero preempt_count 0x%x on CPU %d.\n", preempt_count(), raw_smp_processor_id()); + #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG + dump_stack(); + #endif + } + wc_svr_disallowed_count_increment(); return WC_ACCEL_INHIBIT_E; } @@ -532,15 +686,16 @@ WARN_UNUSED_RESULT int wc_save_vector_registers_x86(enum wc_svr_flags flags) void wc_restore_vector_registers_x86(enum wc_svr_flags flags) { - struct wc_thread_fpu_count_ent *pstate; + struct wc_thread_svr_count_ent *pstate; + unsigned int cur_fpu_state; - if (((preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0) || (task_pid_nr(current) == 0)) { + if ((preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0) { VRG_PR_WARN_X("BUG: wc_restore_vector_registers_x86() called from interrupt handler on CPU %d.\n", raw_smp_processor_id()); return; } - pstate = wc_linuxkm_fpu_state_assoc(0, 1); + pstate = wc_linuxkm_svr_state_assoc(0, 1); if (unlikely(pstate == NULL)) { VRG_PR_WARN_X("BUG: wc_restore_vector_registers_x86() called by pid %d on CPU %d " "with no saved state.\n", task_pid_nr(current), @@ -551,23 +706,24 @@ void wc_restore_vector_registers_x86(enum wc_svr_flags flags) return; } - if ((--pstate->fpu_state & WC_FPU_COUNT_MASK) > 0U) { + if ((--pstate->fpu_state & WC_SVR_COUNT_MASK) > 0U) { if (flags & WC_SVR_FLAG_MAYBE_INHIBIT) { VRG_PR_WARN_X("BUG: wc_restore_vector_registers_x86() called by pid %d on CPU %d " - "with _MAYBE_INHIBIT flag at non-outermost depth %u.\n", task_pid_nr(current), + "with _MAYBE_INHIBIT flag at non-outermost depth %u (age %ld ms).\n", task_pid_nr(current), raw_smp_processor_id(), - (pstate->fpu_state & WC_FPU_COUNT_MASK) + 1U); + (pstate->fpu_state & WC_SVR_COUNT_MASK) + 1U, + WC_SVR_SLOT_AGE_MS(pstate)); #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG dump_stack(); #endif } if (flags & WC_SVR_FLAG_INHIBIT) { - if (pstate->fpu_state & WC_FPU_INHIBITED_FLAG) - pstate->fpu_state &= ~WC_FPU_INHIBITED_FLAG; + if (pstate->fpu_state & WC_SVR_INHIBITED_FLAG) + pstate->fpu_state &= ~WC_SVR_INHIBITED_FLAG; else { VRG_PR_WARN_X("BUG: wc_restore_vector_registers_x86() called by pid %d on CPU %d " - "with _INHIBIT flag but saved state isn't _INHIBITED_.\n", task_pid_nr(current), - raw_smp_processor_id()); + "with _INHIBIT flag but saved state isn't _INHIBITED_ (age %ld ms).\n", + task_pid_nr(current), raw_smp_processor_id(), WC_SVR_SLOT_AGE_MS(pstate)); #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG dump_stack(); #endif @@ -576,29 +732,44 @@ void wc_restore_vector_registers_x86(enum wc_svr_flags flags) return; } - if (pstate->fpu_state == 0U) { - wc_linuxkm_fpu_state_release(pstate); + cur_fpu_state = pstate->fpu_state; + + if ((pstate->fpu_state & ~WC_SVR_BH_HELD_FLAG) == 0U) { + pstate->fpu_state = 0; + wc_linuxkm_svr_state_release(pstate); kernel_fpu_end(); #if IS_ENABLED(CONFIG_PREEMPT_RT) preempt_enable(); #endif - local_bh_enable(); - } else if (unlikely(pstate->fpu_state & WC_FPU_INHIBITED_FLAG)) { + if (cur_fpu_state & WC_SVR_BH_HELD_FLAG) { + if (softirq_count() == 0) { + VRG_PR_ERR_X("BUG: wc_restore_vector_registers_x86(): zero softirq_count after local_bh_disable() on CPU %d.\n", + raw_smp_processor_id()); + } + local_bh_enable(); + } + } else if (unlikely(pstate->fpu_state & WC_SVR_INHIBITED_FLAG)) { if (unlikely(! (flags & (WC_SVR_FLAG_INHIBIT | WC_SVR_FLAG_MAYBE_INHIBIT)))) { VRG_PR_WARN_X("BUG: wc_restore_vector_registers_x86() called by pid %d on CPU %d " - "without _INHIBIT flag but saved state is _INHIBITED_.\n", task_pid_nr(current), - raw_smp_processor_id()); + "without _INHIBIT flag but saved state is _INHIBITED_ (age %ld ms).\n", + task_pid_nr(current), raw_smp_processor_id(), WC_SVR_SLOT_AGE_MS(pstate)); #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG dump_stack(); #endif } pstate->fpu_state = 0U; - wc_linuxkm_fpu_state_release(pstate); - local_bh_enable(); + wc_linuxkm_svr_state_release(pstate); + if (cur_fpu_state & WC_SVR_BH_HELD_FLAG) { + if (softirq_count() == 0) { + VRG_PR_ERR_X("BUG: wc_restore_vector_registers_x86(): zero softirq_count after local_bh_disable() on CPU %d.\n", + raw_smp_processor_id()); + } + local_bh_enable(); + } } #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) migrate_enable(); #endif diff --git a/src/pk_ec.c b/src/pk_ec.c index 12d11c874a..10a6662bc8 100644 --- a/src/pk_ec.c +++ b/src/pk_ec.c @@ -5540,9 +5540,10 @@ int wolfSSL_ECDH_compute_key(void *out, size_t outLen, setKeyRng = 1; } } - #endif - if (!err) { + if (!err) + #endif + { PRIVATE_KEY_UNLOCK(); /* Create secret using wolfSSL. */ ret = wc_ecc_shared_secret_ex(key, (ecc_point*)pubKey->internal, diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index f8ac66f4a2..64a33a520c 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -7732,8 +7732,8 @@ void bench_chacha20_poly1305_aead(void) { double start; int ret = 0, i, count; - ChaCha chacha; /* keyed once, reused per record: the TLS-record path */ - Poly1305 poly; + WC_DECLARE_VAR(chacha, ChaCha, 1, HEAP_HINT); /* keyed once, reused per record: the TLS-record path */ + WC_DECLARE_VAR(poly, Poly1305, 1, HEAP_HINT); byte nonce[CHACHA20_POLY1305_AEAD_IV_SIZE]; DECLARE_MULTI_VALUE_STATS_VARS() @@ -7742,6 +7742,8 @@ void bench_chacha20_poly1305_aead(void) bench_stats_prepare(); + WC_ALLOC_VAR(chacha, ChaCha, 1, HEAP_HINT); + WC_ALLOC_VAR(poly, Poly1305, 1, HEAP_HINT); WC_ALLOC_VAR(bench_additional, byte, AES_AUTH_ADD_SZ, HEAP_HINT); WC_ALLOC_VAR(authTag, byte, CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE, HEAP_HINT); XMEMSET(bench_additional, 0, AES_AUTH_ADD_SZ); @@ -7811,7 +7813,7 @@ void bench_chacha20_poly1305_aead(void) /* TLS-record path: ChaCha keyed once, only the nonce varies per record; * Encrypt_ex/Decrypt_ex use the single-pass stitch (no per-record * re-key). */ - ret = wc_Chacha_SetKey(&chacha, bench_key, + ret = wc_Chacha_SetKey(chacha, bench_key, CHACHA20_POLY1305_AEAD_KEYSIZE); if (ret != 0) { printf("wc_Chacha_SetKey error: %d\n", ret); @@ -7821,7 +7823,7 @@ void bench_chacha20_poly1305_aead(void) bench_stats_start(&count, &start); do { for (i = 0; i < numBlocks; i++) { - ret = wc_ChaCha20Poly1305_Encrypt_ex(&chacha, &poly, bench_cipher, + ret = wc_ChaCha20Poly1305_Encrypt_ex(chacha, poly, bench_cipher, bench_plain, bench_size, nonce, authTag, bench_additional, aesAuthAddSz); if (ret < 0) { @@ -7844,7 +7846,7 @@ void bench_chacha20_poly1305_aead(void) RESET_MULTI_VALUE_STATS_VARS(); /* Valid ciphertext+tag for the Decrypt_ex benchmark. */ - ret = wc_ChaCha20Poly1305_Encrypt_ex(&chacha, &poly, bench_cipher, + ret = wc_ChaCha20Poly1305_Encrypt_ex(chacha, poly, bench_cipher, bench_plain, bench_size, nonce, authTag, bench_additional, aesAuthAddSz); if (ret < 0) { @@ -7855,7 +7857,7 @@ void bench_chacha20_poly1305_aead(void) bench_stats_start(&count, &start); do { for (i = 0; i < numBlocks; i++) { - ret = wc_ChaCha20Poly1305_Decrypt_ex(&chacha, &poly, bench_plain, + ret = wc_ChaCha20Poly1305_Decrypt_ex(chacha, poly, bench_plain, bench_cipher, bench_size, nonce, authTag, bench_additional, aesAuthAddSz); if (ret < 0) { @@ -7932,6 +7934,8 @@ void bench_chacha20_poly1305_aead(void) WC_FREE_VAR(authTag, HEAP_HINT); WC_FREE_VAR(bench_additional, HEAP_HINT); + WC_FREE_VAR(poly, HEAP_HINT); + WC_FREE_VAR(chacha, HEAP_HINT); } #endif /* HAVE_CHACHA && HAVE_POLY1305 */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 102f48df7f..d12fa5e205 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -36883,11 +36883,17 @@ int InitOcspRequest(OcspRequest* req, DecodedCert* cert, byte useNonce, if (useNonce) { WC_RNG rng; - #ifndef HAVE_FIPS - ret = wc_InitRng_ex(&rng, req->heap, INVALID_DEVID); - #else - ret = wc_InitRng(&rng); - #endif +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) + ret = wc_InitRng_ex(&rng, req->heap, INVALID_DEVID); + #else + ret = wc_InitRng(&rng); + #endif + } if (ret != 0) { WOLFSSL_MSG("\tCannot initialize RNG. Skipping the OCSP Nonce."); } else { diff --git a/wolfcrypt/src/curve25519.c b/wolfcrypt/src/curve25519.c index 7f8807e53f..518db08117 100644 --- a/wolfcrypt/src/curve25519.c +++ b/wolfcrypt/src/curve25519.c @@ -221,7 +221,13 @@ int wc_curve25519_make_pub(int public_size, byte* pub, int private_size, { WC_RNG rng; - ret = wc_InitRng(&rng); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng(&rng); + } if (ret == 0) { ret = wc_curve25519_make_pub_blind(public_size, pub, private_size, priv, &rng); @@ -444,7 +450,13 @@ int wc_curve25519_generic(int public_size, byte* pub, { WC_RNG rng; - ret = wc_InitRng(&rng); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng(&rng); + } if (ret == 0) { ret = wc_curve25519_generic_blind(public_size, pub, private_size, priv, basepoint_size, basepoint, &rng); diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 3a56e8159e..e349a8dffb 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -11537,10 +11537,10 @@ static int _ecc_import_x963_ex2(const byte* in, word32 inLen, ecc_key* key, else inLen = inLen*2 + 1; /* used uncompressed len */ } + if (err == MP_OKAY) #endif - /* determine key size */ - if (err == MP_OKAY) { + { keysize = (int)(inLen>>1); /* NOTE: FIPS v6.0.0 or greater, no restriction on imported keys, * only on created keys or signatures */ diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index e48bacf922..1390cced7a 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -748,6 +748,9 @@ const char* wc_GetErrorString(int error) return "Requested operation succeeded, but supplied " "parameters are unapproved for FIPS"; + case NO_DEFAULT_FOUND_E: + return "No default object registered for request type"; + case MAX_CODE_E: case WC_SPAN1_MIN_CODE_E: case MIN_CODE_E: diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index a85d7603d7..f582203257 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -2853,7 +2853,16 @@ int wolfSSL_EVP_PKEY_derive(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *key, size_ (defined(HAVE_FIPS_VERSION) && HAVE_FIPS_VERSION > 2)) WC_RNG rng; - if (wc_InitRng(&rng) != MP_OKAY) { + int ret; + +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng(&rng); + } + if (ret != 0) { WOLFSSL_MSG("Init RNG failed"); return WOLFSSL_FAILURE; } @@ -6648,7 +6657,14 @@ void wolfSSL_EVP_init(void) } /* arg is 4...(ctx->ivSz - 8) */ XMEMCPY(ctx->iv, ptr, (size_t)arg); - if (wc_InitRng(&rng) != 0) { +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng(&rng); + } + if (ret != 0) { WOLFSSL_MSG("wc_InitRng failed"); break; } @@ -12392,11 +12408,17 @@ WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_ex(void* heap) pkey->heap = heap; pkey->type = WOLFSSL_EVP_PKEY_DEFAULT; +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &pkey->rng); + if (ret != 0) +#endif + { #ifndef HAVE_FIPS - ret = wc_InitRng_ex(&pkey->rng, heap, INVALID_DEVID); + ret = wc_InitRng_ex(&pkey->rng, heap, INVALID_DEVID); #else - ret = wc_InitRng(&pkey->rng); + ret = wc_InitRng(&pkey->rng); #endif + } if (ret != 0){ /* Free directly since mutex for ref count not set yet */ XFREE(pkey, heap, DYNAMIC_TYPE_PUBLIC_KEY); diff --git a/wolfcrypt/src/md5.c b/wolfcrypt/src/md5.c index f6c72d3118..56b43dc1ab 100644 --- a/wolfcrypt/src/md5.c +++ b/wolfcrypt/src/md5.c @@ -194,8 +194,10 @@ static int Transform_Len(wc_Md5* md5, const byte* data, word32 len) #define F3(x, y, z) ((x) ^ (y) ^ (z)) #define F4(x, y, z) ((y) ^ ((x) | ~(z))) -#define MD5STEP(f, w, x, y, z, data, s) \ - (w) = (rotlFixed((w) + f(x, y, z) + (data), s) + (x)) +#define MD5STEP(f, w, x, y, z, data, addend, s) \ + (w) = (rotlFixed((w) + f(x, y, z) + \ + readUnalignedWord32((const byte *)&(data)) + (addend), \ + s) + (x)) static int Transform(wc_Md5* md5, const byte* data) { @@ -206,73 +208,73 @@ static int Transform(wc_Md5* md5, const byte* data) word32 c = md5->digest[2]; word32 d = md5->digest[3]; - MD5STEP(F1, a, b, c, d, buffer[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, buffer[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, buffer[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, buffer[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, buffer[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, buffer[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, buffer[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, buffer[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, buffer[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, buffer[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, buffer[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, buffer[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, buffer[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, buffer[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, buffer[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, buffer[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, buffer[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, buffer[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, buffer[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, buffer[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, buffer[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, buffer[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, buffer[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, buffer[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, buffer[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, buffer[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, buffer[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, buffer[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, buffer[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, buffer[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, buffer[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, buffer[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, buffer[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, buffer[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, buffer[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, buffer[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, buffer[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, buffer[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, buffer[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, buffer[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, buffer[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, buffer[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, buffer[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, buffer[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, buffer[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, buffer[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, buffer[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, buffer[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, buffer[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, buffer[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, buffer[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, buffer[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, buffer[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, buffer[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, buffer[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, buffer[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, buffer[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, buffer[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, buffer[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, buffer[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, buffer[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, buffer[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, buffer[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, buffer[9] + 0xeb86d391, 21); + MD5STEP(F1, a, b, c, d, buffer[0] , 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, buffer[1] , 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, buffer[2] , 0x242070db, 17); + MD5STEP(F1, b, c, d, a, buffer[3] , 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, buffer[4] , 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, buffer[5] , 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, buffer[6] , 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, buffer[7] , 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, buffer[8] , 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, buffer[9] , 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, buffer[10] , 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, buffer[11] , 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, buffer[12] , 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, buffer[13] , 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, buffer[14] , 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, buffer[15] , 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, buffer[1] , 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, buffer[6] , 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, buffer[11] , 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, buffer[0] , 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, buffer[5] , 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, buffer[10] , 0x02441453, 9); + MD5STEP(F2, c, d, a, b, buffer[15] , 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, buffer[4] , 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, buffer[9] , 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, buffer[14] , 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, buffer[3] , 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, buffer[8] , 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, buffer[13] , 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, buffer[2] , 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, buffer[7] , 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, buffer[12] , 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, buffer[5] , 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, buffer[8] , 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, buffer[11] , 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, buffer[14] , 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, buffer[1] , 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, buffer[4] , 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, buffer[7] , 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, buffer[10] , 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, buffer[13] , 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, buffer[0] , 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, buffer[3] , 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, buffer[6] , 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, buffer[9] , 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, buffer[12] , 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, buffer[15] , 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, buffer[2] , 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, buffer[0] , 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, buffer[7] , 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, buffer[14] , 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, buffer[5] , 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, buffer[12] , 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, buffer[3] , 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, buffer[10] , 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, buffer[1] , 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, buffer[8] , 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, buffer[15] , 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, buffer[6] , 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, buffer[13] , 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, buffer[4] , 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, buffer[11] , 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, buffer[2] , 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, buffer[9] , 0xeb86d391, 21); /* Add the working vars back into digest state[] */ md5->digest[0] += a; diff --git a/wolfcrypt/src/pkcs12.c b/wolfcrypt/src/pkcs12.c index 67d5511788..f0eb94b2e4 100644 --- a/wolfcrypt/src/pkcs12.c +++ b/wolfcrypt/src/pkcs12.c @@ -2807,7 +2807,14 @@ WC_PKCS12* wc_PKCS12_create(char* pass, word32 passSz, char* name, WOLFSSL_ENTER("wc_PKCS12_create"); - if (wc_InitRng_ex(&rng, heap, INVALID_DEVID) != 0) { +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, heap, INVALID_DEVID); + } + if (ret != 0) { return NULL; } diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 9ef0130ebf..0736e1dc8e 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -4565,7 +4565,13 @@ int wc_PKCS7_EncodeSignedFPD(wc_PKCS7* pkcs7, byte* privateKey, content == NULL || contentSz == 0 || output == NULL || outputSz == 0) return BAD_FUNC_ARG; - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) return ret; @@ -4673,7 +4679,13 @@ int wc_PKCS7_EncodeSignedEncryptedFPD(wc_PKCS7* pkcs7, byte* encryptKey, XMEMCPY(encrypted, output, (word32)encryptedSz); ForceZero(output, outputSz); - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { ForceZero(encrypted, (word32)encryptedSz); XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7); @@ -4771,7 +4783,13 @@ int wc_PKCS7_EncodeSignedCompressedFPD(wc_PKCS7* pkcs7, byte* privateKey, XMEMCPY(compressed, output, compressedSz); ForceZero(output, outputSz); - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { ForceZero(compressed, compressedSz); XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); @@ -4907,7 +4925,13 @@ int wc_PKCS7_EncodeSignedEncryptedCompressedFPD(wc_PKCS7* pkcs7, byte* encryptK XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); ForceZero(output, outputSz); - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { ForceZero(encrypted, encryptedSz); XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7); @@ -8428,7 +8452,13 @@ static int PKCS7_GenerateContentEncryptionKey(wc_PKCS7* pkcs7, word32 len) XMEMSET(tmpKey, 0, len); - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; @@ -8771,7 +8801,13 @@ static int wc_PKCS7_KariGenerateEphemeralKey(WC_PKCS7_KARI* kari) kari->senderKeyInit = 1; - ret = wc_InitRng_ex(&rng, kari->heap, kari->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, kari->heap, kari->devId); + } if (ret != 0) { XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7); kari->senderKeyExportSz = 0; @@ -9647,7 +9683,13 @@ int wc_PKCS7_AddRecipient_KTRI(wc_PKCS7* pkcs7, const byte* cert, word32 certSz, return PUBLIC_KEY_E; } - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { wc_FreeRsaKey(pubKey); FreeDecodedCert(decoded); @@ -10440,7 +10482,13 @@ static int wc_PKCS7_GenerateBlock(wc_PKCS7* pkcs7, WC_RNG* rng, byte* out, if (rnd == NULL) return MEMORY_E; - ret = wc_InitRng_ex(rnd, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, rnd); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(rnd, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { XFREE(rnd, pkcs7->heap, DYNAMIC_TYPE_RNG); return ret; @@ -10720,7 +10768,13 @@ static int wc_PKCS7_PwriKek_KeyWrap(wc_PKCS7* pkcs7, const byte* kek, XMEMCPY(out + 4, cek, cekSz); /* random padding of size padSz */ - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) return ret; @@ -11527,7 +11581,13 @@ int wc_PKCS7_EncodeEnvelopedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz) verSz = SetMyVersion((word32)kariVersion, ver, 0); - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { wc_PKCS7_FreeEncodedRecipientSet(pkcs7); return ret; @@ -11855,7 +11915,13 @@ static int wc_PKCS7_KtriFakeCEK(wc_PKCS7* pkcs7, const byte* encryptedKey, WC_ALLOC_VAR_EX(localRng, WC_RNG, 1, pkcs7->heap, DYNAMIC_TYPE_RNG, WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC); return MEMORY_E); - ret = wc_InitRng_ex(localRng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, localRng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(localRng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG); WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC); @@ -12209,7 +12275,13 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, /* decrypt encryptedKey */ #ifdef WC_RSA_BLINDING - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + #if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) + #endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret == 0) { ret = wc_RsaSetRNG(privKey, &rng); } @@ -15365,7 +15437,13 @@ int wc_PKCS7_EncodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* output, #endif /* HAVE_AESCCM */ } - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + ret = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (ret != 0) +#endif + { + ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); + } if (ret != 0) { wc_PKCS7_FreeEncodedRecipientSet(pkcs7); return ret; diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index a600356d9e..2c7dfed605 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -330,12 +330,15 @@ enum { CONST_NUM_ERR_DRBG_CONT_FAILURE = DRBG_CONT_FAILURE, CONST_NUM_ERR_DRBG_NO_SEED_CB = DRBG_NO_SEED_CB }; - #define DRBG_FAILURE WC_ERR_TRACE(DRBG_FAILURE) - #define DRBG_NEED_RESEED WC_ERR_TRACE(DRBG_NEED_RESEED) - #define DRBG_CONT_FAILURE WC_ERR_TRACE(DRBG_CONT_FAILURE) - #define DRBG_NO_SEED_CB WC_ERR_TRACE(DRBG_NO_SEED_CB) - #define WC_DRBG_FAILED WC_ERR_TRACE(WC_DRBG_FAILED) - #define WC_DRBG_CONT_FAILED WC_ERR_TRACE(WC_DRBG_CONT_FAILED) + /* DRBG_SUCCESS needs to be macroized to avoid "enumerated and + * non-enumerated type in conditional expression" in C++. */ + #define DRBG_SUCCESS (byte)DRBG_SUCCESS + #define DRBG_FAILURE (byte)WC_ERR_TRACE(DRBG_FAILURE) + #define DRBG_NEED_RESEED (byte)WC_ERR_TRACE(DRBG_NEED_RESEED) + #define DRBG_CONT_FAILURE (byte)WC_ERR_TRACE(DRBG_CONT_FAILURE) + #define DRBG_NO_SEED_CB (byte)WC_ERR_TRACE(DRBG_NO_SEED_CB) + #define WC_DRBG_FAILED (byte)WC_ERR_TRACE(WC_DRBG_FAILED) + #define WC_DRBG_CONT_FAILED (byte)WC_ERR_TRACE(WC_DRBG_CONT_FAILED) #endif /* RNG health states */ @@ -2001,7 +2004,7 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #endif #ifdef HAVE_INTEL_RDRAND - /* if CPU supports RDRAND, use it directly and by-pass DRBG init */ + /* if CPU supports RDRAND, use it directly and bypass DRBG init */ if (IS_INTEL_RDRAND(intel_flags)) { #ifdef HAVE_HASHDRBG rng->status = DRBG_OK; @@ -2666,11 +2669,11 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) ret = wc_local_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(bank_inst), output, sz); { - int checkin_ret = wc_rng_bank_checkin(rng->bankref, &bank_inst); + int checkin_ret = wc_rng_bank_inst_checkin(&bank_inst); if (checkin_ret != 0) { #ifdef WC_VERBOSE_RNG WOLFSSL_DEBUG_PRINTF( - "ERROR: wc_RNG_GenerateBlock() wc_rng_bank_checkin() " + "ERROR: wc_RNG_GenerateBlock() wc_rng_bank_inst_checkin() " "failed with err %d.", checkin_ret); #endif if (ret == 0) diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index c17e30eda1..96dfe63a12 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -122,6 +122,7 @@ WOLFSSL_API int wc_rng_bank_init( int nretries = 0; #endif time_t ts1 = XTIME(0); + rng_inst->bank = ctx; for (;;) { time_t ts2; @@ -354,7 +355,7 @@ static struct wc_rng_bank * volatile default_rng_bank; WOLFSSL_API int wc_rng_bank_default_set(struct wc_rng_bank *bank) { int ret; struct wc_rng_bank *cur_default_rng_bank = NULL; - int new_refcount; + WC_ATOMIC_INT_ARG new_refcount; if (bank == NULL) return BAD_FUNC_ARG; @@ -399,6 +400,8 @@ WOLFSSL_API int wc_rng_bank_default_checkout(struct wc_rng_bank **bank) { if (bank == NULL) return BAD_FUNC_ARG; if (cur_default_rng_bank == NULL) + return NO_DEFAULT_FOUND_E; + else if (! (cur_default_rng_bank->flags & WC_RNG_BANK_FLAG_INITED)) return BAD_STATE_E; wolfSSL_RefInc_IfAtLeast(&cur_default_rng_bank->refcount, 2, &new_refcount, &ret); @@ -412,7 +415,7 @@ WOLFSSL_API int wc_rng_bank_default_checkout(struct wc_rng_bank **bank) { WOLFSSL_API int wc_rng_bank_default_checkin(struct wc_rng_bank **bank) { int ret; - int new_refcount; + WC_ATOMIC_INT_ARG new_refcount; if ((bank == NULL) || (*bank == NULL)) return BAD_FUNC_ARG; wolfSSL_RefDec2(&(*bank)->refcount, &new_refcount, &ret); @@ -437,7 +440,7 @@ WOLFSSL_API int wc_rng_bank_default_clear(struct wc_rng_bank *bank) { return BAD_FUNC_ARG; if (wolfSSL_Atomic_Ptr_CompareExchange((void * volatile *)&default_rng_bank, (void **)&bank, NULL)) { int ret; - int new_refcount; + WC_ATOMIC_INT_ARG new_refcount; wolfSSL_RefDec2(&bank->refcount, &new_refcount, &ret); #ifdef WC_VERBOSE_RNG /* wc_rng_bank_fini() is the sole responsibility of the context that @@ -482,21 +485,39 @@ WOLFSSL_API int wc_rng_bank_checkout( int n_rngs_tried = 0; WC_ATOMIC_INT_ARG new_refcount; -#ifdef WC_RNG_BANK_DEFAULT_SUPPORT - if (bank == NULL) - bank = default_rng_bank; -#endif + if (rng_inst == NULL) + return BAD_FUNC_ARG; - if ((bank == NULL) || - (rng_inst == NULL)) - { + if (bank == NULL) { +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + ret = wc_rng_bank_default_checkout(&bank); + if (ret != 0) + return ret; + /* wc_rng_bank_default_checkout() increments bank->refcount, which we + * carry through below (no matching wc_rng_bank_default_checkin()). + */ +#else return BAD_FUNC_ARG; +#endif } + else { + if ((! (bank->flags & WC_RNG_BANK_FLAG_INITED)) || + (wolfSSL_RefCur(bank->refcount) < 1)) + { + return BAD_STATE_E; + } - if ((! (bank->flags & WC_RNG_BANK_FLAG_INITED)) || - (wolfSSL_RefCur(bank->refcount) < 1)) - { - return BAD_STATE_E; + /* Increment bank->refcount here speculatively to mitigate races with + * bank deallocation. + */ + wolfSSL_RefInc_IfAtLeast(&bank->refcount, 1, &new_refcount, &ret); + if (ret != 0) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "wc_rng_bank_checkout() called with refcount %d.\n", new_refcount); +#endif + return ret; + } } if ((flags & WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST) && @@ -507,19 +528,8 @@ WOLFSSL_API int wc_rng_bank_checkout( "BUG: wc_rng_bank_checkout() called with _PREFER_AFFINITY_INST but " "no _get_id_cb.\n"); #endif - return BAD_FUNC_ARG; - } - - /* Increment bank->refcount here speculatively, and assert on the resulting - * refcount, to mitigate races with bank deallocation. - */ - wolfSSL_RefInc_IfAtLeast(&bank->refcount, 1, &new_refcount, &ret); - if (ret != 0) { -#ifdef WC_VERBOSE_RNG - WOLFSSL_DEBUG_PRINTF( - "wc_rng_bank_checkout() called with refcount %d.\n", new_refcount); -#endif - return ret; + ret = BAD_FUNC_ARG; + goto out; } if ((timeout_secs > 0) && (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) @@ -545,11 +555,11 @@ WOLFSSL_API int wc_rng_bank_checkout( ret = bank->affinity_lock_cb(bank->cb_arg); if (ret == 0) new_lock_value |= WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED; - else if ((ret == WC_NO_ERR_TRACE(ALREADY_E)) || - (ret == WC_NO_ERR_TRACE(WC_ACCEL_INHIBIT_E))) + else { + /* need to, and can, continue regardless of the error code from + * bank->affinity_lock_cb. */ ret = 0; - else - break; + } } if (flags & WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST) { @@ -680,13 +690,18 @@ WOLFSSL_API int wc_rng_bank_checkout( } } +out: + if (ret == 0) ret = RNG_FAILURE_E; if (new_lock_value & WC_RNG_BANK_INST_LOCK_AFFINITY_LOCKED) (void)bank->affinity_unlock_cb(bank->cb_arg); - /* Decrement the speculative refcount increment. */ + /* Decrement the speculative refcount increment. This also covers the + * refcount increment in wc_rng_bank_default_checkout() if that's how it was + * incremented. + */ { int refdec_err; wolfSSL_RefDec2(&bank->refcount, &new_refcount, &refdec_err); @@ -711,6 +726,8 @@ WOLFSSL_LOCAL int wc_local_rng_bank_checkout_for_bankref( struct wc_rng_bank *bank, struct wc_rng_bank_inst **rng_inst) { + if (bank == NULL) + return BAD_FUNC_ARG; return wc_rng_bank_checkout( bank, rng_inst, 0, 0, WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST | @@ -726,6 +743,10 @@ static WC_INLINE int rng_inst_matches_bank( { if ((bank == NULL) || (rng_inst == NULL)) return BAD_FUNC_ARG; + if (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) + return BAD_STATE_E; + if (wolfSSL_RefCur(bank->refcount) < 2) + return BAD_STATE_E; #ifdef WC_RNG_BANK_STATIC if ((rng_inst >= &bank->rngs[0]) && (rng_inst <= &bank->rngs[WC_RNG_BANK_STATIC_SIZE - 1])) @@ -748,12 +769,12 @@ WOLFSSL_API int wc_rng_bank_checkin( int lockval; int ret; - if (rng_inst == NULL) + if ((rng_inst == NULL) || (*rng_inst == NULL)) return BAD_FUNC_ARG; #ifdef WC_RNG_BANK_DEFAULT_SUPPORT if (bank == NULL) - bank = default_rng_bank; + bank = (*rng_inst)->bank; #endif ret = rng_inst_matches_bank(bank, *rng_inst); @@ -794,6 +815,14 @@ WOLFSSL_API int wc_rng_bank_checkin( return ret; } +WOLFSSL_API int wc_rng_bank_inst_checkin( + struct wc_rng_bank_inst **rng_inst) +{ + if ((rng_inst == NULL) || (*rng_inst == NULL)) + return BAD_FUNC_ARG; + return wc_rng_bank_checkin((*rng_inst)->bank, rng_inst); +} + /* note the rng_inst passed to wc_rng_bank_inst_reinit() must have been obtained * via wc_rng_bank_checkout() to assure that the caller holds the proper locks. */ @@ -807,15 +836,15 @@ WOLFSSL_API int wc_rng_bank_inst_reinit( time_t ts1 = 0; int devId; -#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (rng_inst == NULL) + return BAD_FUNC_ARG; + if (bank == NULL) - bank = default_rng_bank; -#endif + bank = rng_inst->bank; - /* rng_inst NULL check handled by rng_inst_matches_bank() */ ret = rng_inst_matches_bank(bank, rng_inst); if (ret < 0) - return BAD_FUNC_ARG; + return ret; if (WC_RNG_BANK_DRBG_NULL(&rng_inst->rng)) { @@ -870,20 +899,32 @@ WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank, { int ret = 0; int n; - #ifdef WC_RNG_BANK_DEFAULT_SUPPORT - if (bank == NULL) - bank = default_rng_bank; + int bank_is_default = 0; #endif - if ((bank == NULL) || - (! (bank->flags & WC_RNG_BANK_FLAG_INITED))) - { + if (bank == NULL) { +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (seedSz == 0) { + if (default_rng_bank == NULL) + return NO_DEFAULT_FOUND_E; + else + return 0; + } + ret = wc_rng_bank_default_checkout(&bank); + if (ret != 0) + return ret; + bank_is_default = 1; +#else return BAD_FUNC_ARG; +#endif + } + else { + if (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) + return BAD_STATE_E; + if (seedSz == 0) + return 0; } - - if (seedSz == 0) - return 0; /* this iteration counts down, whereas the iteration in get_drbg() counts * up, to assure they can't possibly phase-lock to each other. @@ -922,6 +963,11 @@ WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank, break; } +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (bank_is_default) + (void)wc_rng_bank_default_checkin(&bank); +#endif + return ret; } @@ -932,22 +978,29 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, int n; int ret; time_t ts1 = 0; - #ifdef WC_RNG_BANK_DEFAULT_SUPPORT - if (bank == NULL) - bank = default_rng_bank; + int bank_is_default = 0; #endif - if ((bank == NULL) || - (! (bank->flags & WC_RNG_BANK_FLAG_INITED))) - { - return BAD_FUNC_ARG; - } - if (flags & (WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST | WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST)) return BAD_FUNC_ARG; + if (bank == NULL) { +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + ret = wc_rng_bank_default_checkout(&bank); + if (ret != 0) + return ret; + bank_is_default = 1; +#else + return BAD_FUNC_ARG; +#endif + } + else { + if (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) + return BAD_STATE_E; + } + if ((timeout_secs > 0) && (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) ts1 = XTIME(0); @@ -956,7 +1009,7 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, ret = wc_rng_bank_checkout(bank, &drbg, n, timeout_secs, flags); if (ret != 0) - return ret; + goto out; WC_RNG_BANK_SET_RESEED_CTR(&drbg->rng, WC_RESEED_INTERVAL); @@ -1000,11 +1053,11 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, if ((ret == WC_NO_ERR_TRACE(WC_TIMEOUT_E)) || (ret == WC_NO_ERR_TRACE(INTERRUPTED_E))) { - return ret; + goto out; } ret = WC_CHECK_FOR_INTR_SIGNALS(); if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) - return ret; + goto out; WC_RELAX_LONG_LOOP(); } else { @@ -1012,41 +1065,84 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, } } - return 0; + ret = 0; + +out: + +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (bank_is_default) + (void)wc_rng_bank_default_checkin(&bank); +#endif + + return ret; } #ifdef WC_HAVE_RNG_BANKREF -WOLFSSL_API int wc_InitRng_BankRef(struct wc_rng_bank *bank, WC_RNG *rng) -{ +static int wc_InitRng_BankRef_local(struct wc_rng_bank *bank, WC_RNG **rng) { int ret; WC_ATOMIC_INT_ARG new_refcount; + if (rng == NULL) + return BAD_FUNC_ARG; + + if (bank == NULL) { #ifdef WC_RNG_BANK_DEFAULT_SUPPORT - if (bank == NULL) - bank = default_rng_bank; + ret = wc_rng_bank_default_checkout(&bank); + if (ret != 0) + return ret; + /* wc_rng_bank_default_checkout() increments bank->refcount, which we + * carry through below (no matching wc_rng_bank_default_checkin()). + */ +#else + return BAD_FUNC_ARG; #endif + } + else { + if (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) + return BAD_STATE_E; + wolfSSL_RefInc_IfAtLeast(&bank->refcount, 1, &new_refcount, &ret); + (void)new_refcount; + if (ret != 0) + return ret; + } - if ((bank == NULL) || - (rng == NULL)) - { - return BAD_FUNC_ARG; +#if !defined(WC_RNG_BANK_STATIC) && !defined(WC_NO_CONSTRUCTORS) + if (*rng == NULL) { + *rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), bank->heap, DYNAMIC_TYPE_RNG); + if (*rng == NULL) { + ret = MEMORY_E; + goto out; + } } +#endif - if (! (bank->flags & WC_RNG_BANK_FLAG_INITED)) - return BAD_STATE_E; + XMEMSET(*rng, 0, sizeof(**rng)); + (*rng)->heap = bank->heap; + (*rng)->status = WC_DRBG_BANKREF; + (*rng)->bankref = bank; - wolfSSL_RefInc_IfAtLeast(&bank->refcount, 1, &new_refcount, &ret); - (void)new_refcount; - if (ret != 0) - return ret; + ret = 0; - XMEMSET(rng, 0, sizeof(*rng)); - rng->heap = bank->heap; - rng->status = WC_DRBG_BANKREF; - rng->bankref = bank; +#if !defined(WC_RNG_BANK_STATIC) && !defined(WC_NO_CONSTRUCTORS) +out: +#endif - return 0; + if (ret != 0) { + int refdec_err; + wolfSSL_RefDec2(&bank->refcount, &new_refcount, &refdec_err); + (void)new_refcount; + (void)refdec_err; + } + + return ret; +} + +WOLFSSL_API int wc_InitRng_BankRef(struct wc_rng_bank *bank, WC_RNG *rng) +{ + if (rng == NULL) + return BAD_FUNC_ARG; + return wc_InitRng_BankRef_local(bank, &rng); } WOLFSSL_API int wc_BankRef_Release(WC_RNG *rng) @@ -1073,37 +1169,10 @@ WOLFSSL_API int wc_BankRef_Release(WC_RNG *rng) #if !defined(WC_RNG_BANK_STATIC) && !defined(WC_NO_CONSTRUCTORS) WOLFSSL_API int wc_rng_new_bankref(struct wc_rng_bank *bank, WC_RNG **rng) { - int ret; - -#ifdef WC_RNG_BANK_DEFAULT_SUPPORT - if (bank == NULL) - bank = default_rng_bank; -#endif - - if ((bank == NULL) || - (rng == NULL)) - { + if (rng == NULL) return BAD_FUNC_ARG; - } - - if ((! (bank->flags & WC_RNG_BANK_FLAG_INITED)) || - (wolfSSL_RefCur(bank->refcount) < 1)) - { - return BAD_STATE_E; - } - - *rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), bank->heap, DYNAMIC_TYPE_RNG); - if (*rng == NULL) { - return MEMORY_E; - } - - ret = wc_InitRng_BankRef(bank, *rng); - if (ret != 0) { - XFREE(*rng, bank->heap, DYNAMIC_TYPE_RNG); - *rng = NULL; - } - - return ret; + *rng = NULL; + return wc_InitRng_BankRef_local(bank, rng); } #endif /* !WC_RNG_BANK_STATIC && !WC_NO_CONSTRUCTORS */ diff --git a/wolfcrypt/src/srp.c b/wolfcrypt/src/srp.c index 44c48d45ef..20a504f0f4 100644 --- a/wolfcrypt/src/srp.c +++ b/wolfcrypt/src/srp.c @@ -557,7 +557,13 @@ static int wc_SrpGenPrivate(Srp* srp, byte* priv, word32 size) WC_RNG rng; int r; - r = wc_InitRng_ex(&rng, srp->heap, INVALID_DEVID); +#if defined(WC_RNG_BANK_DEFAULT_SUPPORT) && defined(WC_HAVE_RNG_BANKREF) + r = wc_InitRng_BankRef(NULL /* bank */, &rng); + if (r != 0) +#endif + { + r = wc_InitRng_ex(&rng, srp->heap, INVALID_DEVID); + } if (r == 0) { r = wc_RNG_GenerateBlock(&rng, priv, size); if (r == 0) { diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 71b031a408..0fb6d9760d 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -530,9 +530,9 @@ int wolfCrypt_Init(void) #endif #if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(WOLFSSL_LINUXKM) - ret = allocate_wolfcrypt_linuxkm_fpu_states(); + ret = wc_linuxkm_allocate_svr_states(); if (ret != 0) { - WOLFSSL_MSG("allocate_wolfcrypt_linuxkm_fpu_states failed"); + WOLFSSL_MSG("wc_linuxkm_allocate_svr_states failed"); WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -893,7 +893,7 @@ int wolfCrypt_Cleanup(void) wolfSSL_CleanupHandle(); #endif #if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(WOLFSSL_LINUXKM) - free_wolfcrypt_linuxkm_fpu_states(); + wc_linuxkm_free_svr_states(); #endif #ifdef HAVE_ENTROPY_MEMUSE diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index e2fa72b69e..8327027f2e 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -138,7 +138,7 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; esp_start_heap = esp_this_heap; \ } \ ESP_LOGI(ESPIDF_TAG, "%s #%d; Heap free: %d", \ - ((b) ? (b) : ""), /* breadcumb string */ \ + ((b) ? (b) : ""), /* breadcrumb string */ \ ((i) ? (i) : 0), /* index */ \ esp_this_heap); @@ -23579,49 +23579,59 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aeskeywrap_test(void) /* Drive wc_AesKeyWrap_ex/wc_AesKeyUnWrap_ex directly with a caller Aes; the * KAT loop above already covers every vector via the key-based wrappers. */ { - Aes* aes = (Aes*)XMALLOC(sizeof(Aes), HEAP_HINT, DYNAMIC_TYPE_AES); - if (aes == NULL) - return WC_TEST_RET_ENC_NC; - + int aes_inited = 0; + int ret; + WC_DECLARE_VAR(aes, Aes, 1, HEAP_HINT); + WC_ALLOC_VAR_EX(aes, Aes, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, + ERROR_OUT(WC_TEST_RET_ENC_EC(MEMORY_E), out)); XMEMSET(output, 0, sizeof(output)); XMEMSET(plain, 0, sizeof(plain)); - if (wc_AesInit(aes, HEAP_HINT, devId) != 0) { - XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES); - return WC_TEST_RET_ENC_NC; - } - if (wc_AesSetKey(aes, test_wrap[0].kek, test_wrap[0].kekLen, NULL, - AES_ENCRYPTION) != 0) { - wc_AesFree(aes); - XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES); - return WC_TEST_RET_ENC_NC; - } - wrapSz = wc_AesKeyWrap_ex(aes, test_wrap[0].data, test_wrap[0].dataLen, + ret = wc_AesInit(aes, HEAP_HINT, devId); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + aes_inited = 1; + ret = wc_AesSetKey(aes, test_wrap[0].kek, test_wrap[0].kekLen, + NULL, AES_ENCRYPTION); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + wrapSz = wc_AesKeyWrap_ex(aes, test_wrap[0].data, + test_wrap[0].dataLen, output, sizeof(output), NULL); + if (wrapSz < 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(wrapSz), out); + if (wrapSz != (int)test_wrap[0].verifyLen) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + if (XMEMCMP(output, test_wrap[0].verify, test_wrap[0].verifyLen) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + wc_AesFree(aes); - if ( (wrapSz < 0) || (wrapSz != (int)test_wrap[0].verifyLen) || - XMEMCMP(output, test_wrap[0].verify, test_wrap[0].verifyLen) != 0) { - XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES); - return WC_TEST_RET_ENC_NC; - } + aes_inited = 0; + ret = wc_AesInit(aes, HEAP_HINT, devId); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + aes_inited = 1; - if (wc_AesInit(aes, HEAP_HINT, devId) != 0) { - XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES); - return WC_TEST_RET_ENC_NC; - } - if (wc_AesSetKey(aes, test_wrap[0].kek, test_wrap[0].kekLen, NULL, - AES_DECRYPTION) != 0) { - wc_AesFree(aes); - XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES); - return WC_TEST_RET_ENC_NC; - } + ret = wc_AesSetKey(aes, test_wrap[0].kek, test_wrap[0].kekLen, NULL, + AES_DECRYPTION); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); plainSz = wc_AesKeyUnWrap_ex(aes, output, (word32)wrapSz, plain, sizeof(plain), NULL); - wc_AesFree(aes); - XFREE(aes, HEAP_HINT, DYNAMIC_TYPE_AES); - if ( (plainSz < 0) || (plainSz != (int)test_wrap[0].dataLen) || - XMEMCMP(plain, test_wrap[0].data, test_wrap[0].dataLen) != 0) - return WC_TEST_RET_ENC_NC; + if (plainSz < 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(plainSz), out); + if (plainSz != (int)test_wrap[0].dataLen) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + if (XMEMCMP(plain, test_wrap[0].data, test_wrap[0].dataLen) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + + out: + + if (aes_inited) + wc_AesFree(aes); + WC_FREE_VAR(aes, HEAP_HINT); + if (ret != 0) + return ret; } /* In-place round-trip (in == out): wrap then unwrap a single buffer. @@ -26624,7 +26634,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); if (rng_inst != bank->rngs + 3) ERROR_OUT(WC_TEST_RET_ENC_NC, out); - ret = wc_rng_bank_checkin(bank, &rng_inst); + ret = wc_rng_bank_inst_checkin(&rng_inst); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -26639,7 +26649,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_rng_bank_checkin(bank, &rng_inst); + ret = wc_rng_bank_inst_checkin(&rng_inst); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); if (rng_inst != NULL) @@ -26650,8 +26660,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) #ifdef WC_HAVE_RNG_BANKREF ret = wc_InitRng_BankRef(NULL, rng); +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (ret != WC_NO_ERR_TRACE(NO_DEFAULT_FOUND_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#else if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#endif ret = wc_InitRng_BankRef(bank, NULL); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) @@ -26671,8 +26686,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) #endif ret = wc_rng_bank_reseed(NULL, 10, WC_RNG_BANK_FLAG_NONE); +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (ret != WC_NO_ERR_TRACE(NO_DEFAULT_FOUND_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#else if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#endif ret = wc_rng_bank_reseed(bank, 10, WC_RNG_BANK_FLAG_NONE); if (ret != 0) @@ -26719,7 +26739,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst), outbuf2, sizeof(outbuf2)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_rng_bank_checkin(bank, &rng_inst); + ret = wc_rng_bank_inst_checkin(&rng_inst); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -26745,13 +26765,18 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) /* can't wc_rng_bank_seed() while holding an inst (deadlock/timeout) -- * check in then check back out. */ - ret = wc_rng_bank_checkin(bank, &rng_inst); + ret = wc_rng_bank_inst_checkin(&rng_inst); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); ret = wc_rng_bank_seed(NULL, (byte *)bank_arg, (word32)sizeof(bank_arg), 10, WC_RNG_BANK_FLAG_CAN_WAIT); +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (ret != WC_NO_ERR_TRACE(NO_DEFAULT_FOUND_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#else if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#endif ret = wc_rng_bank_seed(bank, (byte *)bank_arg, (word32)sizeof(bank_arg), 10, WC_RNG_BANK_FLAG_CAN_WAIT); if (ret != 0) @@ -26772,8 +26797,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) if (XMEMCMP(outbuf1, outbuf2, sizeof(outbuf1)) == 0) ERROR_OUT(WC_TEST_RET_ENC_NC, out); + /* NULL bank to wc_rng_bank_inst_reinit() tells it to use the bank with + * which rng_inst is associated. */ ret = wc_rng_bank_inst_reinit(NULL, rng_inst, 10, WC_RNG_BANK_FLAG_CAN_WAIT); - if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); /* bogus pointer test */ @@ -26792,17 +26819,18 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) if (XMEMCMP(outbuf1, outbuf2, sizeof(outbuf1)) == 0) ERROR_OUT(WC_TEST_RET_ENC_NC, out); - ret = wc_rng_bank_checkin(NULL, &rng_inst); - if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) - ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_rng_bank_checkin(bank, &rng_inst); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); ret = wc_rng_bank_checkout(NULL, &rng_inst, -1, 10, WC_RNG_BANK_FLAG_PREFER_AFFINITY_INST | WC_RNG_BANK_FLAG_AFFINITY_LOCK); +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (ret != WC_NO_ERR_TRACE(NO_DEFAULT_FOUND_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#else if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#endif #ifdef WC_HAVE_RNG_BANKREF if (wolfSSL_RefCur(bank->refcount) != 2) @@ -26974,8 +27002,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) #ifdef WC_HAVE_RNG_BANKREF ret = wc_rng_new_bankref(NULL, &rng2); +#ifdef WC_RNG_BANK_DEFAULT_SUPPORT + if (ret != WC_NO_ERR_TRACE(NO_DEFAULT_FOUND_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#else if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#endif ret = wc_rng_new_bankref(bank2, NULL); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) @@ -82871,9 +82904,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) #endif /* Driver coverage for the new CryptoCb hooks: confirm each op is routed - * through myCryptoDevCb (counter bumped) and the round-trip is correct. */ + * through myCryptoDevCb (counter bumped) and the round-trip is correct. + * + * The FIPS wrappers force the devId to FIPS_INVALID_DEVID, so we skip + * the check for FIPS. */ #if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) && \ - defined(HAVE_ED448_VERIFY) && !defined(WC_NO_RNG) + defined(HAVE_ED448_VERIFY) && !defined(WC_NO_RNG) && \ + !defined(HAVE_FIPS) if (ret == 0) { WC_RNG ed448Rng; int ed448RngInit = 0; @@ -82937,7 +82974,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) #endif /* HAVE_ED448 */ #if defined(WOLFSSL_CMAC) && defined(WOLF_CRYPTO_CB_FREE) && \ - !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) + !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) && \ + !defined(HAVE_FIPS) if (ret == 0) { byte cmacKey[WC_AES_BLOCK_SIZE] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, @@ -82981,7 +83019,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) #if defined(WC_RSA_PSS) && defined(WOLF_CRYPTO_CB_RSA_PAD) && \ !defined(NO_RSA) && !defined(WC_NO_RNG) && defined(WOLFSSL_KEY_GEN) && \ - !defined(NO_SHA256) + !defined(NO_SHA256) && !defined(HAVE_FIPS) if (ret == 0) { WC_RNG rsaRng; int rsaRngInit = 0; diff --git a/wolfssl/openssl/hmac.h b/wolfssl/openssl/hmac.h index 6407b733e3..ddee0995d7 100644 --- a/wolfssl/openssl/hmac.h +++ b/wolfssl/openssl/hmac.h @@ -50,7 +50,9 @@ extern "C" { #endif -#define HMAC_MAX_MD_CBLOCK WC_MAX_BLOCK_SIZE +#ifndef OPENSSL_COEXIST + #define HMAC_MAX_MD_CBLOCK WC_MAX_BLOCK_SIZE +#endif WOLFSSL_API unsigned char* wolfSSL_HMAC(const WOLFSSL_EVP_MD* evp_md, const void* key, int key_len, diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index b45582e9f8..a0862cdd34 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -348,9 +348,11 @@ enum wolfCrypt_ErrorCodes { FIPS_BAD_VALUE_E = -1027, /* Supplied value was rejected by FIPS policy */ FIPS_UNAPPROVED_E = -1028, /* Requested operation succeeded, but supplied */ /* parameters are unapproved for FIPS */ + NO_DEFAULT_FOUND_E = -1029, /* No default object registered for request + * type */ - WC_SPAN2_LAST_E = -1028, /* Update to indicate last used error code */ - WC_LAST_E = -1028, /* the last code used either here or in + WC_SPAN2_LAST_E = -1029, /* Update to indicate last used error code */ + WC_LAST_E = -1029, /* the last code used either here or in * error-ssl.h */ WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */ @@ -380,6 +382,7 @@ WOLFSSL_ABI WOLFSSL_API const char* wc_GetErrorString(int error); #if defined(WOLFSSL_DEBUG_TRACE_ERROR_CODES) && \ (defined(BUILDING_WOLFSSL) || \ defined(WOLFSSL_DEBUG_TRACE_ERROR_CODES_ALWAYS)) + #include #define WC_NO_ERR_TRACE(label) (CONST_NUM_ERR_ ## label) #ifndef WOLFSSL_DEBUG_BACKTRACE_RENDER_CLAUSE #ifdef WOLFSSL_DEBUG_BACKTRACE_ERROR_CODES @@ -393,9 +396,9 @@ WOLFSSL_ABI WOLFSSL_API const char* wc_GetErrorString(int error); #define WC_ERR_TRACE(label) __extension__ \ ({ if (wc_debug_trace_error_codes_enabled()) { \ (void)WOLFSSL_DEBUG_PRINTF_FN( \ - WOLFSSL_DEBUG_PRINTF_FIRST_ARGS \ - "ERR TRACE: %s L %d %s (%d)\n", \ - __FILE__, __LINE__, #label, label); \ + WOLFSSL_DEBUG_PRINTF_FIRST_ARGS \ + "ERR TRACE: %s %s() L %d %s (%d)\n", \ + __FILE__, __func__, __LINE__, #label, label); \ (void)WOLFSSL_DEBUG_BACKTRACE_RENDER_CLAUSE; } \ (label); \ }) diff --git a/wolfssl/wolfcrypt/memory.h b/wolfssl/wolfcrypt/memory.h index 03a23ba2d2..91200566ac 100644 --- a/wolfssl/wolfcrypt/memory.h +++ b/wolfssl/wolfcrypt/memory.h @@ -361,9 +361,17 @@ WOLFSSL_LOCAL WC_DEBUG_CIPHERLIFECYCLE_WUR int wc_debug_CipherLifecycleFree #endif #if (defined(DEBUG_VECTOR_REGISTER_ACCESS) || \ - defined(DEBUG_VECTOR_REGISTER_ACCESS_FUZZING)) && \ + defined(DEBUG_VECTOR_REGISTER_ACCESS_FUZZING) || \ + defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON) || \ + defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_OFF)) && \ !defined(WC_HAVE_VECTOR_SPEEDUPS) - #error DEBUG_VECTOR_REGISTER_ACCESS requires WC_HAVE_VECTOR_SPEEDUPS. + #error DEBUG_VECTOR_REGISTER_ACCESS* requires WC_HAVE_VECTOR_SPEEDUPS. +#endif + +#if defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_ON) + \ + defined(DEBUG_VECTOR_REGISTER_ACCESS_ALWAYS_OFF) + \ + defined(DEBUG_VECTOR_REGISTER_ACCESS_FUZZING) > 1 + #error Conflicting settings for DEBUG_VECTOR_REGISTER_ACCESS_* #endif #ifdef DEBUG_VECTOR_REGISTER_ACCESS_FUZZING diff --git a/wolfssl/wolfcrypt/rng_bank.h b/wolfssl/wolfcrypt/rng_bank.h index f1e102ef0f..4045d86e47 100644 --- a/wolfssl/wolfcrypt/rng_bank.h +++ b/wolfssl/wolfcrypt/rng_bank.h @@ -57,12 +57,15 @@ typedef int (*wc_affinity_lock_fn_t)(void *arg); typedef int (*wc_affinity_get_id_fn_t)(void *arg, int *id); typedef int (*wc_affinity_unlock_fn_t)(void *arg); +struct wc_rng_bank; + struct wc_rng_bank_inst { #ifdef WOLFSSL_NO_ATOMICS int lock; #else wolfSSL_Atomic_Int lock; #endif + struct wc_rng_bank *bank; WC_RNG rng; }; @@ -149,6 +152,9 @@ WOLFSSL_API int wc_rng_bank_checkin( struct wc_rng_bank *bank, struct wc_rng_bank_inst **rng_inst); +WOLFSSL_API int wc_rng_bank_inst_checkin( + struct wc_rng_bank_inst **rng_inst); + WOLFSSL_API int wc_rng_bank_inst_reinit( struct wc_rng_bank *bank, struct wc_rng_bank_inst *rng_inst,