Coin Cracker is an experimental CUDA/Rust secp256k1 interval DLP solver using a Gaudry-Schost-style walk. Given a compressed secp256k1 public key and a private-key interval, it searches the interval and prints the recovered private key when found.
Warning
No warranty. Use at your own risk. The author is not responsible for damage, loss, misuse, or illegal activity. Only run this against keys and ranges you are authorized to test.
- Rust toolchain.
- NVIDIA GPU with a working CUDA driver and CUDA Toolkit.
- CMake 4.2 or newer.
The CUDA architecture is configured as native.
cargo build --releaseThe CUDA cubin is generated under Cargo's build output directory and embedded into the final binary.
coin-cracker \
--dp-bits <DP_BITS> \
--public-key <PUBLIC_KEY_HEX> \
--begin <BEGIN_HEX> \
--range-bits <BITS>Use either --range-bits <BITS> or --end <END_HEX>. --begin and --end are parsed as hexadecimal integers.
--public-key expects a SEC1 compressed public key hex string.
Other useful options:
--blocks <N>: override CUDA block count; default iscuda_cores / 128.--seed <HEX>: 32-byte RNG seed, encoded as 64 hex characters (for deterministic runs).--max-walks <N>: stop after a fixed number of walk calls, useful for smoke tests and benchmarks.
This example searches Bitcoin Puzzle #70:
coin-cracker \
--dp-bits 16 \
--public-key 0290e6900a58d33393bc1097b5aed31f2e4e7cbd3e5466af958665bc0121248483 \
--begin 200000000000000000 \
--range-bits 69On success, stdout contains only:
0000000000000000000000000000000000000000000000349B84B6431A6C4EF1
Progress and metrics are logged to stderr:
INFO *** Coin Cracker by lleoha (2026) ***
WARN No warranty. Use at your own risk; the author is not responsible for any damage, loss, or misuse.
INFO gpu_name=NVIDIA GeForce RTX 5060 gpu_cuda_cores=3840
INFO blocks=30
INFO rng_seed=9cbdb115d957c5b8969342918a23be9a76004d7e575fcdd1dcf61bc20abc2eec
INFO kernel_jumps_per_walk=943718400
INFO walk=1 processed_kernels=0 kernel_ms=0.000 kernel_jumps/s=0.000 dp=0 full_buffers=0
INFO walk=2 processed_kernels=6 kernel_ms=337.310 kernel_jumps/s=2797774125.129 dp=14365 full_buffers=0
(...)
INFO walk=46 processed_kernels=6 kernel_ms=350.746 kernel_jumps/s=2690601098.749 dp=14501 full_buffers=0
INFO summary walk_calls=46 processed_kernels=270 startup_wall_s=0.379 gpu_setup_wall_s=0.026 initial_fill_wall_s=0.823 precompute_wall_s=1.228 solve_wall_s=15.722 kernel_ms=15710.930 kernel_jumps=42467328000 event_kernel_jumps/s=2703043570.886 solve_wall_kernel_jumps/s=2701122451.718 dp=647049 dp/s=41155.370 full_buffers=0
INFO centered_secret=0000000000000000000000000000000000000000000000049B84B6431A6C4EF1
INFO total_wall_s=17.244
Coin Cracker uses the Gaudry-Schost method for solving DLP in an interval and does NOT use equivalence classes. I decided not to use equivalence classes because this makes the raw jumps/s much higher (about 42% in my hand-wavy tests). Using negation-map equivalence classes would require about 41.4% fewer jumps, but the raw speed would also be about 42% lower, so these effects roughly balance and cancel each other out, while keeping the implementation simpler (no fruitless-cycle handling, etc.). The number of walks is rather large, so DP overhead is also high, and I might work on that in the near future.
The method uses custom tame and wild interval shapes and custom sampling patterns based on the research in Kang-1. This project was heavily inspired by it, so credit goes to RetiredCoder.
Coin Cracker vs RCKangaroo
RCKangaroo uses neither the Pollard Kangaroo method (also known as Pollard Lambda) nor the Gaudry-Schost method. Unlike Pollard Kangaroo, RCKangaroo uses the negation-map equivalence class; unlike Gaudry-Schost, it does not restart the walk when a distinguished point is hit. Instead, it jumps to another part of the interval using a different jump table, so it is a kind of hybrid of the two. Coin Cracker uses vanilla Gaudry-Schost (with interval shapes and sampling patterns borrowed from the SOTAv2 method), which means walks are restarted when DP is hit. New walk start points are computed on CPU, so it also requires a moderately high-end CPU when the DP bits setting is relatively low.
On my test GPU (NVIDIA RTX 5060), RCKangaroo reports throughput of ~1.9 G/s vs. Coin Cracker at ~2.7 G/s.
The inventor of the SOTAv2 method estimates the average number of samples required to solve DLP
to be
Caution
I am not a mathematician (actually far from it), so this might be invalid.
The two wild sets are:
where
The tame interval is
The sampling pattern is:
A key parity point: both wild sets have the same parity as
Define:
to be the scaled overlap length between a wild interval and the tame interval.
For one draw from the active tame parity and one draw from either wild set, the probability of a collision is approximately:
For one draw from
For a given sampling pattern, sampling rates are:
Let
Then the no-collision probability is approximately:
so the expected number of samples is:
Averaging over
The piecewise form of
Integrating gives the closed form:
For
So what is the theoretical
The author estimates their
Contributions are very welcome. If you see a correctness issue, performance opportunity, cleanup, documentation improvement, or a better way to explain the algorithm, please open an issue or submit a pull request.
This project is experimental and performance-sensitive, so changes are easiest to review when they are focused, include the reasoning behind the approach, and explain how they were tested. Improvements to the CUDA kernel, Rust host code, benchmarks, documentation, and reproducibility are all appreciated.
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.