From 6c5d90434e12ddceb5b84dfad743d0dcda56add6 Mon Sep 17 00:00:00 2001 From: Nexlab-One Date: Thu, 20 Aug 2026 17:07:47 +0200 Subject: [PATCH 1/2] fix(ml-dsa): drop the redundant hex dependency that forced std on no_std consumers hex was declared unconditionally and non-optionally in [dependencies] while already being present in [dev-dependencies]. There are zero hex:: uses anywhere under src/ -- it is used only by the tests (wycheproof, nistkats, acvp, wire_format, avx2_independent_verify) -- so the entry was pure redundancy. It was not harmless redundancy. hex does not declare #![no_std] unless its own std feature is off, so an unconditional edge to it forced std into every no_std consumer of this crate. That is what broke GIPs bare-metal build cargo check -p gip-packet --no-default-features --target thumbv7em-none-eabihf which reaches lib-q-ml-dsa as a mandatory dependency of gip-crypto. No compiled code changes: cargo check -p lib-q-ml-dsa and --tests both clean. --- lib-q-ml-dsa/Cargo.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib-q-ml-dsa/Cargo.toml b/lib-q-ml-dsa/Cargo.toml index 7c82c2f2..7ba49a6c 100644 --- a/lib-q-ml-dsa/Cargo.toml +++ b/lib-q-ml-dsa/Cargo.toml @@ -31,7 +31,13 @@ lib-q-platform = { path = "../lib-q-platform", version = "0.0.11" } lib-q-keccak = { path = "../lib-q-keccak", version = "0.0.11", features = ["simd"] } lib-q-random = { path = "../lib-q-random", version = "0.0.11", optional = true } hax-lib.workspace = true -hex = { workspace = true } +# `hex` is deliberately NOT a normal dependency: it is used only by this crate's tests +# (wycheproof, nistkats, acvp, wire_format, avx2_independent_verify) and is already declared +# in [dev-dependencies] below. The redundant entry here was unconditional and non-optional, +# and `hex` does not declare #![no_std] unless its own `std` feature is off -- so it forced +# std into every no_std consumer of this crate, which is what broke GIP's +# `cargo check -p gip-packet --target thumbv7em-none-eabihf` build. Zero `hex::` uses exist +# anywhere under src/, so removing it changes no compiled code. zeroize = { workspace = true, optional = true } subtle = { workspace = true, optional = true } getrandom = { workspace = true, optional = true, default-features = false } From c96add671fc70802ac0917af8025eb0cf262fbc7 Mon Sep 17 00:00:00 2001 From: Nexlab-One Date: Thu, 20 Aug 2026 17:40:01 +0200 Subject: [PATCH 2/2] fix(lib-q-ml-dsa, lib-q-ml-kem): stop forcing std through no_std dependency edges Needed for GIP's cross-target-thumb-packet CI job (cargo check --no-default-features --target thumbv7em-none-eabihf), which depends on lib-q-ml-dsa and lib-q-ml-kem through gip-crypto in alloc-only no_std mode. lib-q-ml-dsa: - lib-q-ring/lib-q-sha3/lib-q-intrinsics/lib-q-platform/lib-q-random dependencies had no default-features = false, so they always pulled their own std defaults regardless of lib-q-ml-dsa's own feature selection. - lib-q-keccak dependency likewise had no default-features = false, unconditionally pulling lib-q-keccak's default (std + asm) even when only the `simd` feature was requested. - the `random` feature forced `lib-q-random/std` when it should only need `lib-q-random/alloc` (RNG plumbing, not full std). - `std = []` was a no-op; now properly forwards to each dependency's own std feature so std mode still links everything it used to. lib-q-ml-kem: - same `random` feature bug (forced `lib-q-random/std` instead of `/alloc`). - `lib-q-random` dependency (both the optional normal dep and the dev-dependency) had no default-features override, again pulling std unconditionally. - moved [dev-dependencies] to [target.'cfg(not(target_os = "none"))'.dev-dependencies]: Cargo does not isolate dev-dependency feature requests from normal-dependency feature requests for the same target, so this crate's own dev-deps (which needed lib-q-random/std for a host-only conformance test) were forcing std even on bare-metal (target_os = "none") builds that only check the lib. All manifest/feature-gating only; no algorithm or constant changes. Verified: cargo test -p lib-q-ml-dsa (6/6 wycheproof passed) and cargo test -p lib-q-ml-kem (all passed) at default (std) features; cargo check -p lib-q-ml-dsa, lib-q-ml-kem, lib-q-keccak, lib-q, lib-q-sig, lib-q-kem, lib-q-hpke all OK. --- lib-q-ml-dsa/Cargo.toml | 16 ++++++++-------- lib-q-ml-kem/Cargo.toml | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib-q-ml-dsa/Cargo.toml b/lib-q-ml-dsa/Cargo.toml index 7ba49a6c..29d562b0 100644 --- a/lib-q-ml-dsa/Cargo.toml +++ b/lib-q-ml-dsa/Cargo.toml @@ -24,12 +24,12 @@ ignored = [ bench = false [dependencies] -lib-q-ring = { path = "../lib-q-ring", version = "0.0.11", default-features = false, features = ["std"] } -lib-q-sha3 = { path = "../lib-q-sha3", version = "0.0.11" } -lib-q-intrinsics = { path = "../lib-q-intrinsics", version = "0.0.11" } -lib-q-platform = { path = "../lib-q-platform", version = "0.0.11" } -lib-q-keccak = { path = "../lib-q-keccak", version = "0.0.11", features = ["simd"] } -lib-q-random = { path = "../lib-q-random", version = "0.0.11", optional = true } +lib-q-ring = { path = "../lib-q-ring", version = "0.0.11", default-features = false, features = ["alloc"] } +lib-q-sha3 = { path = "../lib-q-sha3", version = "0.0.11", default-features = false, features = ["alloc"] } +lib-q-intrinsics = { path = "../lib-q-intrinsics", version = "0.0.11", default-features = false } +lib-q-platform = { path = "../lib-q-platform", version = "0.0.11", default-features = false } +lib-q-keccak = { path = "../lib-q-keccak", version = "0.0.11", default-features = false, features = ["simd"] } +lib-q-random = { path = "../lib-q-random", version = "0.0.11", optional = true, default-features = false, features = ["alloc"] } hax-lib.workspace = true # `hex` is deliberately NOT a normal dependency: it is used only by this crate's tests # (wycheproof, nistkats, acvp, wire_format, avx2_independent_verify) and is already declared @@ -103,10 +103,10 @@ simd128 = ["lib-q-sha3/asm", "lib-q-intrinsics/simd128"] # ARM NEON optimizatio simd256 = ["lib-q-sha3/asm", "lib-q-keccak/std", "lib-q-intrinsics/simd256"] # x86_64 AVX2 optimizations # Standard library support -std = [] +std = ["lib-q-ring/std", "lib-q-sha3/std", "lib-q-intrinsics/std", "lib-q-platform/std", "lib-q-random?/std"] # Random number generation -random = ["dep:lib-q-random", "lib-q-random/std"] +random = ["dep:lib-q-random", "lib-q-random/alloc"] nist-drbg = ["random", "lib-q-random/nist-drbg"] # NIST SP 800-90A DRBG for KAT compatibility # Security hardening diff --git a/lib-q-ml-kem/Cargo.toml b/lib-q-ml-kem/Cargo.toml index 234c3c8e..768bed74 100644 --- a/lib-q-ml-kem/Cargo.toml +++ b/lib-q-ml-kem/Cargo.toml @@ -22,9 +22,9 @@ ignored = [ ] [features] default = ["std"] -std = [] # When enabled, the crate is not `#![no_std]` (links `std`, providing the global allocator required by the `cdylib` output). `no_std` consumers must use `default-features = false`. +std = ["lib-q-random?/std"] # When enabled, the crate is not `#![no_std]` (links `std`, providing the global allocator required by the `cdylib` output). `no_std` consumers must use `default-features = false`. deterministic = [] # Expose deterministic generation and encapsulation functions -random = ["dep:lib-q-random", "lib-q-random/std"] +random = ["dep:lib-q-random", "lib-q-random/alloc"] # JS/WASM bindings handle decapsulation keys and shared secrets; the `zeroize` crate is always linked for safe memory hygiene on the Rust side of the boundary. wasm = [ "wasm-bindgen", @@ -50,7 +50,7 @@ pkcs8 = ["dep:der"] hybrid-array = { workspace = true, features = ["extra-sizes"] } rand_core = { workspace = true } lib-q-sha3 = { path = "../lib-q-sha3", version = "0.0.11" } -lib-q-random = { path = "../lib-q-random", version = "0.0.11", optional = true } +lib-q-random = { path = "../lib-q-random", version = "0.0.11", optional = true, default-features = false } zeroize = { workspace = true, default-features = false, features = ["alloc"] } subtle = { workspace = true, default-features = false } getrandom = { workspace = true, optional = true, default-features = false } @@ -78,7 +78,7 @@ crate-type = ["cdylib", "rlib"] [package.metadata.wasm-pack.profile.release] wasm-opt = ["-Oz", "--enable-bulk-memory"] -[dev-dependencies] +[target.'cfg(not(target_os = "none"))'.dev-dependencies] # Conformance test only: `lib-q-types` holds the sizes `lib-q-core::SecurityConstants` reads; # this crate asserts its own real computed sizes match, so drift fails CI on either side. lib-q-types = { path = "../lib-q-types", version = "0.0.11", default-features = false }