EVP_SIGNATURE-ML-DSA(7ossl)

πŸ“¦ version 3.5.0, in opensuse-leap 16.0

πŸ’… EVP_SIGNATURE-ML-DSA πŸ’…

okay so bestie, welcome to the manual page for EVP_SIGNATURE-ML-DSA, EVP_SIGNATURE-ML-DSA-44, EVP_SIGNATURE-ML-DSA-65, and EVP_SIGNATURE-ML-DSA-87 β€” literally the whole ML-DSA squad, together in one doc (this is EVP_SIGNATURE-ML-DSA(7ossl) if you're keeping track πŸŽ€). it's giving post-quantum main character energy and i'm obsessed.


🌸 NAME 🌸

EVP_SIGNATURE-ML-DSA, EVP_SIGNATURE-ML-DSA-44, EVP_SIGNATURE-ML-DSA-65, EVP_SIGNATURE-ML-DSA-87 β€” that's the EVP_SIGNATURE ML-DSA support, periodt. ✨


πŸ¦‹ DESCRIPTION πŸ¦‹

so the ML-DSA-44, ML-DSA-65 and ML-DSA-87 EVP_PKEY implementations support key generation, plus one-shot sign and verify, using the ML-DSA signature schemes described in FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final>. no cap, that's the whole vibe. πŸ’œ

the different algorithm names correspond to the parameter sets defined in FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final> Section 4 Table 1 (go look, it's right there). and like β€” heads up β€” the signatures range in size from ~2.5K to ~4.5K depending on the type chosen πŸ™ˆ. there are also 3 different security categories, again depending on the type. so pick your fighter wisely, bestie.

EVP_SIGNATURE_fetch(3) can be used to explicitely fetch one of the 3 algorithms, which you can then use 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. slay. πŸ”₯

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 πŸ§ͺ. and lowkey important: OpenSSL does not support Pre Hash ML-DSA Signature Generation β€” but you can do it yourself by doing Pre hash encoding externally and then choosing the option to not encode the message. diy era πŸ’…

πŸŽ€ ML-DSA Signature Parameters πŸŽ€

the following parameter works 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's the empty string. so if you don't say anything, it's giving silent treatment 🫢

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. not 31, not 33. thirty-two. ⭐
  • "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. so don't bother setting both, she's not listening πŸ’€
  • "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.
heads up: 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. so like… it's a whole different pipeline, ok? πŸ™ˆ

see EVP_PKEY-ML-DSA(7) for info related to ML-DSA keys πŸ”‘


🌈 NOTES 🌈

for backwards compatability 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. that's the one rule, bestie. null it out. πŸŽ€


πŸ’– 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(sig_alg);
    EVP_PKEY_CTX_free(sctx);
}

that's it, that's the whole ritual πŸ•―οΈβœ¨


πŸ‘‘ SEE ALSO πŸ‘‘

EVP_PKEY-ML-DSA(7) provider-signature(7), EVP_PKEY_sign(3), EVP_PKEY_verify(3), FIPS 204 <https://csrc.nist.gov/pubs/fips/204/final> β€” go read them, i'm not kidding, they're good for you πŸ“


⭐ HISTORY ⭐

this functionality was added in OpenSSL 3.5. new era unlocked πŸ”“πŸŒΈ


Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


okay that's the whole page, bestie 🫢 this was 3.5.0, dated 2026-09-25, and it's the EVP_SIGNATURE-ML-DSA(7ossl) manual β€” mwah, go sign something πŸ’…βœ¨

πŸ“¦ where this page comes from