Skip to main content

Module stack

Module stack 

Source
Expand description

Large-stack execution guard for lattice signing/keygen.

ML-DSA (the FIPS 204 module-lattice signature) allocates large intermediate working sets on the stack inside the upstream ml-dsa crate: the hedged signing path expands the public matrix A and buffers several polynomial vectors through its rejection-sampling loop, and key generation / verifying-key expansion do the same. Those arrays are fixed-size stack allocations in code we do not control (ml-dsa), so they cannot be boxed onto the heap from this crate.

On runtimes with a small thread stack this overflows and faults the guard page. The two constrained runtimes we ship into have different characteristics:

  • BEAM dirty-CPU scheduler (via the Elixir NIFs): the dirty scheduler thread’s default stack (+sssdcpu, ~320 KB) is far too small and the whole VM dies with SIGBUS. This module provides the fix: run the operation on a dedicated worker thread with a generous stack and block the scheduler on the join — exactly the kind of bounded, blocking work dirty schedulers exist for.

  • Browser WASM (via [crate::wasm]): the shadow stack is a fixed, build-time size with no threads, so the fix there is a linker stack-size bump rather than a worker thread. That is why this module is gated #[cfg(not(target_arch = "wasm32"))] — see the crate’s .cargo/config.toml for the WASM side.

Every consumer that drives ML-DSA signing or keygen from a small-stack native thread should route the call through on_signing_stack rather than re-implementing the guard or pushing a +sssdcpu requirement onto its own vm.args. Verification uses far less stack and does not need this.

Constants§

RECOMMENDED_SIGNING_STACK_BYTES
Recommended stack size, in bytes, for a thread that runs ML-DSA signing or key generation.

Functions§

on_signing_stack
Run f on a dedicated worker thread with RECOMMENDED_SIGNING_STACK_BYTES of stack, returning its value.