Author

Topic: Converting HEX private key to bitcoin address (Read 246 times)

newbie
Activity: 62
Merit: 0
September 15, 2022, 05:47:04 AM
#3
This is some random code I have o my PC, it coverts HEX to WIF in python
Code:
import codecs  
import hashlib
PK0 = "00000000000000000000000000000008000000000000000000FFFFFFFFFFFFFFFF"
PK1 = '80'+ PK0
PK2 = hashlib.sha256(codecs.decode(PK1, 'hex'))
PK3 = hashlib.sha256(PK2.digest())
checksum = codecs.encode(PK3.digest(), 'hex')[0:8]
PK4 = PK1 + str(checksum)[2:10]
def base58(address_hex):
    alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
    b58_string = ''
   
    leading_zeros = len(address_hex) - len(address_hex.lstrip('0'))
    address_int = int(address_hex, 16)
    while address_int > 0:
        digit = address_int % 58
        digit_char = alphabet[digit]
        b58_string = digit_char + b58_string
        address_int //= 58
    ones = leading_zeros // 2
    for one in range(ones):
        b58_string = '1' + b58_string
    return b58_string

WIF = base58(PK4)
print(WIF)
#keyint = int(PK0, 16)
#print(keyint)
#print(hex(keyint))
#print(keyint)
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
September 13, 2022, 10:05:40 PM
#2
There's also a pure Python implementation of the RIPEMD160 hash[1] if you want to use that, especially given that OpenSSL is wants/is deprecating its RIPEMD160 code.

[1]: https://github.com/karpathy/cryptos/blob/main/cryptos/ripemd160.py
legendary
Activity: 2310
Merit: 4313
🔐BitcoinMessage.Tools🔑
September 13, 2022, 03:32:24 AM
#1
A week ago or something, I decided it was a perfect time to start learning to program, and after doing some research, I came to the conclusion that Python is a good programming language to start with. In my opinion, the best approach to learning something is practice and practice, which is why I think that writing programs is the best way to learn how to write good programs. By combining my theoretical interest in Bitcoin and practical interest in programming, I believe I can implement things (related to Bitcoin and other  fields) that I previously only read about and make them more "real."

Below is a program that takes a private key in hex format, converts it to WIF (compressed and uncompressed), calculates public keys (compressed and uncompressed) and corresponding addresses. Functions that do elliptic curve calculation (modulo inverse, point addition, doubling and multiplication) and elliptic curve parameters were taken from here: https://github.com/wobine/blackboard101

Code:
import hashlib
import base58

class PublicKey:
    """Calculating public key from private key"""

    def __init__(self, private_key):
        """Initialize parameters of an elliptic curve"""

        self.private_key = private_key
        self.p_curve = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1 # The proven prime
        self.n_curve = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 # Number of points in the field
        self.a_curve, self.b_curve = 0, 7 # These two defines the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve
        self.gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
        self.gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
        self.gpoint = (self.gx, self.gy) # This is generator point.

    def hash(self, key):
        """Function performing SHA-256 hashing"""

        sha = hashlib.sha256()
        sha.update(bytes.fromhex(key))
        return sha.hexdigest()

    def public_address(self, key):
        """Function calculating address"""

        ripemd = hashlib.new('ripemd160')
        sha = hashlib.sha256()
        sha.update(bytes.fromhex(key))
        ripemd.update(sha.digest())
        address = f"00{ripemd.hexdigest()}"
        checksum = self.hash(self.hash(address))[:8]
        address = f"{address}{checksum}"
        address = base58.b58encode(bytes.fromhex(address)).decode("UTF-8")
        return address

    def privatewif(self):
        """Converting a private key to WIF"""

        private_wif = f"80{hex(self.private_key)[2:]}"
        private_wif_comp = f"80{hex(self.private_key)[2:]}01"

        checksum = self.hash(self.hash(private_wif))[:8]
        checksum_comp = self.hash(self.hash(private_wif_comp))[:8]

        private_wif = f"{private_wif}{checksum}"
        private_wif_comp = f"{private_wif_comp}{checksum_comp}"

        private_wif = base58.b58encode(bytes.fromhex(private_wif)).decode("UTF-8")
        private_wif_comp = base58.b58encode(bytes.fromhex(private_wif_comp)).decode("UTF-8")

        print(f"\nWIF - private key\n{private_wif}")
        print(f"Length: {len(private_wif)}\n")
        print(f"WIF compressed - private key\n{private_wif_comp}")
        print(f"Length: {len(private_wif_comp)}\n")

    def modinv(self, a, n):
        """Extended Euclidean Algorithm"""

        lm, hm = 1, 0
        low, high = a%n, n
        while low > 1:
            ratio = int(high/low)
            nm, new = int(hm-lm*ratio), int(high-low*ratio)
            lm, low, hm, high = nm, new, lm, low
        return lm % n

    def ec_add(self, a, b):
        """Point addition"""

        lam_add = ((b[1]-a[1]) * self.modinv(b[0]-a[0], self.p_curve)) % self.p_curve
        x = (pow(lam_add, 2)-a[0]-b[0]) % self.p_curve
        y = (lam_add*(a[0]-x)-a[1]) % self.p_curve
        return x, y

    def ec_double(self, a):
        """EC point doubling"""

        lam = ((3*a[0]*a[0]+self.a_curve) * self.modinv((2*a[1]), self.p_curve)) % self.p_curve
        x = int((lam*lam-2*a[0]) % self.p_curve)
        y = int((lam*(a[0]-x)-a[1]) % self.p_curve)
        return x, y

    def ec_multiply(self, genpoint, scalarhex):
        """EC point multiplication"""

        if scalarhex == 0 or scalarhex >= self.n_curve: raise Exception("Invalid Scalar/Private Key")
        scalarbin = str(bin(scalarhex))[2:]
        q = genpoint
        for i in range (1, len(scalarbin)): #Double and add to multiply point
            q = self.ec_double(q)
            if scalarbin[i] == "1":
                q = self.ec_add(q, genpoint)
        return q

    def public_calc(self):
        """Calculating a public key"""

        public_key = self.ec_multiply(self.gpoint, self.private_key)
        print("\nThe uncompressed public key (not address):")
        print(public_key)
        print("\nThe uncompressed public key (HEX):")
        message = f"04{(hex(public_key[0])[2:]):0>64}{(hex(public_key[1])[2:]):0>64}"
        print(message)
        print(f"Length: {len(message)}\n")
        message = self.public_address(message)
        print(f"Address from uncompressed key\n{message}")
        print("\nThe official Public Key - compressed:")
        if public_key[1] % 2 == 1: # If the Y value for the Public Key is odd.
            message = f"03{hex(public_key[0])[2:]:0>64}"
            print(message)
            print(f"Length: {len(message)}\n")
            message = self.public_address(message)
            print(f"Address from compressed key\n{message}")
        else: # Or else, if the Y value is even.
            message = f"02{hex(public_key[0])[2:]:0>64}"
            print(message)
            print(f"Length: {len(message)}\n")
            message = self.public_address(message)
            print(f"Address from compressed key\n{message}")

prompt = input(f"Please insert your private key in HEX format (0x): ")

try:
    prompt = int(prompt, 16)  # interpret the input as a base-16 number, a hexadecimal.
except ValueError:
    print("You did not enter a hexadecimal number!")
my_key = PublicKey(prompt)
my_key.public_calc()
my_key.privatewif()


Source code is also available here: https://github.com/witcher-sense/learning_python/blob/main/PrivateToPublic.py

It only will work with Python 3.6 or higher, and you will need to make some changes to openssl.conf to get RIPEMD160 hashing working properly.

If you're on Linux, then you can do the following:

To locate a configuration file, insert the following command:
Code:
openssl version -d

Copy the path and change your working directory, for example:
Code:
cd /usr/lib/ssl/

Open openssl.conf in any text editor. You will need a super user rights to edit this file. If you don't have it, ask your administrator for help:

Code:
sudo nano openssl.conf

Add the following lines to a configuration file (some of them are already there and some are waiting for "uncommenting"):

Code:
openssl_conf = openssl_init

[openssl_init]
providers = provider_sect

[provider_sect]
default = default_sect
legacy = legacy_sect

[default_sect]
activate = 1

[legacy_sect]
activate = 1


After these manipulations, RIPEDMD should start working.

Jump to: