Last active
October 21, 2024 20:43
-
-
Save alpinevm/2329083aa44258fb6c96f1a86ca2001c to your computer and use it in GitHub Desktop.
Generate arbitrary ECDSA signature + hash pairs given a public key
This file contains hidden or 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
| # Author: Alpine, @alpinevm | |
| # python3 -m pip install eth_account ecdsa | |
| # Inspired by: https://yondon.blog/2019/01/01/how-not-to-use-ecdsa/ | |
| import random | |
| from eth_account import Account | |
| from ecdsa import SECP256k1, VerifyingKey | |
| from ecdsa.util import number_to_string | |
| def vrs_to_signature_bytes(v, r, s): | |
| r_bytes = r if isinstance(r, bytes) else bytes.fromhex(r[2:]) | |
| s_bytes = s if isinstance(s, bytes) else bytes.fromhex(s[2:]) | |
| v_byte = v.to_bytes(1, 'big') | |
| signature_bytes = r_bytes + s_bytes + v_byte | |
| return signature_bytes | |
| # Constants | |
| curve = SECP256k1.curve | |
| n = SECP256k1.order | |
| # Use the provided address and public key | |
| address = "0x000000097C7e6f43bb3f225DB275B22C666402f1" | |
| # Retrieved from the contract deployment transaction | |
| public_key_hex = "0x4dd42356847875c8ae9fb131edaf9b823f63d6c00b850d678285e4f8eb403b7b4fc3da7548f9ffd09259f29cbf41b5e1daa0f83dcf02fa8dd3cd42647b6606cf" | |
| public_key_bytes = bytes.fromhex(public_key_hex[2:]) | |
| public_key = VerifyingKey.from_string(public_key_bytes, curve=SECP256k1) | |
| print("Target Account Address:", address) | |
| print("Target Account Public Key:", public_key.to_string().hex()) | |
| while True: | |
| # Choose arbitrary values for a and b | |
| a = random.randint(1, n - 1) | |
| b = random.randint(1, n - 1) | |
| # Calculate r (Px) | |
| aG = a * SECP256k1.generator | |
| bH = b * public_key.pubkey.point #type:ignore | |
| P = aG + bH | |
| r = P.x() | |
| # Calculate s and z | |
| s = (r * pow(b, -1, n)) % n | |
| z = (a * s) % n | |
| # "Hash" the message (but actually use the calculated z value) | |
| hash_z = number_to_string(z, SECP256k1.order) | |
| signature = (28, number_to_string(r, SECP256k1.order), number_to_string(s, SECP256k1.order)) | |
| recovered_address = Account._recover_hash(hash_z, signature=vrs_to_signature_bytes(*signature).hex()) | |
| if recovered_address.lower() == address.lower(): | |
| print("Signature", vrs_to_signature_bytes(*signature).hex()) | |
| print("Generated hash", hash_z.hex()) | |
| print("Signature verification passed! The recovered address matches the provided address.") | |
| break |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment