Skip to content

Introduce OQS_MEMOPT_BUILD to enable memory‑optimized implementations#2367

Merged
bhess merged 5 commits into
mainfrom
bhe-memopt-build
Mar 6, 2026
Merged

Introduce OQS_MEMOPT_BUILD to enable memory‑optimized implementations#2367
bhess merged 5 commits into
mainfrom
bhe-memopt-build

Conversation

@bhess
Copy link
Copy Markdown
Member

@bhess bhess commented Feb 20, 2026

Introduces a OQS_MEMOPT_BUILD build option, a CMake configuration option (default OFF) that enables selection of memory-optimized algorithm implementations where available.

Motivation

Upstream implementations (such as #2361) provide alternative implementations optimized for reduced memory usage. Without a dedicated build flag, there is no way to automatically select these. This PR adds the infrastructure to let upstreams declare memory-optimized variants in their META.yml files, which liboqs will then expose and prioritize.

How it works

How it works
Upstream library META.yml files declare a memory-optimized implementation by adding memory_optimized: true to an implementation entry alongside regular variants:

implementations:  
- name: memopt    
  memory_optimized: true  
...

When copy_from_upstream processes this:

Sorting: Memory-optimized implementations are moved to the front of the implementation list, so they appear first in the generated #if/#elif dispatch chain.

CMake gating: The OQS_ENABLE_<ALG>_memopt CMake option is wrapped in if(OQS_MEMOPT_BUILD)...endif(), so it can only be switched on when OQS_MEMOPT_BUILD=ON.

Fallback: If no memopt variant exists for an algorithm, nothing changes, and OQS_MEMOPT_BUILD has no effect. If one exists but OQS_MEMOPT_BUILD=OFF, the standard implementation is used.

The PR also modifies the CBOM generation to avoid 'bom-ref' collision if there are multiple generic implementations.

  • Does this PR change the input/output behaviour of a cryptographic algorithm (i.e., does it change known answer test values)? (If so, a version bump will be required from x.y.z to x.(y+1).0.)
  • Does this PR change the list of algorithms available -- either adding, removing, or renaming? Does this PR otherwise change an API? (If so, PRs in fully supported downstream projects dependent on these, i.e., oqs-provider will also need to be ready for review and merge by the time this is merged. Also, make sure to update the list of algorithms in the continuous benchmarking files: .github/workflows/kem-bench.yml and sig-bench.yml)

Documentation and descriptive text assisted with AI.

Add CMake option/oqsconfig define, docs, and template support so
implementations tagged `memory_optimized: true` in upstream META.yml are
built & preferred when the flag is ON.  Copy‑from‑upstream scripts
adjusted accordingly and CI matrix extended.

Updates CBOM generation to avoid collisions in the bom-ref if there are
multiple generic builds. [full tests]

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
@bhess bhess mentioned this pull request Feb 20, 2026
2 tasks
@coveralls
Copy link
Copy Markdown

coveralls commented Feb 20, 2026

Coverage Status

coverage: 83.03%. remained the same
when pulling 099e189 on bhe-memopt-build
into 6b390dd on main.

rben-dev added a commit to mqom/mqom-v2 that referenced this pull request Feb 21, 2026
Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
@bhess bhess marked this pull request as ready for review February 23, 2026 16:40
@bhess bhess requested a review from xuganyu96 February 23, 2026 16:40
@bhess
Copy link
Copy Markdown
Member Author

bhess commented Feb 23, 2026

Marking this ready for review. #2361 currently builds on top of this PR, making use of the memory_optimized flag and can be seen as a test case.

@dstebila dstebila added the needs review Looking for a(nother) review label Feb 24, 2026
Copy link
Copy Markdown
Contributor

@xuganyu96 xuganyu96 left a comment

Choose a reason for hiding this comment

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

The individual suggestions are all cosmetic/readability recommendations, though I have some concerns with how this feature is designed.

Based on prior discussion, my understanding is MEM_OPT is needed because MQOM has memory-optimized implementation. For just one signature scheme, introducing a global build flag seems like overkill. Is it easier instead, to include the memory-optimized implementation as "just another implementation" that can be enabled/disabled in the same way x86_64/aarch64-optimized builds are enabled/disabled?

Comment thread scripts/copy_from_upstream/src/sig/family/sig_scheme.c Outdated
Comment thread scripts/update_alg_support_table.py Outdated
@bhess
Copy link
Copy Markdown
Member Author

bhess commented Feb 26, 2026

Thanks for your review @xuganyu96.

Based on prior discussion, my understanding is MEM_OPT is needed because MQOM has memory-optimized implementation. For just one signature scheme, introducing a global build flag seems like overkill. Is it easier instead, to include the memory-optimized implementation as "just another implementation" that can be enabled/disabled in the same way x86_64/aarch64-optimized builds are enabled/disabled?

Valid point. I deliberately made this a more generic feature with respect to mlkem-native/mldsa-native, which will also introduce a memory‑optimized variant. This ensures that the MEMOPT feature is available there as well. I expect users on memory‑constrained devices to be particularly interested in such a configuration option.

@baentsch
Copy link
Copy Markdown
Member

Thanks for your review @xuganyu96.

Based on prior discussion, my understanding is MEM_OPT is needed because MQOM has memory-optimized implementation. For just one signature scheme, introducing a global build flag seems like overkill. Is it easier instead, to include the memory-optimized implementation as "just another implementation" that can be enabled/disabled in the same way x86_64/aarch64-optimized builds are enabled/disabled?

Valid point. I deliberately made this a more generic feature with respect to mlkem-native/mldsa-native, which will also introduce a memory‑optimized variant. This ensures that the MEMOPT feature is available there as well. I expect users on memory‑constrained devices to be particularly interested in such a configuration option.

The thought voiced by @xuganyu96 was exactly the reason for my comment in a call a few weeks back why this isn't just (introduced as yet) another variant (of the one specific algorithm having this feature). The explanation by @bhess of course now explains why a more generic approach makes sense.

Can I suggest to introduce such new generic facilities via a new issue, though, to enable broader discussion/information dissemination? This would make clear the benefits and also allow us to communicate this upstream (to other algorithm providers to invite them to also make such options available) and downstream (to users to inform them about this optimization option -- and of course document which algorithms benefit from this). Otherwise this sounds a bit like an afterthought meant to benefit only those algorithms we happen to have more information about than others.

More generally, this was the thing that originally attracted me to OQS: The team's willingness to support the broader PQC algorithm base, the identical treatment of all algorithms. I feel the project deviating from this "impartiality" and would like to invite everyone to help keep this in the back of their minds doing new things.

@bhess
Copy link
Copy Markdown
Member Author

bhess commented Feb 27, 2026

Can I suggest to introduce such new generic facilities via a new issue, though, to enable broader discussion/information dissemination? This would make clear the benefits and also allow us to communicate this upstream (to other algorithm providers to invite them to also make such options available) and downstream (to users to inform them about this optimization option -- and of course document which algorithms benefit from this). Otherwise this sounds a bit like an afterthought meant to benefit only those algorithms we happen to have more information about than others.

Good point, and apologies for the oversight, I was focused on keeping the momentum and unblock #2361. I've opened #2371 for that broader discussion and ensure these facilities are properly documented for everyone.

bhess added 3 commits March 4, 2026 15:17
Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Copy link
Copy Markdown
Contributor

@xuganyu96 xuganyu96 left a comment

Choose a reason for hiding this comment

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

I am still confused about the relationship between the global MEMOPT flag and individual memory-optimized builds. Will all schemes switch to memory-optimized builds when the global flag is turned on? Will users have the option to choose non-memory-optimized build for one scheme and a memory-optimized build for another scheme in the same build?

Also, I assume that the relevant code changes will be applied to kem.c once memory-optimized ML-KEM from mlkem-native ships?

@bhess
Copy link
Copy Markdown
Member Author

bhess commented Mar 5, 2026

I am still confused about the relationship between the global MEMOPT flag and individual memory-optimized builds. Will all schemes switch to memory-optimized builds when the global flag is turned on? Will users have the option to choose non-memory-optimized build for one scheme and a memory-optimized build for another scheme in the same build?

Also, I assume that the relevant code changes will be applied to kem.c once memory-optimized ML-KEM from mlkem-native ships?

Here's the intended behavior: When the global OQS_MEMOPT_BUILD flag is ON, it sets the default for all schemes, selecting the memory-optimized variant wherever one is provided. I expect this is the primary use case: on memory-constrained platforms, users generally want all schemes to minimize their footprint by default.

However, users can still mix. For example, one could set the global flag to ON but explicitly set -DOQS_ENABLE_SIG_<scheme>_MEMOPT=OFF to use the standard build for a specific algorithm.

Regarding KEMs: yes, the same logic will apply. Once a memory-optimized ML-KEM is available in mlkem-native.

Copy link
Copy Markdown
Member

@baentsch baentsch left a comment

Choose a reason for hiding this comment

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

LGTM, Thanks @bhess! Documentation is clear & testing is added. Only nits: 1) Worthwhile pointing to this facility in https://github.com/open-quantum-safe/liboqs/wiki/Contributing-guide (when landed) such as for upstreams to know/read about this facility? 2) New test takes 18mins, i.e., more than the targeted 15.

@bhess
Copy link
Copy Markdown
Member Author

bhess commented Mar 5, 2026

  1. New test takes 18mins, i.e., more than the targeted 15.

I noticed the test always runs in PRs, even though it's technically part of the [full tests] suite where we allow up to 30 minutes. It seems the PR workflows always trigger "platform-tests" by default, whereas only the push tests actually check for the [full tests] string in the commit message.

Should we update the PR tests to also require this tag so we stay within the 15-minute target for standard runs?

@baentsch
Copy link
Copy Markdown
Member

baentsch commented Mar 5, 2026

Should we update the PR tests to also require this tag so we stay within the 15-minute target for standard runs?

Conceptually an OK approach but this creates the risk that such tests don't get run at all then. They then at least should be triggered at merge -- albeit that may be too late if they'd discover a problem...

Just thinking out loud: What about auto-triggering [full tests] after a first positive review has been provided? That would take them off the critical path, not run them too often, nor too rarely.

@bhess
Copy link
Copy Markdown
Member Author

bhess commented Mar 6, 2026

Should we update the PR tests to also require this tag so we stay within the 15-minute target for standard runs?

Conceptually an OK approach but this creates the risk that such tests don't get run at all then. They then at least should be triggered at merge -- albeit that may be too late if they'd discover a problem...

