1

I'm trying to write a script that can generate a private key and the compressed and uncompressed addresses. It seems to work however the private key doesn't correspond to the addresses generated. Can't seem to find where I'm going wrong though...


import hashlib
import base58
import secrets
import ecdsa

# generate private key using secure random number generator
private_key = secrets.randbelow(2**256)

# convert private key to hexadecimal format
private_key_hex = hex(private_key)[2:]

# generate public key using private key and Elliptic Curve Digital Signature Algorithm (ECDSA)
public_key = ecdsa.SigningKey.from_string(bytes.fromhex(private_key_hex), curve=ecdsa.SECP256k1).verifying_key

# convert public key to hexadecimal format
public_key_hex = public_key.to_string().hex()

# generate uncompressed bitcoin address by hashing public key with SHA-256 and RIPEMD-160
uncompressed_address = hashlib.new('ripemd160', hashlib.sha256(bytes.fromhex(public_key_hex)).digest()).hexdigest()

# add prefix "00" to uncompressed address to indicate it is an uncompressed address
uncompressed_address = "00" + uncompressed_address

# generate checksum by hashing address with SHA-256 twice
checksum = hashlib.sha256(hashlib.sha256(bytes.fromhex(uncompressed_address)).digest()).hexdigest()[:8]

# add checksum to address
uncompressed_address += checksum

# encode address in base58 format
uncompressed_address = base58.b58encode(bytes.fromhex(uncompressed_address))

# generate compressed bitcoin address by adding prefix "03" to public key if it is odd, or "02" if it is even
if public_key_hex[-1] in ["1", "3", "5", "7", "9", "b", "d", "f"]:
    compressed_address = "03" + public_key_hex[:66]
else:
    compressed_address = "02" + public_key_hex[:66]

# hash compressed address with SHA-256 and RIPEMD-160
compressed_address = hashlib.new('ripemd160', hashlib.sha256(bytes.fromhex(compressed_address)).digest()).hexdigest()

# add prefix "00" to compressed address to indicate it is a compressed address
compressed_address = "00" + compressed_address

# generate checksum by hashing address with SHA-256 twice
checksum = hashlib.sha256(hashlib.sha256(bytes.fromhex(compressed_address)).digest()).hexdigest()[:8]

# add checksum to address
compressed_address += checksum

# encode address in base58 format
compressed_address = base58.b58encode(bytes.fromhex(compressed_address))

print("Private key:", private_key_hex)
print("Uncompressed address:", uncompressed_address)
print("Compressed address:", compressed_address)
0

1 Answer 1

2

Some key points here:

  • The private key cannot reach 2**256 because you must respect the order of the curve, which is n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141. Set the interval to [1, n).
  • "add prefix "00" to uncompressed address to indicate it is an uncompressed address". It's not because of that. It's to indicate that the address is used for mainnet. If testnet, use 0x6f. (Only p2pkh)
  • The uncompressed public key has the format '04' + x + y = 65 bytes = 130 hex characters. I haven't seen any mention of it in your code. Make sure the variable public_key_hex follows the format.
  • The compressed public key has the format '02' + x or '03' + x, depending on the y is even or odd, respectively. (33 bytes = 66 hex chars)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.