How to Solve the World Pi Day OKX Private Key Puzzle Award (with complete code)
Tags: code, fmzquant, okx, key
Published: 2024-05-23 01:29:38

I saw some Tycoons in the group saying that OKX was holding a World Pi Day Mystery Event, with the theme of "Exploration, Never Ending".

As a veteran programmer, when I saw the news, I smiled and opened my MacBook Pro, and without further ado, let's get started!

> Analysis

Officially, there are 61 bits of key in the picture and the part of the circumference overlap, as we all know, the length of private key is 32 byte, converted to hex is 64 bits plus 0x prefix, a total of 66 bits, there are already 61 bits, for the first look, the "0X" at the first line in the chart is obviously not Pi, it is the start of the private key prefix, then there are about 5 bits (0123456789ABCDEF). The characters are arranged randomly, so there's nothing wrong with running them directly, so let's get started~

Let's use a Mac tool to sharpen the color simply:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9x7gm80jd3v3fq4h2cem.png)

In this way, the Mac can recognize the characters on the picture automatically. Let's copy them directly:
```
3.141592653589793230X1D64338
А694502884197169399375105820
974925E123078164062862089986
28033DB034211706409914808651
32823066470ED424609550582231
8B3
81284
• Exploration, 
038
Never Ending
027
493
05%
0128
4756482337867831731712019091
47D9E56692346034861045432664
8213393607743749141273724587
006606315588174881BEEA209628
2925409192744436789259036001
```
It cannot be used directly. Let's correct it manually. The unconfirmed ones covered by the picture are marked with *. Not sure. Let's talk about it later.
The others blocked by the figure can be judged by observing the stroke shape of other fonts. At this time, we use Python to calculate the difference between the two, and use '_' for the same ones and only showing the different ones.
```
img = '''
3.141592653589793230X1D64338
A694502884197169399375105820
974925E123078164062862089986
28033DB034211706409914808651
32823066470ED424609550582231
8B32594081284811174502841027
0193**2*D2299964462294895493
0381960EFC8103F9365933446128
4756482337867831731712019091
47D9E56692346034861045432664
82133936077A3749141273724587
006606315588174881BEEA209628
2925409192744436789259036001
'''
# True Pi
real='''
3.14159265358979323846264338
3279502884197169399375105820
9749445923078164062862089986
2803482534211706798214808651
3282306647093844609550582231
7253594081284811174502841027
0193852110555964462294895493
0381964428810975665933446128
4756482337867831652712019091
4564856692346034861045432664
8213393607260249141273724587
0066063155881748815209209628
2925409171536436789259036001
'''

items = img.strip().split('\n')
diffStr = ''
for pos, line in enumerate(real.strip().split('\n')):
    for i, c in enumerate(line):
        imgLine = list(items[pos])
        if line[i] == imgLine[i]:
            imgLine[i] = '_'
        else:
            diffStr += imgLine[i]
        items[pos] = ''.join(imgLine)
print('\n'.join(items))
print(diffStr, 'Len:', len(diffStr))
```
The implementation results are as follows:
```
Copy code
___________________0X1D_____
A694________________________
____25E1____________________
____3DB0________4099________
___________ED42_____________
8B32________________________
____**_*D2299_______________
______0EFC___3F93___________
________________731_________
_7D9E_______________________
__________7A37______________
__________________BEEA______
________92744_______________
0X1DA69425E13DB04099ED428B32***D22990EFC3F937317D9E7A37BEEA92744 Len: 64
```
There are three more, and there are just three uncertain ones. Try to remove them, because the other 61 bits are all right after exclusion, leaving only the most definite difference. Finally, the prefix is as follows:
```
0X1DA69425E13DB04099ED428B32D22990EFC3F937317D9E7A37BEEA92744
```
Next, we shall use Python and use force to crawl the balance on the OK chain. We can compare which private key has the balance. In fact, we can also select the public key with 314 USDT transfer first, which is faster. Seeing information on the official website said that we can check the balance directly if there is gas, the code is a little messy.
```
import sys
import web3,time,logging
from eth_account import Account
from web3 import Web3
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
w3 = Web3(Web3.HTTPProvider("https://exchainrpc.okex.org"))
logging.info(w3.clientVersion)
found = None

def get_balance_gas(key):
    global found
    _counter += 1
    address = Account.from_key(key).address
    logging.info('fetch address %s %s' % (found, address))
    while True:
        try:
            balance = w3.eth.get_balance(address)
            break
        except:
            logging.warning(traceback.format_exc())
            time.sleep(1)
            continue
    if balance != 0:
        found = key
        raise BaseException('Found balance: %s %s' % (address, balance))
    return balance

from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=50)
keys = []
prefix = '1DA69425E13DB04099ED428B32D22990EFC3F937317D9E7A37BEEA92744'
# It doesn't matter how to optimize the algorithm. Run the secret key against the clock.
ch = '0123456789ABCDEF'
for a in range(0, 16):
    for b in range(0, 16):
        for c in range(0, 16):
            for d in range(0, 16):
                for e in range(0, 16):
                    keys.append("0x"+prefix+ch[a]+ch[b]+ch[c]+ch[d]+ch[e])
print('all keys:', len(keys))
tasks = [None for t in keys]
for idx, key in enumerate(keys):
    tasks[idx] = executor.submit(get_balance_gas, key)
for t in tasks:
    t.result()
    
```
We can see that it takes 1048576 iterations, but it's much faster with multi-threading, running it on one of my servers.
```
2023-03-15 00:20:19,491 exchain-v1.6.8.5
all keys: 1048576
2023-03-15 00:20:20,372 fetch address None 0xc20C41f06F2428a0FD84ef03Ec6960992F5f8016
2023-03-15 00:20:20,473 fetch address None 0xcFa87ee54bc1c14c09a3AB3f41640bBab5C5480a
2023-03-15 00:20:20,483 fetch address None 0x126E922652f8B276F231D0eCA94d98685a26a45D
The following is omitted...
```
Anxious waiting~~~, bad news came, and there was no result before the strategy exited. All of them were displayed as None.

