Collision demonstration and firmware guard scanner
nobuxpt-entropy-test-readme
https://raw.githubusercontent.com/nobuxpt/coldcard-entropy-test/master/README.md
- Organisation
- nobuxpt
- Evidence role
- Independent primary analysis
- Published
- 2026-08-01
- Source changes
- 0
- Detected differences
- 0
- Unreviewed
- 0
- Copies held
- 1
Two offline tools: a collision simulation over the reduced search space, and a static scanner that flags the defined-ness guard in a firmware source tree. The scanner reads source directories rather than wallets, and neither tool accepts a seed or extended key. ISC licensed, with reference commits cited for the reimplemented generator.
Every check is recorded, including checks that found no text change. A detected edit is therefore bounded between two checks. The publisher's exact save time is not observable from this record. Last checked .
This post is held twice: here, with this project's own note on why it matters, and again as part of the conversation captured at , which is polled for changes. Both copies are the same post; neither is a separate event.
Snapshot and diff bodies for this chain monitor are held in the local evidence archive but withheld from the public site because they can contain the addresses of people who published nothing themselves. Capture times and reviewed change summaries remain available below.
Held captures
-
Recovered from the Internet Archive rather than captured by this project. The row records that third-party provenance separately from captures made by this project.
What changed from the previous capture 0 lines
Extracted text as captured
# COLDCARD Weak-RNG Entropy Test Regression tests for the COLDCARD seed-generation entropy bug (July 2026 advisory). Two tools: 1. **`simulate.py`** — collision test that reproduces the "duplicate wallet found in seconds" demo: the affected RNG chain produces duplicate seeds within millions of generations, while a secure RNG produces none. 2. **`check_firmware.py`** — static source scan that flags the `#ifndef` guard regression in any firmware tree (e.g. the [Coldcard firmware repo] (https://github.com/Coldcard/firmware)). This is **defensive, educational security tooling**: it demonstrates *why* the seed space was weak. It does not contact the Bitcoin network, derive wallet balances, or scan for funds. ## Background Between March 2021 and the July 30 2026 advisory, COLDCARD wallet seeds were generated from the wrong random source. In short: - `generate_seed()` (`shared/seed.py`) calls `ngu.random.bytes(32)`. - libngu (`external/libngu/ngu/random.c`) reads a `rng_get()` symbol. - Its build guard is `#ifndef MICROPY_HW_ENABLE_RNG` — it tests whether the macro is *defined*, not whether it is *enabled*. - The board config defines `MICROPY_HW_ENABLE_RNG (0)`, so the guard passes and the build binds to **MicroPython's Yasmarang software PRNG** fallback (`ports/stm32/rng.c`) instead of the STM32 hardware TRNG. - Yasmarang seeds once from `UID_low32 ^ SysTick->VAL`, `RTC->TR`, `RTC->SSR` — none of which are cryptographic entropy. - libngu then XORs that stream with its *own* Yasmarang seeded from public hardcoded constants, so it stays deterministic. Effective entropy: ~40 bits on Mk2/Mk3 (Block engineering estimate), ~72 bits on Mk4/Q/Mk5. ## `simulate.py` Faithfully reimplements the full vulnerable RNG chain: ``` MicroPython yasmarang fallback ─┐ (UID ^ SysTick, RTC) │ XOR ─> 32 bytes ─> sha256d = seed libngu yasmarang (public consts) ─┘ ``` ### Usage ```bash # ~40-bit state space (Block's estimate) -> collisions by ~1.5M generations python3 simulate.py --mode 40bit --count 1500000 # Worst case: attacker knows UID + RTC, only SysTick varies (~80,000 values)Excerpt only. The complete copy is held offline and backs quotations on this site. The original publication remains the canonical public source.
0 presentation-noise differences. Sidebar, ticker and other page chrome churn that our review classified as not being changes to what the source says.
The excerpts and plain unified diffs above show the text this project held and how it changed. To verify a quotation, compare it against the page itself or against the Internet Archive's copies, which are independent of this project.
Complete captures are held offline rather than mirrored here, so this page shows diffs and excerpts. If a quotation is ever disputed, the full copy can be produced. Ask.
Compare the screenshot or a quotation against the original while it is available.