生成比特币地址时fromhex()非十六进制字符错误求助
比特币地址生成程序偶发非十六进制字符错误
问题代码
生成私钥的方法:
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
生成压缩公钥的方法:
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:]
生成比特币地址的核心方法:
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
运行代码:
for i in range(100): private_key = str(hex(get_private_key()))[2:] address = generate_bitcoin_address(private_key)
错误信息
偶发如下报错:
Public key's hash = 00ededa6d1865639736123207949b0d57dfaf007ed Public key's hash = 000069e3aabbec21d1332740e1440c651c48709819 ... 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
错误原因
问题出在get_compressed_public_key方法中:
- SECP256K1的公钥x坐标是256位整数,但其十六进制表示长度可能不足64位(当高位有0时,
hex()函数不会自动补前导零)。 - 例如,若x坐标的十六进制是63个字符,拼接"02"/"03"后总长度为65(奇数),
bytes.fromhex()要求输入字符串长度为偶数,单个字符无法解析为一个字节,因此触发错误(Python错误提示表述不够直观,实际是长度不匹配导致解析失败)。
修复方案
修改get_compressed_public_key方法,确保x坐标的十六进制字符串固定为64位,不足时补前导零:
def get_compressed_public_key(key): public_key = double_and_add(key, G) # 格式化x坐标为64位十六进制字符串,自动补前导零 x_hex = format(public_key[0], '064x') if public_key[1] % 2 == 0 : return "02" + x_hex else : return "03" + x_hex
使用format(num, '064x')可以保证输出的十六进制字符串恰好64位,拼接后总长度为66(对应33字节的压缩公钥),满足bytes.fromhex()的要求,彻底解决偶发错误。
内容的提问来源于stack exchange,提问作者Dino_coder
相关产品推荐
相关产品推荐