> The path winds along mountain ridges

I don't think so, I can't figure it out, I started to look at the discussion on twitter, and I found that everyone and I arrived at the same steps, but the strange thing is that no one has said that the decryption is successful, and the official has not announced the correct first 61 bits, then a strange reply caught my attention, because there is a difference D2299 in the middle, I am very sure, but he looks terribly confident.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8x8h2xgonolbs438mvx2.png)

However, he posted a 61-bit D2290. He also said that he had been checked carefully. It doesn't matter. Take a chance. Anyway, it's a waste of electricity.
With the attitude of trying, I found a few other people who said that they had found 61-bit. They were all very confident.
The prefixes found in the comments section are collected, with the code just traversed, the basic code has not changed, and it will not be pasted repeatedly.
```
prefixs =[
'1DA69425E13DB04099ED428B3202290EFC3F9317317D9E7A37BEEA92744',
'1DA69425E13DB04099ED428B32D2290EFC3F9373177D9E7A37BEEA92744',
'1DA69425E13DB04099ED428B320D2290EFC3F937317D9E7A37BEEA92744',
'1DA694255E3DB040990ED428B3208890EFC3F937317D9E7A37BEEA92744',
'1DA69425E13DB04099ED428B3202299EFC3F9317317D9E7A37BEEA92744',
'1DA69425E13DB01099ED428B3202290EFC3F9317317D9E7A37BEEA92744',
'1DA69425E13DB04099ED428B32D2290EFC3F9317317D9E7A37BEEA92744',
'1DA69425E13DB04099ED428B32D22990EFC3F937317D9E7A37BEEA92744',
]
```
In fact, there are more new messages later, one brother's PI value is different from mine, it's amazing!
Let's run with these first, I can't believe my eyes, but it came out, it means that one of the prefixes above is correct, which is very unscientific, the private key is:
```
1DA69425E13DB04099ED428B32D2290EFC3F9373177D9E7A37BEEA92744C8155
```
Here is D229, but the picture is clearly D2299, and 731 is followed by 7, here is two, but actually, this is the correct 61 bits, how he calculated it himself is unknown, incredibly curious, but I do not doubt my own operation, I saw one of the comments said that the official customer service said Pi has another version, it was me who were ignorant, with what I have learned and the current human understanding of the universe understanding, the circumference of this irrational number can represent the infinity of the universe, its fractional part never repeats or terminates, you can interpret it as the UUID of the universe you are in, if there are other versions, probably from parallel worlds.

> Web3 currency conversion code

Finally, it's the code to transfer the bonus away, for this time, I use the FMZ platform Web3 directly, set the chain address to OKC, the private key added to the exchange at random, and then two lines will be done, execute it in the debug tool mode directly.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aixyd2pigvsnuc640fax.png)

> Proof

Address of the decrypted public key
```
>>> from eth_account import Account
>>> Account.from_key('0x1DA69425E13DB04099ED428B32D2290EFC3F9373177D9E7A37BEEA92744C8155').address
'0x0bd08825e05e540C9508961a32E58D14da47275A'
```
Check out the link: https://www.okx.com/cn/explorer/okc/address/0x0bd08825e05e540c9508961a32e58d14da47275a

TX after being led by me: https://www.okx.com/cn/explorer/okc/tx/0x4211418b09571011417257201aaf10fc3c5d638809a9456eb5aba5fe8c5d4e2c

We can see that the recipient address is:
```
0x25f0a126be95f437ee71d7c4de725567c5f6c731
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7br5xg7dpbbk7ynjq7ub.png)

To prove that this address is mine, I used this recipient's address to make a transfer to a black hole address.

https://www.okx.com/cn/explorer/okc/tx/0xc32b5e299064456af3eb67c34a3b153f74a1bd18a31429052e3e3c5614bcdb6e

The black hole address is:
```
0x0000000000000000005757572e464d5a2e434f4d
```
This black hole address contains a URL decoded as:

```
~ % python -c 'print(bytes.fromhex("0000000000000000005757572e464d5a2e434f4d"))'
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00WWW.FMZ.COM'
```
> Postscript

This is the end of the story, and in retrospect, I'm grateful for the knowledge I've accumulated over the years, otherwise I wouldn't have been able to crack it so fast and I would have been beaten by others.
I'm sure there was a mistake in the official diagram, but in any case, I was lucky enough to crack the answer before it was made public, and I hope OKX will be more rigorous next time they hold a similar activity.

From: https://blog.mathquant.com/2023/03/16/how-to-solve-the-world-pi-day-okx-private-key-puzzle-award-with-complete-code.html