OSC-2026-0004 · github.com/diybitcoinhardware/embit
info clean-run claude-fable-5 2026-08-04 signed: nostr
- Repository
- github.com/diybitcoinhardware/embit
- Commit
- fff7ffa43f6ce088c5ba22cb3877a122bf01dc96
- Scope path
- src/embit/util/
- Model
- claude-fable-5
- Harness
- claude-code
- Prompts
- prompts/entropy-rng-audit-v1.md
- Independent runs
- 1
- Transcript sha256
- 490fdfb27776b3aa20391b7502d86307ad44e39b613fbf047e482e0466db15bd
- Auditor
- TheIcarusWings (theicaruswings)
- Signature
- nostr-schnorr · npub19tzp8lf3klmqj3dz9mz0qnuvjp7uyy9993gmljmyaxs8phztj7wsnujvq5
Scope. Randomness and ECDSA nonce generation in the signing path, and the secp256k1 backend-selection logic, at HEAD fff7ffa4. embit is the shared Bitcoin library under several DIY signers (SeedSigner, Specter-DIY), so this path is high-leverage. In scope: nonce derivation in every backend (native/ctypes/pure-Python), low-R grinding, RFC6979 correctness, and whether a weaker backend can be selected silently. NOT in scope: PSBT parsing, descriptors, Liquid/confidential-transaction code, slip39, the correctness of libsecp256k1 itself, or seed-entropy quality (embit takes entropy from the caller and generates none).
Findings
info OSC-2026-0004-F1 unreviewed
No weakness found in scope. ECDSA nonces are RFC6979-deterministic in every backend: the native/ctypes path uses libsecp256k1's RFC6979 nonce function, and the pure-Python fallback uses its own RFC6979 deterministic_k (util/key.py:452) with extra_data appended per RFC6979 3.6. Signing therefore has no RNG dependency at all, so the Coldcard failure class (weak RNG silently backing key material) cannot arise here. Low-R grinding (ec.py:218) passes a deterministic counter as extra data rather than randomness, so a grind retry cannot yield a repeated nonce across different messages. Observation (not a defect): the pure-Python fallback is not constant-time (scalar mul branches on secret bits; modinv is extended-Euclidean), it can be selected silently by the import-time fallback chain in util/secp256k1.py, and no runtime indicator of the active backend exists. This does not apply to normal DIY hardware, which runs the native C module under MicroPython; it is recorded because a MicroPython build shipped without the native module would fall through silently, which is structurally the Coldcard lesson. No device was demonstrated taking that path.