Just thinking out loud: What about auto-triggering [full tests] after a first positive review has been provided? That would take them off the critical path, not run them too often, nor too rarely.

I've created an issue to track this: #2375

Given the approvals I'd go ahead merging this PR unless there are any objections. Will update https://github.com/open-quantum-safe/liboqs/wiki/Contributing-guide once merged.

@bhess bhess merged commit a2fb264 into main Mar 6, 2026
107 checks passed
rben-dev added a commit to rben-dev/liboqs that referenced this pull request Mar 18, 2026
- memopt variant of the algorithm allowed using PR open-quantum-safe#2367
- common files for all variants are factorized using PR open-quantum-safe#2382

[extended tests]

Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>
rben-dev added a commit to rben-dev/liboqs that referenced this pull request Mar 18, 2026
- memopt variant of the algorithm allowed using PR open-quantum-safe#2367
- common files for all variants are factorized using PR open-quantum-safe#2382

[extended tests]

Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>
xuganyu96 pushed a commit to rben-dev/liboqs that referenced this pull request Mar 18, 2026
- memopt variant of the algorithm allowed using PR open-quantum-safe#2367
- common files for all variants are factorized using PR open-quantum-safe#2382

[extended tests]

Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>
dstebila pushed a commit that referenced this pull request Apr 7, 2026
* Add common dependencies with include_only

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Remove incorrect debug print in copy_from_upstream

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Add readme for copy_from_upstream

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Import MQOM:
- memopt variant of the algorithm allowed using PR #2367
- common files for all variants are factorized using PR #2382

