mirror of
https://github.com/openssl/openssl.git
synced 2025-04-06 20:20:50 +08:00
Add ML-DSA design document.
Reviewed-by: Viktor Dukhovni <viktor@openssl.org> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26400)
This commit is contained in:
parent
6184259849
commit
2ca319684c
126
doc/designs/ml-dsa.md
Normal file
126
doc/designs/ml-dsa.md
Normal file
@ -0,0 +1,126 @@
|
||||
ML-DSA Design
|
||||
==============
|
||||
|
||||
This document covers OpenSSL specific ML-DSA implementation details.
|
||||
FIPS 204 clearly states most of the requirements of ML-DSA and has comprehensive
|
||||
pseudo code for all its algorithms.
|
||||
|
||||
The base code for OpenSSL has been derived from the BoringSSL C++ code.
|
||||
As OpenSSL is c code, templates can not be used. The OpenSSL code instead uses
|
||||
parameters to pass algorithm specific constants, and also uses these constants
|
||||
to run different conditional functions when required.
|
||||
|
||||
ML_DSA Parameters & Per algorithm Functions
|
||||
-------------------------------------------
|
||||
|
||||
FIPS 204 contains 3 algorithms for different security strengths.
|
||||
FIPS 204 Section 4 Table 1 & Table 2 specifies different constants that are
|
||||
stored in a table of ML_DSA_PARAM objects.
|
||||
The constants include key sizes and coefficient ranges.
|
||||
|
||||
OpenSSL uses 3 key managers and 3 signature functions corresponding to the algorithms
|
||||
ML-DSA-44, ML-DSA-65 and ML-DSA-87.
|
||||
|
||||
ML-DSA only uses SHAKE-128 and SHAKE-256 for digest operations, so these values
|
||||
are pre-fetched and stored within a ML_DSA key. Any functions that require these
|
||||
pre-fetched objects must pass either the key or the pre-fetched object within the key
|
||||
as a parameter. A temporary EVP_MD_CTX is created as needed and the shake object(s)
|
||||
are set into this ctx.
|
||||
|
||||
Initially a separate object called ML_DSA_CTX object was passed around that
|
||||
contained 2 EVP_MD_CTX's containing the pre-fetched EVP_MD shake objects. It was
|
||||
modified to match the ML-KEM code.
|
||||
|
||||
ML-DSA keys
|
||||
------------
|
||||
|
||||
Once loaded an 'ML-DSA-KEY' object contains either a public key or a
|
||||
public/private key pair.
|
||||
When loading a private key, the public key is always generated. In the event
|
||||
that the public key is also supplied, an error will occur if the generated public
|
||||
key does not match the supplied public key.
|
||||
|
||||
An ML_DSA polynomial contains 256 32 bit values which is 1K of space.
|
||||
Keys store vectors of size 'k' or 'l' plus a matrix of size 'k' * 'l',
|
||||
where (k, l) correspond to (4,4), (6,5) or (8,7). The key data could be large
|
||||
if buffers of the maximum size of (8,7) are used for the (4,4) use case.
|
||||
To save space rather than use fixed size buffers, allocations are used instead,
|
||||
for both the public and private elements. (i.e. The private allocations are not
|
||||
done when only a public key is loaded).
|
||||
|
||||
Since keys consist of vectors and a matrix of polynomials, a single block
|
||||
is used to allocate all polynomials, and then the polynomial blocks are
|
||||
assigned to the individual vectors and matrix. This approach is also used when temporary
|
||||
vectors, matrices or polynomials are required
|
||||
|
||||
Keys are not allowed to mutate, so checks are done during load to check that the
|
||||
public and private key components are not changed once set.
|
||||
|
||||
ossl_ml_dsa_key_get_pub() and ossl_ml_dsa_key_get_priv() return the
|
||||
encoded forms of the key components (which are stored within the key).
|
||||
The hash of the encoded public key is also stored in the key.
|
||||
|
||||
The key generation process uses a seed to create a private key, and the public
|
||||
key is then generated using this private key.
|
||||
|
||||
For ACVP testing the seed may be supplied.
|
||||
|
||||
Pure vs Pre Hashed Signature Generation
|
||||
----------------------------------------
|
||||
|
||||
The normal signing process (called Pure ML-DSA Signature Generation)
|
||||
encodes the message internally as 0x00 || len(ctx) || ctx || message.
|
||||
where B<ctx> is some optional value of size 0x00..0xFF.
|
||||
|
||||
ACVP Testing requires the ability to process raw messages without the above encoding.
|
||||
This will be controlled by settable parameters.
|
||||
|
||||
Pre Hash ML-DSA Signature Generation encode the message as
|
||||
0x01 || len(ctx) || ctx || digest_OID || H(message).
|
||||
The scenario that is stated that this is useful for is when this encoded message
|
||||
is supplied from an external source.
|
||||
This ensures domain separation between signature variants
|
||||
|
||||
Currently I do not support the Pre Hash variant as this does not sit well with the
|
||||
OpenSSL API's. The user could do the encoding themselves and then set the settable
|
||||
to not encode the passed in message.
|
||||
|
||||
Signing API
|
||||
-------------
|
||||
|
||||
As only the one-shot implementation is required and the message is not digested
|
||||
the API's used should be
|
||||
|
||||
EVP_PKEY_sign_message_init(), EVP_PKEY_sign(),
|
||||
EVP_PKEY_verify_message_init(), EVP_PKEY_verify().
|
||||
|
||||
Encoding/Decoding
|
||||
-----------------
|
||||
|
||||
Where it makes sense to, WPACKET is used for output (such as signature generation)
|
||||
and PACKET for reading signature data.
|
||||
|
||||
Constant Time Considerations
|
||||
----------------------------
|
||||
|
||||
Similar code to BoringSSL will be added that allows ctgrind to be used to
|
||||
detect constant time issues.
|
||||
|
||||
There are many places that do hashing in the code, and these are capable (although
|
||||
it is not likely) of returning errors. There is not attempt to deal with these cases.
|
||||
|
||||
Changes from BoringSSL
|
||||
----------------------
|
||||
|
||||
At the time of writing, BoringSSL code only supported ML-DSA-65. Since there
|
||||
is specialized code for encoding and decoding of different sizes of
|
||||
polynomial coefficients, code was added to support these different sizes
|
||||
(e.g hints have 1 bit coefficients so 8 coefficients can be packed into 1 byte)
|
||||
|
||||
Differences between BoringSSL and FIPS 204 pseudo code
|
||||
------------------------------------------------------
|
||||
|
||||
The symmetric modulus operation normally gives a result in the range -a/2 ... a/2.
|
||||
BoringSSL chose to keep the result positive by adding q and reducing once is required.
|
||||
|
||||
Montgomery multiplication is used to speed up multiplications (See FIPS 204 Appendix A).
|
@ -42,12 +42,19 @@ Use EVP_PKEY_CTX_set_params() after calling EVP_PKEY_keygen_init().
|
||||
=head2 Common ML-DSA parameters
|
||||
|
||||
In addition to the common parameters that all keytypes should support (see
|
||||
L<provider-keymgmt(7)/Common parameters>), the implementation of these key types
|
||||
support the following.
|
||||
L<provider-keymgmt(7)/Common Information Parameters>, the implementation of
|
||||
these key types support the following.
|
||||
|
||||
The following parameters are gettable using EVP_PKEY_get_octet_string_param(),
|
||||
and settable when using EVP_PKEY_fromdata().
|
||||
|
||||
The following octet string parameters are gettable using
|
||||
L<EVP_PKEY_get_octet_string_param(3)> or L<EVP_PKEY_get_params(3)>.
|
||||
They can be set into L<EVP_PKEY_fromdata(3)>, and are returned by
|
||||
L<EVP_PKEY_todata(3)> given a suitable I<selection>.
|
||||
Once a public or private key is configured, it can no longer be modified,
|
||||
nor can another key component be added.
|
||||
|
||||
=over 4
|
||||
|
||||
=item "pub" (B<OSSL_PKEY_PARAM_PUB_KEY>) <octet string>
|
||||
|
@ -20,7 +20,7 @@ There are 3 different security categories also depending on the type.
|
||||
L<EVP_SIGNATURE_fetch(3)> can be used to explicitely fetch one of the 3
|
||||
algorithms which can then be used with L<EVP_PKEY_sign_message_init(3)>,
|
||||
L<EVP_PKEY_sign(3)>, L<EVP_PKEY_verify_message_init(3)>, and
|
||||
L<EVP_PKEY_verify(3)> to sign or verify one-shot messages.
|
||||
L<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.
|
||||
|
@ -191,7 +191,11 @@ The OpenSSL default provider supports these operations and algorithms:
|
||||
|
||||
=item SM2
|
||||
|
||||
=item ML-DSA, see L<EVP_SIGNATURE-ML-DSA(7)>
|
||||
=item ML-DSA-44, see L<EVP_SIGNATURE-ML-DSA(7)>
|
||||
|
||||
=item ML-DSA-65, see L<EVP_SIGNATURE-ML-DSA(7)>
|
||||
|
||||
=item ML-DSA-87, see L<EVP_SIGNATURE-ML-DSA(7)>
|
||||
|
||||
=item HMAC, see L<EVP_SIGNATURE-HMAC(7)>
|
||||
|
||||
@ -267,7 +271,11 @@ The OpenSSL default provider supports these operations and algorithms:
|
||||
|
||||
=item SM2, see L<EVP_KEYMGMT-SM2(7)>
|
||||
|
||||
=item ML-DSA, see L<EVP_KEYMGMT-ML-DSA(7)>
|
||||
=item ML-DSA-44, see L<EVP_KEYMGMT-ML-DSA(7)>
|
||||
|
||||
=item ML-DSA-65, see L<EVP_KEYMGMT-ML-DSA(7)>
|
||||
|
||||
=item ML-DSA-87, see L<EVP_KEYMGMT-ML-DSA(7)>
|
||||
|
||||
=back
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user