Dice Roll → BIP39 Verifier
SHA256-of-rolls method (Coldcard rolls.py / SeedSigner / Krux).
This page runs the actual, verbatim source code of each project — the Python
files execute in your browser via a locally bundled CPython/WebAssembly runtime (Pyodide).
Nothing leaves this machine; all assets are local files.
Rolls → mnemonic
Type dice rolls as digits 1–6 (the field is prefilled with fresh random test rolls
on every load — type or paste over them). Canonical lengths: 99 rolls for 24 words, 50 rolls for 12 words.
The words are derived by six implementations: Coldcard's rolls.py (verbatim),
the Coldcard firmware's own on-device dice code (v6.6.0X seed.py crypto core with
the pure-Python bip39.py frozen into the firmware, run verbatim),
SeedSigner's mnemonic_generation.py with the real embit 0.8.0 library (verbatim — also the exact
encoding call Krux makes), Trezor's python-mnemonic (verbatim), iancoleman's jsbip39.js (verbatim JS),
and Kern's dice_rolls.c logic with its pinned libwally-core (verbatim C sources compiled to
WebAssembly). Five independent BIP39 encoders in total.
23 words → valid 24th words
Paste the first 23 words of a 24-word mnemonic; the 8 checksum-valid final words are listed.
Verbatim source versions
The Python columns execute these unmodified files (in web/py/); the iancoleman column
executes the unmodified upstream JS (in web/js/); the Kern column executes the pinned C sources
(reference/kern/, reference/libwally-core/, retrieved 2026-08-17) compiled to WebAssembly
(web/kern/kern.wasm). All other files retrieved 2026-08-10; everything verified byte-identical
to the latest release of each project. Only three kinds of glue are added, all non-cryptographic and clearly marked:
import shims (web/py/seedsigner/, so SeedSigner's file can import outside its app; a 3-line jQuery stub
for jsbip39's constructor), the string-marshalling wrapper compiled into the Kern wasm (web/kern/web_glue.c,
plus linker stubs for elliptic-curve symbols the bip39 code never calls), and the wiring on this page.
| Project | Latest release (date) | Verbatim file(s) @ commit |
|---|---|---|
Coldcard rolls.py | v6.6.0X (2026-07-31) | docs/rolls.py @ 05ac3893 (file last changed 2022-12-19) — Coinkite's official verification script, a standalone implementation separate from the firmware. |
| Coldcard firmware (on-device code) | v6.6.0X (2026-07-31) | shared/seed.py @ tag 2026-07-31T1609-v6.6.0X (8919b84a): the dice path is add_dice_rolls() — sha256(b'') updated with each typed digit — then approve_word_list() truncates to 16 bytes for 12 words and calls bip39.b2a_words(). That bip39 module is pure Python, frozen into the firmware from libngu @ b0ce9acf (the release's submodule pin) — this page runs it byte-identical as web/py/bip39.py, with the seed.py crypto core extracted as coldcard_dice.py (device keypad/screen loop removed; reference/coldcard_seed_verbatim.py holds the untouched file). On-device the SHA256 primitive is MicroPython's uhashlib C module rather than CPython's — the cross-implementation agreement on this page is what covers that layer. |
| SeedSigner | 0.8.7 (2026-07-08) | src/seedsigner/helpers/mnemonic_generation.py @ 0736e066 |
| embit | 0.8.0 (PyPI sdist, 2024-05-30) | complete package — SeedSigner's pinned dependency; runs its pure-Python backend in the browser |
| Krux | v26.08.0 (2026-08-04) | no separate column: Krux D6 (dice_rolls.py @ bfbdaec5) computes the same digest and calls the same embit mnemonic_from_bytes as the SeedSigner column; its UI wrapper only runs on the device. Krux D20 joins rolls with "-" and will NOT match. |
| Kern | 0.0.16 (2026-08-11) | C sources pinned @ 0.0.15 tag 5007930 (byte-identical at 0.0.16): dice_rolls.c (its crypto core extracted as reference/kern_dice.c, LVGL UI removed), bip39_filter.c (fully verbatim — the final-word checksum filter behind manual_input.c), compiled to web/kern/kern.wasm together with Kern's pinned libwally-core subset (odudex fork @ 47e75f96, verbatim — the wally_sha256 and bip39_mnemonic_from_bytes Kern calls). Built by web/kern/build_wasm.sh; tests/test_kern.py compiles the same sources natively and cross-checks them. |
| Trezor python-mnemonic | 0.21 (PyPI sdist, 2024-01-05) | complete package (the BIP39 reference implementation) |
| iancoleman/bip39 | 0.5.6 (2023-08-01) | jsbip39.js, sjcl-bip39.js, wordlist_english.js. Matches only when the SHA256 digest is pasted into the tool as raw hex entropy — its "Dice" mode uses base-6 conversion and will NOT match. |
| Pyodide runtime | 314.0.3 (npm) | local copy in web/pyodide/; CPython compiled to WebAssembly |
| BIP39 wordlist | — | bitcoin/bips bip-0039/english.txt @ ce1862ac, SHA256 2f5eed53…24dbda (used by the checksum panel; the columns use each project's own bundled wordlist) |
Verify the sources yourself
Trust nothing this page claims — check it. Each SHA256 below is computed by your
browser (WebCrypto) from the exact bytes this site served for that file. Run the copied command in a
terminal to fetch the same file from the upstream project (pinned by commit hash or release
tarball — a git commit is content-addressed, so its files can't change without changing the hash) and compare
the two digests. A malicious copy of this page could of course fake this table too — which is why the commands
fetch from upstream, not from here, and why verify_sources.sh in the repo performs the same
byte-for-byte check for every vendored file without involving this page at all.
This table lists the files that produce the words above; the page also executes the rest of the embit package
and the Pyodide lockfile (byte-compared against upstream by verify_sources.sh) and two marked
non-cryptographic shims (web/py/seedsigner/ — repo-authored, no upstream: verify_sources.sh
and the test suite pin their hashes, and they are a few lines each, so read them). TRUST.md spells
out the full model, including what this page can never prove.
| File this page executed | SHA256 of the served bytes | Upstream |
|---|