Created
September 13, 2023 00:40
-
-
Save AdamISZ/8dacbbab7525af07c0ca3f12e2262c72 to your computer and use it in GitHub Desktop.
How to prove you're Satoshi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A reminder of how to "prove" you're Satoshi. | |
# ("reminder" - this was done (with tongue in cheek, presumably) | |
# by someone on Twitter a few years ago). | |
# 1. We need the public key of the receiving address of (e.g.) block 1. | |
# it is on the blockchain in uncompressed form (P2PK): | |
block1_uncompressed_output_key_hex = "0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee" | |
# convert the key to compressed because software complains about mixed formats: | |
block1_compressed_output_key_hex = "02" + block1_uncompressed_output_key_hex[2:66] | |
# And ... that's kind of all we need :) | |
# Steps of the algorithm: | |
# 1. Generate a random tweak alpha | |
# 2. Set the nonce point to R = P + alpha * G | |
# 3. Calculate the corresponding x coordinate R(x), call that t. | |
# 4. Set the signature value s = t. | |
# 5. Set the signature hash value h ("H(message)" supposedly) to h = s * alpha | |
# 6. Publish (t, s) as the signature, which validates against Satoshi's public key. | |
# 7. Promise that you will reveal the mysterious message later, and voila, you're Satoshi. | |
from jmbitcoin import btc # you could just use the python-bitcointx package with a bit of messing around | |
import os | |
import base64 | |
from jmbase import bintohex, hextobin | |
#1 | |
P = btc.CPubKey.fromhex(block1_compressed_output_key_hex) | |
alpha_bytes = os.urandom(32) | |
#2 | |
R = btc.add_pubkeys([P, btc.privkey_to_pubkey(alpha_bytes + b"\x01")]) | |
# 3,4 | |
assert isinstance(R, btc.CPubKey) | |
t = R[1:] | |
assert len(t) == 32 | |
s = t | |
#5 | |
sint, alphaint = [int.from_bytes(x, byteorder="big") for x in [s, alpha_bytes]] | |
hint = sint * alphaint % btc.N | |
h = int.to_bytes(hint, 32, byteorder="big") | |
#6 | |
# We need to construct the signature in the expected DER encoding for ECDSA, | |
# hence the below extra chunk of code | |
def der_encode_sig(r: int, s: int) -> bytes: | |
# modified from some ancient pybitcointools code | |
# (because everything nowadays calls libsecp...) | |
def encode(some_integer, maxlength, minlength=1): | |
c = int.to_bytes(some_integer, maxlength, "big") | |
stripped_c = c.lstrip(b"\x00") | |
if len(stripped_c) < minlength: | |
stripped_c = b"\x00" * (minlength - len(stripped_c)) + stripped_c | |
return stripped_c | |
s = btc.N - s if s > btc.N // 2 else s # BIP62 low s | |
b1, b2 = encode(r, 32), encode(s,32) | |
if bytearray(b1)[ | |
0] & 0x80: # add null bytes if leading byte interpreted as negative | |
b1 = b'\x00' + b1 | |
if bytearray(b2)[0] & 0x80: | |
b2 = b'\x00' + b2 | |
left = b'\x02' + encode(len(b1), 1) + b1 | |
right = b'\x02' + encode(len(b2), 1) + b2 | |
return b'\x30' + encode( | |
len(left + right), 1) + left + right | |
sig = der_encode_sig(sint, sint) | |
encoded_sig = base64.b64encode(sig) | |
print("got sig: ", encoded_sig) | |
print("and message hash is: ", bintohex(h)) | |
# Do the "verification": check that (R, s) is a valid signature on message hash h, for key P: | |
verification_result = btc.ecdsa_raw_verify(h, P, sig, rawmsg=True) | |
print("Is the signature valid on Satoshi's key from block 1?: ", verification_result) | |
""" | |
Here is some example output: | |
(jmvenv) waxwing@here:~/code$python fakeforgery.py | |
got sig: b'MEUCIQDOfh42gE4SqQHtp6SUZOaVaDRDrMpGXr7Yr6UOZu2USwIgMYHhyX+x7Vb+Elhba5sZaVJ6mTnlAkF85yK5fmlIrPY=' | |
and message hash is: f888cabdf88abee1ee9369a91578c3efbde119959df18f4e46a3631929338251 | |
Is the signature valid on Satoshi's key from block 1?: True | |
Note: this kind of verification is usually not possible with user-level tools; | |
and that's a *VERY* good thing! Because the ECDSA algorithm is not valid if you don't | |
provide, as part of the verification, the preimage of the message hash. | |
That's basically the entire point of this "trick". | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment