Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e0d56e0
Import mldsa-native
jakemas Nov 19, 2025
36f59e8
static and inline config
jakemas Nov 19, 2025
cec4b95
Apply new API to modulewapper
jakemas Nov 19, 2025
6ea2f37
add statics to config
jakemas Nov 19, 2025
94d6256
Fix PCT break return value
jakemas Nov 19, 2025
985551c
Test trampoline function for e_aes and gcm to fix delocator issue in bcm
jakemas Nov 19, 2025
92f0293
more delocator attempts
jakemas Nov 20, 2025
167e828
update e_aes.c
jakemas Nov 20, 2025
79ee751
delocator issue found
jakemas Nov 20, 2025
a3da447
mode wrapper addition
jakemas Nov 20, 2025
27a9f1d
debug CI output to show problematic instruction
jakemas Nov 21, 2025
38872b4
Revert "debug CI output to show problematic instruction"
jakemas Nov 21, 2025
cc45a8b
test delocator peg fix for division
jakemas Nov 22, 2025
5980e8f
Merge branch 'main' into import-mldsa-native
jakemas Nov 22, 2025
be91c0f
remove delocator fixes on aes gcm code
jakemas Nov 24, 2025
1b3b661
AES GCM trampoline functions to fix delocator
jakemas Nov 24, 2025
41b1d1c
test fix for windows-11-arm
jakemas Nov 25, 2025
f4ba7c1
test window-11-arm fix part 2
jakemas Nov 25, 2025
9dcd2aa
Merge origin/main into import-mldsa-native - Keep deletion of ml_dsa_…
jakemas Nov 25, 2025
9272e31
test fix for windows-11-arm
jakemas Nov 25, 2025
65eebb1
Revert "test fix for windows-11-arm"
jakemas Nov 25, 2025
a154781
preserve mode_wrapper conditional logic
jakemas Nov 25, 2025
480537e
Revert "preserve mode_wrapper conditional logic"
jakemas Nov 25, 2025
798a877
Merge branch 'main' into import-mldsa-native
jakemas Dec 3, 2025
3aa7951
fix modulewrapper rebase
jakemas Dec 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions crypto/fipsmodule/aes/mode_wrappers.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,33 @@
// function pointer calculation in AES_ctr128_encrypt. Without it,
// on AArch64 there is risk of the calculations requiring a PC-relative
// offset outside of the range (-1MB,1MB) addressable using `ADR`.
static inline void aes_hw_encrypt_wrapper(const uint8_t *in, uint8_t *out,
const AES_KEY *key) {
aes_hw_encrypt(in, out, key);
}

static inline void aes_nohw_encrypt_wrapper(const uint8_t *in, uint8_t *out,
const AES_KEY *key) {
aes_nohw_encrypt(in, out, key);
}

static inline void aes_hw_ctr32_encrypt_blocks_wrapper(const uint8_t *in,
uint8_t *out, size_t len,
const AES_KEY *key,
const uint8_t ivec[16])
{
aes_hw_ctr32_encrypt_blocks(in, out, len, key, ivec);
uint8_t *out, size_t len,
const AES_KEY *key,
const uint8_t ivec[16]) {
aes_hw_ctr32_encrypt_blocks(in, out, len, key, ivec);
}

static inline void aes_nohw_ctr32_encrypt_blocks_wrapper(const uint8_t *in,
uint8_t *out, size_t len,
const AES_KEY *key,
const uint8_t ivec[16]) {
aes_nohw_ctr32_encrypt_blocks(in, out, len, key, ivec);
}

static inline void vpaes_encrypt_wrapper(const uint8_t *in, uint8_t *out,
const AES_KEY *key) {
vpaes_encrypt(in, out, key);
}

#if defined(VPAES_CTR32)
Expand All @@ -73,12 +94,7 @@ static inline void vpaes_ctr32_encrypt_blocks_wrapper(const uint8_t *in,
const uint8_t ivec[16]) {
vpaes_ctr32_encrypt_blocks(in, out, len, key, ivec);
}
#else // VPAES_CTR32
static inline void vpaes_encrypt_wrapper(const uint8_t *in, uint8_t *out,
const AES_KEY *key) {
vpaes_encrypt(in, out, key);
}
#endif // !VPAES_CTR32
#endif

void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
const AES_KEY *key, uint8_t ivec[AES_BLOCK_SIZE],
Expand All @@ -98,7 +114,7 @@ void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
#endif
} else {
CRYPTO_ctr128_encrypt_ctr32(in, out, len, key, ivec, ecount_buf, num,
aes_nohw_ctr32_encrypt_blocks);
aes_nohw_ctr32_encrypt_blocks_wrapper);
}

FIPS_service_indicator_update_state();
Expand Down
18 changes: 9 additions & 9 deletions crypto/fipsmodule/cipher/e_aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,40 +304,40 @@ ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_KEY *gcm_key,
if (hwaes_capable()) {
aes_hw_set_encrypt_key(key, (int)key_bytes * 8, aes_key);
if (gcm_key != NULL) {
CRYPTO_gcm128_init_key(gcm_key, aes_key, aes_hw_encrypt, 1);
CRYPTO_gcm128_init_key(gcm_key, aes_key, aes_hw_encrypt_wrapper, 1);
}
if (out_block) {
*out_block = aes_hw_encrypt;
*out_block = aes_hw_encrypt_wrapper;
}
return aes_hw_ctr32_encrypt_blocks;
return aes_hw_ctr32_encrypt_blocks_wrapper;
}

if (vpaes_capable()) {
vpaes_set_encrypt_key(key, (int)key_bytes * 8, aes_key);
if (out_block) {
*out_block = vpaes_encrypt;
*out_block = vpaes_encrypt_wrapper;
}
if (gcm_key != NULL) {
CRYPTO_gcm128_init_key(gcm_key, aes_key, vpaes_encrypt, 0);
CRYPTO_gcm128_init_key(gcm_key, aes_key, vpaes_encrypt_wrapper, 0);
}
#if defined(BSAES)
assert(bsaes_capable());
return vpaes_ctr32_encrypt_blocks_with_bsaes;
#elif defined(VPAES_CTR32)
return vpaes_ctr32_encrypt_blocks;
return vpaes_ctr32_encrypt_blocks_wrapper;
#else
return NULL;
#endif
}

aes_nohw_set_encrypt_key(key, (int)key_bytes * 8, aes_key);
if (gcm_key != NULL) {
CRYPTO_gcm128_init_key(gcm_key, aes_key, aes_nohw_encrypt, 0);
CRYPTO_gcm128_init_key(gcm_key, aes_key, aes_nohw_encrypt_wrapper, 0);
}
if (out_block) {
*out_block = aes_nohw_encrypt;
*out_block = aes_nohw_encrypt_wrapper;
}
return aes_nohw_ctr32_encrypt_blocks;
return aes_nohw_ctr32_encrypt_blocks_wrapper;
}

#if defined(OPENSSL_32_BIT)
Expand Down
5 changes: 5 additions & 0 deletions crypto/fipsmodule/ml_dsa/META.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: mldsa-native
source: pq-code-package/mldsa-native.git
branch: mldsa-pk-from-sk
commit: bd3181cd84eaba93a38a05461eed771290768e23
imported-at: 2025-11-19T11:54:14-0800
151 changes: 151 additions & 0 deletions crypto/fipsmodule/ml_dsa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# ML-DSA

