openssl/include/crypto/ml_kem.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

290 lines
11 KiB
C
Raw Permalink Normal View History

Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/*
* Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
ML-KEM libcrypto implementation polish * Core ML_KEM constants in new <openssl/ml_kem.h> * Renamed variant ordinals to ML_KEM_<bits>_VARIANT, freeing up the unadorned ML_KEM_<bits> names. * Fewer/cleaner macros in <crypto/ml_kem.h> * Fewer/cleaner macros for setting up the ML_KEM_VINFO table. * Made (d, z) be separate inputs to the now single key generation function. Both or neither have to be NULL. This supports potential future callers that store them in a different order, or in separate buffers. - Random values are chosen when both are NULL, we never return the generated seeds, rather we may, when/if (d, z) private key support is added, store these in the expanded key, and make them available for import/export. * No need for a stand-by keygen encoded public key buffer when the caller does not provide one (will ask for it later if needed). New `hash_h_pubkey` function can compute the public hash from the expanded form in constant space (384 bytes for 12-bit encoded scalar). * Simplified code in `scalar_mult`. * New `scalar_mult_add` adds the product to an existing scalar. Used in new `matrix_mult_transpose_add` replacing `matrix_mult_transpose`. * Unrolled loop in `encode_12`. * Folded decompression and inverse NTT into vecode_decode, the three were always used together. * Folded inverse NTT into former `matrix_mult` as `matrix_mult_intt`, always used together. * New gencbd_vector_ntt combines CBD vector generation with inverse NTT in one pass. * All this makes for more readable code in `decrypt_cpa` and especially `genkey()`, which no longer requires caller-allocated variant-specific temporary storage (just a single EVP_MD_CTX is still needed). Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26236)
2024-12-22 00:07:33 +08:00
*
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
* 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
*/
#ifndef OPENSSL_HEADER_ML_KEM_H
# define OPENSSL_HEADER_ML_KEM_H
# pragma once
# include <openssl/e_os2.h>
# include <openssl/bio.h>
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
# include <openssl/core_dispatch.h>
# include <crypto/evp.h>
# define ML_KEM_DEGREE 256
/*
* With (q-1) an odd multiple of 256, and 17 ("zeta") as a primitive 256th root
* of unity, the polynomial (X^256+1) splits in Z_q[X] into 128 irreducible
* quadratic factors of the form (X^2 - zeta^(2i + 1)). This is used to
* implement efficient multiplication in the ring R_q via the "NTT" transform.
*/
# define ML_KEM_PRIME (ML_KEM_DEGREE * 13 + 1)
/*
* Various ML-KEM primitives need random input, 32-bytes at a time. Key
* generation consumes two random values (d, z) with "d" plus the rank (domain
* separation) further expanded to two derived seeds "rho" and "sigma", with
* "rho" used to generate the public matrix "A", and sigma to generate the
* private vector "s" and error vector "e".
*
* Encapsulation also consumes one random value m, that is 32-bytes long. The
* resulting shared secret "K" (also 32 bytes) and an internal random value "r"
* are derived from "m" concatenated with a digest of the received public key.
* Use of the public key hash means that the derived shared secret is
* "contributary", it uses randomness from both parties.
*
* The seed "rho" is appended to the public key and allows the recipient of the
* public key to re-compute the matrix "A" when performing encapsulation.
*
* Note that the matrix "m" we store in the public key is the transpose of the
* "A" matrix from FIPS 203!
*/
# define ML_KEM_RANDOM_BYTES 32 /* rho, sigma, ... */
# define ML_KEM_SEED_BYTES (ML_KEM_RANDOM_BYTES * 2) /* Keygen (d, z) */
# define ML_KEM_PKHASH_BYTES 32 /* Salts the shared-secret */
# define ML_KEM_SHARED_SECRET_BYTES 32
# if ML_KEM_PKHASH_BYTES != ML_KEM_RANDOM_BYTES
# error "unexpected ML-KEM public key hash size"
# endif
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/*-
* The ML-KEM specification can be found in
* https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf
*
* Section 8, Table 2, lists the parameters for the three variants:
*
* Variant n q k eta1 eta2 du dv secbits
* ---------- --- ---- - ---- ---- -- -- -------
* ML-KEM-512 256 3329 2 3 2 10 4 128
* ML-KEM-768 256 3329 3 2 2 10 4 192
* ML-KEM-1024 256 3329 4 2 2 11 5 256
*
* where:
*
* - "n" (ML_KEM_DEGREE above) is the fixed degree of the quotient polynomial
* in the ring: "R_q" = Z[X]/(X^n + 1).
* - "q" (ML_KEM_PRIME above) is the fixed prime (256 * 13 + 1 = 3329) used in
* all ML-KEM variants.
* - "k" is the row rank of the square matrix "A", with entries in R_q, that
* defines the "noisy" linear equations: t = A * s + e. Also the rank of
* of the associated vectors.
* - "eta1" determines the amplitude of "s" and "e" vectors in key generation
* and the "y" vector in ML-KEM encapsulation (K-PKE encryption).
* - "eta2" determines the amplitude of "e1" and "e2" noise terms in ML-KEM
* encapsulation (K-PKE encryption).
* - "du" determines how many bits of each coefficient are retained in the
* compressed form of the "u" vector in the encapsulation ciphertext.
* - "dv" determines how many bits of each coefficient are retained in the
* compressed form of the "v" value in encapsulation ciphertext
* - "secbits" is required security strength of the RNG for the random inputs.
*/
/*
* Variant-specific constants and structures
* -----------------------------------------
*/
# define EVP_PKEY_ML_KEM_512 NID_ML_KEM_512
# define ML_KEM_512_BITS 512
# define ML_KEM_512_RANK 2
# define ML_KEM_512_ETA1 3
# define ML_KEM_512_ETA2 2
# define ML_KEM_512_DU 10
# define ML_KEM_512_DV 4
# define ML_KEM_512_SECBITS 128
# define ML_KEM_512_SECURITY_CATEGORY 1
# define EVP_PKEY_ML_KEM_768 NID_ML_KEM_768
# define ML_KEM_768_BITS 768
# define ML_KEM_768_RANK 3
# define ML_KEM_768_ETA1 2
# define ML_KEM_768_ETA2 2
# define ML_KEM_768_DU 10
# define ML_KEM_768_DV 4
# define ML_KEM_768_SECBITS 192
# define ML_KEM_768_SECURITY_CATEGORY 3
# define EVP_PKEY_ML_KEM_1024 NID_ML_KEM_1024
# define ML_KEM_1024_BITS 1024
# define ML_KEM_1024_RANK 4
# define ML_KEM_1024_ETA1 2
# define ML_KEM_1024_ETA2 2
# define ML_KEM_1024_DU 11
# define ML_KEM_1024_DV 5
# define ML_KEM_1024_SECBITS 256
# define ML_KEM_1024_SECURITY_CATEGORY 5
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
# define ML_KEM_KEY_RANDOM_PCT (1 << 0)
# define ML_KEM_KEY_FIXED_PCT (1 << 1)
# define ML_KEM_KEY_PREFER_SEED (1 << 2)
# define ML_KEM_KEY_RETAIN_SEED (1 << 3)
/* Mask to check whether PCT on import is enabled */
# define ML_KEM_KEY_PCT_TYPE \
(ML_KEM_KEY_RANDOM_PCT | ML_KEM_KEY_FIXED_PCT)
/* Default provider flags */
# define ML_KEM_KEY_PROV_FLAGS_DEFAULT \
(ML_KEM_KEY_RANDOM_PCT | ML_KEM_KEY_PREFER_SEED | ML_KEM_KEY_RETAIN_SEED)
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/*
* External variant-specific API
* -----------------------------
*/
typedef struct {
const char *algorithm_name;
size_t prvkey_bytes;
ML-KEM libcrypto implementation polish * Core ML_KEM constants in new <openssl/ml_kem.h> * Renamed variant ordinals to ML_KEM_<bits>_VARIANT, freeing up the unadorned ML_KEM_<bits> names. * Fewer/cleaner macros in <crypto/ml_kem.h> * Fewer/cleaner macros for setting up the ML_KEM_VINFO table. * Made (d, z) be separate inputs to the now single key generation function. Both or neither have to be NULL. This supports potential future callers that store them in a different order, or in separate buffers. - Random values are chosen when both are NULL, we never return the generated seeds, rather we may, when/if (d, z) private key support is added, store these in the expanded key, and make them available for import/export. * No need for a stand-by keygen encoded public key buffer when the caller does not provide one (will ask for it later if needed). New `hash_h_pubkey` function can compute the public hash from the expanded form in constant space (384 bytes for 12-bit encoded scalar). * Simplified code in `scalar_mult`. * New `scalar_mult_add` adds the product to an existing scalar. Used in new `matrix_mult_transpose_add` replacing `matrix_mult_transpose`. * Unrolled loop in `encode_12`. * Folded decompression and inverse NTT into vecode_decode, the three were always used together. * Folded inverse NTT into former `matrix_mult` as `matrix_mult_intt`, always used together. * New gencbd_vector_ntt combines CBD vector generation with inverse NTT in one pass. * All this makes for more readable code in `decrypt_cpa` and especially `genkey()`, which no longer requires caller-allocated variant-specific temporary storage (just a single EVP_MD_CTX is still needed). Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26236)
2024-12-22 00:07:33 +08:00
size_t prvalloc;
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
size_t pubkey_bytes;
ML-KEM libcrypto implementation polish * Core ML_KEM constants in new <openssl/ml_kem.h> * Renamed variant ordinals to ML_KEM_<bits>_VARIANT, freeing up the unadorned ML_KEM_<bits> names. * Fewer/cleaner macros in <crypto/ml_kem.h> * Fewer/cleaner macros for setting up the ML_KEM_VINFO table. * Made (d, z) be separate inputs to the now single key generation function. Both or neither have to be NULL. This supports potential future callers that store them in a different order, or in separate buffers. - Random values are chosen when both are NULL, we never return the generated seeds, rather we may, when/if (d, z) private key support is added, store these in the expanded key, and make them available for import/export. * No need for a stand-by keygen encoded public key buffer when the caller does not provide one (will ask for it later if needed). New `hash_h_pubkey` function can compute the public hash from the expanded form in constant space (384 bytes for 12-bit encoded scalar). * Simplified code in `scalar_mult`. * New `scalar_mult_add` adds the product to an existing scalar. Used in new `matrix_mult_transpose_add` replacing `matrix_mult_transpose`. * Unrolled loop in `encode_12`. * Folded decompression and inverse NTT into vecode_decode, the three were always used together. * Folded inverse NTT into former `matrix_mult` as `matrix_mult_intt`, always used together. * New gencbd_vector_ntt combines CBD vector generation with inverse NTT in one pass. * All this makes for more readable code in `decrypt_cpa` and especially `genkey()`, which no longer requires caller-allocated variant-specific temporary storage (just a single EVP_MD_CTX is still needed). Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26236)
2024-12-22 00:07:33 +08:00
size_t puballoc;
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
size_t ctext_bytes;
ML-KEM libcrypto implementation polish * Core ML_KEM constants in new <openssl/ml_kem.h> * Renamed variant ordinals to ML_KEM_<bits>_VARIANT, freeing up the unadorned ML_KEM_<bits> names. * Fewer/cleaner macros in <crypto/ml_kem.h> * Fewer/cleaner macros for setting up the ML_KEM_VINFO table. * Made (d, z) be separate inputs to the now single key generation function. Both or neither have to be NULL. This supports potential future callers that store them in a different order, or in separate buffers. - Random values are chosen when both are NULL, we never return the generated seeds, rather we may, when/if (d, z) private key support is added, store these in the expanded key, and make them available for import/export. * No need for a stand-by keygen encoded public key buffer when the caller does not provide one (will ask for it later if needed). New `hash_h_pubkey` function can compute the public hash from the expanded form in constant space (384 bytes for 12-bit encoded scalar). * Simplified code in `scalar_mult`. * New `scalar_mult_add` adds the product to an existing scalar. Used in new `matrix_mult_transpose_add` replacing `matrix_mult_transpose`. * Unrolled loop in `encode_12`. * Folded decompression and inverse NTT into vecode_decode, the three were always used together. * Folded inverse NTT into former `matrix_mult` as `matrix_mult_intt`, always used together. * New gencbd_vector_ntt combines CBD vector generation with inverse NTT in one pass. * All this makes for more readable code in `decrypt_cpa` and especially `genkey()`, which no longer requires caller-allocated variant-specific temporary storage (just a single EVP_MD_CTX is still needed). Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26236)
2024-12-22 00:07:33 +08:00
size_t vector_bytes;
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
size_t u_vector_bytes;
int evp_type;
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
int bits;
int rank;
int du;
int dv;
int secbits;
int security_category;
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
} ML_KEM_VINFO;
/* Retrieve global variant-specific parameters */
const ML_KEM_VINFO *ossl_ml_kem_get_vinfo(int evp_type);
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/* Known as ML_KEM_KEY via crypto/types.h */
ML-KEM libcrypto implementation polish * Core ML_KEM constants in new <openssl/ml_kem.h> * Renamed variant ordinals to ML_KEM_<bits>_VARIANT, freeing up the unadorned ML_KEM_<bits> names. * Fewer/cleaner macros in <crypto/ml_kem.h> * Fewer/cleaner macros for setting up the ML_KEM_VINFO table. * Made (d, z) be separate inputs to the now single key generation function. Both or neither have to be NULL. This supports potential future callers that store them in a different order, or in separate buffers. - Random values are chosen when both are NULL, we never return the generated seeds, rather we may, when/if (d, z) private key support is added, store these in the expanded key, and make them available for import/export. * No need for a stand-by keygen encoded public key buffer when the caller does not provide one (will ask for it later if needed). New `hash_h_pubkey` function can compute the public hash from the expanded form in constant space (384 bytes for 12-bit encoded scalar). * Simplified code in `scalar_mult`. * New `scalar_mult_add` adds the product to an existing scalar. Used in new `matrix_mult_transpose_add` replacing `matrix_mult_transpose`. * Unrolled loop in `encode_12`. * Folded decompression and inverse NTT into vecode_decode, the three were always used together. * Folded inverse NTT into former `matrix_mult` as `matrix_mult_intt`, always used together. * New gencbd_vector_ntt combines CBD vector generation with inverse NTT in one pass. * All this makes for more readable code in `decrypt_cpa` and especially `genkey()`, which no longer requires caller-allocated variant-specific temporary storage (just a single EVP_MD_CTX is still needed). Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26236)
2024-12-22 00:07:33 +08:00
typedef struct ossl_ml_kem_key_st {
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/* Variant metadata, for one of ML-KEM-{512,768,1024} */
const ML_KEM_VINFO *vinfo;
/*
* Library context, initially used to fetch the SHA3 MDs, and later for
* random number generation.
*/
OSSL_LIB_CTX *libctx;
/* Pre-fetched SHA3 */
EVP_MD *shake128_md;
EVP_MD *shake256_md;
EVP_MD *sha3_256_md;
EVP_MD *sha3_512_md;
/*
* Pointers into variable size storage, initially all NULL. Appropriate
* storage is allocated once a public or private key is specified, at
* which point the key becomes immutable.
*/
uint8_t *rho; /* Public matrix seed */
uint8_t *pkhash; /* Public key hash */
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
struct ossl_ml_kem_scalar_st *t; /* Public key vector */
struct ossl_ml_kem_scalar_st *m; /* Pre-computed pubkey matrix */
struct ossl_ml_kem_scalar_st *s; /* Private key secret vector */
uint8_t *z; /* Private key FO failure secret */
ML-KEM libcrypto implementation polish * Core ML_KEM constants in new <openssl/ml_kem.h> * Renamed variant ordinals to ML_KEM_<bits>_VARIANT, freeing up the unadorned ML_KEM_<bits> names. * Fewer/cleaner macros in <crypto/ml_kem.h> * Fewer/cleaner macros for setting up the ML_KEM_VINFO table. * Made (d, z) be separate inputs to the now single key generation function. Both or neither have to be NULL. This supports potential future callers that store them in a different order, or in separate buffers. - Random values are chosen when both are NULL, we never return the generated seeds, rather we may, when/if (d, z) private key support is added, store these in the expanded key, and make them available for import/export. * No need for a stand-by keygen encoded public key buffer when the caller does not provide one (will ask for it later if needed). New `hash_h_pubkey` function can compute the public hash from the expanded form in constant space (384 bytes for 12-bit encoded scalar). * Simplified code in `scalar_mult`. * New `scalar_mult_add` adds the product to an existing scalar. Used in new `matrix_mult_transpose_add` replacing `matrix_mult_transpose`. * Unrolled loop in `encode_12`. * Folded decompression and inverse NTT into vecode_decode, the three were always used together. * Folded inverse NTT into former `matrix_mult` as `matrix_mult_intt`, always used together. * New gencbd_vector_ntt combines CBD vector generation with inverse NTT in one pass. * All this makes for more readable code in `decrypt_cpa` and especially `genkey()`, which no longer requires caller-allocated variant-specific temporary storage (just a single EVP_MD_CTX is still needed). Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26236)
2024-12-22 00:07:33 +08:00
uint8_t *d; /* Private key seed */
int prov_flags; /* prefer/retain seed and PCT flags */
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/*
* Fixed-size built-in buffer, which holds the |rho| and the public key
* |pkhash| in that order, once we have expanded key material.
*/
uint8_t rho_pkhash[64]; /* |rho| + |pkhash| */
/*
* With seed-only keys, that are not yet expanded, this holds the
* |z| and |d| components in that order.
*/
uint8_t *seedbuf; /* |z| + |d| temporary secure storage buffer */
uint8_t *encoded_dk; /* Unparsed P8 private key */
ML-KEM libcrypto implementation polish * Core ML_KEM constants in new <openssl/ml_kem.h> * Renamed variant ordinals to ML_KEM_<bits>_VARIANT, freeing up the unadorned ML_KEM_<bits> names. * Fewer/cleaner macros in <crypto/ml_kem.h> * Fewer/cleaner macros for setting up the ML_KEM_VINFO table. * Made (d, z) be separate inputs to the now single key generation function. Both or neither have to be NULL. This supports potential future callers that store them in a different order, or in separate buffers. - Random values are chosen when both are NULL, we never return the generated seeds, rather we may, when/if (d, z) private key support is added, store these in the expanded key, and make them available for import/export. * No need for a stand-by keygen encoded public key buffer when the caller does not provide one (will ask for it later if needed). New `hash_h_pubkey` function can compute the public hash from the expanded form in constant space (384 bytes for 12-bit encoded scalar). * Simplified code in `scalar_mult`. * New `scalar_mult_add` adds the product to an existing scalar. Used in new `matrix_mult_transpose_add` replacing `matrix_mult_transpose`. * Unrolled loop in `encode_12`. * Folded decompression and inverse NTT into vecode_decode, the three were always used together. * Folded inverse NTT into former `matrix_mult` as `matrix_mult_intt`, always used together. * New gencbd_vector_ntt combines CBD vector generation with inverse NTT in one pass. * All this makes for more readable code in `decrypt_cpa` and especially `genkey()`, which no longer requires caller-allocated variant-specific temporary storage (just a single EVP_MD_CTX is still needed). Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26236)
2024-12-22 00:07:33 +08:00
} ML_KEM_KEY;
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/* The public key is always present, when the private is */
# define ossl_ml_kem_key_vinfo(key) ((key)->vinfo)
# define ossl_ml_kem_have_pubkey(key) ((key)->t != NULL)
# define ossl_ml_kem_have_prvkey(key) ((key)->s != NULL)
# define ossl_ml_kem_have_seed(key) ((key)->d != NULL)
# define ossl_ml_kem_have_dkenc(key) ((key)->encoded_dk != NULL)
# define ossl_ml_kem_decoded_key(key) ((key)->encoded_dk != NULL \
|| ((key)->s == NULL && (key)->d != NULL))
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/*
* ----- ML-KEM key lifecycle
*/
/*
* Allocate a "bare" key for given ML-KEM variant. Initially without any public
* or private key material.
*/
ML_KEM_KEY *ossl_ml_kem_key_new(OSSL_LIB_CTX *libctx, const char *properties,
int evp_type);
/* Reset a key clearing all public and private key material */
void ossl_ml_kem_key_reset(ML_KEM_KEY *key);
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/* Deallocate the key */
void ossl_ml_kem_key_free(ML_KEM_KEY *key);
/*
* Duplicate a key, optionally including some key material, per the
* |selection|, see <openssl/core_dispatch.h>.
*/
ML_KEM_KEY *ossl_ml_kem_key_dup(const ML_KEM_KEY *key, int selection);
/*
* ----- Import or generate key material.
*/
/*
* Functions that augment "bare ML-KEM keys" with key material deserialised
* from an input buffer. It is an error for any key material to already be
* present.
*
* Return 1 on success, 0 otherwise.
*/
__owur
int ossl_ml_kem_parse_public_key(const uint8_t *in, size_t len,
ML_KEM_KEY *key);
__owur
int ossl_ml_kem_parse_private_key(const uint8_t *in, size_t len,
ML_KEM_KEY *key);
ML_KEM_KEY *ossl_ml_kem_set_seed(const uint8_t *seed, size_t seedlen,
ML_KEM_KEY *key);
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
__owur
int ossl_ml_kem_genkey(uint8_t *pubenc, size_t publen, ML_KEM_KEY *key);
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
/*
* Perform an ML-KEM operation with a given ML-KEM key. The key can generally
* be either a private or public key, with the exception of encoding a private
* key or performing KEM decapsulation.
*/
__owur
int ossl_ml_kem_encode_public_key(uint8_t *out, size_t len,
const ML_KEM_KEY *key);
__owur
int ossl_ml_kem_encode_private_key(uint8_t *out, size_t len,
const ML_KEM_KEY *key);
__owur
int ossl_ml_kem_encode_seed(uint8_t *out, size_t len,
const ML_KEM_KEY *key);
Multi-variant ML-KEM This introduces support for ML-KEM-512 and ML-KEM-1024 using the same underlying implementation parameterised by a few macros for the associated types and constants. KAT tests are added for ML-KEM 512 and 1024, to complement the previous tests for ML-KEM-768. MLKEM{512,768,1024} TLS "group" codepoints are updated to match the final IANA assigments and to make the additional KEMs known to the TLS layer. The pure-QC MLKEMs are not in the default list of supported groups, and need to be explicitly enabled by the application. Future work will introduce support for hybrids, and for more fine-grained policy of which keyshares a client should send by default, and when a server should request (HRR) a new mutually-supported group that was not sent. Tests for ML-KEM key exchange added to sslapitest to make sure that our TLS client MLKEM{512,768,1024} implementations interoperate with our TLS server, and that MLKEM* are not negotiated in TLS 1.2. Tests also added to excercise non-derandomised ML-KEM APIs, both directly (bypassing the provider layer), and through the generic EVP KEM API (exercising the provider). These make sure that RNG input is used correctly (KAT tests bypass the RNG by specifying seeds). The API interface to the provider takes an "const ML_KEM_VINFO" pointer, (obtained from ossl_ml_kem_get_vinfo()). This checks input and output buffer sizes before passing control to internal code that assumes correctly sized (for each variant) buffers. The original BoringSSL API was refactored to eliminate the opaque public/private key structure wrappers, since these structures are an internal detail between libcrypto and the provider, they are not part of the public (EVP) API. New "clangover" counter-measures added, refined with much appreciated input from David Benjamin (Chromium). The internal steps of "encrypt_cpa" were reordered to reduce the working-set size of the algorithm, now needs space for just two temporary "vectors" rather than three. The "decap" function now process the decrypted message in one call, rather than three separate calls to scalar_decode_1, scalar_decompress and scalar_add. Some loops were unrolled, improving performance of en/decapsulate (pre-expanded vectors and matrix) by around 5%. To handle, however unlikely, the SHA3 primitives not behaving like "pure" functions and failing, the implementation of `decap` was modifed: - To use the KDF to compute the Fujisaki-Okamoto (FO) failure secret first thing, and if that fails, bail out returning an error, a shared secret is still returned at random from the RNG, but it is OK for the caller to not use it. - If any of the subsequently used hash primitives fail, use the computed FO failure secret (OK, despite no longer constant-time) and return success (otherwise the RNG would replace the result). - We quite reasonably assume that chosen-ciphertext attacks (of the correct length) cannot cause hash functions to fail in a manner the depends on the private key content. Support for ML-KEM-512 required adding a centered binomial distribution helper function to deal with η_1 == 3 in just that variant. Some additional comments were added to highlight how the code relates to the ML-KEM specification in FIPS 203. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26172)
2024-11-30 22:20:58 +08:00
__owur
int ossl_ml_kem_encap_seed(uint8_t *ctext, size_t clen,
uint8_t *shared_secret, size_t slen,
const uint8_t *entropy, size_t elen,
const ML_KEM_KEY *key);
__owur
int ossl_ml_kem_encap_rand(uint8_t *ctext, size_t clen,
uint8_t *shared_secret, size_t slen,
const ML_KEM_KEY *key);
__owur
int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen,
const uint8_t *ctext, size_t clen,
const ML_KEM_KEY *key);
/* Compare the public key hashes of two keys */
__owur
int ossl_ml_kem_pubkey_cmp(const ML_KEM_KEY *key1, const ML_KEM_KEY *key2);
#endif /* OPENSSL_HEADER_ML_KEM_H */