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:
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+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.
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.
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
To prove that this address is mine, I used this recipient's address to make a transfer to a black hole address.
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.