mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 17:10:49 +02:00
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:
@@ -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`
|
||||
|
||||
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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), \
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user