Last active
May 7, 2024 17:15
-
-
Save luisschwab/b812ad104172c37c4247842d501667cd 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
''' | |
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