On Wed, Feb 25, 2026 at 12:40:39AM +1100, Viktor Dukhovni wrote:
> > I am attempting to verify the Pure ML-DSA signature, but I have
> > encountered an issue. OpenSSL does not support the Verify update
> > operation, meaning the data to be verified must be provided in one
> > instance. Is this a limitation of OpenSSL or the Pure ML-DSA
> > algorithm?
>
> Pure ML-DSA requires the entire message to be provided in one shot, or
> that the caller pre-computes the external-μ value, and passes that,
> indicating that the input is the μ value. See EVP_SIGNATURE-ML-DSA(7)
> for details.
I should perhaps mention that this is for the EVP_DigestSignInit() and
EVP_DigestVerifyInit() APIs. OpenSSL also providers an API that is
specifically designed for incremental signing and verification for
algorithms like ML-DSA.
See EVP_PKEY_sign_message_init(3), EVP_PKEY_sign_message_update(3),
EVP_PKEY_sign_message_final(3), EVP_PKEY_verify_message_init(3),
EVP_PKEY_verify_message_update(3), EVP_PKEY_verify_message_final(3),
Support for incremental ML-DSA signing and verification via
EVP_PKEY_sign_message_update(3) and EVP_PKEY_verify_message_update(3)
was added in OpenSSL 3.6.
The CI code for this looks like:
if (!TEST_true(ml_dsa_create_keypair(&pkey, td->alg, td->priv, td->priv_len, NULL, 0, 1))
|| !TEST_ptr(sctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, pkey, NULL))
|| !TEST_ptr(sig_alg = EVP_SIGNATURE_fetch(lib_ctx, td->alg, NULL))
|| !TEST_int_eq(EVP_PKEY_sign_message_init(sctx, sig_alg, params), 1)
|| !TEST_int_eq(EVP_PKEY_sign_message_update(sctx, td->msg, 1), 1)
|| !TEST_int_eq(EVP_PKEY_sign_message_update(sctx, td->msg + 1, td->msg_len - 1), 1)
|| !TEST_int_eq(EVP_PKEY_sign_message_final(sctx, NULL, &psig_len), 1)
|| !TEST_ptr(psig = OPENSSL_zalloc(psig_len))
|| !TEST_int_eq(EVP_PKEY_sign_message_final(sctx, psig, &psig_len), 1))
...
Above the first byte of the message is processed separately from the
rest.
The advantage of the external-μ approach is that if the signer with the
private key is some sort of network HSM one really does not want to
transmit the entire message for signing, and then computing μ on the
client end is compelling. If the message data is local to the party
doing the ML-DSA computations, the EVP_PKEY_sign_message_* (IUF) API
is another option that avoids having to deal with external μ.
Also, if you're willing and able to compute μ for yourself, you can get
incremental ML-DSA message signing and verification with OpenSSL 3.5,
otherwise, you'll need 3.6 or (soon) 4.0.
--
Viktor. 🇺🇦 Слава Україні!