getrandom on wasm32)Open and answer this issue on GitHub.
targets, blocked · opened 2026-10-01 · updated 2026-10-08 · 2 comments
Since #275, every grammar’s interner hashes with ahash, keyed at runtime through getrandom 0.3. On wasm32-unknown-unknown, getrandom 0.3 does not compile until the final application picks a backend:
error: The wasm32-unknown-unknown targets are not supported by default; you may need to enable the "wasm_js" configuration flag.
This is a second blocker, not the first one. nikaia-std does not build for that target today with or without ahash, because polling refuses it (polling does not support this target OS). Reproduction:
rustup target add wasm32-unknown-unknown
cargo check -p nikaia-std --release --target wasm32-unknown-unknown
A parser built with Nikaia interns names from its input. If the hash keys are known in advance, an input can be built in which the names collide. Each lookup then probes linearly, and the parse becomes quadratic in the number of names (HashDoS).
| Seed source | Keys | Fit |
|---|---|---|
getrandom with the wasm_js backend (crypto.getRandomValues) |
random per instance | yes, wherever there is a JS host |
getrandom on WASI (wasm32-wasip*) |
random per process | yes |
ahash-compile-time-rng |
baked into the .wasm, readable by anyone who has it |
only where there is no entropy at all, and said so |
std’s RandomState on wasm32-unknown-unknown |
the addresses of a stack and a heap slot (sys/random/unsupported.rs: “isn’t particularly secure”), close to fixed in a wasm address space |
no |
When #111 adds the target:
getrandom’s backend for wasm (wasm_js, or the WASI one), so keys stay runtime-random;ahash-compile-time-rng is used only for a target with no entropy source, and that build says so where the user sees it.I measured how far nikaia-std is from wasm32-unknown-unknown. Command: cargo check -p nikaia-std --release --target wasm32-unknown-unknown, at 0.0.698.
getrandom 0.3 is the first stop, as this issue says. It is reached only through winnow-grammar → ahash (cargo tree -i getrandom). With getrandom = { features = ["wasm_js"] } as a wasm32 dependency and --cfg getrandom_backend="wasm_js", it compiles.
wasm_js backend goes through wasm-bindgen. A plain .js loader (D22, no wasm-bindgen glue) could not instantiate that module.--cfg getrandom_backend="custom". std defines __getrandom_v03_custom over one import, for example env.nikaia_random(ptr, len). The generated .js provides that import with crypto.getRandomValues on the module’s memory. The keys stay random per instance, and no wasm-bindgen is needed.polling is next: “polling does not support this target OS”. It comes in only through crates/unsafe/polled.polled made a non-wasm dependency, five errors are left, all at name resolution:
rt/readiness.rs: std::os::fd and polled;rt/mod.rs:1143 and :1174: io::wait and io::waiting take AsFd;net.rs:269.Type checking does not run past those, so there may be more behind them.
What is behind the compile errors is the actual work of #111. rt::start spawns the I/O worker and the poller thread, and wasm32-unknown-unknown has no threads, so a spawn traps. D24 and D25 say the executor is driven from the host’s event loop, “through the mechanism the target already uses for its I/O worker”. That mechanism does not exist yet. It needs a decision basis before it is built:
<prefix>_poll that the .js calls from the event loop, or an import the module calls to ask for a wake-up;time::sleep reaches setTimeout;fs of Part III 17.1 does without a worker thread.A sync-only first step is possible without it: .wasm, .js and .d.ts for entry points that do not pause, with a pausing entry point refused on this target until the bridge exists. That still needs rt::start to start no threads on wasm32.
Generated by Claude Code
I measured how far nikaia-std is from wasm32-unknown-unknown. Command: cargo check -p nikaia-std --release --target wasm32-unknown-unknown, at 0.0.698.
getrandom 0.3 is the first stop, as this issue says. It is reached only through winnow-grammar → ahash (cargo tree -i getrandom). With getrandom = { features = ["wasm_js"] } as a wasm32 dependency and --cfg getrandom_backend="wasm_js", it compiles.
wasm_js backend goes through wasm-bindgen. A plain .js loader (D22, no wasm-bindgen glue) could not instantiate that module.--cfg getrandom_backend="custom". std defines __getrandom_v03_custom over one import, for example env.nikaia_random(ptr, len). The generated .js provides that import with crypto.getRandomValues on the module’s memory. The keys stay random per instance, and no wasm-bindgen is needed.polling is next: “polling does not support this target OS”. It comes in only through crates/unsafe/polled.polled made a non-wasm dependency, five errors are left, all at name resolution:
rt/readiness.rs: std::os::fd and polled;rt/mod.rs:1143 and :1174: io::wait and io::waiting take AsFd;net.rs:269.Type checking does not run past those, so there may be more behind them.
What is behind the compile errors is the actual work of #111. rt::start spawns the I/O worker and the poller thread, and wasm32-unknown-unknown has no threads, so a spawn traps. D24 and D25 say the executor is driven from the host’s event loop, “through the mechanism the target already uses for its I/O worker”. That mechanism does not exist yet. It needs a decision basis before it is built:
<prefix>_poll that the .js calls from the event loop, or an import the module calls to ask for a wake-up;time::sleep reaches setTimeout;fs of Part III 17.1 does without a worker thread.A sync-only first step is possible without it: .wasm, .js and .d.ts for entry points that do not pause, with a pausing entry point refused on this target until the bridge exists. That still needs rt::start to start no threads on wasm32.
Generated by Claude Code