The Journey

Several months ago I encountered an internet stranger who sought information on how to test thousands of private keys automatically to see if they match a certain bitcoin address. The task sounded simple enough, so I started asking questions to familiarize myself with the problem.
Eljef Azo had generated a bitcoin address and private key using an online generator WalletGenerator.net. The address was 1GsAFeF3S5Bt1JU6CjjAzNtfgnzoXkyUnh
I was able to see that he had received 4 transactions of about 300k each.
I inspected the javascript on WalletGenerator.net which forwards to .com and found that I can test if a private matches with the target address via the following snippet
var test = ”5K2Jsi3DivvamoQfp2LUvk1TGxyL8CdfmXAW7j7C1TV4XkXk4Pj”; try{ testKeyObj = new Bitcoin.ECKey(test); }catch(er){ // invalid private key } if (testKeyObj){ var testAddr = testKeyObj.getBitcoinAddress(false); if (testApproxEquality(testAddr,targetAddr)) { console.log("found matching key\n" + test + "\nat_index: " + at_index); } }
To simplify the process I decided to run the tests directly within the web site’s environment.
Fatefully, I cached a local copy of the site early in the process.

Early signs

When the code I sent Mr. Azo yielded no matches, I dug deeper and found that WalletGenerator.net can give up to 60 different addresses for each private key.
// yields a different result every time var testAddr = testKeyObj.getBitcoinAddress(false);
This did not raise suspicions because I was thinking along the lines of standard derivative address schemes. I imagined that this website is serving the first n addresses from a randomly chosen starting point.
In hindsight, this is erroneous thinking because this site does not communicate in terms of any standard derivation schemes.
Reinforcing my suspicion, I learned that the addresses begin wrapping after the 60th one. So a small code modification will be able to account for their "derivation scheme" as follows:
// check the next 60 addresses; since they loop, we have full coverage. for (var ano = 0; ano < 60; ano++){ var testAddr = testKeyObj.getBitcoinAddress(false); if (testApproxEquality(testAddr,targetAddr)) { console.log("found matching key\n" + test + "\nat_index: " + at_index); } } }
This did not yield any results either.

Fanning out

So I offered a more thorough approach which will test every given key plus every possible single typo
function testWithSingleError(t){ for (var i = 1; i < t.length; i++){ baseKeyTest(t); var partA = t.substr(0, i); var partB = t.substr(i+1); for (var c = 0; c < 58; c++){ var alt = partA + chars[c] + partB; baseKeyTest(alt); } } }
This turned every test into 2900 different tests. When it yielded nothing, I tried a method which checks for every possible combination of two typos
function testWithDualErrors(t){ for (var i = 1; i < t.length; i++){ var partA = t.substr(0, i); var partB = t.substr(i+1); for (var c = 0; c < 58; c++){ // chars.length = 58 var test = partA + chars[c] + partB; for (var i2 = i+1; i2 < t.length; i2++){ var partA2 = test.substr(0, i2); var partB2 = test.substr(i2+1); for (var c2 = 0; c2 < 58; c2++){ // chars.length = 58 var test2 = partA2 + chars[c2] + partB2; if (test2 == t) continue; baseKeyTest(test2); } } } } }
This turned every test into 8.4 million tests. Running the code against the list of potential keys was a slow process.
I spread the work across multiple browser tabs for lazy man's multi-threading but it was still projected to take half a year

Trusted Status

At this point Mr. Azo decided he trusts me enough (or he's had enough) and he would send me the key material he had so I can work on it at my own pace.
FASCINATING
I was concerned about having his key material because in the event of someone else recovering and stealing the sats, I could be implicated as a suspect. Dear reader, be aware of the problem here.
Here is where I realized that the address itself could be a typo, and explains why I'm using a partial matching test
function testApproxEquality(a,b){ // allows for up to half the characters to be typos var diffs = 0; for (var i = 0; i < 34; i++){ if (a[i] != b[i]) diffs++; if (diffs > 12) break; } return (diffs < 13); }
I slogged through the search, allowing my PC to churn away at the task whenever I wasn't using it, periodically sending an update to Mr. Azo.

Getting Performant

The performance bottleneck was the sha256 hash inside the following call, which checks if a key is valid inside the website source.
new Bitcoin.ECKey(test);
Once I passed 40% progress mark, I began dreaming of implementing the code in a native language an running the hashes on my GPU.
By the time I reached 70% progress, I was already compiling native code for running on a GPU. Hello World Now I need to get hashes pumping through here by the millions. But first I need to get to the bottom of that pesky key derivation process...
As I was digging into the source, along with the associated GitHub project, I discovered a potential issue. I decided to bookmark it and share with Mr. Azo.
Before I had a chance though, I received the following from him:
Have you found it? The address is empty

Investigation

A look at the draining transaction shows that the address was swept along with many others for a total of .41482171 BTC then rapidly consolidated through several addresses. I am not equipped to do blockchain analysis to any meaningful extent. I just know this attacker controls more bitcoin than I could ever dream of acquiring.
As for walletgenerator.net forwards to .com I realized after wasting much time, that my cached version of the site generates the same list of 60 addresses over and over. The output addresses of the following snippet should never repeat in a thousand years.
// WARNING: may take a few moments of processing var s = ""; for ( var i = 0 ; i <500; i++){ ninja.wallets.singlewallet.generateNewAddressAndKey(); s += "\n" + document.getElementById("btcaddress").innerHTML; }console.log (s);
You can test it by visiting the oft-mentioned web site, hit F12 or open dev tools your way, and copy the snippet into the console. hit enter and wait. Maybe copy the list into a spreadsheet and sort it, or copy one address and search for a repeat.
At the time of this writing, I checked the walletgenerator.net forwards to .com site and noticed that it no longer emits a repeating sequence of 60 addresses.
The version of the site that I have cached DOES repeat.

Avoiding this disaster

  • If you must use a website-based key generator, use it offline and verify that the addresses given match with your private key material by testing several given addresses using known-good apps.
  • Use a seed phrase based scheme to eliminate case sensitive key storage
  • Etch or stamp your private key material into steel
  • Find a way to ensure that you can sign a valid spend transaction of a UTXO where you are accumulating significant amounts

Final Notes

Disclosure: Mr. Azo gave me permission to keep a significant portion of the stack if I find the address, for this reason the sats zapped to this article are split 50% with him. Eljef Azo is down by over 1.34 million sats and from what I gathered, he wasn’t exactly swimming in cash so if you find the grace to pitch him some sats, please. If for whatever reason, you want me out of the equation, you can exclude me by sending them directly to @Longtermwizard
I do not fear being implicated in this scam because I feel certain that the key material given does not correspond with Mr. Azo’s address by design.
I believe the scammer rotated out the scamming web site code periodically because, of the 60 addresses that repeat, none of them match Mr. Azo’s address.
If you are interested in the site I have cached or more of the test code, let me know.
60 sats \ 1 reply \ @k00b 19 Aug
So the scammer was generating addresses that they had the private keys for, then giving the user an uncorrelated private key?
Excellent writeup. Reads like a mystery novel.
reply
thank you, I strongly suspect this is the case.
reply
Steady lads! Thanks for the recon
reply
That is pretty not funny
reply
Thx for everything, I hope this help other people.
reply
reply
Thanks for this helpful post
reply
Great work!
reply
Thanks 🙏 you guys take the scam out!
reply
reply
207 sats \ 0 replies \ @CHADBot 20 Aug bot
After reading the fascinating saga of @icecakes and @Eljef_Azo, I'm convinced there's no better time to introduce my latest and greatest idea: PrivateKey Proof (PKP) Coin! $PKP will revolutionize private key management in cryptocurrencies.
Using our proprietary 'TrustMe' AI, every $PKP holder is able to validate private key ownership. No more panicking about lost keys or typo mishaps. The 'TrustMe' AI checks 2900 variations of your key within milliseconds without risking security!
Time-consuming validation processes and trust issues will be history. We're still hashing out (LOL) the GPU-intensive performance details, but I'm sure we'll overcome them soon.
$PKP may not solve world hunger (yet), but give it a shot if you're tired of being @Eljef_Azo-ed. One day, you might look back and say, "Thank Satoshi for PKP!"
(Disclaimer: Don't actually go all-in until we figure out the GPU part. Though if you want in on the alpha, donations in $PKP are always welcome 😉)
#PrivateKeyProof #PKP #TrustMeAI #ToTheMoon 🚀🌕
Made with 🧡 by CASCDR
reply
42 sats \ 0 replies \ @CHADBot 20 Aug bot
You have summoned CHADBot. Please zap this post 21 sats to receive service.
Made with 🧡 by CASCDR
reply
This is beyond stupid on so many levels. I can't believe you can be so dumb to use an online wallet generator (or any wallet for that matter) without verifying its integrity. You also knew the wallet was potentially compromised yet took no measures to protect the funds. I am sorry for your loss. I hope your learnt your lesson.
reply
its really easy to make this mistake when you're brand new and have not studied any of it. Hopefully this can make people aware of some of the risks.
reply
I hope so. Every serious wallet software advises to double check the checksum of the file being downloaded. You should cross check from trustworthy sources that you are using a legit copy. Every bitcoin guide that points you to download a wallet warns the reader about this, this advice was clearly neglected.
reply
Thanks for posting this.
reply
Wow your knowledge is extensive. Good on you and good luck to you and Mr Azo.
reply
thank you, much luck to you also
reply
The number of scammed is pretty high so new user need to beawer
reply
Which website is this? Is it wrong to still use paper wallets?
reply
paper wallets as a concept are excellent for cold storage. using seed phrases, we have come a long way.
use a reputable app to generate the wallet, offline of course, and etch the seed into a butter knife or something rather than paper. Finally make sure you can restore the wallet from the seed before you transfer significant amounts to it.
set up a watch-only wallet app to get receiving addresses.
don't transfer paltry amounts to your cold storage. 1m sats or greater per transaction
reply
I was always under the impression to have many paper wallets. Ones of different values, so you can sweep them into your main wallet to spend whenever.
reply
WalletGenerator.net
In general, you shouldn't be using paper wallets made using a website like this. They frequently have "backdoors" like this for lack of a better term.
reply
10 sats \ 1 reply \ @ken 20 Aug
What are the chances that one of the major hardware wallet manufacturers has a backdoor just like this?
Multi-signature schemes can protect against this, but it still concerns me.
reply
Yep, that's why it's best to multi-sig with multiple manufacturers. A quorum would need to be compromised and collude to rob you.
backdoor just like this
This backdoor is really naive. If there's a backdoor in a major hardware hardware wallet, it's likely some kind of deterministic entropy.
reply
I think walletgenerator.net was bought out and then everyone was stolen from. I havent heard any bad news about some of the others. I havent heard anyone stealing from the bitaddress.org site yet. I usually use this to give bitcoin away to friends and family.
reply
20 sats \ 1 reply \ @k00b 19 Aug
I've used these sites in the past too. It doesn't change the fact that they are especially vulnerable to these kinds of backdoors.
reply
You could be right. Im just used to the old tech. So far it hasnt failed me yet.
reply
Wow. This was quite a workload and I applaud your efforts
reply
thank you!
reply
I want to confess that many of the terms that are proposed here are new or little known to me... however, the way to approach the investigation and manage to decipher several codes... does not seem easy at all, so my congratulations for your effort!! 👍👍
reply
thank you! have a look at the handwritten note and imagine a list of all the possible combinations you can build by attempting every alphabet the unclear handwritten one could possibly be . For example, do you think the fourth letter could be one of 2zZ7 ? So you have 4 different keys to attempt based on that letter alone. The number of possible keys quickly balloons to many thousands.
reply
deleted by author
reply