Skip to contentQbit Wallet is live — add it to Chrome
← All releases
Libraries

qbit-libbitcoinpqc v0.3.1

Release notes

Patch release of qbit-libbitcoinpqc, cut from v0.3.0. It wipes SLH-DSA secret-key material from the stack before key generation and signing return. Keys, signatures and verification results are byte-identical to v0.3.0.

Changes

  • Secret-key scratch is zeroed before return (#5). crypto_sign_seed_keypair and crypto_sign_signature return through one cleanup path that wipes the stack spx_ctx (an exact SK_SEED copy) and optrand. prf_addr, gen_message_random, the SHA-2 finalize helpers, sha256()/sha512() and the AVX2 x8 helpers wipe their local scratch. FORS+C salt-counter exhaustion, which cannot be reached under the signing cap, now also resets *siglen.
  • The released stack is burned once per secret-key call (#6). slh_dsa_keygen, slh_dsa_sign/slh_dsa_sign_with_stats, slh_dsa_secret_key_validate and slh_dsa_derandomize overwrite BITCOIN_PQC_BURN_STACK_BYTES of the stack they released, on success and failure paths. This clears SHA-2 message schedules that compiler spills leave behind, which can be inverted to SK_SEED, SK_PRF and derived seeds. Threaded FORS workers (test/benchmark knob SPX_FORS_THREADS) burn their own stacks.
  • Sanitizer-clean wipe loop (from #14). The secure_zero_local helpers count down without wrapping len, so -fsanitize=unsigned-integer-overflow builds do not trap.
  • crossbeam-epoch 0.9.20 (RUSTSEC-2026-0204, from #4). Lockfile only. The crate reaches the lockfile only through the criterion dev-dependency.
  • Version metadata is 0.3.1. docs/vendored-crypto-provenance.md lists the vendored SPHINCS+ files this release changes.

Not included: #10 (new PqcError::OutOfMemory variant and changed C error codes; this needs a minor release), #4's backend-selection test helpers, #13, and the CI and ruleset changes on main.

Compatibility

  • API and ABI unchanged. No public header declares a new or changed function. The only header change is a comment documenting the stack requirement. The Rust sources (*.rs, including build.rs) are byte-identical to v0.3.0. The library objects export two new internal symbols, slh_dsa_secret_key_validate_unburned and slh_dsa_derandomize_unburned, which no header declares.
  • Outputs unchanged. The golden vectors pass unmodified. A C harness linked against the v0.3.0 and 0.3.1 static libraries produces byte-identical keys and signatures (4 keypairs and 16 signatures, 59,264 bytes, sha256 5f0a2ba45b04406b…).

Stack Requirements

Each secret-key call now overwrites BITCOIN_PQC_BURN_STACK_BYTES of stack below its caller before returning:

  • 16 KiB in optimized native builds (__OPTIMIZE__). Optimized keygen and sign use about 13 KiB below the entry point, so a call needs about 17 KiB of free stack.
  • 208 KiB in unoptimized GCC/Clang builds (Cargo dev profile, CMake Debug), where the -O0 AVX2 transform frame alone is about 190 KiB.
  • 4 KiB under Emscripten.
  • Defining BITCOIN_PQC_BURN_STACK_BYTES at build time overrides the size.

Optimized keygen, validation and signing run on a 64 KiB thread stack (checked with a pthread_attr_setstacksize(65536) thread on x86-64 Linux, clang -O3). Unoptimized builds need more than 208 KiB. Verification does not burn.

Performance

Measured with clang -O3 (CMake Release) on a shared x86-64 Linux host: 3 interleaved runs of 20 iterations, v0.3.0 against 0.3.1.

Call 0.3.0 0.3.1
Sign 144–147 ms 158–164 ms (about +10%)
Keygen 9.5–9.8 ms 10.6–11.1 ms (about +12%)
Secret-key validation 9.6–9.7 ms 10.7–11.1 ms (about +12%)
Verify 1.80–1.86 ms 1.82–1.88 ms (about +1%)

Sign-time key validation. slh_dsa_sign and slh_dsa_sign_with_stats validate the secret key before signing by re-deriving its public root. That costs about 10.7 ms, about 6.7% of a sign. The check was already in 0.3.0. 0.3.1 only routes it through an internal variant that does not burn, so a sign burns the stack once. Callers who validate a key on import and then sign pay for validation twice.

Verification gains only the SHA-2 helper wipes, because it shares those helpers with signing. It does not burn the stack.

Security And Signing Posture

The wipes and the stack burn reduce accidental disclosure of secret-key material through released stack memory. They are not side-channel hardening.

Signing remains deterministic, and deterministic signing is not side-channel hardening. Randomized or hedged signing is not available. Production signing should be limited to trusted local wallet processes, dedicated signing hosts, or comparably isolated key-custody infrastructure. This release does not claim signing support on hostile shared hardware, or resistance to physical side-channel attackers or fault injection. See docs/side-channel-policy.md.

Validation

See the evidence table and the independent review in the release PR (Qbit-Org/qbit-libbitcoinpqc#15). Upstream CI ran on the release commit on a temporary develop branch.