OSC-2026-0006 · github.com/trezor/python-mnemonic
info clean-run claude-fable-5 2026-08-04 signed: nostr
- Repository
- github.com/trezor/python-mnemonic
- Commit
- b57a5ad77a981e743f4167ab2f7927a55c1e82a8
- Scope path
- src/mnemonic/mnemonic.py
- Model
- claude-fable-5
- Harness
- claude-code
- Prompts
- prompts/entropy-rng-audit-v1.md
- Independent runs
- 1
- Transcript sha256
- e0ab780324dd7b793dfc7de223cb791bc425b95a37ba3ded180e28e885e7dd22
- Auditor
- TheIcarusWings (theicaruswings)
- Signature
- nostr-schnorr · npub19tzp8lf3klmqj3dz9mz0qnuvjp7uyy9993gmljmyaxs8phztj7wsnujvq5
Scope. Entropy sourcing and BIP-39 correctness in the reference implementation at HEAD b57a5ad7. In scope: the RNG behind generate(), strength validation, checksum and 11-bit word encoding in to_mnemonic(), and PBKDF2 parameters in to_seed(). NOT in scope: the wordlists themselves, SLIP-39, language detection heuristics, or downstream projects that vendor this code.
Findings
info OSC-2026-0006-F1 unreviewed
No weakness found in scope. generate() draws entropy from secrets.token_bytes (os.urandom-backed CSPRNG); the weak random module (Mersenne Twister) is absent from the generation path. There is no fallback RNG, build flag, or config switch that could substitute a weaker source, which is the structural opposite of the Coldcard build-time swap. Strength is validated twice (generate() rejects values outside the BIP-39 set; to_mnemonic() re-validates byte length), so a caller cannot obtain a short brute-forceable mnemonic. BIP-39 conformance is correct: SHA-256 checksum, ENT/32 checksum bits, 11-bit indices, and PBKDF2-HMAC-SHA512 at the spec-mandated 2048 rounds with the 'mnemonic' salt prefix and NFKD normalization. Observation (not a defect): the repository's last commit is 2024-08-27, about two years before this audit; BIP-39 is a frozen spec and this implementation is small and complete, so age is not evidence of neglect, but the audited commit is not recent.