ML-DSA Programming Guide for Luna HSM

ABBREVIATIONS AND ACRONYMS

Term Definition
API Application Programming Interface
ML-DSA Module-Lattice Key Digital Signature Algorithm
PKCS Public Key Cryptography Standards

References

Document Author Title
PKCS #11 3.2 Draft 13 OASIS pkcs11-spec-v3.2-wd13
FIPS 204   Module-Lattice-Based Digital Signature Standard (nist.gov)

Overview of ML-DSA

This document discusses how customers and third party applications can use ML-DSA API exposed by the Luna HSM 7 Firmware version 7.9.0 onward, and the Luna Universal Client version 10.9.0 onward.

ML-DSA services are exposed through mechanisms, objects and attributes of the Cryptoki interface.

ML-DSA Primer

Two Signing algorithms are described in SP 800-204 that differ depending on whether the message M being signed is the hash of a message (PreHash) or the message itself (Pure).

In each case a Common Internal signing function signs a modified version of M called M’ and takes an optional random string rnd.

σ← ML-DSA.Sign_internal (sk, M′, rnd)

The PreHash and Pure signing algorithms differ in the process to convert Message M to make M’.

For the default “hedged” version of ML-DSA signing, the algorithm uses an approved RBG to generate a 256-bit (32-byte) random seed rnd. If the deterministic variant is desired, then rndis set to the fixed zero string {0}32.

The Luna generates an rng value from the internal RNG.

The ML-DSA.Sign_internal() function immediately converts the M’ into a value called μ(Mu).

μ← H(BytesToBits(tr)||M′, 64)

tr : H(publicKey)

H is defined as: H(str, ℓ) = SHAKE256(str, 8ℓ) i.e. the output is 64*8=512 bits

μ: message representative that may optionally be computed in a different cryptographic module

So, if you know the public key and M’ you can precompute the Mu value outside the HSM and then Sign/Verify based on the Mu value. This is called “ExternalMu-ML-DSA”.

Algorithm 2 – Standard ML-DSA

Sign a message M with private key sk and an optional ctx array.

ML-DSA.Sign(sk, M′, ctx)

The Message is prepended with a flag byte, a length byte, the ctx string and passed down to the Internal Sign function.

M′ ← 0 ∥ 0-255 ∥ )ctx ∥ M

The M’ is then mixed with the hash of the public key to make Mu.

Algorithm 4 – Pre-Hashed ML-DSA

Sign a message M with private key sk , an optional ctx array and using Pre-Hash Function PH

HashML-DSA.Sign(sk, M, ctx PH)

The Message is hashed with PH function (e.g. SHA256) and the result is prepended with a flag byte, a length of ctx byte, the ctx string and the DER encoded OID of the PH function.

M′ ← 1 ∥ 0-255 ∥ ctx… ∥ OID ∥ PH(M)

SP 800-204 states: “While a single key pair may be used for both ML-DSA and HashML-DSA signatures, it is recommended that each key pair only be used for one version or the other.”

In order to maintain the same level of security strength when the content is hashed at the application level or using HashML-DSA , the digest that is signed needs to be generated using an approved hash function or XOF (such as from FIPS 180 [8] or FIPS 202 [7]) that provides an equal or greater security strength than that of the signing key.

ExternalMu-ML-DSA

It is proposed that an implementation may choose to perform the Mu calculation outside the HSM that is performing the ML-DSA signature generation.

μ← SHAKE256(SHAKE256(pubKey,512)||M′, 512)

Where M’ is generated using Pure or PreHash schemes.

The advantages are: that the application is in control of the public key used to form the signature, and there is probably a performance improvement.

Key and Signature Sizes

Sizes (in bytes) of keys and signatures of ML-DSA
  Private Key Public Key Signature Size
ML-DSA-44 2560 1312 2420
ML-DSA-65 4032 1952 3309
ML-DSA-87 4896 2592 4627

PKCS#11 standardization status

A draft 3.2-13 specification adds support for ML-DSA key pair generate and single and multi-part Signing/Verify mechanisms with and without external HASH.

The Signing and Verify mechanisms are Single Part and Multi-Part operations. They support optional Hedging.

The optional ctx values are provided externally to the mechanism.

The standard also adds a new C_VerifySignature* API. This API accepts the signature in the init operation instead of the usual final operation. Luna HSM does not currently support this new function.

Support for ExternalMu-ML-DSA is not in Draft 13. Luna does support it as a proprietary mechanism.

Object Identifiers for ML-DSA

So far, these OIDs have been found to specify ML-DSA algorithms. Note: there are no OIDs specific to the key type, just the algorithms.

From Internet X.509 Public Key Infrastructure: Algorithm Identifiers for ML-DSA (ietf.org)

and

https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration

The OIDs are defined:

>for ‘pure’ algorithms based on each key size and

>for Pre-Hash signatures using SHA512 for each key size.

NOTE   No OIDS are defined for pre hash algorithms that use a hash other than SHA512.

sigAlgs ::= joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) sigAlgs(3)
‘Pure’ algorithms:
id-ML-DSA-44 OBJECT IDENTIFIER ::= { sigAlgs 17 }
id-ML-DSA-65 OBJECT IDENTIFIER ::= { sigAlgs 18 }
id-ML-DSA-87 OBJECT IDENTIFIER ::= { sigAlgs 19 }
Pre-Hash algorithms:
id-Hash-ML-DSA-44-with-sha512 OBJECT IDENTIFIER ::= { sigAlgs 32 }
id-Hash-ML-DSA-65-with-sha512 OBJECT IDENTIFIER ::= { sigAlgs 33 }
id-Hash-ML-DSA-87-with-sha512 OBJECT IDENTIFIER ::= { sigAlgs 34 }

CKA_PUBLIC_KEY_INFO attribute

The CKA_PUBLIC_KEY_INFO attribute holds the public key values as a DER encoded SubjectPublicKeyInfo (as used in X509 certs).

SubjectPublicKeyInfo  ::=  SEQUENCE  {
	algorithm            AlgorithmIdentifier,
	subjectPublicKey     BIT STRING  }

The ‘algorithm’ is a sequence with an OID and optional params.

AlgorithmIdentifier ::=  SEQUENCE  {
	algorithm            OBJECT IDENTIFIER,
	parameter            ANY DEFINED BY algorithm OPTIONAL }

The contents of the parameter component for each ML-DSA algorithm are absent (that is, they are not present in the encoding).

The subjectPublicKey is a bit string that holds the public key value. Its content format depends on the algorithm.

For ML-DSA this is defined by Internet Engineering Task Force IETF to be the simple byte array holding the raw public key.

The OIDs are defined by NIST. The OIDs available specify the algorithm and not the key type; for example an ML-DSA-44 key could be used with the ‘Pure’ id-ML-DSA-44 or the pre-hash id-Hash-ML-DSA-44-with-sha512. Until further clarity is provided, we should use the ‘Pure’ algorithm version to identify the key type.

IETF require ‘pure’ signing for certificate signatures. The use of Pre-Hash is not supported.

A sample public key encoding for ML-DSA-44

Note BIT_STRING encoder always prepends a ‘00’

SEQUENCE {
 SEQUENCE {
   OBJECT_IDENTIFIER { 2.16.840.1.101.3.4.3.17 }
 }
 BIT_STRING { `00` `d7b2b47254aae0db45e7930d4a98d2c97d8f1397d17
89dafa17024b316e9bec94fc9946d42f19b79a7413bbaa33e7149cb42ed51156
5ba5925e8edefa679369a2202766151f16a965f9f81ece76cc070b55869e4db9
. . . . .
784cf05c830b3242c8312` }
}

Private Key Import/Export

Luna HSM firmware version 7.9.0 does not support the wrapping or unwrapping of CK_ML_DSA private key objects.

Wrapping and unwrapping functions are to be supported with future firmware upgrade as those functions become fully standardized.

 

Cryptoki Interface according to PKCS#11 3.2 Draft 13

ML-DSA

ML-DSA mechanisms for signatures and verification, following the digital signature algorithm defined in [FIPS 204].

Definitions

This section defines the key type CKK_ML_DSA for type CK_KEY_TYPE as used in the CKA_KEY_TYPE attribute of all ML-DSA key objects.

Mechanisms:

CKM_ML_DSA_KEY_PAIR_GEN 0x01c
CKM_ML_DSA 0x01d
CKM_EXTMU_ML_DSA 0x8000175
CKM_HASH_ML_DSA 0x01f
CKM_HASH_ML_DSA_SHA224 0x023
CKM_HASH_ML_DSA_SHA25 0x024
CKM_HASH_ML_DSA_SHA384 0x025
CKM_HASH_ML_DSA_SHA512 0x026
CKM_HASH_ML_DSA_SHA3_224 0x027
CKM_HASH_ML_DSA_SHA3_256 0x028
CKM_HASH_ML_DSA_SHA3_384 0x029
CKM_HASH_ML_DSA_SHA3_512 0x02a
CKM_HASH_ML_DSA_SHAKE128 0x02b
CKM_HASH_ML_DSA_SHAKE256 0x02c

