diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras
index 50d4cb7c435..b23b8406791 100644
--- a/.wolfssl_known_macro_extras
+++ b/.wolfssl_known_macro_extras
@@ -728,6 +728,7 @@ WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A
WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
WOLFSSL_DISABLE_EARLY_SANITY_CHECKS
+WOLFSSL_DRBG_SHA256
WOLFSSL_DTLS_DISALLOW_FUTURE
WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS
WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT
diff --git a/IDE/WIN10/wolfssl-fips.vcxproj b/IDE/WIN10/wolfssl-fips.vcxproj
index eac076eb3ae..31149cfec0d 100644
--- a/IDE/WIN10/wolfssl-fips.vcxproj
+++ b/IDE/WIN10/wolfssl-fips.vcxproj
@@ -318,6 +318,13 @@
+
+
+
+
+
+
+
diff --git a/configure.ac b/configure.ac
index 938ceddb4dd..91580eff0c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -624,21 +624,31 @@ AS_CASE([$ENABLED_FIPS],
DEF_SP_MATH="yes"
DEF_FAST_MATH="no"
],
+ [v7],[
+ FIPS_VERSION="v7"
+ HAVE_FIPS_VERSION=7
+ HAVE_FIPS_VERSION_MAJOR=7
+ HAVE_FIPS_VERSION_MINOR=0
+ HAVE_FIPS_VERSION_PATCH=0
+ ENABLED_FIPS="yes"
+ DEF_SP_MATH="yes"
+ DEF_FAST_MATH="no"
+ ],
# Should always remain one ahead of the latest so as not to be confused with
# the latest
- [ready|v6-ready],[
+ [ready|v7-ready],[
FIPS_VERSION="ready"
- HAVE_FIPS_VERSION=7
- HAVE_FIPS_VERSION_MAJOR=7
+ HAVE_FIPS_VERSION=8
+ HAVE_FIPS_VERSION_MAJOR=8
HAVE_FIPS_VERSION_MINOR=0
HAVE_FIPS_VERSION_PATCH=0
ENABLED_FIPS="yes"
DEF_SP_MATH="yes"
DEF_FAST_MATH="no"
],
- [dev|v6-dev],[
+ [dev|v7-dev],[
FIPS_VERSION="dev"
- HAVE_FIPS_VERSION_MAJOR=7
+ HAVE_FIPS_VERSION_MAJOR=8
HAVE_FIPS_VERSION_MINOR=0
HAVE_FIPS_VERSION_PATCH=0
ENABLED_FIPS="yes"
@@ -646,14 +656,14 @@ AS_CASE([$ENABLED_FIPS],
],
[lean-aesgcm|lean-aesgcm-ready|lean-aesgcm-dev],[
FIPS_VERSION="$ENABLED_FIPS"
- HAVE_FIPS_VERSION_MAJOR=7
+ HAVE_FIPS_VERSION_MAJOR=8
HAVE_FIPS_VERSION_MINOR=0
HAVE_FIPS_VERSION_PATCH=0
ENABLED_FIPS="yes"
],
[
AS_IF([test "$ENABLED_FIPS" = "yes"],[ENABLED_FIPS="(unset)"],[ENABLED_FIPS=\"$ENABLED_FIPS\"])
- AC_MSG_ERROR([Invalid value for --enable-fips $ENABLED_FIPS (main options: v1, v2, v5, v6, ready, dev, rand, lean-aesgcm, no, disabled)])
+ AC_MSG_ERROR([Invalid value for --enable-fips $ENABLED_FIPS (main options: v1, v2, v5, v6, v7, ready, dev, rand, lean-aesgcm, no, disabled)])
])
if test -z "$HAVE_FIPS_VERSION_MAJOR"
@@ -1795,118 +1805,6 @@ do
esac
done
-if test "$ENABLED_MLKEM" != "no"
-then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_MLKEM"
- # Use liboqs if specified.
- if test "$ENABLED_LIBOQS" = "no"; then
- ENABLED_WC_MLKEM=yes
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_MLKEM"
- AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_MLKEM"
- fi
-
- if test "$ENABLED_ORIGINAL" = "yes"; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_KYBER"
- if test "$ENABLED_MLKEM512" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER512"
- fi
- if test "$ENABLED_MLKEM768" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER768"
- fi
- if test "$ENABLED_MLKEM1024" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER1024"
- fi
- if test "$ENABLED_ML_KEM" = "unset"; then
- ENABLED_ML_KEM=no
- fi
- fi
- if test "$ENABLED_ML_KEM" = "unset"; then
- ENABLED_ML_KEM=yes
- fi
- if test "$ENABLED_ML_KEM" = "yes"; then
- if test "$ENABLED_MLKEM512" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_512"
- fi
- if test "$ENABLED_MLKEM768" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_768"
- fi
- if test "$ENABLED_MLKEM1024" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_1024"
- fi
- else
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM"
- fi
- if test "$ENABLED_MLKEM_MAKE_KEY" = "no"; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_MAKE_KEY"
- fi
- if test "$ENABLED_MLKEM_ENCAPSULATE" = "no"; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_ENCAPSULATE"
- fi
- if test "$ENABLED_MLKEM_DECAPSULATE" = "no"; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_DECAPSULATE"
- fi
-
- if test "$ENABLED_WC_MLKEM" = "yes"
- then
- test "$enable_sha3" = "" && enable_sha3=yes
- test "$enable_shake128" = "" && enable_shake128=yes
- test "$enable_shake256" = "" && enable_shake256=yes
- fi
-fi
-
-AC_ARG_ENABLE([tls-mlkem-standalone],
- [AS_HELP_STRING([--enable-tls-mlkem-standalone],[Enable ML-KEM as standalone TLS key exchange (non-hybrid) (default: disabled)])],
- [ ENABLED_MLKEM_STANDALONE=$enableval ],
- [ ENABLED_MLKEM_STANDALONE=no ]
- )
-
-AS_IF([ test "$ENABLED_MLKEM_STANDALONE" = "yes" && test "$ENABLED_ML_KEM" = "no" ],[AC_MSG_ERROR([ML-KEM as standalone TLS key exchange (non-hybrid) requires ML-KEM.])])
-if test "$ENABLED_MLKEM_STANDALONE" != "yes"
-then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE"
-fi
-
-AC_ARG_ENABLE([pqc-hybrids],
- [AS_HELP_STRING([--enable-pqc-hybrids],[Enable PQ/T hybrid combinations (default: enabled)])],
- [ ENABLED_PQC_HYBRIDS=$enableval ],
- [ ENABLED_PQC_HYBRIDS=yes ]
- )
-
-if test "$ENABLED_PQC_HYBRIDS" = "yes"
-then
- if test "$ENABLED_ML_KEM" = "no" || test "$ENABLED_MLKEM" = "no"
- then
- ENABLED_PQC_HYBRIDS=no
- elif test "$ENABLED_MLKEM768" = "" && test "$ENABLED_MLKEM1024" = ""; then
- AC_MSG_NOTICE([PQC hybrid combinations require either ML-KEM 768 or ML-KEM 1024, but both disabled.])
- ENABLED_PQC_HYBRIDS=no
- else
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PQC_HYBRIDS"
- fi
-fi
-
-if test "$ENABLED_ML_KEM" != "no" && test "$ENABLED_MLKEM" != "no"
-then
- if test "$ENABLED_PQC_HYBRIDS" = "no" && test "$ENABLED_MLKEM_STANDALONE" = "no" && test "$ENABLED_CRYPTONLY" = "no"
- then
- AC_MSG_ERROR([Both hybrid PQ/T and standalone ML-KEM are disabled, so no PQC hybrid combinations will be available.])
- fi
-fi
-
-# Extra PQ/T Hybrid combinations
-AC_ARG_ENABLE([extra-pqc-hybrids],
- [AS_HELP_STRING([--enable-extra-pqc-hybrids],[Enable extra PQ/T hybrid combinations (default: disabled)])],
- [ ENABLED_EXTRA_PQC_HYBRIDS=$enableval ],
- [ ENABLED_EXTRA_PQC_HYBRIDS=no ]
- )
-
-if test "$ENABLED_EXTRA_PQC_HYBRIDS" = "yes"
-then
- AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires --enable-experimental.]) ])
- AS_IF([ test "$ENABLED_ML_KEM" = "no" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires ML-KEM.]) ])
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_PQC_HYBRIDS"
-fi
-
# Dilithium
# - SHA3, Shake128 and Shake256
AC_ARG_ENABLE([mldsa],
@@ -1978,39 +1876,6 @@ do
esac
done
-if test "$ENABLED_DILITHIUM" != "no"
-then
- AM_CFLAGS="$AM_CFLAGS -DHAVE_DILITHIUM"
-
- if test "$ENABLED_MLDSA44" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_44"
- fi
- if test "$ENABLED_MLDSA65" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_65"
- fi
- if test "$ENABLED_MLDSA87" = ""; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_87"
- fi
- if test "$ENABLED_DILITHIUM_MAKE_KEY" = "no"; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_MAKE_KEY"
- fi
- if test "$ENABLED_DILITHIUM_SIGN" = "no"; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_SIGN"
- fi
- if test "$ENABLED_DILITHIUM_VERIFY" = "no"; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_VERIFY"
- fi
-
- if test "$ENABLED_LIBOQS" = "no"; then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_DILITHIUM"
- AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_DILITHIUM"
- test "$enable_sha3" = "" && enable_sha3=yes
- test "$enable_shake128" = "" && enable_shake128=yes
- test "$enable_shake256" = "" && enable_shake256=yes
- fi
- ENABLED_CERTS=yes
-fi
-
# XMSS
ENABLED_WC_XMSS=no
AC_ARG_ENABLE([xmss],
@@ -2090,19 +1955,6 @@ AC_ARG_WITH([libxmss],
[XMSS_ROOT=""]
)
-if test "$ENABLED_XMSS" != "no"
-then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_XMSS"
-
- # Use hash-sigs XMSS lib if enabled.
- if test "$ENABLED_LIBXMSS" = "yes"; then
- ENABLED_WC_XMSS=no
- else
- ENABLED_WC_XMSS=yes
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_XMSS"
- fi
-fi
-
# LMS
ENABLED_WC_LMS=no
AC_ARG_ENABLE([lms],
@@ -2130,6 +1982,9 @@ do
sha256-192)
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHA256_192"
;;
+ shake256)
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHAKE256"
+ ;;
*)
AC_MSG_ERROR([Invalid choice for LMS []: $ENABLED_LMS.])
break;;
@@ -2204,19 +2059,6 @@ AC_ARG_WITH([liblms],
]
)
-if test "$ENABLED_LMS" != "no"
-then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS"
-
- # Use hash-sigs LMS lib if enabled.
- if test "$ENABLED_LIBLMS" = "yes"; then
- ENABLED_WC_LMS=no
- else
- ENABLED_WC_LMS=yes
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_LMS"
- fi
-fi
-
# SLH-DSA
ENABLED_SLHDSA=yes
AC_ARG_ENABLE([slhdsa],
@@ -2271,59 +2113,50 @@ do
no-f)
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_FAST"
;;
+ sha2)
+ SLHDSA_SHA2=yes
+ SLHDSA_PARAM_SHA2_128S=yes
+ SLHDSA_PARAM_SHA2_128F=yes
+ SLHDSA_PARAM_SHA2_192S=yes
+ SLHDSA_PARAM_SHA2_192F=yes
+ SLHDSA_PARAM_SHA2_256S=yes
+ SLHDSA_PARAM_SHA2_256F=yes
+ ;;
+ sha2-128s)
+ SLHDSA_SHA2=yes
+ SLHDSA_PARAM_SHA2_128S=yes
+ ;;
+ sha2-128f)
+ SLHDSA_SHA2=yes
+ SLHDSA_PARAM_SHA2_128F=yes
+ ;;
+ sha2-192s)
+ SLHDSA_SHA2=yes
+ SLHDSA_PARAM_SHA2_192S=yes
+ ;;
+ sha2-192f)
+ SLHDSA_SHA2=yes
+ SLHDSA_PARAM_SHA2_192F=yes
+ ;;
+ sha2-256s)
+ SLHDSA_SHA2=yes
+ SLHDSA_PARAM_SHA2_256S=yes
+ ;;
+ sha2-256f)
+ SLHDSA_SHA2=yes
+ SLHDSA_PARAM_SHA2_256F=yes
+ ;;
+ no-sha2-s)
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL"
+ ;;
+ no-sha2-f)
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST"
+ ;;
*)
AC_MSG_ERROR([Invalid choice for SLH-DSA []: $ENABLED_SLHDSA.])
break;;
esac
done
-
-if test "$ENABLED_SLHDSA" != "no"
-then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_SLHDSA"
- AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_SLHDSA"
-
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_SLHDSA"
-
- if test "$SLHDSA_PARAM_128S" = "yes"
- then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128S"
- else
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128S"
- fi
- if test "$SLHDSA_PARAM_128F" = "yes"
- then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128F"
- else
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128F"
- fi
- if test "$SLHDSA_PARAM_192S" = "yes"
- then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192S"
- else
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192S"
- fi
- if test "$SLHDSA_PARAM_192F" = "yes"
- then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192F"
- else
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192F"
- fi
- if test "$SLHDSA_PARAM_256S" = "yes"
- then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256S"
- else
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256S"
- fi
- if test "$SLHDSA_PARAM_256F" = "yes"
- then
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256F"
- else
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256F"
- fi
-
- enable_shake256=yes
-fi
-
# SINGLE THREADED
AC_ARG_ENABLE([singlethreaded],
[AS_HELP_STRING([--enable-singlethreaded],[Enable wolfSSL single threaded (default: disabled)])],
@@ -4711,7 +4544,7 @@ if test "$ENABLED_MLKEM" != "no"
then
if test "$ENABLED_SHAKE128" = "no"
then
- AC_MSG_WARN([MLKEM enabled (not explicitly disabled); overriding --disable-shake128 to enable SHAKE128])
+ AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-shake128 to enable SHAKE128])
ENABLED_SHAKE128=yes
enable_shake128=yes
fi
@@ -4729,7 +4562,7 @@ if test "$ENABLED_MLKEM" != "no"
then
if test "$ENABLED_SHAKE256" = "no"
then
- AC_MSG_WARN([MLKEM enabled (not explicitly disabled); overriding --disable-shake256 to enable SHAKE256])
+ AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-shake256 to enable SHAKE256])
ENABLED_SHAKE256=yes
enable_shake256=yes
fi
@@ -4760,6 +4593,25 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512"
fi
+# SHA-256 Hash DRBG (SP 800-90A) -- sub-option of hashdrbg
+AC_ARG_ENABLE([sha256-drbg],
+ [AS_HELP_STRING([--enable-sha256-drbg],[Enable SHA-256 Hash DRBG (default: enabled)])],
+ [ ENABLED_SHA256_DRBG=$enableval ],
+ [ ENABLED_SHA256_DRBG=yes ]
+ )
+
+# SHA-512 Hash DRBG (SP 800-90A) -- sub-option of hashdrbg
+AC_ARG_ENABLE([sha512-drbg],
+ [AS_HELP_STRING([--enable-sha512-drbg],[Enable SHA-512 Hash DRBG (default: enabled)])],
+ [ ENABLED_SHA512_DRBG=$enableval ],
+ [ ENABLED_SHA512_DRBG=yes ]
+ )
+
+# SHA-512 DRBG requires SHA-512
+if test "$ENABLED_SHA512" != "yes"
+then
+ ENABLED_SHA512_DRBG=no
+fi
# SHA384
AC_ARG_ENABLE([sha384],
@@ -6257,11 +6109,11 @@ AC_ARG_ENABLE([aeskeywrap],
# FIPS feature and macro setup
AS_CASE([$FIPS_VERSION],
- [v6|ready|dev],[ # FIPS 140-3 SRTP-KDF
+ [v7|ready|dev],[ # FIPS 140-3 PQ-FS
AS_IF([test "$FIPS_VERSION" = "dev"],
[AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_DEV"])
- AS_IF([test "$FIPS_VERSION" = "ready"],
+ AS_IF([test "$FIPS_VERSION" = "ready" || test "$FIPS_VERSION" = "v7"],
[AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_READY"])
AM_CFLAGS="$AM_CFLAGS \
@@ -6376,8 +6228,8 @@ AS_CASE([$FIPS_VERSION],
(test "$FIPS_VERSION" != "dev" || test "$enable_sha512" != "no")],
[ENABLED_SHA512="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512 -DWOLFSSL_SHA384"])
- # SHA512-224 and SHA512-256 are SHA-2 algorithms not in our FIPS algorithm list
- AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NOSHA512_224 -DWOLFSSL_NOSHA512_256"
+ # SHA512-224 and SHA512-256 enabled for FIPS v7+ (needed for ML-DSA
+ # HashML-DSA ACVP test vectors with SHA2-512/224 and SHA2-512/256)
# Shake128 because we're testing SHAKE256
AS_IF([test "x$ENABLED_SHAKE128" = "xno" &&
@@ -6438,6 +6290,64 @@ AS_CASE([$FIPS_VERSION],
(test "$FIPS_VERSION" != "dev" || test "$enable_aeskeywrap" != "no")],
[ENABLED_AESKEYWRAP="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP"])
+# Post-Quantum section
+ AS_IF([test "$ENABLED_MLKEM" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_mlkem" != "no")],
+ [ENABLED_MLKEM="yes"
+ ENABLED_MLKEM512="yes"
+ ENABLED_MLKEM768="yes"
+ ENABLED_MLKEM1024="yes"
+ ENABLED_MLKEM_MAKE_KEY="yes"
+ ENABLED_MLKEM_ENCAPSULATE="yes"
+ ENABLED_MLKEM_DECAPSULATE="yes"])
+
+ AS_IF([test "$ENABLED_DILITHIUM" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_dilithium" != "no")],
+ [ENABLED_DILITHIUM="yes"
+ ENABLED_MLDSA44="yes"
+ ENABLED_MLDSA65="yes"
+ ENABLED_MLDSA87="yes"
+ ENABLED_DILITHIUM_MAKE_KEY="yes"
+ ENABLED_DILITHIUM_SIGN="yes"
+ ENABLED_DILITHIUM_VERIFY="yes"])
+
+ AS_IF([test "$ENABLED_XMSS" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_xmss" != "no")],
+ [ENABLED_XMSS="yes"])
+
+ AS_IF([test "$ENABLED_LMS" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_lms" != "no")],
+ [ENABLED_LMS="yes"])
+ # LMS: enable SHA-256/192 and SHAKE256 parameter sets for FIPS v7
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHA256_192 -DWOLFSSL_LMS_SHAKE256"
+
+ AS_IF([test "$ENABLED_SLHDSA" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_slhdsa" != "no")],
+ [ENABLED_SLHDSA="yes"
+ SLHDSA_PARAM_128S="yes"
+ SLHDSA_PARAM_128F="yes"
+ SLHDSA_PARAM_192S="yes"
+ SLHDSA_PARAM_192F="yes"
+ SLHDSA_PARAM_256S="yes"
+ SLHDSA_PARAM_256F="yes"
+ SLHDSA_SHA2="yes"
+ SLHDSA_PARAM_SHA2_128S="yes"
+ SLHDSA_PARAM_SHA2_128F="yes"
+ SLHDSA_PARAM_SHA2_192S="yes"
+ SLHDSA_PARAM_SHA2_192F="yes"
+ SLHDSA_PARAM_SHA2_256S="yes"
+ SLHDSA_PARAM_SHA2_256F="yes"])
+
+# SHA-256 DRBG -- cannot be disabled at build time in FIPS mode
+ AS_IF([test "$enable_sha256_drbg" = "no"],
+ [AC_MSG_WARN([Can not disable SHA256-DRBG at build time in FIPS mode, disable at run-time with wc_Sha256Drbg_Disable() or wc_Sha256Drbg_Disable_fips()])])
+ ENABLED_SHA256_DRBG="yes"
+
+# SHA-512 DRBG -- cannot be disabled at build time in FIPS mode
+ AS_IF([test "$enable_sha512_drbg" = "no"],
+ [AC_MSG_WARN([Can not disable SHA512-DRBG at build time in FIPS mode, disable it at run-time with wc_Sha512Drbg_Disable() or wc_Sha512Drbg_Disable_fips()])])
+ ENABLED_SHA512_DRBG="yes"
+
# Old TLS requires MD5 + HMAC, which is not allowed under FIPS 140-3
AS_IF([test "$ENABLED_OLD_TLS" != "no"],
[AC_MSG_WARN([Forcing off oldtls for FIPS ${FIPS_VERSION}.])
@@ -6445,12 +6355,7 @@ AS_CASE([$FIPS_VERSION],
],
- [lean-aesgcm|lean-aesgcm-ready|lean-aesgcm-dev],[
-
- AS_IF([test "$FIPS_VERSION" = "lean-aesgcm-dev"],
- [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_DEV"])
- AS_IF([test "$FIPS_VERSION" = "lean-aesgcm-ready"],
- [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_READY"])
+ [v6],[ # FIPS 140-3 SRTP-KDF (frozen)
AM_CFLAGS="$AM_CFLAGS \
-DHAVE_FIPS \
@@ -6458,7 +6363,194 @@ AS_CASE([$FIPS_VERSION],
-DHAVE_FIPS_VERSION_MAJOR=$HAVE_FIPS_VERSION_MAJOR \
-DHAVE_FIPS_VERSION_MINOR=$HAVE_FIPS_VERSION_MINOR \
-DHAVE_FIPS_VERSION_PATCH=$HAVE_FIPS_VERSION_PATCH \
- -DNO_BIG_INT \
+ -DHAVE_ECC_CDH \
+ -DWC_RSA_NO_PADDING \
+ -DECC_USER_CURVES \
+ -DHAVE_ECC384 \
+ -DHAVE_ECC521 \
+ -DWOLFSSL_VALIDATE_FFC_IMPORT \
+ -DHAVE_FFDHE_Q \
+ -DHAVE_FFDHE_3072 \
+ -DHAVE_FFDHE_4096 \
+ -DHAVE_FFDHE_6144 \
+ -DHAVE_FFDHE_8192"
+
+ # KCAPI API does not support custom k for sign, don't force enable ECC key sizes and don't use seed callback
+ AS_IF([test "x$ENABLED_KCAPI_ECC" = "xno"],
+ [AM_CFLAGS="$AM_CFLAGS \
+ -DWC_RNG_SEED_CB \
+ -DWOLFSSL_ECDSA_SET_K \
+ -DWOLFSSL_VALIDATE_ECC_IMPORT \
+ -DWOLFSSL_VALIDATE_ECC_KEYGEN \
+ -DHAVE_ECC192 \
+ -DHAVE_ECC224 \
+ -DHAVE_ECC256"])
+
+ DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=8192
+# optimizations section
+
+# protocol section
+ AS_IF([test "$ENABLED_WOLFSSH" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_ssh" != "no")],
+ [enable_ssh="yes"])
+
+ AS_IF([test "$ENABLED_HKDF" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_hkdf" != "no")],
+ [ENABLED_HKDF="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_HKDF"])
+
+ AS_IF([test "x$ENABLED_PWDBASED" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_pwdbased" != "no")],
+ [ENABLED_PWDBASED="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_PBKDF2 -DHAVE_AESGCM"])
+
+ AS_IF([test "x$ENABLED_SRTP" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_srtp" != "no")],
+ [ENABLED_SRTP="yes"])
+ AS_IF([test "x$ENABLED_SRTP_KDF" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_srtp_kdf" != "no")],
+ [ENABLED_SRTP_KDF="yes"])
+
+# public key section
+ AS_IF([test "$ENABLED_KEYGEN" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_keygen" != "no")],
+ [ENABLED_KEYGEN="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_KEY_GEN"])
+
+# AS_IF([test "$ENABLED_COMPKEY" != "yes" &&
+# (test "$FIPS_VERSION" != "dev" || test "$enable_compkey" != "yes")],
+# [ENABLED_COMPKEY="yes"])
+
+ AS_IF([test "$ENABLED_RSAPSS" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_rsapss" != "no")],
+ [ENABLED_RSAPSS="yes"; AM_CFLAGS="$AM_CFLAGS -DWC_RSA_PSS"])
+
+ AS_IF([test "$ENABLED_ECC" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_ecc" != "no")],
+ [ENABLED_ECC="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC -DTFM_ECC256"
+ AS_IF([test "$ENABLED_ECC_SHAMIR" = "yes"],
+ [AM_CFLAGS="$AM_CFLAGS -DECC_SHAMIR"])])
+
+ AS_IF([test "$ENABLED_ED25519" = "no" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_ed25519" != "no")],
+ [ENABLED_ED25519="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ED25519 -DHAVE_ED25519_KEY_IMPORT"])
+
+ AS_IF([test "$ENABLED_CURVE25519" != "no" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_curve25519" = "")],
+ [ENABLED_CURVE25519="no"; AM_CFLAGS="$AM_CFLAGS"])
+
+ AS_IF([test "x$ENABLED_ED448" != "xyes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_ed448" != "no")],
+ [ENABLED_ED448="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ED448 -DHAVE_ED448_KEY_IMPORT"])
+
+ AS_IF([test "$ENABLED_CURVE448" != "no" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_curve448" = "")],
+ [ENABLED_CURVE448="no"; AM_CFLAGS="$AM_CFLAGS"])
+
+ AS_IF([test "x$ENABLED_ED25519_STREAM" != "xyes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_ed25519_stream" != "no")],
+ [ENABLED_ED25519_STREAM="yes"])
+ AS_IF([test "x$ENABLED_ED448_STREAM" != "xyes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_ed448_stream" != "no")],
+ [ENABLED_ED448_STREAM="yes"])
+
+ AS_IF([test "x$ENABLED_ECCCUSTCURVES" != "xno" &&
+ test "$FIPS_VERSION" != "dev"],
+ [AC_MSG_WARN([Forcing off ecccustcurves for FIPS ${FIPS_VERSION}.])
+ ENABLED_ECCCUSTCURVES="no"])
+
+# Hashing section
+ AS_IF([test "x$ENABLED_SHA3" != "xyes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_sha3" != "no")],
+ [ENABLED_SHA3="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA3"])
+
+ AS_IF([test "$ENABLED_SHA224" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_sha224" != "no")],
+ [ENABLED_SHA224="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA224"])
+
+ AS_IF([test "$ENABLED_SHA512" = "no" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_sha512" != "no")],
+ [ENABLED_SHA512="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512 -DWOLFSSL_SHA384"])
+
+ # SHA512-224 and SHA512-256 are needed for HashML-DSA (FIPS 204)
+
+ # Shake128 because we're testing SHAKE256
+ AS_IF([test "x$ENABLED_SHAKE128" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_shake128" != "no")],
+ [ENABLED_SHAKE128="yes"])
+
+ # Shake256 mandated for ED448
+ AS_IF([test "x$ENABLED_SHAKE256" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_shake256" != "no")],
+ [ENABLED_SHAKE256="yes"])
+
+# Aes section
+ AS_IF([test "$ENABLED_AESCCM" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aesccm" != "no")],
+ [ENABLED_AESCCM="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AESCCM"])
+
+ AS_IF([test "$ENABLED_AESCTR" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aesctr" != "no")],
+ [ENABLED_AESCTR="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_COUNTER"])
+
+ AS_IF([test "$ENABLED_CMAC" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_cmac" != "no")],
+ [ENABLED_CMAC="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CMAC"])
+
+ AS_IF([test "$ENABLED_AESGCM" = "no" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aesgcm" != "no")],
+ [ENABLED_AESGCM="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AESGCM"; AM_CCASFLAGS="$AM_CCASFLAGS -DHAVE_AESGCM"])
+
+ AS_IF([test "$ENABLED_AESGCM_STREAM" != "yes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aesgcm_stream" != "no")],
+ [ENABLED_AESGCM_STREAM="yes"])
+
+ AS_IF([test "x$ENABLED_AESOFB" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aesofb" != "no")],
+ [ENABLED_AESOFB="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_OFB"])
+
+ AS_IF([test "x$ENABLED_AESCFB" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aescfb" != "no")],
+ [ENABLED_AESCFB="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_CFB"])
+
+ AS_IF([test "x$ENABLED_AESXTS" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aesxts" != "no")],
+ [ENABLED_AESXTS="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS"])
+ AS_IF([test "x$ENABLED_AESXTS" = "xyes" && test "x$ENABLED_AESNI" = "xyes"],
+ [AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_AES_XTS"])
+
+ AS_IF([test "x$ENABLED_AESXTS_STREAM" = "xno" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aesxts_stream" != "no")],
+ [ENABLED_AESXTS_STREAM="yes"])
+
+ AS_IF([(test "$ENABLED_AESCCM" != "no" && test "$HAVE_AESCCM_PORT" != "yes") ||
+ (test "$ENABLED_AESCTR" != "no" && test "$HAVE_AESCTR_PORT" != "yes") ||
+ (test "$ENABLED_AESGCM" != "no" && test "$HAVE_AESGCM_PORT" != "yes") ||
+ (test "$ENABLED_AESOFB" != "no" && test "$HAVE_AESOFB_PORT" != "yes")],
+ [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_DIRECT -DHAVE_AES_ECB"])
+
+ AS_IF([test "x$ENABLED_AESKEYWRAP" != "xyes" &&
+ (test "$FIPS_VERSION" != "dev" || test "$enable_aeskeywrap" != "no")],
+ [ENABLED_AESKEYWRAP="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP"])
+
+# Old TLS requires MD5 + HMAC, which is not allowed under FIPS 140-3
+ AS_IF([test "$ENABLED_OLD_TLS" != "no"],
+ [AC_MSG_WARN([Forcing off oldtls for FIPS ${FIPS_VERSION}.])
+ ENABLED_OLD_TLS="no"; AM_CFLAGS="$AM_CFLAGS -DNO_OLD_TLS"])
+
+ ],
+
+ [lean-aesgcm|lean-aesgcm-ready|lean-aesgcm-dev],[
+
+ AS_IF([test "$FIPS_VERSION" = "lean-aesgcm-dev"],
+ [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_DEV"])
+ AS_IF([test "$FIPS_VERSION" = "lean-aesgcm-ready"],
+ [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_READY"])
+
+ AM_CFLAGS="$AM_CFLAGS \
+ -DHAVE_FIPS \
+ -DHAVE_FIPS_VERSION=$HAVE_FIPS_VERSION \
+ -DHAVE_FIPS_VERSION_MAJOR=$HAVE_FIPS_VERSION_MAJOR \
+ -DHAVE_FIPS_VERSION_MINOR=$HAVE_FIPS_VERSION_MINOR \
+ -DHAVE_FIPS_VERSION_PATCH=$HAVE_FIPS_VERSION_PATCH \
+ -DNO_BIG_INT \
-DWC_RNG_SEED_CB \
-DNO_PBKDF2"
@@ -6922,6 +7014,11 @@ AS_CASE([$SELFTEST_VERSION],
AM_CFLAGS="$AM_CFLAGS -DHAVE_SELFTEST -DHAVE_PUBLIC_FFDHE"
])
+# Selftest uses its own random.c which doesn't support SHA-512 DRBG
+# or runtime DRBG disable/enable APIs
+AS_IF([test "x$ENABLED_SELFTEST" = "xyes"],
+ [ENABLED_SHA512_DRBG=no])
+
AS_IF([test "x$ENABLED_AESXTS" = "xyes"],
[AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS -DWOLFSSL_AES_DIRECT"])
AS_IF([test "x$ENABLED_AESXTS" = "xyes" && test "x$ENABLED_INTELASM" = "xyes"],
@@ -7027,6 +7124,21 @@ then
AM_CFLAGS="$AM_CFLAGS -DWC_SRTP_KDF -DHAVE_AES_ECB -DWOLFSSL_AES_DIRECT"
fi
+# ML-KEM and Dilithium require SHA-3 and SHAKE -- force them on before flag
+# processing so that the correct -D flags are emitted.
+if test "$ENABLED_MLKEM" != "no" && test "$ENABLED_LIBOQS" = "no"
+then
+ ENABLED_SHA3=yes
+ ENABLED_SHAKE128=yes
+ ENABLED_SHAKE256=yes
+fi
+if test "$ENABLED_DILITHIUM" != "no" && test "$ENABLED_LIBOQS" = "no"
+then
+ ENABLED_SHA3=yes
+ ENABLED_SHAKE128=yes
+ ENABLED_SHAKE256=yes
+fi
+
# Set SHA-3 flags
if test "$ENABLED_SHA3" != "no"
then
@@ -7065,6 +7177,301 @@ else
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_SHAKE256"
fi
+# MLKEM CFLAG processing (after FIPS section for sandwich pattern)
+if test "$ENABLED_MLKEM" != "no"
+then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_MLKEM"
+ # Use liboqs if specified.
+ if test "$ENABLED_LIBOQS" = "no"; then
+ ENABLED_WC_MLKEM=yes
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_MLKEM"
+ AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_MLKEM"
+ fi
+
+ if test "$ENABLED_ORIGINAL" = "yes"; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_KYBER"
+ if test "$ENABLED_MLKEM512" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER512"
+ fi
+ if test "$ENABLED_MLKEM768" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER768"
+ fi
+ if test "$ENABLED_MLKEM1024" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER1024"
+ fi
+ if test "$ENABLED_ML_KEM" = "unset"; then
+ ENABLED_ML_KEM=no
+ fi
+ fi
+ if test "$ENABLED_ML_KEM" = "unset"; then
+ ENABLED_ML_KEM=yes
+ fi
+ if test "$ENABLED_ML_KEM" = "yes"; then
+ if test "$ENABLED_MLKEM512" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_512"
+ fi
+ if test "$ENABLED_MLKEM768" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_768"
+ fi
+ if test "$ENABLED_MLKEM1024" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_1024"
+ fi
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM"
+ fi
+ if test "$ENABLED_MLKEM_MAKE_KEY" = "no"; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_MAKE_KEY"
+ fi
+ if test "$ENABLED_MLKEM_ENCAPSULATE" = "no"; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_ENCAPSULATE"
+ fi
+ if test "$ENABLED_MLKEM_DECAPSULATE" = "no"; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_DECAPSULATE"
+ fi
+
+ if test "$ENABLED_WC_MLKEM" = "yes"
+ then
+ test "$enable_sha3" = "" && enable_sha3=yes
+ test "$enable_shake128" = "" && enable_shake128=yes
+ test "$enable_shake256" = "" && enable_shake256=yes
+ fi
+fi
+
+AC_ARG_ENABLE([tls-mlkem-standalone],
+ [AS_HELP_STRING([--enable-tls-mlkem-standalone],[Enable ML-KEM as standalone TLS key exchange (non-hybrid) (default: disabled)])],
+ [ ENABLED_MLKEM_STANDALONE=$enableval ],
+ [ ENABLED_MLKEM_STANDALONE=no ]
+ )
+
+AS_IF([ test "$ENABLED_MLKEM_STANDALONE" = "yes" && test "$ENABLED_ML_KEM" = "no" ],[AC_MSG_ERROR([ML-KEM as standalone TLS key exchange (non-hybrid) requires ML-KEM.])])
+if test "$ENABLED_MLKEM_STANDALONE" != "yes"
+then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE"
+fi
+
+AC_ARG_ENABLE([pqc-hybrids],
+ [AS_HELP_STRING([--enable-pqc-hybrids],[Enable PQ/T hybrid combinations (default: enabled)])],
+ [ ENABLED_PQC_HYBRIDS=$enableval ],
+ [ ENABLED_PQC_HYBRIDS=yes ]
+ )
+
+if test "$ENABLED_PQC_HYBRIDS" = "yes"
+then
+ if test "$ENABLED_ML_KEM" = "no" || test "$ENABLED_MLKEM" = "no"
+ then
+ ENABLED_PQC_HYBRIDS=no
+ elif test "$ENABLED_MLKEM768" = "" && test "$ENABLED_MLKEM1024" = ""; then
+ AC_MSG_NOTICE([PQC hybrid combinations require either ML-KEM 768 or ML-KEM 1024, but both disabled.])
+ ENABLED_PQC_HYBRIDS=no
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PQC_HYBRIDS"
+ fi
+fi
+
+if test "$ENABLED_ML_KEM" != "no" && test "$ENABLED_MLKEM" != "no"
+then
+ if test "$ENABLED_PQC_HYBRIDS" = "no" && test "$ENABLED_MLKEM_STANDALONE" = "no" && test "$ENABLED_CRYPTONLY" = "no"
+ then
+ AC_MSG_ERROR([Both hybrid PQ/T and standalone ML-KEM are disabled, so no PQC hybrid combinations will be available.])
+ fi
+fi
+
+# Extra PQ/T Hybrid combinations
+AC_ARG_ENABLE([extra-pqc-hybrids],
+ [AS_HELP_STRING([--enable-extra-pqc-hybrids],[Enable extra PQ/T hybrid combinations (default: disabled)])],
+ [ ENABLED_EXTRA_PQC_HYBRIDS=$enableval ],
+ [ ENABLED_EXTRA_PQC_HYBRIDS=no ]
+ )
+
+if test "$ENABLED_EXTRA_PQC_HYBRIDS" = "yes"
+then
+ AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires --enable-experimental.]) ])
+ AS_IF([ test "$ENABLED_ML_KEM" = "no" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires ML-KEM.]) ])
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_PQC_HYBRIDS"
+fi
+
+# Dilithium CFLAG processing (after FIPS section for sandwich pattern)
+if test "$ENABLED_DILITHIUM" != "no"
+then
+ AM_CFLAGS="$AM_CFLAGS -DHAVE_DILITHIUM"
+
+ if test "$ENABLED_MLDSA44" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_44"
+ fi
+ if test "$ENABLED_MLDSA65" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_65"
+ fi
+ if test "$ENABLED_MLDSA87" = ""; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_87"
+ fi
+ if test "$ENABLED_DILITHIUM_MAKE_KEY" = "no"; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_MAKE_KEY"
+ fi
+ if test "$ENABLED_DILITHIUM_SIGN" = "no"; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_SIGN"
+ fi
+ if test "$ENABLED_DILITHIUM_VERIFY" = "no"; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_VERIFY"
+ fi
+
+ if test "$ENABLED_LIBOQS" = "no"; then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_DILITHIUM"
+ AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_DILITHIUM"
+ test "$enable_sha3" = "" && enable_sha3=yes
+ test "$enable_shake128" = "" && enable_shake128=yes
+ test "$enable_shake256" = "" && enable_shake256=yes
+ fi
+ ENABLED_CERTS=yes
+fi
+
+# XMSS CFLAG processing (after FIPS section for sandwich pattern)
+if test "$ENABLED_XMSS" != "no"
+then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_XMSS"
+
+ # Use hash-sigs XMSS lib if enabled.
+ if test "$ENABLED_LIBXMSS" = "yes"; then
+ ENABLED_WC_XMSS=no
+ else
+ ENABLED_WC_XMSS=yes
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_XMSS"
+ fi
+fi
+
+# LMS CFLAG processing (after FIPS section for sandwich pattern)
+if test "$ENABLED_LMS" != "no"
+then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS"
+
+ # Use hash-sigs LMS lib if enabled.
+ if test "$ENABLED_LIBLMS" = "yes"; then
+ ENABLED_WC_LMS=no
+ else
+ ENABLED_WC_LMS=yes
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_LMS"
+ fi
+fi
+
+# SLH-DSA CFLAG processing (after FIPS section for sandwich pattern)
+if test "$ENABLED_SLHDSA" != "no"
+then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_SLHDSA"
+ AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_SLHDSA"
+
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_SLHDSA"
+
+ if test "$SLHDSA_PARAM_128S" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128S"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128S"
+ fi
+ if test "$SLHDSA_PARAM_128F" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128F"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128F"
+ fi
+ if test "$SLHDSA_PARAM_192S" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192S"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192S"
+ fi
+ if test "$SLHDSA_PARAM_192F" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192F"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192F"
+ fi
+ if test "$SLHDSA_PARAM_256S" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256S"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256S"
+ fi
+ if test "$SLHDSA_PARAM_256F" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256F"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256F"
+ fi
+
+ # SHA2 parameter set support
+ if test "$SLHDSA_SHA2" = "yes"
+ then
+ # Dependency checks for SHA2 SLH-DSA
+ if test "$ENABLED_SHA256" = "no"
+ then
+ AC_MSG_ERROR([SLH-DSA SHA2 requires SHA-256 (--enable-sha256)])
+ fi
+ if test "$ENABLED_SHA512" = "no"
+ then
+ AC_MSG_ERROR([SLH-DSA SHA2 requires SHA-512 (--enable-sha512)])
+ fi
+ if test "$ENABLED_HMAC" = "no"
+ then
+ AC_MSG_ERROR([SLH-DSA SHA2 requires HMAC (--enable-hmac)])
+ fi
+
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_SHA2"
+
+ if test "$SLHDSA_PARAM_SHA2_128S" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_128S"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_128S"
+ fi
+ if test "$SLHDSA_PARAM_SHA2_128F" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_128F"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_128F"
+ fi
+ if test "$SLHDSA_PARAM_SHA2_192S" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_192S"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_192S"
+ fi
+ if test "$SLHDSA_PARAM_SHA2_192F" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_192F"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_192F"
+ fi
+ if test "$SLHDSA_PARAM_SHA2_256S" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_256S"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_256S"
+ fi
+ if test "$SLHDSA_PARAM_SHA2_256F" = "yes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_256F"
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_256F"
+ fi
+ fi
+
+ # SLH-DSA requires SHAKE-256 (and SHA-3 as its dependency).
+ # This runs after the SHAKE256 flags section, so we must set both the
+ # ENABLED variable and emit the CFLAGS ourselves.
+ if test "$ENABLED_SHAKE256" = "no" || test "$ENABLED_SHAKE256" = ""
+ then
+ ENABLED_SHAKE256=yes
+ if test "$ENABLED_SHA3" = "no"
+ then
+ ENABLED_SHA3=yes
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA3"
+ fi
+ # Remove -DWOLFSSL_NO_SHAKE256 if it was already added and add the
+ # positive define.
+ AM_CFLAGS=$(echo "$AM_CFLAGS" | sed 's/-DWOLFSSL_NO_SHAKE256//g')
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHAKE256"
+ fi
+fi
+
# set POLY1305 default
POLY1305_DEFAULT=yes
@@ -7153,27 +7560,60 @@ then
AM_CFLAGS="$AM_CFLAGS -DHAVE_ASCON"
fi
-# Hash DRBG
+# Hash DRBG (master switch for all Hash DRBGs)
AC_ARG_ENABLE([hashdrbg],
[AS_HELP_STRING([--enable-hashdrbg],[Enable Hash DRBG support (default: enabled)])],
[ ENABLED_HASHDRBG=$enableval ],
[ ENABLED_HASHDRBG=yes ]
)
+# If hashdrbg is explicitly disabled, force both sub-options off
+if test "x$ENABLED_HASHDRBG" = "xno"
+then
+ ENABLED_SHA256_DRBG=no
+ ENABLED_SHA512_DRBG=no
+fi
+
+# If both sub-options are off, treat hashdrbg as off
+if test "x$ENABLED_SHA256_DRBG" != "xyes" && test "x$ENABLED_SHA512_DRBG" != "xyes"
+then
+ ENABLED_HASHDRBG=no
+fi
+
+# FIPS override: Hash DRBG is mandatory
+if test "x$ENABLED_HASHDRBG" != "xyes" && test "x$ENABLED_FIPS" = "xyes" && test "x$ENABLED_KCAPI" = "xno"
+then
+ if test "$enable_hashdrbg" = "no"
+ then
+ AC_MSG_WARN([SHA256-DRBG required in FIPS build])
+ fi
+ ENABLED_HASHDRBG=yes
+ ENABLED_SHA256_DRBG=yes
+fi
+
+# SHA-512 DRBG and runtime DRBG disable/enable APIs are v7+ only
+if test "x$ENABLED_FIPS" = "xyes" && test $HAVE_FIPS_VERSION -lt 7
+then
+ ENABLED_SHA512_DRBG=no
+fi
+
+# Set Hash DRBG compiler flags
if test "x$ENABLED_HASHDRBG" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DHAVE_HASHDRBG"
-else
- # turn on Hash DRBG if FIPS is on (don't force on for KCAPI)
- if test "x$ENABLED_FIPS" = "xyes" && test "x$ENABLED_KCAPI" = "xno"
+ if test "x$ENABLED_SHA256_DRBG" != "xyes"
then
- AM_CFLAGS="$AM_CFLAGS -DHAVE_HASHDRBG"
- ENABLED_HASHDRBG=yes
- else
- AM_CFLAGS="$AM_CFLAGS -DWC_NO_HASHDRBG"
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_SHA256_DRBG"
+ fi
+ if test "x$ENABLED_SHA512_DRBG" = "xyes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DRBG_SHA512"
fi
+else
+ AM_CFLAGS="$AM_CFLAGS -DWC_NO_HASHDRBG"
fi
+
# MemUse Entropy (AKA wolfEntropy)
if test "x$ENABLED_ENTROPY_MEMUSE" != "xno"
then
@@ -10754,6 +11194,11 @@ AS_IF([test "x$ENABLED_MAXSTRENGTH" = "xyes" && \
test "x$ENABLED_LEANPSK" = "xyes"],
[AC_MSG_ERROR([Cannot use Max Strength and Lean PSK at the same time.])])
+AS_IF([test "x$ENABLED_CRYPTONLY" = "xno" && \
+ test "x$ENABLED_PSK" = "xno" && \
+ test "x$ENABLED_ASN" = "xno"],
+ [AC_MSG_ERROR([please enable psk if disabling asn.])])
+
AS_IF([test "x$ENABLED_OCSP" = "xyes" && \
test "x$ENABLED_ASN" = "xno"],
[AC_MSG_ERROR([please enable asn if enabling ocsp.])])
@@ -11506,6 +11951,8 @@ AM_CONDITIONAL([BUILD_FIPS_V5],[test "$HAVE_FIPS_VERSION" = 5])
AM_CONDITIONAL([BUILD_FIPS_V5_PLUS],[test "$HAVE_FIPS_VERSION" -ge 5])
AM_CONDITIONAL([BUILD_FIPS_V6],[test $HAVE_FIPS_VERSION = 6])
AM_CONDITIONAL([BUILD_FIPS_V6_PLUS],[test $HAVE_FIPS_VERSION -ge 6])
+AM_CONDITIONAL([BUILD_FIPS_V7],[test $HAVE_FIPS_VERSION = 7])
+AM_CONDITIONAL([BUILD_FIPS_V7_PLUS],[test $HAVE_FIPS_VERSION -ge 7])
AM_CONDITIONAL([BUILD_SIPHASH],[test "x$ENABLED_SIPHASH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_CMAC],[test "x$ENABLED_CMAC" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_SELFTEST],[test "x$ENABLED_SELFTEST" = "xyes"])
@@ -11994,6 +12441,8 @@ echo " * certgencache: $ENABLED_certgencache"
echo " * CHACHA: $ENABLED_CHACHA"
echo " * XCHACHA: $ENABLED_XCHACHA"
echo " * Hash DRBG: $ENABLED_HASHDRBG"
+echo " * SHA-256 Hash DRBG: $ENABLED_SHA256_DRBG"
+echo " * SHA-512 Hash DRBG: $ENABLED_SHA512_DRBG"
echo " * MmemUse Entropy:"
echo " * (AKA: wolfEntropy): $ENABLED_ENTROPY_MEMUSE"
echo " * PWDBASED: $ENABLED_PWDBASED"
diff --git a/doc/dox_comments/header_files/random.h b/doc/dox_comments/header_files/random.h
index ead9011d468..f6961b99427 100644
--- a/doc/dox_comments/header_files/random.h
+++ b/doc/dox_comments/header_files/random.h
@@ -583,3 +583,241 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len);
\sa wc_Entropy_Get
*/
int wc_Entropy_OnDemandTest(void);
+
+/*!
+ \ingroup Random
+
+ \brief Runs the SHA-512 Hash_DRBG Known Answer Test (KAT) per
+ SP 800-90A. Instantiates a SHA-512 DRBG with seedA, optionally
+ reseeds with seedB, generates output, and compares against known
+ test vectors. Available when WOLFSSL_DRBG_SHA512 is defined.
+
+ \return 0 On success
+ \return BAD_FUNC_ARG If seedA or output is NULL, or if reseed is
+ set and seedB is NULL
+ \return -1 Test failed
+
+ \param reseed Non-zero to test reseeding
+ \param seedA Initial entropy seed
+ \param seedASz Size of seedA in bytes
+ \param seedB Reseed entropy (required if reseed is set)
+ \param seedBSz Size of seedB in bytes
+ \param output Buffer to receive generated output
+ \param outputSz Size of output in bytes
+
+ _Example_
+ \code
+ byte output[WC_SHA512_DIGEST_SIZE * 4];
+ const byte seedA[] = { ... };
+ const byte seedB[] = { ... };
+
+ ret = wc_RNG_HealthTest_SHA512(0, seedA, sizeof(seedA), NULL, 0,
+ output, sizeof(output));
+ if (ret != 0)
+ return -1;
+
+ ret = wc_RNG_HealthTest_SHA512(1, seedA, sizeof(seedA),
+ seedB, sizeof(seedB),
+ output, sizeof(output));
+ if (ret != 0)
+ return -1;
+ \endcode
+
+ \sa wc_RNG_HealthTest
+ \sa wc_RNG_HealthTest_SHA512_ex
+*/
+int wc_RNG_HealthTest_SHA512(int reseed, const byte* seedA, word32 seedASz,
+ const byte* seedB, word32 seedBSz,
+ byte* output, word32 outputSz);
+
+/*!
+ \ingroup Random
+
+ \brief Extended SHA-512 Hash_DRBG health test with nonce,
+ personalization string, and additional input support. Suitable
+ for full ACVP / CAVP test vector validation. Available when
+ WOLFSSL_DRBG_SHA512 is defined.
+
+ \return 0 On success
+ \return BAD_FUNC_ARG If required params are NULL
+ \return -1 Test failed
+
+ \param reseed Non-zero to test reseeding
+ \param nonce Nonce buffer (can be NULL)
+ \param nonceSz Nonce size
+ \param persoString Personalization string (can be NULL)
+ \param persoStringSz Personalization string size
+ \param seedA Initial entropy seed
+ \param seedASz Initial seed size
+ \param seedB Reseed entropy (required if reseed is set)
+ \param seedBSz Reseed size
+ \param additionalA Additional input for first generate (can be NULL)
+ \param additionalASz Additional input A size
+ \param additionalB Additional input for second generate (can be NULL)
+ \param additionalBSz Additional input B size
+ \param output Output buffer
+ \param outputSz Output size
+ \param heap Heap hint (can be NULL)
+ \param devId Device ID (INVALID_DEVID for software)
+
+ _Example_
+ \code
+ byte output[WC_SHA512_DIGEST_SIZE * 4];
+ const byte seedA[] = { ... };
+ const byte nonce[] = { ... };
+
+ int ret = wc_RNG_HealthTest_SHA512_ex(0, nonce, sizeof(nonce),
+ NULL, 0,
+ seedA, sizeof(seedA),
+ NULL, 0,
+ NULL, 0, NULL, 0,
+ output, sizeof(output),
+ NULL, INVALID_DEVID);
+ \endcode
+
+ \sa wc_RNG_HealthTest_SHA512
+ \sa wc_RNG_HealthTest_ex
+*/
+int wc_RNG_HealthTest_SHA512_ex(int reseed, const byte* nonce, word32 nonceSz,
+ const byte* persoString, word32 persoStringSz,
+ const byte* seedA, word32 seedASz,
+ const byte* seedB, word32 seedBSz,
+ const byte* additionalA, word32 additionalASz,
+ const byte* additionalB, word32 additionalBSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId);
+
+/*!
+ \ingroup Random
+
+ \brief Disables the SHA-256 Hash_DRBG at runtime. When disabled,
+ newly initialized WC_RNG instances will not use the SHA-256 DRBG.
+ If the SHA-512 DRBG is enabled (WOLFSSL_DRBG_SHA512), new RNG
+ instances will use SHA-512 instead. Requires HAVE_HASHDRBG.
+
+ \return 0 On success
+
+ _Example_
+ \code
+ wc_Sha256Drbg_Disable();
+ // New WC_RNG instances will now use SHA-512 DRBG if available
+ WC_RNG rng;
+ wc_InitRng(&rng);
+ \endcode
+
+ \sa wc_Sha256Drbg_Enable
+ \sa wc_Sha256Drbg_GetStatus
+ \sa wc_Sha512Drbg_Disable
+*/
+int wc_Sha256Drbg_Disable(void);
+
+/*!
+ \ingroup Random
+
+ \brief Re-enables the SHA-256 Hash_DRBG at runtime after a prior
+ call to wc_Sha256Drbg_Disable(). Requires HAVE_HASHDRBG.
+
+ \return 0 On success
+
+ _Example_
+ \code
+ wc_Sha256Drbg_Disable();
+ // ... use SHA-512 DRBG only ...
+ wc_Sha256Drbg_Enable();
+ // New WC_RNG instances can use SHA-256 DRBG again
+ \endcode
+
+ \sa wc_Sha256Drbg_Disable
+ \sa wc_Sha256Drbg_GetStatus
+*/
+int wc_Sha256Drbg_Enable(void);
+
+/*!
+ \ingroup Random
+
+ \brief Returns the current status of the SHA-256 Hash_DRBG
+ (disabled or enabled). Requires HAVE_HASHDRBG.
+
+ \return 1 SHA-256 DRBG is disabled
+ \return 0 SHA-256 DRBG is enabled
+
+ _Example_
+ \code
+ if (wc_Sha256Drbg_GetStatus()) {
+ printf("SHA-256 DRBG is off\n");
+ }
+ \endcode
+
+ \sa wc_Sha256Drbg_Disable
+ \sa wc_Sha256Drbg_Enable
+*/
+int wc_Sha256Drbg_GetStatus(void);
+
+/*!
+ \ingroup Random
+
+ \brief Disables the SHA-512 Hash_DRBG at runtime. When disabled,
+ newly initialized WC_RNG instances will not use the SHA-512 DRBG.
+ If the SHA-256 DRBG is still enabled, new RNG instances will fall
+ back to SHA-256. Available when WOLFSSL_DRBG_SHA512 is defined.
+ Requires HAVE_HASHDRBG.
+
+ \return 0 On success
+
+ _Example_
+ \code
+ wc_Sha512Drbg_Disable();
+ // New WC_RNG instances will now use SHA-256 DRBG
+ WC_RNG rng;
+ wc_InitRng(&rng);
+ \endcode
+
+ \sa wc_Sha512Drbg_Enable
+ \sa wc_Sha512Drbg_GetStatus
+ \sa wc_Sha256Drbg_Disable
+*/
+int wc_Sha512Drbg_Disable(void);
+
+/*!
+ \ingroup Random
+
+ \brief Re-enables the SHA-512 Hash_DRBG at runtime after a prior
+ call to wc_Sha512Drbg_Disable(). Available when WOLFSSL_DRBG_SHA512
+ is defined. Requires HAVE_HASHDRBG.
+
+ \return 0 On success
+
+ _Example_
+ \code
+ wc_Sha512Drbg_Disable();
+ // ... use SHA-256 DRBG only ...
+ wc_Sha512Drbg_Enable();
+ // New WC_RNG instances can use SHA-512 DRBG again
+ \endcode
+
+ \sa wc_Sha512Drbg_Disable
+ \sa wc_Sha512Drbg_GetStatus
+*/
+int wc_Sha512Drbg_Enable(void);
+
+/*!
+ \ingroup Random
+
+ \brief Returns the current status of the SHA-512 Hash_DRBG
+ (disabled or enabled). Available when WOLFSSL_DRBG_SHA512 is
+ defined. Requires HAVE_HASHDRBG.
+
+ \return 1 SHA-512 DRBG is disabled
+ \return 0 SHA-512 DRBG is enabled
+
+ _Example_
+ \code
+ if (wc_Sha512Drbg_GetStatus()) {
+ printf("SHA-512 DRBG is off\n");
+ }
+ \endcode
+
+ \sa wc_Sha512Drbg_Disable
+ \sa wc_Sha512Drbg_Enable
+*/
+int wc_Sha512Drbg_GetStatus(void);
diff --git a/doc/dox_comments/header_files/wc_slhdsa.h b/doc/dox_comments/header_files/wc_slhdsa.h
new file mode 100644
index 00000000000..a520d153b2c
--- /dev/null
+++ b/doc/dox_comments/header_files/wc_slhdsa.h
@@ -0,0 +1,793 @@
+/*!
+ \ingroup SLH_DSA
+
+ \brief Initializes an SLH-DSA key object with the specified parameter set.
+ Must be called before any other SLH-DSA operation. Use wc_SlhDsaKey_Free()
+ to release resources when done.
+
+ SLH-DSA (FIPS 205) is a stateless hash-based digital signature algorithm.
+ Parameter sets control the hash function (SHAKE or SHA2), security level
+ (128, 192, 256), and speed/size tradeoff (s = small signatures,
+ f = fast signing).
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key is NULL or param is invalid.
+
+ \param [in,out] key Pointer to the SlhDsaKey to initialize.
+ \param [in] param Parameter set to use. One of: SLHDSA_SHAKE128S,
+ SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, SLHDSA_SHAKE192F, SLHDSA_SHAKE256S,
+ SLHDSA_SHAKE256F, SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S,
+ SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F.
+ \param [in] heap Pointer to heap hint for dynamic memory allocation.
+ May be NULL.
+ \param [in] devId Device identifier for hardware crypto callbacks.
+ Use INVALID_DEVID for software-only.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ int ret;
+
+ ret = wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
+ if (ret != 0) {
+ // error initializing key
+ }
+ // ... use key ...
+ wc_SlhDsaKey_Free(&key);
+ \endcode
+
+ \sa wc_SlhDsaKey_Free
+ \sa wc_SlhDsaKey_MakeKey
+*/
+int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param,
+ void* heap, int devId);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Frees resources associated with an SLH-DSA key object.
+
+ \param [in,out] key Pointer to the SlhDsaKey to free. May be NULL.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
+ // ... use key ...
+ wc_SlhDsaKey_Free(&key);
+ \endcode
+
+ \sa wc_SlhDsaKey_Init
+*/
+void wc_SlhDsaKey_Free(SlhDsaKey* key);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Generates a new SLH-DSA key pair using the RNG for randomness.
+ The key must have been initialized with wc_SlhDsaKey_Init() first.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key or rng is NULL, or key is not initialized.
+
+ \param [in,out] key Pointer to an initialized SlhDsaKey.
+ \param [in] rng Pointer to an initialized WC_RNG.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ WC_RNG rng;
+ int ret;
+
+ wc_InitRng(&rng);
+ wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
+ ret = wc_SlhDsaKey_MakeKey(&key, &rng);
+ if (ret != 0) {
+ // error generating key
+ }
+ \endcode
+
+ \sa wc_SlhDsaKey_Init
+ \sa wc_SlhDsaKey_MakeKeyWithRandom
+*/
+int wc_SlhDsaKey_MakeKey(SlhDsaKey* key, WC_RNG* rng);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Generates an SLH-DSA key pair from caller-provided seed material.
+ This is the deterministic key generation interface — given the same seeds,
+ the same key pair is produced.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key or any seed pointer is NULL, or lengths
+ do not match the parameter set's n value.
+
+ \param [in,out] key Pointer to an initialized SlhDsaKey.
+ \param [in] sk_seed Secret key seed (n bytes).
+ \param [in] sk_seed_len Length of sk_seed.
+ \param [in] sk_prf Secret key PRF seed (n bytes).
+ \param [in] sk_prf_len Length of sk_prf.
+ \param [in] pk_seed Public key seed (n bytes).
+ \param [in] pk_seed_len Length of pk_seed.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sk_seed[16], sk_prf[16], pk_seed[16]; // n=16 for 128-bit params
+ int ret;
+
+ // fill seeds with known values (e.g. from NIST test vectors)
+ wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
+ ret = wc_SlhDsaKey_MakeKeyWithRandom(&key,
+ sk_seed, sizeof(sk_seed),
+ sk_prf, sizeof(sk_prf),
+ pk_seed, sizeof(pk_seed));
+ \endcode
+
+ \sa wc_SlhDsaKey_MakeKey
+*/
+int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key,
+ const byte* sk_seed, word32 sk_seed_len,
+ const byte* sk_prf, word32 sk_prf_len,
+ const byte* pk_seed, word32 pk_seed_len);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Signs a message using the SLH-DSA external (pure) interface with
+ deterministic randomness. This is FIPS 205 Algorithm 22 with opt_rand set
+ to PK.seed. The message M is wrapped internally as
+ M' = 0x00 || len(ctx) || ctx || M before signing.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, msg, sig, or sigSz is NULL.
+ \return BUFFER_E if the output buffer is too small.
+
+ \param [in] key Pointer to a private SlhDsaKey.
+ \param [in] ctx Context string for domain separation. May be NULL if
+ ctxSz is 0.
+ \param [in] ctxSz Length of the context string (0-255).
+ \param [in] msg Pointer to the message to sign.
+ \param [in] msgSz Length of the message.
+ \param [out] sig Buffer to receive the signature.
+ \param [in,out] sigSz On input, size of sig buffer. On output, actual
+ signature length.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sig[WC_SLHDSA_MAX_SIG_LEN];
+ word32 sigSz = sizeof(sig);
+ byte msg[] = "Hello World!";
+ int ret;
+
+ // key already generated via wc_SlhDsaKey_MakeKey()
+ ret = wc_SlhDsaKey_SignDeterministic(&key, NULL, 0,
+ msg, sizeof(msg), sig, &sigSz);
+ \endcode
+
+ \sa wc_SlhDsaKey_SignWithRandom
+ \sa wc_SlhDsaKey_Sign
+ \sa wc_SlhDsaKey_Verify
+*/
+int wc_SlhDsaKey_SignDeterministic(SlhDsaKey* key, const byte* ctx,
+ byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Signs a message using the SLH-DSA external (pure) interface with
+ caller-provided additional randomness. This is FIPS 205 Algorithm 22 with
+ an explicit opt_rand value.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, msg, sig, sigSz, or addRnd is NULL.
+
+ \param [in] key Pointer to a private SlhDsaKey.
+ \param [in] ctx Context string. May be NULL if ctxSz is 0.
+ \param [in] ctxSz Length of the context string (0-255).
+ \param [in] msg Pointer to the message to sign.
+ \param [in] msgSz Length of the message.
+ \param [out] sig Buffer to receive the signature.
+ \param [in,out] sigSz On input, size of sig buffer. On output, actual
+ signature length.
+ \param [in] addRnd Additional randomness (n bytes, where n is the
+ parameter set's security parameter).
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sig[WC_SLHDSA_MAX_SIG_LEN];
+ word32 sigSz = sizeof(sig);
+ byte msg[] = "Hello World!";
+ byte addRnd[16]; // n=16 for 128-bit params
+ int ret;
+
+ wc_RNG_GenerateBlock(&rng, addRnd, sizeof(addRnd));
+ ret = wc_SlhDsaKey_SignWithRandom(&key, NULL, 0,
+ msg, sizeof(msg), sig, &sigSz, addRnd);
+ \endcode
+
+ \sa wc_SlhDsaKey_SignDeterministic
+ \sa wc_SlhDsaKey_Sign
+*/
+int wc_SlhDsaKey_SignWithRandom(SlhDsaKey* key, const byte* ctx,
+ byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz,
+ const byte* addRnd);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Signs a message using the SLH-DSA external (pure) interface with
+ RNG-provided randomness. This is the general-purpose signing function
+ that uses the WC_RNG for opt_rand.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, msg, sig, sigSz, or rng is NULL.
+
+ \param [in] key Pointer to a private SlhDsaKey.
+ \param [in] ctx Context string. May be NULL if ctxSz is 0.
+ \param [in] ctxSz Length of the context string (0-255).
+ \param [in] msg Pointer to the message to sign.
+ \param [in] msgSz Length of the message.
+ \param [out] sig Buffer to receive the signature.
+ \param [in,out] sigSz On input, size of sig buffer. On output, actual
+ signature length.
+ \param [in] rng Pointer to an initialized WC_RNG.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ WC_RNG rng;
+ byte sig[WC_SLHDSA_MAX_SIG_LEN];
+ word32 sigSz = sizeof(sig);
+ byte msg[] = "Hello World!";
+ int ret;
+
+ ret = wc_SlhDsaKey_Sign(&key, NULL, 0,
+ msg, sizeof(msg), sig, &sigSz, &rng);
+ \endcode
+
+ \sa wc_SlhDsaKey_SignDeterministic
+ \sa wc_SlhDsaKey_Verify
+*/
+int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx,
+ byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz,
+ WC_RNG* rng);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Verifies an SLH-DSA signature over a message using the external
+ (pure) interface. This is FIPS 205 Algorithm 23. The message is wrapped
+ internally as M' = 0x00 || len(ctx) || ctx || M before verification.
+
+ \return 0 on success (signature valid).
+ \return BAD_FUNC_ARG if key, msg, or sig is NULL.
+ \return SIG_VERIFY_E if the signature is invalid.
+
+ \param [in] key Pointer to a public SlhDsaKey.
+ \param [in] ctx Context string. May be NULL if ctxSz is 0.
+ \param [in] ctxSz Length of the context string (0-255).
+ \param [in] msg Pointer to the message to verify.
+ \param [in] msgSz Length of the message.
+ \param [in] sig Pointer to the signature to verify.
+ \param [in] sigSz Length of the signature.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sig[...]; // previously generated signature
+ word32 sigSz;
+ byte msg[] = "Hello World!";
+ int ret;
+
+ ret = wc_SlhDsaKey_Verify(&key, NULL, 0,
+ msg, sizeof(msg), sig, sigSz);
+ if (ret == 0) {
+ // signature is valid
+ }
+ \endcode
+
+ \sa wc_SlhDsaKey_Sign
+ \sa wc_SlhDsaKey_SignDeterministic
+*/
+int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx,
+ byte ctxSz, const byte* msg, word32 msgSz, const byte* sig,
+ word32 sigSz);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Signs using the SLH-DSA internal interface with deterministic
+ randomness. Unlike the external interface, M' is provided directly by
+ the caller — no 0x00||len(ctx)||ctx||M wrapping is performed. This
+ corresponds to FIPS 205 Algorithm 19 (slh_sign_internal) with opt_rand
+ set to PK.seed.
+
+ Use this when the CAVP test framework or protocol layer has already
+ constructed M'.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, mprime, sig, or sigSz is NULL.
+
+ \param [in] key Pointer to a private SlhDsaKey.
+ \param [in] mprime Pointer to the pre-constructed M' message.
+ \param [in] mprimeSz Length of M'.
+ \param [out] sig Buffer to receive the signature.
+ \param [in,out] sigSz On input, size of sig buffer. On output, actual
+ signature length.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sig[WC_SLHDSA_MAX_SIG_LEN];
+ word32 sigSz = sizeof(sig);
+ byte mprime[] = { ... }; // pre-constructed M'
+ int ret;
+
+ ret = wc_SlhDsaKey_SignMsgDeterministic(&key,
+ mprime, sizeof(mprime), sig, &sigSz);
+ \endcode
+
+ \sa wc_SlhDsaKey_SignMsgWithRandom
+ \sa wc_SlhDsaKey_VerifyMsg
+ \sa wc_SlhDsaKey_SignDeterministic
+*/
+int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key,
+ const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Signs using the SLH-DSA internal interface with caller-provided
+ additional randomness. M' is provided directly — no wrapping is performed.
+ This corresponds to FIPS 205 Algorithm 19 (slh_sign_internal) with an
+ explicit opt_rand value.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, mprime, sig, sigSz, or addRnd is NULL.
+
+ \param [in] key Pointer to a private SlhDsaKey.
+ \param [in] mprime Pointer to the pre-constructed M' message.
+ \param [in] mprimeSz Length of M'.
+ \param [out] sig Buffer to receive the signature.
+ \param [in,out] sigSz On input, size of sig buffer. On output, actual
+ signature length.
+ \param [in] addRnd Additional randomness (n bytes).
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sig[WC_SLHDSA_MAX_SIG_LEN];
+ word32 sigSz = sizeof(sig);
+ byte mprime[] = { ... };
+ byte addRnd[16];
+ int ret;
+
+ wc_RNG_GenerateBlock(&rng, addRnd, sizeof(addRnd));
+ ret = wc_SlhDsaKey_SignMsgWithRandom(&key,
+ mprime, sizeof(mprime), sig, &sigSz, addRnd);
+ \endcode
+
+ \sa wc_SlhDsaKey_SignMsgDeterministic
+ \sa wc_SlhDsaKey_VerifyMsg
+*/
+int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key,
+ const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz,
+ const byte* addRnd);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Verifies an SLH-DSA signature using the internal interface. M' is
+ provided directly — no wrapping is performed. This corresponds to FIPS 205
+ Algorithm 20 (slh_verify_internal).
+
+ \return 0 on success (signature valid).
+ \return BAD_FUNC_ARG if key, mprime, or sig is NULL.
+ \return SIG_VERIFY_E if the signature is invalid.
+
+ \param [in] key Pointer to a public SlhDsaKey.
+ \param [in] mprime Pointer to the pre-constructed M' message.
+ \param [in] mprimeSz Length of M'.
+ \param [in] sig Pointer to the signature to verify.
+ \param [in] sigSz Length of the signature.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sig[...]; // previously generated signature
+ word32 sigSz;
+ byte mprime[] = { ... };
+ int ret;
+
+ ret = wc_SlhDsaKey_VerifyMsg(&key,
+ mprime, sizeof(mprime), sig, sigSz);
+ if (ret == 0) {
+ // signature is valid
+ }
+ \endcode
+
+ \sa wc_SlhDsaKey_SignMsgDeterministic
+ \sa wc_SlhDsaKey_Verify
+*/
+int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
+ word32 mprimeSz, const byte* sig, word32 sigSz);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA)
+ interface with deterministic randomness. The message is hashed with the
+ specified hash algorithm, then signed per FIPS 205 Algorithm 22 with the
+ pre-hash domain separator (0x01).
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, msg, sig, or sigSz is NULL, or hashType
+ is unsupported.
+
+ \param [in] key Pointer to a private SlhDsaKey.
+ \param [in] ctx Context string. May be NULL if ctxSz is 0.
+ \param [in] ctxSz Length of the context string (0-255).
+ \param [in] msg Pointer to the message to hash and sign.
+ \param [in] msgSz Length of the message.
+ \param [in] hashType Hash algorithm to use for pre-hashing. Supported:
+ WC_HASH_TYPE_SHA256, WC_HASH_TYPE_SHA384, WC_HASH_TYPE_SHA512,
+ WC_HASH_TYPE_SHAKE128, WC_HASH_TYPE_SHAKE256, WC_HASH_TYPE_SHA3_224,
+ WC_HASH_TYPE_SHA3_256, WC_HASH_TYPE_SHA3_384, WC_HASH_TYPE_SHA3_512.
+ \param [out] sig Buffer to receive the signature.
+ \param [in,out] sigSz On input, size of sig buffer. On output, actual
+ signature length.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sig[WC_SLHDSA_MAX_SIG_LEN];
+ word32 sigSz = sizeof(sig);
+ byte msg[] = "Hello World!";
+ int ret;
+
+ ret = wc_SlhDsaKey_SignHashDeterministic(&key, NULL, 0,
+ msg, sizeof(msg), WC_HASH_TYPE_SHA256, sig, &sigSz);
+ \endcode
+
+ \sa wc_SlhDsaKey_SignHashWithRandom
+ \sa wc_SlhDsaKey_SignHash
+ \sa wc_SlhDsaKey_VerifyHash
+*/
+int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key,
+ const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz,
+ enum wc_HashType hashType, byte* sig, word32* sigSz);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA)
+ interface with caller-provided additional randomness.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, msg, sig, sigSz, or addRnd is NULL.
+
+ \param [in] key Pointer to a private SlhDsaKey.
+ \param [in] ctx Context string. May be NULL if ctxSz is 0.
+ \param [in] ctxSz Length of the context string (0-255).
+ \param [in] msg Pointer to the message to hash and sign.
+ \param [in] msgSz Length of the message.
+ \param [in] hashType Hash algorithm to use for pre-hashing.
+ \param [out] sig Buffer to receive the signature.
+ \param [in,out] sigSz On input, size of sig buffer. On output, actual
+ signature length.
+ \param [in] addRnd Additional randomness (n bytes).
+
+ \sa wc_SlhDsaKey_SignHashDeterministic
+ \sa wc_SlhDsaKey_VerifyHash
+*/
+int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key,
+ const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz,
+ enum wc_HashType hashType, byte* sig, word32* sigSz, byte* addRnd);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA)
+ interface with RNG-provided randomness.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, msg, sig, sigSz, or rng is NULL.
+
+ \param [in] key Pointer to a private SlhDsaKey.
+ \param [in] ctx Context string. May be NULL if ctxSz is 0.
+ \param [in] ctxSz Length of the context string (0-255).
+ \param [in] msg Pointer to the message to hash and sign.
+ \param [in] msgSz Length of the message.
+ \param [in] hashType Hash algorithm to use for pre-hashing.
+ \param [out] sig Buffer to receive the signature.
+ \param [in,out] sigSz On input, size of sig buffer. On output, actual
+ signature length.
+ \param [in] rng Pointer to an initialized WC_RNG.
+
+ \sa wc_SlhDsaKey_SignHashDeterministic
+ \sa wc_SlhDsaKey_VerifyHash
+*/
+int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx,
+ byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType,
+ byte* sig, word32* sigSz, WC_RNG* rng);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Verifies an SLH-DSA signature over a pre-hashed message
+ (HashSLH-DSA). The message is hashed with the specified hash algorithm
+ before verification.
+
+ \return 0 on success (signature valid).
+ \return BAD_FUNC_ARG if key, msg, or sig is NULL.
+ \return SIG_VERIFY_E if the signature is invalid.
+
+ \param [in] key Pointer to a public SlhDsaKey.
+ \param [in] ctx Context string. May be NULL if ctxSz is 0.
+ \param [in] ctxSz Length of the context string (0-255).
+ \param [in] msg Pointer to the message to hash and verify.
+ \param [in] msgSz Length of the message.
+ \param [in] hashType Hash algorithm used for pre-hashing. Must match the
+ hash used during signing.
+ \param [in] sig Pointer to the signature to verify.
+ \param [in] sigSz Length of the signature.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte sig[...];
+ word32 sigSz;
+ byte msg[] = "Hello World!";
+ int ret;
+
+ ret = wc_SlhDsaKey_VerifyHash(&key, NULL, 0,
+ msg, sizeof(msg), WC_HASH_TYPE_SHA256, sig, sigSz);
+ if (ret == 0) {
+ // signature is valid
+ }
+ \endcode
+
+ \sa wc_SlhDsaKey_SignHashDeterministic
+ \sa wc_SlhDsaKey_Verify
+*/
+int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx,
+ byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType,
+ const byte* sig, word32 sigSz);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Imports an SLH-DSA private key from a raw byte buffer. The buffer
+ must contain the full private key (4*n bytes: SK.seed || SK.prf ||
+ PK.seed || PK.root). After import, the key can be used for signing.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key or in is NULL, or inLen does not match the
+ expected private key size for the parameter set.
+
+ \param [in,out] key Pointer to an initialized SlhDsaKey.
+ \param [in] in Buffer containing the raw private key bytes.
+ \param [in] inLen Length of the input buffer.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte privKey[...]; // 4*n bytes
+ int ret;
+
+ wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
+ ret = wc_SlhDsaKey_ImportPrivate(&key, privKey, sizeof(privKey));
+ \endcode
+
+ \sa wc_SlhDsaKey_ExportPrivate
+ \sa wc_SlhDsaKey_ImportPublic
+*/
+int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* in,
+ word32 inLen);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Imports an SLH-DSA public key from a raw byte buffer. The buffer
+ must contain PK.seed || PK.root (2*n bytes). After import, the key can
+ be used for verification.
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key or in is NULL, or inLen does not match the
+ expected public key size.
+
+ \param [in,out] key Pointer to an initialized SlhDsaKey.
+ \param [in] in Buffer containing the raw public key bytes.
+ \param [in] inLen Length of the input buffer.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte pubKey[...]; // 2*n bytes
+ int ret;
+
+ wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
+ ret = wc_SlhDsaKey_ImportPublic(&key, pubKey, sizeof(pubKey));
+ \endcode
+
+ \sa wc_SlhDsaKey_ExportPublic
+ \sa wc_SlhDsaKey_ImportPrivate
+*/
+int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* in,
+ word32 inLen);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Checks the consistency of an SLH-DSA key. For a key with both
+ private and public components, verifies that the public key matches the
+ private key.
+
+ \return 0 on success (key is valid).
+ \return BAD_FUNC_ARG if key is NULL.
+
+ \param [in] key Pointer to the SlhDsaKey to check.
+
+ \sa wc_SlhDsaKey_MakeKey
+ \sa wc_SlhDsaKey_ImportPrivate
+*/
+int wc_SlhDsaKey_CheckKey(SlhDsaKey* key);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Exports the private key from an SLH-DSA key object into a raw
+ byte buffer (4*n bytes).
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, out, or outLen is NULL.
+ \return BUFFER_E if the output buffer is too small.
+
+ \param [in] key Pointer to the SlhDsaKey containing a private key.
+ \param [out] out Buffer to receive the raw private key bytes.
+ \param [in,out] outLen On input, size of out buffer. On output, bytes
+ written.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte privKey[4 * 32]; // 4*n for 256-bit params
+ word32 privKeySz = sizeof(privKey);
+ int ret;
+
+ ret = wc_SlhDsaKey_ExportPrivate(&key, privKey, &privKeySz);
+ \endcode
+
+ \sa wc_SlhDsaKey_ImportPrivate
+ \sa wc_SlhDsaKey_ExportPublic
+*/
+int wc_SlhDsaKey_ExportPrivate(SlhDsaKey* key, byte* out,
+ word32* outLen);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Exports the public key from an SLH-DSA key object into a raw
+ byte buffer (2*n bytes: PK.seed || PK.root).
+
+ \return 0 on success.
+ \return BAD_FUNC_ARG if key, out, or outLen is NULL.
+ \return BUFFER_E if the output buffer is too small.
+
+ \param [in] key Pointer to the SlhDsaKey containing a public key.
+ \param [out] out Buffer to receive the raw public key bytes.
+ \param [in,out] outLen On input, size of out buffer. On output, bytes
+ written.
+
+ _Example_
+ \code
+ SlhDsaKey key;
+ byte pubKey[2 * 32];
+ word32 pubKeySz = sizeof(pubKey);
+ int ret;
+
+ ret = wc_SlhDsaKey_ExportPublic(&key, pubKey, &pubKeySz);
+ \endcode
+
+ \sa wc_SlhDsaKey_ImportPublic
+ \sa wc_SlhDsaKey_ExportPrivate
+*/
+int wc_SlhDsaKey_ExportPublic(SlhDsaKey* key, byte* out,
+ word32* outLen);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Returns the private key size in bytes for the key's parameter set.
+
+ \return Private key size in bytes (4*n) on success.
+ \return BAD_FUNC_ARG if key is NULL or not initialized.
+
+ \param [in] key Pointer to an initialized SlhDsaKey.
+
+ \sa wc_SlhDsaKey_PublicSize
+ \sa wc_SlhDsaKey_SigSize
+ \sa wc_SlhDsaKey_PrivateSizeFromParam
+*/
+int wc_SlhDsaKey_PrivateSize(SlhDsaKey* key);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Returns the public key size in bytes for the key's parameter set.
+
+ \return Public key size in bytes (2*n) on success.
+ \return BAD_FUNC_ARG if key is NULL or not initialized.
+
+ \param [in] key Pointer to an initialized SlhDsaKey.
+
+ \sa wc_SlhDsaKey_PrivateSize
+ \sa wc_SlhDsaKey_SigSize
+ \sa wc_SlhDsaKey_PublicSizeFromParam
+*/
+int wc_SlhDsaKey_PublicSize(SlhDsaKey* key);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Returns the signature size in bytes for the key's parameter set.
+
+ \return Signature size in bytes on success.
+ \return BAD_FUNC_ARG if key is NULL or not initialized.
+
+ \param [in] key Pointer to an initialized SlhDsaKey.
+
+ \sa wc_SlhDsaKey_PrivateSize
+ \sa wc_SlhDsaKey_PublicSize
+ \sa wc_SlhDsaKey_SigSizeFromParam
+*/
+int wc_SlhDsaKey_SigSize(SlhDsaKey* key);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Returns the private key size in bytes for the given parameter set
+ without needing an initialized key object.
+
+ \return Private key size in bytes (4*n) on success.
+ \return BAD_FUNC_ARG if param is invalid.
+
+ \param [in] param The SLH-DSA parameter set.
+
+ \sa wc_SlhDsaKey_PrivateSize
+*/
+int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Returns the public key size in bytes for the given parameter set
+ without needing an initialized key object.
+
+ \return Public key size in bytes (2*n) on success.
+ \return BAD_FUNC_ARG if param is invalid.
+
+ \param [in] param The SLH-DSA parameter set.
+
+ \sa wc_SlhDsaKey_PublicSize
+*/
+int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param);
+
+/*!
+ \ingroup SLH_DSA
+
+ \brief Returns the signature size in bytes for the given parameter set
+ without needing an initialized key object.
+
+ \return Signature size in bytes on success.
+ \return BAD_FUNC_ARG if param is invalid.
+
+ \param [in] param The SLH-DSA parameter set.
+
+ \sa wc_SlhDsaKey_SigSize
+*/
+int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param);
diff --git a/src/include.am b/src/include.am
index cb91fe84cc5..3dc8c76da8b 100644
--- a/src/include.am
+++ b/src/include.am
@@ -431,7 +431,7 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c
endif BUILD_FIPS_V5
-if BUILD_FIPS_V6_PLUS
+if BUILD_FIPS_V6
# FIPS 140-3 SRTP-KDF first file
src_libwolfssl@LIBSUFFIX@_la_SOURCES += \
wolfcrypt/src/wolfcrypt_first.c
@@ -766,7 +766,390 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \
# fips last file
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c
-endif BUILD_FIPS_V6_PLUS
+endif BUILD_FIPS_V6
+
+if BUILD_FIPS_V7_PLUS
+# FIPS 140-3 v7.0.0+ first file
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += \
+ wolfcrypt/src/wolfcrypt_first.c
+
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += \
+ wolfcrypt/src/hmac.c \
+ wolfcrypt/src/random.c
+
+if BUILD_MEMUSE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfentropy.c
+endif
+
+if BUILD_RNG_BANK
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rng_bank.c
+endif
+
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/kdf.c
+
+if BUILD_RSA
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rsa.c
+endif
+
+if BUILD_ECC
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ecc.c
+endif
+
+if BUILD_AES
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes.c
+
+if BUILD_ARMASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_AES_C)
+endif BUILD_ARMASM
+
+if BUILD_ARMASM_NEON
+if BUILD_ARMASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_AES_ASM_C)
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm_c.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_AES_ASM_S)
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm.S
+endif !BUILD_ARMASM_INLINE
+else
+if BUILD_ARMASM
+if BUILD_ARMASM_INLINE
+if BUILD_ARM_NONTHUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm_c.c
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-aes-asm_c.c
+endif
+else
+if BUILD_ARM_NONTHUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm.S
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-aes-asm.S
+endif
+endif !BUILD_ARMASM_INLINE
+endif BUILD_ARMASM
+endif !BUILD_ARMASM_NEON
+endif BUILD_AES
+
+if BUILD_AESNI
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_asm.S
+if BUILD_X86_ASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_gcm_x86_asm.S
+else
+if BUILD_AESGCM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_gcm_asm.S
+endif
+if BUILD_AESXTS
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_xts_asm.S
+endif
+endif
+endif
+
+if BUILD_SHA
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha.c
+endif
+
+if BUILD_ARMASM_NEON
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(ARMASM_SHA256_C)
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA256_C)
+if BUILD_ARMASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_SHA256_ASM_C)
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_SHA256_ASM_S)
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm.S
+endif !BUILD_ARMASM_INLINE
+else
+if BUILD_ARMASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(ARMASM_SHA256_C)
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA256_C)
+if BUILD_ARMASM_INLINE
+if BUILD_ARM_NONTHUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.c
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha256-asm_c.c
+endif
+else
+if BUILD_ARM_NONTHUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm.S
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha256-asm.S
+endif
+endif !BUILD_ARMASM_INLINE
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha256.c
+if BUILD_INTELASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha256_asm.S
+endif BUILD_INTELASM
+endif !BUILD_ARMASM
+endif !BUILD_ARMASM_NEON
+
+if BUILD_RISCV_ASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha256.c
+endif BUILD_RISCV_ASM
+
+if BUILD_PPC32_ASM
+if BUILD_PPC32_ASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm_c.c
+else
+if BUILD_PPC32_ASM_INLINE_REG
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm_cr.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm.S
+endif !BUILD_PPC32_ASM_INLINE_REG
+endif !BUILD_PPC32_ASM_INLINE
+endif BUILD_PPC32_ASM
+
+if BUILD_SHA512
+if BUILD_RISCV_ASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha512.c
+else
+
+if !BUILD_FIPS_V5
+if !BUILD_FIPS_V6
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c
+endif !BUILD_FIPS_V6
+endif !BUILD_FIPS_V5
+
+if BUILD_ARMASM_NEON
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA512_C)
+if BUILD_ARMASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha512-asm_c.c
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm_c.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha512-asm.S
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm.S
+endif !BUILD_ARMASM_INLINE
+else
+if BUILD_ARMASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA512_C)
+if BUILD_ARMASM_INLINE
+if BUILD_ARM_NONTHUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm_c.c
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha512-asm_c.c
+endif
+else
+if BUILD_ARM_NONTHUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm.S
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha512-asm.S
+endif
+endif !BUILD_ARMASM_INLINE
+else
+
+if BUILD_FIPS_V5
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c
+else
+if BUILD_FIPS_V6
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c
+endif BUILD_FIPS_V6
+endif !BUILD_FIPS_V5
+
+if BUILD_INTELASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512_asm.S
+endif BUILD_INTELASM
+endif !BUILD_ARMASM
+endif !BUILD_ARMASM_NEON
+endif !BUILD_RISCV_ASM
+endif BUILD_SHA512
+
+if BUILD_SHA3
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha3.c
+if BUILD_ARMASM_NEON
+if BUILD_ARMASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha3-asm_c.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha3-asm.S
+endif !BUILD_ARMASM_INLINE
+endif BUILD_ARMASM_NEON
+if BUILD_ARMASM
+if BUILD_ARMASM_INLINE
+if BUILD_ARM_NONTHUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha3-asm_c.c
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha3-asm_c.c
+endif
+else
+if BUILD_ARM_NONTHUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha3-asm.S
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha3-asm.S
+endif
+endif !BUILD_ARMASM_INLINE
+endif BUILD_ARMASM
+if BUILD_RISCV_ASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha3.c
+endif BUILD_RISCV_ASM
+if BUILD_INTELASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha3_asm.S
+endif
+endif
+
+if BUILD_DH
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/dh.c
+endif
+
+if BUILD_CMAC
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c
+endif
+
+if BUILD_CURVE448
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve448.c
+endif
+
+if BUILD_ED448
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ed448.c
+endif
+
+if BUILD_CURVE25519
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve25519.c
+endif
+
+if BUILD_ED25519
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ed25519.c
+endif
+
+if BUILD_ARMASM
+if BUILD_ARMASM_NEON
+if BUILD_ARMASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519_c.c
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519_c.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519.S
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519.S
+endif !BUILD_ARMASM_INLINE
+else
+if BUILD_ARMASM_INLINE
+if BUILD_ARM_NONTHUMB
+if BUILD_ARM_32
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519_c.c
+endif
+if BUILD_ARM_64
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519_c.c
+endif
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-curve25519_c.c
+endif
+else
+if BUILD_ARM_NONTHUMB
+if BUILD_ARM_32
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519.S
+endif
+if BUILD_ARM_64
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519.S
+endif
+endif
+if BUILD_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-curve25519.S
+endif
+endif !BUILD_ARMASM_INLINE
+endif !BUILD_ARMASM_NEON
+endif BUILD_ARMASM
+
+if BUILD_PWDBASED
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/pwdbased.c
+endif BUILD_PWDBASED
+
+if BUILD_SP
+if BUILD_SP_C32
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_c32.c
+endif
+if BUILD_SP_C64
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_c64.c
+endif
+
+if BUILD_SP_X86_64
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_x86_64.c
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_x86_64_asm.S
+endif
+if !BUILD_FIPS_V2
+if BUILD_SP_ARM32
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_arm32.c
+endif
+endif
+if BUILD_SP_ARM_THUMB
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_armthumb.c
+endif
+if !BUILD_FIPS_V2
+if BUILD_SP_ARM64
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_arm64.c
+endif
+endif
+if BUILD_SP_ARM_CORTEX
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_cortexm.c
+endif
+endif BUILD_SP
+
+# PQ Algorithms (FIPS v7.0.0+)
+if BUILD_WC_MLKEM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem.c
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_poly.c
+if BUILD_ARMASM
+if BUILD_ARM_THUMB
+if BUILD_ARMASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-mlkem-asm.S
+endif !BUILD_ARMASM_INLINE
+else
+if BUILD_ARMASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-mlkem-asm.S
+endif !BUILD_ARMASM_INLINE
+endif !BUILD_ARM_THUMB
+endif BUILD_ARMASM
+if !BUILD_X86_ASM
+if BUILD_INTELASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_asm.S
+endif
+endif
+if BUILD_ARMASM_NEON
+if BUILD_ARMASM_INLINE
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c
+else
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-mlkem-asm.S
+endif !BUILD_ARMASM_INLINE
+endif BUILD_ARMASM_NEON
+endif
+
+if BUILD_DILITHIUM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/dilithium.c
+if !BUILD_X86_ASM
+if BUILD_INTELASM
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mldsa_asm.S
+endif BUILD_INTELASM
+endif !BUILD_X86_ASM
+endif
+
+if BUILD_WC_LMS
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms.c
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms_impl.c
+endif
+
+if BUILD_WC_XMSS
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss.c
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss_impl.c
+endif
+
+if BUILD_WC_SLHDSA
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_slhdsa.c
+endif
+
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \
+ wolfcrypt/src/fips_test.c
+
+# fips last file
+src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c
+endif BUILD_FIPS_V7_PLUS
endif BUILD_FIPS
@@ -1377,6 +1760,7 @@ if BUILD_SAKKE
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sakke.c
endif
+if !BUILD_FIPS_V7_PLUS
if BUILD_WC_MLKEM
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_poly.c
@@ -1427,10 +1811,13 @@ if BUILD_WC_XMSS
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss_impl.c
endif
+endif !BUILD_FIPS_V7_PLUS
+if !BUILD_FIPS_V7_PLUS
if BUILD_WC_SLHDSA
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_slhdsa.c
endif
+endif !BUILD_FIPS_V7_PLUS
if !BUILD_FIPS_V6_PLUS
if BUILD_CURVE25519
diff --git a/tests/api.c b/tests/api.c
index 8687213f42b..863cbfcb2fa 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -27168,8 +27168,6 @@ static int error_test(void)
{27, 26 },
#endif
{ -9, WC_SPAN1_FIRST_E + 1 },
- { -124, -124 },
- { -167, -169 },
{ -300, -300 },
{ -335, -336 },
{ -346, -349 },
diff --git a/tests/api/test_hash.c b/tests/api/test_hash.c
index 1fe2e84098d..be5b1be38f4 100644
--- a/tests/api/test_hash.c
+++ b/tests/api/test_hash.c
@@ -68,6 +68,12 @@ static const enum wc_HashType supportedHash[] = {
WC_HASH_TYPE_SHA3_256,
WC_HASH_TYPE_SHA3_384,
WC_HASH_TYPE_SHA3_512,
+#if defined(WOLFSSL_SHAKE128)
+ WC_HASH_TYPE_SHAKE128,
+#endif
+#if defined(WOLFSSL_SHAKE256)
+ WC_HASH_TYPE_SHAKE256,
+#endif
#endif
#ifdef WOLFSSL_SM3
WC_HASH_TYPE_SM3,
@@ -101,6 +107,12 @@ static const enum wc_HashType notCompiledHash[] = {
WC_HASH_TYPE_SHA3_256,
WC_HASH_TYPE_SHA3_384,
WC_HASH_TYPE_SHA3_512,
+#endif
+#if defined(WOLFSSL_SHAKE128) && !defined(WOLFSSL_SHA3)
+ WC_HASH_TYPE_SHAKE128,
+#endif
+#if defined(WOLFSSL_SHAKE256) && !defined(WOLFSSL_SHA3)
+ WC_HASH_TYPE_SHAKE256,
#endif
WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */
};
@@ -108,12 +120,6 @@ static const int notCompiledHashLen = (sizeof(notCompiledHash) /
sizeof(enum wc_HashType)) - 1;
static const enum wc_HashType notSupportedHash[] = {
-#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
- WC_HASH_TYPE_SHAKE128,
-#endif
-#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
- WC_HASH_TYPE_SHAKE256,
-#endif
WC_HASH_TYPE_MD5_SHA,
WC_HASH_TYPE_MD2,
WC_HASH_TYPE_MD4,
@@ -137,6 +143,12 @@ static const enum wc_HashType sizeSupportedHash[] = {
#if defined(HAVE_BLAKE2) || defined(HAVE_BLAKE2S)
WC_HASH_TYPE_BLAKE2B,
WC_HASH_TYPE_BLAKE2S,
+#endif
+#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
+ WC_HASH_TYPE_SHAKE128,
+#endif
+#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
+ WC_HASH_TYPE_SHAKE256,
#endif
WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */
};
@@ -155,18 +167,18 @@ static const enum wc_HashType sizeNotCompiledHash[] = {
#if !defined(HAVE_BLAKE2) && !defined(HAVE_BLAKE2S)
WC_HASH_TYPE_BLAKE2B,
WC_HASH_TYPE_BLAKE2S,
+#endif
+#if defined(WOLFSSL_SHAKE128) && !defined(WOLFSSL_SHA3)
+ WC_HASH_TYPE_SHAKE128,
+#endif
+#if defined(WOLFSSL_SHAKE256) && !defined(WOLFSSL_SHA3)
+ WC_HASH_TYPE_SHAKE256,
#endif
WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */
};
static const int sizeNotCompiledHashLen = (sizeof(sizeNotCompiledHash) /
sizeof(enum wc_HashType)) - 1;
static const enum wc_HashType sizeNotSupportedHash[] = {
-#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
- WC_HASH_TYPE_SHAKE128,
-#endif
-#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
- WC_HASH_TYPE_SHAKE256,
-#endif
WC_HASH_TYPE_NONE
};
static const int sizeNotSupportedHashLen = (sizeof(sizeNotSupportedHash) /
diff --git a/tests/api/test_mldsa.c b/tests/api/test_mldsa.c
index 2aa788e8615..19c24a73e60 100644
--- a/tests/api/test_mldsa.c
+++ b/tests/api/test_mldsa.c
@@ -553,6 +553,8 @@ int test_wc_dilithium(void)
ExpectIntEQ(wc_InitRng(&rng), 0);
#endif
+ PRIVATE_KEY_UNLOCK();
+
ExpectIntEQ(wc_dilithium_init(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_dilithium_init_ex(NULL, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wc_dilithium_free(NULL);
@@ -673,6 +675,8 @@ int test_wc_dilithium(void)
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
+ PRIVATE_KEY_LOCK();
+
wc_dilithium_free(key);
#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \
!defined(WOLFSSL_DILITHIUM_NO_SIGN)
@@ -765,6 +769,8 @@ int test_wc_dilithium_sign(void)
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_dilithium_init(key), 0);
+ PRIVATE_KEY_UNLOCK();
+
#ifndef WOLFSSL_NO_ML_DSA_44
ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0);
#elif !defined(WOLFSSL_NO_ML_DSA_65)
@@ -878,6 +884,8 @@ int test_wc_dilithium_sign(void)
#endif
wc_dilithium_free(importKey);
+ PRIVATE_KEY_LOCK();
+
wc_dilithium_free(key);
wc_FreeRng(&rng);
@@ -1251,6 +1259,8 @@ int test_wc_dilithium_check_key(void)
ExpectIntEQ(wc_InitRng(&rng), 0);
+ PRIVATE_KEY_UNLOCK();
+
ExpectIntEQ(wc_dilithium_check_key(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_dilithium_init(checkKey), 0);
@@ -1337,6 +1347,8 @@ int test_wc_dilithium_check_key(void)
pubCheckKey[48] ^= 0x80;
}
+ PRIVATE_KEY_LOCK();
+
wc_dilithium_free(checkKey);
wc_FreeRng(&rng);
@@ -2940,6 +2952,8 @@ int test_wc_dilithium_der(void)
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_dilithium_init(key), 0);
+ PRIVATE_KEY_UNLOCK();
+
ExpectIntEQ(wc_Dilithium_PublicKeyToDer(key, der, DILITHIUM_MAX_DER_SIZE,
0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_Dilithium_PublicKeyToDer(key, der, DILITHIUM_MAX_DER_SIZE,
@@ -3091,6 +3105,7 @@ int test_wc_dilithium_der(void)
idx = 0;
ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der, &idx, key, len), 0);
+ PRIVATE_KEY_LOCK();
wc_dilithium_free(key);
wc_FreeRng(&rng);
@@ -12346,6 +12361,9 @@ int test_wc_dilithium_sig_kats(void)
}
ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0);
+
+ PRIVATE_KEY_UNLOCK();
+
#ifndef WOLFSSL_NO_ML_DSA_44
ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0);
ExpectIntEQ(wc_dilithium_import_private(sk_44, (word32)sizeof(sk_44), key),
@@ -12377,6 +12395,8 @@ int test_wc_dilithium_sig_kats(void)
ExpectIntEQ(XMEMCMP(sig, sig_87, sizeof(sig_87)), 0);
#endif
+ PRIVATE_KEY_LOCK();
+
wc_dilithium_free(key);
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
@@ -16745,6 +16765,8 @@ int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void)
ExpectNotNull(der = (byte*) XMALLOC(derMaxSz, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
+ PRIVATE_KEY_UNLOCK();
+
for (size_t i = 0; i < sizeof(ossl_form) / sizeof(ossl_form[0]); ++i) {
ExpectNotNull(fp = XFOPEN(ossl_form[i].fileName, "rb"));
ExpectIntGT(derSz = XFREAD(der, 1, derMaxSz, fp), 0);
@@ -16811,6 +16833,8 @@ int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void)
wc_dilithium_free(&key);
}
+ PRIVATE_KEY_LOCK();
+
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
diff --git a/tests/api/test_mlkem.c b/tests/api/test_mlkem.c
index c727194fbe1..c42ab186a49 100644
--- a/tests/api/test_mlkem.c
+++ b/tests/api/test_mlkem.c
@@ -1451,6 +1451,8 @@ int test_wc_mlkem_make_key_kats(void)
XMEMSET(key, 0, sizeof(MlKemKey));
}
+ PRIVATE_KEY_UNLOCK();
+
#ifndef WOLFSSL_NO_ML_KEM_512
ExpectIntEQ(wc_MlKemKey_Init(key, WC_ML_KEM_512, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_MlKemKey_MakeKeyWithRandom(key, seed_512, sizeof(seed_512)),
@@ -1488,6 +1490,8 @@ int test_wc_mlkem_make_key_kats(void)
wc_MlKemKey_Free(key);
#endif
+ PRIVATE_KEY_LOCK();
+
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
@@ -3845,6 +3849,8 @@ int test_wc_mlkem_decapsulate_kats(void)
XMEMSET(key, 0, sizeof(MlKemKey));
}
+ PRIVATE_KEY_UNLOCK();
+
#ifndef WOLFSSL_NO_ML_KEM_512
ExpectIntEQ(wc_MlKemKey_Init(key, WC_ML_KEM_512, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_MlKemKey_DecodePrivateKey(key, dk_512, sizeof(dk_512)), 0);
@@ -3867,6 +3873,8 @@ int test_wc_mlkem_decapsulate_kats(void)
wc_MlKemKey_Free(key);
#endif
+ PRIVATE_KEY_LOCK();
+
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
diff --git a/tests/api/test_random.c b/tests/api/test_random.c
index fe8aaf0ee15..79f8c27b5ee 100644
--- a/tests/api/test_random.c
+++ b/tests/api/test_random.c
@@ -530,3 +530,146 @@ int test_wc_RNG_HealthTest(void)
return EXPECT_RESULT();
}
+/*
+ * Testing wc_RNG_HealthTest_SHA512()
+ * Test vectors from NIST CAVP drbgtestvectors.zip, Hash_DRBG.rsp, [SHA-512].
+ * Source: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-
+ * Validation-Program/documents/drbg/drbgtestvectors.zip
+ */
+int test_wc_RNG_HealthTest_SHA512(void)
+{
+ EXPECT_DECLS;
+#if defined(HAVE_HASHDRBG) && defined(WOLFSSL_DRBG_SHA512) && \
+ !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+
+ /* No-reseed test: drbgvectors_no_reseed/Hash_DRBG.rsp, [SHA-512],
+ * COUNT=0 */
+ const byte test1Seed[] =
+ {
+ /* EntropyInput (32 bytes) */
+ 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a,
+ 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22,
+ 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b,
+ 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c,
+ /* Nonce (16 bytes) */
+ 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa,
+ 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25
+ };
+ const byte test1Output[] =
+ {
+ 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57,
+ 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6,
+ 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d,
+ 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf,
+ 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26,
+ 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64,
+ 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55,
+ 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a,
+ 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78,
+ 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e,
+ 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb,
+ 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30,
+ 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19,
+ 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f,
+ 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d,
+ 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a,
+ 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2,
+ 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd,
+ 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd,
+ 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2,
+ 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b,
+ 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1,
+ 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99,
+ 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e,
+ 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3,
+ 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67,
+ 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3,
+ 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d,
+ 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b,
+ 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13,
+ 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c,
+ 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2
+ };
+
+ /* Reseed test: drbgvectors_pr_false/Hash_DRBG.rsp, [SHA-512], COUNT=0 */
+ const byte test2SeedA[] =
+ {
+ /* EntropyInput (32 bytes) */
+ 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12,
+ 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10,
+ 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff,
+ 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33,
+ /* Nonce (16 bytes) */
+ 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3,
+ 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04
+ };
+ const byte test2SeedB[] =
+ {
+ /* EntropyInputReseed (32 bytes) */
+ 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6,
+ 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0,
+ 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d,
+ 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67
+ };
+ const byte test2Output[] =
+ {
+ 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76,
+ 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c,
+ 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a,
+ 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1,
+ 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70,
+ 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42,
+ 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d,
+ 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15,
+ 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58,
+ 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7,
+ 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05,
+ 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c,
+ 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac,
+ 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f,
+ 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb,
+ 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f,
+ 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1,
+ 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82,
+ 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22,
+ 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e,
+ 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4,
+ 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a,
+ 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a,
+ 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03,
+ 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e,
+ 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78,
+ 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2,
+ 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6,
+ 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e,
+ 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0,
+ 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d,
+ 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0
+ };
+
+ byte output[WC_SHA512_DIGEST_SIZE * 4]; /* 256 bytes */
+
+ /* Bad parameter tests */
+ ExpectIntNE(wc_RNG_HealthTest_SHA512(0, NULL, sizeof(test1Seed),
+ NULL, 0, output, sizeof(output)), 0);
+ ExpectIntNE(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed),
+ NULL, 0, NULL, sizeof(output)), 0);
+ ExpectIntNE(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed),
+ NULL, 0, output, 42), 0); /* wrong output size */
+
+ /* Good parameter tests */
+ /* No-reseed */
+ ExpectIntEQ(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed),
+ NULL, 0, output, sizeof(output)), 0);
+ ExpectBufEQ(test1Output, output, sizeof(output));
+
+ /* With reseed */
+ ExpectIntEQ(wc_RNG_HealthTest_SHA512(1, test2SeedA, sizeof(test2SeedA),
+ test2SeedB, sizeof(test2SeedB), output, sizeof(output)), 0);
+ ExpectBufEQ(test2Output, output, sizeof(output));
+
+#endif /* HAVE_HASHDRBG && WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */
+ return EXPECT_RESULT();
+}
+
diff --git a/tests/api/test_random.h b/tests/api/test_random.h
index a6478b38df9..0454e14c703 100644
--- a/tests/api/test_random.h
+++ b/tests/api/test_random.h
@@ -35,6 +35,7 @@ int test_wc_rng_new(void);
int test_wc_RNG_DRBG_Reseed(void);
int test_wc_RNG_TestSeed(void);
int test_wc_RNG_HealthTest(void);
+int test_wc_RNG_HealthTest_SHA512(void);
#define TEST_RANDOM_DECLS \
TEST_DECL_GROUP("random", test_wc_InitRng), \
@@ -47,6 +48,7 @@ int test_wc_RNG_HealthTest(void);
TEST_DECL_GROUP("random", test_wc_rng_new), \
TEST_DECL_GROUP("random", test_wc_RNG_DRBG_Reseed), \
TEST_DECL_GROUP("random", test_wc_RNG_TestSeed), \
- TEST_DECL_GROUP("random", test_wc_RNG_HealthTest)
+ TEST_DECL_GROUP("random", test_wc_RNG_HealthTest), \
+ TEST_DECL_GROUP("random", test_wc_RNG_HealthTest_SHA512)
#endif /* WOLFCRYPT_TEST_RANDOM_H */
diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c
index 354e5a68004..5c9e7ed608c 100644
--- a/wolfcrypt/benchmark/benchmark.c
+++ b/wolfcrypt/benchmark/benchmark.c
@@ -975,16 +975,37 @@ static WC_INLINE void bench_append_memory_info(char* buffer, size_t size,
#define BENCH_SLHDSA_SHAKE192F 0x00000100
#define BENCH_SLHDSA_SHAKE256S 0x00000200
#define BENCH_SLHDSA_SHAKE256F 0x00000400
+#define BENCH_SLHDSA_SHA2_128S 0x00000800
+#define BENCH_SLHDSA_SHA2_128F 0x00001000
+#define BENCH_SLHDSA_SHA2_192S 0x00002000
+#define BENCH_SLHDSA_SHA2_192F 0x00004000
+#define BENCH_SLHDSA_SHA2_256S 0x00008000
+#define BENCH_SLHDSA_SHA2_256F 0x00010000
#define BENCH_SLHDSA (BENCH_SLHDSA_SHAKE128S | \
BENCH_SLHDSA_SHAKE128F | \
BENCH_SLHDSA_SHAKE192S | \
BENCH_SLHDSA_SHAKE192F | \
BENCH_SLHDSA_SHAKE256S | \
- BENCH_SLHDSA_SHAKE256F)
+ BENCH_SLHDSA_SHAKE256F | \
+ BENCH_SLHDSA_SHA2_128S | \
+ BENCH_SLHDSA_SHA2_128F | \
+ BENCH_SLHDSA_SHA2_192S | \
+ BENCH_SLHDSA_SHA2_192F | \
+ BENCH_SLHDSA_SHA2_256S | \
+ BENCH_SLHDSA_SHA2_256F)
/* Other */
#define BENCH_RNG 0x00000001
#define BENCH_SCRYPT 0x00000002
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ #define BENCH_RNG_SHA512 0x00000004
+#endif
+#define BENCH_RNG_INIT 0x00000008
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ #define BENCH_RNG_SHA512_INIT 0x00000010
+#endif
#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || \
(defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
@@ -1292,6 +1313,17 @@ static const bench_alg bench_other_opt[] = {
#ifndef WC_NO_RNG
{ "-rng", BENCH_RNG },
#endif
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ { "-rng-sha512", BENCH_RNG_SHA512 },
+#endif
+#ifndef WC_NO_RNG
+ { "-rng-init", BENCH_RNG_INIT },
+#endif
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ { "-rng-sha512-init", BENCH_RNG_SHA512_INIT },
+#endif
#ifdef HAVE_SCRYPT
{ "-scrypt", BENCH_SCRYPT },
#endif
@@ -1340,6 +1372,12 @@ static const bench_pq_hash_sig_alg bench_pq_hash_sig_opt[] = {
{ "-slhdsa-shake192f", BENCH_SLHDSA_SHAKE192F},
{ "-slhdsa-shake256s", BENCH_SLHDSA_SHAKE256S},
{ "-slhdsa-shake256f", BENCH_SLHDSA_SHAKE256F},
+ { "-slhdsa-sha2-128s", BENCH_SLHDSA_SHA2_128S},
+ { "-slhdsa-sha2-128f", BENCH_SLHDSA_SHA2_128F},
+ { "-slhdsa-sha2-192s", BENCH_SLHDSA_SHA2_192S},
+ { "-slhdsa-sha2-192f", BENCH_SLHDSA_SHA2_192F},
+ { "-slhdsa-sha2-256s", BENCH_SLHDSA_SHA2_256S},
+ { "-slhdsa-sha2-256f", BENCH_SLHDSA_SHA2_256F},
{ "-slhdsa", BENCH_SLHDSA },
#endif
{ NULL, 0}
@@ -2056,12 +2094,7 @@ static const char* bench_result_words3[][5] = {
#define BENCH_ASYM
#endif
-#if defined(BENCH_ASYM)
-#if defined(HAVE_ECC) || !defined(NO_RSA) || !defined(NO_DH) || \
- defined(HAVE_CURVE25519) || defined(HAVE_ED25519) || \
- defined(HAVE_CURVE448) || defined(HAVE_ED448) || \
- defined(WOLFSSL_HAVE_MLKEM) || defined(HAVE_DILITHIUM) || \
- defined(WOLFSSL_HAVE_LMS)
+#if defined(BENCH_ASYM) || !defined(WC_NO_RNG)
static const char* bench_result_words2[][6] = {
#ifdef BENCH_MICROSECOND
{ "ops took", "μsec" , "avg" , "ops/μsec", "cycles/op",
@@ -2075,8 +2108,7 @@ static const char* bench_result_words2[][6] = {
NULL }, /* 1 Japanese */
#endif
};
-#endif
-#endif
+#endif /* BENCH_ASYM || !WC_NO_RNG */
#ifdef WOLFSSL_CAAM
#include
@@ -3200,6 +3232,102 @@ static void bench_stats_sym_finish(const char* desc, int useDeviceID,
TEST_SLEEP();
} /* bench_stats_sym_finish */
+#ifndef WC_NO_RNG
+/* Report ops/sec in the same format as bench_stats_asym_finish, but without
+ * requiring BENCH_ASYM to be defined. Used for benchmarks like RNG init/free
+ * that measure operation counts rather than byte throughput. */
+static void bench_stats_ops_finish(const char* algo, int strength,
+ const char* desc, int count, double start, int ret)
+{
+ double total, each = 0, opsSec, milliEach;
+ const char **word = bench_result_words2[lng_index];
+ char msg[256];
+#ifdef BENCH_MICROSECOND
+ const int digits = 5;
+#else
+ const int digits = 3;
+#endif
+
+ XMEMSET(msg, 0, sizeof(msg));
+
+ total = current_time(0) - start;
+
+#ifdef WOLFSSL_ESPIDF
+ END_ESP_CYCLES
+#else
+ END_CYCLES
+#endif
+
+ if (count > 0)
+ each = total / count;
+ if (total > 0)
+ opsSec = count / total;
+ else
+ opsSec = 0;
+
+#ifdef BENCH_MICROSECOND
+ milliEach = each / 1000;
+#else
+ milliEach = each * 1000;
+#endif
+
+ SLEEP_ON_ERROR(ret);
+
+ if (csv_format == 1) {
+ (void)XSNPRINTF(msg, sizeof(msg), "%s,%d,%s," FLT_FMT_PREC ","
+ FLT_FMT_PREC "," STATS_CLAUSE_SEPARATOR,
+ algo, strength, desc,
+ FLT_FMT_PREC_ARGS(3, milliEach),
+ FLT_FMT_PREC_ARGS(digits, opsSec));
+ }
+ else {
+#ifdef HAVE_GET_CYCLES
+ (void)XSNPRINTF(msg, sizeof(msg),
+ "%-6s %5d %8s %6d %s " FLT_FMT_PREC2 " %s, %s "
+ FLT_FMT_PREC2 " ms, " FLT_FMT_PREC2 " %s, %lu cycles",
+ algo, strength, desc,
+ count, word[0],
+ FLT_FMT_PREC2_ARGS(5, 3, total), word[1], word[2],
+ FLT_FMT_PREC2_ARGS(5, 3, milliEach),
+ FLT_FMT_PREC2_ARGS(digits + 6, digits, opsSec),
+ word[3], (unsigned long)total_cycles);
+#else
+ (void)XSNPRINTF(msg, sizeof(msg),
+ "%-6s %5d %8s %6d %s " FLT_FMT_PREC2 " %s, %s "
+ FLT_FMT_PREC2 " ms, " FLT_FMT_PREC2 " %s",
+ algo, strength, desc,
+ count, word[0],
+ FLT_FMT_PREC2_ARGS(5, 3, total), word[1], word[2],
+ FLT_FMT_PREC2_ARGS(5, 3, milliEach),
+ FLT_FMT_PREC2_ARGS(digits + 6, digits, opsSec),
+ word[3]);
+#endif
+
+#ifdef WOLFSSL_ESPIDF
+ SHOW_ESP_CYCLES_OPS(msg, sizeof(msg));
+#else
+ SHOW_CYCLES_OPS(msg, sizeof(msg));
+#endif
+ }
+
+ printf("%s", msg);
+
+ if (ret < 0) {
+ printf("%sBenchmark %s %s %d failed: %d\n",
+ err_prefix, algo, desc, strength, ret);
+ }
+
+#ifndef WOLFSSL_SGX
+ XFFLUSH(stdout);
+#endif
+
+ (void)ret;
+
+ bench_stats_prepare();
+ TEST_SLEEP();
+} /* bench_stats_ops_finish */
+#endif /* !WC_NO_RNG */
+
#ifdef BENCH_ASYM
#if defined(HAVE_ECC) || !defined(NO_RSA) || !defined(NO_DH) || \
defined(HAVE_CURVE25519) || defined(HAVE_ED25519) || \
@@ -3837,6 +3965,12 @@ static void* benchmarks_do(void* args)
if (bench_all || (bench_other_algs & BENCH_RNG))
bench_rng();
#endif /* WC_NO_RNG */
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \
+ !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ if (bench_all || (bench_other_algs & BENCH_RNG_SHA512))
+ bench_rng_sha512();
+#endif
#ifndef NO_AES
#ifdef HAVE_AES_CBC
if (bench_all || (bench_cipher_algs & BENCH_AES_CBC)) {
@@ -4397,6 +4531,36 @@ static void* benchmarks_do(void* args)
bench_slhdsa(SLHDSA_SHAKE256F);
}
#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S
+ if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_128S) {
+ bench_slhdsa(SLHDSA_SHA2_128S);
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F
+ if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_128F) {
+ bench_slhdsa(SLHDSA_SHA2_128F);
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S
+ if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_192S) {
+ bench_slhdsa(SLHDSA_SHA2_192S);
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F
+ if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_192F) {
+ bench_slhdsa(SLHDSA_SHA2_192F);
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S
+ if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_256S) {
+ bench_slhdsa(SLHDSA_SHA2_256S);
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F
+ if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_256F) {
+ bench_slhdsa(SLHDSA_SHA2_256F);
+ }
+#endif
#endif
#if defined(HAVE_ECC) && !defined(WC_NO_RNG)
@@ -4596,6 +4760,16 @@ static void* benchmarks_do(void* args)
bench_sphincsKeySign(5, SMALL_VARIANT);
#endif
+#ifndef WC_NO_RNG
+ if (bench_all || (bench_other_algs & BENCH_RNG_INIT))
+ bench_rng_init();
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ if (bench_all || (bench_other_algs & BENCH_RNG_SHA512_INIT))
+ bench_rng_sha512_init();
+#endif
+#endif
+
exit:
/* free benchmark buffers */
XFREE(bench_plain, HEAP_HINT, DYNAMIC_TYPE_WOLF_BIGINT);
@@ -4728,6 +4902,19 @@ int benchmark_init(void)
wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT);
#endif
+#if defined(HAVE_FIPS) && FIPS_VERSION3_GE(7,0,0)
+ /* Pre-run all CASTs so their overhead is not captured in benchmark
+ * metrics. Without this, the first use of each algorithm triggers
+ * its CAST on-demand, inflating that algorithm's benchmark numbers. */
+ {
+ int castRet = wc_RunAllCast_fips();
+ if (castRet != 0) {
+ printf("%swc_RunAllCast_fips: %d CAST(s) failed, module in "
+ "DEGRADED mode\n", err_prefix, castRet);
+ }
+ }
+#endif
+
bench_stats_init();
#if defined(DEBUG_WOLFSSL) && !defined(HAVE_VALGRIND)
@@ -4942,6 +5129,21 @@ void bench_rng(void)
WC_RNG myrng;
DECLARE_MULTI_VALUE_STATS_VARS()
+ /* Force SHA-256 DRBG by temporarily disabling SHA-512 DRBG */
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ #if !defined(NO_SHA256)
+ ret = wc_Sha512Drbg_Disable();
+ if (ret != 0) {
+ printf("wc_Sha512Drbg_Disable failed %d\n", ret);
+ return;
+ }
+ #else
+ printf("RNG SHA-256 DRBG (Skipped: Disabled)\n");
+ return;
+ #endif
+#endif
+
bench_stats_prepare();
#ifndef HAVE_FIPS
@@ -4950,7 +5152,11 @@ void bench_rng(void)
ret = wc_InitRng(&myrng);
#endif
if (ret < 0) {
- printf("InitRNG failed %d\n", ret);
+ printf("InitRNG (SHA-256) failed %d\n", ret);
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ wc_Sha512Drbg_Enable();
+#endif
return;
}
@@ -4981,15 +5187,204 @@ void bench_rng(void)
#endif
);
exit_rng:
- bench_stats_sym_finish("RNG", 0, count, bench_size, start, ret);
+ bench_stats_sym_finish("RNG SHA-256 DRBG", 0, count, bench_size, start,
+ ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
wc_FreeRng(&myrng);
+
+ /* Restore SHA-512 DRBG */
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ wc_Sha512Drbg_Enable();
+#endif
}
#endif /* WC_NO_RNG */
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \
+ !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+void bench_rng_sha512(void)
+{
+ int ret, i, count;
+ double start;
+ long pos, len, remain;
+ WC_RNG myrng;
+ DECLARE_MULTI_VALUE_STATS_VARS()
+
+ /* Force SHA-512 DRBG by temporarily disabling SHA-256 DRBG */
+#ifndef NO_SHA256
+ ret = wc_Sha256Drbg_Disable();
+ if (ret != 0) {
+ printf("wc_Sha256Drbg_Disable failed %d\n", ret);
+ return;
+ }
+#endif
+
+ bench_stats_prepare();
+
+#ifndef HAVE_FIPS
+ ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId);
+#else
+ ret = wc_InitRng(&myrng);
+#endif
+ if (ret < 0) {
+ printf("InitRNG (SHA-512) failed %d\n", ret);
+#ifndef NO_SHA256
+ wc_Sha256Drbg_Enable();
+#endif
+ return;
+ }
+
+ bench_stats_start(&count, &start);
+ do {
+ for (i = 0; i < numBlocks; i++) {
+ /* Split request to handle large RNG request */
+ pos = 0;
+ remain = (int)bench_size;
+ while (remain > 0) {
+ len = remain;
+ if (len > RNG_MAX_BLOCK_LEN)
+ len = RNG_MAX_BLOCK_LEN;
+ ret = wc_RNG_GenerateBlock(&myrng, &bench_plain[pos],
+ (word32)len);
+ if (ret < 0)
+ goto exit_rng_sha512;
+
+ remain -= len;
+ pos += len;
+ }
+ RECORD_MULTI_VALUE_STATS();
+ }
+ count += i;
+ } while (bench_stats_check(start)
+#ifdef MULTI_VALUE_STATISTICS
+ || runs < minimum_runs
+#endif
+ );
+exit_rng_sha512:
+ bench_stats_sym_finish("RNG SHA-512 DRBG", 0, count, bench_size, start,
+ ret);
+#ifdef MULTI_VALUE_STATISTICS
+ bench_multi_value_stats(max, min, sum, squareSum, runs);
+#endif
+
+ wc_FreeRng(&myrng);
+
+ /* Restore SHA-256 DRBG */
+#ifndef NO_SHA256
+ wc_Sha256Drbg_Enable();
+#endif
+}
+#endif /* WOLFSSL_DRBG_SHA512 && !WC_NO_RNG && !HAVE_SELFTEST && FIPS v7+ */
+
+#ifndef WC_NO_RNG
+void bench_rng_init(void)
+{
+ int ret, count;
+ double start;
+ WC_RNG myrng;
+ DECLARE_MULTI_VALUE_STATS_VARS()
+
+ /* Force SHA-256 DRBG by temporarily disabling SHA-512 DRBG */
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ #if !defined(NO_SHA256)
+ ret = wc_Sha512Drbg_Disable();
+ if (ret != 0) {
+ printf("wc_Sha512Drbg_Disable failed %d\n", ret);
+ return;
+ }
+ #else
+ printf("RNG SHA-256 Init/Free (Skipped: Disabled)\n");
+ return;
+ #endif
+#endif
+
+ bench_stats_start(&count, &start);
+ do {
+ #ifndef HAVE_FIPS
+ ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId);
+ #else
+ ret = wc_InitRng(&myrng);
+ #endif
+ if (ret < 0) {
+ printf("InitRNG (SHA-256 init bench) failed %d\n", ret);
+ goto exit_rng_init;
+ }
+ wc_FreeRng(&myrng);
+ count++;
+ RECORD_MULTI_VALUE_STATS();
+ } while (bench_stats_check(start)
+#ifdef MULTI_VALUE_STATISTICS
+ || runs < minimum_runs
+#endif
+ );
+exit_rng_init:
+ bench_stats_ops_finish("RNG", 256, "SHA256 Init/Free", count, start, ret);
+#ifdef MULTI_VALUE_STATISTICS
+ bench_multi_value_stats(max, min, sum, squareSum, runs);
+#endif
+
+ /* Restore SHA-512 DRBG */
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ wc_Sha512Drbg_Enable();
+#endif
+}
+
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+void bench_rng_sha512_init(void)
+{
+ int ret, count;
+ double start;
+ WC_RNG myrng;
+ DECLARE_MULTI_VALUE_STATS_VARS()
+
+ /* Force SHA-512 DRBG by temporarily disabling SHA-256 DRBG */
+#ifndef NO_SHA256
+ ret = wc_Sha256Drbg_Disable();
+ if (ret != 0) {
+ printf("wc_Sha256Drbg_Disable failed %d\n", ret);
+ return;
+ }
+#endif
+
+ bench_stats_start(&count, &start);
+ do {
+ #ifndef HAVE_FIPS
+ ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId);
+ #else
+ ret = wc_InitRng(&myrng);
+ #endif
+ if (ret < 0) {
+ printf("InitRNG (SHA-512 init bench) failed %d\n", ret);
+ goto exit_rng_sha512_init;
+ }
+ wc_FreeRng(&myrng);
+ count++;
+ RECORD_MULTI_VALUE_STATS();
+ } while (bench_stats_check(start)
+#ifdef MULTI_VALUE_STATISTICS
+ || runs < minimum_runs
+#endif
+ );
+exit_rng_sha512_init:
+ bench_stats_ops_finish("RNG", 512, "SHA512 Init/Free", count, start, ret);
+#ifdef MULTI_VALUE_STATISTICS
+ bench_multi_value_stats(max, min, sum, squareSum, runs);
+#endif
+
+ /* Restore SHA-256 DRBG */
+#ifndef NO_SHA256
+ wc_Sha256Drbg_Enable();
+#endif
+}
+#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */
+#endif /* !WC_NO_RNG */
#ifndef NO_AES
@@ -10704,6 +11099,7 @@ static void bench_mlkem_encap(int type, const char* name, int keySize,
RESET_MULTI_VALUE_STATS_VARS();
/* MLKEM Decapsulate */
+ PRIVATE_KEY_UNLOCK();
bench_stats_start(&count, &start);
do {
/* while free pending slots in queue, submit ops */
@@ -10721,6 +11117,7 @@ static void bench_mlkem_encap(int type, const char* name, int keySize,
);
exit_decap:
+ PRIVATE_KEY_LOCK();
bench_stats_asym_finish(name, keySize, desc[13], 0, count, start, ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
@@ -11213,6 +11610,13 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub)
case WC_LMS_PARM_L4_H5_W4:
case WC_LMS_PARM_L4_H10_W4:
case WC_LMS_PARM_L4_H10_W8:
+ case WC_LMS_PARM_L1_H25_W1:
+ case WC_LMS_PARM_L1_H25_W2:
+ case WC_LMS_PARM_L1_H25_W4:
+ case WC_LMS_PARM_L1_H25_W8:
+ case WC_LMS_PARM_L1_H10_W1:
+ case WC_LMS_PARM_L1_H15_W1:
+ case WC_LMS_PARM_L1_H20_W1:
#endif
#ifdef WOLFSSL_LMS_SHA256_192
@@ -11236,6 +11640,57 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub)
case WC_LMS_PARM_SHA256_192_L3_H5_W8:
case WC_LMS_PARM_SHA256_192_L3_H10_W4:
case WC_LMS_PARM_SHA256_192_L4_H5_W8:
+ case WC_LMS_PARM_SHA256_192_L1_H25_W1:
+ case WC_LMS_PARM_SHA256_192_L1_H25_W2:
+ case WC_LMS_PARM_SHA256_192_L1_H25_W4:
+ case WC_LMS_PARM_SHA256_192_L1_H25_W8:
+ case WC_LMS_PARM_SHA256_192_L1_H10_W1:
+ case WC_LMS_PARM_SHA256_192_L1_H15_W1:
+ case WC_LMS_PARM_SHA256_192_L1_H20_W1:
+ case WC_LMS_PARM_SHA256_192_L1_H15_W8:
+#endif
+
+#ifdef WOLFSSL_LMS_SHAKE256
+ case WC_LMS_PARM_SHAKE_L1_H5_W1:
+ case WC_LMS_PARM_SHAKE_L1_H5_W2:
+ case WC_LMS_PARM_SHAKE_L1_H5_W4:
+ case WC_LMS_PARM_SHAKE_L1_H5_W8:
+ case WC_LMS_PARM_SHAKE_L1_H10_W1:
+ case WC_LMS_PARM_SHAKE_L1_H10_W2:
+ case WC_LMS_PARM_SHAKE_L1_H10_W4:
+ case WC_LMS_PARM_SHAKE_L1_H10_W8:
+ case WC_LMS_PARM_SHAKE_L1_H15_W1:
+ case WC_LMS_PARM_SHAKE_L1_H15_W2:
+ case WC_LMS_PARM_SHAKE_L1_H15_W4:
+ case WC_LMS_PARM_SHAKE_L1_H15_W8:
+ case WC_LMS_PARM_SHAKE_L1_H20_W1:
+ case WC_LMS_PARM_SHAKE_L1_H20_W2:
+ case WC_LMS_PARM_SHAKE_L1_H20_W4:
+ case WC_LMS_PARM_SHAKE_L1_H20_W8:
+ case WC_LMS_PARM_SHAKE_L1_H25_W1:
+ case WC_LMS_PARM_SHAKE_L1_H25_W2:
+ case WC_LMS_PARM_SHAKE_L1_H25_W4:
+ case WC_LMS_PARM_SHAKE_L1_H25_W8:
+ case WC_LMS_PARM_SHAKE192_L1_H5_W1:
+ case WC_LMS_PARM_SHAKE192_L1_H5_W2:
+ case WC_LMS_PARM_SHAKE192_L1_H5_W4:
+ case WC_LMS_PARM_SHAKE192_L1_H5_W8:
+ case WC_LMS_PARM_SHAKE192_L1_H10_W1:
+ case WC_LMS_PARM_SHAKE192_L1_H10_W2:
+ case WC_LMS_PARM_SHAKE192_L1_H10_W4:
+ case WC_LMS_PARM_SHAKE192_L1_H10_W8:
+ case WC_LMS_PARM_SHAKE192_L1_H15_W1:
+ case WC_LMS_PARM_SHAKE192_L1_H15_W2:
+ case WC_LMS_PARM_SHAKE192_L1_H15_W4:
+ case WC_LMS_PARM_SHAKE192_L1_H15_W8:
+ case WC_LMS_PARM_SHAKE192_L1_H20_W1:
+ case WC_LMS_PARM_SHAKE192_L1_H20_W2:
+ case WC_LMS_PARM_SHAKE192_L1_H20_W4:
+ case WC_LMS_PARM_SHAKE192_L1_H20_W8:
+ case WC_LMS_PARM_SHAKE192_L1_H25_W1:
+ case WC_LMS_PARM_SHAKE192_L1_H25_W2:
+ case WC_LMS_PARM_SHAKE192_L1_H25_W4:
+ case WC_LMS_PARM_SHAKE192_L1_H25_W8:
#endif
default:
@@ -12060,9 +12515,17 @@ void bench_slhdsa(enum SlhDsaParam param)
}
len = wc_SlhDsaKey_PublicSize(key) / 2 * 8;
- XMEMCPY(name, "SLH-DSA-S", 10);
- if ((param & 1) == 1) {
- name[8] = 'F';
+ if (SLHDSA_IS_SHA2(param)) {
+ XMEMCPY(name, "SLH-DSA-SHA2-S", 15);
+ if ((param & 1) == 1) {
+ name[13] = 'F';
+ }
+ }
+ else {
+ XMEMCPY(name, "SLH-DSA-S", 10);
+ if ((param & 1) == 1) {
+ name[8] = 'F';
+ }
}
bench_stats_start(&count, &start);
@@ -12080,6 +12543,7 @@ void bench_slhdsa(enum SlhDsaParam param)
);
bench_stats_asym_finish(name, len, "gen", 0, count, start, ret);
+ PRIVATE_KEY_UNLOCK();
bench_stats_start(&count, &start);
do {
sigLen = WC_SLHDSA_MAX_SIG_LEN;
@@ -12095,6 +12559,7 @@ void bench_slhdsa(enum SlhDsaParam param)
|| runs < minimum_runs
#endif
);
+ PRIVATE_KEY_LOCK();
bench_stats_asym_finish(name, len, "sign", 0, count, start, ret);
outLen = (word32)sizeof(pk);
@@ -12127,6 +12592,78 @@ void bench_slhdsa(enum SlhDsaParam param)
);
bench_stats_asym_finish(name, len, "verify", 0, count, start, ret);
+ /* Internal interface: sign M' directly (no M' construction). */
+ PRIVATE_KEY_UNLOCK();
+ bench_stats_start(&count, &start);
+ do {
+ sigLen = WC_SLHDSA_MAX_SIG_LEN;
+ ret = wc_SlhDsaKey_SignMsgDeterministic(key, msg,
+ (word32)sizeof(msg), sig, &sigLen);
+ if (ret != 0) {
+ goto exit;
+ }
+ count++;
+ RECORD_MULTI_VALUE_STATS();
+ } while (bench_stats_check(start)
+#ifdef MULTI_VALUE_STATISTICS
+ || runs < minimum_runs
+#endif
+ );
+ PRIVATE_KEY_LOCK();
+ bench_stats_asym_finish(name, len, "sign-msg", 0, count, start, ret);
+
+ bench_stats_start(&count, &start);
+ do {
+ ret = wc_SlhDsaKey_VerifyMsg(key_vfy, msg, (word32)sizeof(msg),
+ sig, sigLen);
+ if (ret != 0) {
+ goto exit;
+ }
+ count++;
+ RECORD_MULTI_VALUE_STATS();
+ } while (bench_stats_check(start)
+#ifdef MULTI_VALUE_STATISTICS
+ || runs < minimum_runs
+#endif
+ );
+ bench_stats_asym_finish(name, len, "vrfy-msg", 0, count, start, ret);
+
+ /* Pre-hash interface: hash message, then sign the hash. */
+ PRIVATE_KEY_UNLOCK();
+ bench_stats_start(&count, &start);
+ do {
+ sigLen = WC_SLHDSA_MAX_SIG_LEN;
+ ret = wc_SlhDsaKey_SignHashDeterministic(key, ctx, 0, msg,
+ (word32)sizeof(msg), WC_HASH_TYPE_SHA256, sig, &sigLen);
+ if (ret != 0) {
+ goto exit;
+ }
+ count++;
+ RECORD_MULTI_VALUE_STATS();
+ } while (bench_stats_check(start)
+#ifdef MULTI_VALUE_STATISTICS
+ || runs < minimum_runs
+#endif
+ );
+ PRIVATE_KEY_LOCK();
+ bench_stats_asym_finish(name, len, "sign-pre", 0, count, start, ret);
+
+ bench_stats_start(&count, &start);
+ do {
+ ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg,
+ (word32)sizeof(msg), WC_HASH_TYPE_SHA256, sig, sigLen);
+ if (ret != 0) {
+ goto exit;
+ }
+ count++;
+ RECORD_MULTI_VALUE_STATS();
+ } while (bench_stats_check(start)
+#ifdef MULTI_VALUE_STATISTICS
+ || runs < minimum_runs
+#endif
+ );
+ bench_stats_asym_finish(name, len, "vrfy-pre", 0, count, start, ret);
+
exit:
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
if (key_vfy)
@@ -15515,6 +16052,7 @@ void bench_dilithiumKeySign(byte level)
#elif !defined WOLFSSL_DILITHIUM_NO_SIGN
+ PRIVATE_KEY_UNLOCK();
#ifndef WOLFSSL_NO_ML_DSA_44
if (level == 2) {
ret = wc_dilithium_import_private(bench_dilithium_level2_key,
@@ -15533,6 +16071,7 @@ void bench_dilithiumKeySign(byte level)
sizeof_bench_dilithium_level5_key, key);
}
#endif
+ PRIVATE_KEY_LOCK();
if (ret != 0) {
printf("Failed to load private key\n");
goto out;
diff --git a/wolfcrypt/benchmark/benchmark.h b/wolfcrypt/benchmark/benchmark.h
index dc97fe68379..7b291b25885 100644
--- a/wolfcrypt/benchmark/benchmark.h
+++ b/wolfcrypt/benchmark/benchmark.h
@@ -130,6 +130,13 @@ void bench_sakkeRskGen(void);
void bench_sakkeValidate(void);
void bench_sakke(void);
void bench_rng(void);
+void bench_rng_init(void);
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \
+ !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+void bench_rng_sha512(void);
+void bench_rng_sha512_init(void);
+#endif
void bench_blake2b(void);
void bench_blake2s(void);
void bench_ascon_hash(void);
diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c
index 8d8de5a2cd9..6413dc3ab0a 100644
--- a/wolfcrypt/src/asn.c
+++ b/wolfcrypt/src/asn.c
@@ -4379,6 +4379,12 @@ static word32 SetBitString16Bit(word16 val, byte* output)
#ifndef WOLFSSL_NOSHA3_512
static const byte hashSha3_512hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 10};
#endif /* WOLFSSL_NOSHA3_512 */
+#ifdef WOLFSSL_SHAKE128
+ static const byte hashShake128hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 11};
+#endif /* WOLFSSL_SHAKE128 */
+#ifdef WOLFSSL_SHAKE256
+ static const byte hashShake256hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 12};
+#endif /* WOLFSSL_SHAKE256 */
#endif /* WOLFSSL_SHA3 */
/* hmacType */
@@ -5252,6 +5258,18 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz)
*oidSz = sizeof(hashSha3_512hOid);
break;
#endif /* WOLFSSL_NOSHA3_512 */
+ #ifdef WOLFSSL_SHAKE128
+ case SHAKE128h:
+ oid = hashShake128hOid;
+ *oidSz = sizeof(hashShake128hOid);
+ break;
+ #endif /* WOLFSSL_SHAKE128 */
+ #ifdef WOLFSSL_SHAKE256
+ case SHAKE256h:
+ oid = hashShake256hOid;
+ *oidSz = sizeof(hashShake256hOid);
+ break;
+ #endif /* WOLFSSL_SHAKE256 */
#endif /* WOLFSSL_SHA3 */
default:
break;
diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c
index 69fa1152a91..87c2794a7f3 100644
--- a/wolfcrypt/src/dh.c
+++ b/wolfcrypt/src/dh.c
@@ -1063,6 +1063,11 @@ static int CheckDhLN(word32 modLen, word32 divLen)
if (divLen == 224 || divLen == 256)
ret = 0;
break;
+ /* Per SP 800-56Ar3 Table 2 */
+ case 3072:
+ if (divLen == 256)
+ ret = 0;
+ break;
default:
break;
}
diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c
index 17a2dd8eb50..2dfcba8e414 100644
--- a/wolfcrypt/src/dilithium.c
+++ b/wolfcrypt/src/dilithium.c
@@ -132,6 +132,11 @@
#include
+#if FIPS_VERSION3_GE(2,0,0)
+ /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+ #define FIPS_NO_WRAPPERS
+#endif
+
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
#include
#endif
@@ -734,6 +739,15 @@ static int dilithium_get_hash_oid(int hash, byte* oidBuffer, word32* oidLen)
oid = sha512Oid;
}
else
+#ifndef WOLFSSL_NOSHA512_224
+ if (hash == WC_HASH_TYPE_SHA512_224) {
+ static byte sha512_224Oid[DILITHIUM_HASH_OID_LEN] = {
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05
+ };
+ oid = sha512_224Oid;
+ }
+ else
+#endif
#ifndef WOLFSSL_NOSHA512_256
if (hash == WC_HASH_TYPE_SHA512_256) {
static byte sha512_256Oid[DILITHIUM_HASH_OID_LEN] = {
@@ -9360,7 +9374,7 @@ static void dilithium_make_pub_vec(dilithium_key* key, sword32* t1)
* @return MEMORY_E when memory allocation fails.
* @return Other negative when an error occurs.
*/
-static int dilithium_verify_mu(dilithium_key* key, const byte* mu,
+static int dilithium_verify_with_mu(dilithium_key* key, const byte* mu,
const byte* sig, word32 sigLen, int* res)
{
#ifndef WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM
@@ -9819,7 +9833,7 @@ static int dilithium_verify_ctx_msg(dilithium_key* key, const byte* ctx,
ctx, (byte)ctxLen, msg, msgLen, mu, DILITHIUM_MU_SZ);
}
if (ret == 0) {
- ret = dilithium_verify_mu(key, mu, sig, sigLen, res);
+ ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res);
}
return ret;
@@ -9862,7 +9876,7 @@ static int dilithium_verify_msg(dilithium_key* key, const byte* msg,
mu, DILITHIUM_MU_SZ);
}
if (ret == 0) {
- ret = dilithium_verify_mu(key, mu, sig, sigLen, res);
+ ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res);
}
return ret;
@@ -9917,7 +9931,7 @@ static int dilithium_verify_ctx_hash(dilithium_key* key, const byte* ctx,
ctx, (byte)ctxLen, oidMsgHash, oidMsgHashLen, mu, DILITHIUM_MU_SZ);
}
if (ret == 0) {
- ret = dilithium_verify_mu(key, mu, sig, sigLen, res);
+ ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res);
}
return ret;
@@ -10132,6 +10146,30 @@ int wc_dilithium_make_key(dilithium_key* key, WC_RNG* rng)
#endif
}
+#ifdef HAVE_FIPS
+ /* Pairwise Consistency Test (PCT) per FIPS 140-3 / ISO 19790:2012
+ * Section 7.10.3.3 (TE10.35.02): sign with new sk, verify with pk.
+ * Runs on every key generation. */
+ if (ret == 0) {
+ static const byte pct_msg[] = "wolfSSL ML-DSA PCT";
+ byte pct_sig[DILITHIUM_MAX_SIG_SIZE];
+ word32 pct_sigSz = DILITHIUM_MAX_SIG_SIZE;
+ int pct_res = 0;
+
+ ret = wc_dilithium_sign_msg(pct_msg, sizeof(pct_msg),
+ pct_sig, &pct_sigSz, key, rng);
+
+ if (ret == 0)
+ ret = wc_dilithium_verify_msg(pct_sig, pct_sigSz,
+ pct_msg, sizeof(pct_msg), &pct_res, key);
+
+ if (ret == 0 && pct_res != 1)
+ ret = ML_DSA_PCT_E;
+
+ ForceZero(pct_sig, sizeof(pct_sig));
+ }
+#endif /* HAVE_FIPS */
+
return ret;
}
@@ -10160,6 +10198,9 @@ int wc_dilithium_make_key_from_seed(dilithium_key* key, const byte* seed)
#endif
}
+ /* Note: PCT is performed in wc_dilithium_make_key() which calls this
+ * function and has the RNG parameter needed for signing. */
+
return ret;
}
#endif
@@ -10461,6 +10502,53 @@ int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen,
return ret;
}
+
+/* Sign using the ML-DSA internal interface with a pre-computed mu value.
+ *
+ * This implements ML-DSA.Sign_internal from FIPS 204 Section 6.2.
+ * The caller provides mu directly (already computed from tr||M'), bypassing
+ * the external message hashing step. Used by ACVP internal interface tests.
+ *
+ * mu [in] Pre-computed mu value (64 bytes).
+ * muLen [in] Length of mu in bytes (must be 64).
+ * sig [out] Buffer to write signature into.
+ * sigLen [in/out] On in, size of buffer.
+ * On out, the length of the signature in bytes.
+ * key [in] Dilithium key to use when signing.
+ * seed [in] 32-byte random seed (rnd).
+ * returns BAD_FUNC_ARG when a parameter is NULL or muLen is not 64,
+ * BUFFER_E when sigLen is too small,
+ * 0 otherwise.
+ */
+int wc_dilithium_sign_mu_with_seed(const byte* mu, word32 muLen,
+ byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed)
+{
+ int ret = 0;
+
+ /* Validate parameters. */
+ if ((mu == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL) ||
+ (seed == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ if ((ret == 0) && (muLen != DILITHIUM_MU_SZ)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ #ifdef WOLFSSL_WC_DILITHIUM
+ /* Build [seed||mu] buffer and call internal sign function. */
+ byte seedMu[DILITHIUM_RND_SZ + DILITHIUM_MU_SZ];
+ XMEMCPY(seedMu, seed, DILITHIUM_RND_SZ);
+ XMEMCPY(seedMu + DILITHIUM_RND_SZ, mu, DILITHIUM_MU_SZ);
+ ret = dilithium_sign_with_seed_mu(key, seedMu, sig, sigLen);
+ #elif defined(HAVE_LIBOQS)
+ ret = NOT_COMPILED_IN;
+ (void)muLen;
+ #endif
+ }
+
+ return ret;
+}
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN */
#ifndef WOLFSSL_DILITHIUM_NO_VERIFY
@@ -10636,6 +10724,47 @@ int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen,
return ret;
}
+
+/* Verify using the ML-DSA internal interface with a pre-computed mu value.
+ *
+ * This implements ML-DSA.Verify_internal from FIPS 204 Section 6.3.
+ * The caller provides mu directly (already computed from tr||M'), bypassing
+ * the external message hashing step. Used by ACVP internal interface tests.
+ *
+ * sig [in] Signature to verify.
+ * sigLen [in] Size of signature in bytes.
+ * mu [in] Pre-computed mu value (64 bytes).
+ * muLen [in] Length of mu in bytes (must be 64).
+ * res [out] *res is set to 1 on successful verification.
+ * key [in] Dilithium key to use to verify.
+ * returns BAD_FUNC_ARG when a parameter is NULL or muLen is not 64,
+ * 0 otherwise.
+ */
+int wc_dilithium_verify_mu(const byte* sig, word32 sigLen, const byte* mu,
+ word32 muLen, int* res, dilithium_key* key)
+{
+ int ret = 0;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (sig == NULL) || (mu == NULL) || (res == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ if ((ret == 0) && (muLen != DILITHIUM_MU_SZ)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ #ifdef WOLFSSL_WC_DILITHIUM
+ ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res);
+ #elif defined(HAVE_LIBOQS)
+ ret = NOT_COMPILED_IN;
+ (void)sigLen;
+ (void)muLen;
+ #endif
+ }
+
+ return ret;
+}
#endif /* WOLFSSL_DILITHIUM_NO_VERIFY */
#ifndef WC_NO_CONSTRUCTORS
diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c
index 431a3c996c0..edc6a43e303 100644
--- a/wolfcrypt/src/error.c
+++ b/wolfcrypt/src/error.c
@@ -665,6 +665,30 @@ const char* wc_GetErrorString(int error)
case ALREADY_E:
return "Operation was redundant or preempted";
+ case ML_KEM_KAT_FIPS_E:
+ return "wolfCrypt FIPS ML-KEM Known Answer Test Failure";
+
+ case ML_DSA_KAT_FIPS_E:
+ return "wolfCrypt FIPS ML-DSA Known Answer Test Failure";
+
+ case LMS_KAT_FIPS_E:
+ return "wolfCrypt FIPS LMS Known Answer Test Failure";
+
+ case XMSS_KAT_FIPS_E:
+ return "wolfCrypt FIPS XMSS Known Answer Test Failure";
+
+ case ML_KEM_PCT_E:
+ return "wolfcrypt ML-KEM Pairwise Consistency Test Failure";
+
+ case ML_DSA_PCT_E:
+ return "wolfcrypt ML-DSA Pairwise Consistency Test Failure";
+
+ case DRBG_SHA512_KAT_FIPS_E:
+ return "SHA-512 DRBG Known Answer Test check FIPS error";
+
+ case SLH_DSA_KAT_FIPS_E:
+ return "SLH-DSA Known Answer Test check FIPS error";
+
case SEQ_OVERFLOW_E:
return "Sequence counter would overflow";
diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c
index 02fe3fa49bc..0d88776767c 100644
--- a/wolfcrypt/src/evp.c
+++ b/wolfcrypt/src/evp.c
@@ -5764,8 +5764,8 @@ void wolfSSL_EVP_init(void)
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
- defined(WOLFSSL_SHA512)
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512)
ret = wc_Sha512_224Copy((wc_Sha512*)&src->hash.digest,
(wc_Sha512*)&des->hash.digest);
#else
@@ -5775,8 +5775,8 @@ void wolfSSL_EVP_init(void)
#endif /* !WOLFSSL_NOSHA512_224 */
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
- defined(WOLFSSL_SHA512)
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512)
ret = wc_Sha512_256Copy((wc_Sha512*)&src->hash.digest,
(wc_Sha512*)&des->hash.digest);
#else
@@ -10702,16 +10702,16 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
- defined(WOLFSSL_SHA512)
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512)
wc_Sha512_224Free((wc_Sha512*)&ctx->hash.digest);
#endif
break;
#endif /* !WOLFSSL_NOSHA512_224 */
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
- defined(WOLFSSL_SHA512)
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512)
wc_Sha512_256Free((wc_Sha512*)&ctx->hash.digest);
#endif
break;
@@ -10812,13 +10812,15 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
ret = wolfSSL_SHA384_Init(&(ctx->hash.digest.sha384));
} else
#endif
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && \
defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
if (XSTRCMP(md, WC_SN_sha512_224) == 0) {
ret = wolfSSL_SHA512_224_Init(&(ctx->hash.digest.sha512));
} else
#endif
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && \
defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256)
if (XSTRCMP(md, WC_SN_sha512_256) == 0) {
ret = wolfSSL_SHA512_256_Init(&(ctx->hash.digest.sha512));
@@ -10969,8 +10971,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
- defined(WOLFSSL_SHA512)
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512)
ret = wolfSSL_SHA512_224_Update((WOLFSSL_SHA512_CTX*)&ctx->hash, data,
(unsigned long)sz);
#endif
@@ -10979,8 +10981,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
- defined(WOLFSSL_SHA512)
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512)
ret = wolfSSL_SHA512_256_Update((WOLFSSL_SHA512_CTX*)&ctx->hash, data,
(unsigned long)sz);
#endif /* WOLFSSL_SHA512 */
@@ -11123,8 +11125,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
- defined(WOLFSSL_SHA512)
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512)
ret = wolfSSL_SHA512_224_Final(md, (WOLFSSL_SHA512_CTX*)&ctx->hash);
if (s) *s = WC_SHA512_224_DIGEST_SIZE;
#endif
@@ -11132,8 +11134,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
#endif /* !WOLFSSL_NOSHA512_224 */
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
- #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \
- defined(WOLFSSL_SHA512)
+ #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
+ !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512)
ret = wolfSSL_SHA512_256_Final(md, (WOLFSSL_SHA512_CTX*)&ctx->hash);
if (s) *s = WC_SHA512_256_DIGEST_SIZE;
#endif
diff --git a/wolfcrypt/src/ext_mlkem.c b/wolfcrypt/src/ext_mlkem.c
index 91634f494f2..90ffbb1662d 100644
--- a/wolfcrypt/src/ext_mlkem.c
+++ b/wolfcrypt/src/ext_mlkem.c
@@ -22,6 +22,12 @@
#include
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_WC_MLKEM)
+
+#if FIPS_VERSION3_GE(2,0,0)
+ /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+ #define FIPS_NO_WRAPPERS
+#endif
+
#include
#ifdef NO_INLINE
diff --git a/wolfcrypt/src/hash.c b/wolfcrypt/src/hash.c
index 61f7aacd632..cf345c8a28f 100644
--- a/wolfcrypt/src/hash.c
+++ b/wolfcrypt/src/hash.c
@@ -335,20 +335,20 @@ int wc_HashGetDigestSize(enum wc_HashType hash_type)
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
dig_size = WC_SHA512_224_DIGEST_SIZE;
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256)
dig_size = WC_SHA512_256_DIGEST_SIZE;
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
case WC_HASH_TYPE_MD5_SHA: /* Old TLS Specific */
@@ -390,13 +390,18 @@ int wc_HashGetDigestSize(enum wc_HashType hash_type)
break;
#endif
- /* Not Supported */
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
case WC_HASH_TYPE_SHAKE128:
+ dig_size = 32; /* SHAKE-128: 256-bit output */
+ break;
#endif
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
case WC_HASH_TYPE_SHAKE256:
+ dig_size = 64; /* SHAKE-256: 512-bit output */
+ break;
#endif
+
+ /* Not Supported */
case WC_HASH_TYPE_NONE:
default:
dig_size = BAD_FUNC_ARG;
@@ -454,20 +459,20 @@ int wc_HashGetBlockSize(enum wc_HashType hash_type)
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
block_size = WC_SHA512_224_BLOCK_SIZE;
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256)
block_size = WC_SHA512_256_BLOCK_SIZE;
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
case WC_HASH_TYPE_MD5_SHA: /* Old TLS Specific */
@@ -509,13 +514,18 @@ int wc_HashGetBlockSize(enum wc_HashType hash_type)
break;
#endif
- /* Not Supported */
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
case WC_HASH_TYPE_SHAKE128:
+ block_size = WC_SHA3_128_BLOCK_SIZE;
+ break;
#endif
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
case WC_HASH_TYPE_SHAKE256:
+ block_size = WC_SHA3_256_BLOCK_SIZE;
+ break;
#endif
+
+ /* Not Supported */
case WC_HASH_TYPE_NONE:
default:
block_size = BAD_FUNC_ARG;
@@ -581,20 +591,20 @@ int wc_Hash_ex(enum wc_HashType hash_type, const byte* data,
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
ret = wc_Sha512_224Hash_ex(data, data_len, hash, heap, devId);
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
-#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
+#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256)
ret = wc_Sha512_256Hash_ex(data, data_len, hash, heap, devId);
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
case WC_HASH_TYPE_MD5_SHA:
@@ -634,17 +644,40 @@ int wc_Hash_ex(enum wc_HashType hash_type, const byte* data,
break;
#endif
- /* Not Supported */
- case WC_HASH_TYPE_MD2:
- case WC_HASH_TYPE_MD4:
- case WC_HASH_TYPE_BLAKE2B:
- case WC_HASH_TYPE_BLAKE2S:
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
case WC_HASH_TYPE_SHAKE128:
+ {
+ wc_Shake shake;
+ ret = wc_InitShake128(&shake, heap, devId);
+ if (ret == 0) {
+ ret = wc_Shake128_Update(&shake, data, data_len);
+ if (ret == 0)
+ ret = wc_Shake128_Final(&shake, hash, 32);
+ wc_Shake128_Free(&shake);
+ }
+ break;
+ }
#endif
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
case WC_HASH_TYPE_SHAKE256:
+ {
+ wc_Shake shake;
+ ret = wc_InitShake256(&shake, heap, devId);
+ if (ret == 0) {
+ ret = wc_Shake256_Update(&shake, data, data_len);
+ if (ret == 0)
+ ret = wc_Shake256_Final(&shake, hash, 64);
+ wc_Shake256_Free(&shake);
+ }
+ break;
+ }
#endif
+
+ /* Not Supported */
+ case WC_HASH_TYPE_MD2:
+ case WC_HASH_TYPE_MD4:
+ case WC_HASH_TYPE_BLAKE2B:
+ case WC_HASH_TYPE_BLAKE2S:
case WC_HASH_TYPE_NONE:
default:
ret = BAD_FUNC_ARG;
@@ -746,20 +779,20 @@ int wc_HashInit_ex(wc_HashAlg* hash, enum wc_HashType type, void* heap,
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
ret = wc_InitSha512_224_ex(&hash->alg.sha512, heap, devId);
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256)
ret = wc_InitSha512_256_ex(&hash->alg.sha512, heap, devId);
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
case WC_HASH_TYPE_SHA3_224:
@@ -789,18 +822,23 @@ int wc_HashInit_ex(wc_HashAlg* hash, enum wc_HashType type, void* heap,
break;
#endif
- /* not supported */
- case WC_HASH_TYPE_MD5_SHA:
- case WC_HASH_TYPE_MD2:
- case WC_HASH_TYPE_MD4:
- case WC_HASH_TYPE_BLAKE2B:
- case WC_HASH_TYPE_BLAKE2S:
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
case WC_HASH_TYPE_SHAKE128:
+ ret = wc_InitShake128(&hash->alg.sha3, heap, devId);
+ break;
#endif
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
case WC_HASH_TYPE_SHAKE256:
+ ret = wc_InitShake256(&hash->alg.sha3, heap, devId);
+ break;
#endif
+
+ /* not supported */
+ case WC_HASH_TYPE_MD5_SHA:
+ case WC_HASH_TYPE_MD2:
+ case WC_HASH_TYPE_MD4:
+ case WC_HASH_TYPE_BLAKE2B:
+ case WC_HASH_TYPE_BLAKE2S:
case WC_HASH_TYPE_NONE:
default:
ret = BAD_FUNC_ARG;
@@ -864,20 +902,20 @@ int wc_HashUpdate(wc_HashAlg* hash, enum wc_HashType type, const byte* data,
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
ret = wc_Sha512_224Update(&hash->alg.sha512, data, dataSz);
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256)
ret = wc_Sha512_256Update(&hash->alg.sha512, data, dataSz);
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
case WC_HASH_TYPE_SHA3_224:
@@ -907,18 +945,23 @@ int wc_HashUpdate(wc_HashAlg* hash, enum wc_HashType type, const byte* data,
break;
#endif
- /* not supported */
- case WC_HASH_TYPE_MD5_SHA:
- case WC_HASH_TYPE_MD2:
- case WC_HASH_TYPE_MD4:
- case WC_HASH_TYPE_BLAKE2B:
- case WC_HASH_TYPE_BLAKE2S:
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
case WC_HASH_TYPE_SHAKE128:
+ ret = wc_Shake128_Update(&hash->alg.sha3, data, dataSz);
+ break;
#endif
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
case WC_HASH_TYPE_SHAKE256:
+ ret = wc_Shake256_Update(&hash->alg.sha3, data, dataSz);
+ break;
#endif
+
+ /* not supported */
+ case WC_HASH_TYPE_MD5_SHA:
+ case WC_HASH_TYPE_MD2:
+ case WC_HASH_TYPE_MD4:
+ case WC_HASH_TYPE_BLAKE2B:
+ case WC_HASH_TYPE_BLAKE2S:
case WC_HASH_TYPE_NONE:
default:
ret = BAD_FUNC_ARG;
@@ -974,20 +1017,20 @@ int wc_HashFinal(wc_HashAlg* hash, enum wc_HashType type, byte* out)
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
ret = wc_Sha512_224Final(&hash->alg.sha512, out);
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256)
ret = wc_Sha512_256Final(&hash->alg.sha512, out);
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
case WC_HASH_TYPE_SHA3_224:
@@ -1017,18 +1060,23 @@ int wc_HashFinal(wc_HashAlg* hash, enum wc_HashType type, byte* out)
break;
#endif
- /* not supported */
- case WC_HASH_TYPE_MD5_SHA:
- case WC_HASH_TYPE_MD2:
- case WC_HASH_TYPE_MD4:
- case WC_HASH_TYPE_BLAKE2B:
- case WC_HASH_TYPE_BLAKE2S:
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
case WC_HASH_TYPE_SHAKE128:
+ ret = wc_Shake128_Final(&hash->alg.sha3, out, 32);
+ break;
#endif
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
case WC_HASH_TYPE_SHAKE256:
+ ret = wc_Shake256_Final(&hash->alg.sha3, out, 64);
+ break;
#endif
+
+ /* not supported */
+ case WC_HASH_TYPE_MD5_SHA:
+ case WC_HASH_TYPE_MD2:
+ case WC_HASH_TYPE_MD4:
+ case WC_HASH_TYPE_BLAKE2B:
+ case WC_HASH_TYPE_BLAKE2S:
case WC_HASH_TYPE_NONE:
default:
ret = BAD_FUNC_ARG;
@@ -1090,22 +1138,22 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type)
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224)
wc_Sha512_224Free(&hash->alg.sha512);
ret = 0;
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256)
wc_Sha512_256Free(&hash->alg.sha512);
ret = 0;
#endif
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif
break;
#endif
case WC_HASH_TYPE_SHA3_224:
@@ -1140,18 +1188,25 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type)
break;
#endif
- /* not supported */
- case WC_HASH_TYPE_MD5_SHA:
- case WC_HASH_TYPE_MD2:
- case WC_HASH_TYPE_MD4:
- case WC_HASH_TYPE_BLAKE2B:
- case WC_HASH_TYPE_BLAKE2S:
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
case WC_HASH_TYPE_SHAKE128:
+ wc_Shake128_Free(&hash->alg.sha3);
+ ret = 0;
+ break;
#endif
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
case WC_HASH_TYPE_SHAKE256:
+ wc_Shake256_Free(&hash->alg.sha3);
+ ret = 0;
+ break;
#endif
+
+ /* not supported */
+ case WC_HASH_TYPE_MD5_SHA:
+ case WC_HASH_TYPE_MD2:
+ case WC_HASH_TYPE_MD4:
+ case WC_HASH_TYPE_BLAKE2B:
+ case WC_HASH_TYPE_BLAKE2S:
case WC_HASH_TYPE_NONE:
default:
ret = BAD_FUNC_ARG;
@@ -1210,6 +1265,12 @@ int wc_HashSetFlags(wc_HashAlg* hash, enum wc_HashType type, word32 flags)
case WC_HASH_TYPE_SHA3_256:
case WC_HASH_TYPE_SHA3_384:
case WC_HASH_TYPE_SHA3_512:
+ #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
+ case WC_HASH_TYPE_SHAKE128:
+ #endif
+ #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
+ case WC_HASH_TYPE_SHAKE256:
+ #endif
#ifdef WOLFSSL_SHA3
ret = wc_Sha3_SetFlags(&hash->alg.sha3, flags);
#endif
@@ -1228,12 +1289,6 @@ int wc_HashSetFlags(wc_HashAlg* hash, enum wc_HashType type, word32 flags)
case WC_HASH_TYPE_BLAKE2B:
case WC_HASH_TYPE_BLAKE2S:
case WC_HASH_TYPE_NONE:
- #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
- case WC_HASH_TYPE_SHAKE128:
- #endif
- #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
- case WC_HASH_TYPE_SHAKE256:
- #endif
default:
ret = BAD_FUNC_ARG;
};
@@ -1289,6 +1344,12 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags)
case WC_HASH_TYPE_SHA3_256:
case WC_HASH_TYPE_SHA3_384:
case WC_HASH_TYPE_SHA3_512:
+ #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
+ case WC_HASH_TYPE_SHAKE128:
+ #endif
+ #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
+ case WC_HASH_TYPE_SHAKE256:
+ #endif
#ifdef WOLFSSL_SHA3
ret = wc_Sha3_GetFlags(&hash->alg.sha3, flags);
#endif
@@ -1306,12 +1367,6 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags)
case WC_HASH_TYPE_MD4:
case WC_HASH_TYPE_BLAKE2B:
case WC_HASH_TYPE_BLAKE2S:
- #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
- case WC_HASH_TYPE_SHAKE128:
- #endif
- #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
- case WC_HASH_TYPE_SHAKE256:
- #endif
case WC_HASH_TYPE_NONE:
default:
ret = BAD_FUNC_ARG;
@@ -1536,7 +1591,7 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags)
#endif
return wc_Sha512Hash_ex(data, len, hash, NULL, devId);
}
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#ifndef WOLFSSL_NOSHA512_224
int wc_Sha512_224Hash_ex(const byte* data, word32 len, byte* hash,
void* heap, int devId)
@@ -1576,9 +1631,9 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags)
return wc_Sha512_224Hash_ex(data, len, hash, NULL, devId);
}
#endif /* !WOLFSSL_NOSHA512_224 */
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif /* !HAVE_FIPS || FIPS v7+ */
-#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#ifndef WOLFSSL_NOSHA512_256
int wc_Sha512_256Hash_ex(const byte* data, word32 len, byte* hash,
void* heap, int devId)
@@ -1618,7 +1673,7 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags)
return wc_Sha512_256Hash_ex(data, len, hash, NULL, devId);
}
#endif /* !WOLFSSL_NOSHA512_256 */
-#endif /* !HAVE_FIPS && !HAVE_SELFTEST */
+#endif /* !HAVE_FIPS || FIPS v7+ */
#endif /* WOLFSSL_SHA512 */
diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c
index 4b3cfd15890..5489a490aa4 100644
--- a/wolfcrypt/src/hmac.c
+++ b/wolfcrypt/src/hmac.c
@@ -87,6 +87,12 @@ int wc_HmacSizeByType(int type)
if (!(type == WC_MD5 || type == WC_SHA ||
#ifdef WOLFSSL_SM3
type == WC_SM3 ||
+ #endif
+ #ifndef WOLFSSL_NOSHA512_224
+ type == WC_SHA512_224 ||
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ type == WC_SHA512_256 ||
#endif
type == WC_SHA224 || type == WC_SHA256 ||
type == WC_SHA384 || type == WC_SHA512 ||
@@ -129,6 +135,16 @@ int wc_HmacSizeByType(int type)
case WC_SHA512:
ret = WC_SHA512_DIGEST_SIZE;
break;
+ #ifndef WOLFSSL_NOSHA512_224
+ case WC_SHA512_224:
+ ret = WC_SHA512_224_DIGEST_SIZE;
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ case WC_SHA512_256:
+ ret = WC_SHA512_256_DIGEST_SIZE;
+ break;
+ #endif
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
@@ -201,6 +217,16 @@ static int HmacKeyInitHash(wc_HmacHash* hash, int type, void* heap, int devId)
case WC_SHA512:
ret = wc_InitSha512_ex(&hash->sha512, heap, devId);
break;
+ #ifndef WOLFSSL_NOSHA512_224
+ case WC_SHA512_224:
+ ret = wc_InitSha512_224_ex(&hash->sha512, heap, devId);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ case WC_SHA512_256:
+ ret = wc_InitSha512_256_ex(&hash->sha512, heap, devId);
+ break;
+ #endif
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
@@ -300,6 +326,16 @@ static int HmacKeyCopyHash(byte macType, wc_HmacHash* src, wc_HmacHash* dst)
case WC_SHA512:
ret = wc_Sha512Copy(&src->sha512, &dst->sha512);
break;
+ #ifndef WOLFSSL_NOSHA512_224
+ case WC_SHA512_224:
+ ret = wc_Sha512_224Copy(&src->sha512, &dst->sha512);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ case WC_SHA512_256:
+ ret = wc_Sha512_256Copy(&src->sha512, &dst->sha512);
+ break;
+ #endif
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
@@ -395,6 +431,18 @@ static int HmacKeyHashUpdate(byte macType, wc_HmacHash* hash, byte* pad)
case WC_SHA512:
ret = wc_Sha512Update(&hash->sha512, pad, WC_SHA512_BLOCK_SIZE);
break;
+ #ifndef WOLFSSL_NOSHA512_224
+ case WC_SHA512_224:
+ ret = wc_Sha512_224Update(&hash->sha512, pad,
+ WC_SHA512_224_BLOCK_SIZE);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ case WC_SHA512_256:
+ ret = wc_Sha512_256Update(&hash->sha512, pad,
+ WC_SHA512_256_BLOCK_SIZE);
+ break;
+ #endif
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
@@ -475,6 +523,12 @@ int wc_HmacSetKey_ex(Hmac* hmac, int type, const byte* key, word32 length,
!(type == WC_MD5 || type == WC_SHA ||
#ifdef WOLFSSL_SM3
type == WC_SM3 ||
+ #endif
+ #ifndef WOLFSSL_NOSHA512_224
+ type == WC_SHA512_224 ||
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ type == WC_SHA512_256 ||
#endif
type == WC_SHA224 || type == WC_SHA256 ||
type == WC_SHA384 || type == WC_SHA512 ||
@@ -731,6 +785,46 @@ int wc_HmacSetKey_ex(Hmac* hmac, int type, const byte* key, word32 length,
length = WC_SHA512_DIGEST_SIZE;
}
break;
+ #ifndef WOLFSSL_NOSHA512_224
+ case WC_SHA512_224:
+ hmac_block_size = WC_SHA512_224_BLOCK_SIZE;
+ if (length <= WC_SHA512_224_BLOCK_SIZE) {
+ if (key != NULL) {
+ XMEMCPY(ip, key, length);
+ }
+ }
+ else {
+ ret = wc_Sha512_224Update(&hmac->hash.sha512, key, length);
+ if (ret != 0)
+ break;
+ ret = wc_Sha512_224Final(&hmac->hash.sha512, ip);
+ if (ret != 0)
+ break;
+
+ length = WC_SHA512_224_DIGEST_SIZE;
+ }
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ case WC_SHA512_256:
+ hmac_block_size = WC_SHA512_256_BLOCK_SIZE;
+ if (length <= WC_SHA512_256_BLOCK_SIZE) {
+ if (key != NULL) {
+ XMEMCPY(ip, key, length);
+ }
+ }
+ else {
+ ret = wc_Sha512_256Update(&hmac->hash.sha512, key, length);
+ if (ret != 0)
+ break;
+ ret = wc_Sha512_256Final(&hmac->hash.sha512, ip);
+ if (ret != 0)
+ break;
+
+ length = WC_SHA512_256_DIGEST_SIZE;
+ }
+ break;
+ #endif
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
@@ -983,6 +1077,16 @@ int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
case WC_SHA512:
ret = wc_Sha512Update(&hmac->hash.sha512, msg, length);
break;
+ #ifndef WOLFSSL_NOSHA512_224
+ case WC_SHA512_224:
+ ret = wc_Sha512_224Update(&hmac->hash.sha512, msg, length);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ case WC_SHA512_256:
+ ret = wc_Sha512_256Update(&hmac->hash.sha512, msg, length);
+ break;
+ #endif
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
@@ -1210,6 +1314,48 @@ int wc_HmacFinal(Hmac* hmac, byte* hash)
break;
ret = wc_Sha512Final(&hmac->hash.sha512, hash);
break;
+ #ifndef WOLFSSL_NOSHA512_224
+ case WC_SHA512_224:
+ ret = wc_Sha512_224Final(&hmac->hash.sha512,
+ (byte*)hmac->innerHash);
+ if (ret != 0)
+ break;
+ #ifndef WOLFSSL_HMAC_COPY_HASH
+ ret = wc_Sha512_224Update(&hmac->hash.sha512, (byte*)hmac->opad,
+ WC_SHA512_224_BLOCK_SIZE);
+ #else
+ ret = HmacKeyCopyHash(WC_SHA512_224, &hmac->o_hash, &hmac->hash);
+ #endif
+ if (ret != 0)
+ break;
+ ret = wc_Sha512_224Update(&hmac->hash.sha512,
+ (byte*)hmac->innerHash, WC_SHA512_224_DIGEST_SIZE);
+ if (ret != 0)
+ break;
+ ret = wc_Sha512_224Final(&hmac->hash.sha512, hash);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ case WC_SHA512_256:
+ ret = wc_Sha512_256Final(&hmac->hash.sha512,
+ (byte*)hmac->innerHash);
+ if (ret != 0)
+ break;
+ #ifndef WOLFSSL_HMAC_COPY_HASH
+ ret = wc_Sha512_256Update(&hmac->hash.sha512, (byte*)hmac->opad,
+ WC_SHA512_256_BLOCK_SIZE);
+ #else
+ ret = HmacKeyCopyHash(WC_SHA512_256, &hmac->o_hash, &hmac->hash);
+ #endif
+ if (ret != 0)
+ break;
+ ret = wc_Sha512_256Update(&hmac->hash.sha512,
+ (byte*)hmac->innerHash, WC_SHA512_256_DIGEST_SIZE);
+ if (ret != 0)
+ break;
+ ret = wc_Sha512_256Final(&hmac->hash.sha512, hash);
+ break;
+ #endif
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
@@ -1489,6 +1635,24 @@ void wc_HmacFree(Hmac* hmac)
wc_Sha512Free(&hmac->o_hash.sha512);
#endif
break;
+ #ifndef WOLFSSL_NOSHA512_224
+ case WC_SHA512_224:
+ wc_Sha512_224Free(&hmac->hash.sha512);
+ #ifdef WOLFSSL_HMAC_COPY_HASH
+ wc_Sha512_224Free(&hmac->i_hash.sha512);
+ wc_Sha512_224Free(&hmac->o_hash.sha512);
+ #endif
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA512_256
+ case WC_SHA512_256:
+ wc_Sha512_256Free(&hmac->hash.sha512);
+ #ifdef WOLFSSL_HMAC_COPY_HASH
+ wc_Sha512_256Free(&hmac->i_hash.sha512);
+ wc_Sha512_256Free(&hmac->o_hash.sha512);
+ #endif
+ break;
+ #endif
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c
index 9fa318c7608..c75f89a5060 100644
--- a/wolfcrypt/src/random.c
+++ b/wolfcrypt/src/random.c
@@ -133,7 +133,12 @@ This library contains implementation for the random number generator.
#ifndef WC_NO_RNG /* if not FIPS and RNG is disabled then do not compile */
-#include
+#ifndef NO_SHA256
+ #include
+#endif
+#ifdef WOLFSSL_DRBG_SHA512
+ #include
+#endif
#ifdef WOLF_CRYPTO_CB
#include
@@ -332,16 +337,60 @@ enum {
drbgInitV = 4
};
+#ifndef NO_SHA256
typedef struct DRBG_internal DRBG_internal;
+#endif
+
+#ifdef WOLFSSL_DRBG_SHA512
+typedef struct DRBG_SHA512_internal DRBG_SHA512_internal;
+
+static int Hash512_DRBG_Reseed(DRBG_SHA512_internal* drbg, const byte* seed,
+ word32 seedSz,
+ const byte* additional, word32 additionalSz);
+static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out,
+ word32 outSz,
+ const byte* additional, word32 additionalSz);
+static int Hash512_DRBG_Instantiate(DRBG_SHA512_internal* drbg,
+ const byte* seed, word32 seedSz,
+ const byte* nonce, word32 nonceSz,
+ const byte* perso, word32 persoSz,
+ void* heap, int devId);
+static int Hash512_DRBG_Uninstantiate(DRBG_SHA512_internal* drbg);
+#endif
+
+/* Runtime DRBG disable state */
+#ifndef NO_SHA256
+#ifdef WOLFSSL_NO_SHA256_DRBG
+static int sha256DrbgDisabled = 1;
+#else
+static int sha256DrbgDisabled = 0;
+#endif
+#endif
+#ifdef WOLFSSL_DRBG_SHA512
+static int sha512DrbgDisabled = 0;
+#endif
static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap,
int devId);
+#ifdef WOLFSSL_DRBG_SHA512
+static int wc_RNG_HealthTest_SHA512_ex_internal(DRBG_SHA512_internal* drbg,
+ int reseed, const byte* nonce, word32 nonceSz,
+ const byte* perso, word32 persoSz,
+ const byte* seedA, word32 seedASz,
+ const byte* seedB, word32 seedBSz,
+ const byte* additionalA, word32 additionalASz,
+ const byte* additionalB, word32 additionalBSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId);
+#endif
+
/* Hash Derivation Function */
/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type,
const byte* inA, word32 inASz,
- const byte* inB, word32 inBSz)
+ const byte* inB, word32 inBSz,
+ const byte* inC, word32 inCSz)
{
int ret = DRBG_FAILURE;
byte ctr;
@@ -406,6 +455,10 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type,
if (inB != NULL && inBSz > 0)
ret = wc_Sha256Update(sha, inB, inBSz);
}
+ if (ret == 0) {
+ if (inC != NULL && inCSz > 0)
+ ret = wc_Sha256Update(sha, inC, inCSz);
+ }
if (ret == 0)
ret = wc_Sha256Final(sha, digest);
@@ -440,7 +493,8 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type,
}
/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
-static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz)
+static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz,
+ const byte* additional, word32 additionalSz)
{
int ret;
WC_DECLARE_VAR(newV, byte, DRBG_SEED_LEN, 0);
@@ -458,13 +512,14 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz
XMEMSET(newV, 0, DRBG_SEED_LEN);
ret = Hash_df(drbg, newV, DRBG_SEED_LEN, drbgReseed,
- drbg->V, sizeof(drbg->V), seed, seedSz);
+ drbg->V, sizeof(drbg->V), seed, seedSz,
+ additional, additionalSz);
if (ret == DRBG_SUCCESS) {
XMEMCPY(drbg->V, newV, sizeof(drbg->V));
ForceZero(newV, DRBG_SEED_LEN);
ret = Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V,
- sizeof(drbg->V), NULL, 0);
+ sizeof(drbg->V), NULL, 0, NULL, 0);
}
if (ret == DRBG_SUCCESS) {
drbg->reseedCtr = 1;
@@ -490,17 +545,31 @@ int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz)
return BAD_FUNC_ARG;
}
- if (rng->drbg == NULL) {
- #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND)
- if (IS_INTEL_RDRAND(intel_flags)) {
- /* using RDRAND not DRBG, so return success */
- return 0;
- }
- return BAD_FUNC_ARG;
- #endif
+#ifdef HAVE_INTEL_RDRAND
+ if (IS_INTEL_RDRAND(intel_flags)) {
+ /* using RDRAND not DRBG, so return success */
+ return 0;
}
+#endif
- return Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, seed, seedSz);
+#ifndef NO_SHA256
+ if (rng->drbgType == WC_DRBG_SHA256) {
+ if (rng->drbg == NULL)
+ return BAD_FUNC_ARG;
+ return Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, seed, seedSz,
+ NULL, 0);
+ }
+#endif
+#ifdef WOLFSSL_DRBG_SHA512
+ if (rng->drbgType == WC_DRBG_SHA512) {
+ if (rng->drbg512 == NULL)
+ return BAD_FUNC_ARG;
+ return Hash512_DRBG_Reseed((DRBG_SHA512_internal *)rng->drbg512,
+ seed, seedSz, NULL, 0);
+ }
+#endif
+
+ return BAD_FUNC_ARG;
}
static WC_INLINE void array_add_one(byte* data, word32 dataSz)
@@ -638,7 +707,8 @@ static WC_INLINE void array_add(byte* d, word32 dLen, const byte* s, word32 sLen
}
/* Returns: DRBG_SUCCESS, DRBG_NEED_RESEED, or DRBG_FAILURE */
-static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz)
+static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz,
+ const byte* additional, word32 additionalSz)
{
int ret;
#ifdef WOLFSSL_SMALL_STACK_CACHE
@@ -680,6 +750,49 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz)
type = drbgGenerateH;
reseedCtr = drbg->reseedCtr;
+ /* SP 800-90A 10.1.1.4 step 2: if additional_input != Null,
+ * w = Hash(0x02 || V || additional_input), V = (V + w) mod 2^seedlen */
+ if (additional != NULL && additionalSz > 0) {
+ byte addType = drbgGenerateW;
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
+ ret = wc_InitSha256_ex(sha, drbg->heap, drbg->devId);
+ #else
+ ret = wc_InitSha256(sha);
+ #endif
+ if (ret != 0) {
+ #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
+ XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST);
+ #endif
+ return DRBG_FAILURE;
+ }
+#else
+ ret = 0;
+#endif
+ if (ret == 0)
+ ret = wc_Sha256Update(sha, &addType, sizeof(addType));
+ if (ret == 0)
+ ret = wc_Sha256Update(sha, drbg->V, sizeof(drbg->V));
+ if (ret == 0)
+ ret = wc_Sha256Update(sha, additional, additionalSz);
+ if (ret == 0)
+ ret = wc_Sha256Final(sha, digest);
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha256Free(sha);
+#endif
+ if (ret == 0) {
+ array_add(drbg->V, sizeof(drbg->V), digest,
+ WC_SHA256_DIGEST_SIZE);
+ }
+ else {
+ ForceZero(digest, WC_SHA256_DIGEST_SIZE);
+ #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
+ XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST);
+ #endif
+ return DRBG_FAILURE;
+ }
+ }
+
ret = Hash_gen(drbg, out, outSz, drbg->V);
if (ret == DRBG_SUCCESS) {
#ifndef WOLFSSL_SMALL_STACK_CACHE
@@ -735,15 +848,18 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz)
/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
static int Hash_DRBG_Init(DRBG_internal* drbg, const byte* seed, word32 seedSz,
- const byte* nonce, word32 nonceSz)
+ const byte* nonce, word32 nonceSz,
+ const byte* perso, word32 persoSz)
{
if (seed == NULL)
return DRBG_FAILURE;
if (Hash_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz,
- nonce, nonceSz) == DRBG_SUCCESS &&
+ nonce, nonceSz,
+ perso, persoSz) == DRBG_SUCCESS &&
Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V,
- sizeof(drbg->V), NULL, 0) == DRBG_SUCCESS) {
+ sizeof(drbg->V), NULL, 0,
+ NULL, 0) == DRBG_SUCCESS) {
drbg->reseedCtr = 1;
return DRBG_SUCCESS;
@@ -754,9 +870,10 @@ static int Hash_DRBG_Init(DRBG_internal* drbg, const byte* seed, word32 seedSz,
}
/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
-static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 seedSz,
- const byte* nonce, word32 nonceSz,
- void* heap, int devId)
+static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed,
+ word32 seedSz, const byte* nonce,
+ word32 nonceSz, const byte* perso,
+ word32 persoSz, void* heap, int devId)
{
int ret = DRBG_FAILURE;
@@ -779,7 +896,8 @@ static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 s
#endif
if (seed != NULL)
- ret = Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz);
+ ret = Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz,
+ perso, persoSz);
return ret;
}
@@ -803,6 +921,443 @@ static int Hash_DRBG_Uninstantiate(DRBG_internal* drbg)
return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
}
+/* ====================================================================== */
+/* SHA-512 Hash_DRBG (SP 800-90A Rev 1, Table 2) */
+/* */
+/* Internal state (V, C): seedlen = 888 bits = 111 bytes each */
+/* Output block length: 512 bits = 64 bytes (WC_SHA512_DIGEST_SIZE) */
+/* Security strength: 256 bits */
+/* */
+/* NOTE: The raw entropy seed gathered at instantiation / reseed is */
+/* WC_DRBG_SEED_SZ (1024 bits in FIPS builds), NOT seedlen. We overseed */
+/* to tolerate weak entropy sources. Hash_df then compresses the seed */
+/* material down to the 888-bit V and derives C from V. See random.h. */
+/* ====================================================================== */
+#ifdef WOLFSSL_DRBG_SHA512
+
+#define OUTPUT_BLOCK_LEN_SHA512 (WC_SHA512_DIGEST_SIZE) /* 64 bytes */
+
+/* Hash Derivation Function using SHA-512 */
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz,
+ byte type,
+ const byte* inA, word32 inASz,
+ const byte* inB, word32 inBSz,
+ const byte* inC, word32 inCSz)
+{
+ int ret = DRBG_FAILURE;
+ byte ctr;
+ word32 i;
+ word32 len;
+ word32 bits = (outSz * 8);
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha512* sha = &drbg->sha512;
+#else
+ wc_Sha512 sha[1];
+#endif
+#if defined(WOLFSSL_SMALL_STACK_CACHE)
+ byte* digest = drbg->digest_scratch;
+#elif defined(WOLFSSL_SMALL_STACK)
+ byte* digest;
+#else
+ byte digest[WC_SHA512_DIGEST_SIZE];
+#endif
+
+ if (drbg == NULL) {
+ return DRBG_FAILURE;
+ }
+
+#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
+ digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap,
+ DYNAMIC_TYPE_DIGEST);
+ if (digest == NULL)
+ return DRBG_FAILURE;
+#endif
+
+#ifdef LITTLE_ENDIAN_ORDER
+ bits = ByteReverseWord32(bits);
+#endif
+ len = (outSz / OUTPUT_BLOCK_LEN_SHA512)
+ + ((outSz % OUTPUT_BLOCK_LEN_SHA512) ? 1 : 0);
+
+ ctr = 1;
+ for (i = 0; i < len; i++) {
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
+ ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId);
+ #else
+ ret = wc_InitSha512(sha);
+ #endif
+ if (ret != 0)
+ break;
+#endif
+ ret = wc_Sha512Update(sha, &ctr, sizeof(ctr));
+ if (ret == 0) {
+ ctr++;
+ ret = wc_Sha512Update(sha, (byte*)&bits, sizeof(bits));
+ }
+
+ if (ret == 0) {
+ /* churning V is the only string that doesn't have the type added */
+ if (type != drbgInitV)
+ ret = wc_Sha512Update(sha, &type, sizeof(type));
+ }
+ if (ret == 0)
+ ret = wc_Sha512Update(sha, inA, inASz);
+ if (ret == 0) {
+ if (inB != NULL && inBSz > 0)
+ ret = wc_Sha512Update(sha, inB, inBSz);
+ }
+ if (ret == 0) {
+ if (inC != NULL && inCSz > 0)
+ ret = wc_Sha512Update(sha, inC, inCSz);
+ }
+ if (ret == 0)
+ ret = wc_Sha512Final(sha, digest);
+
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha512Free(sha);
+#endif
+ if (ret == 0) {
+ if (outSz > OUTPUT_BLOCK_LEN_SHA512) {
+ XMEMCPY(out, digest, OUTPUT_BLOCK_LEN_SHA512);
+ outSz -= OUTPUT_BLOCK_LEN_SHA512;
+ out += OUTPUT_BLOCK_LEN_SHA512;
+ }
+ else {
+ XMEMCPY(out, digest, outSz);
+ }
+ }
+ }
+
+ ForceZero(digest, WC_SHA512_DIGEST_SIZE);
+
+#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
+ XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST);
+#endif
+
+ return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
+}
+
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash512_DRBG_Reseed(DRBG_SHA512_internal* drbg, const byte* seed,
+ word32 seedSz,
+ const byte* additional, word32 additionalSz)
+{
+ int ret;
+ WC_DECLARE_VAR(newV, byte, DRBG_SHA512_SEED_LEN, 0);
+
+ if (drbg == NULL) {
+ return DRBG_FAILURE;
+ }
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ newV = drbg->seed_scratch;
+#else
+ WC_ALLOC_VAR_EX(newV, byte, DRBG_SHA512_SEED_LEN, drbg->heap,
+ DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
+#endif
+ XMEMSET(newV, 0, DRBG_SHA512_SEED_LEN);
+
+ ret = Hash512_df(drbg, newV, DRBG_SHA512_SEED_LEN, drbgReseed,
+ drbg->V, sizeof(drbg->V), seed, seedSz,
+ additional, additionalSz);
+ if (ret == DRBG_SUCCESS) {
+ XMEMCPY(drbg->V, newV, sizeof(drbg->V));
+ ForceZero(newV, DRBG_SHA512_SEED_LEN);
+
+ ret = Hash512_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V,
+ sizeof(drbg->V), NULL, 0,
+ NULL, 0);
+ }
+ if (ret == DRBG_SUCCESS) {
+ drbg->reseedCtr = 1;
+ }
+
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ WC_FREE_VAR_EX(newV, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+ return ret;
+}
+
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash512_gen(DRBG_SHA512_internal* drbg, byte* out, word32 outSz,
+ const byte* V)
+{
+ int ret = DRBG_FAILURE;
+ word32 i;
+ word32 len;
+#if defined(WOLFSSL_SMALL_STACK_CACHE)
+ wc_Sha512* sha = &drbg->sha512;
+ byte* data = drbg->seed_scratch;
+ byte* digest = drbg->digest_scratch;
+#elif defined(WOLFSSL_SMALL_STACK)
+ wc_Sha512 sha[1];
+ byte* data = NULL;
+ byte* digest = NULL;
+#else
+ wc_Sha512 sha[1];
+ byte data[DRBG_SHA512_SEED_LEN];
+ byte digest[WC_SHA512_DIGEST_SIZE];
+#endif
+
+ if (drbg == NULL) {
+ return DRBG_FAILURE;
+ }
+
+#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
+ data = (byte*)XMALLOC(DRBG_SHA512_SEED_LEN, drbg->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap,
+ DYNAMIC_TYPE_DIGEST);
+ if (data == NULL || digest == NULL) {
+ XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST);
+ XFREE(data, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ return DRBG_FAILURE;
+ }
+#endif
+
+ /* Special case: outSz is 0 and out is NULL. Generate a block to save for
+ * the continuous test. */
+ if (outSz == 0) {
+ outSz = 1;
+ }
+
+ len = (outSz / OUTPUT_BLOCK_LEN_SHA512)
+ + ((outSz % OUTPUT_BLOCK_LEN_SHA512) ? 1 : 0);
+
+ XMEMCPY(data, V, DRBG_SHA512_SEED_LEN);
+ for (i = 0; i < len; i++) {
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
+ ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId);
+ #else
+ ret = wc_InitSha512(sha);
+ #endif
+ if (ret == 0)
+#endif
+ ret = wc_Sha512Update(sha, data, DRBG_SHA512_SEED_LEN);
+ if (ret == 0)
+ ret = wc_Sha512Final(sha, digest);
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha512Free(sha);
+#endif
+
+ if (ret == 0) {
+ if (out != NULL && outSz != 0) {
+ if (outSz >= OUTPUT_BLOCK_LEN_SHA512) {
+ XMEMCPY(out, digest, OUTPUT_BLOCK_LEN_SHA512);
+ outSz -= OUTPUT_BLOCK_LEN_SHA512;
+ out += OUTPUT_BLOCK_LEN_SHA512;
+ array_add_one(data, DRBG_SHA512_SEED_LEN);
+ }
+ else {
+ XMEMCPY(out, digest, outSz);
+ outSz = 0;
+ }
+ }
+ }
+ else {
+ break;
+ }
+ }
+ ForceZero(data, DRBG_SHA512_SEED_LEN);
+
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ WC_FREE_VAR_EX(digest, drbg->heap, DYNAMIC_TYPE_DIGEST);
+ WC_FREE_VAR_EX(data, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+ return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
+}
+
+/* Returns: DRBG_SUCCESS, DRBG_NEED_RESEED, or DRBG_FAILURE */
+static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out,
+ word32 outSz,
+ const byte* additional, word32 additionalSz)
+{
+ int ret;
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha512* sha = &drbg->sha512;
+#else
+ wc_Sha512 sha[1];
+#endif
+ byte type;
+ word64 reseedCtr;
+
+ if (drbg == NULL) {
+ return DRBG_FAILURE;
+ }
+
+ if (drbg->reseedCtr >= WC_RESEED_INTERVAL) {
+ return DRBG_NEED_RESEED;
+ }
+ else {
+ #if defined(WOLFSSL_SMALL_STACK_CACHE)
+ byte* digest = drbg->digest_scratch;
+ #elif defined(WOLFSSL_SMALL_STACK)
+ byte* digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap,
+ DYNAMIC_TYPE_DIGEST);
+ if (digest == NULL)
+ return DRBG_FAILURE;
+ #else
+ byte digest[WC_SHA512_DIGEST_SIZE];
+ #endif
+
+ type = drbgGenerateH;
+ reseedCtr = drbg->reseedCtr;
+
+ /* SP 800-90A Section 10.1.1.4 step 2:
+ * If additional_input != Null, w = Hash(0x02 || V || additional_input),
+ * V = (V + w) mod 2^seedlen */
+ ret = DRBG_SUCCESS;
+ if (additional != NULL && additionalSz > 0) {
+ byte addType = drbgGenerateW; /* 0x02 */
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
+ ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId);
+ #else
+ ret = wc_InitSha512(sha);
+ #endif
+ if (ret == 0)
+#endif
+ ret = wc_Sha512Update(sha, &addType, sizeof(addType));
+ if (ret == 0)
+ ret = wc_Sha512Update(sha, drbg->V, sizeof(drbg->V));
+ if (ret == 0)
+ ret = wc_Sha512Update(sha, additional, additionalSz);
+ if (ret == 0)
+ ret = wc_Sha512Final(sha, digest);
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha512Free(sha);
+#endif
+ if (ret == 0)
+ array_add(drbg->V, sizeof(drbg->V), digest,
+ WC_SHA512_DIGEST_SIZE);
+ }
+
+ if (ret == 0)
+ ret = Hash512_gen(drbg, out, outSz, drbg->V);
+ if (ret == DRBG_SUCCESS) {
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
+ ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId);
+ #else
+ ret = wc_InitSha512(sha);
+ #endif
+ if (ret == 0)
+#endif
+ ret = wc_Sha512Update(sha, &type, sizeof(type));
+ if (ret == 0)
+ ret = wc_Sha512Update(sha, drbg->V, sizeof(drbg->V));
+ if (ret == 0)
+ ret = wc_Sha512Final(sha, digest);
+
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha512Free(sha);
+#endif
+
+ if (ret == 0) {
+ array_add(drbg->V, sizeof(drbg->V), digest,
+ WC_SHA512_DIGEST_SIZE);
+ array_add(drbg->V, sizeof(drbg->V), drbg->C, sizeof(drbg->C));
+ #ifdef LITTLE_ENDIAN_ORDER
+ reseedCtr = ByteReverseWord64(reseedCtr);
+ #endif
+ array_add(drbg->V, sizeof(drbg->V),
+ (byte*)&reseedCtr, sizeof(reseedCtr));
+ ret = DRBG_SUCCESS;
+ }
+ drbg->reseedCtr++;
+ }
+ ForceZero(digest, WC_SHA512_DIGEST_SIZE);
+ #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
+ XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST);
+ #endif
+ }
+
+ return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
+}
+
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash512_DRBG_Init(DRBG_SHA512_internal* drbg, const byte* seed,
+ word32 seedSz, const byte* nonce, word32 nonceSz,
+ const byte* perso, word32 persoSz)
+{
+ if (seed == NULL)
+ return DRBG_FAILURE;
+
+ if (Hash512_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz,
+ nonce, nonceSz,
+ perso, persoSz) == DRBG_SUCCESS &&
+ Hash512_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V,
+ sizeof(drbg->V), NULL, 0,
+ NULL, 0) == DRBG_SUCCESS) {
+
+ drbg->reseedCtr = 1;
+ return DRBG_SUCCESS;
+ }
+ else {
+ return DRBG_FAILURE;
+ }
+}
+
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash512_DRBG_Instantiate(DRBG_SHA512_internal* drbg,
+ const byte* seed, word32 seedSz,
+ const byte* nonce, word32 nonceSz,
+ const byte* perso, word32 persoSz,
+ void* heap, int devId)
+{
+ int ret = DRBG_FAILURE;
+
+ XMEMSET(drbg, 0, sizeof(DRBG_SHA512_internal));
+ drbg->heap = heap;
+#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
+ drbg->devId = devId;
+#else
+ (void)devId;
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
+ ret = wc_InitSha512_ex(&drbg->sha512, drbg->heap, drbg->devId);
+ #else
+ ret = wc_InitSha512(&drbg->sha512);
+ #endif
+ if (ret != 0)
+ return ret;
+#endif
+
+ if (seed != NULL)
+ ret = Hash512_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz,
+ perso, persoSz);
+ return ret;
+}
+
+/* Returns: DRBG_SUCCESS or DRBG_FAILURE */
+static int Hash512_DRBG_Uninstantiate(DRBG_SHA512_internal* drbg)
+{
+ word32 i;
+ int compareSum = 0;
+ byte* compareDrbg = (byte*)drbg;
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha512Free(&drbg->sha512);
+#endif
+
+ ForceZero(drbg, sizeof(DRBG_SHA512_internal));
+
+ for (i = 0; i < sizeof(DRBG_SHA512_internal); i++) {
+ compareSum |= compareDrbg[i] ^ 0;
+ }
+
+ return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE;
+}
+
+#endif /* WOLFSSL_DRBG_SHA512 */
+
/* FIPS 140-3 IG 10.3.A / SP800-90B Health Tests for Seed Data
*
@@ -933,6 +1488,64 @@ int wc_RNG_TestSeed(const byte* seed, word32 seedSz)
return ret;
}
+/* Runtime DRBG disable/enable API -- only available in non-selftest and
+ * FIPS v7+ builds (older FIPS/selftest random.c doesn't have these) */
+#if !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+#ifndef NO_SHA256
+int wc_Sha256Drbg_Disable(void)
+{
+#ifdef WOLFSSL_DRBG_SHA512
+ if (sha512DrbgDisabled)
+ return BAD_STATE_E; /* can't disable both */
+ sha256DrbgDisabled = 1;
+ return 0;
+#else
+ return NOT_COMPILED_IN;
+#endif
+}
+
+int wc_Sha256Drbg_Enable(void)
+{
+ sha256DrbgDisabled = 0;
+ return 0;
+}
+
+int wc_Sha256Drbg_GetStatus(void)
+{
+ return sha256DrbgDisabled;
+}
+#else
+/* When SHA-256 is not compiled in, these are stubs */
+int wc_Sha256Drbg_Disable(void) { return NOT_COMPILED_IN; }
+int wc_Sha256Drbg_Enable(void) { return 0; }
+int wc_Sha256Drbg_GetStatus(void) { return 1; } /* always disabled */
+#endif /* !NO_SHA256 */
+#endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS v7+) */
+
+#ifdef WOLFSSL_DRBG_SHA512
+int wc_Sha512Drbg_Disable(void)
+{
+#ifndef NO_SHA256
+ if (sha256DrbgDisabled)
+ return BAD_STATE_E; /* can't disable both */
+#endif
+ sha512DrbgDisabled = 1;
+ return 0;
+}
+
+int wc_Sha512Drbg_Enable(void)
+{
+ sha512DrbgDisabled = 0;
+ return 0;
+}
+
+int wc_Sha512Drbg_GetStatus(void)
+{
+ return sha512DrbgDisabled;
+}
+#endif /* WOLFSSL_DRBG_SHA512 */
+
#endif /* HAVE_HASHDRBG */
/* End NIST DRBG Code */
@@ -983,11 +1596,41 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz,
#ifdef HAVE_HASHDRBG
/* init the DBRG to known values */
+#ifndef NO_SHA256
rng->drbg = NULL;
#ifdef WOLFSSL_SMALL_STACK_CACHE
rng->drbg_scratch = NULL;
#endif
+#endif
+#ifdef WOLFSSL_DRBG_SHA512
+ rng->drbg512 = NULL;
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ rng->drbg512_scratch = NULL;
+ rng->health_check_scratch_512 = NULL;
+ #endif
+#endif
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ rng->newSeed_buf = NULL;
+#ifndef NO_SHA256
+ rng->health_check_scratch = NULL;
+#endif
+#endif
rng->status = DRBG_NOT_INIT;
+
+ /* Select DRBG type: prefer SHA-512 unless disabled or not compiled */
+#ifdef WOLFSSL_DRBG_SHA512
+ if (!wc_Sha512Drbg_GetStatus())
+ rng->drbgType = WC_DRBG_SHA512;
+ else
+#endif
+#ifndef NO_SHA256
+ if (!wc_Sha256Drbg_GetStatus())
+ rng->drbgType = WC_DRBG_SHA256;
+ else
+#endif
+ {
+ return BAD_STATE_E; /* no DRBG available */
+ }
#endif
#if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) || \
@@ -1043,54 +1686,110 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz,
seedSz = MAX_SEED_SZ;
}
-#if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY)
- rng->drbg =
- (struct DRBG*)XMALLOC(sizeof(DRBG_internal), rng->heap,
- DYNAMIC_TYPE_RNG);
- if (rng->drbg == NULL) {
- #if defined(DEBUG_WOLFSSL)
- WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes",
- sizeof(DRBG_internal));
- #endif
- ret = MEMORY_E;
- rng->status = DRBG_FAILED;
- }
-#else
- rng->drbg = (struct DRBG*)&rng->drbg_data;
-#endif /* WOLFSSL_NO_MALLOC or WOLFSSL_STATIC_MEMORY */
-
-#ifdef WOLFSSL_SMALL_STACK_CACHE
- if (ret == 0) {
- rng->drbg_scratch =
- (DRBG_internal *)XMALLOC(sizeof(DRBG_internal), rng->heap,
- DYNAMIC_TYPE_RNG);
- if (rng->drbg_scratch == NULL) {
-#if defined(DEBUG_WOLFSSL)
+#ifndef NO_SHA256
+ if (rng->drbgType == WC_DRBG_SHA256) {
+ #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY)
+ rng->drbg =
+ (struct DRBG*)XMALLOC(sizeof(DRBG_internal), rng->heap,
+ DYNAMIC_TYPE_RNG);
+ if (rng->drbg == NULL) {
+ #if defined(DEBUG_WOLFSSL)
WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes",
sizeof(DRBG_internal));
-#endif
+ #endif
ret = MEMORY_E;
rng->status = DRBG_FAILED;
}
- }
+ #else
+ rng->drbg = (struct DRBG*)&rng->drbg_data;
+ #endif /* WOLFSSL_NO_MALLOC or WOLFSSL_STATIC_MEMORY */
- if (ret == 0) {
- ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg_scratch,
- NULL /* seed */, 0, NULL /* nonce */, 0, rng->heap, devId);
- if (ret == 0)
- drbg_scratch_instantiated = 1;
- }
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ if (ret == 0) {
+ rng->drbg_scratch =
+ (DRBG_internal *)XMALLOC(sizeof(DRBG_internal), rng->heap,
+ DYNAMIC_TYPE_RNG);
+ if (rng->drbg_scratch == NULL) {
+ #if defined(DEBUG_WOLFSSL)
+ WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes",
+ sizeof(DRBG_internal));
+ #endif
+ ret = MEMORY_E;
+ rng->status = DRBG_FAILED;
+ }
+ }
- if (ret == 0) {
- rng->health_check_scratch =
- (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, rng->heap,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (rng->health_check_scratch == NULL) {
+ if (ret == 0) {
+ ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg_scratch,
+ NULL, 0, NULL, 0, NULL, 0, rng->heap, devId);
+ if (ret == 0)
+ drbg_scratch_instantiated = 1;
+ }
+
+ if (ret == 0) {
+ rng->health_check_scratch =
+ (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, rng->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ if (rng->health_check_scratch == NULL) {
+ ret = MEMORY_E;
+ rng->status = DRBG_FAILED;
+ }
+ }
+ #endif /* WOLFSSL_SMALL_STACK_CACHE */
+ } /* WC_DRBG_SHA256 */
+#endif /* !NO_SHA256 */
+
+#ifdef WOLFSSL_DRBG_SHA512
+ if (rng->drbgType == WC_DRBG_SHA512) {
+ #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY)
+ rng->drbg512 =
+ (struct DRBG_SHA512*)XMALLOC(sizeof(DRBG_SHA512_internal),
+ rng->heap, DYNAMIC_TYPE_RNG);
+ if (rng->drbg512 == NULL) {
+ #if defined(DEBUG_WOLFSSL)
+ WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes",
+ sizeof(DRBG_SHA512_internal));
+ #endif
ret = MEMORY_E;
rng->status = DRBG_FAILED;
}
- }
+ #else
+ rng->drbg512 = (struct DRBG_SHA512*)&rng->drbg512_data;
+ #endif
+
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ if (ret == 0) {
+ rng->drbg512_scratch =
+ (DRBG_SHA512_internal *)XMALLOC(sizeof(DRBG_SHA512_internal),
+ rng->heap, DYNAMIC_TYPE_RNG);
+ if (rng->drbg512_scratch == NULL) {
+ ret = MEMORY_E;
+ rng->status = DRBG_FAILED;
+ }
+ }
+
+ if (ret == 0) {
+ ret = Hash512_DRBG_Instantiate(rng->drbg512_scratch,
+ NULL, 0, NULL, 0, NULL, 0, rng->heap, devId);
+ if (ret == 0)
+ drbg_scratch_instantiated = 1;
+ }
+
+ if (ret == 0) {
+ rng->health_check_scratch_512 =
+ (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE_SHA512, rng->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ if (rng->health_check_scratch_512 == NULL) {
+ ret = MEMORY_E;
+ rng->status = DRBG_FAILED;
+ }
+ }
+ #endif /* WOLFSSL_SMALL_STACK_CACHE */
+ } /* WC_DRBG_SHA512 */
+#endif /* WOLFSSL_DRBG_SHA512 */
+ /* newSeed_buf shared by both DRBG types for PollAndReSeed */
+#ifdef WOLFSSL_SMALL_STACK_CACHE
if (ret == 0) {
rng->newSeed_buf = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap,
DYNAMIC_TYPE_SEED);
@@ -1171,14 +1870,29 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz,
}
#endif
- if (ret == DRBG_SUCCESS)
- ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg,
- #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED)
- seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ,
- #else
- seed, seedSz,
- #endif
- nonce, nonceSz, rng->heap, devId);
+ if (ret == DRBG_SUCCESS) {
+#ifndef NO_SHA256
+ if (rng->drbgType == WC_DRBG_SHA256)
+ ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg,
+ #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED)
+ seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ,
+ #else
+ seed, seedSz,
+ #endif
+ nonce, nonceSz, NULL, 0, rng->heap, devId);
+#endif
+#ifdef WOLFSSL_DRBG_SHA512
+ if (rng->drbgType == WC_DRBG_SHA512)
+ ret = Hash512_DRBG_Instantiate(
+ (DRBG_SHA512_internal *)rng->drbg512,
+ #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED)
+ seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ,
+ #else
+ seed, seedSz,
+ #endif
+ nonce, nonceSz, NULL, 0, rng->heap, devId);
+#endif
+ }
} /* ret == 0 */
#ifdef WOLFSSL_SMALL_STACK
@@ -1190,29 +1904,56 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz,
WC_FREE_VAR_EX(seed, rng->heap, DYNAMIC_TYPE_SEED);
if (ret != DRBG_SUCCESS) {
- #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY)
- XFREE(rng->drbg, rng->heap, DYNAMIC_TYPE_RNG);
+ #ifndef NO_SHA256
+ if (rng->drbgType == WC_DRBG_SHA256) {
+ #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY)
+ XFREE(rng->drbg, rng->heap, DYNAMIC_TYPE_RNG);
+ #endif
+ rng->drbg = NULL;
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ XFREE(rng->health_check_scratch, rng->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ rng->health_check_scratch = NULL;
+ if (drbg_scratch_instantiated)
+ (void)Hash_DRBG_Uninstantiate(
+ (DRBG_internal *)rng->drbg_scratch);
+ XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG);
+ rng->drbg_scratch = NULL;
+ #endif
+ }
+ #endif /* !NO_SHA256 */
+ #ifdef WOLFSSL_DRBG_SHA512
+ if (rng->drbgType == WC_DRBG_SHA512) {
+ #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY)
+ XFREE(rng->drbg512, rng->heap, DYNAMIC_TYPE_RNG);
+ #endif
+ rng->drbg512 = NULL;
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ XFREE(rng->health_check_scratch_512, rng->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ rng->health_check_scratch_512 = NULL;
+ if (drbg_scratch_instantiated)
+ (void)Hash512_DRBG_Uninstantiate(rng->drbg512_scratch);
+ XFREE(rng->drbg512_scratch, rng->heap, DYNAMIC_TYPE_RNG);
+ rng->drbg512_scratch = NULL;
+ #endif
+ }
#endif
- rng->drbg = NULL;
#ifdef WOLFSSL_SMALL_STACK_CACHE
- XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_TMP_BUFFER);
- rng->health_check_scratch = NULL;
- XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_SEED);
rng->newSeed_buf = NULL;
- if (drbg_scratch_instantiated)
- (void)Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch);
- XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG);
- rng->drbg_scratch = NULL;
#endif
}
/* else wc_RNG_HealthTestLocal was successful */
if (ret == DRBG_SUCCESS) {
#ifdef WOLFSSL_CHECK_MEM_ZERO
- #ifdef HAVE_HASHDRBG
- struct DRBG_internal* drbg = (struct DRBG_internal*)rng->drbg;
- wc_MemZero_Add("DRBG V", &drbg->V, sizeof(drbg->V));
- wc_MemZero_Add("DRBG C", &drbg->C, sizeof(drbg->C));
+ #ifndef NO_SHA256
+ if (rng->drbgType == WC_DRBG_SHA256) {
+ struct DRBG_internal* drbg = (struct DRBG_internal*)rng->drbg;
+ wc_MemZero_Add("DRBG V", &drbg->V, sizeof(drbg->V));
+ wc_MemZero_Add("DRBG C", &drbg->C, sizeof(drbg->C));
+ }
#endif
#endif
@@ -1373,9 +2114,20 @@ static int PollAndReSeed(WC_RNG* rng)
"err %d.", ret);
#endif
}
- if (ret == DRBG_SUCCESS)
- ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg,
- newSeed + SEED_BLOCK_SZ, SEED_SZ);
+ if (ret == DRBG_SUCCESS) {
+#ifndef NO_SHA256
+ if (rng->drbgType == WC_DRBG_SHA256)
+ ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg,
+ newSeed + SEED_BLOCK_SZ, SEED_SZ,
+ NULL, 0);
+#endif
+#ifdef WOLFSSL_DRBG_SHA512
+ if (rng->drbgType == WC_DRBG_SHA512)
+ ret = Hash512_DRBG_Reseed(
+ (DRBG_SHA512_internal *)rng->drbg512,
+ newSeed + SEED_BLOCK_SZ, SEED_SZ, NULL, 0);
+#endif
+ }
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE)
if (newSeed != NULL) {
ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ);
@@ -1471,11 +2223,35 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz)
}
#endif
- ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz);
- if (ret == DRBG_NEED_RESEED) {
- ret = PollAndReSeed(rng);
- if (ret == DRBG_SUCCESS)
- ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz);
+#ifndef NO_SHA256
+ if (rng->drbgType == WC_DRBG_SHA256) {
+ ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz,
+ NULL, 0);
+ if (ret == DRBG_NEED_RESEED) {
+ ret = PollAndReSeed(rng);
+ if (ret == DRBG_SUCCESS)
+ ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output,
+ sz, NULL, 0);
+ }
+ }
+ else
+#endif
+#ifdef WOLFSSL_DRBG_SHA512
+ if (rng->drbgType == WC_DRBG_SHA512) {
+ ret = Hash512_DRBG_Generate((DRBG_SHA512_internal *)rng->drbg512,
+ output, sz, NULL, 0);
+ if (ret == DRBG_NEED_RESEED) {
+ ret = PollAndReSeed(rng);
+ if (ret == DRBG_SUCCESS)
+ ret = Hash512_DRBG_Generate(
+ (DRBG_SHA512_internal *)rng->drbg512, output, sz,
+ NULL, 0);
+ }
+ }
+ else
+#endif
+ {
+ ret = DRBG_FAILURE;
}
if (ret == DRBG_SUCCESS) {
@@ -1560,6 +2336,7 @@ int wc_FreeRng(WC_RNG* rng)
#endif
#ifdef HAVE_HASHDRBG
+#ifndef NO_SHA256
if (rng->drbg != NULL) {
if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg) != DRBG_SUCCESS)
ret = RNG_FAILURE_E;
@@ -1570,20 +2347,51 @@ int wc_FreeRng(WC_RNG* rng)
wc_MemZero_Check(rng->drbg, sizeof(DRBG_internal));
#endif
rng->drbg = NULL;
- }
#ifdef WOLFSSL_SMALL_STACK_CACHE
- if (rng->drbg_scratch != NULL) {
- if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch) != DRBG_SUCCESS)
+ if (rng->drbg_scratch != NULL) {
+ if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch)
+ != DRBG_SUCCESS)
+ ret = RNG_FAILURE_E;
+ XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG);
+ rng->drbg_scratch = NULL;
+ }
+ XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ rng->health_check_scratch = NULL;
+ #endif
+ }
+#endif /* !NO_SHA256 */
+
+#ifdef WOLFSSL_DRBG_SHA512
+ if (rng->drbg512 != NULL) {
+ if (Hash512_DRBG_Uninstantiate(
+ (DRBG_SHA512_internal *)rng->drbg512) != DRBG_SUCCESS)
ret = RNG_FAILURE_E;
- XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG);
- rng->drbg_scratch = NULL;
+
+ #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY)
+ XFREE(rng->drbg512, rng->heap, DYNAMIC_TYPE_RNG);
+ #endif
+ rng->drbg512 = NULL;
+
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ if (rng->drbg512_scratch != NULL) {
+ if (Hash512_DRBG_Uninstantiate(rng->drbg512_scratch)
+ != DRBG_SUCCESS)
+ ret = RNG_FAILURE_E;
+ XFREE(rng->drbg512_scratch, rng->heap, DYNAMIC_TYPE_RNG);
+ rng->drbg512_scratch = NULL;
+ }
+ XFREE(rng->health_check_scratch_512, rng->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ rng->health_check_scratch_512 = NULL;
+ #endif
}
- XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_RNG);
- rng->health_check_scratch = NULL;
- XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_RNG);
+#endif /* WOLFSSL_DRBG_SHA512 */
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_SEED);
rng->newSeed_buf = NULL;
- #endif
+#endif
rng->status = DRBG_NOT_INIT;
#endif /* HAVE_HASHDRBG */
@@ -1643,18 +2451,19 @@ static int wc_RNG_HealthTest_ex_internal(DRBG_internal* drbg,
(void)heap;
(void)devId;
- if (Hash_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz) != 0) {
+ if (Hash_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz,
+ NULL, 0) != 0) {
goto exit_rng_ht;
}
#else
if (Hash_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz,
- heap, devId) != 0) {
+ NULL, 0, heap, devId) != 0) {
goto exit_rng_ht;
}
#endif
if (reseed) {
- if (Hash_DRBG_Reseed(drbg, seedB, seedBSz) != 0) {
+ if (Hash_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0) != 0) {
goto exit_rng_ht;
}
}
@@ -1664,11 +2473,11 @@ static int wc_RNG_HealthTest_ex_internal(DRBG_internal* drbg,
* answer test checks the second block of DRBG out of
* the generator to ensure the internal state is updated
* as expected. */
- if (Hash_DRBG_Generate(drbg, output, outputSz) != 0) {
+ if (Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0) != 0) {
goto exit_rng_ht;
}
- if (Hash_DRBG_Generate(drbg, output, outputSz) != 0) {
+ if (Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0) != 0) {
goto exit_rng_ht;
}
@@ -1711,7 +2520,8 @@ int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz,
#ifdef WOLFSSL_SMALL_STACK_CACHE
ret = Hash_DRBG_Instantiate(drbg,
- NULL /* seed */, 0, NULL /* nonce */, 0, heap, devId);
+ NULL /* seed */, 0, NULL /* nonce */, 0,
+ NULL /* perso */, 0, heap, devId);
if (ret == 0)
#endif
{
@@ -1778,10 +2588,182 @@ const FLASH_QUALIFIER byte outputB_data[] = {
};
+/* SHA-512 DRBG KAT vectors for local health test.
+ * Source: NIST CAVP Hash_DRBG.rsp, [SHA-512], PredictionResistance=False,
+ * EntropyInputLen=256, NonceLen=128, PersonalizationStringLen=0,
+ * AdditionalInputLen=0, ReturnedBitsLen=2048. */
+#ifdef WOLFSSL_DRBG_SHA512
+
+/* Reseed test vectors (COUNT=0 from reseed section) */
+static const byte sha512_seedA_data[] = {
+ /* EntropyInput (32 bytes) || Nonce (16 bytes) */
+ 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12,
+ 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10,
+ 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff,
+ 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33,
+ 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3,
+ 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04
+};
+static const byte sha512_reseedSeedA_data[] = {
+ /* EntropyInputReseed (32 bytes) */
+ 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6,
+ 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0,
+ 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d,
+ 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67
+};
+static const byte sha512_outputA_data[] = {
+ 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76,
+ 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c,
+ 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a,
+ 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1,
+ 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70,
+ 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42,
+ 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d,
+ 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15,
+ 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58,
+ 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7,
+ 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05,
+ 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c,
+ 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac,
+ 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f,
+ 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb,
+ 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f,
+ 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1,
+ 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82,
+ 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22,
+ 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e,
+ 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4,
+ 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a,
+ 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a,
+ 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03,
+ 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e,
+ 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78,
+ 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2,
+ 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6,
+ 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e,
+ 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0,
+ 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d,
+ 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0
+};
+
+/* No-reseed test vectors (COUNT=0 from no-reseed section) */
+static const byte sha512_seedB_data[] = {
+ /* EntropyInput (32 bytes) || Nonce (16 bytes) */
+ 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a,
+ 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22,
+ 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b,
+ 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c,
+ 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa,
+ 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25
+};
+static const byte sha512_outputB_data[] = {
+ 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57,
+ 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6,
+ 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d,
+ 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf,
+ 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26,
+ 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64,
+ 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55,
+ 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a,
+ 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78,
+ 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e,
+ 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb,
+ 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30,
+ 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19,
+ 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f,
+ 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d,
+ 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a,
+ 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2,
+ 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd,
+ 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd,
+ 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2,
+ 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b,
+ 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1,
+ 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99,
+ 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e,
+ 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3,
+ 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67,
+ 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3,
+ 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d,
+ 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b,
+ 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13,
+ 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c,
+ 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2
+};
+#endif /* WOLFSSL_DRBG_SHA512 */
+
+
static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap,
int devId)
{
int ret = 0;
+
+#ifdef WOLFSSL_DRBG_SHA512
+ /* SHA-512 DRBG health test path */
+ if (rng->drbgType == WC_DRBG_SHA512) {
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ byte *check512 = rng->health_check_scratch_512;
+ DRBG_SHA512_internal* drbg512 = rng->drbg512_scratch;
+ #else
+ WC_DECLARE_VAR(check512, byte, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, 0);
+ WC_DECLARE_VAR(drbg512, DRBG_SHA512_internal, 1, 0);
+
+ WC_ALLOC_VAR_EX(check512, byte, RNG_HEALTH_TEST_CHECK_SIZE_SHA512,
+ heap, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E);
+ WC_ALLOC_VAR_EX(drbg512, DRBG_SHA512_internal,
+ sizeof(DRBG_SHA512_internal), heap, DYNAMIC_TYPE_TMP_BUFFER,
+ WC_DO_NOTHING);
+ #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
+ if (drbg512 == NULL) {
+ WC_FREE_VAR_EX(check512, heap, DYNAMIC_TYPE_TMP_BUFFER);
+ return MEMORY_E;
+ }
+ #endif
+ #endif
+
+ if (reseed) {
+ /* Reseed test with NIST CAVP SHA-512 vectors */
+ ret = wc_RNG_HealthTest_SHA512_ex_internal(
+ drbg512, 1, NULL, 0, NULL, 0,
+ sha512_seedA_data, sizeof(sha512_seedA_data),
+ sha512_reseedSeedA_data,
+ sizeof(sha512_reseedSeedA_data),
+ NULL, 0, NULL, 0,
+ check512, RNG_HEALTH_TEST_CHECK_SIZE_SHA512,
+ heap, devId);
+ if (ret == 0) {
+ if (ConstantCompare(check512, sha512_outputA_data,
+ RNG_HEALTH_TEST_CHECK_SIZE_SHA512) != 0)
+ ret = -1;
+ }
+ }
+ else {
+ /* No-reseed test with NIST CAVP SHA-512 vectors */
+ ret = wc_RNG_HealthTest_SHA512_ex_internal(
+ drbg512, 0, NULL, 0, NULL, 0,
+ sha512_seedB_data, sizeof(sha512_seedB_data),
+ NULL, 0,
+ NULL, 0, NULL, 0,
+ check512, RNG_HEALTH_TEST_CHECK_SIZE_SHA512,
+ heap, devId);
+ if (ret == 0) {
+ if (ConstantCompare(check512, sha512_outputB_data,
+ RNG_HEALTH_TEST_CHECK_SIZE_SHA512) != 0)
+ ret = -1;
+ }
+ }
+
+ #ifndef WOLFSSL_SMALL_STACK_CACHE
+ WC_FREE_VAR_EX(check512, heap, DYNAMIC_TYPE_TMP_BUFFER);
+ WC_FREE_VAR_EX(drbg512, heap, DYNAMIC_TYPE_TMP_BUFFER);
+ #endif
+ return ret;
+ }
+#endif /* WOLFSSL_DRBG_SHA512 */
+
+ /* SHA-256 DRBG health test path (original) */
+#ifndef NO_SHA256
+ {
#ifdef WOLFSSL_SMALL_STACK_CACHE
byte *check = rng->health_check_scratch;
DRBG_internal* drbg = (DRBG_internal *)rng->drbg_scratch;
@@ -1919,9 +2901,408 @@ static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap,
WC_FREE_VAR_EX(check, heap, DYNAMIC_TYPE_TMP_BUFFER);
WC_FREE_VAR_EX(drbg, heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
+ } /* SHA-256 path */
+#endif /* !NO_SHA256 */
+
+ return ret;
+}
+
+/* ====================================================================== */
+/* SHA-512 Health Test API */
+/* ====================================================================== */
+#ifdef WOLFSSL_DRBG_SHA512
+
+static int wc_RNG_HealthTest_SHA512_ex_internal(DRBG_SHA512_internal* drbg,
+ int reseed, const byte* nonce, word32 nonceSz,
+ const byte* perso, word32 persoSz,
+ const byte* seedA, word32 seedASz,
+ const byte* seedB, word32 seedBSz,
+ const byte* additionalA, word32 additionalASz,
+ const byte* additionalB, word32 additionalBSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId)
+{
+ int ret = -1;
+
+ if (seedA == NULL || output == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (reseed != 0 && seedB == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (outputSz != RNG_HEALTH_TEST_CHECK_SIZE_SHA512) {
+ return ret;
+ }
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ (void)heap;
+ (void)devId;
+
+ if (Hash512_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz,
+ perso, persoSz) != 0) {
+ goto exit_rng_ht512;
+ }
+#else
+ if (Hash512_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz,
+ perso, persoSz, heap, devId) != 0) {
+ goto exit_rng_ht512;
+ }
+#endif
+
+ if (reseed) {
+ if (Hash512_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0) != 0) {
+ goto exit_rng_ht512;
+ }
+ }
+
+ /* First generate: output discarded per NIST DRBGVS procedure */
+ if (Hash512_DRBG_Generate(drbg, output, outputSz,
+ additionalA, additionalASz) != 0) {
+ goto exit_rng_ht512;
+ }
+
+ /* Second generate: this is the actual test output */
+ if (Hash512_DRBG_Generate(drbg, output, outputSz,
+ additionalB, additionalBSz) != 0) {
+ goto exit_rng_ht512;
+ }
+
+ ret = 0;
+
+exit_rng_ht512:
+
+#ifndef WOLFSSL_SMALL_STACK_CACHE
+ if (Hash512_DRBG_Uninstantiate(drbg) != 0) {
+ ret = -1;
+ }
+#endif
+
+ return ret;
+}
+
+
+/* Extended API with personalization string and additional input
+ * for ACVP testing */
+int wc_RNG_HealthTest_SHA512_ex(int reseed,
+ const byte* nonce, word32 nonceSz,
+ const byte* persoString, word32 persoStringSz,
+ const byte* seedA, word32 seedASz,
+ const byte* seedB, word32 seedBSz,
+ const byte* additionalA, word32 additionalASz,
+ const byte* additionalB, word32 additionalBSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId)
+{
+ int ret = -1;
+ DRBG_SHA512_internal* drbg;
+#ifndef WOLFSSL_SMALL_STACK
+ DRBG_SHA512_internal drbg_var;
+#endif
+
+ if (seedA == NULL || output == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (outputSz != RNG_HEALTH_TEST_CHECK_SIZE_SHA512) {
+ return ret;
+ }
+
+#ifdef WOLFSSL_SMALL_STACK
+ drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), heap,
+ DYNAMIC_TYPE_RNG);
+ if (drbg == NULL) {
+ return MEMORY_E;
+ }
+#else
+ drbg = &drbg_var;
+#endif
+
+ /* SP 800-90A Sec 10.1.1.2: personalization string is concatenated
+ * with entropy during instantiation via Hash_df. */
+ ret = Hash512_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz,
+ persoString, persoStringSz, heap, devId);
+ if (ret != 0) {
+ goto exit_sha512_ex;
+ }
+
+ if (reseed) {
+ if (seedB != NULL && seedBSz > 0) {
+ ret = Hash512_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0);
+ if (ret != 0) goto exit_sha512_ex;
+ }
+ }
+
+ /* First generate (output discarded per NIST procedure) */
+ ret = Hash512_DRBG_Generate(drbg, output, outputSz,
+ additionalA, additionalASz);
+ if (ret != 0) goto exit_sha512_ex;
+
+ /* Second generate (this is the actual output) */
+ ret = Hash512_DRBG_Generate(drbg, output, outputSz,
+ additionalB, additionalBSz);
+
+exit_sha512_ex:
+ (void)Hash512_DRBG_Uninstantiate(drbg);
+
+#ifdef WOLFSSL_SMALL_STACK
+ XFREE(drbg, heap, DYNAMIC_TYPE_RNG);
+#endif
+
+ return (ret == DRBG_SUCCESS) ? 0 : -1;
+}
+
+
+/* Simple API matching wc_RNG_HealthTest() pattern - entropy+nonce only */
+int wc_RNG_HealthTest_SHA512(int reseed,
+ const byte* seedA, word32 seedASz,
+ const byte* seedB, word32 seedBSz,
+ byte* output, word32 outputSz)
+{
+ int ret = -1;
+ DRBG_SHA512_internal* drbg;
+#ifndef WOLFSSL_SMALL_STACK
+ DRBG_SHA512_internal drbg_var;
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+ drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), NULL,
+ DYNAMIC_TYPE_RNG);
+ if (drbg == NULL) {
+ return MEMORY_E;
+ }
+#else
+ drbg = &drbg_var;
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ ret = Hash512_DRBG_Instantiate(drbg,
+ NULL /* seed */, 0, NULL /* nonce */, 0,
+ NULL, 0, NULL, INVALID_DEVID);
+ if (ret == 0)
+#endif
+ {
+ ret = wc_RNG_HealthTest_SHA512_ex_internal(
+ drbg, reseed, NULL, 0, NULL, 0,
+ seedA, seedASz, seedB, seedBSz,
+ NULL, 0, NULL, 0,
+ output, outputSz, NULL, INVALID_DEVID);
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ Hash512_DRBG_Uninstantiate(drbg);
+#endif
+ }
+ WC_FREE_VAR_EX(drbg, NULL, DYNAMIC_TYPE_RNG);
+
+ return ret;
+}
+
+#endif /* WOLFSSL_DRBG_SHA512 */
+
+#ifndef NO_SHA256
+/* Extended SHA-256 Hash_DRBG health test per SP 800-90A.
+ * Supports flexible output sizes, prediction resistance, personalization
+ * strings, and additional input.
+ *
+ * predResistance=0: Instantiate(entropyA, nonce, perso) ->
+ * Reseed(entropyB, additionalReseed) ->
+ * Gen1(additionalA, discard) -> Gen2(additionalB, keep)
+ * predResistance=1: Instantiate(entropyA, nonce, perso) ->
+ * Reseed(entropyB, additionalA)+Gen1(NULL, discard) ->
+ * Reseed(entropyC, additionalB)+Gen2(NULL, keep)
+ */
+int wc_RNG_HealthTest_SHA256_ex(
+ int predResistance,
+ const byte* nonce, word32 nonceSz,
+ const byte* persoString, word32 persoStringSz,
+ const byte* entropyA, word32 entropyASz,
+ const byte* entropyB, word32 entropyBSz,
+ const byte* entropyC, word32 entropyCsz,
+ const byte* additionalA, word32 additionalASz,
+ const byte* additionalB, word32 additionalBSz,
+ const byte* additionalReseed, word32 additionalReseedSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId)
+{
+ int ret;
+ DRBG_internal* drbg;
+#ifndef WOLFSSL_SMALL_STACK
+ DRBG_internal drbg_var;
+#endif
+
+ if (entropyA == NULL || output == NULL || outputSz == 0) {
+ return BAD_FUNC_ARG;
+ }
+
+#ifdef WOLFSSL_SMALL_STACK
+ drbg = (DRBG_internal*)XMALLOC(sizeof(DRBG_internal), heap,
+ DYNAMIC_TYPE_RNG);
+ if (drbg == NULL) {
+ return MEMORY_E;
+ }
+#else
+ drbg = &drbg_var;
+#endif
+
+ /* Instantiate with entropy, nonce, personalization string */
+ ret = Hash_DRBG_Instantiate(drbg, entropyA, entropyASz, nonce, nonceSz,
+ persoString, persoStringSz, heap, devId);
+ if (ret != 0) goto exit_sha256_ex;
+
+ if (predResistance) {
+ /* Prediction resistance mode per SP 800-90A 9.3.1:
+ * additional_input is passed to Reseed, Generate gets NULL */
+
+ /* Reseed 1 with additionalA, then Generate 1 with NULL (discard) */
+ if (entropyB != NULL && entropyBSz > 0) {
+ ret = Hash_DRBG_Reseed(drbg, entropyB, entropyBSz,
+ additionalA, additionalASz);
+ if (ret != 0) goto exit_sha256_ex;
+ }
+ ret = Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0);
+ if (ret != 0) goto exit_sha256_ex;
+
+ /* Reseed 2 with additionalB, then Generate 2 with NULL (keep) */
+ if (entropyC != NULL && entropyCsz > 0) {
+ ret = Hash_DRBG_Reseed(drbg, entropyC, entropyCsz,
+ additionalB, additionalBSz);
+ if (ret != 0) goto exit_sha256_ex;
+ }
+ ret = Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0);
+ }
+ else {
+ /* Standard mode: explicit reseed, then two generates */
+ if (entropyB != NULL && entropyBSz > 0) {
+ ret = Hash_DRBG_Reseed(drbg, entropyB, entropyBSz,
+ additionalReseed, additionalReseedSz);
+ if (ret != 0) goto exit_sha256_ex;
+ }
+
+ /* Generate 1 (output discarded per NIST DRBGVS procedure) */
+ ret = Hash_DRBG_Generate(drbg, output, outputSz,
+ additionalA, additionalASz);
+ if (ret != 0) goto exit_sha256_ex;
+
+ /* Generate 2 (this is the actual test output) */
+ ret = Hash_DRBG_Generate(drbg, output, outputSz,
+ additionalB, additionalBSz);
+ }
+
+exit_sha256_ex:
+ (void)Hash_DRBG_Uninstantiate(drbg);
+
+#ifdef WOLFSSL_SMALL_STACK
+ XFREE(drbg, heap, DYNAMIC_TYPE_RNG);
+#endif
return ret;
}
+#endif /* !NO_SHA256 */
+
+
+#ifdef WOLFSSL_DRBG_SHA512
+/* Extended SHA-512 Hash_DRBG health test per SP 800-90A.
+ * Supports flexible output sizes and prediction resistance mode.
+ *
+ * Per SP 800-90A Section 9.3.1, when prediction resistance is requested,
+ * the additional_input is consumed by the Reseed step and the subsequent
+ * Generate uses NULL additional_input.
+ *
+ * predResistance=0: Instantiate ->
+ * Reseed(entropyB, additionalReseed) ->
+ * Gen1(additionalA, discard) -> Gen2(additionalB, keep)
+ * predResistance=1: Instantiate ->
+ * Reseed(entropyB, additionalA)+Gen1(NULL, discard) ->
+ * Reseed(entropyC, additionalB)+Gen2(NULL, keep)
+ */
+int wc_RNG_HealthTest_SHA512_ex2(
+ int predResistance,
+ const byte* nonce, word32 nonceSz,
+ const byte* persoString, word32 persoStringSz,
+ const byte* entropyA, word32 entropyASz,
+ const byte* entropyB, word32 entropyBSz,
+ const byte* entropyC, word32 entropyCsz,
+ const byte* additionalA, word32 additionalASz,
+ const byte* additionalB, word32 additionalBSz,
+ const byte* additionalReseed, word32 additionalReseedSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId)
+{
+ int ret;
+ DRBG_SHA512_internal* drbg;
+#ifndef WOLFSSL_SMALL_STACK
+ DRBG_SHA512_internal drbg_var;
+#endif
+
+ if (entropyA == NULL || output == NULL || outputSz == 0) {
+ return BAD_FUNC_ARG;
+ }
+
+#ifdef WOLFSSL_SMALL_STACK
+ drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), heap,
+ DYNAMIC_TYPE_RNG);
+ if (drbg == NULL) {
+ return MEMORY_E;
+ }
+#else
+ drbg = &drbg_var;
+#endif
+
+ /* Instantiate with entropy, nonce, personalization string */
+ ret = Hash512_DRBG_Instantiate(drbg, entropyA, entropyASz, nonce, nonceSz,
+ persoString, persoStringSz, heap, devId);
+ if (ret != 0) goto exit_sha512_ex2;
+
+ if (predResistance) {
+ /* Prediction resistance mode per SP 800-90A 9.3.1:
+ * additional_input is passed to Reseed, Generate gets NULL */
+
+ /* Reseed 1 with additionalA, then Generate 1 with NULL (discard) */
+ if (entropyB != NULL && entropyBSz > 0) {
+ ret = Hash512_DRBG_Reseed(drbg, entropyB, entropyBSz,
+ additionalA, additionalASz);
+ if (ret != 0) goto exit_sha512_ex2;
+ }
+ ret = Hash512_DRBG_Generate(drbg, output, outputSz, NULL, 0);
+ if (ret != 0) goto exit_sha512_ex2;
+
+ /* Reseed 2 with additionalB, then Generate 2 with NULL (keep) */
+ if (entropyC != NULL && entropyCsz > 0) {
+ ret = Hash512_DRBG_Reseed(drbg, entropyC, entropyCsz,
+ additionalB, additionalBSz);
+ if (ret != 0) goto exit_sha512_ex2;
+ }
+ ret = Hash512_DRBG_Generate(drbg, output, outputSz, NULL, 0);
+ }
+ else {
+ /* Standard mode: explicit reseed, then two generates */
+ if (entropyB != NULL && entropyBSz > 0) {
+ ret = Hash512_DRBG_Reseed(drbg, entropyB, entropyBSz,
+ additionalReseed, additionalReseedSz);
+ if (ret != 0) goto exit_sha512_ex2;
+ }
+
+ /* Generate 1 (output discarded per NIST DRBGVS procedure) */
+ ret = Hash512_DRBG_Generate(drbg, output, outputSz,
+ additionalA, additionalASz);
+ if (ret != 0) goto exit_sha512_ex2;
+
+ /* Generate 2 (this is the actual test output) */
+ ret = Hash512_DRBG_Generate(drbg, output, outputSz,
+ additionalB, additionalBSz);
+ }
+
+exit_sha512_ex2:
+ (void)Hash512_DRBG_Uninstantiate(drbg);
+
+#ifdef WOLFSSL_SMALL_STACK
+ XFREE(drbg, heap, DYNAMIC_TYPE_RNG);
+#endif
+
+ return (ret == DRBG_SUCCESS) ? 0 : -1;
+}
+
+#endif /* WOLFSSL_DRBG_SHA512 */
#endif /* HAVE_HASHDRBG */
diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c
index fe87d86539b..17e5576bc66 100644
--- a/wolfcrypt/src/rng_bank.c
+++ b/wolfcrypt/src/rng_bank.c
@@ -26,6 +26,33 @@
#include
#include
+/* Helper to get reseedCtr from the active DRBG, regardless of SHA-256/SHA-512 */
+#ifdef WOLFSSL_DRBG_SHA512
+ #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)
+#else
+ #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
+
WOLFSSL_API int wc_rng_bank_init(
struct wc_rng_bank *ctx,
int n_rngs,
@@ -343,7 +370,7 @@ WOLFSSL_API int wc_rng_bank_checkout(
*rng_inst = &bank->rngs[preferred_inst_offset];
if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) &&
- (((struct DRBG_internal *)(*rng_inst)->rng.drbg)->reseedCtr >=
+ (WC_RNG_BANK_RESEED_CTR(&(*rng_inst)->rng) >=
WC_RESEED_INTERVAL) &&
(flags & WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST) &&
(n_rngs_tried < bank->n_rngs))
@@ -353,7 +380,7 @@ WOLFSSL_API int wc_rng_bank_checkout(
else {
#ifdef WC_VERBOSE_RNG
if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) &&
- (((struct DRBG_internal *)(*rng_inst)->rng.drbg)->reseedCtr >=
+ (WC_RNG_BANK_RESEED_CTR(&(*rng_inst)->rng) >=
WC_RESEED_INTERVAL))
{
WOLFSSL_DEBUG_PRINTF(
@@ -484,7 +511,7 @@ WOLFSSL_API int wc_rng_bank_inst_reinit(
int devId;
if ((rng_inst == NULL) ||
- (rng_inst->rng.drbg == NULL))
+ WC_RNG_BANK_DRBG_NULL(&rng_inst->rng))
{
return BAD_FUNC_ARG;
}
@@ -561,7 +588,7 @@ WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank,
#endif
break;
}
- else if (drbg->rng.drbg == NULL) {
+ else if (WC_RNG_BANK_DRBG_NULL(&drbg->rng)) {
#ifdef WC_VERBOSE_RNG
WOLFSSL_DEBUG_PRINTF(
"WARNING: wc_rng_bank_seed(): inst#%d has null .drbg.\n", n);
@@ -612,8 +639,7 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank,
if (ret != 0)
return ret;
- ((struct DRBG_internal *)drbg->rng.drbg)->reseedCtr =
- WC_RESEED_INTERVAL;
+ WC_RNG_BANK_SET_RESEED_CTR(&drbg->rng, WC_RESEED_INTERVAL);
if (flags & WC_RNG_BANK_FLAG_CAN_WAIT) {
byte scratch[4];
diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c
index 3a12311eff6..a0de108b0d3 100644
--- a/wolfcrypt/src/rsa.c
+++ b/wolfcrypt/src/rsa.c
@@ -1054,6 +1054,47 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz,
}
#endif /* SHA2 Hashes */
+#if defined(WOLFSSL_SHA3) && \
+ (defined(WOLFSSL_SHAKE128) || defined(WOLFSSL_SHAKE256))
+/* SHAKE XOF used directly as mask generation function (not MGF1).
+ * Per FIPS 186-5, SHAKE can be used as the MGF for RSA-PSS. */
+static int RsaMGF_SHAKE(enum wc_HashType shakeType, byte* seed, word32 seedSz,
+ byte* out, word32 outSz, void* heap)
+{
+ wc_Shake shake;
+ int ret;
+
+ (void)heap;
+ (void)shakeType;
+
+#ifdef WOLFSSL_SHAKE128
+ if (shakeType == WC_HASH_TYPE_SHAKE128)
+ ret = wc_InitShake128(&shake, heap, INVALID_DEVID);
+ else
+#endif
+ ret = wc_InitShake256(&shake, heap, INVALID_DEVID);
+
+ if (ret == 0) {
+#ifdef WOLFSSL_SHAKE128
+ if (shakeType == WC_HASH_TYPE_SHAKE128) {
+ ret = wc_Shake128_Update(&shake, seed, seedSz);
+ if (ret == 0)
+ ret = wc_Shake128_Final(&shake, out, outSz);
+ wc_Shake128_Free(&shake);
+ }
+ else
+#endif
+ {
+ ret = wc_Shake256_Update(&shake, seed, seedSz);
+ if (ret == 0)
+ ret = wc_Shake256_Final(&shake, out, outSz);
+ wc_Shake256_Free(&shake);
+ }
+ }
+ return ret;
+}
+#endif /* WOLFSSL_SHA3 && (WOLFSSL_SHAKE128 || WOLFSSL_SHAKE256) */
+
/* helper function to direct which mask generation function is used
switched on type input
*/
@@ -1099,6 +1140,52 @@ static int RsaMGF(int type, byte* seed, word32 seedSz, byte* out,
heap);
break;
#endif
+ #endif
+ #ifdef WOLFSSL_SHA3
+ #ifndef WOLFSSL_NOSHA3_224
+ case WC_MGF1SHA3_224:
+ ret = RsaMGF1(WC_HASH_TYPE_SHA3_224, seed, seedSz, out, outSz,
+ heap);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA3_256
+ case WC_MGF1SHA3_256:
+ ret = RsaMGF1(WC_HASH_TYPE_SHA3_256, seed, seedSz, out, outSz,
+ heap);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA3_384
+ case WC_MGF1SHA3_384:
+ ret = RsaMGF1(WC_HASH_TYPE_SHA3_384, seed, seedSz, out, outSz,
+ heap);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA3_512
+ case WC_MGF1SHA3_512:
+ ret = RsaMGF1(WC_HASH_TYPE_SHA3_512, seed, seedSz, out, outSz,
+ heap);
+ break;
+ #endif
+ #endif /* WOLFSSL_SHA3 */
+ #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
+ case WC_MGF1SHAKE128:
+ ret = RsaMGF1(WC_HASH_TYPE_SHAKE128, seed, seedSz, out, outSz,
+ heap);
+ break;
+ case WC_MGFSHAKE128:
+ ret = RsaMGF_SHAKE(WC_HASH_TYPE_SHAKE128, seed, seedSz, out, outSz,
+ heap);
+ break;
+ #endif
+ #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
+ case WC_MGF1SHAKE256:
+ ret = RsaMGF1(WC_HASH_TYPE_SHAKE256, seed, seedSz, out, outSz,
+ heap);
+ break;
+ case WC_MGFSHAKE256:
+ ret = RsaMGF_SHAKE(WC_HASH_TYPE_SHAKE256, seed, seedSz, out, outSz,
+ heap);
+ break;
#endif
default:
WOLFSSL_MSG("Unknown MGF type: check build options");
@@ -2035,9 +2122,29 @@ int wc_hash2mgf(enum wc_HashType hType)
case WC_HASH_TYPE_SHA512_256:
#endif
case WC_HASH_TYPE_SHA3_224:
+#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_224)
+ return WC_MGF1SHA3_224;
+#else
+ break;
+#endif
case WC_HASH_TYPE_SHA3_256:
+#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_256)
+ return WC_MGF1SHA3_256;
+#else
+ break;
+#endif
case WC_HASH_TYPE_SHA3_384:
+#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_384)
+ return WC_MGF1SHA3_384;
+#else
+ break;
+#endif
case WC_HASH_TYPE_SHA3_512:
+#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_512)
+ return WC_MGF1SHA3_512;
+#else
+ break;
+#endif
case WC_HASH_TYPE_BLAKE2B:
case WC_HASH_TYPE_BLAKE2S:
#ifdef WOLFSSL_SM3
@@ -2045,9 +2152,11 @@ int wc_hash2mgf(enum wc_HashType hType)
#endif
#ifdef WOLFSSL_SHAKE128
case WC_HASH_TYPE_SHAKE128:
+ return WC_MGF1SHAKE128;
#endif
#ifdef WOLFSSL_SHAKE256
case WC_HASH_TYPE_SHAKE256:
+ return WC_MGF1SHAKE256;
#endif
default:
break;
diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c
index 7035060621c..f89e7ea5471 100644
--- a/wolfcrypt/src/wc_lms.c
+++ b/wolfcrypt/src/wc_lms.c
@@ -22,6 +22,11 @@
#include
#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS)
+
+#if FIPS_VERSION3_GE(2,0,0)
+ /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+ #define FIPS_NO_WRAPPERS
+#endif
#include
#ifdef NO_INLINE
@@ -109,6 +114,19 @@ static int wc_lmskey_state_init(LmsState* state, const LmsParams* params)
/* Keep a reference to the parameters for use in operations. */
state->params = params;
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(params->lmOtsType)) {
+ ret = wc_InitShake256(&state->shake, NULL, INVALID_DEVID);
+ if (ret == 0) {
+ ret = wc_InitShake256(&state->shake_k, NULL, INVALID_DEVID);
+ if (ret != 0) {
+ wc_Shake256_Free(&state->shake);
+ }
+ }
+ return ret;
+ }
+#endif
+
/* Initialize the two hash algorithms. */
ret = wc_InitSha256(&state->hash);
if (ret == 0) {
@@ -127,6 +145,13 @@ static int wc_lmskey_state_init(LmsState* state, const LmsParams* params)
*/
static void wc_lmskey_state_free(LmsState* state)
{
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(state->params->lmOtsType)) {
+ wc_Shake256_Free(&state->shake_k);
+ wc_Shake256_Free(&state->shake);
+ return;
+ }
+#endif
wc_Sha256Free(&state->hash_k);
wc_Sha256Free(&state->hash);
}
@@ -276,6 +301,35 @@ static const wc_LmsParamsMap wc_lms_map[] = {
WC_SHA256_DIGEST_SIZE) },
#endif
#endif
+#if LMS_MAX_HEIGHT >= 25
+ { WC_LMS_PARM_L1_H25_W1 , "LMS/HSS_L1_H25_W1",
+ LMS_PARAMS(1, 25, 1, 1, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_L1_H25_W2 , "LMS/HSS_L1_H25_W2",
+ LMS_PARAMS(1, 25, 2, 1, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W2,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_L1_H25_W4 , "LMS/HSS_L1_H25_W4",
+ LMS_PARAMS(1, 25, 4, 2, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W4,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_L1_H25_W8 , "LMS/HSS_L1_H25_W8",
+ LMS_PARAMS(1, 25, 8, 3, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W8,
+ WC_SHA256_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 10
+ { WC_LMS_PARM_L1_H10_W1 , "LMS/HSS_L1_H10_W1",
+ LMS_PARAMS(1, 10, 1, 1, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 15
+ { WC_LMS_PARM_L1_H15_W1 , "LMS/HSS_L1_H15_W1",
+ LMS_PARAMS(1, 15, 1, 1, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 20
+ { WC_LMS_PARM_L1_H20_W1 , "LMS/HSS_L1_H20_W1",
+ LMS_PARAMS(1, 20, 1, 1, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+#endif
#endif /* !WOLFSSL_NO_LMS_SHA256_256 */
#ifdef WOLFSSL_LMS_SHA256_192
@@ -356,7 +410,193 @@ static const wc_LmsParamsMap wc_lms_map[] = {
LMS_PARAMS(1, 20, 8, 4, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W8,
WC_SHA256_192_DIGEST_SIZE) },
#endif
+#if LMS_MAX_HEIGHT >= 25
+ { WC_LMS_PARM_SHA256_192_L1_H25_W1 , "LMS/HSS_SHA256/192_L1_H25_W1",
+ LMS_PARAMS(1, 25, 1, 2, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHA256_192_L1_H25_W2 , "LMS/HSS_SHA256/192_L1_H25_W2",
+ LMS_PARAMS(1, 25, 2, 2, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W2,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHA256_192_L1_H25_W4 , "LMS/HSS_SHA256/192_L1_H25_W4",
+ LMS_PARAMS(1, 25, 4, 3, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W4,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHA256_192_L1_H25_W8 , "LMS/HSS_SHA256/192_L1_H25_W8",
+ LMS_PARAMS(1, 25, 8, 4, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W8,
+ WC_SHA256_192_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 10
+ { WC_LMS_PARM_SHA256_192_L1_H10_W1 , "LMS/HSS_SHA256/192_L1_H10_W1",
+ LMS_PARAMS(1, 10, 1, 2, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 15
+ { WC_LMS_PARM_SHA256_192_L1_H15_W1 , "LMS/HSS_SHA256/192_L1_H15_W1",
+ LMS_PARAMS(1, 15, 1, 2, LMS_SHA256_M24_H15, LMOTS_SHA256_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHA256_192_L1_H15_W8 , "LMS/HSS_SHA256/192_L1_H15_W8",
+ LMS_PARAMS(1, 15, 8, 4, LMS_SHA256_M24_H15, LMOTS_SHA256_N24_W8,
+ WC_SHA256_192_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 20
+ { WC_LMS_PARM_SHA256_192_L1_H20_W1 , "LMS/HSS_SHA256/192_L1_H20_W1",
+ LMS_PARAMS(1, 20, 1, 2, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+#endif
#endif /* WOLFSSL_LMS_SHA256_192 */
+
+#ifdef WOLFSSL_LMS_SHAKE256
+#ifndef WOLFSSL_NO_LMS_SHAKE256_256
+ /* SHAKE256/256 L1 H5 */
+ { WC_LMS_PARM_SHAKE_L1_H5_W1 , "LMS/HSS_SHAKE256/256_L1_H5_W1",
+ LMS_PARAMS(1, 5, 1, 1, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H5_W2 , "LMS/HSS_SHAKE256/256_L1_H5_W2",
+ LMS_PARAMS(1, 5, 2, 1, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W2,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H5_W4 , "LMS/HSS_SHAKE256/256_L1_H5_W4",
+ LMS_PARAMS(1, 5, 4, 2, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W4,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H5_W8 , "LMS/HSS_SHAKE256/256_L1_H5_W8",
+ LMS_PARAMS(1, 5, 8, 3, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W8,
+ WC_SHA256_DIGEST_SIZE) },
+#if LMS_MAX_HEIGHT >= 10
+ /* SHAKE256/256 L1 H10 */
+ { WC_LMS_PARM_SHAKE_L1_H10_W1 , "LMS/HSS_SHAKE256/256_L1_H10_W1",
+ LMS_PARAMS(1, 10, 1, 1, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H10_W2 , "LMS/HSS_SHAKE256/256_L1_H10_W2",
+ LMS_PARAMS(1, 10, 2, 1, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W2,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H10_W4 , "LMS/HSS_SHAKE256/256_L1_H10_W4",
+ LMS_PARAMS(1, 10, 4, 2, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W4,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H10_W8 , "LMS/HSS_SHAKE256/256_L1_H10_W8",
+ LMS_PARAMS(1, 10, 8, 3, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W8,
+ WC_SHA256_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 15
+ /* SHAKE256/256 L1 H15 */
+ { WC_LMS_PARM_SHAKE_L1_H15_W1 , "LMS/HSS_SHAKE256/256_L1_H15_W1",
+ LMS_PARAMS(1, 15, 1, 1, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H15_W2 , "LMS/HSS_SHAKE256/256_L1_H15_W2",
+ LMS_PARAMS(1, 15, 2, 1, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W2,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H15_W4 , "LMS/HSS_SHAKE256/256_L1_H15_W4",
+ LMS_PARAMS(1, 15, 4, 2, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W4,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H15_W8 , "LMS/HSS_SHAKE256/256_L1_H15_W8",
+ LMS_PARAMS(1, 15, 8, 3, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W8,
+ WC_SHA256_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 20
+ /* SHAKE256/256 L1 H20 */
+ { WC_LMS_PARM_SHAKE_L1_H20_W1 , "LMS/HSS_SHAKE256/256_L1_H20_W1",
+ LMS_PARAMS(1, 20, 1, 1, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H20_W2 , "LMS/HSS_SHAKE256/256_L1_H20_W2",
+ LMS_PARAMS(1, 20, 2, 1, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W2,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H20_W4 , "LMS/HSS_SHAKE256/256_L1_H20_W4",
+ LMS_PARAMS(1, 20, 4, 2, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W4,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H20_W8 , "LMS/HSS_SHAKE256/256_L1_H20_W8",
+ LMS_PARAMS(1, 20, 8, 3, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W8,
+ WC_SHA256_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 25
+ /* SHAKE256/256 L1 H25 */
+ { WC_LMS_PARM_SHAKE_L1_H25_W1 , "LMS/HSS_SHAKE256/256_L1_H25_W1",
+ LMS_PARAMS(1, 25, 1, 1, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W1,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H25_W2 , "LMS/HSS_SHAKE256/256_L1_H25_W2",
+ LMS_PARAMS(1, 25, 2, 1, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W2,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H25_W4 , "LMS/HSS_SHAKE256/256_L1_H25_W4",
+ LMS_PARAMS(1, 25, 4, 2, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W4,
+ WC_SHA256_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE_L1_H25_W8 , "LMS/HSS_SHAKE256/256_L1_H25_W8",
+ LMS_PARAMS(1, 25, 8, 3, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W8,
+ WC_SHA256_DIGEST_SIZE) },
+#endif
+#endif /* !WOLFSSL_NO_LMS_SHAKE256_256 */
+
+#ifdef WOLFSSL_LMS_SHAKE256
+ /* SHAKE256/192 L1 H5 */
+ { WC_LMS_PARM_SHAKE192_L1_H5_W1 , "LMS/HSS_SHAKE256/192_L1_H5_W1",
+ LMS_PARAMS(1, 5, 1, 2, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H5_W2 , "LMS/HSS_SHAKE256/192_L1_H5_W2",
+ LMS_PARAMS(1, 5, 2, 2, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W2,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H5_W4 , "LMS/HSS_SHAKE256/192_L1_H5_W4",
+ LMS_PARAMS(1, 5, 4, 3, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W4,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H5_W8 , "LMS/HSS_SHAKE256/192_L1_H5_W8",
+ LMS_PARAMS(1, 5, 8, 4, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W8,
+ WC_SHA256_192_DIGEST_SIZE) },
+#if LMS_MAX_HEIGHT >= 10
+ /* SHAKE256/192 L1 H10 */
+ { WC_LMS_PARM_SHAKE192_L1_H10_W1 , "LMS/HSS_SHAKE256/192_L1_H10_W1",
+ LMS_PARAMS(1, 10, 1, 2, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H10_W2 , "LMS/HSS_SHAKE256/192_L1_H10_W2",
+ LMS_PARAMS(1, 10, 2, 2, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W2,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H10_W4 , "LMS/HSS_SHAKE256/192_L1_H10_W4",
+ LMS_PARAMS(1, 10, 4, 3, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W4,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H10_W8 , "LMS/HSS_SHAKE256/192_L1_H10_W8",
+ LMS_PARAMS(1, 10, 8, 4, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W8,
+ WC_SHA256_192_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 15
+ /* SHAKE256/192 L1 H15 */
+ { WC_LMS_PARM_SHAKE192_L1_H15_W1 , "LMS/HSS_SHAKE256/192_L1_H15_W1",
+ LMS_PARAMS(1, 15, 1, 2, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H15_W2 , "LMS/HSS_SHAKE256/192_L1_H15_W2",
+ LMS_PARAMS(1, 15, 2, 2, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W2,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H15_W4 , "LMS/HSS_SHAKE256/192_L1_H15_W4",
+ LMS_PARAMS(1, 15, 4, 3, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W4,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H15_W8 , "LMS/HSS_SHAKE256/192_L1_H15_W8",
+ LMS_PARAMS(1, 15, 8, 4, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W8,
+ WC_SHA256_192_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 20
+ /* SHAKE256/192 L1 H20 */
+ { WC_LMS_PARM_SHAKE192_L1_H20_W1 , "LMS/HSS_SHAKE256/192_L1_H20_W1",
+ LMS_PARAMS(1, 20, 1, 2, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H20_W2 , "LMS/HSS_SHAKE256/192_L1_H20_W2",
+ LMS_PARAMS(1, 20, 2, 2, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W2,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H20_W4 , "LMS/HSS_SHAKE256/192_L1_H20_W4",
+ LMS_PARAMS(1, 20, 4, 3, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W4,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H20_W8 , "LMS/HSS_SHAKE256/192_L1_H20_W8",
+ LMS_PARAMS(1, 20, 8, 4, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W8,
+ WC_SHA256_192_DIGEST_SIZE) },
+#endif
+#if LMS_MAX_HEIGHT >= 25
+ /* SHAKE256/192 L1 H25 */
+ { WC_LMS_PARM_SHAKE192_L1_H25_W1 , "LMS/HSS_SHAKE256/192_L1_H25_W1",
+ LMS_PARAMS(1, 25, 1, 2, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W1,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H25_W2 , "LMS/HSS_SHAKE256/192_L1_H25_W2",
+ LMS_PARAMS(1, 25, 2, 2, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W2,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H25_W4 , "LMS/HSS_SHAKE256/192_L1_H25_W4",
+ LMS_PARAMS(1, 25, 4, 3, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W4,
+ WC_SHA256_192_DIGEST_SIZE) },
+ { WC_LMS_PARM_SHAKE192_L1_H25_W8 , "LMS/HSS_SHAKE256/192_L1_H25_W8",
+ LMS_PARAMS(1, 25, 8, 4, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W8,
+ WC_SHA256_192_DIGEST_SIZE) },
+#endif
+#endif /* WOLFSSL_LMS_SHAKE256 (M24 entries) */
+#endif /* WOLFSSL_LMS_SHAKE256 */
};
/* Number of parameter sets supported. */
#define WC_LMS_MAP_LEN ((int)(sizeof(wc_lms_map) / sizeof(*wc_lms_map)))
diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c
index 44191dbb33c..d08590ac282 100644
--- a/wolfcrypt/src/wc_lms_impl.c
+++ b/wolfcrypt/src/wc_lms_impl.c
@@ -594,6 +594,69 @@ static WC_INLINE int wc_lms_hash_sha256_192_final(wc_Sha256* sha256, byte* hash)
}
#endif /* WOLFSSL_LMS_SHA256_192 */
+#ifdef WOLFSSL_LMS_SHAKE256
+/* Hash data using SHAKE256 and compute result.
+ *
+ * @param [in] shake SHAKE256 hash object.
+ * @param [in] data Data to hash.
+ * @param [in] len Length of data to hash.
+ * @param [out] hash Hash output.
+ * @param [in] hashLen Length of hash output.
+ * @return 0 on success.
+ */
+static WC_INLINE int wc_lms_shake256_hash(wc_Shake* shake, byte* data,
+ word32 len, byte* hash, word32 hashLen)
+{
+ int ret;
+
+ ret = wc_Shake256_Update(shake, data, len);
+ if (ret == 0) {
+ ret = wc_Shake256_Final(shake, hash, hashLen);
+ }
+
+ return ret;
+}
+
+/* Update hash with first data using SHAKE256.
+ *
+ * @param [in] shake SHAKE256 hash object.
+ * @param [in] data Data to hash.
+ * @param [in] len Length of data to hash.
+ * @return 0 on success.
+ */
+static WC_INLINE int wc_lms_shake256_hash_first(wc_Shake* shake,
+ const byte* data, word32 len)
+{
+ return wc_Shake256_Update(shake, data, len);
+}
+
+/* Update hash with further data using SHAKE256.
+ *
+ * @param [in] shake SHAKE256 hash object.
+ * @param [in] data Data to hash.
+ * @param [in] len Length of data to hash.
+ * @return 0 on success.
+ */
+static WC_INLINE int wc_lms_shake256_hash_update(wc_Shake* shake,
+ const byte* data, word32 len)
+{
+ return wc_Shake256_Update(shake, data, len);
+}
+
+/* Finalize SHAKE256 hash.
+ *
+ * @param [in] shake SHAKE256 hash object.
+ * @param [out] hash Hash output.
+ * @param [in] hashLen Length of hash output.
+ * @return 0 on success.
+ */
+static WC_INLINE int wc_lms_shake256_hash_final(wc_Shake* shake, byte* hash,
+ word32 hashLen)
+{
+ return wc_Shake256_Final(shake, hash, hashLen);
+}
+#endif /* WOLFSSL_LMS_SHAKE256 */
+
/***************************************
* LM-OTS APIs
**************************************/
@@ -809,33 +872,59 @@ static int wc_lmots_msg_hash(LmsState* state, const byte* msg, word32 msgSz,
/* I || u32str(q) || u16str(D_MESG) */
c16toa(LMS_D_MESG, ip);
- /* H(I || u32str(q) || u16str(D_MESG) || ...) */
- ret = wc_lms_hash_first(&state->hash, buffer, LMS_MSG_PRE_LEN);
- if (ret == 0) {
- /* H(... || C || ...) */
- ret = wc_lms_hash_update(&state->hash, c, state->params->hash_len);
- }
- if (ret == 0) {
- /* H(... || message) */
- ret = wc_lms_hash_update(&state->hash, msg, msgSz);
- }
-#ifdef WOLFSSL_LMS_SHA256_192
- if ((ret == 0) &&
- ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) {
- /* Q = H(...) */
- ret = wc_lms_hash_sha256_192_final(&state->hash, q);
- }
- else
-#endif
-#ifndef WOLFSSL_NO_LMS_SHA256_256
- if (ret == 0) {
- /* Q = H(...) */
- ret = wc_lms_hash_final(&state->hash, q);
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(state->params->lmOtsType)) {
+ /* H(I || u32str(q) || u16str(D_MESG) || ...) */
+ ret = wc_lms_shake256_hash_first(&state->shake, buffer,
+ LMS_MSG_PRE_LEN);
+ if (ret == 0) {
+ /* H(... || C || ...) */
+ ret = wc_lms_shake256_hash_update(&state->shake, c,
+ state->params->hash_len);
+ }
+ if (ret == 0) {
+ /* H(... || message) */
+ ret = wc_lms_shake256_hash_update(&state->shake, msg, msgSz);
+ }
+ if (ret == 0) {
+ /* Q = H(...) */
+ ret = wc_lms_shake256_hash_final(&state->shake, q,
+ state->params->hash_len);
+ }
}
else
#endif
{
- ret = NOT_COMPILED_IN;
+ /* H(I || u32str(q) || u16str(D_MESG) || ...) */
+ ret = wc_lms_hash_first(&state->hash, buffer, LMS_MSG_PRE_LEN);
+ if (ret == 0) {
+ /* H(... || C || ...) */
+ ret = wc_lms_hash_update(&state->hash, c,
+ state->params->hash_len);
+ }
+ if (ret == 0) {
+ /* H(... || message) */
+ ret = wc_lms_hash_update(&state->hash, msg, msgSz);
+ }
+ #ifdef WOLFSSL_LMS_SHA256_192
+ if ((ret == 0) &&
+ ((state->params->lmOtsType & LMS_HASH_MASK) ==
+ LMS_SHA256_192)) {
+ /* Q = H(...) */
+ ret = wc_lms_hash_sha256_192_final(&state->hash, q);
+ }
+ else
+ #endif
+ #ifndef WOLFSSL_NO_LMS_SHA256_256
+ if (ret == 0) {
+ /* Q = H(...) */
+ ret = wc_lms_hash_final(&state->hash, q);
+ }
+ else
+ #endif
+ {
+ ret = NOT_COMPILED_IN;
+ }
}
return ret;
@@ -896,7 +985,12 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed,
params->ls, a);
}
#ifndef WC_LMS_FULL_HASH
- if (ret == 0) {
+#ifdef WOLFSSL_LMS_SHAKE256
+ if ((ret == 0) && !LMS_IS_SHAKE(params->lmOtsType))
+#else
+ if (ret == 0)
+#endif
+ {
#ifdef WOLFSSL_LMS_SHA256_192
if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
/* Put in padding for final block. */
@@ -921,6 +1015,15 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed,
* = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */
c16toa(i, ip);
*jp = LMS_D_FIXED;
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(params->lmOtsType)) {
+ XMEMCPY(tmp, seed, params->hash_len);
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_HASH_BUFFER_LEN(params->hash_len), tmp, params->hash_len);
+ }
+ else
+#endif
+ {
#ifndef WC_LMS_FULL_HASH
#ifdef WOLFSSL_LMS_SHA256_192
if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
@@ -956,12 +1059,22 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed,
#endif
}
#endif /* !WC_LMS_FULL_HASH */
+ }
/* Apply the hash function coefficient number of times. */
for (j = 0; (ret == 0) && (j < a[i]); j++) {
/* I || u32str(q) || u16str(i) || u8str(j) || tmp */
*jp = j;
/* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */
+ #ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(params->lmOtsType)) {
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_HASH_BUFFER_LEN(params->hash_len), tmp,
+ params->hash_len);
+ }
+ else
+ #endif
+ {
#ifndef WC_LMS_FULL_HASH
#ifdef WOLFSSL_LMS_SHA256_192
if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
@@ -993,6 +1106,7 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed,
#endif
}
#endif /* !WC_LMS_FULL_HASH */
+ }
}
if (ret == 0) {
@@ -1055,107 +1169,163 @@ static int wc_lmots_compute_kc_from_sig(LmsState* state, const byte* msg,
/* I || u32str(q) || u16str(D_PBLC). */
c16toa(LMS_D_PBLC, ip);
- /* H(I || u32str(q) || u16str(D_PBLC) || ...). */
- ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN);
- if (ret == 0) {
- /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */
- ret = wc_lmots_msg_hash(state, msg, msgSz, c, q);
- }
- if (ret == 0) {
- /* Calculate checksum list all coefficients. */
- ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width,
- params->ls, a);
- }
-#ifndef WC_LMS_FULL_HASH
- if (ret == 0) {
- #ifdef WOLFSSL_LMS_SHA256_192
- if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
- /* Put in padding for final block. */
- LMS_SHA256_SET_LEN_47(buffer);
- }
- else
- #endif
- {
- #ifndef WOLFSSL_NO_LMS_SHA256_256
- /* Put in padding for final block. */
- LMS_SHA256_SET_LEN_55(buffer);
- #endif
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(params->lmOtsType)) {
+ /* H(I || u32str(q) || u16str(D_PBLC) || ...). */
+ ret = wc_lms_shake256_hash_first(&state->shake_k, buffer,
+ LMS_K_PRE_LEN);
+ if (ret == 0) {
+ /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */
+ ret = wc_lmots_msg_hash(state, msg, msgSz, c, q);
}
- }
-#endif /* !WC_LMS_FULL_HASH */
-
- /* Compute z for each coefficient. */
- for (i = 0; (ret == 0) && (i < params->p); i++) {
- unsigned int j;
-
- /* I || u32(str) || u16str(i) || ... */
- c16toa(i, ip);
+ if (ret == 0) {
+ /* Calculate checksum list all coefficients. */
+ ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width,
+ params->ls, a);
+ }
+
+ /* Compute z for each coefficient. */
+ for (i = 0; (ret == 0) && (i < params->p); i++) {
+ unsigned int j;
+
+ /* I || u32(str) || u16str(i) || ... */
+ c16toa(i, ip);
+
+ /* tmp = y[i].
+ * I || u32(str) || u16str(i) || ... || tmp */
+ XMEMCPY(tmp, sig_y, params->hash_len);
+ sig_y += params->hash_len;
+
+ /* Finish iterations of hash from coefficient to max. */
+ for (j = a[i]; (ret == 0) && (j < max); j++) {
+ /* I || u32str(q) || u16str(i) || u8str(j) || tmp */
+ *jp = (word8)j;
+ /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_HASH_BUFFER_LEN(params->hash_len), tmp,
+ params->hash_len);
+ }
- /* tmp = y[i].
- * I || u32(str) || u16str(i) || ... || tmp */
- XMEMCPY(tmp, sig_y, params->hash_len);
- sig_y += params->hash_len;
+ if (ret == 0) {
+ /* H(... || z[i] || ...) (for calculating Kc). */
+ ret = wc_lms_shake256_hash_update(&state->shake_k, tmp,
+ params->hash_len);
+ }
+ }
- /* Finish iterations of hash from coefficient to max. */
- for (j = a[i]; (ret == 0) && (j < max); j++) {
- /* I || u32str(q) || u16str(i) || u8str(j) || tmp */
- *jp = (word8)j;
- /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */
- #ifndef WC_LMS_FULL_HASH
+ if (ret == 0) {
+ /* Kc = H(...) */
+ ret = wc_lms_shake256_hash_final(&state->shake_k, kc,
+ params->hash_len);
+ }
+ }
+ else
+#endif
+ {
+ /* H(I || u32str(q) || u16str(D_PBLC) || ...). */
+ ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN);
+ if (ret == 0) {
+ /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */
+ ret = wc_lmots_msg_hash(state, msg, msgSz, c, q);
+ }
+ if (ret == 0) {
+ /* Calculate checksum list all coefficients. */
+ ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width,
+ params->ls, a);
+ }
+#ifndef WC_LMS_FULL_HASH
+ if (ret == 0) {
#ifdef WOLFSSL_LMS_SHA256_192
if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
- ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp);
+ /* Put in padding for final block. */
+ LMS_SHA256_SET_LEN_47(buffer);
}
else
#endif
{
#ifndef WOLFSSL_NO_LMS_SHA256_256
- ret = wc_lms_hash_block(&state->hash, buffer, tmp);
- #else
- ret = NOT_COMPILED_IN;
+ /* Put in padding for final block. */
+ LMS_SHA256_SET_LEN_55(buffer);
#endif
}
- /* Apply the hash function coefficient number of times. */
- #else
- #ifdef WOLFSSL_LMS_SHA256_192
- if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
- ret = wc_lms_hash_sha256_192(&state->hash, buffer,
- LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp);
- }
- else
- #endif
- {
- #ifndef WOLFSSL_NO_LMS_SHA256_256
- ret = wc_lms_hash(&state->hash, buffer,
- LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp);
- #else
- ret = NOT_COMPILED_IN;
+ }
+#endif /* !WC_LMS_FULL_HASH */
+
+ /* Compute z for each coefficient. */
+ for (i = 0; (ret == 0) && (i < params->p); i++) {
+ unsigned int j;
+
+ /* I || u32(str) || u16str(i) || ... */
+ c16toa(i, ip);
+
+ /* tmp = y[i].
+ * I || u32(str) || u16str(i) || ... || tmp */
+ XMEMCPY(tmp, sig_y, params->hash_len);
+ sig_y += params->hash_len;
+
+ /* Finish iterations of hash from coefficient to max. */
+ for (j = a[i]; (ret == 0) && (j < max); j++) {
+ /* I || u32str(q) || u16str(i) || u8str(j) || tmp */
+ *jp = (word8)j;
+ /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */
+ #ifndef WC_LMS_FULL_HASH
+ #ifdef WOLFSSL_LMS_SHA256_192
+ if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
+ ret = wc_lms_sha256_192_hash_block(&state->hash, buffer,
+ tmp);
+ }
+ else
+ #endif
+ {
+ #ifndef WOLFSSL_NO_LMS_SHA256_256
+ ret = wc_lms_hash_block(&state->hash, buffer, tmp);
+ #else
+ ret = NOT_COMPILED_IN;
+ #endif
+ }
+ /* Apply the hash function coefficient number of times. */
+ #else
+ #ifdef WOLFSSL_LMS_SHA256_192
+ if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
+ ret = wc_lms_hash_sha256_192(&state->hash, buffer,
+ LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp);
+ }
+ else
#endif
+ {
+ #ifndef WOLFSSL_NO_LMS_SHA256_256
+ ret = wc_lms_hash(&state->hash, buffer,
+ LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp);
+ #else
+ ret = NOT_COMPILED_IN;
+ #endif
+ }
+ #endif /* !WC_LMS_FULL_HASH */
}
- #endif /* !WC_LMS_FULL_HASH */
- }
- if (ret == 0) {
- /* H(... || z[i] || ...) (for calculating Kc). */
- ret = wc_lms_hash_update(&state->hash_k, tmp, params->hash_len);
+ if (ret == 0) {
+ /* H(... || z[i] || ...) (for calculating Kc). */
+ ret = wc_lms_hash_update(&state->hash_k, tmp,
+ params->hash_len);
+ }
}
- }
-#ifdef WOLFSSL_LMS_SHA256_192
- if ((ret == 0) &&
- ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) {
- /* Kc = H(...) */
- ret = wc_lms_hash_sha256_192_final(&state->hash_k, kc);
- }
- else
-#endif
- if (ret == 0) {
- #ifndef WOLFSSL_NO_LMS_SHA256_256
- /* Kc = H(...) */
- ret = wc_lms_hash_final(&state->hash_k, kc);
- #else
- ret = NOT_COMPILED_IN;
+ #ifdef WOLFSSL_LMS_SHA256_192
+ if ((ret == 0) &&
+ ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) {
+ /* Kc = H(...) */
+ ret = wc_lms_hash_sha256_192_final(&state->hash_k, kc);
+ }
+ else
#endif
+ if (ret == 0) {
+ #ifndef WOLFSSL_NO_LMS_SHA256_256
+ /* Kc = H(...) */
+ ret = wc_lms_hash_final(&state->hash_k, kc);
+ #else
+ ret = NOT_COMPILED_IN;
+ #endif
+ }
}
return ret;
@@ -1199,89 +1369,93 @@ static int wc_lmots_make_public_hash(LmsState* state, const byte* seed, byte* k)
/* I || u32str(q) || u16str(D_PBLC). */
c16toa(LMS_D_PBLC, ip);
- /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */
- ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN);
-
-#ifndef WC_LMS_FULL_HASH
-#ifdef WOLFSSL_LMS_SHA256_192
- if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
- /* Put in padding for final block. */
- LMS_SHA256_SET_LEN_47(buffer);
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(params->lmOtsType)) {
+ /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */
+ ret = wc_lms_shake256_hash_first(&state->shake_k, buffer,
+ LMS_K_PRE_LEN);
+
+ for (i = 0; (ret == 0) && (i < params->p); i++) {
+ unsigned int j;
+
+ /* tmp = x[i]
+ * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */
+ c16toa(i, ip);
+ *jp = LMS_D_FIXED;
+ XMEMCPY(tmp, seed, params->hash_len);
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_HASH_BUFFER_LEN(params->hash_len), tmp, params->hash_len);
+ /* Do all iterations to calculate y. */
+ for (j = 0; (ret == 0) && (j < max); j++) {
+ /* I || u32str(q) || u16str(i) || u8str(j) || tmp */
+ *jp = (word8)j;
+ /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_HASH_BUFFER_LEN(params->hash_len), tmp,
+ params->hash_len);
+ }
+ if (ret == 0) {
+ /* K = H(... || y[i] || ...) */
+ ret = wc_lms_shake256_hash_update(&state->shake_k, tmp,
+ params->hash_len);
+ }
+ }
+ if (ret == 0) {
+ /* K = H(I || u32str(q) || u16str(D_PBLC) ||
+ * y[0] || ... || y[p-1]) */
+ ret = wc_lms_shake256_hash_final(&state->shake_k, k,
+ params->hash_len);
+ }
}
else
#endif
{
- #ifndef WOLFSSL_NO_LMS_SHA256_256
- /* Put in padding for final block. */
- LMS_SHA256_SET_LEN_55(buffer);
- #endif
- }
-#endif /* !WC_LMS_FULL_HASH */
+ /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */
+ ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN);
- for (i = 0; (ret == 0) && (i < params->p); i++) {
- unsigned int j;
-
- /* tmp = x[i]
- * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */
- c16toa(i, ip);
- *jp = LMS_D_FIXED;
#ifndef WC_LMS_FULL_HASH
#ifdef WOLFSSL_LMS_SHA256_192
if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
- XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE);
- ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp);
- }
- else
- #endif
- {
- #ifndef WOLFSSL_NO_LMS_SHA256_256
- XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE);
- ret = wc_lms_hash_block(&state->hash, buffer, tmp);
- #else
- ret = NOT_COMPILED_IN;
- #endif
- }
-#else
- #ifdef WOLFSSL_LMS_SHA256_192
- if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
- XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE);
- ret = wc_lms_hash_sha256_192(&state->hash, buffer,
- LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp);
+ /* Put in padding for final block. */
+ LMS_SHA256_SET_LEN_47(buffer);
}
else
#endif
{
#ifndef WOLFSSL_NO_LMS_SHA256_256
- XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE);
- ret = wc_lms_hash(&state->hash, buffer,
- LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp);
- #else
- ret = NOT_COMPILED_IN;
+ /* Put in padding for final block. */
+ LMS_SHA256_SET_LEN_55(buffer);
#endif
}
#endif /* !WC_LMS_FULL_HASH */
- /* Do all iterations to calculate y. */
- for (j = 0; (ret == 0) && (j < max); j++) {
- /* I || u32str(q) || u16str(i) || u8str(j) || tmp */
- *jp = (word8)j;
- /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */
- #ifndef WC_LMS_FULL_HASH
+
+ for (i = 0; (ret == 0) && (i < params->p); i++) {
+ unsigned int j;
+
+ /* tmp = x[i]
+ * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */
+ c16toa(i, ip);
+ *jp = LMS_D_FIXED;
+#ifndef WC_LMS_FULL_HASH
#ifdef WOLFSSL_LMS_SHA256_192
if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
+ XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE);
ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp);
}
else
#endif
{
#ifndef WOLFSSL_NO_LMS_SHA256_256
+ XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE);
ret = wc_lms_hash_block(&state->hash, buffer, tmp);
#else
ret = NOT_COMPILED_IN;
#endif
}
- #else
+#else
#ifdef WOLFSSL_LMS_SHA256_192
if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
+ XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE);
ret = wc_lms_hash_sha256_192(&state->hash, buffer,
LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp);
}
@@ -1289,33 +1463,76 @@ static int wc_lmots_make_public_hash(LmsState* state, const byte* seed, byte* k)
#endif
{
#ifndef WOLFSSL_NO_LMS_SHA256_256
+ XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE);
ret = wc_lms_hash(&state->hash, buffer,
LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp);
#else
ret = NOT_COMPILED_IN;
#endif
}
- #endif /* !WC_LMS_FULL_HASH */
+#endif /* !WC_LMS_FULL_HASH */
+ /* Do all iterations to calculate y. */
+ for (j = 0; (ret == 0) && (j < max); j++) {
+ /* I || u32str(q) || u16str(i) || u8str(j) || tmp */
+ *jp = (word8)j;
+ /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */
+ #ifndef WC_LMS_FULL_HASH
+ #ifdef WOLFSSL_LMS_SHA256_192
+ if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
+ ret = wc_lms_sha256_192_hash_block(&state->hash, buffer,
+ tmp);
+ }
+ else
+ #endif
+ {
+ #ifndef WOLFSSL_NO_LMS_SHA256_256
+ ret = wc_lms_hash_block(&state->hash, buffer, tmp);
+ #else
+ ret = NOT_COMPILED_IN;
+ #endif
+ }
+ #else
+ #ifdef WOLFSSL_LMS_SHA256_192
+ if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
+ ret = wc_lms_hash_sha256_192(&state->hash, buffer,
+ LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp);
+ }
+ else
+ #endif
+ {
+ #ifndef WOLFSSL_NO_LMS_SHA256_256
+ ret = wc_lms_hash(&state->hash, buffer,
+ LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp);
+ #else
+ ret = NOT_COMPILED_IN;
+ #endif
+ }
+ #endif /* !WC_LMS_FULL_HASH */
+ }
+ if (ret == 0) {
+ /* K = H(... || y[i] || ...) */
+ ret = wc_lms_hash_update(&state->hash_k, tmp,
+ params->hash_len);
+ }
}
- if (ret == 0) {
- /* K = H(... || y[i] || ...) */
- ret = wc_lms_hash_update(&state->hash_k, tmp, params->hash_len);
+ #ifdef WOLFSSL_LMS_SHA256_192
+ if ((ret == 0) &&
+ ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) {
+ /* K = H(I || u32str(q) || u16str(D_PBLC) ||
+ * y[0] || ... || y[p-1]) */
+ ret = wc_lms_hash_sha256_192_final(&state->hash_k, k);
}
- }
-#ifdef WOLFSSL_LMS_SHA256_192
- if ((ret == 0) && ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) {
- /* K = H(I || u32str(q) || u16str(D_PBLC) || y[0] || ... || y[p-1]) */
- ret = wc_lms_hash_sha256_192_final(&state->hash_k, k);
- }
- else
-#endif
- if (ret == 0) {
- #ifndef WOLFSSL_NO_LMS_SHA256_256
- /* K = H(I || u32str(q) || u16str(D_PBLC) || y[0] || ... || y[p-1]) */
- ret = wc_lms_hash_final(&state->hash_k, k);
- #else
- ret = NOT_COMPILED_IN;
+ else
#endif
+ if (ret == 0) {
+ #ifndef WOLFSSL_NO_LMS_SHA256_256
+ /* K = H(I || u32str(q) || u16str(D_PBLC) ||
+ * y[0] || ... || y[p-1]) */
+ ret = wc_lms_hash_final(&state->hash_k, k);
+ #else
+ ret = NOT_COMPILED_IN;
+ #endif
+ }
}
return ret;
@@ -1473,6 +1690,19 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg,
c16toa(LMS_D_C, ip);
/* I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || ... */
*jp = LMS_D_FIXED;
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(state->params->lmOtsType)) {
+ /* I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || SEED */
+ XMEMCPY(tmp, seed, state->params->hash_len);
+ /* C = H(I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || SEED)
+ * sig = u32str(type) || C || ... */
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_HASH_BUFFER_LEN(state->params->hash_len), sig_c,
+ state->params->hash_len);
+ }
+ else
+#endif
+ {
#ifndef WC_LMS_FULL_HASH
#ifdef WOLFSSL_LMS_SHA256_192
if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
@@ -1524,6 +1754,7 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg,
#endif
}
#endif /* !WC_LMS_FULL_HASH */
+ }
if (ret == 0) {
byte* sig_y = sig_c + state->params->hash_len;
@@ -1671,6 +1902,15 @@ static int wc_lms_leaf_hash(LmsState* state, const byte* seed, word32 i,
/* I || u32str(r) || u16str(D_LEAF) || OTS_PUB_HASH[i] */
c16toa(LMS_D_LEAF, dp);
/* temp = H(I || u32str(r) || u16str(D_LEAF) || OTS_PUB_HASH[i]) */
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(state->params->lmOtsType)) {
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_SEED_HASH_LEN(state->params->hash_len), leaf,
+ state->params->hash_len);
+ }
+ else
+#endif
+ {
#ifndef WC_LMS_FULL_HASH
/* Put in padding for final block. */
#ifdef WOLFSSL_LMS_SHA256_192
@@ -1705,6 +1945,7 @@ static int wc_lms_leaf_hash(LmsState* state, const byte* seed, word32 i,
#endif
}
#endif /* !WC_LMS_FULL_HASH */
+ }
}
return ret;
@@ -1735,6 +1976,18 @@ static int wc_lms_interior_hash(LmsState* state, byte* sp, word32 r,
/* I || u32str(r) || u16str(D_INTR) || ... || temp */
c32toa(r, rp);
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(state->params->lmOtsType)) {
+ /* left_side = pop(data stack)
+ * I || u32str(r) || u16str(D_INTR) || left_side || temp */
+ XMEMCPY(left, sp, state->params->hash_len);
+ /* temp = H(I || u32str(r) || u16str(D_INTR) || left_side || temp) */
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_NODE_HASH_LEN(state->params->hash_len), node,
+ state->params->hash_len);
+ }
+ else
+#endif
#ifdef WOLFSSL_LMS_SHA256_192
if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
/* left_side = pop(data stack)
@@ -2304,6 +2557,19 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc,
c16toa(LMS_D_LEAF, ip);
XMEMCPY(node, kc, params->hash_len);
/* Put tmp into offset required for first iteration. */
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(params->lmOtsType)) {
+ b[0][0] = node;
+ b[0][1] = node + params->hash_len;
+ b[1][0] = node + params->hash_len;
+ b[1][1] = node;
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_SEED_HASH_LEN(params->hash_len), b[r & 1][0],
+ params->hash_len);
+ }
+ else
+#endif
+ {
#ifndef WC_LMS_FULL_HASH
/* Put in padding for final block. */
#ifdef WOLFSSL_LMS_SHA256_192
@@ -2354,6 +2620,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc,
#endif
}
#endif /* !WC_LMS_FULL_HASH */
+ }
if (ret == 0) {
int i;
@@ -2362,6 +2629,32 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc,
c16toa(LMS_D_INTR, ip);
/* Do all but last height. */
+ #ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(params->lmOtsType)) {
+ for (i = 0; (ret == 0) && (i < params->height - 1); i++) {
+ /* Put path into offset required. */
+ XMEMCPY(b[r & 1][1], path, params->hash_len);
+ path += params->hash_len;
+
+ /* node_num = node_num / 2 */
+ r >>= 1;
+ /* H(...||u32str(node_num/2)||..) */
+ c32toa(r, rp);
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_NODE_HASH_LEN(params->hash_len), b[r & 1][0],
+ params->hash_len);
+ }
+ if (ret == 0) {
+ /* Last height. */
+ XMEMCPY(b[r & 1][1], path, params->hash_len);
+ r >>= 1;
+ c32toa(r, rp);
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_NODE_HASH_LEN(params->hash_len), tc, params->hash_len);
+ }
+ }
+ else
+ #endif
#ifdef WOLFSSL_LMS_SHA256_192
if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
for (i = 0; (ret == 0) && (i < params->height - 1); i++) {
@@ -2503,6 +2796,18 @@ static int wc_lms_verify(LmsState* state, const byte* pub, const byte* msg,
ret = wc_lmots_calc_kc(state, pub + LMS_TYPE_LEN, msg, msgSz,
sig_lmots, kc);
}
+ if (ret == 0) {
+ /* Algorithm 6a. Step 3.d-e: Check LMS type in signature matches
+ * the expected type from the public key. */
+ const byte* sig_lms_type = sig + LMS_Q_LEN + LMS_TYPE_LEN +
+ params->hash_len + params->p * params->hash_len;
+ word32 sigType;
+
+ ato32(sig_lms_type, &sigType);
+ if (sigType != (params->lmsType & LMS_H_W_MASK)) {
+ ret = SIG_TYPE_E;
+ }
+ }
if (ret == 0) {
/* Algorithm 6a. Step 2.j. */
const byte* sig_path = sig + LMS_Q_LEN + LMS_TYPE_LEN +
@@ -2559,6 +2864,18 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id,
/* parent's I || q || D_CHILD_SEED || D_FIXED || parent's SEED */
XMEMCPY(tmp, seed, state->params->hash_len);
/* SEED = H(parent's I || q || D_CHILD_SEED || D_FIXED || parent's SEED) */
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(state->params->lmOtsType)) {
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_HASH_BUFFER_LEN(state->params->hash_len), seed_i,
+ state->params->hash_len);
+ if (ret == 0) {
+ seed_i += state->params->hash_len;
+ }
+ }
+ else
+#endif
+ {
#ifndef WC_LMS_FULL_HASH
#ifdef WOLFSSL_LMS_SHA256_192
if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
@@ -2600,11 +2917,21 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id,
#endif
}
#endif /* !WC_LMS_FULL_HASH */
+ }
if (ret == 0) {
/* parent's I || q || D_CHILD_I || D_FIXED || parent's SEED */
c16toa(LMS_D_CHILD_I, ip);
/* I = H(parent's I || q || D_CHILD_I || D_FIXED || parent's SEED) */
+#ifdef WOLFSSL_LMS_SHAKE256
+ if (LMS_IS_SHAKE(state->params->lmOtsType)) {
+ ret = wc_lms_shake256_hash(&state->shake, buffer,
+ LMS_HASH_BUFFER_LEN(state->params->hash_len), tmp,
+ state->params->hash_len);
+ }
+ else
+#endif
+ {
#ifndef WC_LMS_FULL_HASH
#ifdef WOLFSSL_LMS_SHA256_192
if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) {
@@ -2636,6 +2963,7 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id,
#endif
}
#endif /* !WC_LMS_FULL_HASH */
+ }
/* Copy part of hash as new I into private key. */
XMEMCPY(seed_i, tmp, LMS_I_LEN);
}
diff --git a/wolfcrypt/src/wc_mlkem.c b/wolfcrypt/src/wc_mlkem.c
index 99b08fda915..99af9d11ac8 100644
--- a/wolfcrypt/src/wc_mlkem.c
+++ b/wolfcrypt/src/wc_mlkem.c
@@ -71,6 +71,11 @@
#undef WOLFSSL_RISCV_ASM
#endif
+#if FIPS_VERSION3_GE(2,0,0)
+ /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+ #define FIPS_NO_WRAPPERS
+#endif
+
#include
#include
#include
@@ -392,6 +397,35 @@ int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng)
ret = wc_KyberKey_MakeKeyWithRandom(key, rand, sizeof(rand));
}
+#ifdef HAVE_FIPS
+ /* Pairwise Consistency Test (PCT) per FIPS 140-3 / ISO 19790:2012
+ * Section 7.10.3.3: encapsulate with ek, decapsulate with dk,
+ * verify shared secrets match. */
+ if (ret == 0) {
+ byte pct_ct[WC_ML_KEM_MAX_CIPHER_TEXT_SIZE];
+ byte pct_ss1[WC_ML_KEM_SS_SZ];
+ byte pct_ss2[WC_ML_KEM_SS_SZ];
+ word32 ctSz = 0;
+
+ ret = wc_MlKemKey_CipherTextSize(key, &ctSz);
+
+ if (ret == 0)
+ ret = wc_MlKemKey_Encapsulate(key, pct_ct, pct_ss1, rng);
+
+ if (ret == 0)
+ ret = wc_MlKemKey_Decapsulate(key, pct_ss2, pct_ct, ctSz);
+
+ if (ret == 0) {
+ if (XMEMCMP(pct_ss1, pct_ss2, WC_ML_KEM_SS_SZ) != 0)
+ ret = ML_KEM_PCT_E;
+ }
+
+ ForceZero(pct_ss1, sizeof(pct_ss1));
+ ForceZero(pct_ss2, sizeof(pct_ss2));
+ ForceZero(pct_ct, sizeof(pct_ct));
+ }
+#endif /* HAVE_FIPS */
+
/* Ensure seeds are zeroized. */
ForceZero((void*)rand, (word32)sizeof(rand));
@@ -647,6 +681,9 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand,
}
#endif
+ /* Note: PCT is performed in wc_MlKemKey_MakeKey() which calls this
+ * function and has the RNG parameter needed for encapsulation. */
+
return ret;
}
#endif /* !WOLFSSL_MLKEM_NO_MAKE_KEY */
diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c
index 46adf35f72b..b25a878c1aa 100644
--- a/wolfcrypt/src/wc_slhdsa.c
+++ b/wolfcrypt/src/wc_slhdsa.c
@@ -21,6 +21,11 @@
#include
+#if FIPS_VERSION3_GE(2,0,0)
+ /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+ #define FIPS_NO_WRAPPERS
+#endif
+
#include
#ifdef WOLFSSL_HAVE_SLHDSA
@@ -35,6 +40,11 @@
#endif
#include
#include
+#ifdef WOLFSSL_SLHDSA_SHA2
+ #include
+ #include
+ #include
+#endif
#if defined(USE_INTEL_SPEEDUP)
/* CPU information for Intel. */
@@ -370,6 +380,27 @@ static const SlhDsaParameters SlhDsaParams[] =
#ifndef WOLFSSL_SLHDSA_PARAM_NO_256F
SLHDSA_PARAMETERS(SLHDSA_SHAKE256F, 32, 68, 17, 4, 9, 35),
#endif
+#ifdef WOLFSSL_SLHDSA_SHA2
+ /* n, h, d, h_m, a, k */
+#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S
+ SLHDSA_PARAMETERS(SLHDSA_SHA2_128S, 16, 63, 7, 9, 12, 14),
+#endif
+#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F
+ SLHDSA_PARAMETERS(SLHDSA_SHA2_128F, 16, 66, 22, 3, 6, 33),
+#endif
+#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S
+ SLHDSA_PARAMETERS(SLHDSA_SHA2_192S, 24, 63, 7, 9, 14, 17),
+#endif
+#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F
+ SLHDSA_PARAMETERS(SLHDSA_SHA2_192F, 24, 66, 22, 3, 8, 33),
+#endif
+#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S
+ SLHDSA_PARAMETERS(SLHDSA_SHA2_256S, 32, 64, 8, 8, 14, 22),
+#endif
+#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F
+ SLHDSA_PARAMETERS(SLHDSA_SHA2_256F, 32, 68, 17, 4, 9, 35),
+#endif
+#endif /* WOLFSSL_SLHDSA_SHA2 */
};
/* Number of parameters in array. */
@@ -571,32 +602,758 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1,
}
else
#endif
- {
- /* Process the state using C code. */
- BlockSha3(state);
- }
- /* Copy hash result, of the required length, from the state into hash. */
- XMEMCPY(hash, shake->s, hash_len);
+ {
+ /* Process the state using C code. */
+ BlockSha3(state);
+ }
+ /* Copy hash result, of the required length, from the state into hash. */
+ XMEMCPY(hash, shake->s, hash_len);
+
+ return 0;
+#else
+ /* Copy the first block of data into the cached data buffer. */
+ XMEMCPY(shake->t, data1, data1_len);
+ /* Encode HashAddress into the cached data buffer next. */
+ HA_Encode(adrs, shake->t + data1_len);
+ /* Copy the second block of data into the cached data buffer next. */
+ XMEMCPY(shake->t + data1_len + SLHDSA_HA_SZ, data2, data2_len);
+ /* Copy the third block of data into the cached data buffer next. */
+ XMEMCPY(shake->t + data1_len + SLHDSA_HA_SZ + data2_len, data3, data3_len);
+
+ /* Update count of bytes cached. */
+ shake->i = data1_len + SLHDSA_HA_SZ + data2_len + data3_len;
+
+ /* Calculate and output hash. */
+ return wc_Shake256_Final(shake, hash, hash_len);
+#endif
+}
+
+/******************************************************************************
+ * SHA2 Hash Functions (FIPS 205, Section 11.2)
+ ******************************************************************************/
+
+#ifdef WOLFSSL_SLHDSA_SHA2
+
+/* Size of compressed HashAddress (ADRS^c) per FIPS 205 Section 11.2. */
+#define SLHDSA_HAC_SZ 22
+
+/* Encode a compressed HashAddress (ADRS^c).
+ *
+ * FIPS 205. Section 11.2.
+ * Byte 0: low byte of adrs[0] (layer)
+ * Bytes 1-8: adrs[2..3] (low 8 bytes of tree address)
+ * Byte 9: low byte of adrs[4] (type)
+ * Bytes 10-21: adrs[5..7] (remaining 12 bytes, verbatim)
+ *
+ * @param [in] adrs HashAddress to encode (8 x word32).
+ * @param [out] address Buffer to encode into (22 bytes).
+ */
+static void HA_Encode_Compressed(const word32* adrs, byte* address)
+{
+ /* Byte 0: low byte of layer address. */
+ address[0] = (byte)adrs[0];
+ /* Bytes 1-4: adrs[2] (tree address high word). */
+ c32toa(adrs[2], address + 1);
+ /* Bytes 5-8: adrs[3] (tree address low word). */
+ c32toa(adrs[3], address + 5);
+ /* Byte 9: low byte of type. */
+ address[9] = (byte)adrs[4];
+ /* Bytes 10-13: adrs[5] (key pair address / padding). */
+ c32toa(adrs[5], address + 10);
+ /* Bytes 14-17: adrs[6] (chain address / tree height). */
+ c32toa(adrs[6], address + 14);
+ /* Bytes 18-21: adrs[7] (hash address / tree index). */
+ c32toa(adrs[7], address + 18);
+}
+
+/* Pre-compute SHA2 midstates for PK.seed.
+ *
+ * SHA-256: PK.seed || pad(64 - n) is exactly one 64-byte block.
+ * SHA-512: PK.seed || pad(128 - n) is exactly one 128-byte block.
+ *
+ * @param [in, out] key SLH-DSA key with pk_seed set at key->sk[2*n].
+ * @return 0 on success.
+ */
+static int slhdsakey_precompute_sha2_midstates(SlhDsaKey* key)
+{
+ int ret;
+ byte n = key->params->n;
+ const byte* pk_seed = key->sk + 2 * n;
+ byte block[WC_SHA512_BLOCK_SIZE];
+
+ /* SHA-256 midstate: PK.seed || zeros to fill 64-byte block. */
+ XMEMSET(block, 0, WC_SHA256_BLOCK_SIZE);
+ XMEMCPY(block, pk_seed, n);
+ ret = wc_InitSha256(&key->hash.sha2.sha256_mid);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_mid, block,
+ WC_SHA256_BLOCK_SIZE);
+ }
+
+ /* SHA-512 midstate: PK.seed || zeros to fill 128-byte block.
+ * Only needed for categories 3 and 5 (n > 16). */
+ if ((ret == 0) && (n > 16)) {
+ XMEMSET(block, 0, WC_SHA512_BLOCK_SIZE);
+ XMEMCPY(block, pk_seed, n);
+ ret = wc_InitSha512(&key->hash.sha2.sha512_mid);
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_mid, block,
+ WC_SHA512_BLOCK_SIZE);
+ }
+ }
+
+ return ret;
+}
+
+/* SHA2 F function.
+ *
+ * FIPS 205. Section 11.2.
+ * F(PK.seed, ADRS, M1) = Trunc_n(SHA-256(PK.seed||pad(64-n)||ADRS^c||M1))
+ *
+ * Uses pre-computed midstate for the first block.
+ *
+ * @param [in] key SLH-DSA key (SHA2 hash objects + midstate).
+ * @param [in] pk_seed Public key seed (unused - midstate).
+ * @param [in] adrs HashAddress.
+ * @param [in] m Message of n bytes.
+ * @param [in] n Number of bytes in hash output.
+ * @param [out] hash Buffer to hold hash output.
+ * @return 0 on success.
+ */
+static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed,
+ const word32* adrs, const byte* m, byte n, byte* hash)
+{
+ int ret;
+ byte address[SLHDSA_HAC_SZ];
+ byte digest[WC_SHA256_DIGEST_SIZE];
+
+ (void)pk_seed;
+
+ /* Encode compressed address. */
+ HA_Encode_Compressed(adrs, address);
+
+ /* Restore SHA-256 midstate. */
+ ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256);
+ if (ret == 0) {
+ /* Update with compressed ADRS and message. */
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, m, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Final(&key->hash.sha2.sha256, digest);
+ }
+ if (ret == 0) {
+ /* Truncate to n bytes. */
+ XMEMCPY(hash, digest, n);
+ }
+
+ return ret;
+}
+
+/* SHA2 H function.
+ *
+ * FIPS 205. Section 11.2.
+ * Cat 1: H(PK.seed, ADRS, M2) = Trunc_n(SHA-256(PK.seed||pad||ADRS^c||M2))
+ * Cat 3,5: H(PK.seed, ADRS, M2) = Trunc_n(SHA-512(PK.seed||pad||ADRS^c||M2))
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] pk_seed Public key seed (unused - midstate).
+ * @param [in] adrs HashAddress.
+ * @param [in] node Message of 2n bytes.
+ * @param [in] n Number of bytes in hash output.
+ * @param [out] hash Buffer to hold hash output.
+ * @return 0 on success.
+ */
+static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed,
+ const word32* adrs, const byte* node, byte n, byte* hash)
+{
+ int ret;
+ byte address[SLHDSA_HAC_SZ];
+
+ (void)pk_seed;
+
+ /* Encode compressed address. */
+ HA_Encode_Compressed(adrs, address);
+
+ if (n == 16) {
+ /* Category 1: use SHA-256. */
+ byte digest[WC_SHA256_DIGEST_SIZE];
+
+ ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid,
+ &key->hash.sha2.sha256);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, address,
+ SLHDSA_HAC_SZ);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, node, 2 * n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Final(&key->hash.sha2.sha256, digest);
+ }
+ if (ret == 0) {
+ XMEMCPY(hash, digest, n);
+ }
+ }
+ else {
+ /* Categories 3, 5: use SHA-512. */
+ byte digest[WC_SHA512_DIGEST_SIZE];
+
+ ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid,
+ &key->hash.sha2.sha512);
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512, address,
+ SLHDSA_HAC_SZ);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512, node, 2 * n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Final(&key->hash.sha2.sha512, digest);
+ }
+ if (ret == 0) {
+ XMEMCPY(hash, digest, n);
+ }
+ }
+
+ return ret;
+}
+
+/* SHA2 H function with two separate n-byte halves.
+ *
+ * Same as slhdsakey_hash_h_sha2 but M2 = m1 || m2.
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] pk_seed Public key seed (unused - midstate).
+ * @param [in] adrs HashAddress.
+ * @param [in] m1 First n bytes of message.
+ * @param [in] m2 Second n bytes of message.
+ * @param [in] n Number of bytes in hash output.
+ * @param [out] hash Buffer to hold hash output.
+ * @return 0 on success.
+ */
+static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed,
+ const word32* adrs, const byte* m1, const byte* m2, byte n, byte* hash)
+{
+ int ret;
+ byte address[SLHDSA_HAC_SZ];
+
+ (void)pk_seed;
+
+ /* Encode compressed address. */
+ HA_Encode_Compressed(adrs, address);
+
+ if (n == 16) {
+ /* Category 1: use SHA-256. */
+ byte digest[WC_SHA256_DIGEST_SIZE];
+
+ ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid,
+ &key->hash.sha2.sha256);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, address,
+ SLHDSA_HAC_SZ);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, m1, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, m2, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Final(&key->hash.sha2.sha256, digest);
+ }
+ if (ret == 0) {
+ XMEMCPY(hash, digest, n);
+ }
+ }
+ else {
+ /* Categories 3, 5: use SHA-512. */
+ byte digest[WC_SHA512_DIGEST_SIZE];
+
+ ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid,
+ &key->hash.sha2.sha512);
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512, address,
+ SLHDSA_HAC_SZ);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512, m1, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512, m2, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Final(&key->hash.sha2.sha512, digest);
+ }
+ if (ret == 0) {
+ XMEMCPY(hash, digest, n);
+ }
+ }
+
+ return ret;
+}
+
+/* SHA2 PRF function.
+ *
+ * FIPS 205. Section 11.2.
+ * PRF(PK.seed, SK.seed, ADRS) =
+ * Trunc_n(SHA-256(PK.seed || pad(64-n) || ADRS^c || SK.seed))
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] pk_seed Public key seed (unused - midstate).
+ * @param [in] sk_seed Private key seed.
+ * @param [in] adrs HashAddress.
+ * @param [in] n Number of bytes in hash output.
+ * @param [out] hash Buffer to hold hash output.
+ * @return 0 on success.
+ */
+static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed,
+ const byte* sk_seed, const word32* adrs, byte n, byte* hash)
+{
+ int ret;
+ byte address[SLHDSA_HAC_SZ];
+ byte digest[WC_SHA256_DIGEST_SIZE];
+
+ (void)pk_seed;
+
+ /* Encode compressed address. */
+ HA_Encode_Compressed(adrs, address);
+
+ /* Restore SHA-256 midstate. */
+ ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256, sk_seed, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Final(&key->hash.sha2.sha256, digest);
+ }
+ if (ret == 0) {
+ XMEMCPY(hash, digest, n);
+ }
+
+ return ret;
+}
+
+/* SHA2 T_l streaming: start with address.
+ *
+ * Restores midstate then updates with compressed ADRS.
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] pk_seed Public key seed (unused - midstate).
+ * @param [in] adrs HashAddress.
+ * @param [in] n Number of bytes of hash output (determines cat).
+ * @return 0 on success.
+ */
+static int slhdsakey_hash_start_addr_sha2(SlhDsaKey* key,
+ const byte* pk_seed, const word32* adrs, byte n)
+{
+ int ret;
+ byte address[SLHDSA_HAC_SZ];
+
+ (void)pk_seed;
+
+ HA_Encode_Compressed(adrs, address);
+
+ if (n == 16) {
+ /* Category 1: SHA-256 -- use sha256_2 (T_l must not collide with
+ * sha256 which is used by F and H). */
+ ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid,
+ &key->hash.sha2.sha256_2);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, address,
+ SLHDSA_HAC_SZ);
+ }
+ }
+ else {
+ /* Categories 3, 5: SHA-512 -- use sha512_2 (T_l must not collide
+ * with sha512 which is used by H). */
+ ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid,
+ &key->hash.sha2.sha512_2);
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, address,
+ SLHDSA_HAC_SZ);
+ }
+ }
+
+ return ret;
+}
+
+/* SHA2 T_l streaming: update with data.
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] data Data to hash.
+ * @param [in] len Length of data.
+ * @return 0 on success.
+ */
+static int slhdsakey_hash_update_sha2(SlhDsaKey* key, const byte* data,
+ word32 len)
+{
+ if (key->params->n == 16) {
+ return wc_Sha256Update(&key->hash.sha2.sha256_2, data, len);
+ }
+ else {
+ return wc_Sha512Update(&key->hash.sha2.sha512_2, data, len);
+ }
+}
+
+/* SHA2 T_l streaming: finalize.
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [out] hash Output buffer.
+ * @param [in] len Desired output length (truncate to n).
+ * @return 0 on success.
+ */
+static int slhdsakey_hash_final_sha2(SlhDsaKey* key, byte* hash, word32 len)
+{
+ int ret;
+ byte n = key->params->n;
+
+ if (n == 16) {
+ byte digest[WC_SHA256_DIGEST_SIZE];
+ ret = wc_Sha256Final(&key->hash.sha2.sha256_2, digest);
+ if (ret == 0) {
+ XMEMCPY(hash, digest, (len < n) ? len : n);
+ }
+ }
+ else {
+ byte digest[WC_SHA512_DIGEST_SIZE];
+ ret = wc_Sha512Final(&key->hash.sha2.sha512_2, digest);
+ if (ret == 0) {
+ XMEMCPY(hash, digest, (len < n) ? len : n);
+ }
+ }
+
+ return ret;
+}
+
+/* Local MGF1 implementation for H_msg.
+ *
+ * FIPS 205. Section 11.2.
+ * H_msg uses MGF1-SHA-256/512(R || PK.seed || digest, m) where m is the
+ * required output length.
+ *
+ * @param [in] key SLH-DSA key (for hash objects).
+ * @param [in] seed Seed data for MGF1.
+ * @param [in] seedLen Length of seed.
+ * @param [out] out Output buffer.
+ * @param [in] outLen Required output length.
+ * @return 0 on success.
+ */
+static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed,
+ word32 seedLen, byte* out, word32 outLen)
+{
+ int ret = 0;
+ word32 counter = 0;
+ word32 done = 0;
+ byte n = key->params->n;
+
+ while ((ret == 0) && (done < outLen)) {
+ byte cBuf[4];
+ word32 left = outLen - done;
+
+ c32toa(counter, cBuf);
+
+ if (n == 16) {
+ /* Category 1: MGF1-SHA-256. */
+ byte digest[WC_SHA256_DIGEST_SIZE];
+ word32 cpLen = (left < WC_SHA256_DIGEST_SIZE) ?
+ left : WC_SHA256_DIGEST_SIZE;
+
+ ret = wc_InitSha256(&key->hash.sha2.sha256_2);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, seed, seedLen);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, cBuf, 4);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Final(&key->hash.sha2.sha256_2, digest);
+ }
+ if (ret == 0) {
+ XMEMCPY(out + done, digest, cpLen);
+ done += cpLen;
+ }
+ }
+ else {
+ /* Categories 3, 5: MGF1-SHA-512. */
+ byte digest[WC_SHA512_DIGEST_SIZE];
+ word32 cpLen = (left < WC_SHA512_DIGEST_SIZE) ?
+ left : WC_SHA512_DIGEST_SIZE;
+
+ ret = wc_InitSha512(&key->hash.sha2.sha512_2);
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, seed, seedLen);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, cBuf, 4);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Final(&key->hash.sha2.sha512_2, digest);
+ }
+ if (ret == 0) {
+ XMEMCPY(out + done, digest, cpLen);
+ done += cpLen;
+ }
+ }
+ counter++;
+ }
+
+ return ret;
+}
+
+/* SHA2 PRF_msg function.
+ *
+ * FIPS 205. Section 11.2.
+ * PRF_msg(SK.prf, opt_rand, M) =
+ * Trunc_n(HMAC-SHA-256/512(SK.prf, opt_rand || M))
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] sk_prf SK.prf seed.
+ * @param [in] opt_rand Random or PK.seed.
+ * @param [in] hdr Message header (2 bytes).
+ * @param [in] ctx Context data (may be NULL).
+ * @param [in] ctxSz Context data length.
+ * @param [in] msg Message data.
+ * @param [in] msgSz Message data length.
+ * @param [in] n Number of bytes in hash output.
+ * @param [out] hash Buffer to hold hash output.
+ * @return 0 on success.
+ */
+static int slhdsakey_prf_msg_sha2(SlhDsaKey* key, const byte* sk_prf,
+ const byte* opt_rand, const byte* hdr, const byte* ctx, byte ctxSz,
+ const byte* msg, word32 msgSz, byte n, byte* hash)
+{
+ int ret;
+ Hmac hmac;
+ int hmacType;
+ byte digest[WC_SHA512_DIGEST_SIZE];
+
+ if (n == 16) {
+ hmacType = WC_SHA256;
+ }
+ else {
+ hmacType = WC_SHA512;
+ }
+
+ ret = wc_HmacInit(&hmac, key->heap, INVALID_DEVID);
+ if (ret == 0) {
+ ret = wc_HmacSetKey(&hmac, hmacType, sk_prf, n);
+ }
+ if (ret == 0) {
+ ret = wc_HmacUpdate(&hmac, opt_rand, n);
+ }
+ if ((ret == 0) && (hdr != NULL)) {
+ ret = wc_HmacUpdate(&hmac, hdr, 2);
+ }
+ if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) {
+ ret = wc_HmacUpdate(&hmac, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = wc_HmacUpdate(&hmac, msg, msgSz);
+ }
+ if (ret == 0) {
+ ret = wc_HmacFinal(&hmac, digest);
+ }
+ wc_HmacFree(&hmac);
+
+ if (ret == 0) {
+ XMEMCPY(hash, digest, n);
+ }
+
+ return ret;
+}
+
+/* SHA2 H_msg function.
+ *
+ * FIPS 205. Section 11.2.
+ * H_msg(R, PK.seed, PK.root, M) = MGF1-SHA-256/512(
+ * R || PK.seed || SHA-256/512(R || PK.seed || PK.root || M), m)
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] r Randomizer (n bytes from signature).
+ * @param [in] hdr Message header (2 bytes).
+ * @param [in] ctx Context data (may be NULL).
+ * @param [in] ctxSz Context data length.
+ * @param [in] msg Message data.
+ * @param [in] msgSz Message data length.
+ * @param [out] md Output message digest.
+ * @param [in] mdLen Required digest length (dl1+dl2+dl3).
+ * @return 0 on success.
+ */
+static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r,
+ const byte* hdr, const byte* ctx, byte ctxSz, const byte* msg,
+ word32 msgSz, byte* md, word32 mdLen)
+{
+ int ret;
+ byte n = key->params->n;
+ const byte* pk_seed = key->sk + 2 * n;
+ const byte* pk_root = key->sk + 3 * n;
+
+ if (n == 16) {
+ /* Category 1: SHA-256 + MGF1-SHA-256. */
+ byte innerHash[WC_SHA256_DIGEST_SIZE];
+ /* Seed for MGF1: R || PK.seed || innerHash. */
+ byte mgfSeed[32 + 16 + WC_SHA256_DIGEST_SIZE];
+
+ /* Step 1: innerHash = SHA-256(R || PK.seed || PK.root || M). */
+ ret = wc_InitSha256(&key->hash.sha2.sha256_2);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, r, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, pk_seed, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, pk_root, n);
+ }
+ if ((ret == 0) && (hdr != NULL)) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, hdr, 2);
+ }
+ if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Update(&key->hash.sha2.sha256_2, msg, msgSz);
+ }
+ if (ret == 0) {
+ ret = wc_Sha256Final(&key->hash.sha2.sha256_2, innerHash);
+ }
+
+ /* Step 2: MGF1-SHA-256(R || PK.seed || innerHash, mdLen). */
+ if (ret == 0) {
+ XMEMCPY(mgfSeed, r, n);
+ XMEMCPY(mgfSeed + n, pk_seed, n);
+ XMEMCPY(mgfSeed + 2 * n, innerHash, WC_SHA256_DIGEST_SIZE);
+ ret = slhdsakey_mgf1_sha2(key, mgfSeed,
+ 2 * n + WC_SHA256_DIGEST_SIZE, md, mdLen);
+ }
+ }
+ else {
+ /* Categories 3, 5: SHA-512 + MGF1-SHA-512. */
+ byte innerHash[WC_SHA512_DIGEST_SIZE];
+ /* Seed for MGF1: R || PK.seed || innerHash. */
+ byte mgfSeed[32 + 32 + WC_SHA512_DIGEST_SIZE];
+
+ /* Step 1: innerHash = SHA-512(R || PK.seed || PK.root || M). */
+ ret = wc_InitSha512(&key->hash.sha2.sha512_2);
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, r, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, pk_seed, n);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, pk_root, n);
+ }
+ if ((ret == 0) && (hdr != NULL)) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, hdr, 2);
+ }
+ if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Update(&key->hash.sha2.sha512_2, msg, msgSz);
+ }
+ if (ret == 0) {
+ ret = wc_Sha512Final(&key->hash.sha2.sha512_2, innerHash);
+ }
+
+ /* Step 2: MGF1-SHA-512(R || PK.seed || innerHash, mdLen). */
+ if (ret == 0) {
+ XMEMCPY(mgfSeed, r, n);
+ XMEMCPY(mgfSeed + n, pk_seed, n);
+ XMEMCPY(mgfSeed + 2 * n, innerHash, WC_SHA512_DIGEST_SIZE);
+ ret = slhdsakey_mgf1_sha2(key, mgfSeed,
+ 2 * n + WC_SHA512_DIGEST_SIZE, md, mdLen);
+ }
+ }
+
+ return ret;
+}
+
+#endif /* WOLFSSL_SLHDSA_SHA2 */
+
+/******************************************************************************
+ * Dispatching Hash Macros
+ ******************************************************************************/
+
+/* When WOLFSSL_SLHDSA_SHA2 is defined, macros dispatch between SHAKE and SHA2
+ * based on the key's parameter set. When not defined, macros call SHAKE
+ * directly (zero overhead). */
+
+#ifdef WOLFSSL_SLHDSA_SHA2
+
+/* SHAKE wrapper functions for SHA2 dispatch macros. */
+static int slhdsakey_hash_f_shake(SlhDsaKey* key, const byte* pk_seed,
+ const word32* adrs, const byte* m, byte n, byte* hash)
+{
+#ifndef WOLFSSL_WC_SLHDSA_SMALL
+ return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs, m,
+ n, hash, n);
+#else
+ return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, m,
+ n, NULL, 0, hash, n);
+#endif
+}
- return 0;
+static int slhdsakey_hash_h_shake(SlhDsaKey* key, const byte* pk_seed,
+ const word32* adrs, const byte* node, byte n, byte* hash)
+{
+#ifndef WOLFSSL_WC_SLHDSA_SMALL
+ return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs, node,
+ 2 * n, hash, n);
#else
- /* Copy the first block of data into the cached data buffer. */
- XMEMCPY(shake->t, data1, data1_len);
- /* Encode HashAddress into the cached data buffer next. */
- HA_Encode(adrs, shake->t + data1_len);
- /* Copy the second block of data into the cached data buffer next. */
- XMEMCPY(shake->t + data1_len + SLHDSA_HA_SZ, data2, data2_len);
- /* Copy the third block of data into the cached data buffer next. */
- XMEMCPY(shake->t + data1_len + SLHDSA_HA_SZ + data2_len, data3, data3_len);
+ return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, node,
+ 2 * n, NULL, 0, hash, n);
+#endif
+}
- /* Update count of bytes cached. */
- shake->i = data1_len + SLHDSA_HA_SZ + data2_len + data3_len;
+static int slhdsakey_hash_h_2_shake(SlhDsaKey* key, const byte* pk_seed,
+ const word32* adrs, const byte* m1, const byte* m2, byte n, byte* hash)
+{
+ return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, m1,
+ n, m2, n, hash, n);
+}
- /* Calculate and output hash. */
- return wc_Shake256_Final(shake, hash, hash_len);
+static int slhdsakey_hash_prf_shake(SlhDsaKey* key, const byte* pk_seed,
+ const byte* sk_seed, const word32* adrs, byte n, byte* hash)
+{
+#ifndef WOLFSSL_WC_SLHDSA_SMALL
+ return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs,
+ sk_seed, n, hash, n);
+#else
+ return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs,
+ sk_seed, n, NULL, 0, hash, n);
#endif
}
+#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \
+ (SLHDSA_IS_SHA2((k)->params->param) ? \
+ slhdsakey_hash_prf_sha2(k, pk_seed, sk_seed, adrs, n, o) : \
+ slhdsakey_hash_prf_shake(k, pk_seed, sk_seed, adrs, n, o))
+
+#define HASH_F(k, pk_seed, adrs, m, n, o) \
+ (SLHDSA_IS_SHA2((k)->params->param) ? \
+ slhdsakey_hash_f_sha2(k, pk_seed, adrs, m, n, o) : \
+ slhdsakey_hash_f_shake(k, pk_seed, adrs, m, n, o))
+
+#define HASH_H(k, pk_seed, adrs, node, n, o) \
+ (SLHDSA_IS_SHA2((k)->params->param) ? \
+ slhdsakey_hash_h_sha2(k, pk_seed, adrs, node, n, o) : \
+ slhdsakey_hash_h_shake(k, pk_seed, adrs, node, n, o))
+
+#define HASH_H_2(k, pk_seed, adrs, m1, m2, n, o) \
+ (SLHDSA_IS_SHA2((k)->params->param) ? \
+ slhdsakey_hash_h_2_sha2(k, pk_seed, adrs, m1, m2, n, o) : \
+ slhdsakey_hash_h_2_shake(k, pk_seed, adrs, m1, m2, n, o))
+
+#else /* !WOLFSSL_SLHDSA_SHA2 */
+
#ifndef WOLFSSL_WC_SLHDSA_SMALL
/* PRF hash.
*
@@ -606,7 +1363,7 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1,
* FIPS 205. Section 11.1.
* PRF(PK.seed, SK.seed, ADRS) = SHAKE256(PK.seed || ADRS || SK.seed, 8n)
*
- * @param [in] shake SHAKE-256 object.
+ * @param [in] key SLH-DSA key.
* @param [in] pk_seed Public key seed.
* @param [in] sk_seed Private key seed.
* @param [in] adrs HashAddress.
@@ -615,128 +1372,70 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1,
* @return 0 on success.
* @return SHAKE-256 error return code on digest failure.
*/
-#define HASH_PRF(shake, pk_seed, sk_seed, adrs, n, hash) \
- slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, sk_seed, n, hash, n)
-/* Hash F.
- *
- * FIPS 205. Section 4.1.
- * F(PK.seed, ADRS, M1) (Bn x B32 x Bn -> Bn ) is a hash function that takes
- * an n-byte message as input and produces an n-byte output.
- * FIPS 205. Section 11.1.
- * F(PK.seed, ADRS, M1) = SHAKE256(PK.seed || ADRS || M1, 8n)
- *
- * @param [in] shake SHAKE-256 object.
- * @param [in] pk_seed Public key seed.
- * @param [in] adrs HashAddress.
- * @param [in] m Message of n bytes.
- * @param [in] n Number of bytes in hash output.
- * @param [out] hash Buffer to hold hash output.
- * @return 0 on success.
- * @return SHAKE-256 error return code on digest failure.
- */
-#define HASH_F(shake, pk_seed, adrs, m, n, hash) \
- slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, m, n, hash, n)
-/* Hash H.
- *
- * FIPS 205. Section 4.1.
- * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that
- * takes a 2n-byte message as input.
- * FIPS 205. Section 11.1.
- * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n)
- *
- * @param [in] shake SHAKE-256 object.
- * @param [in] pk_seed Public key seed.
- * @param [in] adrs HashAddress.
- * @param [in] m Message of 2*n bytes.
- * @param [in] n Number of bytes in hash output.
- * @param [out] hash Buffer to hold hash output.
- * @return 0 on success.
- * @return SHAKE-256 error return code on digest failure.
- */
-#define HASH_H(shake, pk_seed, adrs, node, n, hash) \
- slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, node, 2 * (n), hash, (n))
+#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \
+ slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, \
+ sk_seed, n, o, n)
+/* Hash F. */
+#define HASH_F(k, pk_seed, adrs, m, n, o) \
+ slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, m, n, \
+ o, n)
+/* Hash H. */
+#define HASH_H(k, pk_seed, adrs, node, n, o) \
+ slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, node, \
+ 2 * (n), o, (n))
#else
-/* PRF hash.
- *
- * FIPS 205. Section 4.1.
- * PRF(PK.seed, SK.seed, ADRS) (Bn x Bn x B32 -> Bn) is a PRF that is used to
- * generate the secret values in WOTS+ and FORS private keys.
- * FIPS 205. Section 11.1.
- * F(PK.seed, SK.seed, ADRS) = SHAKE256(PK.seed || ADRS || SK.seed, 8n)
- *
- * @param [in] shake SHAKE-256 object.
- * @param [in] pk_seed Public key seed.
- * @param [in] sk_seed Private key seed.
- * @param [in] adrs HashAddress.
- * @param [in] n Number of bytes in hash output.
- * @param [out] hash Buffer to hold hash output.
- * @return 0 on success.
- * @return SHAKE-256 error return code on digest failure.
- */
-#define HASH_PRF(shake, pk_seed, sk_seed, adrs, n, hash) \
- slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, sk_seed, n, NULL, 0, \
- hash, n)
-/* Hash F.
- *
- * FIPS 205. Section 4.1.
- * F(PK.seed, ADRS, M1) (Bn x B32 x Bn -> Bn ) is a hash function that takes
- * an n-byte message as input and produces an n-byte output.
- * FIPS 205. Section 11.1.
- * F(PK.seed, ADRS, M1) = SHAKE256(PK.seed || ADRS || M1, 8n)
- *
- * @param [in] shake SHAKE-256 object.
- * @param [in] pk_seed Public key seed.
- * @param [in] adrs HashAddress.
- * @param [in] m Message of n bytes.
- * @param [in] n Number of bytes in hash output.
- * @param [out] hash Buffer to hold hash output.
- * @return 0 on success.
- * @return SHAKE-256 error return code on digest failure.
- */
-#define HASH_F(shake, pk_seed, adrs, m, n, hash) \
- slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, m, n, NULL, 0, hash, n)
-/* Hash H.
- *
- * FIPS 205. Section 4.1.
- * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that
- * takes a 2n-byte message as input.
- * FIPS 205. Section 11.1.
- * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n)
- *
- * @param [in] shake SHAKE-256 object.
- * @param [in] pk_seed Public key seed.
- * @param [in] adrs HashAddress.
- * @param [in] m Message of 2*n bytes.
- * @param [in] n Number of bytes in hash output.
- * @param [out] hash Buffer to hold hash output.
- * @return 0 on success.
- * @return SHAKE-256 error return code on digest failure.
- */
-#define HASH_H(shake, pk_seed, adrs, node, n, hash) \
- slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, node, 2 * n, NULL, 0, \
- hash, n)
+/* PRF hash. */
+#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \
+ slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, \
+ sk_seed, n, NULL, 0, o, n)
+/* Hash F. */
+#define HASH_F(k, pk_seed, adrs, m, n, o) \
+ slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, m, n, \
+ NULL, 0, o, n)
+/* Hash H. */
+#define HASH_H(k, pk_seed, adrs, node, n, o) \
+ slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, node, \
+ 2 * n, NULL, 0, o, n)
#endif
-/* Hash H with 2n byte message as two separate n byte parameters.
- *
- * FIPS 205. Section 4.1.
- * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that
- * takes a 2n-byte message as input.
- * FIPS 205. Section 11.1.
- * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n)
- *
- * @param [in] shake SHAKE-256 object.
- * @param [in] pk_seed Public key seed.
- * @param [in] adrs HashAddress.
- * @param [in] m1 First n bytes of message.
- * @param [in] m2 Second n bytes of message.
- * @param [in] n Number of bytes in hash output.
- * @param [out] hash Buffer to hold hash output.
- * @return 0 on success.
- * @return SHAKE-256 error return code on digest failure.
- */
-#define HASH_H_2(shake, pk_seed, adrs, m1, m2, n, hash) \
- slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, m1, n, m2, n, hash, n)
+/* Hash H with 2n byte message as two separate n byte parameters. */
+#define HASH_H_2(k, pk_seed, adrs, m1, m2, n, o) \
+ slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, m1, n, \
+ m2, n, o, n)
+
+#endif /* WOLFSSL_SLHDSA_SHA2 */
+
+/* T_l streaming dispatch macros for the secondary hash (used by WOTS+ pk
+ * compression and FORS root computation). */
+#ifdef WOLFSSL_SLHDSA_SHA2
+
+#define HASH_T_START_ADDR(k, pk_seed, adrs, n) \
+ (SLHDSA_IS_SHA2((k)->params->param) ? \
+ slhdsakey_hash_start_addr_sha2(k, pk_seed, adrs, n) : \
+ slhdsakey_hash_start_addr(&(k)->hash.shk.shake2, pk_seed, adrs, n))
+
+#define HASH_T_UPDATE(k, d, l) \
+ (SLHDSA_IS_SHA2((k)->params->param) ? \
+ slhdsakey_hash_update_sha2(k, d, l) : \
+ slhdsakey_hash_update(&(k)->hash.shk.shake2, d, l))
+
+#define HASH_T_FINAL(k, o, l) \
+ (SLHDSA_IS_SHA2((k)->params->param) ? \
+ slhdsakey_hash_final_sha2(k, o, l) : \
+ slhdsakey_hash_final(&(k)->hash.shk.shake2, o, l))
+
+#else
+
+#define HASH_T_START_ADDR(k, pk_seed, adrs, n) \
+ slhdsakey_hash_start_addr(&(k)->hash.shk.shake2, pk_seed, adrs, n)
+
+#define HASH_T_UPDATE(k, d, l) \
+ slhdsakey_hash_update(&(k)->hash.shk.shake2, d, l)
+
+#define HASH_T_FINAL(k, o, l) \
+ slhdsakey_hash_final(&(k)->hash.shk.shake2, o, l)
+
+#endif /* WOLFSSL_SLHDSA_SHA2 */
/* Start hashing with SHAKE-256.
*
@@ -925,13 +1624,13 @@ static int slhdsakey_chain(SlhDsaKey* key, const byte* x, byte i, byte s,
/* Set the hash address for first iteration. */
HA_SetHashAddress(adrs, i);
/* First iteration of hash using input and writing to output buffers. */
- ret = HASH_F(&key->shake, pk_seed, adrs, x, n, node);
+ ret = HASH_F(key, pk_seed, adrs, x, n, node);
if (ret == 0) {
for (j = i + 1; j < i + s; j++) {
/* Set the hash address. */
HA_SetHashAddress(adrs, j);
/* Iterate hash using output buffer as input. */
- ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node);
+ ret = HASH_F(key, pk_seed, adrs, node, n, node);
if (ret != 0) {
break;
}
@@ -2139,7 +2838,7 @@ static int slhdsakey_wots_pkgen_chain_x4_16(SlhDsaKey* key, const byte* sk_seed,
}
}
if (ret == 0) {
- ret = slhdsakey_hash_update(&key->shake2, sk, len * 16);
+ ret = HASH_T_UPDATE(key, sk, len * 16);
}
WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -2207,7 +2906,7 @@ static int slhdsakey_wots_pkgen_chain_x4_24(SlhDsaKey* key, const byte* sk_seed,
}
}
if (ret == 0) {
- ret = slhdsakey_hash_update(&key->shake2, sk, len * 24);
+ ret = HASH_T_UPDATE(key, sk, len * 24);
}
WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -2275,7 +2974,7 @@ static int slhdsakey_wots_pkgen_chain_x4_32(SlhDsaKey* key, const byte* sk_seed,
}
}
if (ret == 0) {
- ret = slhdsakey_hash_update(&key->shake2, sk, len * 32);
+ ret = HASH_T_UPDATE(key, sk, len * 32);
}
WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -2396,7 +3095,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed,
/* Step 5. Set chain address for WOTS PRF. */
HA_SetChainAddress(sk_adrs, i);
/* Step 6. PRF hash seeds and chain address. */
- ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n,
+ ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n,
sk + i * n);
if (ret != 0) {
break;
@@ -2413,7 +3112,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed,
}
if (ret == 0) {
/* Step 13: Compress public key. */
- ret = slhdsakey_hash_update(&key->shake2, sk, len * n);
+ ret = HASH_T_UPDATE(key, sk, len * n);
}
WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA);
#else
@@ -2424,7 +3123,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed,
/* Step 5. Set chain address for WOTS PRF. */
HA_SetChainAddress(sk_adrs, i);
/* Step 6. PRF hash seeds and chain address. */
- ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n, sk);
+ ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n, sk);
if (ret != 0) {
break;
}
@@ -2437,7 +3136,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed,
}
/* Step 13: Compress public key - for each tmp. */
- ret = slhdsakey_hash_update(&key->shake2, sk, n);
+ ret = HASH_T_UPDATE(key, sk, n);
if (ret != 0) {
break;
}
@@ -2482,7 +3181,7 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed,
HA_Copy(wotspk_adrs, adrs);
HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK);
/* Step 13. Start hash with public key seed and address. */
- ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n);
+ ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n);
}
if (ret == 0) {
HashAddress sk_adrs;
@@ -2506,7 +3205,7 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed,
}
if (ret == 0) {
/* Step 13: Output hash of compressed public key. */
- ret = slhdsakey_hash_final(&key->shake2, node, n);
+ ret = HASH_T_FINAL(key, node, n);
}
return ret;
@@ -2908,7 +3607,7 @@ static int slhdsakey_wots_sign(SlhDsaKey* key, const byte* m,
/* Step 12: Set chain address for WOTS PRF. */
HA_SetChainAddress(sk_adrs, i);
/* Step 13. PRF hash seeds and chain address. */
- ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n, sig);
+ ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n, sig);
if (ret != 0) {
break;
}
@@ -3281,14 +3980,14 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig,
if (ret == 0) {
HA_Copy(wotspk_adrs, adrs);
HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK);
- ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n);
+ ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n);
}
if (ret == 0) {
- ret = slhdsakey_hash_update(&key->shake2, nodes, len * n);
+ ret = HASH_T_UPDATE(key, nodes, len * n);
sig += len * n;
}
if (ret == 0) {
- ret = slhdsakey_hash_final(&key->shake2, pk_sig, n);
+ ret = HASH_T_FINAL(key, pk_sig, n);
}
WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -3354,15 +4053,15 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig,
HA_Copy(wotspk_adrs, adrs);
HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK);
/* Step 15: Hash the public key seed and WOTS PK address ... */
- ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n);
+ ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n);
}
if (ret == 0) {
/* Step 15: Update with the nodes ... */
- ret = slhdsakey_hash_update(&key->shake2, nodes, len * n);
+ ret = HASH_T_UPDATE(key, nodes, len * n);
}
if (ret == 0) {
/* Step 15: Generate root node - public key signature. */
- ret = slhdsakey_hash_final(&key->shake2, pk_sig, n);
+ ret = HASH_T_FINAL(key, pk_sig, n);
}
WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -3408,7 +4107,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig,
HA_Copy(wotspk_adrs, adrs);
HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK);
/* Step 15: Hash the public key seed and WOTS PK address ... */
- ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n);
+ ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n);
if (ret == 0) {
/* Step 8: For each value in msg. */
for (i = 0; i < len; i++) {
@@ -3421,7 +4120,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig,
break;
}
/* Step 15: Update with node ... */
- ret = slhdsakey_hash_update(&key->shake2, node, n);
+ ret = HASH_T_UPDATE(key, node, n);
if (ret != 0) {
break;
}
@@ -3431,7 +4130,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig,
}
if (ret == 0) {
/* Step 15: Generate root node - public key signature. */
- ret = slhdsakey_hash_final(&key->shake2, pk_sig, n);
+ ret = HASH_T_FINAL(key, pk_sig, n);
}
return ret;
@@ -3587,7 +4286,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i,
HA_SetTreeHeight(adrs, z - k);
HA_SetTreeIndex(adrs, (m * i + j) >> (z - k));
/* Step 11: Calculate node from two below. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes + k * n,
+ ret = HASH_H(key, pk_seed, adrs, nodes + k * n,
n, nodes + (k - 1 + ((j >> (z-k)) & 1)) * n);
if (ret != 0) {
break;
@@ -3608,7 +4307,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i,
HA_SetTreeHeight(adrs, z);
HA_SetTreeIndex(adrs, i);
/* Step 11: Calculate node from two below. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, node);
}
}
@@ -3679,7 +4378,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i,
HA_SetTreeHeight(adrs, z);
HA_SetTreeIndex(adrs, i);
/* Step 11: Calculate node from two below. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, node);
}
}
@@ -3829,11 +4528,11 @@ static int slhdsakey_xmss_pk_from_sig(SlhDsaKey* key, word32 idx,
/* Step 10: Check which order to put nodes. */
if (side == 0) {
/* Steps 12,17: Calculate node with sig node on right. */
- ret = HASH_H_2(&key->shake, pk_seed, adrs, node, auth, n, node);
+ ret = HASH_H_2(key, pk_seed, adrs, node, auth, n, node);
}
else {
/* Steps 15,17: Calculate node with sig node on left. */
- ret = HASH_H_2(&key->shake, pk_seed, adrs, auth, node, n, node);
+ ret = HASH_H_2(key, pk_seed, adrs, auth, node, n, node);
}
if (ret != 0) {
break;
@@ -4076,7 +4775,7 @@ static int slhdsakey_fors_sk_gen(SlhDsaKey* key, const byte* sk_seed,
/* Step 4: Set tree index. */
HA_SetTreeIndex(sk_adrs, idx);
/* Step 5: Hash seeds and address. */
- return HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, key->params->n,
+ return HASH_PRF(key, pk_seed, sk_seed, sk_adrs, key->params->n,
node);
}
@@ -4297,7 +4996,7 @@ static int slhdsakey_fors_node_x4_z0(SlhDsaKey* key, const byte* sk_seed,
/* Step 4: Set tree index. */
HA_SetTreeIndex(adrs, i);
/* Step 5: Compute node from public key seed, address and value. */
- ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node);
+ ret = HASH_F(key, pk_seed, adrs, node, n, node);
}
return ret;
@@ -4349,7 +5048,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed,
/* Step 4: Set tree index. */
HA_SetTreeIndex(adrs, 2 * i + 0);
/* Step 5: Compute node from public key seed, address and value. */
- ret = HASH_F(&key->shake, pk_seed, adrs, nodes, n, nodes);
+ ret = HASH_F(key, pk_seed, adrs, nodes, n, nodes);
}
/* Step 8: Compute right node. */
if (ret == 0) {
@@ -4361,7 +5060,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed,
/* Step 4: Set tree index. */
HA_SetTreeIndex(adrs, 2 * i + 1);
/* Step 5: Compute node from public key seed, address and value. */
- ret = HASH_F(&key->shake, pk_seed, adrs, nodes + n, n, nodes + n);
+ ret = HASH_F(key, pk_seed, adrs, nodes + n, n, nodes + n);
}
if (ret == 0) {
/* Step 9: Set tree height. */
@@ -4369,7 +5068,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed,
/* Step 10: Set tree index. */
HA_SetTreeIndex(adrs, i);
/* Step 11: Compute node from public key seed, address and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, node);
}
return ret;
@@ -4480,14 +5179,14 @@ static int slhdsakey_fors_node_x4_low(SlhDsaKey* key, const byte* sk_seed,
/* Step 10: Set tree index. */
HA_SetTreeIndex(adrs, 2 * i + 0);
/* Step 11: Compute node from public key seed, address and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, nodes);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, nodes);
}
/* Step 8: Compute right node. */
if (ret == 0) {
/* Step 10: Set tree index. */
HA_SetTreeIndex(adrs, 2 * i + 1);
/* Step 11: Compute node from public key seed, address and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes + 2 * n, n,
+ ret = HASH_H(key, pk_seed, adrs, nodes + 2 * n, n,
nodes + 1 * n);
}
if (ret == 0) {
@@ -4496,7 +5195,7 @@ static int slhdsakey_fors_node_x4_low(SlhDsaKey* key, const byte* sk_seed,
/* Step 10: Set tree index. */
HA_SetTreeIndex(adrs, i);
/* Step 11: Compute node from public key seed, address and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, node);
}
WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -4592,14 +5291,14 @@ static int slhdsakey_fors_node_x4_high(SlhDsaKey* key, const byte* sk_seed,
/* Step 10: Set tree index. */
HA_SetTreeIndex(adrs, 2 * i + 0);
/* Step 11: Compute node from public key seed, address and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, nodes);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, nodes);
}
/* Step 8: Compute right node. */
if ((ret == 0) && (z2 > 1)) {
/* Step 10: Set tree index. */
HA_SetTreeIndex(adrs, 2 * i + 1);
/* Step 11: Compute node from public key seed, address and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes + 2 * n, n,
+ ret = HASH_H(key, pk_seed, adrs, nodes + 2 * n, n,
nodes + 1 * n);
}
if (ret == 0) {
@@ -4608,7 +5307,7 @@ static int slhdsakey_fors_node_x4_high(SlhDsaKey* key, const byte* sk_seed,
/* Step 10: Set tree index. */
HA_SetTreeIndex(adrs, i);
/* Step 11: Compute node from public key seed, address and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, node);
}
WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -4725,7 +5424,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i,
/* Step 4: Set tree index. */
HA_SetTreeIndex(adrs, i);
/* Step 5: Compute node from public key seed, address and value. */
- ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node);
+ ret = HASH_F(key, pk_seed, adrs, node, n, node);
}
}
/* Step 6: Non leaf node. */
@@ -4754,7 +5453,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i,
HA_SetTreeIndex(adrs, m * i + j);
/* Step 5: Compute node from public key seed, address and value.
*/
- ret = HASH_F(&key->shake, pk_seed, adrs, nodes + o, n,
+ ret = HASH_F(key, pk_seed, adrs, nodes + o, n,
nodes + o);
if (ret != 0) {
break;
@@ -4771,7 +5470,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i,
HA_SetTreeIndex(adrs, (m * i + j) >> (z - k));
/* Step 11: Compute node from public key seed, address
* and left and right nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes + k * n,
+ ret = HASH_H(key, pk_seed, adrs, nodes + k * n,
n, nodes + (k - 1 + ((j >> (z-k)) & 1)) * n);
if (ret != 0) {
break;
@@ -4790,7 +5489,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i,
HA_SetTreeIndex(adrs, i);
/* Step 11: Compute node from public key seed, address
* and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, node);
}
}
@@ -4847,7 +5546,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i,
/* Step 4: Set tree index. */
HA_SetTreeIndex(adrs, i);
/* Step 5: Compute node from public key seed, address and value. */
- ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node);
+ ret = HASH_F(key, pk_seed, adrs, node, n, node);
}
}
else {
@@ -4867,7 +5566,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i,
/* Step 10: Set tree index. */
HA_SetTreeIndex(adrs, i);
/* Step 11: Compute node from public key seed, address and nodes. */
- ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node);
+ ret = HASH_H(key, pk_seed, adrs, nodes, n, node);
}
}
@@ -5275,7 +5974,7 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors,
/* Step 5: Set tree index for address. */
HA_SetTreeIndex(adrs, idx);
/* Step 6: Compute node from public key seed, address and value. */
- ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node + i * n);
+ ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node + i * n);
if (ret != 0) {
break;
}
@@ -5296,12 +5995,12 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors,
/* Step 10: Check which side node is on. */
if (side == 0) {
/* Step 12: Hash node || auth node. */
- ret = HASH_H_2(&key->shake, pk_seed, adrs, node + i * n,
+ ret = HASH_H_2(key, pk_seed, adrs, node + i * n,
sig_fors, n, node + i * n);
}
else {
/* Step 15: Hash auth node || node. */
- ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors,
+ ret = HASH_H_2(key, pk_seed, adrs, sig_fors,
node + i * n, n, node + i * n);
}
if (ret != 0) {
@@ -5317,7 +6016,7 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors,
}
if (ret == 0) {
/* Step 24: Add more root nodes to hash ... */
- ret = slhdsakey_hash_update(&key->shake2, node, i * n);
+ ret = HASH_T_UPDATE(key, node, i * n);
}
WC_FREE_VAR_EX(node, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -5394,7 +6093,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors,
/* Step 5: Set tree index for address. */
HA_SetTreeIndex(adrs, idx);
/* Step 6: Compute node from public key seed, address and value. */
- ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node + i * n);
+ ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node + i * n);
if (ret != 0) {
break;
}
@@ -5415,12 +6114,12 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors,
/* Step 10: Check which side node is on. */
if (bit == 0) {
/* Step 12: Hash node || auth node. */
- ret = HASH_H_2(&key->shake, pk_seed, adrs, node + i * n,
+ ret = HASH_H_2(key, pk_seed, adrs, node + i * n,
sig_fors, n, node + i * n);
}
else {
/* Step 15: Hash auth node || node. */
- ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors,
+ ret = HASH_H_2(key, pk_seed, adrs, sig_fors,
node + i * n, n, node + i * n);
}
if (ret != 0) {
@@ -5436,7 +6135,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors,
}
if (ret == 0) {
/* Step 24: Add more root nodes to hash ... */
- ret = slhdsakey_hash_update(&key->shake2, node, i * n);
+ ret = HASH_T_UPDATE(key, node, i * n);
}
WC_FREE_VAR_EX(node, key->heap, DYNAMIC_TYPE_SLHDSA);
@@ -5505,7 +6204,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors,
/* Step 5: Set tree index for address. */
HA_SetTreeIndex(adrs, idx);
/* Step 6: Compute node from public key seed, address and value. */
- ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node);
+ ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node);
if (ret != 0) {
break;
}
@@ -5526,12 +6225,12 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors,
/* Step 10: Check which side node is on. */
if (bit == 0) {
/* Step 12: Hash node || auth node. */
- ret = HASH_H_2(&key->shake, pk_seed, adrs, node, sig_fors, n,
+ ret = HASH_H_2(key, pk_seed, adrs, node, sig_fors, n,
node);
}
else {
/* Step 15: Hash auth node || node. */
- ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors, node, n,
+ ret = HASH_H_2(key, pk_seed, adrs, sig_fors, node, n,
node);
}
if (ret != 0) {
@@ -5542,7 +6241,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors,
}
if (ret == 0) {
/* Step 24: Add root node to hash ... */
- ret = slhdsakey_hash_update(&key->shake2, node, n);
+ ret = HASH_T_UPDATE(key, node, n);
}
if (ret != 0) {
break;
@@ -5595,7 +6294,7 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors,
/* Steps 22-23: Set type and clear all but key pair address. */
HA_SetTypeAndClearNotKPA(forspk_adrs, HA_FORS_ROOTS);
/* Step 24: Add public key seed and FORS roots address to hash ... */
- ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, forspk_adrs, n);
+ ret = HASH_T_START_ADDR(key, pk_seed, forspk_adrs, n);
/* Steps 2-20: Compute roots and add to hash. */
#if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL)
@@ -5614,7 +6313,7 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors,
if (ret == 0) {
/* Step 24. Compute FORS public key. */
- ret = slhdsakey_hash_final(&key->shake2, pk_fors, n);
+ ret = HASH_T_FINAL(key, pk_fors, n);
}
return ret;
@@ -5664,15 +6363,7 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap,
/* Zeroize key. */
XMEMSET(key, 0, sizeof(SlhDsaKey));
- /* Initialize SHAKE-256 object. */
- ret = wc_InitShake256(&key->shake, key->heap, INVALID_DEVID);
- }
- if (ret == 0) {
- /* Initialize second SHAKE-256 object. */
- ret = wc_InitShake256(&key->shake2, key->heap, INVALID_DEVID);
- }
- if (ret == 0) {
- /* Set the parameters into key. */
+ /* Set the parameters into key early so SLHDSA_IS_SHA2 works. */
key->params = &SlhDsaParams[idx];
/* Set heap hint to use with all allocations. */
key->heap = heap;
@@ -5680,6 +6371,32 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap,
/* Set device id. */
key->devId = devId;
#endif
+
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(param)) {
+ /* Initialize SHA2 hash objects. */
+ ret = wc_InitSha256(&key->hash.sha2.sha256);
+ if (ret == 0) {
+ ret = wc_InitSha256(&key->hash.sha2.sha256_2);
+ }
+ if ((ret == 0) && (key->params->n > 16)) {
+ ret = wc_InitSha512(&key->hash.sha2.sha512);
+ if (ret == 0) {
+ ret = wc_InitSha512(&key->hash.sha2.sha512_2);
+ }
+ }
+ }
+ else
+#endif
+ {
+ /* Initialize SHAKE-256 objects. */
+ ret = wc_InitShake256(&key->hash.shk.shake, key->heap,
+ INVALID_DEVID);
+ if (ret == 0) {
+ ret = wc_InitShake256(&key->hash.shk.shake2, key->heap,
+ INVALID_DEVID);
+ }
+ }
}
(void)devId;
@@ -5701,9 +6418,25 @@ void wc_SlhDsaKey_Free(SlhDsaKey* key)
if ((key != NULL) && (key->params != NULL)) {
/* Ensure the private key data is zeroized. */
ForceZero(key->sk, key->params->n * 2);
- /* Dispose of the SHAKE-256 objects. */
- wc_Shake256_Free(&key->shake2);
- wc_Shake256_Free(&key->shake);
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ /* Dispose of the SHA2 hash objects. */
+ wc_Sha256Free(&key->hash.sha2.sha256);
+ wc_Sha256Free(&key->hash.sha2.sha256_2);
+ wc_Sha256Free(&key->hash.sha2.sha256_mid);
+ if (key->params->n > 16) {
+ wc_Sha512Free(&key->hash.sha2.sha512);
+ wc_Sha512Free(&key->hash.sha2.sha512_2);
+ wc_Sha512Free(&key->hash.sha2.sha512_mid);
+ }
+ }
+ else
+#endif
+ {
+ /* Dispose of the SHAKE-256 objects. */
+ wc_Shake256_Free(&key->hash.shk.shake2);
+ wc_Shake256_Free(&key->hash.shk.shake);
+ }
}
}
@@ -5890,6 +6623,16 @@ int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key, const byte* sk_seed,
XMEMCPY(key->sk + 2 * n, pk_seed, n);
}
+#ifdef WOLFSSL_SLHDSA_SHA2
+ /* Pre-compute SHA2 midstates now that PK.seed is set. */
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ ret = slhdsakey_precompute_sha2_midstates(key);
+ }
+ if (ret != 0) {
+ return ret;
+ }
+#endif
+
/* Step 1: Set address to all zeroes. */
HA_Init(adrs);
/* Step 2: Set the address layer to the top of the subtree. */
@@ -5965,36 +6708,113 @@ static int slhdsakey_sign(SlhDsaKey* key, byte* md, byte* sig)
return ret;
}
-/* Generate a pure SLH-DSA signature.
+/* Lower-level sign: slh_sign_internal(M, SK, addrnd).
*
- * FIPS 205. Section 10.2.2. Algorithm 22.
- * slh_sign(M, ctx, SK)
- * 1: if |ctx| > 255 then
- * 2: return falsity
- * > return an error indication if the context string is too long
- * 3: end if
- * 4: addrnd <-$- Bn > skip lines 4 through 7 for the deterministic variant
- * 5: if addrnd = NULL then
- * 6: return falsity
- * > return an error indication if random bit generation failed
- * 7: end if
- * 8: M' <- toByte(0, 1) || toByte(|ctx|, 1) || ctx || M
- * > omit addrnd for the deterministic variant
- * 9: SIG <- slh_sign_internal(M', SK, addrnd)
- * 10: return SIG
+ * Takes M directly and performs PRF_msg, H_msg, and the FORS + hypertree
+ * signing -- Algorithm 19 without the M' construction of Algorithm 22.
*
* FIPS 205. Section 9.2. Algorithm 19.
* slh_sign_internal(M, SK, addrnd)
- * ...
* 2: opt_rand <- addrnd
- * > substitute opt_rand <- PK.seed for the deterministic variant
- * 3: R <- PRFmsg (SK.prf, opt_rand, M) > generate randomizer
+ * 3: R <- PRFmsg(SK.prf, opt_rand, M)
* 4: SIG <- R
- * 5: digest <- Hmsg(R, PK.seed, PK.root, M) > compute message digest
- * 6: md <- digest [0 : upper(k.a / 8)] > first upper(k.a / 8)] bytes
+ * 5: digest <- Hmsg(R, PK.seed, PK.root, M)
+ * 6: md <- digest[0 : upper(k*a / 8)]
* ...
*
- * Note: ctx length is of type byte which means it can never be more than 255.
+ * @param [in] key SLH-DSA key (private key must be set).
+ * @param [in] m Message (goes directly to PRF_msg and H_msg).
+ * @param [in] mSz Length of message in bytes.
+ * @param [out] sig Buffer to hold signature.
+ * @param [in, out] sigSz On in, buffer length. On out, signature length.
+ * @param [in] addRnd opt_rand (PK.seed for deterministic).
+ * @return 0 on success.
+ */
+static int slhdsakey_sign_internal_msg(SlhDsaKey* key, const byte* m,
+ word32 mSz, byte* sig, word32* sigSz, const byte* addRnd)
+{
+ int ret = 0;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (key->params == NULL) || (m == NULL) ||
+ (sig == NULL) || (sigSz == NULL) || (addRnd == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ else if (*sigSz < key->params->sigLen) {
+ ret = BAD_LENGTH_E;
+ }
+ else if ((key->flags & WC_SLHDSA_FLAG_PRIVATE) == 0) {
+ ret = MISSING_KEY;
+ }
+ if (ret == 0) {
+ byte md[SLHDSA_MAX_MD];
+ byte n = key->params->n;
+
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ /* SHA2: PRF_msg = Trunc_n(HMAC(SK.prf, opt_rand || M)).
+ * Internal interface: no M' header, pass whole M directly. */
+ ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd,
+ NULL, NULL, 0, m, mSz, n, sig);
+ if (ret == 0) {
+ /* SHA2: H_msg via MGF1. No header for internal interface. */
+ ret = slhdsakey_h_msg_sha2(key, sig,
+ NULL, NULL, 0, m, mSz,
+ md, key->params->dl1 + key->params->dl2 +
+ key->params->dl3);
+ sig += n;
+ }
+ }
+ else
+#endif
+ {
+ /* SHAKE: PRF_msg = SHAKE256(SK.prf || opt_rand || M, 8n). */
+ {
+ wc_Shake tmpShake;
+ ret = wc_InitShake256(&tmpShake, NULL, INVALID_DEVID);
+ if (ret == 0) ret = wc_Shake256_Update(&tmpShake, key->sk + n, n);
+ if (ret == 0) ret = wc_Shake256_Update(&tmpShake, addRnd, n);
+ if (ret == 0) ret = wc_Shake256_Update(&tmpShake, m, mSz);
+ if (ret == 0) ret = wc_Shake256_Final(&tmpShake, sig, n);
+ wc_Shake256_Free(&tmpShake);
+ }
+ /* SHAKE: H_msg = SHAKE256(R || PK.seed || PK.root || M, ...). */
+ if (ret == 0) {
+ ret = wc_InitShake256(&key->hash.shk.shake, NULL, INVALID_DEVID);
+ }
+ if (ret == 0) {
+ ret = wc_Shake256_Update(&key->hash.shk.shake, sig, n);
+ sig += n;
+ }
+ if (ret == 0) {
+ ret = wc_Shake256_Update(&key->hash.shk.shake,
+ key->sk + 2 * n, 2 * n);
+ }
+ if (ret == 0) {
+ ret = wc_Shake256_Update(&key->hash.shk.shake, m, mSz);
+ }
+ if (ret == 0) {
+ ret = wc_Shake256_Final(&key->hash.shk.shake, md,
+ key->params->dl1 + key->params->dl2 + key->params->dl3);
+ }
+ }
+ if (ret == 0) {
+ ret = slhdsakey_sign(key, md, sig);
+ }
+ if (ret == 0) {
+ *sigSz = key->params->sigLen;
+ }
+ }
+
+ return ret;
+}
+
+/* Upper-level sign: construct M' from ctx + msg, then call internal.
+ *
+ * FIPS 205. Section 10.2.2. Algorithm 22.
+ * slh_sign(M, ctx, SK)
+ * 8: M' <- toByte(0, 1) || toByte(|ctx|, 1) || ctx || M
+ * 9: SIG <- slh_sign_internal(M', SK, addrnd)
*
* @param [in] key SLH-DSA key.
* @param [in] ctx Context of signing.
@@ -6004,6 +6824,7 @@ static int slhdsakey_sign(SlhDsaKey* key, byte* md, byte* sig)
* @param [out] sig Buffer to hold signature.
* @param [in, out] sigSz On in, length of signature buffer.
* On out, length of signature data.
+ * @param [in] addRnd opt_rand (PK.seed for deterministic, random otherwise).
* @return 0 on success.
* @return BAD_FUNC_ARG when key, key's parameters, msg, sig, sigSz or addRnd
* is NULL.
@@ -6036,65 +6857,76 @@ static int slhdsakey_sign_external(SlhDsaKey* key, const byte* ctx, byte ctxSz,
}
/* Check we have a private key to sign with. */
else if ((key->flags & WC_SLHDSA_FLAG_PRIVATE) == 0) {
- ret = MISSING_KEY;
- }
- if (ret == 0) {
- byte md[SLHDSA_MAX_MD];
- byte hdr[2];
- byte n = key->params->n;
-
- /* Alg 22, Step 8: Set first two bytes to pass to hash ... */
- hdr[0] = 0;
- hdr[1] = ctxSz;
-
- /* Alg 19, Step 3: Start hash with private key PRF seed ... */
- ret = slhdsakey_hash_start(&key->shake, key->sk + n, n);
- if (ret == 0) {
- /* Alg 19, Step 3: Add addrnd to hash ... */
- ret = slhdsakey_hash_update(&key->shake, addRnd, n);
- }
- if (ret == 0) {
- /* Alg 19, Step 3: Add M' header ... */
- ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr));
- }
- if ((ret == 0) && (ctxSz > 0)) {
- /* Alg 19, Step 3: Add ctx ... */
- ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz);
- }
- if (ret == 0) {
- /* Alg 19, Step 3: Add M ... */
- ret = slhdsakey_hash_update(&key->shake, msg, msgSz);
- }
- if (ret == 0) {
- /* Alg 19, Steps 3-4: Compute randomizer into signature. */
- ret = slhdsakey_hash_final(&key->shake, sig, n);
- }
- if (ret == 0) {
- /* Alg 19, Step 5: Start hash with signature ... */
- ret = slhdsakey_hash_start(&key->shake, sig, n);
- /* Move over randomizer. */
- sig += n;
- }
- if (ret == 0) {
- /* Alg 19, Step 5: Add public key seed and root ... */
- ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n);
- }
- if (ret == 0) {
- /* Alg 19, Step 5: Add M' header ... */
- ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr));
- }
- if ((ret == 0) && (ctxSz > 0)) {
- /* Alg 19, Step 5: Add ctx ... */
- ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz);
- }
- if (ret == 0) {
- /* Alg 19, Step 5: Add M ... */
- ret = slhdsakey_hash_update(&key->shake, msg, msgSz);
+ ret = MISSING_KEY;
+ }
+ if (ret == 0) {
+ byte md[SLHDSA_MAX_MD];
+ byte hdr[2];
+ byte n = key->params->n;
+
+ /* Alg 22, Step 8: M' = toByte(0,1) || toByte(|ctx|,1) || ctx || M.
+ * We stream the M' components into PRF_msg and H_msg. */
+ hdr[0] = 0;
+ hdr[1] = ctxSz;
+
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ /* SHA2: PRF_msg via HMAC. */
+ ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, hdr, ctx,
+ ctxSz, msg, msgSz, n, sig);
+ if (ret == 0) {
+ /* SHA2: H_msg via MGF1. */
+ ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, msg,
+ msgSz, md, key->params->dl1 + key->params->dl2 +
+ key->params->dl3);
+ /* Move over randomizer. */
+ sig += n;
+ }
}
- if (ret == 0) {
- /* Alg 19, Steps 5-6: Compute digest of required length. */
- ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 +
- key->params->dl2 + key->params->dl3);
+ else
+#endif
+ {
+ /* SHAKE: PRF_msg streaming with M' = hdr || ctx || msg. */
+ ret = slhdsakey_hash_start(&key->hash.shk.shake, key->sk + n, n);
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, addRnd, n);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr,
+ sizeof(hdr));
+ }
+ if ((ret == 0) && (ctxSz > 0)) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_final(&key->hash.shk.shake, sig, n);
+ }
+ /* SHAKE: H_msg streaming. */
+ if (ret == 0) {
+ ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n);
+ sig += n;
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake,
+ key->sk + 2 * n, 2 * n);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr,
+ sizeof(hdr));
+ }
+ if ((ret == 0) && (ctxSz > 0)) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_final(&key->hash.shk.shake, md,
+ key->params->dl1 + key->params->dl2 + key->params->dl3);
+ }
}
if (ret == 0) {
/* Alg 19. Steps 7-19 */
@@ -6226,6 +7058,51 @@ int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz,
return ret;
}
+
+/* Sign using internal interface -- M' provided directly (deterministic).
+ *
+ * opt_rand = PK.seed for the deterministic variant.
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] mprime M' message (already in internal format).
+ * @param [in] mprimeSz Length of M' in bytes.
+ * @param [out] sig Buffer to hold signature.
+ * @param [in, out] sigSz On in, buffer length. On out, signature length.
+ * @return 0 on success.
+ */
+int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, const byte* mprime,
+ word32 mprimeSz, byte* sig, word32* sigSz)
+{
+ int ret;
+
+ if ((key == NULL) || (key->params == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ else {
+ ret = slhdsakey_sign_internal_msg(key, mprime, mprimeSz, sig, sigSz,
+ key->sk + 2 * key->params->n);
+ }
+
+ return ret;
+}
+
+/* Sign using internal interface -- M' provided directly (with explicit random).
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] mprime M' message (already in internal format).
+ * @param [in] mprimeSz Length of M' in bytes.
+ * @param [out] sig Buffer to hold signature.
+ * @param [in, out] sigSz On in, buffer length. On out, signature length.
+ * @param [in] addRnd opt_rand value.
+ * @return 0 on success.
+ */
+int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, const byte* mprime,
+ word32 mprimeSz, byte* sig, word32* sigSz, const byte* addRnd)
+{
+ return slhdsakey_sign_internal_msg(key, mprime, mprimeSz, sig, sigSz,
+ addRnd);
+}
+
#endif
/* Verify SLH-DSA signature.
@@ -6337,38 +7214,112 @@ int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, byte ctxSz,
if (ret == 0) {
byte md[SLHDSA_MAX_MD];
byte n = key->params->n;
+ byte hdr[2];
- /* Alg 20, Step 8: Hash randomizer ... */
- ret = slhdsakey_hash_start(&key->shake, sig, n);
- if (ret == 0) {
- /* Alg 20, Step 8: Update hash with public key seed and root ... */
- ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n);
- }
- if (ret == 0) {
- byte hdr[2];
+ /* Alg 23, Step 4: Make M' header. */
+ hdr[0] = 0;
+ hdr[1] = ctxSz;
- /* Alg 23, Step 4: Make M' header. */
- hdr[0] = 0;
- hdr[1] = ctxSz;
- /* Alg 20, Step 8: Update hash with M' header ... */
- ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr));
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ /* SHA2: H_msg via MGF1 (no PRF_msg for verify). */
+ ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, msg, msgSz,
+ md, key->params->dl1 + key->params->dl2 + key->params->dl3);
}
- if ((ret == 0) && (ctxSz > 0)) {
- /* Alg 20, Step 8: Update hash with context ... */
- ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz);
+ else
+#endif
+ {
+ /* SHAKE: H_msg streaming. */
+ ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n);
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake,
+ key->sk + 2 * n, 2 * n);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr,
+ sizeof(hdr));
+ }
+ if ((ret == 0) && (ctxSz > 0)) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_final(&key->hash.shk.shake, md,
+ key->params->dl1 + key->params->dl2 + key->params->dl3);
+ }
}
if (ret == 0) {
- /* Alg 20, Step 8: Update hash with message ... */
- ret = slhdsakey_hash_update(&key->shake, msg, msgSz);
+ /* Alg 23, Step 5: Verify M'.
+ * Alg 20, Steps 4,6-18: Verify digest. */
+ ret = slhdsakey_verify(key, md, sig);
}
- if (ret == 0) {
- /* Alg 20, Step 8: Compute message digest. */
- ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 +
- key->params->dl2 + key->params->dl3);
+ }
+
+ return ret;
+}
+
+/* Verify SLH-DSA signature using internal interface -- M' provided directly.
+ *
+ * FIPS 205. Section 9.3. Algorithm 20.
+ * slh_verify_internal(M', SIG, PK)
+ *
+ * @param [in] key SLH-DSA key.
+ * @param [in] mprime M' message (already in internal format).
+ * @param [in] mprimeSz Length of M' in bytes.
+ * @param [in] sig Signature data.
+ * @param [in] sigSz Length of signature in bytes.
+ * @return 0 on success.
+ * @return SIG_VERIFY_E on verification failure.
+ */
+int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
+ word32 mprimeSz, const byte* sig, word32 sigSz)
+{
+ int ret = 0;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (key->params == NULL) || (mprime == NULL) ||
+ (sig == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ else if (sigSz != key->params->sigLen) {
+ ret = BAD_LENGTH_E;
+ }
+ else if ((key->flags & WC_SLHDSA_FLAG_PUBLIC) == 0) {
+ ret = MISSING_KEY;
+ }
+ if (ret == 0) {
+ byte md[SLHDSA_MAX_MD];
+ byte n = key->params->n;
+
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ /* SHA2: H_msg. Internal interface: no M' header, pass whole
+ * message directly. */
+ ret = slhdsakey_h_msg_sha2(key, sig,
+ NULL, NULL, 0, mprime, mprimeSz,
+ md, key->params->dl1 + key->params->dl2 + key->params->dl3);
+ }
+ else
+#endif
+ {
+ /* SHAKE: H_msg = SHAKE(R || PK.seed || PK.root || M). */
+ ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n);
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake,
+ key->sk + 2 * n, 2 * n);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake,
+ mprime, mprimeSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_final(&key->hash.shk.shake, md,
+ key->params->dl1 + key->params->dl2 + key->params->dl3);
+ }
}
if (ret == 0) {
- /* Alg 23, Step 5: Verify M'.
- * Alg 20, Steps 4,6-18: Verify digest. */
ret = slhdsakey_verify(key, md, sig);
}
}
@@ -6424,6 +7375,32 @@ static const byte slhdsakey_oid_shake256[] = {
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0c
};
#endif
+#ifdef WOLFSSL_SHA3
+#ifndef WOLFSSL_NOSHA3_224
+/* OID for SHA3-224 for hash signing/verification. */
+static const byte slhdsakey_oid_sha3_224[] = {
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07
+};
+#endif
+#ifndef WOLFSSL_NOSHA3_256
+/* OID for SHA3-256 for hash signing/verification. */
+static const byte slhdsakey_oid_sha3_256[] = {
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08
+};
+#endif
+#ifndef WOLFSSL_NOSHA3_384
+/* OID for SHA3-384 for hash signing/verification. */
+static const byte slhdsakey_oid_sha3_384[] = {
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09
+};
+#endif
+#ifndef WOLFSSL_NOSHA3_512
+/* OID for SHA3-512 for hash signing/verification. */
+static const byte slhdsakey_oid_sha3_512[] = {
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a
+};
+#endif
+#endif
/* Pre-hash the message with the hash specified.
*
@@ -6507,6 +7484,40 @@ static int slhdsakey_prehash_msg(const byte* msg, word32 msgSz,
*phLen = WC_SHA3_512_DIGEST_SIZE;
ret = wc_Shake256Hash(msg, msgSz, ph, WC_SHA3_512_DIGEST_SIZE);
break;
+ #endif
+ #ifdef WOLFSSL_SHA3
+ #ifndef WOLFSSL_NOSHA3_224
+ case WC_HASH_TYPE_SHA3_224:
+ *oid = slhdsakey_oid_sha3_224;
+ *oidLen = (byte)sizeof(slhdsakey_oid_sha3_224);
+ *phLen = WC_SHA3_224_DIGEST_SIZE;
+ ret = wc_Sha3_224Hash(msg, msgSz, ph);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA3_256
+ case WC_HASH_TYPE_SHA3_256:
+ *oid = slhdsakey_oid_sha3_256;
+ *oidLen = (byte)sizeof(slhdsakey_oid_sha3_256);
+ *phLen = WC_SHA3_256_DIGEST_SIZE;
+ ret = wc_Sha3_256Hash(msg, msgSz, ph);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA3_384
+ case WC_HASH_TYPE_SHA3_384:
+ *oid = slhdsakey_oid_sha3_384;
+ *oidLen = (byte)sizeof(slhdsakey_oid_sha3_384);
+ *phLen = WC_SHA3_384_DIGEST_SIZE;
+ ret = wc_Sha3_384Hash(msg, msgSz, ph);
+ break;
+ #endif
+ #ifndef WOLFSSL_NOSHA3_512
+ case WC_HASH_TYPE_SHA3_512:
+ *oid = slhdsakey_oid_sha3_512;
+ *oidLen = (byte)sizeof(slhdsakey_oid_sha3_512);
+ *phLen = WC_SHA3_512_DIGEST_SIZE;
+ ret = wc_Sha3_512Hash(msg, msgSz, ph);
+ break;
+ #endif
#endif
default:
ret = NOT_COMPILED_IN;
@@ -6626,62 +7637,74 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx,
hdr[0] = 1;
hdr[1] = ctxSz;
- /* Alg 19, Step 3: Start hash with private key PRF seed ... */
- ret = slhdsakey_hash_start(&key->shake, key->sk + n, n);
- if (ret == 0) {
- /* Alg 19, Step 3: Add addrnd to hash ... */
- ret = slhdsakey_hash_update(&key->shake, addRnd, n);
- }
- if (ret == 0) {
- /* Alg 19, Step 3: Add M' header ... */
- ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr));
- }
- if ((ret == 0) && (ctxSz > 0)) {
- /* Alg 19, Step 3: Add ctx ... */
- ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz);
- }
- if (ret == 0) {
- /* Alg 23, Step 24, Alg 19, Step 3: Add M' OID ... */
- ret = slhdsakey_hash_update(&key->shake, oid, oidLen);
- }
- if (ret == 0) {
- /* Alg 23, Step 24, Alg 19, Step 3: Add M' pre-hash ... */
- ret = slhdsakey_hash_update(&key->shake, ph, phLen);
- }
- if (ret == 0) {
- /* Alg 19, Step 3-4: Compute randomizer into signature. */
- ret = slhdsakey_hash_final(&key->shake, sig, n);
- }
- if (ret == 0) {
- /* Alg 19, Step 5: Start hash with signature ... */
- ret = slhdsakey_hash_start(&key->shake, sig, n);
- /* Move over randomizer. */
- sig += n;
- }
- if (ret == 0) {
- /* Alg 19, Step 5: Add public key seed and root ... */
- ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n);
- }
- if (ret == 0) {
- /* Alg 19, Step 5: Add M' header ... */
- ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr));
- }
- if ((ret == 0) && (ctxSz > 0)) {
- /* Alg 19, Step 5: Add ctx ... */
- ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz);
- }
- if (ret == 0) {
- /* Alg 23, Step 24, Alg 19, Step 5: Add M' OID ... */
- ret = slhdsakey_hash_update(&key->shake, oid, oidLen);
- }
- if (ret == 0) {
- /* Alg 23, Step 24, Alg 19, Step 5: Add M' pre-hash ... */
- ret = slhdsakey_hash_update(&key->shake, ph, phLen);
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ /* SHA2: Build oid||ph as message for PRF_msg/H_msg. */
+ byte phMsg[80]; /* Max: 11 byte OID + 64 byte hash */
+ word32 phMsgLen = oidLen + phLen;
+
+ XMEMCPY(phMsg, oid, oidLen);
+ XMEMCPY(phMsg + oidLen, ph, phLen);
+
+ ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, hdr, ctx,
+ ctxSz, phMsg, phMsgLen, n, sig);
+ if (ret == 0) {
+ ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, phMsg,
+ phMsgLen, md, key->params->dl1 + key->params->dl2 +
+ key->params->dl3);
+ sig += n;
+ }
}
- if (ret == 0) {
- /* Alg 19, Steps 5-6: Compute digest of required length. */
- ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 +
- key->params->dl2 + key->params->dl3);
+ else
+#endif
+ {
+ /* SHAKE: PRF_msg streaming. */
+ ret = slhdsakey_hash_start(&key->hash.shk.shake, key->sk + n, n);
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, addRnd, n);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr,
+ sizeof(hdr));
+ }
+ if ((ret == 0) && (ctxSz > 0)) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_final(&key->hash.shk.shake, sig, n);
+ }
+ /* SHAKE: H_msg streaming. */
+ if (ret == 0) {
+ ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n);
+ sig += n;
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake,
+ key->sk + 2 * n, 2 * n);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr,
+ sizeof(hdr));
+ }
+ if ((ret == 0) && (ctxSz > 0)) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_final(&key->hash.shk.shake, md,
+ key->params->dl1 + key->params->dl2 + key->params->dl3);
+ }
}
if (ret == 0) {
/* Alg 19. Steps 7-19 */
@@ -6919,37 +7942,51 @@ int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
if (ret == 0) {
byte n = key->params->n;
byte md[SLHDSA_MAX_MD];
+ byte hdr[2];
- /* Alg 20, Step 8: Hash randomizer ... */
- ret = slhdsakey_hash_start(&key->shake, sig, n);
- if (ret == 0) {
- /* Alg 20, Step 8: Update hash with public key seed and root ... */
- ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n);
- }
- if (ret == 0) {
- byte hdr[2];
+ /* Alg 24, Step 20: Make M' header. */
+ hdr[0] = 1;
+ hdr[1] = ctxSz;
- /* Alg 24, Step 20: Make M' header. */
- hdr[0] = 1;
- hdr[1] = ctxSz;
- ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr));
- }
- if ((ret == 0) && (ctxSz > 0)) {
- /* Alg 20, Step 8: Update hash with message ... */
- ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz);
- }
- if (ret == 0) {
- /* Alg 24, Step 20; Alg 20, Step 8: Update with M' OID ... */
- ret = slhdsakey_hash_update(&key->shake, oid, oidLen);
- }
- if (ret == 0) {
- /* Alg 24, Step 20; Alg 20, Step 8: Update with M' pre-hash ... */
- ret = slhdsakey_hash_update(&key->shake, ph, phLen);
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ /* SHA2: Build oid||ph as message for H_msg. */
+ byte phMsg[80]; /* Max: 11 byte OID + 64 byte hash */
+ word32 phMsgLen = oidLen + phLen;
+
+ XMEMCPY(phMsg, oid, oidLen);
+ XMEMCPY(phMsg + oidLen, ph, phLen);
+
+ ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, phMsg,
+ phMsgLen, md, key->params->dl1 + key->params->dl2 +
+ key->params->dl3);
}
- if (ret == 0) {
- /* Alg 20, Step 8: Compute message digest. */
- ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 +
- key->params->dl2 + key->params->dl3);
+ else
+#endif
+ {
+ /* SHAKE: H_msg streaming. */
+ ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n);
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake,
+ key->sk + 2 * n, 2 * n);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr,
+ sizeof(hdr));
+ }
+ if ((ret == 0) && (ctxSz > 0)) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen);
+ }
+ if (ret == 0) {
+ ret = slhdsakey_hash_final(&key->hash.shk.shake, md,
+ key->params->dl1 + key->params->dl2 + key->params->dl3);
+ }
}
if (ret == 0) {
/* Alg 24, Step 21: Verify M'.
@@ -6989,6 +8026,11 @@ int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* priv, word32 privLen)
/* Copy private and public key data into SLH-DSA key object. */
XMEMCPY(key->sk, priv, 4 * key->params->n);
key->flags = WC_SLHDSA_FLAG_BOTH_KEYS;
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ ret = slhdsakey_precompute_sha2_midstates(key);
+ }
+#endif
}
return ret;
@@ -7020,6 +8062,11 @@ int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* pub, word32 pubLen)
/* Copy public key data into SLH-DSA key object. */
XMEMCPY(key->sk + 2 * key->params->n, pub, 2 * key->params->n);
key->flags = WC_SLHDSA_FLAG_PUBLIC;
+#ifdef WOLFSSL_SLHDSA_SHA2
+ if (SLHDSA_IS_SHA2(key->params->param)) {
+ ret = slhdsakey_precompute_sha2_midstates(key);
+ }
+#endif
}
return ret;
@@ -7235,6 +8282,26 @@ int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param)
case SLHDSA_SHAKE256F:
ret = WC_SLHDSA_SHAKE256F_PRIV_LEN;
break;
+#ifdef WOLFSSL_SLHDSA_SHA2
+ case SLHDSA_SHA2_128S:
+ ret = WC_SLHDSA_SHA2_128S_PRIV_LEN;
+ break;
+ case SLHDSA_SHA2_128F:
+ ret = WC_SLHDSA_SHA2_128F_PRIV_LEN;
+ break;
+ case SLHDSA_SHA2_192S:
+ ret = WC_SLHDSA_SHA2_192S_PRIV_LEN;
+ break;
+ case SLHDSA_SHA2_192F:
+ ret = WC_SLHDSA_SHA2_192F_PRIV_LEN;
+ break;
+ case SLHDSA_SHA2_256S:
+ ret = WC_SLHDSA_SHA2_256S_PRIV_LEN;
+ break;
+ case SLHDSA_SHA2_256F:
+ ret = WC_SLHDSA_SHA2_256F_PRIV_LEN;
+ break;
+#endif
default:
ret = NOT_COMPILED_IN;
break;
@@ -7273,6 +8340,26 @@ int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param)
case SLHDSA_SHAKE256F:
ret = WC_SLHDSA_SHAKE256F_PUB_LEN;
break;
+#ifdef WOLFSSL_SLHDSA_SHA2
+ case SLHDSA_SHA2_128S:
+ ret = WC_SLHDSA_SHA2_128S_PUB_LEN;
+ break;
+ case SLHDSA_SHA2_128F:
+ ret = WC_SLHDSA_SHA2_128F_PUB_LEN;
+ break;
+ case SLHDSA_SHA2_192S:
+ ret = WC_SLHDSA_SHA2_192S_PUB_LEN;
+ break;
+ case SLHDSA_SHA2_192F:
+ ret = WC_SLHDSA_SHA2_192F_PUB_LEN;
+ break;
+ case SLHDSA_SHA2_256S:
+ ret = WC_SLHDSA_SHA2_256S_PUB_LEN;
+ break;
+ case SLHDSA_SHA2_256F:
+ ret = WC_SLHDSA_SHA2_256F_PUB_LEN;
+ break;
+#endif
default:
ret = NOT_COMPILED_IN;
break;
@@ -7310,6 +8397,26 @@ int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param)
case SLHDSA_SHAKE256F:
ret = WC_SLHDSA_SHAKE256F_SIG_LEN;
break;
+#ifdef WOLFSSL_SLHDSA_SHA2
+ case SLHDSA_SHA2_128S:
+ ret = WC_SLHDSA_SHA2_128S_SIG_LEN;
+ break;
+ case SLHDSA_SHA2_128F:
+ ret = WC_SLHDSA_SHA2_128F_SIG_LEN;
+ break;
+ case SLHDSA_SHA2_192S:
+ ret = WC_SLHDSA_SHA2_192S_SIG_LEN;
+ break;
+ case SLHDSA_SHA2_192F:
+ ret = WC_SLHDSA_SHA2_192F_SIG_LEN;
+ break;
+ case SLHDSA_SHA2_256S:
+ ret = WC_SLHDSA_SHA2_256S_SIG_LEN;
+ break;
+ case SLHDSA_SHA2_256F:
+ ret = WC_SLHDSA_SHA2_256F_SIG_LEN;
+ break;
+#endif
default:
ret = NOT_COMPILED_IN;
break;
diff --git a/wolfcrypt/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c
index ef7248d209e..dfc6375e4e3 100644
--- a/wolfcrypt/src/wc_xmss.c
+++ b/wolfcrypt/src/wc_xmss.c
@@ -22,6 +22,11 @@
#include
#ifdef WOLFSSL_HAVE_XMSS
+
+#if FIPS_VERSION3_GE(2,0,0)
+ /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
+ #define FIPS_NO_WRAPPERS
+#endif
#include
#ifdef NO_INLINE
diff --git a/wolfcrypt/src/wolfentropy.c b/wolfcrypt/src/wolfentropy.c
index c05e56f6572..30c67d167e8 100644
--- a/wolfcrypt/src/wolfentropy.c
+++ b/wolfcrypt/src/wolfentropy.c
@@ -354,19 +354,37 @@ static word64 entropy_state[ENTROPY_NUM_WORDS + EXTRA_ENTROPY_WORDS] = {0};
/* Using memory will take different amount of times depending on the CPU's
* caches and business.
+ *
+ * Returns int (not void) because the SHA-3 conditioning calls go through
+ * FIPS wrappers. When the FIPS module is in FAILED state (e.g. integrity
+ * hash mismatch during first build before fips-hash.sh), every SHA-3 call
+ * returns FIPS_NOT_ALLOWED_E. Without checking these returns, this function
+ * would silently loop through all ENTROPY_NUM_UPDATES iterations on every
+ * noise sample, each iteration firing the FIPS error callback -- producing
+ * tens of thousands of spurious error reports during Entropy_Init().
+ *
+ * Non-FIPS builds never hit this path because SHA-3 calls always succeed
+ * without a CAST gate. We use int returns unconditionally (rather than
+ * void in non-FIPS, int in FIPS) to maintain a common ABI in case these
+ * functions become public API as wolfentropy matures.
*/
-static void Entropy_MemUse(void)
+static int Entropy_MemUse(void)
{
int i;
static byte d[WC_SHA3_256_DIGEST_SIZE];
int j;
+ int ret;
for (j = 0; j < ENTROPY_NUM_UPDATES; j++) {
/* Hash the first 32 64-bit words of state. */
- wc_Sha3_256_Update(&entropyHash, (byte*)entropy_state,
+ ret = wc_Sha3_256_Update(&entropyHash, (byte*)entropy_state,
sizeof(*entropy_state) * ENTROPY_NUM_64BIT_WORDS);
+ if (ret != 0)
+ return ret;
/* Get pseudo-random indices. */
- wc_Sha3_256_Final(&entropyHash, d);
+ ret = wc_Sha3_256_Final(&entropyHash, d);
+ if (ret != 0)
+ return ret;
for (i = 0; i < ENTROPY_NUM_64BIT_WORDS; i++) {
/* Choose a 64-bit word from a pseudo-random block.*/
@@ -378,6 +396,8 @@ static void Entropy_MemUse(void)
entropy_state[i] += entropy_state[idx];
}
}
+
+ return 0;
}
@@ -390,34 +410,40 @@ static word64 entropy_last_time = 0;
*
* Called to test raw entropy.
*
- * @return 64-bit value that is the noise.
+ * @param [out] sample 64-bit noise value (time delta).
+ * @return 0 on success.
+ * @return Negative on failure (e.g. FIPS module not operational).
*/
-static word64 Entropy_GetSample(void)
+static int Entropy_GetSample(word64* sample)
{
word64 now;
- word64 ret;
+ int ret = 0;
#ifdef HAVE_FIPS
/* First sample must be disregard when in FIPS. */
if (entropy_last_time == 0) {
/* Get sample which triggers CAST in FIPS mode. */
- Entropy_MemUse();
+ ret = Entropy_MemUse();
+ if (ret != 0)
+ return ret;
/* Start entropy time after CASTs. */
entropy_last_time = Entropy_TimeHiRes();
}
#endif
/* Use memory such that it will take an unpredictable amount of time. */
- Entropy_MemUse();
+ ret = Entropy_MemUse();
+ if (ret != 0)
+ return ret;
/* Get the time now to subtract from previous end time. */
now = Entropy_TimeHiRes();
/* Calculate time diff since last sampling. */
- ret = now - entropy_last_time;
+ *sample = now - entropy_last_time;
/* Store last time. */
entropy_last_time = now;
- return ret;
+ return 0;
}
/* Get as many samples of noise as required.
@@ -426,18 +452,29 @@ static word64 Entropy_GetSample(void)
*
* @param [out] noise Buffer to hold samples.
* @param [in] samples Number of one byte samples to get.
+ * @return 0 on success.
+ * @return Negative on hash failure (e.g. FIPS module not operational).
*/
-static void Entropy_GetNoise(unsigned char* noise, int samples)
+static int Entropy_GetNoise(unsigned char* noise, int samples)
{
int i;
+ int ret;
+ word64 sample;
/* Do it once to get things going. */
- Entropy_MemUse();
+ ret = Entropy_MemUse();
+ if (ret != 0)
+ return ret;
/* Get as many samples as required. */
for (i = 0; i < samples; i++) {
- noise[i] = (byte)Entropy_GetSample();
+ ret = Entropy_GetSample(&sample);
+ if (ret != 0)
+ return ret;
+ noise[i] = (byte)sample;
}
+
+ return 0;
}
/* Generate raw entropy for performing assessment.
@@ -458,7 +495,7 @@ int wc_Entropy_GetRawEntropy(unsigned char* raw, int cnt)
if (ret == 0)
#endif
{
- Entropy_GetNoise(raw, cnt);
+ ret = Entropy_GetNoise(raw, cnt);
}
#ifdef ENTROPY_MEMUSE_THREADED
/* Stop the counter thread to avoid thrashing the system. */
@@ -670,7 +707,7 @@ static int Entropy_HealthTest_Startup(void)
Entropy_HealthTest_Reset();
/* Fill initial sample buffer with noise. */
- Entropy_GetNoise(initial, ENTROPY_INITIAL_COUNT);
+ ret = Entropy_GetNoise(initial, ENTROPY_INITIAL_COUNT);
/* Health check initial noise. */
for (i = 0; (ret == 0) && (i < ENTROPY_INITIAL_COUNT); i++) {
ret = Entropy_HealthTest_Repetition(initial[i]);
@@ -799,7 +836,7 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len)
}
/* Get raw entropy noise. */
- Entropy_GetNoise(noise, noise_len);
+ ret = Entropy_GetNoise(noise, noise_len);
/* Health check each noise value. */
for (i = 0; (ret == 0) && (i < noise_len); i++) {
ret = Entropy_HealthTest_Repetition(noise[i]);
diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c
index 80866209c5f..b5bf2f17ccd 100644
--- a/wolfcrypt/test/test.c
+++ b/wolfcrypt/test/test.c
@@ -1056,6 +1056,15 @@ static void myFipsCb(int ok, int err, const char* hash)
if (err == WC_NO_ERR_TRACE(IN_CORE_FIPS_E)) {
printf("In core integrity hash check failure, copy above hash\n");
printf("into verifyCore[] in fips_test.c and rebuild\n");
+#ifdef TEST_ALWAYS_RUN_TO_END
+ /* When TEST_ALWAYS_RUN_TO_END is defined, testwolfcrypt tries to
+ * run every test even after failures. But with a wrong integrity
+ * hash the FIPS module is in FAILED state and every API call will
+ * fail, fire this callback, and produce millions of lines of
+ * redundant output. Exit now -- the hash has been printed for
+ * fips-hash.sh to extract, and no test can possibly pass. */
+ exit(IN_CORE_FIPS_E);
+#endif
}
#ifdef REALLY_LONG_DRBG_CONTINUOUS_TEST
only_run_cb_once = 0;
@@ -2784,17 +2793,21 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
#endif
#ifdef WOLFSSL_HAVE_MLKEM
+ PRIVATE_KEY_UNLOCK();
if ( (ret = mlkem_test()) != 0)
TEST_FAIL("MLKEM test failed!\n", ret);
else
TEST_PASS("MLKEM test passed!\n");
+ PRIVATE_KEY_LOCK();
#endif
#ifdef HAVE_DILITHIUM
+ PRIVATE_KEY_UNLOCK();
if ( (ret = dilithium_test()) != 0)
TEST_FAIL("DILITHIUM test failed!\n", ret);
else
TEST_PASS("DILITHIUM test passed!\n");
+ PRIVATE_KEY_LOCK();
#endif
#if defined(WOLFSSL_HAVE_XMSS)
@@ -3689,8 +3702,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t error_test(void)
int first;
int last;
} missing[] = {
- { -124, -124 },
- { -167, -169 },
{ WC_SPAN1_LAST_E - 1, WC_SPAN2_FIRST_E + 1 },
{ WC_SPAN2_LAST_E - 1, WC_SPAN2_MIN_CODE_E }
};
@@ -20549,14 +20560,37 @@ static wc_test_ret_t _rng_test(WC_RNG* rng)
WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
{
#endif
- ((struct DRBG_internal *)rng->drbg)->reseedCtr = WC_RESEED_INTERVAL;
+ #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ if (rng->drbgType == WC_DRBG_SHA512) {
+ ((struct DRBG_SHA512_internal *)rng->drbg512)->reseedCtr =
+ WC_RESEED_INTERVAL;
+ }
+ else
+ #endif
+ {
+ ((struct DRBG_internal *)rng->drbg)->reseedCtr =
+ WC_RESEED_INTERVAL;
+ }
ret = wc_RNG_GenerateBlock(rng, block, sizeof(block));
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
- if (((struct DRBG_internal *)rng->drbg)->reseedCtr == WC_RESEED_INTERVAL)
- return WC_TEST_RET_ENC_NC;
+ #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ if (rng->drbgType == WC_DRBG_SHA512) {
+ if (((struct DRBG_SHA512_internal *)rng->drbg512)->reseedCtr ==
+ WC_RESEED_INTERVAL)
+ return WC_TEST_RET_ENC_NC;
+ }
+ else
+ #endif
+ {
+ if (((struct DRBG_internal *)rng->drbg)->reseedCtr ==
+ WC_RESEED_INTERVAL)
+ return WC_TEST_RET_ENC_NC;
+ }
#ifdef WOLF_CRYPTO_CB
}
#endif
@@ -20877,6 +20911,150 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void)
if (XMEMCMP(test2Output, output, sizeof(output)) != 0)
return WC_TEST_RET_ENC_NC;
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ /* SHA-512 DRBG Health Tests using NIST CAVP test vectors.
+ * Source: NIST CAVP drbgtestvectors.zip, Hash_DRBG.rsp, [SHA-512],
+ * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-
+ * Validation-Program/documents/drbg/drbgtestvectors.zip */
+ {
+ /* No-reseed test: drbgvectors_no_reseed/Hash_DRBG.rsp, [SHA-512],
+ * PredictionResistance=False, EntropyInputLen=256, NonceLen=128,
+ * PersonalizationStringLen=0, AdditionalInputLen=0,
+ * ReturnedBitsLen=2048, COUNT=0.
+ * EntropyInput || Nonce concatenated as seedA. */
+ WOLFSSL_SMALL_STACK_STATIC const byte sha512test1Entropy[] =
+ {
+ /* EntropyInput (32 bytes) */
+ 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a,
+ 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22,
+ 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b,
+ 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c,
+ /* Nonce (16 bytes) */
+ 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa,
+ 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25
+ };
+ WOLFSSL_SMALL_STACK_STATIC const byte sha512test1Output[] =
+ {
+ 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57,
+ 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6,
+ 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d,
+ 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf,
+ 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26,
+ 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64,
+ 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55,
+ 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a,
+ 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78,
+ 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e,
+ 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb,
+ 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30,
+ 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19,
+ 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f,
+ 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d,
+ 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a,
+ 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2,
+ 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd,
+ 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd,
+ 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2,
+ 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b,
+ 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1,
+ 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99,
+ 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e,
+ 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3,
+ 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67,
+ 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3,
+ 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d,
+ 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b,
+ 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13,
+ 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c,
+ 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2
+ };
+
+ /* Reseed test: drbgvectors_pr_false/Hash_DRBG.rsp, [SHA-512],
+ * PredictionResistance=False, EntropyInputLen=256, NonceLen=128,
+ * PersonalizationStringLen=0, AdditionalInputLen=0,
+ * ReturnedBitsLen=2048, COUNT=0. */
+ WOLFSSL_SMALL_STACK_STATIC const byte sha512test2EntropyA[] =
+ {
+ /* EntropyInput (32 bytes) */
+ 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12,
+ 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10,
+ 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff,
+ 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33,
+ /* Nonce (16 bytes) */
+ 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3,
+ 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04
+ };
+ WOLFSSL_SMALL_STACK_STATIC const byte sha512test2EntropyB[] =
+ {
+ /* EntropyInputReseed (32 bytes) */
+ 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6,
+ 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0,
+ 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d,
+ 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67
+ };
+ WOLFSSL_SMALL_STACK_STATIC const byte sha512test2Output[] =
+ {
+ 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76,
+ 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c,
+ 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a,
+ 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1,
+ 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70,
+ 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42,
+ 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d,
+ 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15,
+ 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58,
+ 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7,
+ 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05,
+ 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c,
+ 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac,
+ 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f,
+ 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb,
+ 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f,
+ 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1,
+ 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82,
+ 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22,
+ 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e,
+ 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4,
+ 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a,
+ 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a,
+ 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03,
+ 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e,
+ 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78,
+ 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2,
+ 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6,
+ 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e,
+ 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0,
+ 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d,
+ 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0
+ };
+
+ byte output512[WC_SHA512_DIGEST_SIZE * 4]; /* 256 bytes */
+
+ /* Test 1: SHA-512 DRBG no-reseed */
+ ret = wc_RNG_HealthTest_SHA512(0,
+ sha512test1Entropy, sizeof(sha512test1Entropy),
+ NULL, 0,
+ output512, sizeof(output512));
+ if (ret != 0)
+ return WC_TEST_RET_ENC_EC(ret);
+
+ if (XMEMCMP(sha512test1Output, output512, sizeof(output512)) != 0)
+ return WC_TEST_RET_ENC_NC;
+
+ /* Test 2: SHA-512 DRBG with reseed */
+ ret = wc_RNG_HealthTest_SHA512(1,
+ sha512test2EntropyA, sizeof(sha512test2EntropyA),
+ sha512test2EntropyB, sizeof(sha512test2EntropyB),
+ output512, sizeof(output512));
+ if (ret != 0)
+ return WC_TEST_RET_ENC_EC(ret);
+
+ if (XMEMCMP(sha512test2Output, output512, sizeof(output512)) != 0)
+ return WC_TEST_RET_ENC_NC;
+ }
+#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */
+
/* Basic RNG generate block test */
if ((ret = random_rng_test()) != 0)
return ret;
@@ -21097,8 +21275,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
for (i = 0; i < bank->n_rngs; ++i) {
+ #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ word64 bankReseedCtr;
+ if (bank->rngs[i].rng.drbgType == WC_DRBG_SHA512)
+ bankReseedCtr = ((struct DRBG_SHA512_internal *)
+ bank->rngs[i].rng.drbg512)->reseedCtr;
+ else
+ bankReseedCtr = ((struct DRBG_internal *)
+ bank->rngs[i].rng.drbg)->reseedCtr;
+ if (bankReseedCtr != WC_RESEED_INTERVAL)
+ #else
if (((struct DRBG_internal *)bank->rngs[i].rng.drbg)
->reseedCtr != WC_RESEED_INTERVAL)
+ #endif
{
ERROR_OUT(WC_TEST_RET_ENC_I(i), out);
}
@@ -51836,6 +52026,77 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void)
#endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_SMALL_STACK) */
#if defined(WOLFSSL_HAVE_SLHDSA)
+
+#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
+/* KeyGen KAT: deterministic key generation cross-validated against NIST CAVP
+ * vectors. Verifies that MakeKeyWithRandom produces the expected sk and pk
+ * for a given parameter set. */
+static wc_test_ret_t slhdsa_keygen_kat(enum SlhDsaParam param,
+ const byte* sk_seed, word32 sk_seed_sz,
+ const byte* sk_prf, word32 sk_prf_sz,
+ const byte* pk_seed, word32 pk_seed_sz,
+ const byte* expected_sk, word32 expected_sk_sz,
+ const byte* expected_pk, word32 expected_pk_sz)
+{
+ int ret;
+ WC_DECLARE_VAR(key, SlhDsaKey, 1, HEAP_HINT);
+ byte sk_out[WC_SLHDSA_MAX_PRIV_LEN];
+ byte pk_out[WC_SLHDSA_MAX_PUB_LEN];
+ word32 outLen;
+
+ WC_ALLOC_VAR_EX(key, SlhDsaKey, 1, HEAP_HINT,
+ DYNAMIC_TYPE_TMP_BUFFER, return WC_TEST_RET_ENC_EC(MEMORY_E));
+ XMEMSET(key, 0, sizeof(*key));
+
+ ret = wc_SlhDsaKey_Init(key, param, NULL, INVALID_DEVID);
+ if (ret != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
+ }
+
+ ret = wc_SlhDsaKey_MakeKeyWithRandom(key,
+ sk_seed, sk_seed_sz, sk_prf, sk_prf_sz, pk_seed, pk_seed_sz);
+ if (ret != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
+ }
+
+ outLen = WC_SLHDSA_MAX_PRIV_LEN;
+ PRIVATE_KEY_UNLOCK();
+ ret = wc_SlhDsaKey_ExportPrivate(key, sk_out, &outLen);
+ PRIVATE_KEY_LOCK();
+ if (ret != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
+ }
+ if (outLen != expected_sk_sz) {
+ ERROR_OUT(WC_TEST_RET_ENC_I(outLen), out);
+ }
+ if (XMEMCMP(sk_out, expected_sk, outLen) != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_NC, out);
+ }
+
+ outLen = WC_SLHDSA_MAX_PUB_LEN;
+ ret = wc_SlhDsaKey_ExportPublic(key, pk_out, &outLen);
+ if (ret != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
+ }
+ if (outLen != expected_pk_sz) {
+ ERROR_OUT(WC_TEST_RET_ENC_I(outLen), out);
+ }
+ if (XMEMCMP(pk_out, expected_pk, outLen) != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_NC, out);
+ }
+
+out:
+#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
+ if (key)
+#endif
+ {
+ wc_SlhDsaKey_Free(key);
+ }
+ WC_FREE_VAR_EX(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
+ return ret;
+}
+#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */
+
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
{
@@ -51878,8 +52139,10 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
sigLen = WC_SLHDSA_MAX_SIG_LEN;
+ PRIVATE_KEY_UNLOCK();
ret = wc_SlhDsaKey_Sign(key, ctx, 0, msg, (word32)sizeof(msg),
sig, &sigLen, &rng);
+ PRIVATE_KEY_LOCK();
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
@@ -51904,14 +52167,57 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
+ {
+#ifdef WOLFSSL_SLHDSA_SHA2
+ enum wc_HashType phType = SLHDSA_IS_SHA2(param) ?
+ WC_HASH_TYPE_SHA256 : WC_HASH_TYPE_SHAKE256;
+#else
+ enum wc_HashType phType = WC_HASH_TYPE_SHAKE256;
+#endif
+ sigLen = WC_SLHDSA_MAX_SIG_LEN;
+ PRIVATE_KEY_UNLOCK();
+ ret = wc_SlhDsaKey_SignHash(key, ctx, 0, msg, (word32)sizeof(msg),
+ phType, sig, &sigLen, &rng);
+ PRIVATE_KEY_LOCK();
+ if (ret != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
+ }
+ ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg, (word32)sizeof(msg),
+ phType, sig, sigLen);
+ }
+ if (ret != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
+ }
+
+ /* Additional pre-hash test: SHA-384 exercises a different OID path */
+#ifdef WOLFSSL_SHA384
sigLen = WC_SLHDSA_MAX_SIG_LEN;
+ PRIVATE_KEY_UNLOCK();
ret = wc_SlhDsaKey_SignHash(key, ctx, 0, msg, (word32)sizeof(msg),
- WC_HASH_TYPE_SHAKE256, sig, &sigLen, &rng);
+ WC_HASH_TYPE_SHA384, sig, &sigLen, &rng);
+ PRIVATE_KEY_LOCK();
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg, (word32)sizeof(msg),
- WC_HASH_TYPE_SHAKE256, sig, sigLen);
+ WC_HASH_TYPE_SHA384, sig, sigLen);
+ if (ret != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
+ }
+#endif
+
+ /* Internal interface: SignMsgDeterministic + VerifyMsg round-trip.
+ * These take M' directly (no 0x00||len(ctx)||ctx||M wrapping). */
+ sigLen = WC_SLHDSA_MAX_SIG_LEN;
+ PRIVATE_KEY_UNLOCK();
+ ret = wc_SlhDsaKey_SignMsgDeterministic(key,
+ msg, (word32)sizeof(msg), sig, &sigLen);
+ PRIVATE_KEY_LOCK();
+ if (ret != 0) {
+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
+ }
+ ret = wc_SlhDsaKey_VerifyMsg(key_vfy,
+ msg, (word32)sizeof(msg), sig, sigLen);
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
@@ -53007,7 +53313,9 @@ wc_test_ret_t slhdsa_test(void)
}
outLen = WC_SLHDSA_MAX_PRIV_LEN;
+ PRIVATE_KEY_UNLOCK();
ret = wc_SlhDsaKey_ExportPrivate(key, sk, &outLen);
+ PRIVATE_KEY_LOCK();
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
@@ -53049,8 +53357,10 @@ wc_test_ret_t slhdsa_test(void)
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
outLen = (word32)sizeof(sig_shake128s);
+ PRIVATE_KEY_UNLOCK();
ret = wc_SlhDsaKey_SignWithRandom(key, ctx, 0, msg, (word32)sizeof(msg),
sig, &outLen, pk_seed_shake128s);
+ PRIVATE_KEY_LOCK();
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
@@ -53065,6 +53375,601 @@ wc_test_ret_t slhdsa_test(void)
#endif
#endif
+ /* --- SHA2 KeyGen KATs (NIST CAVP cross-validation) ---
+ * These verify that deterministic key generation produces the exact pk/sk
+ * that NIST expects. Covers both SHA-256 (cat 1, n=16) and SHA-512
+ * (cat 3 n=24, cat 5 n=32) code paths. */
+#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S
+ {
+ /* NIST CAVP SLH-DSA-SHA2-128s keyGen vector (tgId=1, tcId=1).
+ * Same seeds as SHAKE128S; pk_root differs due to SHA-256 hash. */
+ static const byte sk_seed_sha2_128s[] = {
+ 0x17, 0x3D, 0x04, 0xC9, 0x38, 0xC1, 0xC3, 0x6B,
+ 0xF2, 0x89, 0xC3, 0xC0, 0x22, 0xD0, 0x4B, 0x14
+ };
+ static const byte sk_prf_sha2_128s[] = {
+ 0x63, 0xAE, 0x23, 0xC4, 0x1A, 0xA5, 0x46, 0xDA,
+ 0x58, 0x97, 0x74, 0xAC, 0x20, 0xB7, 0x45, 0xC4
+ };
+ static const byte pk_seed_sha2_128s[] = {
+ 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76,
+ 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE
+ };
+ static const byte expected_sk_sha2_128s[] = {
+ 0x17, 0x3D, 0x04, 0xC9, 0x38, 0xC1, 0xC3, 0x6B,
+ 0xF2, 0x89, 0xC3, 0xC0, 0x22, 0xD0, 0x4B, 0x14,
+ 0x63, 0xAE, 0x23, 0xC4, 0x1A, 0xA5, 0x46, 0xDA,
+ 0x58, 0x97, 0x74, 0xAC, 0x20, 0xB7, 0x45, 0xC4,
+ 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76,
+ 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE,
+ 0x01, 0x62, 0xC1, 0x02, 0x19, 0xD4, 0x22, 0xAD,
+ 0xBA, 0x13, 0x59, 0xE6, 0xAA, 0x65, 0x29, 0x9C
+ };
+ static const byte expected_pk_sha2_128s[] = {
+ 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76,
+ 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE,
+ 0x01, 0x62, 0xC1, 0x02, 0x19, 0xD4, 0x22, 0xAD,
+ 0xBA, 0x13, 0x59, 0xE6, 0xAA, 0x65, 0x29, 0x9C
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHA2_128S,
+ sk_seed_sha2_128s, (word32)sizeof(sk_seed_sha2_128s),
+ sk_prf_sha2_128s, (word32)sizeof(sk_prf_sha2_128s),
+ pk_seed_sha2_128s, (word32)sizeof(pk_seed_sha2_128s),
+ expected_sk_sha2_128s, (word32)sizeof(expected_sk_sha2_128s),
+ expected_pk_sha2_128s, (word32)sizeof(expected_pk_sha2_128s));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_128S keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S
+ {
+ /* NIST CAVP SLH-DSA-SHA2-192s keyGen vector (tgId=5, tcId=41).
+ * Uses SHA-512 for H and T_l operations (n=24). */
+ static const byte sk_seed_sha2_192s[] = {
+ 0x04, 0x02, 0x66, 0x52, 0x9C, 0x18, 0x64, 0x08,
+ 0x89, 0x25, 0x50, 0x6C, 0x20, 0xA6, 0x24, 0xA2,
+ 0xB6, 0xD5, 0x0C, 0xD7, 0x7C, 0x1C, 0x6F, 0x0D
+ };
+ static const byte sk_prf_sha2_192s[] = {
+ 0x28, 0x41, 0x15, 0x0A, 0xE8, 0x15, 0x75, 0x12,
+ 0xEF, 0x34, 0xA3, 0x43, 0xFF, 0xEA, 0x77, 0xFF,
+ 0x7D, 0x9E, 0x81, 0x4B, 0x45, 0xA8, 0xB4, 0x14
+ };
+ static const byte pk_seed_sha2_192s[] = {
+ 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86,
+ 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C,
+ 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86
+ };
+ static const byte expected_sk_sha2_192s[] = {
+ 0x04, 0x02, 0x66, 0x52, 0x9C, 0x18, 0x64, 0x08,
+ 0x89, 0x25, 0x50, 0x6C, 0x20, 0xA6, 0x24, 0xA2,
+ 0xB6, 0xD5, 0x0C, 0xD7, 0x7C, 0x1C, 0x6F, 0x0D,
+ 0x28, 0x41, 0x15, 0x0A, 0xE8, 0x15, 0x75, 0x12,
+ 0xEF, 0x34, 0xA3, 0x43, 0xFF, 0xEA, 0x77, 0xFF,
+ 0x7D, 0x9E, 0x81, 0x4B, 0x45, 0xA8, 0xB4, 0x14,
+ 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86,
+ 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C,
+ 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86,
+ 0x2C, 0x6A, 0x7B, 0xC4, 0xAC, 0x4A, 0xAA, 0x84,
+ 0xAC, 0xCE, 0xF6, 0x0D, 0x52, 0x9F, 0x03, 0x11,
+ 0x27, 0x4F, 0x20, 0x5E, 0x8D, 0xA6, 0x42, 0xC9
+ };
+ static const byte expected_pk_sha2_192s[] = {
+ 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86,
+ 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C,
+ 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86,
+ 0x2C, 0x6A, 0x7B, 0xC4, 0xAC, 0x4A, 0xAA, 0x84,
+ 0xAC, 0xCE, 0xF6, 0x0D, 0x52, 0x9F, 0x03, 0x11,
+ 0x27, 0x4F, 0x20, 0x5E, 0x8D, 0xA6, 0x42, 0xC9
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHA2_192S,
+ sk_seed_sha2_192s, (word32)sizeof(sk_seed_sha2_192s),
+ sk_prf_sha2_192s, (word32)sizeof(sk_prf_sha2_192s),
+ pk_seed_sha2_192s, (word32)sizeof(pk_seed_sha2_192s),
+ expected_sk_sha2_192s, (word32)sizeof(expected_sk_sha2_192s),
+ expected_pk_sha2_192s, (word32)sizeof(expected_pk_sha2_192s));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_192S keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S
+ {
+ /* NIST CAVP SLH-DSA-SHA2-256s keyGen vector (tgId=9, tcId=81).
+ * Uses SHA-512 for H and T_l operations (n=32). */
+ static const byte sk_seed_sha2_256s[] = {
+ 0xFC, 0xBF, 0x36, 0xA9, 0x80, 0x7B, 0x30, 0x69,
+ 0x7B, 0xE0, 0x63, 0xA5, 0x10, 0x5E, 0x09, 0x1B,
+ 0x41, 0x2A, 0x39, 0x1D, 0xD3, 0x9E, 0x13, 0x26,
+ 0xEB, 0xA2, 0x3C, 0xBD, 0x40, 0x96, 0xCA, 0x77
+ };
+ static const byte sk_prf_sha2_256s[] = {
+ 0xEF, 0x41, 0x21, 0xC0, 0x8D, 0xD7, 0x1B, 0xE9,
+ 0x13, 0x57, 0x2F, 0x1F, 0x91, 0xE5, 0x7D, 0x0A,
+ 0xCB, 0xCD, 0x5C, 0xEC, 0x28, 0x53, 0x9A, 0xC2,
+ 0x75, 0x83, 0x2B, 0xBA, 0xA6, 0xC1, 0x10, 0x81
+ };
+ static const byte pk_seed_sha2_256s[] = {
+ 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9,
+ 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62,
+ 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86,
+ 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54
+ };
+ static const byte expected_sk_sha2_256s[] = {
+ 0xFC, 0xBF, 0x36, 0xA9, 0x80, 0x7B, 0x30, 0x69,
+ 0x7B, 0xE0, 0x63, 0xA5, 0x10, 0x5E, 0x09, 0x1B,
+ 0x41, 0x2A, 0x39, 0x1D, 0xD3, 0x9E, 0x13, 0x26,
+ 0xEB, 0xA2, 0x3C, 0xBD, 0x40, 0x96, 0xCA, 0x77,
+ 0xEF, 0x41, 0x21, 0xC0, 0x8D, 0xD7, 0x1B, 0xE9,
+ 0x13, 0x57, 0x2F, 0x1F, 0x91, 0xE5, 0x7D, 0x0A,
+ 0xCB, 0xCD, 0x5C, 0xEC, 0x28, 0x53, 0x9A, 0xC2,
+ 0x75, 0x83, 0x2B, 0xBA, 0xA6, 0xC1, 0x10, 0x81,
+ 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9,
+ 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62,
+ 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86,
+ 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54,
+ 0x3E, 0x57, 0xAB, 0x49, 0x4D, 0x47, 0x06, 0x8F,
+ 0xFE, 0xE4, 0xB8, 0x24, 0x4A, 0xAD, 0x6F, 0x19,
+ 0xCD, 0xF9, 0x4A, 0x21, 0x72, 0xBD, 0x13, 0x4A,
+ 0x15, 0xA6, 0xB5, 0xF2, 0x98, 0xD5, 0xA8, 0x0E
+ };
+ static const byte expected_pk_sha2_256s[] = {
+ 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9,
+ 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62,
+ 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86,
+ 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54,
+ 0x3E, 0x57, 0xAB, 0x49, 0x4D, 0x47, 0x06, 0x8F,
+ 0xFE, 0xE4, 0xB8, 0x24, 0x4A, 0xAD, 0x6F, 0x19,
+ 0xCD, 0xF9, 0x4A, 0x21, 0x72, 0xBD, 0x13, 0x4A,
+ 0x15, 0xA6, 0xB5, 0xF2, 0x98, 0xD5, 0xA8, 0x0E
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHA2_256S,
+ sk_seed_sha2_256s, (word32)sizeof(sk_seed_sha2_256s),
+ sk_prf_sha2_256s, (word32)sizeof(sk_prf_sha2_256s),
+ pk_seed_sha2_256s, (word32)sizeof(pk_seed_sha2_256s),
+ expected_sk_sha2_256s, (word32)sizeof(expected_sk_sha2_256s),
+ expected_pk_sha2_256s, (word32)sizeof(expected_pk_sha2_256s));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_256S keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+
+ /* --- SHAKE KeyGen KATs (128f, 192s/f, 256s/f) --- */
+#ifdef WOLFSSL_SLHDSA_PARAM_128F
+ {
+ /* NIST CAVP SLH-DSA-SHAKE-128f keyGen vector (tgId=4, tcId=31) */
+ static const byte sk_seed_shake_128f[] = {
+ 0x39, 0x56, 0xAB, 0x39, 0x1B, 0x4D, 0x22, 0xFC,
+ 0x90, 0x7A, 0xF0, 0x74, 0x03, 0x26, 0xD0, 0x61
+ };
+ static const byte sk_prf_shake_128f[] = {
+ 0xAB, 0x0E, 0xB2, 0x06, 0x43, 0x6F, 0x2B, 0x86,
+ 0xEB, 0xE0, 0x86, 0xD7, 0x77, 0x39, 0xB3, 0xE4
+ };
+ static const byte pk_seed_shake_128f[] = {
+ 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6,
+ 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3
+ };
+ static const byte expected_sk_shake_128f[] = {
+ 0x39, 0x56, 0xAB, 0x39, 0x1B, 0x4D, 0x22, 0xFC,
+ 0x90, 0x7A, 0xF0, 0x74, 0x03, 0x26, 0xD0, 0x61,
+ 0xAB, 0x0E, 0xB2, 0x06, 0x43, 0x6F, 0x2B, 0x86,
+ 0xEB, 0xE0, 0x86, 0xD7, 0x77, 0x39, 0xB3, 0xE4,
+ 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6,
+ 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3,
+ 0x66, 0x57, 0x8F, 0x1F, 0x24, 0xC3, 0xFE, 0x37,
+ 0x1C, 0x97, 0xC1, 0x4C, 0xE0, 0xE7, 0x9C, 0xDC
+ };
+ static const byte expected_pk_shake_128f[] = {
+ 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6,
+ 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3,
+ 0x66, 0x57, 0x8F, 0x1F, 0x24, 0xC3, 0xFE, 0x37,
+ 0x1C, 0x97, 0xC1, 0x4C, 0xE0, 0xE7, 0x9C, 0xDC
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHAKE128F,
+ sk_seed_shake_128f, (word32)sizeof(sk_seed_shake_128f),
+ sk_prf_shake_128f, (word32)sizeof(sk_prf_shake_128f),
+ pk_seed_shake_128f, (word32)sizeof(pk_seed_shake_128f),
+ expected_sk_shake_128f, (word32)sizeof(expected_sk_shake_128f),
+ expected_pk_shake_128f, (word32)sizeof(expected_pk_shake_128f));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHAKE128F keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_192S
+ {
+ /* NIST CAVP SLH-DSA-SHAKE-192s keyGen vector (tgId=6, tcId=51) */
+ static const byte sk_seed_shake_192s[] = {
+ 0x87, 0x32, 0x62, 0x18, 0x60, 0xE9, 0xA6, 0xE1,
+ 0x88, 0x7B, 0xE5, 0x5F, 0x7A, 0xF6, 0x92, 0xB9,
+ 0x8E, 0xB4, 0xC1, 0x0B, 0x25, 0x99, 0xF9, 0x4A
+ };
+ static const byte sk_prf_shake_192s[] = {
+ 0xD5, 0xCC, 0x9D, 0x64, 0x70, 0xD8, 0xB2, 0x11,
+ 0x36, 0x15, 0x8E, 0x8B, 0x17, 0x10, 0xF1, 0xFB,
+ 0xE0, 0x3E, 0xCE, 0xD3, 0x7E, 0xD4, 0xAC, 0x68
+ };
+ static const byte pk_seed_shake_192s[] = {
+ 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53,
+ 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6,
+ 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8
+ };
+ static const byte expected_sk_shake_192s[] = {
+ 0x87, 0x32, 0x62, 0x18, 0x60, 0xE9, 0xA6, 0xE1,
+ 0x88, 0x7B, 0xE5, 0x5F, 0x7A, 0xF6, 0x92, 0xB9,
+ 0x8E, 0xB4, 0xC1, 0x0B, 0x25, 0x99, 0xF9, 0x4A,
+ 0xD5, 0xCC, 0x9D, 0x64, 0x70, 0xD8, 0xB2, 0x11,
+ 0x36, 0x15, 0x8E, 0x8B, 0x17, 0x10, 0xF1, 0xFB,
+ 0xE0, 0x3E, 0xCE, 0xD3, 0x7E, 0xD4, 0xAC, 0x68,
+ 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53,
+ 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6,
+ 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8,
+ 0xC6, 0x20, 0x45, 0x2E, 0x86, 0x4E, 0x84, 0x97,
+ 0xE1, 0xB3, 0x8A, 0x7B, 0x04, 0x44, 0x92, 0x19,
+ 0xAC, 0xD9, 0xE4, 0x39, 0x3F, 0x9C, 0x88, 0xEF
+ };
+ static const byte expected_pk_shake_192s[] = {
+ 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53,
+ 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6,
+ 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8,
+ 0xC6, 0x20, 0x45, 0x2E, 0x86, 0x4E, 0x84, 0x97,
+ 0xE1, 0xB3, 0x8A, 0x7B, 0x04, 0x44, 0x92, 0x19,
+ 0xAC, 0xD9, 0xE4, 0x39, 0x3F, 0x9C, 0x88, 0xEF
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHAKE192S,
+ sk_seed_shake_192s, (word32)sizeof(sk_seed_shake_192s),
+ sk_prf_shake_192s, (word32)sizeof(sk_prf_shake_192s),
+ pk_seed_shake_192s, (word32)sizeof(pk_seed_shake_192s),
+ expected_sk_shake_192s, (word32)sizeof(expected_sk_shake_192s),
+ expected_pk_shake_192s, (word32)sizeof(expected_pk_shake_192s));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHAKE192S keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_192F
+ {
+ /* NIST CAVP SLH-DSA-SHAKE-192f keyGen vector (tgId=8, tcId=71) */
+ static const byte sk_seed_shake_192f[] = {
+ 0xFB, 0x7A, 0x2C, 0x2C, 0x75, 0xCE, 0x6C, 0x96,
+ 0xB5, 0xF4, 0x32, 0x8E, 0x0A, 0xB3, 0x00, 0x47,
+ 0x6F, 0xC6, 0xF8, 0x64, 0xCB, 0x5B, 0x0B, 0x99
+ };
+ static const byte sk_prf_shake_192f[] = {
+ 0x99, 0x0E, 0xCB, 0x72, 0x6C, 0xA8, 0x22, 0xA4,
+ 0xE3, 0x65, 0x2D, 0xD9, 0x2E, 0xC0, 0xAA, 0xB7,
+ 0x63, 0x7E, 0xA4, 0x1C, 0x04, 0x82, 0xAE, 0x28
+ };
+ static const byte pk_seed_shake_192f[] = {
+ 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81,
+ 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90,
+ 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3
+ };
+ static const byte expected_sk_shake_192f[] = {
+ 0xFB, 0x7A, 0x2C, 0x2C, 0x75, 0xCE, 0x6C, 0x96,
+ 0xB5, 0xF4, 0x32, 0x8E, 0x0A, 0xB3, 0x00, 0x47,
+ 0x6F, 0xC6, 0xF8, 0x64, 0xCB, 0x5B, 0x0B, 0x99,
+ 0x99, 0x0E, 0xCB, 0x72, 0x6C, 0xA8, 0x22, 0xA4,
+ 0xE3, 0x65, 0x2D, 0xD9, 0x2E, 0xC0, 0xAA, 0xB7,
+ 0x63, 0x7E, 0xA4, 0x1C, 0x04, 0x82, 0xAE, 0x28,
+ 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81,
+ 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90,
+ 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3,
+ 0x98, 0xF1, 0xA9, 0x87, 0x6C, 0xB0, 0x82, 0xA4,
+ 0x8E, 0x9A, 0xE2, 0xC8, 0x62, 0xB2, 0x89, 0x48,
+ 0x6A, 0x39, 0x25, 0xCE, 0xFC, 0x6F, 0xF4, 0xBE
+ };
+ static const byte expected_pk_shake_192f[] = {
+ 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81,
+ 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90,
+ 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3,
+ 0x98, 0xF1, 0xA9, 0x87, 0x6C, 0xB0, 0x82, 0xA4,
+ 0x8E, 0x9A, 0xE2, 0xC8, 0x62, 0xB2, 0x89, 0x48,
+ 0x6A, 0x39, 0x25, 0xCE, 0xFC, 0x6F, 0xF4, 0xBE
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHAKE192F,
+ sk_seed_shake_192f, (word32)sizeof(sk_seed_shake_192f),
+ sk_prf_shake_192f, (word32)sizeof(sk_prf_shake_192f),
+ pk_seed_shake_192f, (word32)sizeof(pk_seed_shake_192f),
+ expected_sk_shake_192f, (word32)sizeof(expected_sk_shake_192f),
+ expected_pk_shake_192f, (word32)sizeof(expected_pk_shake_192f));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHAKE192F keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_256S
+ {
+ /* NIST CAVP SLH-DSA-SHAKE-256s keyGen vector (tgId=10, tcId=91) */
+ static const byte sk_seed_shake_256s[] = {
+ 0xE4, 0x40, 0xE3, 0x96, 0x44, 0xA1, 0x1A, 0x6A,
+ 0x58, 0xE8, 0x50, 0xC0, 0x9C, 0x8F, 0x03, 0xC2,
+ 0x73, 0xE4, 0x65, 0x23, 0x7F, 0x3B, 0xEF, 0x7C,
+ 0x58, 0xDE, 0x62, 0x28, 0x1E, 0x67, 0x6C, 0xEA
+ };
+ static const byte sk_prf_shake_256s[] = {
+ 0x99, 0xC1, 0x99, 0xC0, 0x0D, 0xB3, 0x0F, 0x84,
+ 0x99, 0xA6, 0x1B, 0x5B, 0x9D, 0xC8, 0xA3, 0x61,
+ 0x72, 0x5F, 0x6A, 0xE8, 0x0E, 0x97, 0x03, 0x71,
+ 0x76, 0xF4, 0x08, 0xC3, 0x0B, 0x38, 0x84, 0x4D
+ };
+ static const byte pk_seed_shake_256s[] = {
+ 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE,
+ 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB,
+ 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E,
+ 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF
+ };
+ static const byte expected_sk_shake_256s[] = {
+ 0xE4, 0x40, 0xE3, 0x96, 0x44, 0xA1, 0x1A, 0x6A,
+ 0x58, 0xE8, 0x50, 0xC0, 0x9C, 0x8F, 0x03, 0xC2,
+ 0x73, 0xE4, 0x65, 0x23, 0x7F, 0x3B, 0xEF, 0x7C,
+ 0x58, 0xDE, 0x62, 0x28, 0x1E, 0x67, 0x6C, 0xEA,
+ 0x99, 0xC1, 0x99, 0xC0, 0x0D, 0xB3, 0x0F, 0x84,
+ 0x99, 0xA6, 0x1B, 0x5B, 0x9D, 0xC8, 0xA3, 0x61,
+ 0x72, 0x5F, 0x6A, 0xE8, 0x0E, 0x97, 0x03, 0x71,
+ 0x76, 0xF4, 0x08, 0xC3, 0x0B, 0x38, 0x84, 0x4D,
+ 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE,
+ 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB,
+ 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E,
+ 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF,
+ 0x02, 0xAC, 0xD6, 0xB3, 0x19, 0x8E, 0xE1, 0xC9,
+ 0xFE, 0x9A, 0xFE, 0x61, 0xFD, 0x86, 0xD1, 0xE0,
+ 0x87, 0x7A, 0xD9, 0x06, 0x19, 0x80, 0xB5, 0x7B,
+ 0x17, 0x8C, 0xE2, 0x71, 0x91, 0xD8, 0xEB, 0x1B
+ };
+ static const byte expected_pk_shake_256s[] = {
+ 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE,
+ 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB,
+ 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E,
+ 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF,
+ 0x02, 0xAC, 0xD6, 0xB3, 0x19, 0x8E, 0xE1, 0xC9,
+ 0xFE, 0x9A, 0xFE, 0x61, 0xFD, 0x86, 0xD1, 0xE0,
+ 0x87, 0x7A, 0xD9, 0x06, 0x19, 0x80, 0xB5, 0x7B,
+ 0x17, 0x8C, 0xE2, 0x71, 0x91, 0xD8, 0xEB, 0x1B
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHAKE256S,
+ sk_seed_shake_256s, (word32)sizeof(sk_seed_shake_256s),
+ sk_prf_shake_256s, (word32)sizeof(sk_prf_shake_256s),
+ pk_seed_shake_256s, (word32)sizeof(pk_seed_shake_256s),
+ expected_sk_shake_256s, (word32)sizeof(expected_sk_shake_256s),
+ expected_pk_shake_256s, (word32)sizeof(expected_pk_shake_256s));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHAKE256S keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_256F
+ {
+ /* NIST CAVP SLH-DSA-SHAKE-256f keyGen vector (tgId=12, tcId=111) */
+ static const byte sk_seed_shake_256f[] = {
+ 0x2A, 0xC9, 0x40, 0x38, 0x58, 0xD1, 0x86, 0xB1,
+ 0x72, 0xED, 0xD8, 0xDF, 0x9C, 0x78, 0xA1, 0x14,
+ 0x49, 0x89, 0x36, 0x81, 0x48, 0x7D, 0x3A, 0xF0,
+ 0xDA, 0xD0, 0xEC, 0x34, 0x1E, 0x8A, 0xCA, 0x48
+ };
+ static const byte sk_prf_shake_256f[] = {
+ 0xAF, 0xA2, 0x77, 0x1B, 0xAE, 0x6C, 0x17, 0xDD,
+ 0x6F, 0x77, 0xB4, 0xE3, 0x80, 0x8B, 0x05, 0xF5,
+ 0x6F, 0x31, 0xB8, 0xF4, 0x12, 0x8D, 0xF2, 0xCC,
+ 0xB6, 0x77, 0xF0, 0x28, 0x3C, 0xFB, 0x18, 0xDA
+ };
+ static const byte pk_seed_shake_256f[] = {
+ 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0,
+ 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55,
+ 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A,
+ 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70
+ };
+ static const byte expected_sk_shake_256f[] = {
+ 0x2A, 0xC9, 0x40, 0x38, 0x58, 0xD1, 0x86, 0xB1,
+ 0x72, 0xED, 0xD8, 0xDF, 0x9C, 0x78, 0xA1, 0x14,
+ 0x49, 0x89, 0x36, 0x81, 0x48, 0x7D, 0x3A, 0xF0,
+ 0xDA, 0xD0, 0xEC, 0x34, 0x1E, 0x8A, 0xCA, 0x48,
+ 0xAF, 0xA2, 0x77, 0x1B, 0xAE, 0x6C, 0x17, 0xDD,
+ 0x6F, 0x77, 0xB4, 0xE3, 0x80, 0x8B, 0x05, 0xF5,
+ 0x6F, 0x31, 0xB8, 0xF4, 0x12, 0x8D, 0xF2, 0xCC,
+ 0xB6, 0x77, 0xF0, 0x28, 0x3C, 0xFB, 0x18, 0xDA,
+ 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0,
+ 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55,
+ 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A,
+ 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70,
+ 0x7A, 0x15, 0x8F, 0xF5, 0xD3, 0x0E, 0x34, 0x28,
+ 0x18, 0x3A, 0x3B, 0x3A, 0x96, 0xA0, 0xE4, 0xA3,
+ 0x41, 0xA2, 0xA1, 0x6E, 0x5A, 0x62, 0x26, 0xAF,
+ 0x37, 0x4D, 0x1E, 0xFB, 0x39, 0xA3, 0x5D, 0xF6
+ };
+ static const byte expected_pk_shake_256f[] = {
+ 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0,
+ 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55,
+ 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A,
+ 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70,
+ 0x7A, 0x15, 0x8F, 0xF5, 0xD3, 0x0E, 0x34, 0x28,
+ 0x18, 0x3A, 0x3B, 0x3A, 0x96, 0xA0, 0xE4, 0xA3,
+ 0x41, 0xA2, 0xA1, 0x6E, 0x5A, 0x62, 0x26, 0xAF,
+ 0x37, 0x4D, 0x1E, 0xFB, 0x39, 0xA3, 0x5D, 0xF6
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHAKE256F,
+ sk_seed_shake_256f, (word32)sizeof(sk_seed_shake_256f),
+ sk_prf_shake_256f, (word32)sizeof(sk_prf_shake_256f),
+ pk_seed_shake_256f, (word32)sizeof(pk_seed_shake_256f),
+ expected_sk_shake_256f, (word32)sizeof(expected_sk_shake_256f),
+ expected_pk_shake_256f, (word32)sizeof(expected_pk_shake_256f));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHAKE256F keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+
+ /* --- SHA2 fast variant KeyGen KATs --- */
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F
+ {
+ /* NIST CAVP SLH-DSA-SHA2-128f keyGen vector (tgId=3, tcId=21) */
+ static const byte sk_seed_sha2_128f[] = {
+ 0xC4, 0x2B, 0xCB, 0x3B, 0x5A, 0x6F, 0x33, 0x1F,
+ 0x5C, 0xCE, 0x89, 0x92, 0x53, 0xC6, 0xD9, 0xE2
+ };
+ static const byte sk_prf_sha2_128f[] = {
+ 0x9F, 0xF2, 0xB7, 0xEA, 0xD7, 0xA0, 0x4B, 0xAB,
+ 0x17, 0x94, 0xDB, 0x8C, 0xC6, 0x59, 0xC3, 0xB4
+ };
+ static const byte pk_seed_sha2_128f[] = {
+ 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D,
+ 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94
+ };
+ static const byte expected_sk_sha2_128f[] = {
+ 0xC4, 0x2B, 0xCB, 0x3B, 0x5A, 0x6F, 0x33, 0x1F,
+ 0x5C, 0xCE, 0x89, 0x92, 0x53, 0xC6, 0xD9, 0xE2,
+ 0x9F, 0xF2, 0xB7, 0xEA, 0xD7, 0xA0, 0x4B, 0xAB,
+ 0x17, 0x94, 0xDB, 0x8C, 0xC6, 0x59, 0xC3, 0xB4,
+ 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D,
+ 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94,
+ 0xB5, 0x46, 0xDF, 0x24, 0x7B, 0xE4, 0xC4, 0x57,
+ 0xF3, 0xD4, 0x67, 0xCD, 0xFC, 0xFA, 0xBD, 0x39
+ };
+ static const byte expected_pk_sha2_128f[] = {
+ 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D,
+ 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94,
+ 0xB5, 0x46, 0xDF, 0x24, 0x7B, 0xE4, 0xC4, 0x57,
+ 0xF3, 0xD4, 0x67, 0xCD, 0xFC, 0xFA, 0xBD, 0x39
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHA2_128F,
+ sk_seed_sha2_128f, (word32)sizeof(sk_seed_sha2_128f),
+ sk_prf_sha2_128f, (word32)sizeof(sk_prf_sha2_128f),
+ pk_seed_sha2_128f, (word32)sizeof(pk_seed_sha2_128f),
+ expected_sk_sha2_128f, (word32)sizeof(expected_sk_sha2_128f),
+ expected_pk_sha2_128f, (word32)sizeof(expected_pk_sha2_128f));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_128F keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F
+ {
+ /* NIST CAVP SLH-DSA-SHA2-192f keyGen vector (tgId=7, tcId=61) */
+ static const byte sk_seed_sha2_192f[] = {
+ 0xA0, 0x21, 0xB4, 0xB9, 0xD6, 0xDE, 0xE1, 0x68,
+ 0x72, 0x2B, 0xC1, 0x02, 0x25, 0xE5, 0x0A, 0x94,
+ 0x66, 0x42, 0xAF, 0x63, 0x0C, 0x3C, 0x7C, 0x7D
+ };
+ static const byte sk_prf_sha2_192f[] = {
+ 0x69, 0xE3, 0xA4, 0x0B, 0xA0, 0x9D, 0xF2, 0xAC,
+ 0x16, 0x5B, 0x79, 0x2A, 0x07, 0xF0, 0x64, 0xAC,
+ 0x5F, 0xC2, 0x8D, 0x8C, 0x99, 0xA5, 0x80, 0xF4
+ };
+ static const byte pk_seed_sha2_192f[] = {
+ 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47,
+ 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B,
+ 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3
+ };
+ static const byte expected_sk_sha2_192f[] = {
+ 0xA0, 0x21, 0xB4, 0xB9, 0xD6, 0xDE, 0xE1, 0x68,
+ 0x72, 0x2B, 0xC1, 0x02, 0x25, 0xE5, 0x0A, 0x94,
+ 0x66, 0x42, 0xAF, 0x63, 0x0C, 0x3C, 0x7C, 0x7D,
+ 0x69, 0xE3, 0xA4, 0x0B, 0xA0, 0x9D, 0xF2, 0xAC,
+ 0x16, 0x5B, 0x79, 0x2A, 0x07, 0xF0, 0x64, 0xAC,
+ 0x5F, 0xC2, 0x8D, 0x8C, 0x99, 0xA5, 0x80, 0xF4,
+ 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47,
+ 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B,
+ 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3,
+ 0x35, 0x77, 0xFD, 0x58, 0x4B, 0xC0, 0x78, 0x4C,
+ 0x55, 0x9C, 0xDB, 0x24, 0x37, 0xA4, 0x6F, 0x7F,
+ 0x75, 0x3C, 0x33, 0x63, 0x69, 0x41, 0x9A, 0xCF
+ };
+ static const byte expected_pk_sha2_192f[] = {
+ 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47,
+ 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B,
+ 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3,
+ 0x35, 0x77, 0xFD, 0x58, 0x4B, 0xC0, 0x78, 0x4C,
+ 0x55, 0x9C, 0xDB, 0x24, 0x37, 0xA4, 0x6F, 0x7F,
+ 0x75, 0x3C, 0x33, 0x63, 0x69, 0x41, 0x9A, 0xCF
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHA2_192F,
+ sk_seed_sha2_192f, (word32)sizeof(sk_seed_sha2_192f),
+ sk_prf_sha2_192f, (word32)sizeof(sk_prf_sha2_192f),
+ pk_seed_sha2_192f, (word32)sizeof(pk_seed_sha2_192f),
+ expected_sk_sha2_192f, (word32)sizeof(expected_sk_sha2_192f),
+ expected_pk_sha2_192f, (word32)sizeof(expected_pk_sha2_192f));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_192F keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F
+ {
+ /* NIST CAVP SLH-DSA-SHA2-256f keyGen vector (tgId=11, tcId=101) */
+ static const byte sk_seed_sha2_256f[] = {
+ 0x18, 0x52, 0x37, 0x02, 0xA0, 0xFE, 0x2C, 0x9E,
+ 0x48, 0x89, 0x48, 0xB1, 0x27, 0x18, 0x5B, 0xAB,
+ 0x93, 0xD3, 0xF0, 0x2C, 0x3D, 0x7C, 0x23, 0xA1,
+ 0xB3, 0x79, 0xF7, 0x62, 0xDE, 0x05, 0x09, 0xE5
+ };
+ static const byte sk_prf_sha2_256f[] = {
+ 0x6A, 0xB0, 0xD9, 0xF9, 0x35, 0x40, 0xBD, 0x80,
+ 0x9D, 0x1D, 0x2E, 0x8A, 0x05, 0x04, 0x40, 0xAA,
+ 0x81, 0xE8, 0x53, 0x75, 0x04, 0x70, 0xE2, 0xB0,
+ 0x0C, 0x95, 0x9D, 0xBD, 0x3B, 0xE4, 0x0E, 0x2B
+ };
+ static const byte pk_seed_sha2_256f[] = {
+ 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1,
+ 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44,
+ 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5,
+ 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0
+ };
+ static const byte expected_sk_sha2_256f[] = {
+ 0x18, 0x52, 0x37, 0x02, 0xA0, 0xFE, 0x2C, 0x9E,
+ 0x48, 0x89, 0x48, 0xB1, 0x27, 0x18, 0x5B, 0xAB,
+ 0x93, 0xD3, 0xF0, 0x2C, 0x3D, 0x7C, 0x23, 0xA1,
+ 0xB3, 0x79, 0xF7, 0x62, 0xDE, 0x05, 0x09, 0xE5,
+ 0x6A, 0xB0, 0xD9, 0xF9, 0x35, 0x40, 0xBD, 0x80,
+ 0x9D, 0x1D, 0x2E, 0x8A, 0x05, 0x04, 0x40, 0xAA,
+ 0x81, 0xE8, 0x53, 0x75, 0x04, 0x70, 0xE2, 0xB0,
+ 0x0C, 0x95, 0x9D, 0xBD, 0x3B, 0xE4, 0x0E, 0x2B,
+ 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1,
+ 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44,
+ 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5,
+ 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0,
+ 0x0A, 0xD5, 0x19, 0x7F, 0xFC, 0xBA, 0xAF, 0xE1,
+ 0x1B, 0x1E, 0x41, 0x3F, 0x26, 0xAD, 0xB1, 0x50,
+ 0x4C, 0xE1, 0xC3, 0xF5, 0xC4, 0x0C, 0x1D, 0xCD,
+ 0xA1, 0x4E, 0x99, 0xFD, 0x12, 0x6D, 0x5B, 0x81
+ };
+ static const byte expected_pk_sha2_256f[] = {
+ 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1,
+ 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44,
+ 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5,
+ 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0,
+ 0x0A, 0xD5, 0x19, 0x7F, 0xFC, 0xBA, 0xAF, 0xE1,
+ 0x1B, 0x1E, 0x41, 0x3F, 0x26, 0xAD, 0xB1, 0x50,
+ 0x4C, 0xE1, 0xC3, 0xF5, 0xC4, 0x0C, 0x1D, 0xCD,
+ 0xA1, 0x4E, 0x99, 0xFD, 0x12, 0x6D, 0x5B, 0x81
+ };
+ ret = slhdsa_keygen_kat(SLHDSA_SHA2_256F,
+ sk_seed_sha2_256f, (word32)sizeof(sk_seed_sha2_256f),
+ sk_prf_sha2_256f, (word32)sizeof(sk_prf_sha2_256f),
+ pk_seed_sha2_256f, (word32)sizeof(pk_seed_sha2_256f),
+ expected_sk_sha2_256f, (word32)sizeof(expected_sk_sha2_256f),
+ expected_pk_sha2_256f, (word32)sizeof(expected_pk_sha2_256f));
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_256F keyGen KAT", 0);
+ goto out;
+ }
+ }
+#endif
+#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */
+
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
#ifdef WOLFSSL_SLHDSA_PARAM_128S
ret = slhdsa_test_param(SLHDSA_SHAKE128S);
@@ -53108,6 +54013,48 @@ wc_test_ret_t slhdsa_test(void)
goto out;
}
#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S
+ ret = slhdsa_test_param(SLHDSA_SHA2_128S);
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_128S", 0);
+ goto out;
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F
+ ret = slhdsa_test_param(SLHDSA_SHA2_128F);
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_128F", 0);
+ goto out;
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S
+ ret = slhdsa_test_param(SLHDSA_SHA2_192S);
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_192S", 0);
+ goto out;
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F
+ ret = slhdsa_test_param(SLHDSA_SHA2_192F);
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_192F", 0);
+ goto out;
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S
+ ret = slhdsa_test_param(SLHDSA_SHA2_256S);
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_256S", 0);
+ goto out;
+ }
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F
+ ret = slhdsa_test_param(SLHDSA_SHA2_256F);
+ if (ret != 0) {
+ wc_test_render_error_message("SLHDSA_SHA2_256F", 0);
+ goto out;
+ }
+#endif
#endif
out:
@@ -64571,7 +65518,7 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
len = (word32)sizeof(seed);
if (info->seed.sz < len)
len = info->seed.sz;
- XMEMCPY(info->seed.seed, seed, sizeof(seed));
+ XMEMCPY(info->seed.seed, seed, len);
info->seed.seed += len;
info->seed.sz -= len;
(*seedWord32)++;
@@ -66511,7 +67458,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void)
#else
printf("Test Profile: Default (Aggressive multi-threaded)\n");
#endif
- printf("Expected statistical false positive rate: ~%.2f failures\n",
+ printf("Current expected statistical false positive rate with ADP/RCT"
+ ": NONE\n");
+ printf("Historical expected statistical false positive rate with "
+ "continuous test: ~%.2f failures\n",
(double)total_iterations * 32.0 / 4294967296.0);
for (i = 0; i < NUM_THREADS; i++) {
diff --git a/wolfssl/wolfcrypt/dilithium.h b/wolfssl/wolfcrypt/dilithium.h
index dc6114f3e6c..61e1b63c74a 100644
--- a/wolfssl/wolfcrypt/dilithium.h
+++ b/wolfssl/wolfcrypt/dilithium.h
@@ -832,6 +832,9 @@ WOLFSSL_API
int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen,
int hashAlg, const byte* hash, word32 hashLen, byte* sig, word32 *sigLen,
dilithium_key* key, const byte* seed);
+WOLFSSL_API
+int wc_dilithium_sign_mu_with_seed(const byte* mu, word32 muLen,
+ byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed);
#endif
WOLFSSL_API
int wc_dilithium_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
@@ -844,6 +847,9 @@ WOLFSSL_API
int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen,
const byte* ctx, byte ctxLen, int hashAlg, const byte* hash,
word32 hashLen, int* res, dilithium_key* key);
+WOLFSSL_API
+int wc_dilithium_verify_mu(const byte* sig, word32 sigLen, const byte* mu,
+ word32 muLen, int* res, dilithium_key* key);
#ifndef WC_NO_CONSTRUCTORS
WOLFSSL_API
diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h
index f879aabc3bb..15027fcbe14 100644
--- a/wolfssl/wolfcrypt/error-crypt.h
+++ b/wolfssl/wolfcrypt/error-crypt.h
@@ -88,7 +88,7 @@ enum wolfCrypt_ErrorCodes {
AES_EAX_AUTH_E = -122, /* AES-EAX Authentication check failure */
KEY_EXHAUSTED_E = -123, /* No longer usable for operation. */
- /* -124 unused. */
+ ML_KEM_KAT_FIPS_E = -124, /* ML-KEM KAT failure */
MEMORY_E = -125, /* out of memory error */
VAR_STATE_CHANGE_E = -126, /* var state modified by different thread */
@@ -136,7 +136,9 @@ enum wolfCrypt_ErrorCodes {
ED448_KAT_FIPS_E = -164, /* Ed448 Known answer test failure */
PBKDF2_KAT_FIPS_E = -165, /* PBKDF2 Known answer test failure */
WC_KEY_MISMATCH_E = -166, /* Error for private/public key mismatch */
- /* -167..-169 unused. */
+ ML_DSA_KAT_FIPS_E = -167, /* ML-DSA KAT failure */
+ LMS_KAT_FIPS_E = -168, /* LMS KAT failure */
+ XMSS_KAT_FIPS_E = -169, /* XMSS KAT failure */
ECC_BAD_ARG_E = -170, /* ECC input argument of wrong type */
ASN_ECC_KEY_E = -171, /* ASN ECC bad input */
@@ -311,10 +313,14 @@ enum wolfCrypt_ErrorCodes {
* not match stored hash*/
BUSY_E = -1006, /* Object is busy */
ALREADY_E = -1007, /* Operation was redundant or preempted */
-
- SEQ_OVERFLOW_E = -1008, /* Sequence counter would overflow */
- WC_SPAN2_LAST_E = -1008, /* Update to indicate last used error code */
- WC_LAST_E = -1008, /* the last code used either here or in
+ ML_KEM_PCT_E = -1008, /* ML-KEM Pairwise Consistency Test failure */
+ ML_DSA_PCT_E = -1009, /* ML-DSA Pairwise Consistency Test failure */
+ DRBG_SHA512_KAT_FIPS_E = -1010, /* SHA-512 DRBG KAT failure */
+
+ SEQ_OVERFLOW_E = -1011, /* Sequence counter would overflow */
+ SLH_DSA_KAT_FIPS_E = -1012, /* SLH-DSA CAST KAT failure */
+ WC_SPAN2_LAST_E = -1012, /* Update to indicate last used error code */
+ WC_LAST_E = -1012, /* the last code used either here or in
* error-ssl.h */
WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */
diff --git a/wolfssl/wolfcrypt/fips_test.h b/wolfssl/wolfcrypt/fips_test.h
index e4e8bf84d23..de2b506df2c 100644
--- a/wolfssl/wolfcrypt/fips_test.h
+++ b/wolfssl/wolfcrypt/fips_test.h
@@ -74,7 +74,13 @@ enum FipsCastId {
FIPS_CAST_PBKDF2 = 18,
/* v7.0.0 + */
FIPS_CAST_AES_ECB = 19,
- FIPS_CAST_COUNT = 20
+ FIPS_CAST_ML_KEM = 20,
+ FIPS_CAST_ML_DSA = 21,
+ FIPS_CAST_LMS = 22,
+ FIPS_CAST_XMSS = 23,
+ FIPS_CAST_DRBG_SHA512 = 24,
+ FIPS_CAST_SLH_DSA = 25,
+ FIPS_CAST_COUNT = 26
};
enum FipsCastStateId {
diff --git a/wolfssl/wolfcrypt/lms.h b/wolfssl/wolfcrypt/lms.h
index 8ba69d98a3e..19a7a0543c4 100644
--- a/wolfssl/wolfcrypt/lms.h
+++ b/wolfssl/wolfcrypt/lms.h
@@ -118,6 +118,15 @@ enum wc_LmsParm {
WC_LMS_PARM_L4_H5_W8 = 33,
WC_LMS_PARM_L4_H10_W4 = 34,
WC_LMS_PARM_L4_H10_W8 = 35,
+ /* H25 parameter sets for SHA-256/256 */
+ WC_LMS_PARM_L1_H25_W1 = 56,
+ WC_LMS_PARM_L1_H25_W2 = 57,
+ WC_LMS_PARM_L1_H25_W4 = 58,
+ WC_LMS_PARM_L1_H25_W8 = 59,
+ /* W1 for non-H5 heights */
+ WC_LMS_PARM_L1_H10_W1 = 60,
+ WC_LMS_PARM_L1_H15_W1 = 61,
+ WC_LMS_PARM_L1_H20_W1 = 62,
#endif
#ifdef WOLFSSL_LMS_SHA256_192
@@ -141,6 +150,61 @@ enum wc_LmsParm {
WC_LMS_PARM_SHA256_192_L3_H5_W8 = 50,
WC_LMS_PARM_SHA256_192_L3_H10_W4 = 51,
WC_LMS_PARM_SHA256_192_L4_H5_W8 = 52,
+ /* H25 for SHA-256/192 */
+ WC_LMS_PARM_SHA256_192_L1_H25_W1 = 63,
+ WC_LMS_PARM_SHA256_192_L1_H25_W2 = 64,
+ WC_LMS_PARM_SHA256_192_L1_H25_W4 = 65,
+ WC_LMS_PARM_SHA256_192_L1_H25_W8 = 66,
+ /* W1 for non-H5 heights (SHA-256/192) */
+ WC_LMS_PARM_SHA256_192_L1_H10_W1 = 67,
+ WC_LMS_PARM_SHA256_192_L1_H15_W1 = 68,
+ WC_LMS_PARM_SHA256_192_L1_H20_W1 = 69,
+ WC_LMS_PARM_SHA256_192_L1_H15_W8 = 70,
+#endif
+
+#ifdef WOLFSSL_LMS_SHAKE256
+ /* SHAKE256/256, 32-byte output */
+ WC_LMS_PARM_SHAKE_L1_H5_W1 = 100,
+ WC_LMS_PARM_SHAKE_L1_H5_W2 = 101,
+ WC_LMS_PARM_SHAKE_L1_H5_W4 = 102,
+ WC_LMS_PARM_SHAKE_L1_H5_W8 = 103,
+ WC_LMS_PARM_SHAKE_L1_H10_W1 = 104,
+ WC_LMS_PARM_SHAKE_L1_H10_W2 = 105,
+ WC_LMS_PARM_SHAKE_L1_H10_W4 = 106,
+ WC_LMS_PARM_SHAKE_L1_H10_W8 = 107,
+ WC_LMS_PARM_SHAKE_L1_H15_W1 = 108,
+ WC_LMS_PARM_SHAKE_L1_H15_W2 = 109,
+ WC_LMS_PARM_SHAKE_L1_H15_W4 = 110,
+ WC_LMS_PARM_SHAKE_L1_H15_W8 = 111,
+ WC_LMS_PARM_SHAKE_L1_H20_W1 = 112,
+ WC_LMS_PARM_SHAKE_L1_H20_W2 = 113,
+ WC_LMS_PARM_SHAKE_L1_H20_W4 = 114,
+ WC_LMS_PARM_SHAKE_L1_H20_W8 = 115,
+ WC_LMS_PARM_SHAKE_L1_H25_W1 = 116,
+ WC_LMS_PARM_SHAKE_L1_H25_W2 = 117,
+ WC_LMS_PARM_SHAKE_L1_H25_W4 = 118,
+ WC_LMS_PARM_SHAKE_L1_H25_W8 = 119,
+ /* SHAKE256/192, 24-byte output */
+ WC_LMS_PARM_SHAKE192_L1_H5_W1 = 120,
+ WC_LMS_PARM_SHAKE192_L1_H5_W2 = 121,
+ WC_LMS_PARM_SHAKE192_L1_H5_W4 = 122,
+ WC_LMS_PARM_SHAKE192_L1_H5_W8 = 123,
+ WC_LMS_PARM_SHAKE192_L1_H10_W1 = 124,
+ WC_LMS_PARM_SHAKE192_L1_H10_W2 = 125,
+ WC_LMS_PARM_SHAKE192_L1_H10_W4 = 126,
+ WC_LMS_PARM_SHAKE192_L1_H10_W8 = 127,
+ WC_LMS_PARM_SHAKE192_L1_H15_W1 = 128,
+ WC_LMS_PARM_SHAKE192_L1_H15_W2 = 129,
+ WC_LMS_PARM_SHAKE192_L1_H15_W4 = 130,
+ WC_LMS_PARM_SHAKE192_L1_H15_W8 = 131,
+ WC_LMS_PARM_SHAKE192_L1_H20_W1 = 132,
+ WC_LMS_PARM_SHAKE192_L1_H20_W2 = 133,
+ WC_LMS_PARM_SHAKE192_L1_H20_W4 = 134,
+ WC_LMS_PARM_SHAKE192_L1_H20_W8 = 135,
+ WC_LMS_PARM_SHAKE192_L1_H25_W1 = 136,
+ WC_LMS_PARM_SHAKE192_L1_H25_W2 = 137,
+ WC_LMS_PARM_SHAKE192_L1_H25_W4 = 138,
+ WC_LMS_PARM_SHAKE192_L1_H25_W8 = 139,
#endif
};
diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h
index db7d58a97ef..67e640bb297 100644
--- a/wolfssl/wolfcrypt/random.h
+++ b/wolfssl/wolfcrypt/random.h
@@ -52,11 +52,15 @@
#endif
#endif
-/* Size of the BRBG seed */
+/* Size of the DRBG seed (SHA-256) */
#ifndef DRBG_SEED_LEN
#define DRBG_SEED_LEN (440/8)
#endif
+#ifdef WOLFSSL_DRBG_SHA512
+ #define DRBG_SHA512_SEED_LEN (888/8) /* 111 bytes per SP 800-90A Table 2 */
+#endif
+
#if !defined(CUSTOM_RAND_TYPE)
/* To maintain compatibility the default is byte */
@@ -104,9 +108,16 @@
#endif
#elif defined(HAVE_HASHDRBG)
#ifdef NO_SHA256
- #error "Hash DRBG requires SHA-256."
+ #ifndef WOLFSSL_DRBG_SHA512
+ #error "Hash DRBG requires SHA-256 or SHA-512."
+ #endif
#endif /* NO_SHA256 */
- #include
+ #ifndef NO_SHA256
+ #include
+ #endif
+ #ifdef WOLFSSL_DRBG_SHA512
+ #include
+ #endif
#elif defined(HAVE_WNR)
/* allow whitewood as direct RNG source using wc_GenerateSeed directly */
#elif defined(HAVE_INTEL_RDRAND)
@@ -239,7 +250,33 @@ struct OS_Seed {
#define WC_DRBG_SEED_BLOCK_SZ SEED_BLOCK_SZ
-#define WC_DRBG_SEED_SZ (RNG_SECURITY_STRENGTH*ENTROPY_SCALE_FACTOR/8)
+/* WC_DRBG_SEED_SZ is the number of bytes of raw entropy gathered from the
+ * NDRNG at instantiation and reseed. We deliberately "overseed" beyond the
+ * NIST minimum (security_strength bits) to account for entropy sources that
+ * may deliver fewer than 1 bit of real entropy per bit of output. With the
+ * default FIPS ENTROPY_SCALE_FACTOR of 4 this yields 256*4/8 = 128 bytes =
+ * 1024 bits of raw seed material, guaranteeing at least 256 bits of real
+ * entropy even if the source provides only 1 good bit per 4.
+ *
+ * Hash_df then compresses this seed material into the internal V and C state
+ * vectors (seedlen = 440 bits for SHA-256, 888 bits for SHA-512 per
+ * SP 800-90A Table 2).
+ *
+ * In FIPS mode (ENTROPY_SCALE_FACTOR >= 4) the base is already >= 128 bytes
+ * which exceeds DRBG_SHA512_SEED_LEN (111), so both DRBGs use the same
+ * seed size. In non-FIPS mode we use the base for both DRBGs so that
+ * enabling SHA-512 DRBG does not inflate the per-init entropy cost.
+ * SP 800-90A requires only security_strength bits (256 = 32 bytes) of
+ * entropy regardless of hash size; hash_df compresses the seed material
+ * into the internal V/C state vectors. */
+#define WC_DRBG_SEED_SZ_BASE (RNG_SECURITY_STRENGTH*ENTROPY_SCALE_FACTOR/8)
+
+#if defined(HAVE_FIPS) && defined(WOLFSSL_DRBG_SHA512) && \
+ (WC_DRBG_SEED_SZ_BASE < DRBG_SHA512_SEED_LEN)
+ #define WC_DRBG_SEED_SZ DRBG_SHA512_SEED_LEN
+#else
+ #define WC_DRBG_SEED_SZ WC_DRBG_SEED_SZ_BASE
+#endif
/* The maximum seed size will be the seed size plus a seed block for the
* test, and an additional half of the seed size. This additional half
@@ -248,8 +285,14 @@ struct OS_Seed {
#define WC_DRBG_MAX_SEED_SZ (WC_DRBG_SEED_SZ + WC_DRBG_SEED_SZ/2 + \
SEED_BLOCK_SZ)
-#define RNG_HEALTH_TEST_CHECK_SIZE (WC_SHA256_DIGEST_SIZE * 4)
+#ifndef NO_SHA256
+ #define RNG_HEALTH_TEST_CHECK_SIZE (WC_SHA256_DIGEST_SIZE * 4)
+#endif
+#ifdef WOLFSSL_DRBG_SHA512
+ #define RNG_HEALTH_TEST_CHECK_SIZE_SHA512 (WC_SHA512_DIGEST_SIZE * 4)
+#endif
+#ifndef NO_SHA256
struct DRBG_internal {
#ifdef WORD64_AVAILABLE
word64 reseedCtr;
@@ -268,8 +311,34 @@ struct DRBG_internal {
byte digest_scratch[WC_SHA256_DIGEST_SIZE];
#endif
};
+#endif /* !NO_SHA256 */
+
+#ifdef WOLFSSL_DRBG_SHA512
+struct DRBG_SHA512_internal {
+ word64 reseedCtr;
+ byte V[DRBG_SHA512_SEED_LEN];
+ byte C[DRBG_SHA512_SEED_LEN];
+ void* heap;
+#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB)
+ int devId;
+#endif
+#ifdef WOLFSSL_SMALL_STACK_CACHE
+ wc_Sha512 sha512;
+ byte seed_scratch[DRBG_SHA512_SEED_LEN];
+ byte digest_scratch[WC_SHA512_DIGEST_SIZE];
+#endif
+};
+#endif /* WOLFSSL_DRBG_SHA512 */
#endif /* HAVE_HASHDRBG */
+/* DRBG type enum */
+#ifdef HAVE_HASHDRBG
+enum wc_DrbgType {
+ WC_DRBG_SHA256 = 0,
+ WC_DRBG_SHA512 = 1,
+};
+#endif
+
/* RNG health states */
#define WC_DRBG_NOT_INIT 0
#define WC_DRBG_OK 1
@@ -301,17 +370,35 @@ struct WC_RNG {
#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES
struct {
#endif
- /* Hash-based Deterministic Random Bit Generator */
+ #ifndef NO_SHA256
+ /* SHA-256 Hash-based Deterministic Random Bit Generator */
struct DRBG* drbg;
#if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY)
struct DRBG_internal drbg_data;
#endif
#ifdef WOLFSSL_SMALL_STACK_CACHE
- /* Scratch buffers -- all preallocated by _InitRng(). */
+ /* SHA-256 scratch buffers -- preallocated by _InitRng(). */
struct DRBG_internal *drbg_scratch;
byte *health_check_scratch;
+ #endif
+ #endif /* !NO_SHA256 */
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ /* Seed buffer for PollAndReSeed -- shared by both DRBG types */
byte *newSeed_buf;
#endif
+ #ifdef WOLFSSL_DRBG_SHA512
+ /* SHA-512 Hash-based Deterministic Random Bit Generator */
+ struct DRBG_SHA512* drbg512;
+ #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY)
+ struct DRBG_SHA512_internal drbg512_data;
+ #endif
+ #ifdef WOLFSSL_SMALL_STACK_CACHE
+ /* SHA-512 scratch buffers -- preallocated by _InitRng(). */
+ struct DRBG_SHA512_internal *drbg512_scratch;
+ byte *health_check_scratch_512;
+ #endif
+ #endif /* WOLFSSL_DRBG_SHA512 */
+ byte drbgType; /* WC_DRBG_SHA256 or WC_DRBG_SHA512 */
#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES
};
#endif
@@ -407,6 +494,89 @@ WOLFSSL_API int wc_FreeRng(WC_RNG* rng);
const byte* seedB, word32 seedBSz,
byte* output, word32 outputSz,
void* heap, int devId);
+#if !defined(NO_SHA256) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ /* Extended SHA-256 Hash_DRBG health test per SP 800-90A.
+ * Flexible output size, prediction resistance, personalization
+ * strings, and additional input support. */
+ WOLFSSL_API int wc_RNG_HealthTest_SHA256_ex(
+ int predResistance,
+ const byte* nonce, word32 nonceSz,
+ const byte* persoString,
+ word32 persoStringSz,
+ const byte* entropyA,
+ word32 entropyASz,
+ const byte* entropyB,
+ word32 entropyBSz,
+ const byte* entropyC,
+ word32 entropyCsz,
+ const byte* additionalA,
+ word32 additionalASz,
+ const byte* additionalB,
+ word32 additionalBSz,
+ const byte* additionalReseed,
+ word32 additionalReseedSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId);
+#endif /* !NO_SHA256 && !HAVE_SELFTEST && FIPS v7+ */
+#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ WOLFSSL_API int wc_RNG_HealthTest_SHA512(int reseed,
+ const byte* seedA, word32 seedASz,
+ const byte* seedB, word32 seedBSz,
+ byte* output, word32 outputSz);
+ WOLFSSL_API int wc_RNG_HealthTest_SHA512_ex(int reseed,
+ const byte* nonce, word32 nonceSz,
+ const byte* persoString,
+ word32 persoStringSz,
+ const byte* seedA, word32 seedASz,
+ const byte* seedB, word32 seedBSz,
+ const byte* additionalA,
+ word32 additionalASz,
+ const byte* additionalB,
+ word32 additionalBSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId);
+ /* Extended SHA-512 Hash_DRBG health test per SP 800-90A.
+ * Flexible output size, prediction resistance support.
+ * predResistance=1: additionalA/B go to Reseed per SP 800-90A 9.3.1,
+ * Generate gets NULL additional input.
+ * predResistance=0: additionalReseed goes to Reseed, additionalA/B go
+ * to Generate calls 1 and 2 respectively. */
+ WOLFSSL_API int wc_RNG_HealthTest_SHA512_ex2(
+ int predResistance,
+ const byte* nonce, word32 nonceSz,
+ const byte* persoString,
+ word32 persoStringSz,
+ const byte* entropyA,
+ word32 entropyASz,
+ const byte* entropyB,
+ word32 entropyBSz,
+ const byte* entropyC,
+ word32 entropyCsz,
+ const byte* additionalA,
+ word32 additionalASz,
+ const byte* additionalB,
+ word32 additionalBSz,
+ const byte* additionalReseed,
+ word32 additionalReseedSz,
+ byte* output, word32 outputSz,
+ void* heap, int devId);
+#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */
+
+ /* Runtime DRBG disable/enable API */
+#if !defined(HAVE_SELFTEST) && \
+ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
+ WOLFSSL_API int wc_Sha256Drbg_Disable(void);
+ WOLFSSL_API int wc_Sha256Drbg_Enable(void);
+ WOLFSSL_API int wc_Sha256Drbg_GetStatus(void);
+#ifdef WOLFSSL_DRBG_SHA512
+ WOLFSSL_API int wc_Sha512Drbg_Disable(void);
+ WOLFSSL_API int wc_Sha512Drbg_Enable(void);
+ WOLFSSL_API int wc_Sha512Drbg_GetStatus(void);
+#endif
+#endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS v7+) */
+
#endif /* HAVE_HASHDRBG */
#ifdef __cplusplus
diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h
index 6c6c2185e35..69cc33486aa 100644
--- a/wolfssl/wolfcrypt/rsa.h
+++ b/wolfssl/wolfcrypt/rsa.h
@@ -426,6 +426,14 @@ WOLFSSL_API int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz,
#define WC_MGF1SHA512 3
#define WC_MGF1SHA512_224 5
#define WC_MGF1SHA512_256 6
+#define WC_MGF1SHA3_224 7
+#define WC_MGF1SHA3_256 8
+#define WC_MGF1SHA3_384 9
+#define WC_MGF1SHA3_512 10
+#define WC_MGF1SHAKE128 11
+#define WC_MGF1SHAKE256 12
+#define WC_MGFSHAKE128 13
+#define WC_MGFSHAKE256 14
/* Padding types */
#define WC_RSA_PKCSV15_PAD 0
diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h
index 914ffa13712..8ae9a870c2a 100644
--- a/wolfssl/wolfcrypt/wc_lms.h
+++ b/wolfssl/wolfcrypt/wc_lms.h
@@ -94,6 +94,9 @@
#include
#include
+#ifdef WOLFSSL_LMS_SHAKE256
+#include
+#endif
/* When raw hash access APIs are disabled or unavailable (WOLFSSL_NO_HASH_RAW),
* fall back to using the full hash API calls. */
@@ -122,10 +125,10 @@
#define LMS_MAX_HEIGHT WOLFSSL_LMS_MAX_HEIGHT
#else
/* Maximum height of a tree supported by implementation. */
- #define LMS_MAX_HEIGHT 20
+ #define LMS_MAX_HEIGHT 25
#endif
-#if (LMS_MAX_HEIGHT < 5) || (LMS_MAX_HEIGHT > 20)
- #error "LMS parameters only support heights 5-20."
+#if (LMS_MAX_HEIGHT < 5) || (LMS_MAX_HEIGHT > 25)
+ #error "LMS parameters only support heights 5-25."
#endif
/* Length of I in bytes. */
@@ -312,10 +315,16 @@
#define LMS_SHA256 0x0000
/* Indicates using SHA-256/192 for hashing. */
#define LMS_SHA256_192 0x1000
+/* Indicates using SHAKE256/256 for hashing. */
+#define LMS_SHAKE256 0x2000
+/* Indicates using SHAKE256/192 for hashing. */
+#define LMS_SHAKE256_192 0x3000
/* Mask to get hashing algorithm from type. */
#define LMS_HASH_MASK 0xf000
/* Mask to get height or Winternitz width from type. */
#define LMS_H_W_MASK 0x0fff
+/* Bit test: non-zero if type uses SHAKE256. */
+#define LMS_IS_SHAKE(type) (((type) & 0x2000) != 0)
/* LMS Parameters. */
/* SHA-256 hash, 32-bytes of hash used, tree height of 5. */
@@ -349,15 +358,55 @@
/* SHA-256 hash, 32-bytes of hash used, tree height of 25. */
#define LMS_SHA256_M24_H25 (0x0e | LMS_SHA256_192)
-/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 1 bit. */
+/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 1 bit. */
#define LMOTS_SHA256_N24_W1 (0x05 | LMS_SHA256_192)
-/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 2 bits. */
+/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 2 bits. */
#define LMOTS_SHA256_N24_W2 (0x06 | LMS_SHA256_192)
-/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 4 bits. */
+/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 4 bits. */
#define LMOTS_SHA256_N24_W4 (0x07 | LMS_SHA256_192)
-/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 8 bits. */
+/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 8 bits. */
#define LMOTS_SHA256_N24_W8 (0x08 | LMS_SHA256_192)
+/* SHAKE256 hash, 32-bytes of hash used, tree height of 5. */
+#define LMS_SHAKE_M32_H5 (0x0f | LMS_SHAKE256)
+/* SHAKE256 hash, 32-bytes of hash used, tree height of 10. */
+#define LMS_SHAKE_M32_H10 (0x10 | LMS_SHAKE256)
+/* SHAKE256 hash, 32-bytes of hash used, tree height of 15. */
+#define LMS_SHAKE_M32_H15 (0x11 | LMS_SHAKE256)
+/* SHAKE256 hash, 32-bytes of hash used, tree height of 20. */
+#define LMS_SHAKE_M32_H20 (0x12 | LMS_SHAKE256)
+/* SHAKE256 hash, 32-bytes of hash used, tree height of 25. */
+#define LMS_SHAKE_M32_H25 (0x13 | LMS_SHAKE256)
+
+/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 1 bit. */
+#define LMOTS_SHAKE_N32_W1 (0x09 | LMS_SHAKE256)
+/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 2 bits. */
+#define LMOTS_SHAKE_N32_W2 (0x0a | LMS_SHAKE256)
+/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 4 bits. */
+#define LMOTS_SHAKE_N32_W4 (0x0b | LMS_SHAKE256)
+/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 8 bits. */
+#define LMOTS_SHAKE_N32_W8 (0x0c | LMS_SHAKE256)
+
+/* SHAKE256 hash, 24-bytes of hash used, tree height of 5. */
+#define LMS_SHAKE_M24_H5 (0x14 | LMS_SHAKE256_192)
+/* SHAKE256 hash, 24-bytes of hash used, tree height of 10. */
+#define LMS_SHAKE_M24_H10 (0x15 | LMS_SHAKE256_192)
+/* SHAKE256 hash, 24-bytes of hash used, tree height of 15. */
+#define LMS_SHAKE_M24_H15 (0x16 | LMS_SHAKE256_192)
+/* SHAKE256 hash, 24-bytes of hash used, tree height of 20. */
+#define LMS_SHAKE_M24_H20 (0x17 | LMS_SHAKE256_192)
+/* SHAKE256 hash, 24-bytes of hash used, tree height of 25. */
+#define LMS_SHAKE_M24_H25 (0x18 | LMS_SHAKE256_192)
+
+/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 1 bit. */
+#define LMOTS_SHAKE_N24_W1 (0x0d | LMS_SHAKE256_192)
+/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 2 bits. */
+#define LMOTS_SHAKE_N24_W2 (0x0e | LMS_SHAKE256_192)
+/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 4 bits. */
+#define LMOTS_SHAKE_N24_W4 (0x0f | LMS_SHAKE256_192)
+/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 8 bits. */
+#define LMOTS_SHAKE_N24_W8 (0x10 | LMS_SHAKE256_192)
+
typedef struct LmsParams {
/* Number of tree levels. */
word8 levels;
@@ -408,10 +457,16 @@ typedef struct LmsState {
#endif
/* LMS parameters. */
const LmsParams* params;
- /* Hash algorithm. */
+ /* Hash algorithm (SHA-256). */
wc_Sha256 hash;
- /* Hash algorithm for calculating K. */
+ /* Hash algorithm for calculating K (SHA-256). */
wc_Sha256 hash_k;
+#ifdef WOLFSSL_LMS_SHAKE256
+ /* Hash algorithm (SHAKE256). */
+ wc_Shake shake;
+ /* Hash algorithm for calculating K (SHAKE256). */
+ wc_Shake shake_k;
+#endif
} LmsState;
#ifndef WOLFSSL_WC_LMS_SMALL
diff --git a/wolfssl/wolfcrypt/wc_slhdsa.h b/wolfssl/wolfcrypt/wc_slhdsa.h
index 19ee86fbb28..f8ade51b076 100644
--- a/wolfssl/wolfcrypt/wc_slhdsa.h
+++ b/wolfssl/wolfcrypt/wc_slhdsa.h
@@ -26,8 +26,20 @@
#include
#include
+#ifdef WOLFSSL_SLHDSA_SHA2
+ #include
+ #include
+ #include
+#endif
+
+#if FIPS_VERSION3_GE(7,0,0)
+ #include
+#endif
+
#ifdef WOLFSSL_HAVE_SLHDSA
+/* ======== SHAKE parameter guards ======== */
+
/* When a bits/opt is defined then ensure 'NO' defines are off. */
#ifdef WOLFSSL_SLHDSA_PARAM_128S
#undef WOLFSSL_SLHDSA_PARAM_NO_128S
@@ -155,6 +167,141 @@
#define WOLFSSL_SLHDSA_PARAM_NO_256
#endif
+/* ======== SHA2 parameter guards ======== */
+#ifdef WOLFSSL_SLHDSA_SHA2
+
+/* When a SHA2 param is defined, ensure 'NO' defines are off. */
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL
+#endif
+#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST
+#endif
+
+/* Derive aggregate 'NO' defines for SHA2. */
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_128
+#endif
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_192
+#endif
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_256
+#endif
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL
+#endif
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST
+#endif
+
+/* Turn on SHA2 parameter set based on 'NO' defines. */
+#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL)
+ #undef WOLFSSL_SLHDSA_PARAM_SHA2_128S
+ #define WOLFSSL_SLHDSA_PARAM_SHA2_128S
+#endif
+#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST)
+ #undef WOLFSSL_SLHDSA_PARAM_SHA2_128F
+ #define WOLFSSL_SLHDSA_PARAM_SHA2_128F
+#endif
+#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL)
+ #undef WOLFSSL_SLHDSA_PARAM_SHA2_192S
+ #define WOLFSSL_SLHDSA_PARAM_SHA2_192S
+#endif
+#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST)
+ #undef WOLFSSL_SLHDSA_PARAM_SHA2_192F
+ #define WOLFSSL_SLHDSA_PARAM_SHA2_192F
+#endif
+#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL)
+ #undef WOLFSSL_SLHDSA_PARAM_SHA2_256S
+ #define WOLFSSL_SLHDSA_PARAM_SHA2_256S
+#endif
+#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256) && \
+ !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST)
+ #undef WOLFSSL_SLHDSA_PARAM_SHA2_256F
+ #define WOLFSSL_SLHDSA_PARAM_SHA2_256F
+#endif
+
+/* Re-derive aggregate NOs for SHA2. */
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL
+#endif
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST
+#endif
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_128
+#endif
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_192
+#endif
+#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \
+ defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F)
+ #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256
+ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_256
+#endif
+
+#endif /* WOLFSSL_SLHDSA_SHA2 */
+
+/* ======== SHAKE size defines ======== */
+
/* Seed length for SLH-DSA SHAKE-128s/f. */
#define WC_SLHDSA_SHAKE128_SEED_LEN 16
/* Seed length for SLH-DSA SHAKE-192s/f. */
@@ -216,8 +363,76 @@
/* Seed length for SLH-DSA SHAKE-256f. */
#define WC_SLHDSA_SHAKE256F_SEED_LEN WC_SLHDSA_SHAKE256_SEED_LEN
-/* Determine maximum private and public key lengths based on maximum SHAKE-256
- * output length. */
+/* ======== SHA2 size defines ======== */
+#ifdef WOLFSSL_SLHDSA_SHA2
+
+/* Seed length for SLH-DSA SHA2-128s/f. */
+#define WC_SLHDSA_SHA2_128_SEED_LEN 16
+/* Seed length for SLH-DSA SHA2-192s/f. */
+#define WC_SLHDSA_SHA2_192_SEED_LEN 24
+/* Seed length for SLH-DSA SHA2-256s/f. */
+#define WC_SLHDSA_SHA2_256_SEED_LEN 32
+
+/* Private key length for SLH-DSA SHA2-128s. */
+#define WC_SLHDSA_SHA2_128S_PRIV_LEN (4 * 16)
+/* Public key length for SLH-DSA SHA2-128s. */
+#define WC_SLHDSA_SHA2_128S_PUB_LEN (2 * 16)
+/* Signature length for SLH-DSA SHA2-128s. */
+#define WC_SLHDSA_SHA2_128S_SIG_LEN 7856
+/* Seed length for SLH-DSA SHA2-128s. */
+#define WC_SLHDSA_SHA2_128S_SEED_LEN WC_SLHDSA_SHA2_128_SEED_LEN
+
+/* Private key length for SLH-DSA SHA2-128f. */
+#define WC_SLHDSA_SHA2_128F_PRIV_LEN (4 * 16)
+/* Public key length for SLH-DSA SHA2-128f. */
+#define WC_SLHDSA_SHA2_128F_PUB_LEN (2 * 16)
+/* Signature length for SLH-DSA SHA2-128f. */
+#define WC_SLHDSA_SHA2_128F_SIG_LEN 17088
+/* Seed length for SLH-DSA SHA2-128f. */
+#define WC_SLHDSA_SHA2_128F_SEED_LEN WC_SLHDSA_SHA2_128_SEED_LEN
+
+/* Private key length for SLH-DSA SHA2-192s. */
+#define WC_SLHDSA_SHA2_192S_PRIV_LEN (4 * 24)
+/* Public key length for SLH-DSA SHA2-192s. */
+#define WC_SLHDSA_SHA2_192S_PUB_LEN (2 * 24)
+/* Signature length for SLH-DSA SHA2-192s. */
+#define WC_SLHDSA_SHA2_192S_SIG_LEN 16224
+/* Seed length for SLH-DSA SHA2-192s. */
+#define WC_SLHDSA_SHA2_192S_SEED_LEN WC_SLHDSA_SHA2_192_SEED_LEN
+
+/* Private key length for SLH-DSA SHA2-192f. */
+#define WC_SLHDSA_SHA2_192F_PRIV_LEN (4 * 24)
+/* Public key length for SLH-DSA SHA2-192f. */
+#define WC_SLHDSA_SHA2_192F_PUB_LEN (2 * 24)
+/* Signature length for SLH-DSA SHA2-192f. */
+#define WC_SLHDSA_SHA2_192F_SIG_LEN 35664
+/* Seed length for SLH-DSA SHA2-192f. */
+#define WC_SLHDSA_SHA2_192F_SEED_LEN WC_SLHDSA_SHA2_192_SEED_LEN
+
+/* Private key length for SLH-DSA SHA2-256s. */
+#define WC_SLHDSA_SHA2_256S_PRIV_LEN (4 * 32)
+/* Public key length for SLH-DSA SHA2-256s. */
+#define WC_SLHDSA_SHA2_256S_PUB_LEN (2 * 32)
+/* Signature length for SLH-DSA SHA2-256s. */
+#define WC_SLHDSA_SHA2_256S_SIG_LEN 29792
+/* Seed length for SLH-DSA SHA2-256s. */
+#define WC_SLHDSA_SHA2_256S_SEED_LEN WC_SLHDSA_SHA2_256_SEED_LEN
+
+/* Private key length for SLH-DSA SHA2-256f. */
+#define WC_SLHDSA_SHA2_256F_PRIV_LEN (4 * 32)
+/* Public key length for SLH-DSA SHA2-256f. */
+#define WC_SLHDSA_SHA2_256F_PUB_LEN (2 * 32)
+/* Signature length for SLH-DSA SHA2-256f. */
+#define WC_SLHDSA_SHA2_256F_SIG_LEN 49856
+/* Seed length for SLH-DSA SHA2-256f. */
+#define WC_SLHDSA_SHA2_256F_SEED_LEN WC_SLHDSA_SHA2_256_SEED_LEN
+
+#endif /* WOLFSSL_SLHDSA_SHA2 */
+
+/* ======== Maximum size defines ======== */
+
+/* Determine maximum private and public key lengths based on maximum 256-bit
+ * output length. SHA2 variants have identical sizes to SHAKE counterparts. */
#ifndef WOLFSSL_SLHDSA_PARAM_NO_256
/* Maximum private key length. */
#define WC_SLHDSA_MAX_PRIV_LEN WC_SLHDSA_SHAKE256F_PRIV_LEN
@@ -279,8 +494,23 @@ enum SlhDsaParam {
SLHDSA_SHAKE192F = 3, /* SLH-DSA SHAKE192f */
SLHDSA_SHAKE256S = 4, /* SLH-DSA SHAKE256s */
SLHDSA_SHAKE256F = 5, /* SLH-DSA SHAKE256f */
+#ifdef WOLFSSL_SLHDSA_SHA2
+ SLHDSA_SHA2_128S = 6, /* SLH-DSA SHA2-128s */
+ SLHDSA_SHA2_128F = 7, /* SLH-DSA SHA2-128f */
+ SLHDSA_SHA2_192S = 8, /* SLH-DSA SHA2-192s */
+ SLHDSA_SHA2_192F = 9, /* SLH-DSA SHA2-192f */
+ SLHDSA_SHA2_256S = 10, /* SLH-DSA SHA2-256s */
+ SLHDSA_SHA2_256F = 11, /* SLH-DSA SHA2-256f */
+#endif
};
+/* Helper macro to detect SHA2 parameter sets. */
+#ifdef WOLFSSL_SLHDSA_SHA2
+ #define SLHDSA_IS_SHA2(p) ((p) >= SLHDSA_SHA2_128S)
+#else
+ #define SLHDSA_IS_SHA2(p) (0)
+#endif
+
/* Pre-defined parameter values. */
typedef struct SlhDsaParameters {
enum SlhDsaParam param; /* Parameter set id. */
@@ -317,10 +547,31 @@ typedef struct SlhDsaKey {
/* sk_seed | sk_prf | pk_seed, pk_root */
byte sk[32 * 4];
- /* First SHAKE-256 object. */
- wc_Shake shake;
- /* Second SHAKE-256 object. */
- wc_Shake shake2;
+ /* Hash objects for SHAKE or SHA2. */
+ union {
+ struct {
+ /* Primary SHAKE-256 object. */
+ wc_Shake shake;
+ /* Secondary SHAKE-256 object (T_l streaming). */
+ wc_Shake shake2;
+ } shk;
+#ifdef WOLFSSL_SLHDSA_SHA2
+ struct {
+ /* F, PRF (all cats) + H, T_l (cat 1). */
+ wc_Sha256 sha256;
+ /* T_l streaming (cat 1), H_msg scratch. */
+ wc_Sha256 sha256_2;
+ /* H, T_l (cats 3, 5). */
+ wc_Sha512 sha512;
+ /* H_msg streaming (cats 3, 5). */
+ wc_Sha512 sha512_2;
+ /* Pre-computed midstate: PK.seed || pad(64 - n). */
+ wc_Sha256 sha256_mid;
+ /* Pre-computed midstate: PK.seed || pad(128 - n). */
+ wc_Sha512 sha512_mid;
+ } sha2;
+#endif
+ } hash;
} SlhDsaKey;
WOLFSSL_API int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param,
@@ -344,6 +595,15 @@ WOLFSSL_API int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx,
WOLFSSL_API int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, const byte* sig, word32 sigSz);
+/* Internal interface: M' provided directly (no M' construction). */
+WOLFSSL_API int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key,
+ const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz);
+WOLFSSL_API int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key,
+ const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz,
+ const byte* addRnd);
+WOLFSSL_API int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
+ word32 mprimeSz, const byte* sig, word32 sigSz);
+
WOLFSSL_API int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key,
const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz,
enum wc_HashType hashType, byte* sig, word32* sigSz);