[extended tests]

Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>

---------

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>
Co-authored-by: Basil Hess <bhe@zurich.ibm.com>
@dstebila dstebila deleted the bhe-memopt-build branch April 7, 2026 19:27
Nelonn pushed a commit to Nelonn/liboqs that referenced this pull request Apr 8, 2026
* Add common dependencies with include_only

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Remove incorrect debug print in copy_from_upstream

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Add readme for copy_from_upstream

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Import MQOM:
- memopt variant of the algorithm allowed using PR open-quantum-safe#2367
- common files for all variants are factorized using PR open-quantum-safe#2382

[extended tests]

Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>

---------

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>
Co-authored-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>
dstebila added a commit that referenced this pull request Apr 14, 2026
* fix: build on windows clang

Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

* Update CMakeLists.txt

Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

* Update CMakeLists.txt

Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

* Pin Wycheproof test vectors to last good commit (#2393)

This is a temporary solution for unblocking CI pipeline; a more
permanent fix is needed to incorporate new test cases

Signed-off-by: Ganyu (Bruce) Xu <g66xu@uwaterloo.ca>
Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

* sntrup761: replace PQClean code with public domain OpenSSH code (#2356)

* sntrup761: replace PQClean code with public domain OpenSSH code

Signed-off-by: Billy Brumley <bbb@iki.fi>

* Update top-level LICENSE file

Signed-off-by: Douglas Stebila <dstebila@uwaterloo.ca>

* [src/kem/ntruprime/sntrup761_openssh] use macro for explicit_bzero

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [src/kem/ntruprime/sntrup761_openssh] assign values to volatiles to make stricter android ld.lld happy

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [src/kem/ntruprime/sntrup761_openssh] drop attributes for MSVC

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [src/kem/ntruprime/sntrup761_openssh] alloca for stack allocated variable length arrays

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [src/kem/ntruprime/sntrup761_openssh] MSVC doesn't like variable length arrays on the stack; script to modify upstream source

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [src/kem/ntruprime/sntrup761_openssh] sntrup761.sh: resulting changes

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [docs/algorithms/kem] YAML doc update for sntrup761

Signed-off-by: Billy Brumley <bbb@iki.fi>

* doc: copy_from_upstream.py changes for sntrup761 from OpenSSH

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [.github] CODEOWNERS: sntrup761, sign up for /src/kem/ntruprime

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [docs/algorithms/kem] sntrup761 from upstream OpenSSH has no runtime featurization

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [src/kem/ntruprime] add OPENSSH prefix and use it

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [docs/algorithms/kem] sntrup761: markdown fix, are implementations chosen based on runtime CPU feature detection

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [src/kem/ntruprime/sntrup761_openssh] sntrup761: use __builtin_alloca intrinsic as a fallback for alloca in non-MSVC cases

Signed-off-by: Billy Brumley <bbb@iki.fi>

* [extended tests] sntrup761: add CT exception for rejection sampling

Signed-off-by: Billy Brumley <bbb@iki.fi>

---------

Signed-off-by: Billy Brumley <bbb@iki.fi>
Signed-off-by: Douglas Stebila <dstebila@uwaterloo.ca>
Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Co-authored-by: Douglas Stebila <dstebila@uwaterloo.ca>
Co-authored-by: Basil Hess <bhe@zurich.ibm.com>
Co-authored-by: Douglas Stebila <dstebila@users.noreply.github.com>
Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

* Add MQOM to liboqs (#2385)

* Add common dependencies with include_only

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Remove incorrect debug print in copy_from_upstream

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Add readme for copy_from_upstream

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Import MQOM:
- memopt variant of the algorithm allowed using PR #2367
- common files for all variants are factorized using PR #2382

[extended tests]

Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>

---------

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>
Co-authored-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

* Update mlkem-native to v1.1.0 (#2376)

* Update mlkem-native to v1.1.0 [full tests] [extended tests]

Signed-off-by: Matthias J. Kannwischer <matthias@kannwischer.eu>

* ML-KEM: Remove constant-time passes whitelist [full tests] [extended tests]

This commit removes the constant time passes which for ML-KEM that is used
to suppress the false positives of the constant-time tests.
This is no longer needed with mlkem-native as mlkem-native does explicit
declassifications for public data that is being branched on.

Signed-off-by: Matthias J. Kannwischer <matthias@kannwischer.eu>

---------

Signed-off-by: Matthias J. Kannwischer <matthias@kannwischer.eu>
Co-authored-by: Douglas Stebila <dstebila@users.noreply.github.com>
Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

* Fix mismatched macros in LMS variants (#2379)

Signed-off-by: Abhi S <saxena_abhinav@icloud.com>
Co-authored-by: Douglas Stebila <dstebila@users.noreply.github.com>
Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

* Bump the pip group across 2 directories with 1 update (#2389)

Bumps the pip group with 1 update in the /.github/workflows directory: [requests](https://github.com/psf/requests).
Bumps the pip group with 1 update in the /scripts/copy_from_upstream directory: [requests](https://github.com/psf/requests).

Updates `requests` from 2.32.4 to 2.33.0
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.4...v2.33.0)

Updates `requests` from 2.32.4 to 2.33.0
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.4...v2.33.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.33.0
  dependency-type: direct:production
  dependency-group: pip
- dependency-name: requests
  dependency-version: 2.33.0
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>

---------

Signed-off-by: Nelonn <42481486+Nelonn@users.noreply.github.com>
Signed-off-by: Ganyu (Bruce) Xu <g66xu@uwaterloo.ca>
Signed-off-by: Billy Brumley <bbb@iki.fi>
Signed-off-by: Douglas Stebila <dstebila@uwaterloo.ca>
Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>
Signed-off-by: Matthias J. Kannwischer <matthias@kannwischer.eu>
Signed-off-by: Abhi S <saxena_abhinav@icloud.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Bruce <g66xu@uwaterloo.ca>
Co-authored-by: Billy Brumley <bbb@iki.fi>
Co-authored-by: Douglas Stebila <dstebila@uwaterloo.ca>
Co-authored-by: Basil Hess <bhe@zurich.ibm.com>
Co-authored-by: Douglas Stebila <dstebila@users.noreply.github.com>
Co-authored-by: Ryad Benadjila <ryadbenadjila@gmail.com>
Co-authored-by: Matthias J. Kannwischer <matthias@kannwischer.eu>
Co-authored-by: Abhi S <150999537+abhi-dev-engg@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
will-bates11 pushed a commit to will-bates11/liboqs that referenced this pull request Apr 14, 2026
* Add common dependencies with include_only

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Remove incorrect debug print in copy_from_upstream

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Add readme for copy_from_upstream

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>

* Import MQOM:
- memopt variant of the algorithm allowed using PR open-quantum-safe#2367
- common files for all variants are factorized using PR open-quantum-safe#2382

[extended tests]

Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>

---------

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Ryad Benadjila <ryadbenadjila@gmail.com>
Co-authored-by: Basil Hess <bhe@zurich.ibm.com>
Signed-off-by: Will Bates <william.bates11@outlook.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs review Looking for a(nother) review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants