使用fastecdsa实现ScroogeCoin时签名报错:无法将整数转字节
ScroogeCoin实现中fastecdsa签名报错排查
问题详情
使用fastecdsa库实现ScroogeCoin时,调用create_coins函数触发类型错误,报错指向签名代码tx["signature"] = ecdsa.sign(...),提示无法将整数转换为字节。已尝试对tx["hash"]使用encode()、bytes.fromhex()等转换方式,仍未解决。
相关代码
import hashlib import json from fastecdsa import keys, curve, ecdsa class ScroogeCoin(object): def __init__(self): self.private_key, self.public_key = keys.gen_keypair(curve.secp256k1) self.address = hashlib.sha256(json.dumps(self.public_key.x).encode()).hexdigest() self.chain = [] self.current_transactions = [] def create_coins(self, receivers: dict): """Scrooge adds value to some coins""" tx = { "sender" : self.address, "location": {"block": -1, "tx": -1}, "receivers" : receivers, } tx["hash"] = hashlib.sha256(json.dumps(tx).encode()).hexdigest() tx["signature"] = ecdsa.sign(self.private_key, tx["hash"]) self.current_transactions.append(tx) ...
报错信息
Traceback (most recent call last): File "D:\Scrooge_coin_assignmnet.py", line 216, in <module> main() File "D:\Scrooge_coin_assignmnet.py", line 197, in main Scrooge.create_coins({users[0].address:10, users[1].address:20, users[3].address:50}) File "D:\Scrooge_coin_assignmnet.py", line 27, in create_coins tx["signature"] = ecdsa.sign(self.private_key, tx["hash"])# signed hash of tx File "C:\Users\d\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastecdsa\ecdsa.py", line 36, in sign rfc6979 = RFC6979(msg, d, curve.q, hashfunc, prehashed=prehashed) File "C:\Users\d\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastecdsa\util.py", line 25, in __init__ self.msg = msg_bytes(msg) File "C:\Users\d\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastecdsa\util.py", line 153, in msg_bytes raise ValueError('Msg "{}" of type {} cannot be converted to bytes'.format( ValueError: Msg "21783419755125685845542189331366569080312572314742637241373298325693730090205" of type <class 'int'> cannot be converted to bytes
错误原因
- 参数顺序完全颠倒:fastecdsa的
ecdsa.sign函数定义为sign(msg, d, curve=curve.P256, ...),第一个参数是待签名的消息,第二个参数是私钥。当前代码把私钥放在第一个参数位置,交易哈希放在第二个,导致私钥被当作消息处理,而哈希字符串被误解析为整数,触发类型错误。 - 哈希格式处理不当:即使参数顺序正确,直接传入十六进制哈希字符串也会导致库尝试将其解析为整数,需要传递字节类型的哈希值,或配合
prehashed=True参数使用。
解决方案
修改签名代码的参数顺序,并正确处理哈希的字节格式,同时利用prehashed=True跳过重复哈希(因为我们已经对交易做了SHA256哈希):
修改后的create_coins函数
def create_coins(self, receivers: dict): """Scrooge adds value to some coins""" tx = { "sender" : self.address, "location": {"block": -1, "tx": -1}, "receivers" : receivers, } # 直接获取字节类型的SHA256哈希,同时存十六进制字符串到tx["hash"] tx_hash_bytes = hashlib.sha256(json.dumps(tx).encode()).digest() tx["hash"] = tx_hash_bytes.hex() # 修正参数顺序:消息在前,私钥在后,指定曲线并启用prehashed tx["signature"] = ecdsa.sign(tx_hash_bytes, self.private_key, curve=curve.secp256k1, prehashed=True) self.current_transactions.append(tx)
关键说明
- 调整
ecdsa.sign的参数顺序是核心修复点,必须保证消息(哈希值)在前,私钥在后。 - 使用
digest()获取字节哈希比先转十六进制再转回字节更高效,也避免字符串解析错误。 prehashed=True告诉库我们传入的已经是哈希后的结果,不需要再对消息执行哈希操作,符合签名逻辑。
内容的提问来源于stack exchange,提问作者Bruce Huynh
相关产品推荐
相关产品推荐

