Merge pull request #10450 from Frauschi/slhdsa_pre_hash

HashSLH-DSA APIs take the pre-hashed digest, not the raw message
This commit is contained in:
Daniel Pouzzner
2026-05-11 16:29:32 -05:00
committed by GitHub
8 changed files with 619 additions and 204 deletions
+16
View File
@@ -2,6 +2,22 @@
## Enhancements
* **BREAKING (FIPS 205 SLH-DSA)**: `wc_SlhDsaKey_SignHash`,
`wc_SlhDsaKey_SignHashDeterministic`, `wc_SlhDsaKey_SignHashWithRandom`, and
`wc_SlhDsaKey_VerifyHash` now take the **caller-pre-hashed message digest**
via `hash`/`hashSz` parameters (renamed from `msg`/`msgSz`), aligned with
ML-DSA's `wc_dilithium_sign_ctx_hash` / `wc_dilithium_verify_ctx_hash`
semantics, and NIST ACVP `signatureInterface=external` / `preHash=preHash`
test vectors. `hashSz` must equal `wc_HashGetDigestSize(hashType)` (32 bytes
for SHAKE128, 64 bytes for SHAKE256 per FIPS 205 Section 10.2.2); otherwise
`BAD_LENGTH_E` is returned. Migration: hash the message yourself before the
call (callers using positional arguments are source-compatible; only the
parameter names changed). The pre-existing `wc_SlhDsaKey_SignMsgDeterministic`
and `wc_SlhDsaKey_SignMsgWithRandom` (FIPS 205 internal interface, M'
supplied directly) are unaffected and gain stricter input validation
matching the `*Hash*` family. `wc_SlhDsaKey_VerifyMsg` is unchanged. All
three gain doxygen coverage.
* TLS 1.3: zero traffic key staging buffers in `SetKeysSide()` once a
CryptoCB callback has imported the AES key into a Secure Element
(`aes->devCtx != NULL`). Clears `keys->{client,server}_write_key`
+86 -42
View File
@@ -302,15 +302,19 @@ int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx,
\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.
the caller — no 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'.
Use this when the ACVP signatureInterface=internal test framework or a
protocol layer has already constructed M'. For HashSLH-DSA the caller
builds M' as 0x01 || ctxSz || ctx || OID(hashType) || PHM and passes it
in here, where PHM is the hash of the application message under hashType.
\return 0 on success.
\return BAD_FUNC_ARG if key, mprime, sig, or sigSz is NULL.
\return BAD_LENGTH_E if sigSz is less than the parameter set's signature
length.
\return MISSING_KEY if the private key has not been set.
\param [in] key Pointer to a private SlhDsaKey.
\param [in] mprime Pointer to the pre-constructed M' message.
@@ -334,6 +338,7 @@ int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx,
\sa wc_SlhDsaKey_SignMsgWithRandom
\sa wc_SlhDsaKey_VerifyMsg
\sa wc_SlhDsaKey_SignDeterministic
\sa wc_SlhDsaKey_SignHashDeterministic
*/
int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key,
const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz);
@@ -344,10 +349,14 @@ int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key,
\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.
explicit opt_rand value. See wc_SlhDsaKey_SignMsgDeterministic for the M'
layout used by HashSLH-DSA.
\return 0 on success.
\return BAD_FUNC_ARG if key, mprime, sig, sigSz, or addRnd is NULL.
\return BAD_LENGTH_E if sigSz is less than the parameter set's signature
length.
\return MISSING_KEY if the private key has not been set.
\param [in] key Pointer to a private SlhDsaKey.
\param [in] mprime Pointer to the pre-constructed M' message.
@@ -373,6 +382,7 @@ int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key,
\sa wc_SlhDsaKey_SignMsgDeterministic
\sa wc_SlhDsaKey_VerifyMsg
\sa wc_SlhDsaKey_SignHashWithRandom
*/
int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key,
const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz,
@@ -412,6 +422,7 @@ int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key,
\sa wc_SlhDsaKey_SignMsgDeterministic
\sa wc_SlhDsaKey_Verify
\sa wc_SlhDsaKey_VerifyHash
*/
int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
word32 mprimeSz, const byte* sig, word32 sigSz);
@@ -419,22 +430,28 @@ int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
/*!
\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).
\brief Signs a caller-pre-hashed message digest using the SLH-DSA external
(HashSLH-DSA) interface with deterministic randomness, per FIPS 205
Algorithm 23 with the pre-hash domain separator (0x01). The caller must
hash the application message with hashType first and pass the digest as
hash; this function does NOT hash its input.
\return 0 on success.
\return BAD_FUNC_ARG if key, msg, sig, or sigSz is NULL, or hashType
is unsupported.
\return BAD_FUNC_ARG if key, hash, sig, or sigSz is NULL.
\return BAD_LENGTH_E if hashSz does not equal the digest size for hashType
(32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
\return NOT_COMPILED_IN if hashType is not supported in this build.
\return MISSING_KEY if the private key has not been set.
\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,
\param [in] hash Pointer to the pre-hashed message digest. hashSz must
equal the digest size for hashType.
\param [in] hashSz Length of the digest in bytes.
\param [in] hashType Hash algorithm used for pre-hashing (selects OID).
Supported: WC_HASH_TYPE_SHA224, WC_HASH_TYPE_SHA256, WC_HASH_TYPE_SHA384,
WC_HASH_TYPE_SHA512, WC_HASH_TYPE_SHA512_224, WC_HASH_TYPE_SHA512_256,
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.
@@ -447,35 +464,44 @@ int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
byte sig[WC_SLHDSA_MAX_SIG_LEN];
word32 sigSz = sizeof(sig);
byte msg[] = "Hello World!";
byte digest[WC_SHA256_DIGEST_SIZE];
int ret;
wc_Sha256Hash(msg, sizeof(msg), digest);
ret = wc_SlhDsaKey_SignHashDeterministic(&key, NULL, 0,
msg, sizeof(msg), WC_HASH_TYPE_SHA256, sig, &sigSz);
digest, sizeof(digest), WC_HASH_TYPE_SHA256, sig, &sigSz);
\endcode
\sa wc_SlhDsaKey_SignHashWithRandom
\sa wc_SlhDsaKey_SignHash
\sa wc_SlhDsaKey_VerifyHash
\sa wc_SlhDsaKey_SignMsgDeterministic
*/
int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key,
const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz,
const byte* ctx, byte ctxSz, const byte* hash, word32 hashSz,
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.
\brief Signs a caller-pre-hashed message digest using the SLH-DSA external
(HashSLH-DSA) interface with caller-provided additional randomness. The
caller must hash the application message with hashType first and pass the
digest as hash; this function does NOT hash its input.
\return 0 on success.
\return BAD_FUNC_ARG if key, msg, sig, sigSz, or addRnd is NULL.
\return BAD_FUNC_ARG if key, hash, sig, sigSz, or addRnd is NULL.
\return BAD_LENGTH_E if hashSz does not equal the digest size for hashType
(32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
\return NOT_COMPILED_IN if hashType is not supported in this build.
\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 [in] hash Pointer to the pre-hashed message digest. hashSz must
equal the digest size for hashType.
\param [in] hashSz Length of the digest in bytes.
\param [in] hashType Hash algorithm used for pre-hashing (selects OID).
\param [out] sig Buffer to receive the signature.
\param [in,out] sigSz On input, size of sig buffer. On output, actual
signature length.
@@ -483,26 +509,33 @@ int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key,
\sa wc_SlhDsaKey_SignHashDeterministic
\sa wc_SlhDsaKey_VerifyHash
\sa wc_SlhDsaKey_SignMsgWithRandom
*/
int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key,
const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz,
const byte* ctx, byte ctxSz, const byte* hash, word32 hashSz,
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.
\brief Signs a caller-pre-hashed message digest using the SLH-DSA external
(HashSLH-DSA) interface with RNG-provided randomness. The caller must
hash the application message with hashType first and pass the digest as
hash; this function does NOT hash its input.
\return 0 on success.
\return BAD_FUNC_ARG if key, msg, sig, sigSz, or rng is NULL.
\return BAD_FUNC_ARG if key, hash, sig, sigSz, or rng is NULL.
\return BAD_LENGTH_E if hashSz does not equal the digest size for hashType
(32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
\return NOT_COMPILED_IN if hashType is not supported in this build.
\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 [in] hash Pointer to the pre-hashed message digest. hashSz must
equal the digest size for hashType.
\param [in] hashSz Length of the digest in bytes.
\param [in] hashType Hash algorithm used for pre-hashing (selects OID).
\param [out] sig Buffer to receive the signature.
\param [in,out] sigSz On input, size of sig buffer. On output, actual
signature length.
@@ -510,29 +543,37 @@ int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key,
\sa wc_SlhDsaKey_SignHashDeterministic
\sa wc_SlhDsaKey_VerifyHash
\sa wc_SlhDsaKey_SignMsgDeterministic
*/
int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType,
byte ctxSz, const byte* hash, word32 hashSz, 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.
\brief Verifies an SLH-DSA signature using the external HashSLH-DSA
interface (FIPS 205 Algorithm 24). The caller must hash the application
message with hashType first and pass the digest as hash; this function
does NOT hash its input.
\return 0 on success (signature valid).
\return BAD_FUNC_ARG if key, msg, or sig is NULL.
\return BAD_FUNC_ARG if key, hash, or sig is NULL.
\return BAD_LENGTH_E if sigSz does not match the parameter set, or if
hashSz does not equal the digest size for hashType (32 for SHAKE128, 64
for SHAKE256 per FIPS 205 Section 10.2.2).
\return NOT_COMPILED_IN if hashType is not supported in this build.
\return MISSING_KEY if the public key has not been set.
\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] hash Pointer to the pre-hashed message digest. hashSz must
equal the digest size for hashType.
\param [in] hashSz Length of the digest in bytes.
\param [in] hashType Hash algorithm used for pre-hashing (selects OID).
Must match the hash used during signing.
\param [in] sig Pointer to the signature to verify.
\param [in] sigSz Length of the signature.
@@ -542,10 +583,12 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx,
byte sig[...];
word32 sigSz;
byte msg[] = "Hello World!";
byte digest[WC_SHA256_DIGEST_SIZE];
int ret;
wc_Sha256Hash(msg, sizeof(msg), digest);
ret = wc_SlhDsaKey_VerifyHash(&key, NULL, 0,
msg, sizeof(msg), WC_HASH_TYPE_SHA256, sig, sigSz);
digest, sizeof(digest), WC_HASH_TYPE_SHA256, sig, sigSz);
if (ret == 0) {
// signature is valid
}
@@ -553,9 +596,10 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx,
\sa wc_SlhDsaKey_SignHashDeterministic
\sa wc_SlhDsaKey_Verify
\sa wc_SlhDsaKey_VerifyMsg
*/
int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType,
byte ctxSz, const byte* hash, word32 hashSz, enum wc_HashType hashType,
const byte* sig, word32 sigSz);
/*!
+195 -6
View File
@@ -1042,24 +1042,52 @@ int test_wc_slhdsa_sign_hash(void)
expSigLen = TEST_SLHDSA_DEFAULT_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0);
/* Test SignHash NULL parameter handling. */
/* Test SignHash NULL parameter handling. Use 32-byte hash length so the
* NULL check trips before the digest-length check (HashSLH-DSA expects
* SHA-256 digest = 32 bytes). */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignHash(NULL, ctx, sizeof(ctx), hash,
sizeof(hash), WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
32, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), NULL,
sizeof(hash), WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
32, WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
sizeof(hash), WC_HASH_TYPE_SHA256, NULL, &sigLen, &rng),
32, WC_HASH_TYPE_SHA256, NULL, &sigLen, &rng),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
sizeof(hash), WC_HASH_TYPE_SHA256, sig, NULL, &rng),
32, WC_HASH_TYPE_SHA256, sig, NULL, &rng),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash,
sizeof(hash), WC_HASH_TYPE_SHA256, sig, &sigLen, NULL),
32, WC_HASH_TYPE_SHA256, sig, &sigLen, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* HashSLH-DSA must reject digest lengths that don't match hashType. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 31,
WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
WC_NO_ERR_TRACE(BAD_LENGTH_E));
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 33,
WC_HASH_TYPE_SHA256, sig, &sigLen, &rng),
WC_NO_ERR_TRACE(BAD_LENGTH_E));
/* Generate a real signature first so VerifyHash gets to its length check
* rather than failing on signature size. */
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
WC_HASH_TYPE_SHA256, sig, &sigLen, &rng), 0);
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 31,
WC_HASH_TYPE_SHA256, sig, sigLen),
WC_NO_ERR_TRACE(BAD_LENGTH_E));
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 33,
WC_HASH_TYPE_SHA256, sig, sigLen),
WC_NO_ERR_TRACE(BAD_LENGTH_E));
/* Unsupported hashType (FIPS 205 doesn't list WC_HASH_TYPE_NONE) hits
* the default branch of slhdsakey_validate_prehash. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
WC_HASH_TYPE_NONE, sig, &sigLen, &rng),
WC_NO_ERR_TRACE(NOT_COMPILED_IN));
/* Test SignHash with SHA-256. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
@@ -1110,6 +1138,31 @@ int test_wc_slhdsa_sign_hash(void)
WC_HASH_TYPE_SHA256, sig, sigLen), 0);
}
#ifdef WOLFSSL_SHA512
/* SHA-512 round-trip exercises a 64-byte digest path. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 64,
WC_HASH_TYPE_SHA512, sig, &sigLen, &rng), 0);
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 64,
WC_HASH_TYPE_SHA512, sig, sigLen), 0);
/* SHA-512 must also reject the wrong digest length. */
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
WC_HASH_TYPE_SHA512, sig, &sigLen, &rng),
WC_NO_ERR_TRACE(BAD_LENGTH_E));
#endif
#ifdef WOLFSSL_SHAKE256
/* SHAKE256 PHM is fixed at 512 bits per FIPS 205 Section 10.2.2. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 64,
WC_HASH_TYPE_SHAKE256, sig, &sigLen, &rng), 0);
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, ctx, sizeof(ctx), hash, 64,
WC_HASH_TYPE_SHAKE256, sig, sigLen), 0);
ExpectIntEQ(wc_SlhDsaKey_SignHash(&key, ctx, sizeof(ctx), hash, 32,
WC_HASH_TYPE_SHAKE256, sig, &sigLen, &rng),
WC_NO_ERR_TRACE(BAD_LENGTH_E));
#endif
wc_SlhDsaKey_Free(&key);
wc_FreeRng(&rng);
@@ -1118,6 +1171,142 @@ int test_wc_slhdsa_sign_hash(void)
return EXPECT_RESULT();
}
/*
* Test the FIPS 205 internal interface (M' supplied directly) for SLH-DSA.
* Covers wc_SlhDsaKey_SignMsgDeterministic, wc_SlhDsaKey_SignMsgWithRandom,
* and wc_SlhDsaKey_VerifyMsg, plus a HashSLH-DSA equivalence cross-check
* that proves an externally-built M' matches the SignHash/VerifyHash path.
*/
int test_wc_slhdsa_sign_msg(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \
!defined(NO_SHA256)
SlhDsaKey key;
WC_RNG rng;
byte mprime[64];
byte* sig = NULL;
word32 sigLen;
byte addRnd[WC_SLHDSA_MAX_SEED];
sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(sig);
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(mprime, 0xAA, sizeof(mprime));
XMEMSET(addRnd, 0x55, sizeof(addRnd));
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL,
INVALID_DEVID), 0);
ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0);
/* SignMsgDeterministic NULL-arg checks. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(NULL, mprime, sizeof(mprime),
sig, &sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, NULL, sizeof(mprime),
sig, &sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, mprime, sizeof(mprime),
NULL, &sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, mprime, sizeof(mprime),
sig, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* SignMsgDeterministic must reject sigSz smaller than params->sigLen. */
sigLen = 1;
ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, mprime,
sizeof(mprime), sig, &sigLen), WC_NO_ERR_TRACE(BAD_LENGTH_E));
/* Round-trip: Deterministic. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, mprime,
sizeof(mprime), sig, &sigLen), 0);
ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, mprime, sizeof(mprime), sig,
sigLen), 0);
/* SignMsgWithRandom NULL-arg checks. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignMsgWithRandom(NULL, mprime, sizeof(mprime),
sig, &sigLen, addRnd), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_SignMsgWithRandom(&key, mprime, sizeof(mprime),
sig, &sigLen, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* SignMsgWithRandom must reject sigSz smaller than params->sigLen. */
sigLen = 1;
ExpectIntEQ(wc_SlhDsaKey_SignMsgWithRandom(&key, mprime, sizeof(mprime),
sig, &sigLen, addRnd), WC_NO_ERR_TRACE(BAD_LENGTH_E));
/* Round-trip: WithRandom. Reset sigLen explicitly so the test doesn't
* silently rely on the previous call having set it to params->sigLen. */
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignMsgWithRandom(&key, mprime, sizeof(mprime),
sig, &sigLen, addRnd), 0);
ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, mprime, sizeof(mprime), sig,
sigLen), 0);
/* VerifyMsg NULL-arg checks. */
ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(NULL, mprime, sizeof(mprime), sig,
sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, NULL, sizeof(mprime), sig,
sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SlhDsaKey_VerifyMsg(&key, mprime, sizeof(mprime), NULL,
sigLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Equivalence cross-check: build M' = 0x01 || ctxSz || OID(SHA-256) ||
* SHA256(orig) externally, sign it via SignMsgDeterministic, and verify
* via VerifyHash with the same SHA-256 digest. Both paths must agree. */
{
static const byte sha256_oid[] = {
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
0x04, 0x02, 0x01
};
static const byte orig[] = "Hello World!";
byte digest[WC_SHA256_DIGEST_SIZE];
byte built_mprime[2 + sizeof(sha256_oid) + WC_SHA256_DIGEST_SIZE];
word32 idx = 0;
word32 sigLen2;
ExpectIntEQ(wc_Sha256Hash(orig, (word32)sizeof(orig) - 1, digest), 0);
built_mprime[idx++] = 0x01; /* HashSLH-DSA domain separator */
built_mprime[idx++] = 0; /* ctxSz = 0 */
XMEMCPY(built_mprime + idx, sha256_oid, sizeof(sha256_oid));
idx += (word32)sizeof(sha256_oid);
XMEMCPY(built_mprime + idx, digest, sizeof(digest));
idx += (word32)sizeof(digest);
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ExpectIntEQ(wc_SlhDsaKey_SignMsgDeterministic(&key, built_mprime,
idx, sig, &sigLen), 0);
/* The same signature must verify via the HashSLH-DSA external API. */
ExpectIntEQ(wc_SlhDsaKey_VerifyHash(&key, NULL, 0, digest,
sizeof(digest), WC_HASH_TYPE_SHA256, sig, sigLen), 0);
/* And the deterministic HashSLH-DSA path must produce the SAME
* signature bytes (this is the strongest interop check). */
sigLen2 = WC_SLHDSA_MAX_SIG_LEN;
{
byte* sig2 = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(sig2);
ExpectIntEQ(wc_SlhDsaKey_SignHashDeterministic(&key, NULL, 0,
digest, sizeof(digest), WC_HASH_TYPE_SHA256, sig2,
&sigLen2), 0);
ExpectIntEQ(sigLen2, sigLen);
ExpectIntEQ(XMEMCMP(sig2, sig, sigLen), 0);
XFREE(sig2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
wc_SlhDsaKey_Free(&key);
wc_FreeRng(&rng);
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
}
/*
* Test export and import for SLH-DSA keys.
*/
+2
View File
@@ -31,6 +31,7 @@ int test_wc_slhdsa_sign(void);
int test_wc_slhdsa_verify(void);
int test_wc_slhdsa_sign_vfy(void);
int test_wc_slhdsa_sign_hash(void);
int test_wc_slhdsa_sign_msg(void);
int test_wc_slhdsa_export_import(void);
int test_wc_slhdsa_check_key(void);
int test_wc_slhdsa_der_roundtrip(void);
@@ -48,6 +49,7 @@ int test_wc_slhdsa_decoder_disabled_oid(void);
TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_verify), \
TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_sign_vfy), \
TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_sign_hash), \
TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_sign_msg), \
TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_export_import), \
TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_check_key), \
TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_der_roundtrip), \
+90 -29
View File
@@ -12737,41 +12737,102 @@ void bench_slhdsa(int param)
);
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);
#ifndef NO_SHA256
/* Pre-hash interface: hash message ONCE outside the timed loop (the
* bench measures sign/verify, not the application-side hash), then sign
* and verify the digest. SHA-256 path: only built when SHA-256 is
* available; HashSLH-DSA still works at runtime with any hashType the
* build supports, but the bench needs a compile-time choice. */
{
byte digest[WC_SHA256_DIGEST_SIZE];
bench_stats_start(&count, &start);
do {
ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg,
(word32)sizeof(msg), WC_HASH_TYPE_SHA256, sig, sigLen);
ret = wc_Sha256Hash(msg, (word32)sizeof(msg), digest);
if (ret != 0) {
goto exit;
}
count++;
RECORD_MULTI_VALUE_STATS();
} while (bench_stats_check(start)
PRIVATE_KEY_UNLOCK();
bench_stats_start(&count, &start);
do {
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ret = wc_SlhDsaKey_SignHashDeterministic(key, ctx, 0, digest,
(word32)sizeof(digest), 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
|| runs < minimum_runs
#endif
);
bench_stats_asym_finish(name, len, "vrfy-pre", 0, count, start, ret);
);
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, digest,
(word32)sizeof(digest), 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);
}
#elif defined(WOLFSSL_SHAKE256)
/* SHAKE-only build (NO_SHA256): use SHAKE256 prehash bench instead. */
{
byte digest[WC_SHA3_512_DIGEST_SIZE];
ret = wc_Shake256Hash(msg, (word32)sizeof(msg), digest,
WC_SHA3_512_DIGEST_SIZE);
if (ret != 0) {
goto exit;
}
PRIVATE_KEY_UNLOCK();
bench_stats_start(&count, &start);
do {
sigLen = WC_SLHDSA_MAX_SIG_LEN;
ret = wc_SlhDsaKey_SignHashDeterministic(key, ctx, 0, digest,
(word32)sizeof(digest), WC_HASH_TYPE_SHAKE256, 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, digest,
(word32)sizeof(digest), WC_HASH_TYPE_SHAKE256, 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);
}
#endif /* NO_SHA256 / WOLFSSL_SHAKE256 */
exit:
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
+181 -108
View File
@@ -7266,9 +7266,11 @@ int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz,
return ret;
}
/* Sign using internal interface -- M' provided directly (deterministic).
/* Sign using the FIPS 205 internal interface (Algorithm 19) -- M' provided
* directly by the caller, deterministic variant (opt_rand = PK.seed).
*
* opt_rand = PK.seed for the deterministic variant.
* Used for HashSLH-DSA implementations that build M' externally and for ACVP
* signatureInterface=internal test vectors.
*
* @param [in] key SLH-DSA key.
* @param [in] mprime M' message (already in internal format).
@@ -7276,16 +7278,29 @@ int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz,
* @param [out] sig Buffer to hold signature.
* @param [in, out] sigSz On in, buffer length. On out, signature length.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, key's parameters, mprime, sig or sigSz is
* NULL.
* @return BAD_LENGTH_E when sigSz is less than required signature length.
* @return MISSING_KEY when private key not set.
* @return MEMORY_E on dynamic memory allocation failure.
* @return SHAKE-256 error return code on digest failure.
*/
int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, const byte* mprime,
word32 mprimeSz, byte* sig, word32* sigSz)
{
int ret;
int ret = 0;
if ((key == NULL) || (key->params == NULL)) {
if ((key == NULL) || (key->params == NULL) || (mprime == NULL) ||
(sig == NULL) || (sigSz == NULL)) {
ret = BAD_FUNC_ARG;
}
else {
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) {
ret = slhdsakey_sign_internal_msg(key, mprime, mprimeSz, sig, sigSz,
key->sk + 2 * key->params->n);
}
@@ -7293,7 +7308,11 @@ int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, const byte* mprime,
return ret;
}
/* Sign using internal interface -- M' provided directly (with explicit random).
/* Sign using the FIPS 205 internal interface (Algorithm 19) -- M' provided
* directly by the caller, with explicit randomness.
*
* Used for HashSLH-DSA implementations that build M' externally and for ACVP
* signatureInterface=internal test vectors.
*
* @param [in] key SLH-DSA key.
* @param [in] mprime M' message (already in internal format).
@@ -7302,12 +7321,34 @@ int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, const byte* mprime,
* @param [in, out] sigSz On in, buffer length. On out, signature length.
* @param [in] addRnd opt_rand value.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, key's parameters, mprime, sig, sigSz or
* addRnd is NULL.
* @return BAD_LENGTH_E when sigSz is less than required signature length.
* @return MISSING_KEY when private key not set.
* @return MEMORY_E on dynamic memory allocation failure.
* @return SHAKE-256 error return code on digest failure.
*/
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);
int ret = 0;
if ((key == NULL) || (key->params == NULL) || (mprime == 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) {
ret = slhdsakey_sign_internal_msg(key, mprime, mprimeSz, sig, sigSz,
addRnd);
}
return ret;
}
#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */
@@ -7538,6 +7579,16 @@ int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
return ret;
}
/* All HashSLH-DSA hash OIDs are DER-encoded as tag(0x06) + length(0x09) + 9
* bytes, so any approved hash OID is exactly 11 bytes. The PRF_msg / H_msg
* input for the SHA-2 path is the concatenation OID || PHM, bounded by
* SLHDSA_OID_MAX_LEN + WC_MAX_DIGEST_SIZE. WC_MAX_DIGEST_SIZE is the project-
* wide max digest size (>= 64 today) and absorbs any future hash with a
* larger digest as long as slhdsakey_validate_prehash continues to enforce
* hashSz <= WC_MAX_DIGEST_SIZE. */
#define SLHDSA_OID_MAX_LEN 11
#define SLHDSA_PHMSG_MAX_LEN (SLHDSA_OID_MAX_LEN + WC_MAX_DIGEST_SIZE)
#ifdef WOLFSSL_SHA224
/* OID for SHA-224 for hash signing/verification. */
static const byte slhdsakey_oid_sha224[] = {
@@ -7613,70 +7664,73 @@ static const byte slhdsakey_oid_sha3_512[] = {
#endif
#endif
/* Pre-hash the message with the hash specified.
/* Validate the caller-supplied pre-hashed digest length and look up the
* corresponding OID for the chosen hash algorithm.
*
* @param [in] msg Message to hash.
* @param [in] msgSz Length of message in bytes.
* @param [in] hashType Hash algorithm.
* @param [out] ph Prehash buffer.
* @param [out] phLen Length of prehash data.
* The HashSLH-DSA family takes the digest as input rather than the full
* message. This mirrors the wc_dilithium_*_ctx_hash interface and matches the
* convention used by NIST ACVP signatureInterface=external / preHash test
* vectors and other libraries (OpenSSL HASH-ML-DSA, leancrypto SLH-DSA,
* mldsa-native pre_hash_internal). The expected digest length is fixed by
* FIPS 205 Section 10.2.2 and equals wc_HashGetDigestSize(hashType) for the
* fixed-output hashes; for SHAKE128/256 the standard fixes the XOF output to
* 256/512 bits respectively. Callers feed the caller-supplied digest buffer
* directly into the M' construction -- there is no copy.
*
* @param [in] hashSz Length of the caller-supplied digest in bytes.
* @param [in] hashType Hash algorithm identifier (selects OID and length).
* @param [out] oid OID data for hash algorithm.
* @param [out] oidLen Length of OID data for hash algorithm.
* @return 0 on success.
* @return BAD_LENGTH_E when hashSz does not equal the expected digest size.
* @return NOT_COMPILED_IN when hash algorithm not supported.
*/
static int slhdsakey_prehash_msg(const byte* msg, word32 msgSz,
enum wc_HashType hashType, byte* ph, byte* phLen, const byte** oid,
byte* oidLen)
static int slhdsakey_validate_prehash(word32 hashSz,
enum wc_HashType hashType, const byte** oid, byte* oidLen)
{
int ret;
int ret = 0;
word32 expectedLen = 0;
switch ((int)hashType) {
#ifdef WOLFSSL_SHA224
case WC_HASH_TYPE_SHA224:
*oid = slhdsakey_oid_sha224;
*oidLen = (byte)sizeof(slhdsakey_oid_sha224);
*phLen = WC_SHA224_DIGEST_SIZE;
ret = wc_Sha224Hash(msg, msgSz, ph);
expectedLen = WC_SHA224_DIGEST_SIZE;
break;
#endif
#ifndef NO_SHA256
case WC_HASH_TYPE_SHA256:
*oid = slhdsakey_oid_sha256;
*oidLen = (byte)sizeof(slhdsakey_oid_sha256);
*phLen = WC_SHA256_DIGEST_SIZE;
ret = wc_Sha256Hash(msg, msgSz, ph);
expectedLen = WC_SHA256_DIGEST_SIZE;
break;
#endif
#ifdef WOLFSSL_SHA384
case WC_HASH_TYPE_SHA384:
*oid = slhdsakey_oid_sha384;
*oidLen = (byte)sizeof(slhdsakey_oid_sha384);
*phLen = WC_SHA384_DIGEST_SIZE;
ret = wc_Sha384Hash(msg, msgSz, ph);
expectedLen = WC_SHA384_DIGEST_SIZE;
break;
#endif
#ifdef WOLFSSL_SHA512
case WC_HASH_TYPE_SHA512:
*oid = slhdsakey_oid_sha512;
*oidLen = (byte)sizeof(slhdsakey_oid_sha512);
*phLen = WC_SHA512_DIGEST_SIZE;
ret = wc_Sha512Hash(msg, msgSz, ph);
expectedLen = WC_SHA512_DIGEST_SIZE;
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
*oid = slhdsakey_oid_sha512_224;
*oidLen = (byte)sizeof(slhdsakey_oid_sha512_224);
*phLen = WC_SHA512_224_DIGEST_SIZE;
ret = wc_Sha512_224Hash(msg, msgSz, ph);
expectedLen = WC_SHA512_224_DIGEST_SIZE;
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
*oid = slhdsakey_oid_sha512_256;
*oidLen = (byte)sizeof(slhdsakey_oid_sha512_256);
*phLen = WC_SHA512_256_DIGEST_SIZE;
ret = wc_Sha512_256Hash(msg, msgSz, ph);
expectedLen = WC_SHA512_256_DIGEST_SIZE;
break;
#endif
#endif
@@ -7684,16 +7738,16 @@ static int slhdsakey_prehash_msg(const byte* msg, word32 msgSz,
case WC_HASH_TYPE_SHAKE128:
*oid = slhdsakey_oid_shake128;
*oidLen = (byte)sizeof(slhdsakey_oid_shake128);
*phLen = WC_SHA3_256_DIGEST_SIZE;
ret = wc_Shake128Hash(msg, msgSz, ph, WC_SHA3_256_DIGEST_SIZE);
/* FIPS 205 Section 10.2.2 fixes SHAKE128 PHM length at 256 bits. */
expectedLen = WC_SHA3_256_DIGEST_SIZE;
break;
#endif
#ifdef WOLFSSL_SHAKE256
case WC_HASH_TYPE_SHAKE256:
*oid = slhdsakey_oid_shake256;
*oidLen = (byte)sizeof(slhdsakey_oid_shake256);
*phLen = WC_SHA3_512_DIGEST_SIZE;
ret = wc_Shake256Hash(msg, msgSz, ph, WC_SHA3_512_DIGEST_SIZE);
/* FIPS 205 Section 10.2.2 fixes SHAKE256 PHM length at 512 bits. */
expectedLen = WC_SHA3_512_DIGEST_SIZE;
break;
#endif
#ifdef WOLFSSL_SHA3
@@ -7701,32 +7755,28 @@ static int slhdsakey_prehash_msg(const byte* msg, word32 msgSz,
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);
expectedLen = WC_SHA3_224_DIGEST_SIZE;
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);
expectedLen = WC_SHA3_256_DIGEST_SIZE;
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);
expectedLen = WC_SHA3_384_DIGEST_SIZE;
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);
expectedLen = WC_SHA3_512_DIGEST_SIZE;
break;
#endif
#endif
@@ -7735,6 +7785,10 @@ static int slhdsakey_prehash_msg(const byte* msg, word32 msgSz,
break;
}
if ((ret == 0) && (hashSz != expectedLen)) {
ret = BAD_LENGTH_E;
}
return ret;
}
@@ -7790,37 +7844,40 @@ static int slhdsakey_prehash_msg(const byte* msg, word32 msgSz,
*
* Note: ctx length is of type byte which means it can never be more than 255.
*
* The caller MUST pre-hash the application message with hashType before
* calling and pass the digest as hash. hashSz must equal the digest size of
* hashType (32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
*
* @param [in] key SLH-DSA key.
* @param [in] ctx Context of signing.
* @param [in] ctxSz Length of context in bytes.
* @param [in] msg Message to sign.
* @param [in] msgSz Length of message in bytes.
* @param [in] hashType Hash algorithm to use in pre-hash.
* @param [in] hash Pre-hashed message digest to sign.
* @param [in] hashSz Length of digest in bytes.
* @param [in] hashType Hash algorithm used for pre-hash (selects OID).
* @param [out] sig Buffer to hold signature.
* @param [in, out] sigSz On in, length of signature buffer.
* On out, length of signature data.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, key's parameters, msg, sig, sigSz or addRnd
* @return BAD_FUNC_ARG when key, key's parameters, hash, sig, sigSz or addRnd
* is NULL.
* @return BAD_FUNC_ARG when ctx is NULL but ctx length is greater than 0.
* @return BAD_LENGTH_E when sigSz is less than required signature length.
* @return BAD_LENGTH_E when sigSz is less than required signature length, or
* when hashSz does not equal the digest size for hashType.
* @return NOT_COMPILED in when hash algorithm is not supported.
* @return MEMORY_E on dynamic memory allocation failure.
* @return SHAKE-256 error return code on digest failure.
*/
static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType,
byte ctxSz, const byte* hash, word32 hashSz, enum wc_HashType hashType,
byte* sig, word32* sigSz, byte* addRnd)
{
int ret = 0;
byte ph[WC_MAX_DIGEST_SIZE];
byte phLen = 0;
const byte* oid = NULL;
byte oidLen = 0;
/* Validate parameters. */
if ((key == NULL) || (key->params == NULL) ||
((ctx == NULL) && (ctxSz > 0)) || (msg == NULL) || (sig == NULL) ||
((ctx == NULL) && (ctxSz > 0)) || (hash == NULL) || (sig == NULL) ||
(sigSz == NULL)) {
ret = BAD_FUNC_ARG;
}
@@ -7834,10 +7891,9 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx,
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
/* Alg 23, Steps 8-23: Pre-hash message with hash algorithm specified.
*/
ret = slhdsakey_prehash_msg(msg, msgSz, hashType, ph, &phLen, &oid,
&oidLen);
/* Alg 23, Steps 8-23: Validate caller-supplied pre-hashed digest length
* and select OID for the chosen hash algorithm. */
ret = slhdsakey_validate_prehash(hashSz, hashType, &oid, &oidLen);
}
if (ret == 0) {
byte n = key->params->n;
@@ -7850,12 +7906,12 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx,
#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 = (word32)oidLen + phLen;
/* SHA2: Build oid||hash as message for PRF_msg/H_msg. */
byte phMsg[SLHDSA_PHMSG_MAX_LEN];
word32 phMsgLen = (word32)oidLen + hashSz;
XMEMCPY(phMsg, oid, oidLen);
XMEMCPY(phMsg + oidLen, ph, phLen);
XMEMCPY(phMsg + oidLen, hash, hashSz);
ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, hdr, ctx,
ctxSz, phMsg, phMsgLen, n, sig);
@@ -7885,7 +7941,7 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx,
ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen);
}
if (ret == 0) {
ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen);
ret = slhdsakey_hash_update(&key->hash.shk.shake, hash, hashSz);
}
if (ret == 0) {
ret = slhdsakey_hash_final(&key->hash.shk.shake, sig, n);
@@ -7910,7 +7966,7 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx,
ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen);
}
if (ret == 0) {
ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen);
ret = slhdsakey_hash_update(&key->hash.shk.shake, hash, hashSz);
}
if (ret == 0) {
ret = slhdsakey_hash_final(&key->hash.shk.shake, md,
@@ -7931,29 +7987,33 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx,
return ret;
}
/* Generate a deterministic pre-hash SLH-DSA signature.
/* Generate a deterministic HashSLH-DSA signature.
*
* addrnd is the public key seed.
* addrnd is the public key seed. The caller MUST pre-hash the application
* message with hashType before calling and pass the digest as hash; hashSz
* must equal the digest size of hashType (32 for SHAKE128, 64 for SHAKE256
* per FIPS 205 Section 10.2.2).
*
* @param [in] key SLH-DSA key.
* @param [in] ctx Context of signing.
* @param [in] ctxSz Length of context in bytes.
* @param [in] msg Message to sign.
* @param [in] msgSz Length of message in bytes.
* @param [in] hashType Hash algorithm to use in pre-hash.
* @param [in] hash Pre-hashed message digest to sign.
* @param [in] hashSz Length of digest in bytes.
* @param [in] hashType Hash algorithm used for pre-hash (selects OID).
* @param [out] sig Buffer to hold signature.
* @param [in, out] sigSz On in, length of signature buffer.
* On out, length of signature data.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, key's parameters, msg, sig or sigSz is NULL.
* @return BAD_FUNC_ARG when key, key's parameters, hash, sig or sigSz is NULL.
* @return BAD_FUNC_ARG when ctx is NULL but ctx length is greater than 0.
* @return BAD_LENGTH_E when sigSz is less than required signature length.
* @return BAD_LENGTH_E when sigSz is less than required signature length, or
* when hashSz does not equal the digest size for hashType.
* @return MISSING_KEY when private key not set.
* @return MEMORY_E on dynamic memory allocation failure.
* @return SHAKE-256 error return code on digest failure.
*/
int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType,
byte ctxSz, const byte* hash, word32 hashSz, enum wc_HashType hashType,
byte* sig, word32* sigSz)
{
int ret;
@@ -7967,68 +8027,79 @@ int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key, const byte* ctx,
ret = MISSING_KEY;
}
else {
/* Pre-hash sign. */
ret = slhdsakey_signhash_external(key, ctx, ctxSz, msg, msgSz, hashType,
sig, sigSz, key->sk + 2 * key->params->n);
/* HashSLH-DSA sign with caller-supplied digest. */
ret = slhdsakey_signhash_external(key, ctx, ctxSz, hash, hashSz,
hashType, sig, sigSz, key->sk + 2 * key->params->n);
}
return ret;
}
/* Generate a pre-hash SLH-DSA signature.
/* Generate a HashSLH-DSA signature with explicit randomness.
*
* The caller MUST pre-hash the application message with hashType before
* calling and pass the digest as hash; hashSz must equal the digest size of
* hashType (32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
*
* @param [in] key SLH-DSA key.
* @param [in] ctx Context of signing.
* @param [in] ctxSz Length of context in bytes.
* @param [in] msg Message to sign.
* @param [in] msgSz Length of message in bytes.
* @param [in] hashType Hash algorithm to use in pre-hash.
* @param [in] hash Pre-hashed message digest to sign.
* @param [in] hashSz Length of digest in bytes.
* @param [in] hashType Hash algorithm used for pre-hash (selects OID).
* @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 Additional random for signature.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, key's parameters, msg, sig, sigSz or addrnd
* @return BAD_FUNC_ARG when key, key's parameters, hash, sig, sigSz or addrnd
* is NULL.
* @return BAD_FUNC_ARG when ctx is NULL but ctx length is greater than 0.
* @return BAD_LENGTH_E when sigSz is less than required signature length.
* @return BAD_LENGTH_E when sigSz is less than required signature length, or
* when hashSz does not equal the digest size for hashType.
* @return MISSING_KEY when private key not set.
* @return NOT_COMPILED in when hash algorithm is not supported.
* @return MEMORY_E on dynamic memory allocation failure.
* @return SHAKE-256 error return code on digest failure.
*/
int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key, const byte* ctx, byte ctxSz,
const byte* msg, word32 msgSz, enum wc_HashType hashType, byte* sig,
const byte* hash, word32 hashSz, enum wc_HashType hashType, byte* sig,
word32* sigSz, byte* addRnd)
{
/* Pre-hash sign */
return slhdsakey_signhash_external(key, ctx, ctxSz, msg, msgSz, hashType,
/* HashSLH-DSA sign with caller-supplied digest. */
return slhdsakey_signhash_external(key, ctx, ctxSz, hash, hashSz, hashType,
sig, sigSz, addRnd);
}
/* Generate a pre-hash SLH-DSA signature with a random number generator.
/* Generate a HashSLH-DSA signature using an RNG for added randomness.
*
* The caller MUST pre-hash the application message with hashType before
* calling and pass the digest as hash; hashSz must equal the digest size of
* hashType (32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
*
* @param [in] key SLH-DSA key.
* @param [in] ctx Context of signing.
* @param [in] ctxSz Length of context in bytes.
* @param [in] msg Message to sign.
* @param [in] msgSz Length of message in bytes.
* @param [in] hashType Hash algorithm to use in pre-hash.
* @param [in] hash Pre-hashed message digest to sign.
* @param [in] hashSz Length of digest in bytes.
* @param [in] hashType Hash algorithm used for pre-hash (selects OID).
* @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] rng Random number generator.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, key's parameters, msg, sig, sigSz or rng is
* @return BAD_FUNC_ARG when key, key's parameters, hash, sig, sigSz or rng is
* NULL.
* @return BAD_FUNC_ARG when ctx is NULL but ctx length is greater than 0.
* @return BAD_LENGTH_E when hashSz does not equal the digest size for
* hashType.
* @return MISSING_KEY when private key not set.
* @return NOT_COMPILED in when hash algorithm is not supported.
* @return MEMORY_E on dynamic memory allocation failure.
* @return SHAKE-256 error return code on digest failure.
*/
int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
const byte* msg, word32 msgSz, enum wc_HashType hashType, byte* sig,
const byte* hash, word32 hashSz, enum wc_HashType hashType, byte* sig,
word32* sigSz, WC_RNG* rng)
{
int ret = 0;
@@ -8036,7 +8107,7 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
/* Validate parameters before generating random. */
if ((key == NULL) || (key->params == NULL) ||
((ctx == NULL) && (ctxSz > 0)) || (msg == NULL) || (sig == NULL) ||
((ctx == NULL) && (ctxSz > 0)) || (hash == NULL) || (sig == NULL) ||
(sigSz == NULL) || (rng == NULL)) {
ret = BAD_FUNC_ARG;
}
@@ -8053,8 +8124,8 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
ret = wc_RNG_GenerateBlock(rng, addRnd, key->params->n);
}
if (ret == 0) {
/* Pre-hash sign. */
ret = wc_SlhDsaKey_SignHashWithRandom(key, ctx, ctxSz, msg, msgSz,
/* HashSLH-DSA sign with caller-supplied digest. */
ret = wc_SlhDsaKey_SignHashWithRandom(key, ctx, ctxSz, hash, hashSz,
hashType, sig, sigSz, addRnd);
}
@@ -8106,36 +8177,39 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
* 20: M' <- toByte(1, 1) || toByte(|ctx|, 1) || ctx || OID || PHM
* 21: return slh_verify_internal(M', SIG, PK)
*
* The caller MUST pre-hash the application message with hashType before
* calling and pass the digest as hash; hashSz must equal the digest size of
* hashType (32 for SHAKE128, 64 for SHAKE256 per FIPS 205 Section 10.2.2).
*
* @param [in] key SLH-DSA key.
* @param [in] ctx Context of signing.
* @param [in] ctxSz Length of context in bytes.
* @param [in] msg Message to sign.
* @param [in] msgSz Length of message in bytes.
* @param [in] hashType Hash algorithm to use in pre-hash.
* @param [in] hash Pre-hashed message digest to verify against.
* @param [in] hashSz Length of digest in bytes.
* @param [in] hashType Hash algorithm used for pre-hash (selects OID).
* @param [in] sig Signature data.
* @param [in] sigSz Length of signature in bytes.
* @return 0 on success.
* @return BAD_FUNC_ARG when key, key's parameters, msg or sig is NULL.
* @return BAD_FUNC_ARG when key, key's parameters, hash or sig is NULL.
* @return BAD_FUNC_ARG when ctx is NULL but ctx length is greater than 0.
* @return BAD_LENGTH_E when signature size does not match parameters.
* @return BAD_LENGTH_E when signature size does not match parameters, or
* when hashSz does not equal the digest size for hashType.
* @return MISSING_KEY when public key not set.
* @return NOT_COMPILED in when hash algorithm is not supported.
* @return MEMORY_E on dynamic memory allocation failure.
* @return SHAKE-256 error return code on digest failure.
*/
int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
const byte* msg, word32 msgSz, enum wc_HashType hashType, const byte* sig,
const byte* hash, word32 hashSz, enum wc_HashType hashType, const byte* sig,
word32 sigSz)
{
int ret = 0;
byte ph[WC_MAX_DIGEST_SIZE];
byte phLen = 0;
const byte* oid = NULL;
byte oidLen = 0;
/* Validate parameters. */
if ((key == NULL) || (key->params == NULL) ||
((ctx == NULL) && (ctxSz > 0)) || (msg == NULL) || (sig == NULL)) {
((ctx == NULL) && (ctxSz > 0)) || (hash == NULL) || (sig == NULL)) {
ret = BAD_FUNC_ARG;
}
/* Alg 20, Step 1: Check signature length is the expect length. */
@@ -8148,10 +8222,9 @@ int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
ret = MISSING_KEY;
}
if (ret == 0) {
/* Alg 24, Steps 4-19: Pre-hash message with hash algorithm specified.
*/
ret = slhdsakey_prehash_msg(msg, msgSz, hashType, ph, &phLen, &oid,
&oidLen);
/* Alg 24, Steps 4-19: Validate caller-supplied pre-hashed digest length
* and select OID for the chosen hash algorithm. */
ret = slhdsakey_validate_prehash(hashSz, hashType, &oid, &oidLen);
}
if (ret == 0) {
byte n = key->params->n;
@@ -8164,12 +8237,12 @@ int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
#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 = (word32)oidLen + phLen;
/* SHA2: Build oid||hash as message for H_msg. */
byte phMsg[SLHDSA_PHMSG_MAX_LEN];
word32 phMsgLen = (word32)oidLen + hashSz;
XMEMCPY(phMsg, oid, oidLen);
XMEMCPY(phMsg + oidLen, ph, phLen);
XMEMCPY(phMsg + oidLen, hash, hashSz);
ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, phMsg,
phMsgLen, md, (word32)key->params->dl1 + key->params->dl2 +
@@ -8195,7 +8268,7 @@ int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz,
ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen);
}
if (ret == 0) {
ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen);
ret = slhdsakey_hash_update(&key->hash.shk.shake, hash, hashSz);
}
if (ret == 0) {
ret = slhdsakey_hash_final(&key->hash.shk.shake, md,
+41 -14
View File
@@ -54542,6 +54542,7 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
/* HashSLH-DSA takes the caller's pre-hashed digest as input. */
{
#ifdef WOLFSSL_SLHDSA_SHA2
enum wc_HashType phType = SLHDSA_IS_SHA2(param) ?
@@ -54549,15 +54550,33 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
#else
enum wc_HashType phType = WC_HASH_TYPE_SHAKE256;
#endif
byte digest[WC_SHA3_512_DIGEST_SIZE];
word32 digestLen;
#ifdef WOLFSSL_SLHDSA_SHA2
if (phType == WC_HASH_TYPE_SHA256) {
ret = wc_Sha256Hash(msg, (word32)sizeof(msg), digest);
digestLen = WC_SHA256_DIGEST_SIZE;
}
else
#endif
{
ret = wc_Shake256Hash(msg, (word32)sizeof(msg), digest,
WC_SHA3_512_DIGEST_SIZE);
digestLen = WC_SHA3_512_DIGEST_SIZE;
}
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
sigLen = WC_SLHDSA_MAX_SIG_LEN;
PRIVATE_KEY_UNLOCK();
ret = wc_SlhDsaKey_SignHash(key, ctx, 0, msg, (word32)sizeof(msg),
ret = wc_SlhDsaKey_SignHash(key, ctx, 0, digest, digestLen,
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),
ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, digest, digestLen,
phType, sig, sigLen);
}
if (ret != 0) {
@@ -54566,18 +54585,26 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param)
/* 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_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_SHA384, sig, sigLen);
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
{
byte digest384[WC_SHA384_DIGEST_SIZE];
ret = wc_Sha384Hash(msg, (word32)sizeof(msg), digest384);
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
sigLen = WC_SLHDSA_MAX_SIG_LEN;
PRIVATE_KEY_UNLOCK();
ret = wc_SlhDsaKey_SignHash(key, ctx, 0, digest384, sizeof(digest384),
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, digest384,
sizeof(digest384), WC_HASH_TYPE_SHA384, sig, sigLen);
if (ret != 0) {
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
}
#endif
+8 -5
View File
@@ -666,7 +666,10 @@ WOLFSSL_API int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, const byte* sig, word32 sigSz);
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
/* Internal interface: M' provided directly (no M' construction). */
/* External-M' / FIPS 205 internal interface (Algorithms 19/20): the caller
* supplies the fully-built M'. Use these for HashSLH-DSA implementations that
* construct M' externally, distributed signers that operate on a pre-built
* message representative, and ACVP signatureInterface=internal test groups. */
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,
@@ -678,17 +681,17 @@ WOLFSSL_API int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY
WOLFSSL_API int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key,
const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz,
const byte* ctx, byte ctxSz, const byte* hash, word32 hashSz,
enum wc_HashType hashType, byte* sig, word32* sigSz);
WOLFSSL_API int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key,
const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz,
const byte* ctx, byte ctxSz, const byte* hash, word32 hashSz,
enum wc_HashType hashType, byte* sig, word32* sigSz, byte* addRnd);
WOLFSSL_API int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType,
byte ctxSz, const byte* hash, word32 hashSz, enum wc_HashType hashType,
byte* sig, word32* sigSz, WC_RNG* rng);
#endif /* WOLFSSL_SLHDSA_VERIFY_ONLY */
WOLFSSL_API int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType,
byte ctxSz, const byte* hash, word32 hashSz, enum wc_HashType hashType,
const byte* sig, word32 sigSz);
#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY