Skip to content

Add ML-DSA private keys to table.#399

Open
msporny wants to merge 3 commits intomultiformats:masterfrom
msporny:patch-3
Open

Add ML-DSA private keys to table.#399
msporny wants to merge 3 commits intomultiformats:masterfrom
msporny:patch-3

Conversation

@msporny
Copy link
Copy Markdown
Contributor

@msporny msporny commented Apr 11, 2026

This is needed by the W3C Data Integrity Quantum-Safe Cryptosuite specification:

https://w3c-ccg.github.io/di-quantum-safe/#multikey

... about to go onto the standards track at W3C.

Copy link
Copy Markdown
Member

@vmx vmx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me, as always I think it's good to have two people look at it. If no one finds the time, I'll merge it eventually.

@msporny
Copy link
Copy Markdown
Contributor Author

msporny commented Apr 13, 2026

Perhaps @Wind4Greg could take a look as he's the one authoring the spec at W3C. @dlongley might take a look as well as he's authored multiple W3C Data Integrity cryptosuites.

Copy link
Copy Markdown
Contributor

@Wind4Greg Wind4Greg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Consistent with public keys.

Comment thread table.csv Outdated
Comment on lines +221 to +223
mldsa-44-priv, key, 0x1317, draft, ML-DSA 44 private key; as specified by FIPS 204
mldsa-65-priv, key, 0x1318, draft, ML-DSA 65 private key; as specified by FIPS 204
mldsa-87-priv, key, 0x1319, draft, ML-DSA 87 private key; as specified by FIPS 204
Copy link
Copy Markdown
Member

@lidel lidel Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing worth noting: FIPS 204 and RFC 9881 define three distinct encodings for ML-DSA private keys:

32-byte seed (recommended, used by JOSE/COSE)
full expanded key
combined form with both

The -priv entries here don't specify which encoding they represent. Consistent with other private key codecs in this table, so not a blocker, but leaves room for implementation divergence.

@msporny did you have a specific encoding in mind? The W3C spec linked in this PR lists private key sizes of 2,560 / 4,032 / 4,896 bytes for ML-DSA-44/65/87, which matches the expanded key format, but doesn't say so explicitly. Worth making that explicit in your spec + why you use expanded and not the compact seed?

@vmx do you feel we should we should clarify here from the start?

If so, should we go with explanded or seed?

Suggested change
mldsa-44-priv, key, 0x1317, draft, ML-DSA 44 private key; as specified by FIPS 204
mldsa-65-priv, key, 0x1318, draft, ML-DSA 65 private key; as specified by FIPS 204
mldsa-87-priv, key, 0x1319, draft, ML-DSA 87 private key; as specified by FIPS 204
mldsa-44-priv, key, 0x1317, draft, ML-DSA 44 private key; expanded key format (2560 bytes) as specified by FIPS 204
mldsa-65-priv, key, 0x1318, draft, ML-DSA 65 private key; expanded key format (4032 bytes) as specified by FIPS 204
mldsa-87-priv, key, 0x1319, draft, ML-DSA 87 private key; expanded key format (4896 bytes) as specified by FIPS 204
Suggested change
mldsa-44-priv, key, 0x1317, draft, ML-DSA 44 private key; as specified by FIPS 204
mldsa-65-priv, key, 0x1318, draft, ML-DSA 65 private key; as specified by FIPS 204
mldsa-87-priv, key, 0x1319, draft, ML-DSA 87 private key; as specified by FIPS 204
mldsa-44-priv, key, 0x1317, draft, ML-DSA 44 private key; seed key format (32 bytes) as specified by FIPS 204
mldsa-65-priv, key, 0x1318, draft, ML-DSA 65 private key; seed key format (32 bytes) as specified by FIPS 204
mldsa-87-priv, key, 0x1319, draft, ML-DSA 87 private key; seed key format (32 bytes) as specified by FIPS 204

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agree with the changes. Thank you for the catch!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @vmx, that makes sense to me if the purpose of this if for holding private keys, in, say, an HSM, for use in signing. Otherwise we could just have a single code point for the 32 byte seed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the seed 32 bytes for all security levels? I'm wondering if we need to provide a hint to the software wrt. what the expected security strength level should be in the generated key. For example, secretKeyMultibase doesn't tell you the security strength level of they expanded key, and it might be a good idea to do that since the information doesn't exist anywhere else. IOW, we might need three more entries:

mldsa-44-seed
mldsa-65-seed
mldsa-87-seed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that the seed size is the same for all variants here. I think we should go with the "seed key format (32 bytes)" second suggested change above from @lidel.

I think it's clear that having the seed version of these is useful so we should certainly define that. I don't know that expanded format will be useful in the future, but it may be. Minimally, the seed version should be defined (for all 3, so 3 different entries in the table) -- and if we think the expanded version is necessary that would be 3 more (total of 6).

So, +1 for defining mldsa-44|65|87-priv as the seed version. IIRC, the ed25519 and x25519 private keys are also defined as their 32-byte seed variants here (and then those are expanded internally for use -- yes, it's a much simpler expansion, but the concept is similar).

Copy link
Copy Markdown
Member

@lidel lidel Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be (also?) useful option to avoid the chore of registering every combination for every key and instead delegate as much is possible to existing RFCs.

For example, with codes proposed in:

we could represent both seed or expanded formats, or even both. https://www.rfc-editor.org/rfc/rfc9881#section-6 defines the ASN.1 encoding of ML-DSA private keys inside PKCS#8. For ML-DSA-44 its:

ML-DSA-44-PrivateKey ::= CHOICE {
  seed         [0] OCTET STRING (SIZE (32)),
  expandedKey      OCTET STRING (SIZE (2560)),
  both             SEQUENCE {
    seed         OCTET STRING (SIZE (32)),
    expandedKey  OCTET STRING (SIZE (2560))
  }
}

Fine to have both ways, but in practice, I find self-describing containers pretty interoperable (easy to find a library that knows how to read/write PKCS#8 etc)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation burden is much higher if ASN.1/DER (PKCS#8) is added as a requirement.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agreed, -1 to re-using the optionality in RFC 9881. We're trying to keep the header values simple so there is no confusion (or extra parsing) needed past the Multikey header. It's either seed bytes or an expandedKey. The "both" option in ASN.1 is not something we want to introduce because you then run the possibility of someone reading in a "both" as an expanded key (which would be an implementation bug, but one that we'd like to avoid).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Co-authored-by: Marcin Rataj <lidel@lidel.org>
@vmx
Copy link
Copy Markdown
Member

vmx commented Apr 14, 2026

I'm not deep enough in the keys topic. In case it's likely that we'll add other forms of the private keys, I think it would make sense to also add the form to the identifier itself. We could also change it later, but I guess it's less hassle to do it right away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants