What went wrong
In plain English
A wallet seed is only as unguessable as the randomness used to create it. Because of a build-configuration mistake, certain COLDCARD firmware versions asked for randomness from what the code appeared to treat as the dedicated hardware random-number generator, but the request was quietly served by a predictable software substitute instead. Seeds created that way had less unpredictability behind them than intended.
Technical detail
Technical detail
Entropy is the measure of how much genuine unpredictability went into a secret. A 24-word BIP39 seed is meant to carry 256 bits of entropy, and a 12-word seed 128 bits. That number, not the length of the phrase, is what makes a seed infeasible to guess.
Coinkite describes the cause as a complex and subtle series of bugs that prevented the hardware random-number generator from contributing randomness in certain firmware versions. In 2021, COLDCARD moved its elliptic-curve operations to the same libsecp256k1 implementation used by Bitcoin Core, which required adding libNgU, an embedded MicroPython library. During that migration, seed generation moved from ckcc.rng_bytes() to ngu.random.bytes(). Coinkite states that the second path resolved to MicroPython’s software fallback rather than COLDCARD’s hardware implementation.
The build did not fail, because both implementations exposed the same function signature. Coinkite explains that MICROPY_HW_ENABLE_RNG was explicitly set to zero on the assumption that neither MicroPython implementation was needed, while the guard meant to catch a missing hardware generator used #ifndef, which tests only whether a macro is defined and not whether its value is non-zero. A macro defined as zero satisfied that test, so compilation proceeded with the software fallback linked in.
Coinkite notes that the MicroPython fallback itself was introduced upstream in May 2018, and did not enter COLDCARD wallet seed generation until the libNgU migration in March 2021. The eight-year figure that circulated describes the age of the upstream code, not the span of affected seed generation.
Technical detail
Entropy is the measure of how much genuine unpredictability went into a secret. A 24-word BIP39 seed is meant to carry 256 bits of entropy, and a 12-word seed 128 bits. That number, not the length of the phrase, is what makes a seed infeasible to guess.
Coinkite describes the cause as a complex and subtle series of bugs that prevented the hardware random-number generator from contributing randomness in certain firmware versions. In 2021, COLDCARD moved its elliptic-curve operations to the same libsecp256k1 implementation used by Bitcoin Core, which required adding libNgU, an embedded MicroPython library. During that migration, seed generation moved from ckcc.rng_bytes() to ngu.random.bytes(). Coinkite states that the second path resolved to MicroPython’s software fallback rather than COLDCARD’s hardware implementation.
The build did not fail, because both implementations exposed the same function signature. Coinkite explains that MICROPY_HW_ENABLE_RNG was explicitly set to zero on the assumption that neither MicroPython implementation was needed, while the guard meant to catch a missing hardware generator used #ifndef, which tests only whether a macro is defined and not whether its value is non-zero. A macro defined as zero satisfied that test, so compilation proceeded with the software fallback linked in.
Coinkite notes that the MicroPython fallback itself was introduced upstream in May 2018, and did not enter COLDCARD wallet seed generation until the libNgU migration in March 2021. The eight-year figure that circulated describes the age of the upstream code, not the span of affected seed generation.
Official source: Coinkite technical deep dive
