You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Python的bitcoinlib库对原始文本消息进行签名并生成Base64编码的有效签名?

如何使用Python的bitcoinlib库对原始文本消息进行签名并生成Base64编码的有效签名?

你遇到的问题其实很典型——bitcoinlib确实把主要精力放在了比特币交易处理上,直接用Transaction类来签消息完全走偏了,它根本不是干这个的!咱们换个思路,利用bitcoinlib的Key类底层的ECDSA能力,手动实现比特币标准的消息签名流程就行。

先说说你原来代码的问题

你之前误用了Transaction类:

  • Transaction.inputs_add()是用来添加交易输入的,和消息签名完全不相关,自然会报错;
  • Transaction.sign()的参数是为交易签名设计的,根本不支持传入自定义消息,所以这条路走不通。

正确解决方案:基于比特币标准手动实现

比特币的消息签名有一套固定规范,我们可以基于Key类的底层能力来实现:

  1. 按照比特币要求构造待签名的消息payload(必须加上特定前缀和消息长度,防止签名被恶意复用在其他场景);
  2. 对payload做双重SHA256哈希;
  3. 用私钥对哈希值签名;
  4. 把签名结果转成Base64编码。

修改后的完整代码

from bitcoinlib.keys import Key
import hashlib
import base64

class BitcoinClient:
    def __init__(self, private_key_wif: str) -> None:
        """
        Initialize the BitcoinClient with a WIF private key.

        :param private_key_wif: The private key in Wallet Import Format (WIF).
        """
        self.key = Key(import_key=private_key_wif)
        self.address = self.key.address()

    def get_address(self) -> str:
        """
        Get the Bitcoin address associated with the private key.

        :return: Bitcoin address as a string.
        """
        return self.address

    def sign_message(self, message: str) -> str:
        """
        Sign a message using the private key, following Bitcoin's message signing standard.

        :param message: The message to be signed.
        :return: The signature as a base64-encoded string.
        """
        # 将消息转为UTF-8字节
        message_bytes = message.encode('utf-8')
        # 构造比特币标准的消息前缀+内容
        prefix = "Bitcoin Signed Message:\n"
        payload = f"{prefix}{len(message_bytes)}\n{message}".encode('utf-8')
        # 计算双重SHA256哈希
        double_hash = hashlib.sha256(hashlib.sha256(payload).digest()).digest()
        # 用私钥签名哈希(use_hash=False表示我们已经自己算好哈希了)
        signature_bytes = self.key.sign(double_hash, use_hash=False)
        # 转成Base64编码返回
        return base64.b64encode(signature_bytes).decode('utf-8')

    def verify_message(self, message: str, signature: str) -> bool:
        """
        Verify a signed message against the Bitcoin address.

        :param message: The original message.
        :param signature: The base64-encoded signature to verify.
        :return: True if the signature is valid, False otherwise.
        """
        message_bytes = message.encode('utf-8')
        prefix = "Bitcoin Signed Message:\n"
        payload = f"{prefix}{len(message_bytes)}\n{message}".encode('utf-8')
        double_hash = hashlib.sha256(hashlib.sha256(payload).digest()).digest()
        # 解码Base64签名
        signature_bytes = base64.b64decode(signature)
        # 验证签名
        return self.key.verify(double_hash, signature_bytes, use_hash=False)

if __name__ == "__main__":
    # 填入你的WIF私钥和测试消息
    private_key_wif = "你的WIF私钥"
    message = "Hello world!"

    try:
        signer = BitcoinClient(private_key_wif)
        signature = signer.sign_message(message)
        address = signer.get_address()
        is_valid = signer.verify_message(message, signature)

        print(f"Bitcoin Address: {address}")
        print(f"Signature: {signature}")
        print(f"Is signature valid: {is_valid}")
    except ValueError as e:
        print(f"Error: {e}")

关键要点说明

  • 我们完全抛弃了Transaction类,直接用Key类的signverify方法,这两个方法可以直接处理原始哈希值;
  • 设置use_hash=False非常重要:bitcoinlib的sign方法默认会对输入数据做哈希,而我们已经按照比特币标准计算了双重SHA256哈希,所以必须跳过内置的哈希步骤;
  • 构造payload时严格遵循比特币规范,这样生成的签名可以被其他比特币工具(比如Bitcoin Core钱包)验证。

补充说明

如果你未来升级bitcoinlib到更高版本,可能会发现Key类已经内置了sign_messageverify_message方法,到时候直接调用就行,但在0.6.0版本里,手动实现是最可靠的方案。

备注:内容来源于stack exchange,提问作者Sorry_my_code_is_dumb

火山引擎 最新活动