Created
March 11, 2019 09:44
-
-
Save jonajosejg/32898da0079c64ad5de7200d22743437 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env python3 | |
# Reproduce Bitcoin ABC's deterministic Schnorr signature near end of key_tests.cpp | |
from ecdsa.numbertheory import jacobi | |
from ecdsa import SECP256k1 | |
import hashlib | |
import hmac | |
G = SECP256k1.generator | |
p = SECP256k1.curve.p() | |
n = SECP256k1.order | |
def sha(b): | |
return hashlib.sha256(b).digest() | |
msg = b"Very deterministic message" | |
msghash = sha(sha(msg)) | |
assert msghash == bytes.fromhex("5255683da567900bfd3e786ed8836a4e7763c221bf1ac20ece2a5171b9199e8a") | |
print("msg = "+repr(msg)) | |
print("msghash = "+msghash.hex()) | |
# 5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj | |
# Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw | |
privkey = 0x12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747 | |
print("privkey = "+hex(privkey)) | |
# pubkey point | |
P = privkey*G | |
comppub = (b'\x03' if (P.y()&1) else b'\x02') + P.x().to_bytes(32,'big') | |
assert comppub == bytes.fromhex("030b4c866585dd868a9d62348a9cd008d6a312937048fff31670e7e920cfc7a744") | |
### Validate the signature found in the code | |
sig = bytes.fromhex("2c56731ac2f7a7e7f11518fc7722a166b02438924ca9d8b4d1113" | |
"47b81d0717571846de67ad3d913a8fdf9d8f3f73161a4c48ae81c" | |
"b183b214765feb86e255ce") | |
r = int.from_bytes(sig[:32],'big') | |
s = int.from_bytes(sig[32:],'big') | |
print("sig.r = " + hex(r)) | |
print("sig.s = " + hex(s)) | |
e = int.from_bytes(sha(r.to_bytes(32, 'big') + comppub + msghash), 'big') % n | |
print("e = " + hex(e)) | |
checkR = s*G + (n-e)*P | |
print("chk.rx = " + hex(checkR.x())) | |
print("chk.ry = " + hex(checkR.y())) | |
print("jacobi(chk.y) = %+d"%(jacobi(checkR.y(),p))) | |
assert checkR.x() == r | |
### Now try to reconstruct the deterministic nonce | |
# see secp256k1_schnorr_sig_generate_k() in schnorr_impl.h | |
# and nonce_function_rfc6979() in secp256k1.c | |
algo16 = b"Schnorr+SHA256 " | |
ndata = b'' | |
V = b'\x01'*32 | |
K = b'\x00'*32 | |
buf = privkey.to_bytes(32,'big') + msghash + ndata + algo16 | |
# initialize | |
K = hmac.HMAC(K, V+b'\x00'+buf, 'sha256').digest() | |
V = hmac.HMAC(K, V, 'sha256').digest() | |
K = hmac.HMAC(K, V+b'\x01'+buf, 'sha256').digest() | |
V = hmac.HMAC(K, V, 'sha256').digest() | |
# generate once | |
V = hmac.HMAC(K, V, 'sha256').digest() | |
T = b'' | |
k = int.from_bytes(V, 'big') | |
print("nonce k = " + hex(k)) | |
R = k*G | |
print(" (kG).x = " + hex(R.x())) | |
print("+(kG).y = " + hex(R.y())) | |
print("jacobi((kG).y) = %+d"%(jacobi(R.y(),p))) | |
print("-(kG).y = " + hex(p-R.y())) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment