Last active
June 7, 2022 06:01
-
-
Save jujum4n/1ba13e18f9b32665d24f to your computer and use it in GitHub Desktop.
Python Bitcoin Keypair Generator
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
| # By: Justin Chase | |
| # Description: Based heavily on PYBITCOINTOOLS - https://github.com/vbuterin/pybitcointools By: vbuterin | |
| # Version: 0.01 | |
| import sys, re | |
| import binascii | |
| import os | |
| import hashlib | |
| import random | |
| import time | |
| import ssl | |
| # Elliptic curve parameters (secp256k1) | |
| P = 2**256 - 2**32 - 977 | |
| N = 115792089237316195423570985008687907852837564279074904382605163141518161494337 | |
| A = 0 | |
| B = 7 | |
| Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 | |
| Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 | |
| G = (Gx, Gy) | |
| if sys.version_info.major == 2: | |
| string_types = (str, unicode) | |
| string_or_bytes_types = string_types | |
| int_types = (int, float, long) | |
| # Base switching | |
| code_strings = { | |
| 2: '01', | |
| 10: '0123456789', | |
| 16: '0123456789abcdef', | |
| 32: 'abcdefghijklmnopqrstuvwxyz234567', | |
| 58: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz', | |
| 256: ''.join([chr(x) for x in range(256)]) | |
| } | |
| def bin_dbl_sha256(s): | |
| bytes_to_hash = from_string_to_bytes(s) | |
| return hashlib.sha256(hashlib.sha256(bytes_to_hash).digest()).digest() | |
| def lpad(msg, symbol, length): | |
| if len(msg) >= length: | |
| return msg | |
| return symbol * (length - len(msg)) + msg | |
| def get_code_string(base): | |
| if base in code_strings: | |
| return code_strings[base] | |
| else: | |
| raise ValueError("Invalid base!") | |
| def changebase(string, frm, to, minlen=0): | |
| if frm == to: | |
| return lpad(string, get_code_string(frm)[0], minlen) | |
| return encode(decode(string, frm), to, minlen) | |
| def bin_to_b58check(inp, magicbyte=0): | |
| inp_fmtd = chr(int(magicbyte)) + inp | |
| leadingzbytes = len(re.match('^\x00*', inp_fmtd).group(0)) | |
| checksum = bin_dbl_sha256(inp_fmtd)[:4] | |
| return '1' * leadingzbytes + changebase(inp_fmtd + checksum, 256, 58) | |
| def bytes_to_hex_string(b): | |
| return b.encode('hex') | |
| def safe_from_hex(s): | |
| return s.decode('hex') | |
| def from_int_representation_to_bytes(a): | |
| return str(a) | |
| def from_int_to_byte(a): | |
| return chr(a) | |
| def from_byte_to_int(a): | |
| return ord(a) | |
| def from_bytes_to_string(s): | |
| return s | |
| def from_string_to_bytes(a): | |
| return a | |
| def safe_hexlify(a): | |
| return binascii.hexlify(a) | |
| def encode(val, base, minlen=0): | |
| base, minlen = int(base), int(minlen) | |
| code_string = get_code_string(base) | |
| result = "" | |
| while val > 0: | |
| result = code_string[val % base] + result | |
| val //= base | |
| return code_string[0] * max(minlen - len(result), 0) + result | |
| def decode(string, base): | |
| base = int(base) | |
| code_string = get_code_string(base) | |
| result = 0 | |
| if base == 16: | |
| string = string.lower() | |
| while len(string) > 0: | |
| result *= base | |
| result += code_string.find(string[0]) | |
| string = string[1:] | |
| return result | |
| def random_string(x): | |
| return os.urandom(x) | |
| def encode_pubkey(pub, formt): | |
| if not isinstance(pub, (tuple, list)): | |
| pub = decode_pubkey(pub) | |
| if formt == 'decimal': | |
| return pub | |
| elif formt == 'bin': | |
| return b'\x04' + encode(pub[0], 256, 32) + encode(pub[1], 256, 32) | |
| elif formt == 'bin_compressed': | |
| return from_int_to_byte(2 + (pub[1] % 2)) + encode(pub[0], 256, 32) | |
| elif formt == 'hex': | |
| return '04' + encode(pub[0], 16, 64) + encode(pub[1], 16, 64) | |
| elif formt == 'hex_compressed': | |
| return '0' + str(2 + (pub[1] % 2)) + encode(pub[0], 16, 64) | |
| elif formt == 'bin_electrum': | |
| return encode(pub[0], 256, 32) + encode(pub[1], 256, 32) | |
| elif formt == 'hex_electrum': | |
| return encode(pub[0], 16, 64) + encode(pub[1], 16, 64) | |
| else: | |
| raise Exception("Invalid format!") | |
| def nurandom_key(userentropy): | |
| entropy = random_string(256) \ | |
| + str(random.randrange(2 ** 256)) \ | |
| + str(int(time.time() * 1000000)) \ | |
| + str(userentropy) \ | |
| + random_string(256) | |
| return nusha256(entropy) | |
| def bin_sha256(string): | |
| binary_data = string if isinstance(string, bytes) else bytes(string, 'utf-8') | |
| return hashlib.sha256(binary_data).digest() | |
| def nusha256(string): | |
| return bytes_to_hex_string(bin_sha256(string)) | |
| def b58check_to_bin(inp): | |
| leadingzbytes = len(re.match('^1*', inp).group(0)) | |
| data = b'\x00' * leadingzbytes + changebase(inp, 58, 256) | |
| assert bin_dbl_sha256(data[:-4])[:4] == data[-4:] | |
| return data[1:-4] | |
| def get_version_byte(inp): | |
| leadingzbytes = len(re.match('^1*', inp).group(0)) | |
| data = b'\x00' * leadingzbytes + changebase(inp, 58, 256) | |
| assert bin_dbl_sha256(data[:-4])[:4] == data[-4:] | |
| return ord(data[0]) | |
| def hex_to_b58check(inp, magicbyte=0): | |
| return bin_to_b58check(binascii.unhexlify(inp), magicbyte) | |
| def b58check_to_hex(inp): | |
| return safe_hexlify(b58check_to_bin(inp)) | |
| def bin_hash160(string): | |
| intermed = hashlib.sha256(string).digest() | |
| try: | |
| digest = hashlib.new('ripemd160', intermed).digest() | |
| except: | |
| digest = ssl.RIPEMD160(intermed).digest() | |
| return digest | |
| def pubkey_to_address(pubkey, magicbyte=0): | |
| if isinstance(pubkey, (list, tuple)): | |
| pubkey = encode_pubkey(pubkey, 'bin') | |
| if len(pubkey) in [66, 130]: | |
| return bin_to_b58check( | |
| bin_hash160(binascii.unhexlify(pubkey)), magicbyte) | |
| return bin_to_b58check(bin_hash160(pubkey), magicbyte) | |
| pubtoaddr = pubkey_to_address | |
| def privkey_to_address(priv, magicbyte=0): | |
| return pubkey_to_address(privkey_to_pubkey(priv), magicbyte) | |
| privtoaddr = privkey_to_address | |
| def from_jacobian(p): | |
| z = inv(p[2], P) | |
| return ((p[0] * z**2) % P, (p[1] * z**3) % P) | |
| def jacobian_double(p): | |
| if not p[1]: | |
| return (0, 0, 0) | |
| ysq = (p[1] ** 2) % P | |
| S = (4 * p[0] * ysq) % P | |
| M = (3 * p[0] ** 2 + A * p[2] ** 4) % P | |
| nx = (M**2 - 2 * S) % P | |
| ny = (M * (S - nx) - 8 * ysq ** 2) % P | |
| nz = (2 * p[1] * p[2]) % P | |
| return (nx, ny, nz) | |
| def jacobian_add(p, q): | |
| if not p[1]: | |
| return q | |
| if not q[1]: | |
| return p | |
| U1 = (p[0] * q[2] ** 2) % P | |
| U2 = (q[0] * p[2] ** 2) % P | |
| S1 = (p[1] * q[2] ** 3) % P | |
| S2 = (q[1] * p[2] ** 3) % P | |
| if U1 == U2: | |
| if S1 != S2: | |
| return (0, 0, 1) | |
| return jacobian_double(p) | |
| H = U2 - U1 | |
| R = S2 - S1 | |
| H2 = (H * H) % P | |
| H3 = (H * H2) % P | |
| U1H2 = (U1 * H2) % P | |
| nx = (R ** 2 - H3 - 2 * U1H2) % P | |
| ny = (R * (U1H2 - nx) - S1 * H3) % P | |
| nz = H * p[2] * q[2] | |
| return (nx, ny, nz) | |
| def jacobian_multiply(a, n): | |
| if a[1] == 0 or n == 0: | |
| return (0, 0, 1) | |
| if n == 1: | |
| return a | |
| if n < 0 or n >= N: | |
| return jacobian_multiply(a, n % N) | |
| if (n % 2) == 0: | |
| return jacobian_double(jacobian_multiply(a, n//2)) | |
| if (n % 2) == 1: | |
| return jacobian_add(jacobian_double(jacobian_multiply(a, n//2)), a) | |
| def to_jacobian(p): | |
| o = (p[0], p[1], 1) | |
| return o | |
| def fast_multiply(a, n): | |
| return from_jacobian(jacobian_multiply(to_jacobian(a), n)) | |
| def privkey_to_pubkey(privkey): | |
| f = get_privkey_format(privkey) | |
| privkey = decode_privkey(privkey, f) | |
| if privkey >= N: | |
| raise Exception("Invalid privkey") | |
| if f in ['bin', 'bin_compressed', 'hex', 'hex_compressed', 'decimal']: | |
| return encode_pubkey(fast_multiply(G, privkey), f) | |
| else: | |
| return encode_pubkey(fast_multiply(G, privkey), f.replace('wif', 'hex')) | |
| def decode_privkey(priv,formt=None): | |
| if not formt: formt = get_privkey_format(priv) | |
| if formt == 'decimal': return priv | |
| elif formt == 'bin': return decode(priv, 256) | |
| elif formt == 'bin_compressed': return decode(priv[:32], 256) | |
| elif formt == 'hex': return decode(priv, 16) | |
| elif formt == 'hex_compressed': return decode(priv[:64], 16) | |
| elif formt == 'wif': return decode(b58check_to_bin(priv),256) | |
| elif formt == 'wif_compressed': | |
| return decode(b58check_to_bin(priv)[:32],256) | |
| else: raise Exception("WIF does not represent privkey") | |
| def get_privkey_format(priv): | |
| if isinstance(priv, int_types): return 'decimal' | |
| elif len(priv) == 32: return 'bin' | |
| elif len(priv) == 33: return 'bin_compressed' | |
| elif len(priv) == 64: return 'hex' | |
| elif len(priv) == 66: return 'hex_compressed' | |
| else: | |
| bin_p = b58check_to_bin(priv) | |
| if len(bin_p) == 32: return 'wif' | |
| elif len(bin_p) == 33: return 'wif_compressed' | |
| else: raise Exception("WIF does not represent privkey") | |
| def inv(a, n): | |
| if a == 0: | |
| return 0 | |
| lm, hm = 1, 0 | |
| low, high = a % n, n | |
| while low > 1: | |
| r = high//low | |
| nm, new = hm-lm*r, high-low*r | |
| lm, low, hm, high = nm, new, lm, low | |
| return lm % n | |
| def change_curve(p, n, a, b, gx, gy): | |
| global P, N, A, B, Gx, Gy, G | |
| P, N, A, B, Gx, Gy = p, n, a, b, gx, gy | |
| G = (Gx, Gy) | |
| def getBitcoinKeyPair(userentropy): | |
| PAIR = [] | |
| rand_key = nurandom_key(userentropy) | |
| payment_address = privkey_to_address(rand_key) | |
| payment_address = str(payment_address) | |
| PAIR.append(payment_address) | |
| PAIR.append(hexstrtowif(rand_key)) | |
| return PAIR | |
| def hexstrtowif(hex_str): | |
| numpriv = int(hex_str, 16) | |
| t='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' | |
| step1 = '80'+hex(numpriv)[2:].strip('L').zfill(64) | |
| step2 = hashlib.sha256(binascii.unhexlify(step1)).hexdigest() | |
| step3 = hashlib.sha256(binascii.unhexlify(step2)).hexdigest() | |
| step4 = int(step1 + step3[:8] , 16) | |
| return ''.join([t[step4/(58**l)%58] for l in range(100)])[::-1].lstrip('1') | |
| def example_usage(): | |
| #Entropy from Form input | |
| userentropy = str('source of user entropy 12803hasipokdjm;l12@#$EFDS') | |
| #Generate a new Keypair using Users Entropy | |
| keyPair = getBitcoinKeyPair(userentropy) | |
| print 'Public: ' + keyPair[0] | |
| print 'Private: ' + keyPair[1] | |
| print 'Wif: ' + hexstrtowif(keyPair[1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
the term"conda" is not recognize as a name of a cmdlet can you please help