IERG 4130 · Cryptography

When a Wallet RNG Is Predictable

A local toy demonstration of how a small, reproducible RNG seed can make wallet generation enumerable.
Teaching-only model. This page uses a toy wallet address and a 24-bit seed so the attack can finish in a browser. It never connects to a blockchain, never uses real elliptic-curve keys, and must not be used with real funds.

1. Vulnerable wallet generator

The global toy space is 224 = 16,777,216 possible seeds. The attack below scans only an estimated local window.

Toy model used by this demo

// This is a teaching model, not Coldcard source.
function xorshift32(state) {
  state ^= state << 13
  state ^= state >>> 17
  state ^= state << 5
  return state
}

function weakRandomBytes(fallbackSeed, length) {
  state = fallbackSeed
  output = []

  for i in 0 .. length - 1:
    state = xorshift32(state)
    output.push(state & 0xff)

  return output
}

// Six hexadecimal digits keep only 24 seed bits.
fallbackSeed = parseHex(userInput) & 0xffffff
fallbackSeed = fallbackSeed || 1

// Global toy space: 2^24 possible initial states
randomBytes = weakRandomBytes(fallbackSeed, 32)
privateKey = hex(randomBytes)
address = toyAddress(privateKey)

This matches the JavaScript below: the same seed produces the same 32 bytes, private key, and toy address. The real case study uses a different fallback generator and a constrained reseed; the security lesson is the same.

2. Hacker's offline recovery

This is not the hidden seed. It represents an estimate from timing, device behavior, or a controlled reproduction.
The attacker knows the address and estimates the boot/reseed state. This page does not scan the full 224 space by default; it scans a local window so the demonstration stays interactive. A real 32-bit search is much larger.
Generate a wallet first.

Attacker's code

for seed in likely_seeds:
    candidate = wallet_from_seed(seed)
    if candidate.address == observed_address:
        recovered_private_key = candidate.private_key

The attacker does not reverse the hash. They reproduce the generator and use the public address as a candidate-validation oracle.

3. The secure contrast

// Use an operating-system CSPRNG
privateKey = crypto.getRandomValues(new Uint8Array(32))

A secure generator must draw fresh, unpredictable entropy. A timestamp, device identifier, counter, or short reseed is not a substitute.

Looks random ≠ is random

A deterministic PRNG can produce convincing-looking bytes while remaining reproducible.

Entropy is a budget

If the effective seed has only 24 or 32 bits, later hashing cannot expand the number of possible secrets.

Public data enables checking

An address or public key lets an attacker reject wrong candidates without seeing the private key.

Case study: Block Engineering, “Predictable RNG Fallback and 32-Bit Reseed in COLDCARD Firmware” . This demo is a simplified teaching model, not a reproduction of the device firmware.