Files
wolfssl/doc/dox_comments/header_files/wc_slhdsa.h
T
David Garske dc56e87522 Merge pull request #10466 from Frauschi/slhdsa_cryptocb
Add CryptoCb support for SLH-DSA
2026-05-19 13:59:40 -07:00

1126 lines
39 KiB
C

/*!
\ingroup SLH_DSA
\brief Initializes an SLH-DSA key object with the specified parameter set.
Must be called before any other SLH-DSA operation. Use wc_SlhDsaKey_Free()
to release resources when done.
SLH-DSA (FIPS 205) is a stateless hash-based digital signature algorithm.
Parameter sets control the hash function (SHAKE or SHA2), security level
(128, 192, 256), and speed/size tradeoff (s = small signatures,
f = fast signing).
\return 0 on success.
\return BAD_FUNC_ARG if key is NULL or param is invalid.
\param [in,out] key Pointer to the SlhDsaKey to initialize.
\param [in] param Parameter set to use. One of: SLHDSA_SHAKE128S,
SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, SLHDSA_SHAKE192F, SLHDSA_SHAKE256S,
SLHDSA_SHAKE256F, SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S,
SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F.
\param [in] heap Pointer to heap hint for dynamic memory allocation.
May be NULL.
\param [in] devId Device identifier for hardware crypto callbacks.
Use INVALID_DEVID for software-only.
_Example_
\code
SlhDsaKey key;
int ret;
ret = wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
if (ret != 0) {
// error initializing key
}
// ... use key ...
wc_SlhDsaKey_Free(&key);
\endcode
\sa wc_SlhDsaKey_Free
\sa wc_SlhDsaKey_MakeKey
*/
int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param,
void* heap, int devId);
/*!
\ingroup SLH_DSA
\brief Initializes an SLH-DSA key with a device-side key identifier (id).
Equivalent to wc_SlhDsaKey_Init() but also stashes a binary id that a
crypto callback can use to look up the underlying key material on the
device. Only available when wolfSSL is built with WOLF_PRIVATE_KEY_ID.
The id is copied into the key object; the caller may free its buffer
immediately after this call returns.
\return 0 on success.
\return BAD_FUNC_ARG if key is NULL, or if id is NULL while len > 0.
\return BUFFER_E if len is negative or greater than SLHDSA_MAX_ID_LEN.
\param [in,out] key Pointer to the SlhDsaKey to initialize.
\param [in] param Parameter set to use (see wc_SlhDsaKey_Init).
\param [in] id Pointer to the device-side key identifier bytes. May be
NULL if len is 0.
\param [in] len Number of bytes in id. Must be in [0, SLHDSA_MAX_ID_LEN].
\param [in] heap Pointer to heap hint for dynamic memory allocation.
May be NULL.
\param [in] devId Device identifier for the crypto callback. Should be
a registered cb devId, not INVALID_DEVID, for the id to be meaningful.
_Example_
\code
SlhDsaKey key;
unsigned char id[8] = { 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08 };
int ret;
ret = wc_SlhDsaKey_Init_id(&key, SLHDSA_SHAKE128F, id, sizeof(id),
NULL, devId);
if (ret != 0) {
// error initializing key with id
}
// ... use key, the cb resolves id -> device key ...
wc_SlhDsaKey_Free(&key);
\endcode
\sa wc_SlhDsaKey_Init
\sa wc_SlhDsaKey_Init_label
\sa wc_SlhDsaKey_Free
*/
int wc_SlhDsaKey_Init_id(SlhDsaKey* key, enum SlhDsaParam param,
const unsigned char* id, int len, void* heap, int devId);
/*!
\ingroup SLH_DSA
\brief Initializes an SLH-DSA key with a device-side key label.
Equivalent to wc_SlhDsaKey_Init() but also stashes a label string that
a crypto callback can use to look up the underlying key material on
the device. Only available when wolfSSL is built with
WOLF_PRIVATE_KEY_ID.
The label length is taken via XSTRLEN, so embedded NUL bytes terminate
the label. The copy stored in key->label is NOT guaranteed to be
NUL-terminated (when the input is exactly SLHDSA_MAX_LABEL_LEN bytes
the entire array is consumed). Consumers must read at most
key->labelLen bytes — do not pass key->label to C-string APIs.
\return 0 on success.
\return BAD_FUNC_ARG if key or label is NULL.
\return BUFFER_E if label is empty or longer than SLHDSA_MAX_LABEL_LEN.
\param [in,out] key Pointer to the SlhDsaKey to initialize.
\param [in] param Parameter set to use (see wc_SlhDsaKey_Init).
\param [in] label NUL-terminated device-side key label string.
\param [in] heap Pointer to heap hint for dynamic memory allocation.
May be NULL.
\param [in] devId Device identifier for the crypto callback. Should be
a registered cb devId, not INVALID_DEVID, for the label to be
meaningful.
_Example_
\code
SlhDsaKey key;
int ret;
ret = wc_SlhDsaKey_Init_label(&key, SLHDSA_SHAKE128F,
"device-key-1", NULL, devId);
if (ret != 0) {
// error initializing key with label
}
// ... use key, the cb resolves label -> device key ...
wc_SlhDsaKey_Free(&key);
\endcode
\sa wc_SlhDsaKey_Init
\sa wc_SlhDsaKey_Init_id
\sa wc_SlhDsaKey_Free
*/
int wc_SlhDsaKey_Init_label(SlhDsaKey* key, enum SlhDsaParam param,
const char* label, void* heap, int devId);
/*!
\ingroup SLH_DSA
\brief Frees resources associated with an SLH-DSA key object.
\param [in,out] key Pointer to the SlhDsaKey to free. May be NULL.
_Example_
\code
SlhDsaKey key;
wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
// ... use key ...
wc_SlhDsaKey_Free(&key);
\endcode
\sa wc_SlhDsaKey_Init
*/
void wc_SlhDsaKey_Free(SlhDsaKey* key);
/*!
\ingroup SLH_DSA
\brief Generates a new SLH-DSA key pair using the RNG for randomness.
The key must have been initialized with wc_SlhDsaKey_Init() first.
\return 0 on success.
\return BAD_FUNC_ARG if key or rng is NULL, or key is not initialized.
\param [in,out] key Pointer to an initialized SlhDsaKey.
\param [in] rng Pointer to an initialized WC_RNG.
_Example_
\code
SlhDsaKey key;
WC_RNG rng;
int ret;
wc_InitRng(&rng);
wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
ret = wc_SlhDsaKey_MakeKey(&key, &rng);
if (ret != 0) {
// error generating key
}
\endcode
\sa wc_SlhDsaKey_Init
\sa wc_SlhDsaKey_MakeKeyWithRandom
*/
int wc_SlhDsaKey_MakeKey(SlhDsaKey* key, WC_RNG* rng);
/*!
\ingroup SLH_DSA
\brief Generates an SLH-DSA key pair from caller-provided seed material.
This is the deterministic key generation interface — given the same seeds,
the same key pair is produced.
\return 0 on success.
\return BAD_FUNC_ARG if key or any seed pointer is NULL, or lengths
do not match the parameter set's n value.
\param [in,out] key Pointer to an initialized SlhDsaKey.
\param [in] sk_seed Secret key seed (n bytes).
\param [in] sk_seed_len Length of sk_seed.
\param [in] sk_prf Secret key PRF seed (n bytes).
\param [in] sk_prf_len Length of sk_prf.
\param [in] pk_seed Public key seed (n bytes).
\param [in] pk_seed_len Length of pk_seed.
_Example_
\code
SlhDsaKey key;
byte sk_seed[16], sk_prf[16], pk_seed[16]; // n=16 for 128-bit params
int ret;
// fill seeds with known values (e.g. from NIST test vectors)
wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
ret = wc_SlhDsaKey_MakeKeyWithRandom(&key,
sk_seed, sizeof(sk_seed),
sk_prf, sizeof(sk_prf),
pk_seed, sizeof(pk_seed));
\endcode
\sa wc_SlhDsaKey_MakeKey
*/
int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key,
const byte* sk_seed, word32 sk_seed_len,
const byte* sk_prf, word32 sk_prf_len,
const byte* pk_seed, word32 pk_seed_len);
/*!
\ingroup SLH_DSA
\brief Signs a message using the SLH-DSA external (pure) interface with
deterministic randomness. This is FIPS 205 Algorithm 22 with opt_rand set
to PK.seed. The message M is wrapped internally as
M' = 0x00 || len(ctx) || ctx || M before signing.
\return 0 on success.
\return BAD_FUNC_ARG if key, msg, sig, or sigSz is NULL.
\return BUFFER_E if the output buffer is too small.
\param [in] key Pointer to a private SlhDsaKey.
\param [in] ctx Context string for domain separation. May be NULL if
ctxSz is 0.
\param [in] ctxSz Length of the context string (0-255).
\param [in] msg Pointer to the message to sign.
\param [in] msgSz Length of the message.
\param [out] sig Buffer to receive the signature.
\param [in,out] sigSz On input, size of sig buffer. On output, actual
signature length.
_Example_
\code
SlhDsaKey key;
byte sig[WC_SLHDSA_MAX_SIG_LEN];
word32 sigSz = sizeof(sig);
byte msg[] = "Hello World!";
int ret;
// key already generated via wc_SlhDsaKey_MakeKey()
ret = wc_SlhDsaKey_SignDeterministic(&key, NULL, 0,
msg, sizeof(msg), sig, &sigSz);
\endcode
\sa wc_SlhDsaKey_SignWithRandom
\sa wc_SlhDsaKey_Sign
\sa wc_SlhDsaKey_Verify
*/
int wc_SlhDsaKey_SignDeterministic(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz);
/*!
\ingroup SLH_DSA
\brief Signs a message using the SLH-DSA external (pure) interface with
caller-provided additional randomness. This is FIPS 205 Algorithm 22 with
an explicit opt_rand value.
\return 0 on success.
\return BAD_FUNC_ARG if key, msg, sig, sigSz, or addRnd is NULL.
\param [in] key Pointer to a private SlhDsaKey.
\param [in] ctx Context string. May be NULL if ctxSz is 0.
\param [in] ctxSz Length of the context string (0-255).
\param [in] msg Pointer to the message to sign.
\param [in] msgSz Length of the message.
\param [out] sig Buffer to receive the signature.
\param [in,out] sigSz On input, size of sig buffer. On output, actual
signature length.
\param [in] addRnd Additional randomness (n bytes, where n is the
parameter set's security parameter).
_Example_
\code
SlhDsaKey key;
byte sig[WC_SLHDSA_MAX_SIG_LEN];
word32 sigSz = sizeof(sig);
byte msg[] = "Hello World!";
byte addRnd[16]; // n=16 for 128-bit params
int ret;
wc_RNG_GenerateBlock(&rng, addRnd, sizeof(addRnd));
ret = wc_SlhDsaKey_SignWithRandom(&key, NULL, 0,
msg, sizeof(msg), sig, &sigSz, addRnd);
\endcode
\sa wc_SlhDsaKey_SignDeterministic
\sa wc_SlhDsaKey_Sign
*/
int wc_SlhDsaKey_SignWithRandom(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz,
const byte* addRnd);
/*!
\ingroup SLH_DSA
\brief Signs a message using the SLH-DSA external (pure) interface with
RNG-provided randomness. This is the general-purpose signing function
that uses the WC_RNG for opt_rand.
\return 0 on success.
\return BAD_FUNC_ARG if key, msg, sig, sigSz, or rng is NULL.
\param [in] key Pointer to a private SlhDsaKey.
\param [in] ctx Context string. May be NULL if ctxSz is 0.
\param [in] ctxSz Length of the context string (0-255).
\param [in] msg Pointer to the message to sign.
\param [in] msgSz Length of the message.
\param [out] sig Buffer to receive the signature.
\param [in,out] sigSz On input, size of sig buffer. On output, actual
signature length.
\param [in] rng Pointer to an initialized WC_RNG.
_Example_
\code
SlhDsaKey key;
WC_RNG rng;
byte sig[WC_SLHDSA_MAX_SIG_LEN];
word32 sigSz = sizeof(sig);
byte msg[] = "Hello World!";
int ret;
ret = wc_SlhDsaKey_Sign(&key, NULL, 0,
msg, sizeof(msg), sig, &sigSz, &rng);
\endcode
\sa wc_SlhDsaKey_SignDeterministic
\sa wc_SlhDsaKey_Verify
*/
int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz,
WC_RNG* rng);
/*!
\ingroup SLH_DSA
\brief Verifies an SLH-DSA signature over a message using the external
(pure) interface. This is FIPS 205 Algorithm 24. The message is wrapped
internally as M' = 0x00 || len(ctx) || ctx || M before verification.
\return 0 on success (signature valid).
\return BAD_FUNC_ARG if key, msg, or sig is NULL, or ctx is NULL but
ctxSz is greater than 0.
\return BAD_LENGTH_E if sigSz does not match the parameter set's
signature length.
\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 verify.
\param [in] msgSz Length of the message.
\param [in] sig Pointer to the signature to verify.
\param [in] sigSz Length of the signature.
_Example_
\code
SlhDsaKey key;
byte sig[...]; // previously generated signature
word32 sigSz;
byte msg[] = "Hello World!";
int ret;
ret = wc_SlhDsaKey_Verify(&key, NULL, 0,
msg, sizeof(msg), sig, sigSz);
if (ret == 0) {
// signature is valid
}
\endcode
\sa wc_SlhDsaKey_Sign
\sa wc_SlhDsaKey_SignDeterministic
*/
int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx,
byte ctxSz, const byte* msg, word32 msgSz, const byte* sig,
word32 sigSz);
/*!
\ingroup SLH_DSA
\brief Signs using the SLH-DSA internal interface with deterministic
randomness. Unlike the external interface, M' is provided directly by
the caller — no wrapping is performed. This corresponds to FIPS 205
Algorithm 19 (slh_sign_internal) with opt_rand set to PK.seed.
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.
\param [in] mprimeSz Length of M'.
\param [out] sig Buffer to receive the signature.
\param [in,out] sigSz On input, size of sig buffer. On output, actual
signature length.
_Example_
\code
SlhDsaKey key;
byte sig[WC_SLHDSA_MAX_SIG_LEN];
word32 sigSz = sizeof(sig);
byte mprime[] = { ... }; // pre-constructed M'
int ret;
ret = wc_SlhDsaKey_SignMsgDeterministic(&key,
mprime, sizeof(mprime), sig, &sigSz);
\endcode
\sa wc_SlhDsaKey_SignMsgWithRandom
\sa wc_SlhDsaKey_VerifyMsg
\sa wc_SlhDsaKey_SignDeterministic
\sa wc_SlhDsaKey_SignHashDeterministic
*/
int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key,
const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz);
/*!
\ingroup SLH_DSA
\brief Signs using the SLH-DSA internal interface with caller-provided
additional randomness. M' is provided directly — no wrapping is performed.
This corresponds to FIPS 205 Algorithm 19 (slh_sign_internal) with an
explicit opt_rand value. 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.
\param [in] mprimeSz Length of M'.
\param [out] sig Buffer to receive the signature.
\param [in,out] sigSz On input, size of sig buffer. On output, actual
signature length.
\param [in] addRnd Additional randomness (n bytes).
_Example_
\code
SlhDsaKey key;
byte sig[WC_SLHDSA_MAX_SIG_LEN];
word32 sigSz = sizeof(sig);
byte mprime[] = { ... };
byte addRnd[16];
int ret;
wc_RNG_GenerateBlock(&rng, addRnd, sizeof(addRnd));
ret = wc_SlhDsaKey_SignMsgWithRandom(&key,
mprime, sizeof(mprime), sig, &sigSz, addRnd);
\endcode
\sa wc_SlhDsaKey_SignMsgDeterministic
\sa wc_SlhDsaKey_VerifyMsg
\sa wc_SlhDsaKey_SignHashWithRandom
*/
int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key,
const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz,
const byte* addRnd);
/*!
\ingroup SLH_DSA
\brief Verifies an SLH-DSA signature using the internal interface. M' is
provided directly — no wrapping is performed. This corresponds to FIPS 205
Algorithm 20 (slh_verify_internal).
\return 0 on success (signature valid).
\return BAD_FUNC_ARG if key, mprime, or sig is NULL.
\return BAD_LENGTH_E if sigSz does not match the parameter set's
signature length.
\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] mprime Pointer to the pre-constructed M' message.
\param [in] mprimeSz Length of M'.
\param [in] sig Pointer to the signature to verify.
\param [in] sigSz Length of the signature.
_Example_
\code
SlhDsaKey key;
byte sig[...]; // previously generated signature
word32 sigSz;
byte mprime[] = { ... };
int ret;
ret = wc_SlhDsaKey_VerifyMsg(&key,
mprime, sizeof(mprime), sig, sigSz);
if (ret == 0) {
// signature is valid
}
\endcode
\sa wc_SlhDsaKey_SignMsgDeterministic
\sa wc_SlhDsaKey_Verify
\sa wc_SlhDsaKey_VerifyHash
*/
int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime,
word32 mprimeSz, const byte* sig, word32 sigSz);
/*!
\ingroup SLH_DSA
\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, 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] 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.
\param [in,out] sigSz On input, size of sig buffer. On output, actual
signature length.
_Example_
\code
SlhDsaKey key;
byte sig[WC_SLHDSA_MAX_SIG_LEN];
word32 sigSz = sizeof(sig);
byte msg[] = "Hello World!";
byte digest[WC_SHA256_DIGEST_SIZE];
int ret;
wc_Sha256Hash(msg, sizeof(msg), digest);
ret = wc_SlhDsaKey_SignHashDeterministic(&key, NULL, 0,
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* hash, word32 hashSz,
enum wc_HashType hashType, byte* sig, word32* sigSz);
/*!
\ingroup SLH_DSA
\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, 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] 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.
\param [in] addRnd Additional randomness (n bytes).
\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* hash, word32 hashSz,
enum wc_HashType hashType, byte* sig, word32* sigSz, const byte* addRnd);
/*!
\ingroup SLH_DSA
\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, 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] 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.
\param [in] rng Pointer to an initialized WC_RNG.
\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* hash, word32 hashSz, enum wc_HashType hashType,
byte* sig, word32* sigSz, WC_RNG* rng);
/*!
\ingroup SLH_DSA
\brief Verifies an SLH-DSA signature using the external HashSLH-DSA
interface (FIPS 205 Algorithm 25). 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, 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] 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.
_Example_
\code
SlhDsaKey key;
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,
digest, sizeof(digest), WC_HASH_TYPE_SHA256, sig, sigSz);
if (ret == 0) {
// signature is valid
}
\endcode
\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* hash, word32 hashSz, enum wc_HashType hashType,
const byte* sig, word32 sigSz);
/*!
\ingroup SLH_DSA
\brief Imports an SLH-DSA private key from a raw byte buffer. The buffer
must contain the full private key (4*n bytes: SK.seed || SK.prf ||
PK.seed || PK.root). After import, the key can be used for signing.
\return 0 on success.
\return BAD_FUNC_ARG if key or in is NULL, or inLen does not match the
expected private key size for the parameter set.
\param [in,out] key Pointer to an initialized SlhDsaKey.
\param [in] in Buffer containing the raw private key bytes.
\param [in] inLen Length of the input buffer.
_Example_
\code
SlhDsaKey key;
byte privKey[...]; // 4*n bytes
int ret;
wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
ret = wc_SlhDsaKey_ImportPrivate(&key, privKey, sizeof(privKey));
\endcode
\sa wc_SlhDsaKey_ExportPrivate
\sa wc_SlhDsaKey_ImportPublic
*/
int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* in,
word32 inLen);
/*!
\ingroup SLH_DSA
\brief Imports an SLH-DSA public key from a raw byte buffer. The buffer
must contain PK.seed || PK.root (2*n bytes). After import, the key can
be used for verification.
\return 0 on success.
\return BAD_FUNC_ARG if key or in is NULL, or inLen does not match the
expected public key size.
\param [in,out] key Pointer to an initialized SlhDsaKey.
\param [in] in Buffer containing the raw public key bytes.
\param [in] inLen Length of the input buffer.
_Example_
\code
SlhDsaKey key;
byte pubKey[...]; // 2*n bytes
int ret;
wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID);
ret = wc_SlhDsaKey_ImportPublic(&key, pubKey, sizeof(pubKey));
\endcode
\sa wc_SlhDsaKey_ExportPublic
\sa wc_SlhDsaKey_ImportPrivate
*/
int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* in,
word32 inLen);
/*!
\ingroup SLH_DSA
\brief Checks the consistency of an SLH-DSA key. For a key with both
private and public components, verifies that the public key matches the
private key.
\return 0 on success (key is valid).
\return BAD_FUNC_ARG if key is NULL.
\param [in] key Pointer to the SlhDsaKey to check.
\sa wc_SlhDsaKey_MakeKey
\sa wc_SlhDsaKey_ImportPrivate
*/
int wc_SlhDsaKey_CheckKey(SlhDsaKey* key);
/*!
\ingroup SLH_DSA
\brief Exports the private key from an SLH-DSA key object into a raw
byte buffer (4*n bytes).
\return 0 on success.
\return BAD_FUNC_ARG if key, out, or outLen is NULL.
\return BUFFER_E if the output buffer is too small.
\param [in] key Pointer to the SlhDsaKey containing a private key.
\param [out] out Buffer to receive the raw private key bytes.
\param [in,out] outLen On input, size of out buffer. On output, bytes
written.
_Example_
\code
SlhDsaKey key;
byte privKey[4 * 32]; // 4*n for 256-bit params
word32 privKeySz = sizeof(privKey);
int ret;
ret = wc_SlhDsaKey_ExportPrivate(&key, privKey, &privKeySz);
\endcode
\sa wc_SlhDsaKey_ImportPrivate
\sa wc_SlhDsaKey_ExportPublic
*/
int wc_SlhDsaKey_ExportPrivate(SlhDsaKey* key, byte* out,
word32* outLen);
/*!
\ingroup SLH_DSA
\brief Exports the public key from an SLH-DSA key object into a raw
byte buffer (2*n bytes: PK.seed || PK.root).
\return 0 on success.
\return BAD_FUNC_ARG if key, out, or outLen is NULL.
\return BUFFER_E if the output buffer is too small.
\param [in] key Pointer to the SlhDsaKey containing a public key.
\param [out] out Buffer to receive the raw public key bytes.
\param [in,out] outLen On input, size of out buffer. On output, bytes
written.
_Example_
\code
SlhDsaKey key;
byte pubKey[2 * 32];
word32 pubKeySz = sizeof(pubKey);
int ret;
ret = wc_SlhDsaKey_ExportPublic(&key, pubKey, &pubKeySz);
\endcode
\sa wc_SlhDsaKey_ImportPublic
\sa wc_SlhDsaKey_ExportPrivate
*/
int wc_SlhDsaKey_ExportPublic(SlhDsaKey* key, byte* out,
word32* outLen);
/*!
\ingroup SLH_DSA
\brief Returns the private key size in bytes for the key's parameter set.
\return Private key size in bytes (4*n) on success.
\return BAD_FUNC_ARG if key is NULL or not initialized.
\param [in] key Pointer to an initialized SlhDsaKey.
\sa wc_SlhDsaKey_PublicSize
\sa wc_SlhDsaKey_SigSize
\sa wc_SlhDsaKey_PrivateSizeFromParam
*/
int wc_SlhDsaKey_PrivateSize(SlhDsaKey* key);
/*!
\ingroup SLH_DSA
\brief Returns the public key size in bytes for the key's parameter set.
\return Public key size in bytes (2*n) on success.
\return BAD_FUNC_ARG if key is NULL or not initialized.
\param [in] key Pointer to an initialized SlhDsaKey.
\sa wc_SlhDsaKey_PrivateSize
\sa wc_SlhDsaKey_SigSize
\sa wc_SlhDsaKey_PublicSizeFromParam
*/
int wc_SlhDsaKey_PublicSize(SlhDsaKey* key);
/*!
\ingroup SLH_DSA
\brief Returns the signature size in bytes for the key's parameter set.
\return Signature size in bytes on success.
\return BAD_FUNC_ARG if key is NULL or not initialized.
\param [in] key Pointer to an initialized SlhDsaKey.
\sa wc_SlhDsaKey_PrivateSize
\sa wc_SlhDsaKey_PublicSize
\sa wc_SlhDsaKey_SigSizeFromParam
*/
int wc_SlhDsaKey_SigSize(SlhDsaKey* key);
/*!
\ingroup SLH_DSA
\brief Returns the private key size in bytes for the given parameter set
without needing an initialized key object.
\return Private key size in bytes (4*n) on success.
\return BAD_FUNC_ARG if param is invalid.
\param [in] param The SLH-DSA parameter set.
\sa wc_SlhDsaKey_PrivateSize
*/
int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param);
/*!
\ingroup SLH_DSA
\brief Returns the public key size in bytes for the given parameter set
without needing an initialized key object.
\return Public key size in bytes (2*n) on success.
\return BAD_FUNC_ARG if param is invalid.
\param [in] param The SLH-DSA parameter set.
\sa wc_SlhDsaKey_PublicSize
*/
int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param);
/*!
\ingroup SLH_DSA
\brief Returns the signature size in bytes for the given parameter set
without needing an initialized key object.
\return Signature size in bytes on success.
\return BAD_FUNC_ARG if param is invalid.
\param [in] param The SLH-DSA parameter set.
\sa wc_SlhDsaKey_SigSize
*/
int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param);
/*!
\ingroup SLH_DSA
\brief Decodes a DER-encoded SLH-DSA private key in the PKCS#8
OneAsymmetricKey format defined by RFC 9909. The privateKey OCTET STRING
contains the raw concatenation SK.seed || SK.prf || PK.seed || PK.root
(4*n bytes) directly, without a nested OCTET STRING wrapper as used by
Ed25519/Ed448. The SLH-DSA parameter set is detected from the
AlgorithmIdentifier OID and key->params is updated to match. Available
only when WOLFSSL_SLHDSA_VERIFY_ONLY is not defined.
On a failure that is detected before any write to key->sk
(BAD_FUNC_ARG, header/OID parse errors, or wrong privateKey length), the
key state is left untouched. On a failure detected after
wc_SlhDsaKey_ImportPrivate has populated key->sk (a SHA-2 precompute
error, or a trailing-field validation error), key->sk is scrubbed with
ForceZero and the WC_SLHDSA_FLAG_PRIVATE/PUBLIC flags are cleared so
flags can never claim valid bytes that were zeroed. In both rollback
cases, key->params and inOutIdx are restored to their pre-call values.
\return 0 on success.
\return BAD_FUNC_ARG if input, inOutIdx, or key is NULL, or inSz is 0.
\return ASN_PARSE_E if the DER cannot be parsed as an SLH-DSA private
key (malformed input, wrong key size, or trailing-field violation).
\return NOT_COMPILED_IN if the OID names an SLH-DSA variant that is not
built into this library.
\param [in] input DER-encoded key data.
\param [in,out] inOutIdx On input, starting offset into input. On output,
advanced past the parsed key (unchanged on failure).
\param [in,out] key SLH-DSA key. Parameter set is auto-detected from the
encoded OID.
\param [in] inSz Total size of input in bytes.
\sa wc_SlhDsaKey_KeyToDer
\sa wc_SlhDsaKey_PublicKeyDecode
\sa wc_SlhDsaKey_ImportPrivate
*/
int wc_SlhDsaKey_PrivateKeyDecode(const byte* input, word32* inOutIdx,
SlhDsaKey* key, word32 inSz);
/*!
\ingroup SLH_DSA
\brief Decodes a DER-encoded SLH-DSA public key in the
SubjectPublicKeyInfo (SPKI) format. The SLH-DSA parameter set is
detected from the AlgorithmIdentifier OID and key->params is updated
accordingly.
As a fast path, if key->params is already set the function first hands
the entire window from inOutIdx to inSz to wc_SlhDsaKey_ImportPublic.
ImportPublic's length check is the disambiguator: a window of exactly
2*n bytes is accepted as a raw public key (PK.seed || PK.root) and
consumed in full; any other length is rejected and the function falls
through to SPKI parsing. SPKI input always carries enough
AlgorithmIdentifier/BIT STRING overhead that it never collides with the
2*n raw length, so it falls through cleanly. The caller does not need
to pre-trim the window to 2*n.
On a failure detected before any write (BAD_FUNC_ARG or a malformed
SPKI), the key state is left untouched. On a failure detected after
ImportPublic has populated the public half of key->sk (a SHA-2
precompute error), the public half sk[2*n .. 4*n] is scrubbed and
WC_SLHDSA_FLAG_PUBLIC is cleared from the flags; the private half is
left intact in case the caller imported it earlier. key->params and
inOutIdx are restored to their pre-call values.
\return 0 on success.
\return BAD_FUNC_ARG if input, inOutIdx, or key is NULL, or inSz is 0.
\return ASN_PARSE_E if the DER cannot be parsed as an SLH-DSA public
key.
\return NOT_COMPILED_IN if the OID names an SLH-DSA variant that is not
built into this library.
\param [in] input DER-encoded key data, or a raw 2*n public key when
key->params is already set.
\param [in,out] inOutIdx On input, starting offset into input. On output,
advanced past the parsed key (unchanged on failure).
\param [in,out] key SLH-DSA key. Parameter set is auto-detected from the
encoded OID, or honored as-is in the raw fast path.
\param [in] inSz Total size of input in bytes.
\sa wc_SlhDsaKey_PublicKeyToDer
\sa wc_SlhDsaKey_PrivateKeyDecode
\sa wc_SlhDsaKey_ImportPublic
*/
int wc_SlhDsaKey_PublicKeyDecode(const byte* input, word32* inOutIdx,
SlhDsaKey* key, word32 inSz);
/*!
\ingroup SLH_DSA
\brief Encodes an SLH-DSA private key to DER in the PKCS#8
OneAsymmetricKey format defined by RFC 9909. The privateKey OCTET STRING
contains the raw 4*n bytes (SK.seed || SK.prf || PK.seed || PK.root)
directly, without the nested OCTET STRING wrapping used by Ed25519/Ed448.
Available only when WOLFSSL_SLHDSA_VERIFY_ONLY is not defined and
WC_ENABLE_ASYM_KEY_EXPORT is set.
\return Size of the encoded DER in bytes on success. Pass NULL as output
to query the required buffer size without writing.
\return BAD_FUNC_ARG if key or key->params is NULL.
\return MISSING_KEY if the private key has not been set.
\return BUFFER_E if output is non-NULL and inLen is smaller than the
required size.
\return NOT_COMPILED_IN if key->params names an SLH-DSA variant whose
parameter set is not built in.
\param [in] key SLH-DSA key with a populated private key.
\param [out] output Buffer to receive the DER encoding, or NULL to query
the required size.
\param [in] inLen Size of output in bytes (ignored when output is NULL).
\sa wc_SlhDsaKey_PrivateKeyDecode
\sa wc_SlhDsaKey_PrivateKeyToDer
\sa wc_SlhDsaKey_PublicKeyToDer
*/
int wc_SlhDsaKey_KeyToDer(SlhDsaKey* key, byte* output, word32 inLen);
/*!
\ingroup SLH_DSA
\brief Encodes an SLH-DSA private key to DER. RFC 9909 packs
SK.seed || SK.prf || PK.seed || PK.root into a single OCTET STRING, so
SLH-DSA has no distinct private-only encoding. This function is an
intentional alias of wc_SlhDsaKey_KeyToDer, kept for API parity with
Ed25519/Ed448 which do have a separate private form.
Available only when WOLFSSL_SLHDSA_VERIFY_ONLY is not defined and
WC_ENABLE_ASYM_KEY_EXPORT is set.
Return codes are inherited unchanged from wc_SlhDsaKey_KeyToDer.
\return Size of the encoded DER in bytes on success. Pass NULL as output
to query the required buffer size.
\return BAD_FUNC_ARG if key or key->params is NULL.
\return MISSING_KEY if the private key has not been set.
\return BUFFER_E if output is non-NULL and inLen is smaller than the
required size.
\return NOT_COMPILED_IN if key->params names an SLH-DSA variant whose
parameter set is not built in.
\param [in] key SLH-DSA key with a populated private key.
\param [out] output Buffer to receive the DER encoding, or NULL to query
the required size.
\param [in] inLen Size of output in bytes (ignored when output is NULL).
\sa wc_SlhDsaKey_KeyToDer
\sa wc_SlhDsaKey_PrivateKeyDecode
*/
int wc_SlhDsaKey_PrivateKeyToDer(SlhDsaKey* key, byte* output, word32 inLen);
/*!
\ingroup SLH_DSA
\brief Encodes an SLH-DSA public key to DER. When withAlg is non-zero
the output is a full SubjectPublicKeyInfo structure (AlgorithmIdentifier
plus BIT STRING). When withAlg is zero the output contains the raw
public key bytes without the SPKI wrapping.
Available only when WC_ENABLE_ASYM_KEY_EXPORT is set.
\return Size of the encoded DER in bytes on success. Pass NULL as output
to query the required buffer size.
\return BAD_FUNC_ARG if key or key->params is NULL.
\return BUFFER_E if output is non-NULL and inLen is smaller than the
required size.
\return NOT_COMPILED_IN if key->params names an SLH-DSA variant whose
parameter set is not built in.
\param [in] key SLH-DSA key with a populated public key.
\param [out] output Buffer to receive the DER encoding, or NULL to query
the required size.
\param [in] inLen Size of output in bytes (ignored when output is NULL).
\param [in] withAlg Non-zero to emit SubjectPublicKeyInfo (with
AlgorithmIdentifier); zero to emit the raw public key only.
\sa wc_SlhDsaKey_PublicKeyDecode
\sa wc_SlhDsaKey_KeyToDer
*/
int wc_SlhDsaKey_PublicKeyToDer(SlhDsaKey* key, byte* output, word32 inLen,
int withAlg);