I made a program that makes Bitcoin Address with random private key. Some variables and methods that do not have a separate description are the fixed values of the SECP256K1 elliptic curve. As they are not related to errors, I omitted them.
get_private_key method returns random 256 bit int private key.
def get_private_key():
while (True):
random_str = os.urandom(256 // 8) + str(random.random()).encode() + str(time.time()).encode()
random_num = hashlib.sha256(random_str).digest()
private_key = int.from_bytes(random_num, 'big')
if private_key < q-1:
break
return private_key
And generate the public key in the following method. (double_and_add method returns tuple that has two add-calculated 256 bit ints.) get_compressed_public_key method returns 33bytes hexadecimal number in string without 0x.
def get_compressed_public_key(key):
public_key = double_and_add(key, G)
if public_key[1] % 2 == 0 :
return "02" + str(hex(public_key[0]))[2:]
else :
return "03" + str(hex(public_key[0]))[2:]
generate_bitcoin_address method returns 25byte btcoin address with hash160 method and returns 25byte bitcoin address.
def hash160(data):
sha256_hash = SHA256.new(data)
ripemd160_hash = RIPEMD160.new(sha256_hash.digest())
return ripemd160_hash.hexdigest()
def generate_bitcoin_address(key):
# Generate compressed public key
hex_val = int(key, 16)
compressed_pkey = get_compressed_public_key(hex_val)
**data = bytes.fromhex(compressed_pkey)**
hash160_val = "00" + hash160(data)
print("Public Key's hash =", hash160_val)
# Get Checksum Value
sha256_first = SHA256.new(bytes.fromhex(hash160_val))
sha256_second = SHA256.new(bytes.fromhex(sha256_first.hexdigest()))
checksum = sha256_second.hexdigest()[:8]
# Returns 25byte Bitcoin Address.
return hash160_val + checksum
When I run code like this,
for i in range(100):
private_key = str(hex(get_private_key()))[2:]
address = generate_bitcoin_address(private_key)
I expected 100 prints of Public key's hash. However, It runs several times sometimes and give me following results.
Public key's hash = 00ededa6d1865639736123207949b0d57dfaf007ed
Public key's hash = 000069e3aabbec21d1332740e1440c651c48709819
Public key's hash = 00afc95e037950b2ea956aa6b53a7a050beb8b0630
Public key's hash = 00e20cb4fe60856bd9201f0ddc65eac5e8df69e6f8
Public key's hash = 00d2b0c84885e9e97df2db00774662ad5fe0aaf3fa
Public key's hash = 0028c2bc126e96eba5a6eee68cee5f1300fe1d87cd
Traceback (most recent call last):
File "c:\Users\asn68\Desktop\a\2.py", line 112, in <module>
address = generate_bitcoin_address(private_key)
File "c:\Users\asn68\Desktop\a\2.py", line 86, in generate_bitcoin_address
data = bytes.fromhex(compressed_pkey)
ValueError: non-hexadecimal number found in fromhex() arg at position 65
compressed_pkey is a 33bytes hex in str. No matter what random privatekey comes in, compressed_pkey must be 33bytes hex in string. I don't know why console says it's non-hexadecimal number.
If i print compressed_pkey together, it gives me values like these.
0344f0ff20daa00ff16e265af78eeba9a77493a889ab211b04135f94f3a8d80962
Public key's hash = 000163aedee962317a67ca493cb8ff69e0f8f417ae
0293079d9372346d0584e364a9cfd696a03046ec08e1d6108ffb0b5ae1aa408d11
Public key's hash = 0076c593b889dbef7e9b97c7a6ef0cf1a766ea1540
03c7a2e36cbe7d5c59ca9b193c87aeef88aa48339b250399c79d2f3035821dc850
Public key's hash = 0032896aff3ef34ecabb558b53e79a69badeac3875
0359a4924371f48435d539ef9a15e6b67a5f7ccdca0b7b585c7bdcd7c954a3ba1a
Public key's hash = 00cc34ab18e0a61d23af3dc7bb43fb5e626b061a80
and occurs same error.
It's hard to tell definitely without proper debugging, but most probably the reason is that the string passed to bytes.fromhex()
should contain two hexadecimal digits per byte, but if you try to pass the odd number of digits, it would raise the error, e.g.:
x = str(hex(1234)[2:]) # '4d2'
_ = bytes.fromhex(x) # ValueError: non-hexadecimal number found in fromhex() arg at position 3
You need to make sure that the value returned from get_compressed_public_key()
has an even number of hexadecimal digits.