Skip to content

Instantly share code, notes, and snippets.

@sixTheDave
Created September 11, 2022 18:50
Show Gist options
  • Save sixTheDave/038463c232c5cf644860ab038a1c9fde to your computer and use it in GitHub Desktop.
Save sixTheDave/038463c232c5cf644860ab038a1c9fde to your computer and use it in GitHub Desktop.
from eth_account.account import to_standard_signature_bytes
from eth_keys import keys
from eth_utils import (big_endian_to_int, to_bytes)
from hexbytes import HexBytes
from eth_keys.backends.native.jacobian import (inv, fast_multiply, fast_add)
from eth_keys.constants import (SECPK1_G as G, SECPK1_N as N)
def recover_public_key(message_hash, signature):
message_hash_bytes = HexBytes(message_hash)
if len(message_hash_bytes) != 32:
raise ValueError("The message hash must be exactly 32-bytes")
signature_bytes = HexBytes(signature)
signature_obj = keys.Signature(signature_bytes = to_standard_signature_bytes(signature_bytes))
return signature_obj.recover_public_key_from_msg_hash(message_hash_bytes)
def forge(public_key, a = 0, b = 1):
t = public_key.to_bytes()
Y = big_endian_to_int(t[:32]), big_endian_to_int(t[32:])
r, y = fast_add(fast_multiply(G, a), fast_multiply(Y, b))
s_raw = r * inv(b, N) % N
v_raw = (y % 2) ^ (0 if s_raw * 2 < N else 1)
s = s_raw if s_raw * 2 < N else N - s_raw
v = v_raw + 27
z = a * s_raw % N
eth_signature_bytes = to_bytes(r).rjust(32, b'\0') + to_bytes(s).rjust(32, b'\0') + to_bytes(v)
return '0x' + to_bytes(z).rjust(32, b'\0').hex(), '0x' + eth_signature_bytes.hex()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment