This is a cryptographic experiment β or perhaps a cosmic joke β that attempts to find Ethereum accounts with positive balances through pure brute-force random generation of public keys. Every worker samples a random secp256k1 scalar, derives the corresponding public key and address, immediately discards the scalar, and asks an RPC provider whether that address holds any ETH.
Spoiler alert: you still won't find anything. But that's exactly the point.
This project serves as a practical demonstration of why blockchain cryptography works. Ethereum (and similar blockchains) rely on the mathematical near-impossibility of randomly producing a private key that maps to a funded address. When people say "your crypto wallet is secure," this is what they meanβnot that it is theoretically impossible to collide with an existing account, but that the probability is so astronomically small that it might as well be impossible.
Unlike real-world attacks that exploit:
- Weak random number generators
- Brain wallets (human-chosen phrases like "password123")
- Implementation bugs or protocol vulnerabilities
- Reused nonces or signature flaws
...this project uses pure, unbiased random generation against properly implemented cryptography. It's the digital equivalent of trying to find a specific grain of sand on all the beaches in the universe, while blindfolded, in the dark.
While this project demonstrates that the cryptography itself is secure, it's crucial to understand that your wallet's security depends entirely on keeping your private keys secret.
The math proves that guessing your private key is impossible. But:
- Phishing attacks can trick you into revealing your seed phrase
- Malware can steal keys from compromised devices
- Hot wallet vulnerabilities can expose keys stored on internet-connected systems
- Exchange hacks have resulted in billions of dollars stolen - not by breaking cryptography, but by exploiting security flaws in key storage and management
- Social engineering can manipulate you into handing over access
Major incidents that have resulted in billions of dollars in losses all share one thing in common: none of them broke the underlying cryptography. Instead, they exploited weaknesses in implementation, human behavior, and operational security:
-
Mt. Gox (2014, ~$450M): The largest Bitcoin exchange at the time collapsed after years of poor security practices and missing funds. Private keys were stored insecurely, enabling systematic theft.
-
The DAO (2016, ~$60M): A smart contract reentrancy vulnerability allowed an attacker to drain funds. Led to Ethereum's controversial hard fork. The cryptography was fine - the code logic wasn't.
-
Parity Wallet (2017, ~$280M): A bug in the multi-signature wallet code allowed someone to accidentally become the owner and then "kill" the contract, freezing funds permanently. Again, not a crypto break - just more bad code.
-
Coincheck (2018, ~$530M): Hot wallet private keys were stored on internet-connected systems without proper security measures. Attackers simply broke in and stole the keys.
-
Poly Network (2021, ~$611M): Cross-chain bridge exploit where the attacker found a way to forge transactions between blockchains. Interestingly, the hacker later returned most funds, claiming it was a "white hat" test. We bow our heads to you anonymous hero.
-
Ronin Network (2022, ~$625M): Social engineering and compromised private keys of validator nodes. Attackers gained control of enough validators to approve fraudulent withdrawals.
-
Wormhole Bridge (2022, ~$325M): Smart contract vulnerability in a cross-chain bridge allowed minting of fake tokens. Cryptographic signatures worked perfectly - the validation logic didn't.
Bottom line: The cryptography protecting your wallet is virtually unbreakable. You, however, might not be. Guard your private keys like they're the combination to a vault containing all your wealth - because that's exactly what they are.
Let's quantify exactly how hopeless this endeavor is.
Here's a crucial distinction: Ethereum uses 256-bit private keys , but these are hashed down to 160-bit addresses using the Keccak-256 algorithm. What actually matters when looking for collisions is the address space, not the private key space.
Private key space:
Address space:
Why does this matter? Because multiple private keys can theoretically map to the same address (though finding such a collision is still astronomically unlikely). When searching for a match, we're looking for any private key that produces a funded address - so the address space is our relevant search domain.
To put
Current estimates suggest there are approximately
Now let's imagine we somehow commandeer all computational power on Earth. As of 2025, estimates put total global computing power at roughly
Since there are
The expected time to find a single match is:
Converting to years (
Translation: The universe is approximately
-
All stars burn out: Around
$10^{14}$ years - you'd actually finish your search BEFORE the last stars die! Though you'd still be searching in darkness for the last third of your quest as stars progressively burn out. -
Proton decay (if it happens):
$10^{34}$ to$10^{40}$ years (lower bound) - you'd finish searching long, long before even the lower estimates of proton decay. The atoms making up your computer would remain intact throughout your entire futile search. -
Stellar-mass black holes evaporate: Around
$10^{67}$ years - you'd finish your search about$10^{53}$ years before these even start evaporating. -
Supermassive black holes evaporate: Around
$10^{85}$ years - if you could somehow keep running until then, you'd complete your entire search about$10^{71}$ times over. You'd find approximately$10^{80}$ funded addresses - which ironically is close to the number of atoms in the observable universe. Too bad none of it exists anymore.
In a dead, dark universe with no stars, no planets, no atoms - just you, somehow, checking keys - you'd finish your search long before the final supermassive black holes evaporated into Hawking radiation.
You might ask the universe's last superintelligent computer: "How can the net amount of entropy of the universe be massively decreased?" hoping to somehow reverse time and continue your search. But even Multivac's distant descendant would simply respond: INSUFFICIENT DATA FOR A MEANINGFUL ANSWER.
"But wait," you might say, "what about the birthday paradox? If I check billions of addresses, don't my odds improve?"
Not meaningfully. When searching for any of the
Even if you check
Still effectively zero. You'd need to check an incomprehensible number of keys before the birthday paradox provides any meaningful advantage.
Even though the probability math screams βfutile,β running the scanner makes that futility visceral. Watching billions of random public keys miss every funded address drives home how enormous the address space really is, why unbiased entropy matters, and why real attackers focus on social engineering, poor wallet hygiene, or implementation bugs instead of brute force. Treat the tool as an educational dashboard for cryptographic scaleβnot a treasure hunter.
Happy exploring! π
git clone https://github.com/jaroslawjanas/coin-finder.git
cd coin-finderconda env create -f environment.yml
conda activate coin-finderWindows users: consider
conda init powershellif PowerShell doesnβt auto-activate.
Copy .env.example to .env and set values as needed:
cp .env.example .envAt minimum define:
ETH_RPC_URL=https://your-provider.example/v2/your-key
The RPC endpoint must support JSON-RPC POST batching (eth_getBalance).
Recommendation: For quick testing without API keys, we recommend using the free public node at
https://ethereum-rpc.publicnode.com/with a batch size of 100. Example:ETH_RPC_URL=https://ethereum-rpc.publicnode.com/Then run with:
python -m coin_finder --workers 4 --batch-size 100
python -m coin_finder --workers 6 --batch-size 100The process runs until interrupted (Ctrl+C). Hits are appended to output/eth_hits.csv. The dashboard renders three stacked panels - the main summary, Throughput Rates (requests/sec and keys/sec), and Lifetime Stats (runtime, totals, and hit chance). Lifetime counters persist between runs via output/stats.json.
python -m coin_finder [OPTIONS]
| Option | Description | Default / ENV |
|---|---|---|
--eth-rpc-url TEXT |
Ethereum JSON-RPC endpoint (batch capable). Required. | ETH_RPC_URL |
--provider-name TEXT |
Label stored in CSV for the provider. | ethereum / PROVIDER_NAME |
-w, --workers INTEGER |
Number of concurrent workers. | 4 / WORKERS |
-b, --batch-size INTEGER |
Keys generated per worker per batch. | 512 / BATCH_SIZE |
--rpc-timeout FLOAT |
HTTP timeout (seconds). | 30 / RPC_TIMEOUT |
--rpc-max-outstanding INTEGER |
Max simultaneous RPC requests. | 8 / RPC_MAX_OUTSTANDING |
--stats-refresh-interval FLOAT |
Dashboard refresh cadence (seconds). | 0.25 / STATS_REFRESH_INTERVAL |
--output-dir PATH |
Directory for CSV hits. | output/ / OUTPUT_DIR |
--hits-filename TEXT |
CSV filename under output_dir. |
eth_hits.csv / HITS_FILENAME |
--seed TEXT |
Optional base seed for RNG reproducibility. | SEED |
--log-level TEXT |
Logging level. | INFO / LOG_LEVEL |
All options have matching environment variables. CLI flags override env values.
Hits are appended to output/<hits_filename> with headers:
public_key_hex,address,balance_wei,balance_eth,detected_at
Each successful hit is recorded with:
- public_key_hex: The public key in hexadecimal format
- address: The Ethereum address
- balance_wei: Balance in wei (smallest ETH unit)
- balance_eth: Balance formatted in ETH with 18 decimal precision
- detected_at: ISO 8601 timestamp (UTC) when the hit was detected
βββββββββββββββ βββββββββββββββ βββββββββββββββββ
β RNG + Keygenβ batch β ETH RPC β results β CSV Writer β
β (per worker)βββββββββΊβ Batch ClientββββββββββΊβ (async locked)β
ββββββββ¬βββββββ ββββββββ¬βββββββ βββββββββ¬ββββββββ
β stats update β latency metrics β hits
βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Statistics Registry β
β (rates, totals, last hit, errors) β
βββββββββββββββββ¬βββββββββββββββββββββββ¬βββββββββββββββββββββββ
β β
βΌ βΌ
Rich Dashboard Structured logging (stdout)
HashStreamRNGblends user seed, worker/batch IDs, nanosecond timestamps, and OS entropy.JsonRpcHttpClientmanages batching, rate limiting (capacity limiter), and exponential backoff.EthBalanceClientconverts batched responses into typed results.Statisticsoffers snapshots for the dashboard and metrics updates.dashboard_looprenders a live terminal UI with throughput metrics.run_workerloops until stop, generating keys β requesting balances β recording hits.runner.pyorchestrates workers, dashboard, and graceful shutdown.
- Implement
<chain>/keygen.py(keypair + address derivation). - Implement
<chain>/rpc.pyfor batch balance checks. - Wire into the pipeline (chain-specific client; extend
AppConfig). - Update CSV headers and CLI flags as needed.
The current design isolates chain-specific logic from the pipeline.
| Goal | Suggestion |
|---|---|
| Smoke test | Run with a local mock RPC server or set --batch-size 5 and intercept requests (e.g., mitmproxy). |
| Throughput benchmark | Configure a fast provider (low latency). Run python -m coin_finder --workers 16 --batch-size 2048 --stats-refresh-interval 0.5 and observe the dashboard rates. |
| Retry logic | Intentionally return HTTP 429/500 from a mock server to ensure exponential backoff kicks in (log level DEBUG). |
| Deterministic behavior | Supply --seed foo and capture addresses generated in first batch to verify reproducibility. |
Since live providers charge per request, benchmarking against production endpoints can be expensive. Use low batch sizes for validation.
- Private scalars are never persisted. Hits only include public keys, addresses, balances, and timestamps; treat
output/as sensitive metadata regardless. - Avoid logging beyond hits. DEBUG-level logs can leak timing information - use only for development.
- Store API keys in
.env. The.gitignorealready excludes.envandoutput/.
- Add graceful shutdown on SIGTERM/SIGINT with progress reporting.
- Support Ethereum Etherscan REST
balancemultias a fallback. - Add Electrum and Esplora clients for Bitcoin, or Solana RPC integration.
- Emit Prometheus metrics or OpenTelemetry traces.
- Plugin system for pluggable providers/chains.
GNU AFFERO GENERAL PUBLIC LICENSE - see LICENSE.
Happy hacking (responsibly)! π οΈ