GPU-accelerated Bitcoin private-key collision search in pure Python — 107 million keys/second on a gaming laptop, checking a 50-million-address funded database on the fly.
Educational/research implementation of the full pipeline — private key → k·G → HASH160 → binary search against a local database of every funded Bitcoin address — written as a single readable Python + CUDA-C (CuPy NVRTC) codebase. No compiled binaries, no build system: the CUDA kernels live as source strings and are JIT-compiled at runtime.
RTX 5070 Ti Laptop, sustained 20 s load, default settings:
| Mode | Throughput |
|---|---|
| Pure key generation | 183 Mkeys/s |
| Full pipeline vs 50.46M-address DB | 107 Mkeys/s |
| Mixed entropy-space schedule (default) | ~36 Mkeys/s (bounded by CPU-side weak-entropy generation, by design) |
The jump-optimized step-scan design (random base + P ← P+G stride walk + Montgomery batch inversion: 1 field inversion + 3(S−1) multiplications per S=128 candidates) is 14–17× faster than the naive one-key-per-thread version (13.0 → 183 Mkeys/s).
- GPU kernels (
gpu_hunt.py): 256-bit field arithmetic, windowed k·G in Jacobian coordinates, SHA-256/RIPEMD-160, in-VRAM binary search over the sorted funded-address database; hits are rechecked on CPU and confirmed against live balance APIs before counting - CPU multi-process version (
keyhunt.py): same idea, stdlib-only — mmap-shared sorted binary DB + per-worker binary search; works without any GPU - Multi-space scheduler (
key_spaces.py, v3): round-robin across private-key distributions — uniform random, puzzle ranges, timestamp-seeded, SHA-256-stirred, brainwallet, small-int, pattern — each key tagged so any hit traces back to its source space - Crash-safe hit recording: GPU hits are appended to
gpu_hunt_hits_raw.csvbefore CPU verification — a crash never loses a candidate - Checkpoint/resume: per-space cursors persist across restarts; a restarted scan resumes exactly where it stopped (verified: cursor deltas == scanned bases)
- Offline self-tests: domain arithmetic, k·G vs CPU reference, HASH160, stride scan across N-wrap, end-to-end synthetic DB, all 8 key spaces GPU-vs-CPU cross-checked, BIP-44/49/84/86 official vectors
pip install -r requirements.txt # numpy, cupy-cuda12x (+ nvidia-cuda-nvrtc-cu12)
# CPU version: download the funded-address dump and build the local DB (first run)
python keyhunt.py # then: python keyhunt.py --selftest
# GPU version (requires the DB built by keyhunt)
python gpu_hunt.py # default multi-space schedule
python gpu_hunt.py --spaces uniform # single space, full speed
python gpu_hunt.py --selftest # full GPU self-test suiteWith --api the CPU version falls back to per-address online balance checks (blockstream.info + mempool.space, dual-source) — no DB download needed, much slower.
- GPU flags a candidate → immediately appended to
gpu_hunt_hits_raw.csv(open/append/close, flushed per hit) - CPU re-derives all 5 address types from the private key and re-checks the DB
- Live balance confirmed via Esplora API; only confirmed-funded hits count, but zero-balance DB hits are also logged (tagged) — e.g. famous weak keys like
k=17hit within seconds of every restart
The expected value of random collision against all funded addresses is well-known to be negative (you will burn more electricity than the astronomical-unlikely hit pays). This repo exists to teach the engineering: 256-bit field arithmetic on GPUs, batch inversion, in-memory search, pipeline design. The weak-entropy spaces demonstrate why real-world losses came from broken RNGs (see bitcoin-weak-rng-scanner), not from brute force.
MIT. Only ever test against keys you generated yourself.
