Skip to content

Instantly share code, notes, and snippets.

@luisschwab
Last active May 7, 2024 17:15
Show Gist options
  • Save luisschwab/b812ad104172c37c4247842d501667cd to your computer and use it in GitHub Desktop.
Save luisschwab/b812ad104172c37c4247842d501667cd to your computer and use it in GitHub Desktop.
'''
A simple example illustrating
message signing and signature
verification using secp256k1
'''
import coincurve
import hashlib
# order of the finite field in secp256k1
n = int('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16)
def sign(message: str, privkey: int):
'''
given a message string and a private key, return a signature in the format (r,s)
'''
message = message.encode("utf-8")
# sign a compact representation of the message instead
z = int(hashlib.sha256(message).hexdigest(), 16)
while(True):
# nonce (make it random)
k = 808
# R = kG
# r = R_x
r = coincurve.PrivateKey.from_int(k).public_key.point()[0] % n
# r cannot be 0
if r == 0: break
# multiplicative inverse of k
k1 = pow(k, -1, n)
s = ((z + r*privkey)*k1) % n
if s == 0: break
return (r, s)
def verify(message: str, r: int, s: int, pubkey: str):
'''
given a message string, a signature (r,s) and a public key, return wheter the signature is valid
u = z/s
v = r/s
uG + vP = R
If R_x = r, then it's a valid signature
'''
if r > n: return False
if s > n: return False
message = message.encode("utf-8")
z = int(hashlib.sha256(message).hexdigest(), 16)
# multiplicative inverse of s
s1 = pow(s, -1, n)
# u = z / s
u = (z * s1) % n
# v = r / s
v = (r * s1) % n
# pubkey point
P = coincurve.PublicKey(bytes.fromhex(pubkey))
# uG
U = coincurve.PrivateKey.from_int(u).public_key
# vP
V = P.multiply(v.to_bytes(32, "big"))
# R = uG + vP
R = coincurve.PublicKey.combine_keys([U, V])
# check if R_x matches r
if R.point()[0] == r: return True
return False
def run():
privkey = 1337
pubkey = coincurve.PrivateKey.from_int(privkey).public_key.format().hex()
message = "It ain't what you don't know that gets you into trouble; it's what you know for sure that just ain't so."
print(f"message:\n{message}")
print("\nsigning...")
r, s = sign(message, privkey)
print(f"r: {r}\ns: {s}")
print("\nverifying...")
if verify(message, r, s, pubkey):
print(f"good signature from {pubkey}!")
else:
print(f"bad signature from {pubkey}.")
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment