Skip to content

Add option to allocate large MLDSA objects from a global buffer#786

Open
bensze01 wants to merge 36 commits into
Mbed-TLS:developmentfrom
bensze01:mldsa-buffer-alloc
Open

Add option to allocate large MLDSA objects from a global buffer#786
bensze01 wants to merge 36 commits into
Mbed-TLS:developmentfrom
bensze01:mldsa-buffer-alloc

Conversation

@bensze01

@bensze01 bensze01 commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Resolves #645

PR checklist

  • changelog not required because: MLDSA is not user-visible yet
  • framework PR not required: crypto-only feature
  • TF-PSA-Crypto development PR provided Add option to allocate large MLDSA objects from a global buffer #786
  • TF-PSA-Crypto 1.1 PR not required because: new feature
  • mbedtls development PR not required because: crypto-only feature
  • mbedtls 4.1 PR not required because: crypto-only feature
  • mbedtls 3.6 PR not required because: crypto-only feature
  • tests provided

@bensze01 bensze01 changed the title Mldsa buffer alloc Add option to allocate large MLDSA objects from a global buffer Apr 30, 2026
@bensze01 bensze01 force-pushed the mldsa-buffer-alloc branch 8 times, most recently from d3e85ab to 8b57228 Compare May 6, 2026 16:06
@bensze01 bensze01 force-pushed the mldsa-buffer-alloc branch 5 times, most recently from cfee876 to b937dbf Compare May 13, 2026 16:17
@bensze01 bensze01 force-pushed the mldsa-buffer-alloc branch 3 times, most recently from 39a6e29 to e46c386 Compare May 14, 2026 18:47
@bensze01 bensze01 added enhancement New feature or request size-s Estimated task size: small (~2d) priority-high High priority - will be reviewed soon labels May 18, 2026
@bensze01 bensze01 marked this pull request as ready for review May 18, 2026 15:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds an experimental option TF_PSA_CRYPTO_PQCP_BUFFER_ALLOC that makes mldsa-native allocate its large temporary objects from a single, global, statically-allocated bump buffer instead of the stack. When MBEDTLS_THREADING_C is enabled, access to the buffer is serialized by a new dedicated mutex.

Changes:

  • New pqcp_buffer_alloc.{h,c} defines the global buffer and MLD_CUSTOM_ALLOC/MLD_CUSTOM_FREE macros plumbed into mldsa-native via pqcp-config.h and a per-call empty context stuffed by macros in wrap_mldsa_native.h.
  • A new global mutex mbedtls_threading_pqcp_buffer_alloc_mutex is declared/initialised in platform/threading.{c,h} to guard the buffer.
  • New configuration option (config metadata + scripts + two new CI components exercising the option with and without pthreads).

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
include/psa/crypto_config.h Adds docblock + define for TF_PSA_CRYPTO_PQCP_BUFFER_ALLOC (currently enabled by default; module path also wrong).
scripts/data_files/config-options-current.txt Registers the new option name.
scripts/config.py Excludes the new option from blanket "full" configs.
drivers/pqcp/src/pqcp-config.h Wires MLD_CONFIG_CONTEXT_PARAMETER, MLD_CONFIG_CUSTOM_ALLOC_FREE, and the alloc/free macros into mldsa-native.
drivers/pqcp/src/pqcp_buffer_alloc.h Defines the global buffer, context struct and CUSTOM_ALLOC/CUSTOM_FREE bump-allocator macros.
drivers/pqcp/src/pqcp_buffer_alloc.c Provides the storage for the global buffer.
drivers/pqcp/src/wrap_mldsa_native.h Adds per-function macro wrappers that inject a zero-initialised context argument when context-stuffing is enabled.
drivers/pqcp/src/wrap_mldsa_native.c Disables the new wrapper macros locally so the real function definitions are not affected, and tightens the guard with MBEDTLS_PSA_CRYPTO_C.
platform/threading.c, platform/threading_internal.h Declares/initialises/destroys the new mutex when the option is enabled.
tests/scripts/components-configuration-crypto.sh Adds two CI components covering the new option with and without pthread.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread include/psa/crypto_config.h Outdated
Comment thread include/psa/crypto_config.h Outdated
Comment thread drivers/pqcp/src/pqcp_buffer_alloc.h
Comment thread drivers/pqcp/src/pqcp_buffer_alloc.h Outdated
@gilles-peskine-arm gilles-peskine-arm added the needs-review Every commit must be reviewed by at least two team members label May 18, 2026

@gilles-peskine-arm gilles-peskine-arm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I've done a design review, not yet a full code review.

The design feels more complex and fragile than it needs to be. So please document the rationale. I especially want to understand why a context parameter is needed at all: can't we just make the offset a global variable, given that we end up having only one mldsa-native function active at time anyway?

Comment thread include/psa/crypto_config.h
Comment thread drivers/pqcp/src/pqcp_buffer_alloc.h Outdated
Comment thread drivers/pqcp/src/pqcp_buffer_alloc.h Outdated
Comment thread drivers/pqcp/src/pqcp_buffer_alloc.h Outdated
Comment thread drivers/pqcp/src/pqcp_buffer_alloc.h Outdated
Comment thread drivers/pqcp/src/pqcp_buffer_alloc.h Outdated
Comment thread drivers/pqcp/src/pqcp_buffer_alloc.h
@gilles-peskine-arm gilles-peskine-arm removed the needs-review Every commit must be reviewed by at least two team members label May 19, 2026
bensze01 added 15 commits June 11, 2026 13:45
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
This only affects mldsa65, as all other parameter sets were already
divisible by 32.

Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
We call the RNG rather than letting mldsa-native do so, so these
non-internal functions are unused

Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Extend the smoke test to allow poisoning the buffer allocator's state on
locking or unlocking its mutex.

This allows us to test the macros we use to calculate the memory usage
of individual mldsa-native functions, as well as whether the mutex
effectively controls access to the allocator.

Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
POISON_ON_UNLOCK would leave the allocator in a state that caused the
following unit test to fail.

Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
These pointers need to be initialized before the first call to a macro
that can jump to exit:

Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
bjwtaylor
bjwtaylor previously approved these changes Jun 15, 2026

@bjwtaylor bjwtaylor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved subject to Gilles comments.

bensze01 added 5 commits June 18, 2026 20:09
This reverts commit 3dda749.

Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
Signed-off-by: Bence Szépkúti <bence.szepkuti@arm.com>
@bensze01

Copy link
Copy Markdown
Contributor Author

I've pushed the bulk of the rework - I'll add the multipart testcases, and POISON_ON_START later tonight.

@gilles-peskine-arm gilles-peskine-arm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I have reviewed everything at ef8131f except the changes in .data files, i.e. basically everything except the new poisoning tests. I haven't reviewed that part partly because that's all I have time for today, and partly because as noted below I don't like adding more parameters to the existing functions, but I want to sleep on it.

Other than this aspect, I'm happy with the design and the execution except in a few minor places. (Also the CI is unhappy.)

return status;
}

/* After this point, we may allocate memory, so we must go through

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor: “we may allocate memory” originally only referred to using mbedtls_calloc inside our own code. Now it's both that and the allocator inside mldsa-native which requires us to call tf_psa_crypto_pqcp_alloc_done(). It would help to update this comment.

psa_status_t status = tf_psa_crypto_pqcp_alloc_start();
if (status != PSA_SUCCESS) {
return status;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor: please add a comment reminding that from that point onwards, we must not return without calling tf_psa_crypto_pqcp_alloc_done().

Same in verify_finish.

mbedtls_platform_zeroize(operation, sizeof(*operation));
}
return status;
if (status == PSA_SUCCESS) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor: most places prioritize alloc_status over the “normal” status, but here it's the opposite. That's not really important since apart from programming errors in mldsa-native or in our code, the only case where they're both nonzero should be when they're both INSUFFICIENT_MEMORY.

cleanup:
mbedtls_free(public_key);
psa_status_t alloc_status = tf_psa_crypto_pqcp_alloc_done();
if (status != PSA_SUCCESS) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (status != PSA_SUCCESS) {
if (status != PSA_SUCCESS || alloc_status != PSA_SUCCESS) {

ctest
}

component_test_pqcp_buffer_alloc_own_shake_no_builtin_pthread () {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The mldsa-native shake implementation doesn't use MLD_ALLOC. So, from a white-box perspective, we don't need to test the combination of TF_PSA_CRYPTO_PQCP_OWN_SHAKE and TF_PSA_CRYPTO_PQCP_BUFFER_ALLOC. Given that we're trying to keep the number of all.sh components down, please remove this one, as well as the corresponding line in test_suite_config.crypto_combinations.data.


PSA_INIT();

PSA_ASSERT(poison_setup(poison_mode, poison_bytes));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing poison_cleanup in sign_setup.

return NULL;
}

/* Check that there is room. This shouldn't happen if the buffer size

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor: this hasn't been addressed.


#if defined(TF_PSA_CRYPTO_PQCP_BUFFER_ALLOC)
/* Alignment sanity check*/
TEST_EQUAL(TF_PSA_CRYPTO_PQCP_ALLOC_BUFFER_SIZE % MLD_DEFAULT_ALIGN, 0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The CI points out that MLD_DEFAULT_ALIGN isn't available here.


static void poison_cleanup(void)
{
#if defined(MBEDTLS_TEST_HOOKS)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
#if defined(MBEDTLS_TEST_HOOKS)
#if defined(TF_PSA_CRYPTO_PQCP_BUFFER_ALLOC) && defined(MBEDTLS_TEST_HOOKS)

psa_status_t expected_status)
psa_status_t expected_status,
int poison_mode,
int64_t poison_bytes)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm unsure about the test arrangements. I like the poisoning mechanism. What I don't like much is that it's added to all the test functions. It has quite a few downsides:

  • More complex code in functions whose main goal is to test other aspects: data validation, normal operation or both.
  • More complex test data.
  • In particular the test generator needs to change, which is a bit of a hassle due to the repository split. (You need to make the new behavior an option to the test generator in scripts/maintainer/generate_mldsa_tests.py, like what's already there with multipart=True.)

I'm not fully convinced, but I think it would be better to have dedicated functions for the poisoning. These functions wouldn't need a variety of test data, and they don't need to test the invalid inputs that we reject before calling mldsa-native functions.

@gilles-peskine-arm gilles-peskine-arm added needs-work and removed needs-review Every commit must be reviewed by at least two team members labels Jun 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request needs-work priority-high High priority - will be reviewed soon size-m Estimated task size: medium (~1w)

Projects

Development

Successfully merging this pull request may close these issues.

Configuration option for using a global variable as the ML-DSA workspace

4 participants