CK_ML_DSA_PARAMETER_SET_TYPE is used to indicate which ML-DSA parameter set the keys belong to.

typedef CK_ULONG CK_ML_DSA_PARAMETER_SET_TYPE;

Parameter set types:

           CKP_ML_DSA_44 1

           CKP_ML_DSA_65 2

           CKP_ML_DSA_87 3

Key Type

           CKK_ML_DSA 0x4A

CK_HEDGE_TYPE is used to indicate how hedge or deterministic signature variants are handled.

typedef CK_ULONG CK_HEDGE_TYPE;

Hedge types

           CKH_HEDGE_PREFERRED 0

           CKH_HEDGE_REQUIRED 1

           CKH_DETERMINISTIC_REQUIRED 2

CK_SIGN_ADDITIONAL_CONTEXT is used in the mechanism parameters to supply a NIST defined context string in signature scheme.

typedef struct CK_SIGN_ADDITIONAL_CONTEXT {

           CK_HEDGE_TYPE hedgeVariant;

           CK_BYTE_PTR pContext;

           CK_ULONG ulContextLen;

} CK_SIGN_ADDITIONAL_CONTEXT;

CK_HASH_SIGN_ADDITIONAL_CONTEXT is used in the mechanism parameters to supply a NIST defined context string in signature scheme and the hash.

typedef struct CK_HASH_SIGN_ADDITIONAL_CONTEXT {

           CK_HEDGE_TYPE hedgeVariant;

           CK_BYTE_PTR pContext;

           CK_ULONG ulContextLen;

           CK_MECHANISM_TYPE hash;

} CK_HASH_SIGN_ADDITIONAL_CONTEXT;

ML-DSA public key objects

ML-DSA public key objects (object class CKO_PUBLIC_KEY, key type CKK_ML_DSA) hold ML-DSA public keys.

The following table defines the ML-DSA public key object attributes, in addition to the common attributes defined for this object class:

ML-DSA Public Key Object Attributes
Attribute Data Type Meaning
CKA_PARAMETER_SET CK_ML_DSA_PARAMETER_SET_TYPE ML-DSA parameter set
CKA_VALUE Big integer Public value as defined in [FIPS 204]
CKA_PUBLIC_KEY_INFO Big integer Public Key DER encoded

The CKA_PARAMETER_SET attribute value selects a predefined set of parameters specified by NIST.

The parameter set allows to select the security level and public key sizes. All three NIST Parameter sets are supported.

The C_CopyObject function allows attributes to be changed as per standard CKO_PUBLIC_KEY objects.

The C_CreateObject function should use the CKA_VALUE in the template to specify the Public key value. Each parameter set has a unique public key length. The public key value is validated by ensuring it is one of the approved lengths. If the CKA_PARAMETER_SET attribute is specified in the template then it must match the value implied by CKA_VALUE else the appropriate value will be added to the object.

  Public Key
ML-DSA-44 1312
ML-DSA-65 1952
ML-DSA-87 2592

C_DeriveKey and C_UnwrapKey functions are not supported on, or with, CKK_ML_DSA public key objects.

ML-DSA private key objects

ML-DSA private key objects (object class CKO_PRIVATE_KEY, key type CKK_ML_DSA) hold ML-DSA private keys.

The following table defines the ML-DSA private key object attributes, in addition to the common attributes defined for this object class:

ML-DSA Private Key Object Attributes
Attribute Data Type Meaning
CKA_PARAMETER_SET CK_ML_DSA_PARAMETER_SET_TYPE ML-DSA parameter set
CKA_SEED Big Integer Seed value as defined in ML_DSA KeyGen in FIPS 204
CKA_VALUE Big Integer Private value as defined in [FIPS 204]
CKA_PUBLIC_KEY_INFO Big Integer Public Key DER encoded

At least one of CKA_SEED and CKA_VALUE must be specified on CKA_PUBLIC_KEY_INFO. Tokens may reject creation requests that only specify one of these values. For highest compatibility, applications should set both.

Both CKA_VALUE and CKA_SEED are sensitive attributes and cannot be read using C_GetAttributeValue.

The CKA_PARAMETER_SET attribute value selects a predefined set of parameters specified by NIST.

The parameter set is used to select the security level and public key sizes. Tokens may support a subset of the defined parameter set values. (Luna HSMs support all parameter set values).

NOTE   When generating a ML-DSA private key, the parameter set is not specified in the key’s template.

This is because ML-DSA private keys are generated only as part of a ML-DSA key pair, and the parameter set for the pair is specified in the template for the ML-DSA public key.

The C_CopyObject function allows attributes to be changed as per standard CKO_PRIVATE_KEY objects.

The C_CreateObject function is not supported.

The C_WrapKey and C_UnwrapKey functions are not supported with this release or with CKK_ML_DSA private key objects

The C_DeriveKey function is not supported on, or with, CKK_ML_DSA private key objects.

ML-DSA key pair generation

The ML-DSA key pair generation mechanisms, denoted CKM_ML_DSA_KEY_PAIR_GEN, is a key pair generation mechanism as defined in [FIPS 204].

It does not have a parameter.

The mechanism generates ML-DSA public/private key pairs with a parameter set, as specified in the CKA_PARAMETER_SET attribute of the template for the public key.

The mechanism contributes the CKA_CLASS, CKA_KEY_TYPE and CKA_VALUE attributes to the new public key and the CKA_CLASS, CKA_KEY_TYPE, CKA_PARAMETER_SET, CKA_SEED and CKA_VALUE attributes to the new private key; other attributes required by the ML-DSA public and private key types must be specified in the templates.

For this mechanism, the ulMinKeySize and ulMaxKeySize fields of the CK_MECHANISM_INFO structure specify the supported range of ML-DSA public key in bytes.

ML-DSA Signature

The ML-DSA signature mechanisms, denoted CKM_ML_DSA are a mechanisms for generating and verifying ML-DSA ‘Pure’ signatures in single or multi-part as defined in [FIPS 204].

The mechanism has an optional parameter CK_SIGN_ADDITIONAL_CONTEXT. If no parameter is supplied the HedgeVariant is set to CKH_HEDGE_PREFERRED, ulContextLen is set to zero and pContext is set to NULL.

On signing, if hedgeVariant is set to CKH_HEDGE_PREFERRED, the token may create either a hedged signature or a deterministic signature as specified in [FIPS 204]. The Luna HSM creates a hedged signature. If hedgeVariant is set to CKH_HEDGE_REQUIRED is set, the token must produce a hedged signature or fail. If the hedgeVariant is set to CKH_DETERMINISTIC_REQUIRED, the token must produce a deterministic signature or fail.

On verification the hedgeVariant parameter is ignored.

Constraints on key types and the length of the data are summarized in the following table. In the table, k is the length in bytes of the ML-DSA signature.

ML-DSA: Key and Data Length
Function Key type Input length Output length
C_Sign ML-DSA Private Key any k
C_Verify ML-DSA Public Key any, k N/A

For these mechanisms, the ulMinKeySize and ulMaxKeySize fields of the CK_MECHANISM_INFO structure specify the supported range of ML-DSA public keys in bytes.

  Signature Size (k)
ML-DSA-44 2420
ML-DSA-65 3309
ML-DSA-87 4627

Hash ML-DSA Signature

The hash ML-DSA signature mechanisms, denoted CKM_HASH_ML_DSA are single part mechanisms for generating and verifying hash ML-DSA signatures defined in [FIPS 204]. The data passed in is an already-hashed message.

It has a parameter CK_HASH_SIGN_ADDITIONAL_CONTEXT. On signing, if hedgeVariant is set to CKH_HEDGE_PREFERRED, the token may create either a hedged signature or a deterministic signature as specified in [FIPS 204]. Luna HSM defaults to hedged signatures. If hedgeVariant is set to CKH_HEDGE_REQUIRED is set, the token must produce a hedged signature or fail. If the hedgeVariant is set to CKH_DETERMINISTIC_REQUIRED, the token must produce a deterministic signature or fail. On verification the hedgeVariant parameter is ignored.

Constraints on key types and the length of the data are summarized in the following table. In the table, k is the length in bytes of the ML-DSA signature. The length of the hash must match the length (in bytes) expected from the ‘hash’ mechanism type.

ML-DSA: Key and Data Length
Function Key type Input length Output length
C_Sign ML-DSA Private Key Length of hash k
C_Verify ML-DSA Public Key any, k N/A

For these mechanisms, the ulMinKeySize and ulMaxKeySize fields of the CK_MECHANISM_INFO structure specify the supported range of ML-DSA public keys in bytes.

Hash ML-DSA Signature with hashing

The hash ML-DSA with hashing mechanism, denoted CKM_HASH_ML_DSA_<hash> where <hash> identifies a hash function as in the table below, is a mechanism for single- and multiple-part signatures and verification for ML-DSA. This mechanism computes the entire preHash ML-DSA specification, including the hashing on token.

Hash ML-DSA with hashing: mechanisms and hash functions
Mechanism Hash function OID for HASH Hash Len (bits/bytes)
CKM_HASH_ML_DSA_SHA256 SHA-256 hashAlgs 1 256/32
CKM_HASH_ML_DSA_SHA384 SHA-384 hashAlgs 2 384/48
CKM_HASH_ML_DSA_SHA512 SHA-512 hashAlgs 3 512/64
CKM_HASH_ML_DSA_SHA3_224 SHA3-224 hashAlgs 7 224/28
CKM_HASH_ML_DSA_SHA3_256 SHA3-256 hashAlgs 8 256/32
CKM_HASH_ML_DSA_SHA3_384 SHA3-384 hashAlgs 9 384/48
CKM_HASH_ML_DSA_ SHA3_512 SHA3-512 hashAlgs 10 512/64
CKM_HASH_ML_DSA_ SHAKE128 SHAKE128 SHAKE128 hashAlgs 11 256/32
CKM_HASH_ML_DSA_ SHAKE256 SHAKE256 hashAlgs 12 512/64

OID values for each mechanism are the same as expected by CKM_HASH_ML_DSA mechanism.

Where OID Path is::

joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashAlgs(2)

BER encoding for each hash algorithm that is inserted in the signature calculation is an 11-byte array:

0x06 0x09 0x60 0x86 0x48 0x01 0x65 0x03 0x04 0x03 <id>

Note the output sizes of SHAKE128 and SHAKE256 hashes.

These mechanisms all have an optional parameter CK_SIGN_ADDITIONAL_CONTEXT. If no parameter is supplied ulContextLen is set to zero and pContext is set to NULL. On signing, if hedgeVariant is set to CKH_HEDGE_PREFERRED, the token may create either a hedged signature or a deterministic signature, as specified in [FIPS 204].

>If hedgeVariant is set to CKH_HEDGE_REQUIRED is set, the token must produce a hedged signature or fail.

>If the hedgeVariant is set to CKH_DETERMINISTIC_REQUIRED, the token must produce a deterministic signature or fail. On verification the hedgeVariant parameter is ignored.

Constraints on key types and the length of data are summarized in the following table:

Hash ML-DSA: with hashing Key and Data Length
Function Key type Input length Output length
C_Sign ML-DSA Private Key any k
C_Verify ML-DSA Public Key any, k N/A

For these mechanisms, the ulMinKeySize and ulMaxKeySize fields of the CK_MECHANISM_INFO structure specify the supported range of ML-DSA public keys in bytes.

ExternalMu ML-DSA Signature – Proprietary

The External Mu ML-DSA signature mechanism, denoted CKM_EXTMU_ML_DSA is a single part mechanism for generating and verifying hash ML-DSA signatures defined in [FIPS 204]. The data passed in is an already pre-processed message representing the Mu value.

This is a proprietary mechanism. It is not a NIST approved algorithm.

The mechanism has an optional parameter CK_SIGN_ADDITIONAL_CONTEXT which is used to pass the hedgeVariant value only. If a parameter is supplied ulContextLen must be zero and pContext must be NULL.

On signing, if the parameter is supplied with hedgeVariant set to CKH_DETERMINISTIC_REQUIRED then deterministic signature is generated, else a hedged signature is generated.

On verification the hedgeVariant parameter is ignored.

Constraints on key types and the length of the data are summarized in the following table. In the table, k is the length in bytes of the ML-DSA signature and Mu is 64 bytes long.

ML-DSA: Key and Data Length
Function Key type Input length Output length
C_Sign ML-DSA Private Key Length of Mu k
C_Verify ML-DSA Public Key Mu, k N/A

C_Sign and C_Verify Single-part operations only.

For these mechanisms, the ulMinKeySize and ulMaxKeySize fields of the CK_MECHANISM_INFO structure must specify the supported range of ML-DSA public keys in bytes.