feat(sim): sim_radio_get_params export + fix identity-collision RNG bug

meshcore-solo-site's new cross-visitor relay bridge (Phase 3) needs a way
to read a sim instance's live freq/bw/sf/cr so a WebSocket relay server
can fan traffic out only to other visitors tuned to the same params,
mirroring real LoRa channel isolation. Added sim_radio_get_params()
(examples/companion_radio/main.cpp), reading NodePrefs directly -- the
real live source of truth, since SimRadio::setParams() has always been a
complete no-op (accepts and discards its arguments). Out-params via
pointer, same buffer-pointer idiom sim_radio_poll_tx() already uses;
build_wasm.sh needed HEAPF32/HEAP32 added to EXPORTED_RUNTIME_METHODS so
JS can read them back.

While testing the relay bridge with two independent browser contexts, hit
a real bug: sim_instance_salt() (SimInstance.h) is a pure function of the
simInstanceTag STRING ('hero'/'B'/'R'), so it's only useful for telling
apart same-tab instances -- it's identical for two genuinely different
visitors who both boot a 'hero' instance. Combined with SimRNG::begin()'s
other seed ingredients -- time(NULL) (1-second resolution) and a WASM
heap pointer (no ASLR inside the sandbox, so it's fully deterministic
across independent boots of the same binary) -- two different visitors
landing on the same wall-clock second reliably generated byte-identical
Ed25519 identities (confirmed: two fresh browser contexts launched
together produced provably identical advert packets end to end).

Fixed by mixing in real crypto.getRandomValues()-sourced entropy from the
host page (new sim_instance_entropy(), read the same way simInstanceTag
already is) into both SimRNG::begin() and the twin seeding pattern in
SimRadio::getRngSeed(). Applies to every sim instance uniformly (hero/B/R
all get proper per-session entropy now), not just the new relay path --
strictly an improvement with no compatibility concern, since identity
generation only ever runs once per fresh/empty IDBFS.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iubftDmKNWmkNnhJRz8UH
This commit is contained in:
Jakub
2026-09-04 19:12:36 +02:00
co-authored by Claude Sonnet 5
parent 80c375427a
commit cc01583d53
5 changed files with 69 additions and 4 deletions
+6 -1
View File
@@ -213,6 +213,11 @@ done
# included in the build" -- confirmed by hitting exactly that during Phase
# 3. Purely additive: nothing Phase 2's web/index.html already does
# (sim_enqueue_key() with a plain number, no buffer marshaling) is affected.
#
# HEAPF32,HEAP32 (relay-bridge addition): sim_radio_get_params() writes its
# freq/bw (float) and sf/cr (int) results into a JS-malloc'd scratch buffer
# via out-params -- reading them back needs the typed-array views, same
# reasoning as HEAPU8 above for sim_radio_poll_tx()'s byte buffer.
"$EMXX" \
"${OBJS[@]}" \
-lidbfs.js \
@@ -222,7 +227,7 @@ done
-sEXPORT_NAME=MeshCoreSim \
-sENVIRONMENT=web \
-sEXIT_RUNTIME=0 \
-sEXPORTED_RUNTIME_METHODS=FS,ccall,cwrap,HEAPU8 \
-sEXPORTED_RUNTIME_METHODS=FS,ccall,cwrap,HEAPU8,HEAPF32,HEAP32 \
-sEXPORTED_FUNCTIONS=_main,_malloc,_free \
-o "$OUT_DIR/meshcore_sim.js"