The source code in this directory implements ML-DSA as defined in
the [FIPS 204 Module-Lattice-Based Digital Signature Standard](https://csrc.nist.gov/pubs/fips/204/final).
It is imported from [mldsa-native](https://github.com/pq-code-package/mldsa-native)
using [importer.sh](importer.sh); see [META.yml](META.yml) for import details.

## Running the importer

To re-run the importer, do

```bash
rm -rf mldsa # Remove old mldsa source
./importer.sh
```

By default, the importer will not run if [mldsa](mldsa) already/still exists. To force removal of any existing [mldsa](mldsa), use `./importer.sh --force`.
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be cleaner to use git ls-remote to check if the current folder is up-to-date, and then replace iff there's a new version (rather than force deleting the existing repo.)


The repository and branch to be used for the import can be configured through the environment variables `GITHUB_REPOSITORY` and `GITHUB_SHA`, respectively. The default is equivalent to

```bash
GITHUB_REPOSITORY=pq-code-package/mldsa-native.git GITHUB_SHA=main ./importer.sh
```

That is, by default importer.sh will clone and install the latest [main](https://github.com/pq-code-package/mldsa-native/tree/main) of mldsa-native.

After a successful import, [META.yml](META.yml) will reflect the source, branch, commit and timestamp of the import.

### Import Scope

mldsa-native has a C-only version as well as native 'backends' in AVX2 and
Neon for high performance. At present, [importer.sh](importer.sh) imports only
the C-only version.

mldsa-native offers its own FIPS-202 implementation, including fast
versions of batched FIPS-202. [importer.sh](importer.sh) does _not_ import those.
Instead, glue-code around AWS-LC's own FIPS-202 implementation is provided in
[fips202_glue.h](fips202_glue.h) and [fips202x4_glue.h](fips202x4_glue.h).

## Configuration and compatibility layer

mldsa-native is used with a custom configuration file [mldsa_native_config.h](mldsa_native_config.h). This file includes
a compatibility layer between AWS-LC/OpenSSL and mldsa-native, covering:

* FIPS/PCT: If `AWSLC_FIPS` is set, `MLD_CONFIG_KEYGEN_PCT` is
enabled to include a PCT.
* FIPS/PCT: If `BORINGSSL_FIPS_BREAK_TESTS` is set,
`MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST` is set and `mld_break_pct`
defined via `boringssl_fips_break_test("MLDSA_PWCT")`, to include
runtime-breakage of the PCT for testing purposes.
* CT: If `BORINGSSL_CONSTANT_TIME_VALIDATION` is set, then
`MLD_CONFIG_CT_TESTING_ENABLED` is set to enable valgrind testing.
* Zeroization: `MLD_CONFIG_CUSTOM_ZEROIZE` is set and `mld_zeroize`
mapped to `OPENSSL_cleanse` to use OpenSSL's zeroization function.
* Randombytes: `MLD_CONFIG_CUSTOM_RANDOMBYTES` is set and `mld_randombytes`
mapped to `RAND_bytes` to use AWS-LC's randombytes function.

## Build process

At the core, mldsa-native is a 'single-level' implementation of ML-DSA:
A build of the main source tree provides an implementation of
exactly one of ML-DSA-44/65/87, depending on the MLD_CONFIG_PARAMETER_SET
parameter. All source files for a single-build of mldsa-native are bundled in
[mldsa_native_bcm.c](mldsa/mldsa_native_bcm.c), which is also imported from
mldsa-native.

To build all security levels, [mldsa_native_bcm.c](mldsa/mldsa_native_bcm.c)
is included three times into [ml_dsa.c](ml_dsa.c), once per security level.
Level-independent code is included only once and shared across the levels;
this is controlled through the configuration options
`MLD_CONFIG_MULTILEVEL_WITH_SHARED` and `MLD_CONFIG_MULTILEVEL_NO_SHARED`
used prior to importing the instances of [mldsa_native_bcm.c](mldsa/mldsa_native_bcm.c) into [ml_dsa.c](ml_dsa.c).

Note that the multilevel build process is entirely internal to `ml_dsa.c`,
and does not affect the AWS-LC build otherwise.

## Formal Verification

All C-code imported by [importer.sh](importer.sh) is formally verified using the
C Bounded Model Checker ([CBMC](https://github.com/diffblue/cbmc/)) to be free of
various classes of undefined behaviour, including out-of-bounds memory accesses and
arithmetic overflow; the latter is of particular interest for ML-DSA because of
the use of lazy modular reduction for improved performance.

The heart of the CBMC proofs are function contract and loop annotations to
the C-code. Function contracts are denoted `__contract__(...)` clauses and
occur at the time of declaration, while loop contracts are denoted
`__loop__` and follow the `for` statement.

The function contract and loop statements are kept in the source, but
removed by the preprocessor so long as the CBMC macro is undefined. Keeping
them simplifies the import, and care has been taken to make them readable
to the non-expert, and thereby serve as precise documentation of
assumptions and guarantees upheld by the code.

## Testing

We KAT ML-DSA with test vectors obtained from https://github.com/post-quantum-cryptography/KAT within `PQDSAParameterTest.KAT`. We select the KATs for the signing mode `hedged`, which derives the signing private random seed (rho) pseudorandomly from the signer's private key, the message to be signed, and a 256-bit string `rnd` which is generated at random. The `pure` variant of these KATs were used, as they provide test vector inputs for "pure" i.e., non-pre-hashed messages. The KAT files have been modified to insert linebreaks between each test vector set.

We also run the ACVP test vectors obtained from https://github.com/usnistgov/ACVP-Server within the three functions `PerMLDSATest.ACVPKeyGen`, `PerMLDSATest.ACVPSigGen` and `PerMLDSATest.ACVPSigVer`. These correspond to the tests found at [ML-DSA-keyGen-FIPS204](https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-keyGen-FIPS204), [ML-DSA-sigGen-FIPS204](https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigGen-FIPS204), and [ML-DSA-sigVer-FIPS204](https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigVer-FIPS204).
To test ML-DSA pure, non-deterministic mode, we use `tgId = 19, 21, 23` of sigGen and `tgId = 7, 9, 11` of sigVer.
To test ML-DSA ExternalMu, non-deterministic mode, we use `tgId = 20, 22, 24` of sigGen and `tgId = 8, 10, 12` of sigVer.

The test suite includes:

* Known Answer Tests (KAT) for all three parameter sets (ML-DSA-44/65/87)
* Functional tests for key generation, signing, and verification
* ExtMu (External Mu) variant tests for pre-hash modes
* ACVP (Automated Cryptographic Validation Protocol) test vectors
* Pairwise Consistency Test (PCT) validation when FIPS mode is enabled
* Key consistency tests including public key derivation from secret key

## Side-channels

mldsa-native's CI uses a patched version of valgrind to check for various
compilers and compile flags that there are no secret-dependent memory
accesses, branches, or divisions. The relevant assertions are kept
and used if `MLD_CONFIG_CT_TESTING_ENABLED` is set, which is the case
if and only if `BORINGSSL_CONSTANT_TIME_VALIDATION` is set.

mldsa-native uses value barriers to block
potentially harmful compiler reasoning and optimization. Where standard
gcc/clang inline assembly is not available, mldsa-native falls back to a
slower 'opt blocker' based on a volatile global -- both are described in
[ct.h](https://github.com/pq-code-package/mldsa-native/blob/main/mldsa/ct.h).

## Comparison to reference implementation

mldsa-native is a fork of the ML-DSA [reference
implementation](https://github.com/pq-crystals/dilithium) (Dilithium).

The following gives an overview of the major changes:

- CBMC and debug annotations, and minor code restructurings or signature
changes to facilitate the CBMC proofs. For example, functions are structured
to make loop bounds and memory access patterns explicit for formal verification.
- Introduction of 4x-batched versions of some functions from the reference
implementation. This is to leverage 4x-batched Keccak-f1600 implementations
if present. The batching happens at the C level even if no native backend
for FIPS 202 is present.
- FIPS 204 compliance: Introduced optional PCT (FIPS 204, Section 4.4, Pairwise
Consistency) and zeroization of stack buffers as required by (FIPS 204,
Section 3.6.3, Destruction of intermediate values).
- Introduction of native backend implementations for AVX2. Those are drop-in
replacements for the corresponding C functions and dispatched at compile-time.
- Restructuring of files to separate level-specific from level-generic
functionality. This is needed to enable a multi-level build of mldsa-native
where level-generic code is shared between levels.
- More pervasive use of value barriers to harden constant-time primitives,
even when Link-Time-Optimization (LTO) is enabled. The use of LTO can lead
to insecure compilation in case of the reference implementation.
Loading
Loading