EVP_SIGNATURE-ML-DSA(7ssl)

EVP_SIGNATURE-ML-DSA7ssl

The evp_pkey ml-dsa signature implementations

Overview

The ML-DSA-44, ML-DSA-65 and ML-DSA-87 EVP_PKEY implementations support key generation, and one-shot sign and verify using the ML-DSA signature schemes described in FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final>.

The different algorithms names correspond to the parameter sets defined in FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final> Section 4 Table 1. (The signatures range in size from ~2.5K to ~4.5K depending on the type chosen). There are 3 different security categories also depending on the type.

EVP_SIGNATURE_fetch(3) can be used to explicitly fetch one of the 3 algorithms which can then be used with EVP_PKEY_sign_message_init(3), EVP_PKEY_sign(3), EVP_PKEY_verify_message_init(3), and EVP_PKEY_verify(3) to perform one-shot message signing or signature verification.

The normal signing process (called Pure ML-DSA Signature Generation) encodes the message internally as 0x00 || len(ctx) || ctx || message. where ctx is some optional value of size 0x00..0xFF. This process is defined in FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final> Algorithm 2 step 10 and Algorithm 3 step 5. OpenSSL also allows the message to not be encoded which is required for testing. OpenSSL does not support Pre Hash ML-DSA Signature Generation, but this may be done by the user by doing Pre hash encoding externally and then choosing the option to not encode the message.

ML-DSA Signature Parameters

The following parameter can be used for both signing and verification. it may be set by passing an OSSL_PARAM array to EVP_PKEY_sign_message_init(3) or EVP_PKEY_verify_message_init(3)

"context-string" (OSSL_SIGNATURE_PARAM_CONTEXT_STRING) <octet string>

A string of octets with length at most 255. By default it is the empty string.

The following parameters can be used when signing: They can be set by passing an OSSL_PARAM array to EVP_PKEY_sign_init_ex2(3).

"message-encoding" (OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING) <integer>

The default value of 1 uses 'Pure ML-DSA Signature Generation' as described above. Setting it to 0 does not encode the message, which is used for testing. The message encoding steps are defined in FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final> Algorithm 2 step 10 and Algorithm 3 step 5.

"test-entropy" (OSSL_SIGNATURE_PARAM_TEST_ENTROPY) <octet string>

Used for testing to pass an optional deterministic per message random value. If set the size must be 32 bytes.

"deterministic" (OSSL_SIGNATURE_PARAM_DETERMINISTIC) <integer>

The default value of 0 causes the per message randomness to be randomly generated using a DRBG. Setting this to 1 causes the per message randomness to be set to 32 bytes of zeros. This value is ignored if "test-entropy" is set.

"mu" (OSSL_SIGNATURE_PARAM_MU) <integer>

The default value of 0 causes sign and verify operations to process a raw message. Setting this to 1 causes those operations to assume the input is the "mu" value from FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final> Algorithm 7 step 6 and Algorithm 8 step 7.

Note that the message encoding steps from FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final> Algorithm 2 step 10 and Algorithm 3 step 5 are omitted when this setting is 1.

See EVP_PKEY-ML-DSA(7) for information related to ML-DSA keys.

FIPS indicator

The following parameter can be retrieved using EVP_PKEY_CTX_get_params(3):

"fips-indicator" (OSSL_SIGNATURE_PARAM_FIPS_APPROVED_INDICATOR) <integer>

The OpenSSL FIPS provider returns 1 if the operation is FIPS approved, or 0 otherwise. See "FIPS indicators" in fips_module(7) for more information. Supplying "test-entropy", or setting the test-only "message-encoding" parameter to 0, causes this indicator to return 0.

Notes

For backwards compatibility reasons EVP_DigestSignInit_ex(), EVP_DigestSign(), EVP_DigestVerifyInit_ex() and EVP_DigestVerify() may also be used, but the digest passed in mdname must be NULL.

Examples

To sign a message using an ML-DSA EVP_PKEY structure:

    void do_sign(EVP_PKEY *key, unsigned char *msg, size_t msg_len)
    {
        size_t sig_len;
        unsigned char *sig = NULL;
        const OSSL_PARAM params[] = {
            OSSL_PARAM_octet_string("context-string", (unsigned char *)"A context string", 16),
            OSSL_PARAM_END
        };
        EVP_PKEY_CTX *sctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL);
        EVP_SIGNATURE *sig_alg = EVP_SIGNATURE_fetch(NULL, "ML-DSA-65", NULL);
        EVP_PKEY_sign_message_init(sctx, sig_alg, params);
        /* Calculate the required size for the signature by passing a NULL buffer. */
        EVP_PKEY_sign(sctx, NULL, &sig_len, msg, msg_len);
        sig = OPENSSL_zalloc(sig_len);
        EVP_PKEY_sign(sctx, sig, &sig_len, msg, msg_len);
        ...
        OPENSSL_free(sig);
        EVP_SIGNATURE_free(sig_alg);
        EVP_PKEY_CTX_free(sctx);
    }

Releases

2 releases since Debian 13 (Trixie); the text changed 1 time.

  1. 13
  2. Arch

History

This functionality was added in OpenSSL 3.5.

From openssl 3.6.5-1 in Arch Linux 2026-11-01. Parsed by carta from the page's man source.