繁体   English   中英

如何验证 trezor 钱包的签名

[英]How to verify a signature made by trezor wallet

我想验证由我的 trezor 硬件钱包签名的消息。 基本上我有这些信息。

.venv/bin/trezorctl btc get-public-node -n 0
Passphrase required: 
Confirm your passphrase: 
node.depth: 1
node.fingerprint: ea66f037
node.child_num: 0
node.chain_code: e02030f2a7dfb474d53a96cb26febbbe3bd3b9756f4e0a820146ff1fb4e0bd99
node.public_key: 026b4cc594c849a0d9a124725997604bc6a0ec8f100b621b1eaed4c6094619fc46
xpub: xpub69cRfCiJ5BVzesfFdsTgEb29SskY74wYfjTRw5kdctGN2xp1HF4udTP21t68PAQ4CBq1Rn3wAsWr84wiDiRmmSZLwkEkv4qK5T5Y7EXebyQ

$ .venv/bin/trezorctl btc sign-message 'aaa' -n 0
Please confirm action on your Trezor device
Passphrase required: 
Confirm your passphrase: 
message: aaa
address: 17DB2Q3oZVkQAffkpFvF4cwsXggu39iKdQ
signature: IHQ7FDJy6zjwMImIsFcHGdhVxAH7ozoEoelN2EfgKZZ0JVAbvnGN/w8zxiMivqkO8ijw8fXeCMDt0K2OW7q2GF0=

我想使用 python3-ecdsa。 当我想用任何有效的公钥验证签名时,我得到一个 AssertionError: (65, 64),因为签名的 base64.b64decode 是 65 个字节,但应该是 64。当我想加载 node.public_key 时进入 ecdsa.VerifyingKey,我得到一个 AssertionError: (32, 64),因为 bytes.fromhex 返回 32 个字节,但我发现的每个示例都使用 64 个字节作为公钥。 可能我需要将 bip32 xpub 转换为公钥,但我真的不知道如何。

解决方案

python-ecdsa 需要 0.14 或更高版本才能处理公钥的压缩格式。

import ecdsa
import base64
import hashlib

class DoubleSha256:

    def __init__(self, *args, **kwargs):
        self._m = hashlib.sha256(*args, **kwargs)

    def __getattr__(self, attr):
        if attr == 'digest':
            return self.double_digest
        return getattr(self._m, attr)

    def double_digest(self):
        m = hashlib.sha256()
        m.update(self._m.digest())
        return m.digest()


def pad_message(message):
    return "\x18Bitcoin Signed Message:\n".encode('UTF-8') + bytes([len(message)]) + message.encode('UTF-8')


public_key_hex = '026b4cc594c849a0d9a124725997604bc6a0ec8f100b621b1eaed4c6094619fc46'
public_key = bytes.fromhex(public_key_hex)
message = pad_message('aaa')
sig = base64.b64decode('IHQ7FDJy6zjwMImIsFcHGdhVxAH7ozoEoelN2EfgKZZ0JVAbvnGN/w8zxiMivqkO8ijw8fXeCMDt0K2OW7q2GF0=')

vk = ecdsa.VerifyingKey.from_string(public_key, curve=ecdsa.SECP256k1)
print(vk.verify(sig[1:], message, hashfunc=DoubleSha256))

公钥。 从数学上讲,椭圆曲线公钥是曲线上的一个点。 对于比特币使用的椭圆曲线 secp256k1 以及其他 X9 样式(Weierstrass 形式)曲线,(实际上)有两个标准表示最初由 X9.62 建立并被许多其他人重用:

  • 未压缩格式:由一个值为 0x04 的八位字节组成,后跟两个大小等于曲线顺序大小的块,包含(仿射)X 和 Y 坐标。 对于 secp256k1,这是 1+32x2 = 65 个八位字节

  • 压缩格式:由一个值为 0x02 或 0x03 的八位字节组成,指示 Y 坐标的奇偶校验,后跟一个大小等于包含 X 坐标的曲线顺序的块。 对于 secp256k1,这是 1+32 = 33 个八位字节

你的 trezor 输出的公钥是第二种形式,0x02 + 32 个八位字节 = 33 个八位字节。 不是 32。

我从来没有见过一个 X9EC 库(ECDSA 和/或 ECDH)至少不接受标准的未压缩形式,通常两者都接受。 可以想象,您的 Python 库只需要没有前导 0x04 的未压缩形式,但如果是这样,这种无缘无故且相当危险的非标准性,除非在文档或代码中提供了很好的解释,否则会使我怀疑其质量。 如果确实需要将压缩形式转换为未压缩形式,则必须实现曲线方程,对于 secp256k1 可以在标准参考中找到,更不用说许多实现了。 计算x^3 + a*x + b ,在 F_p 中取平方根,并选择具有正确奇偶校验的正值或负值(同意这里的前导字节 0x02)。

“xpub”是分层确定性密钥的 base58check 编码,它不仅是 EC(DSA) 密钥,还为密钥派生过程添加了元数据。 如果你对它进行 base58 解码并删除检查,你会得到(十六进制):

0488B21E01EA66F03700000000E02030F2A7DFB474D53A96CB26FEBBBE3BD3B9756F4E0A820146FF1FB4E0BD99026B4CC594C849A0D9A124725997604BC6A0EC8F100B621B1EAED4C6094619FC46good

完全按照您的显示显示:

0488B21E  fixed prefix 
01  .depth 
EA66F037  .fingerprint
00000000  .child_num
E02030F2A7DFB474D53A96CB26FEBBBE3BD3B9756F4E0A820146FF1FB4E0BD99  .chain_code
026B4CC594C849A0D9A124725997604BC6A0EC8F100B621B1EAED4C6094619FC46  .public_key

确认这一点,(即示于十六进制的字节)026B4CC594C849A0D9A124725997604BC6A0EC8F100B621B1EAED4C6094619FC46是SHA256的RIPEMD160(在示于十六进制字节为)441e1d2adf9ff2a60​​75d71d0d8782228e0df47f8,和前缀的版本字节00 mainnet到和base58check编码给出如所示的地址17DB2Q3oZVkQAffkpFvF4cwsXggu39iKdQ。

签名。 在数学上,X9.62 类型的 ECDSA 签名是两个整数,称为 r 和 s。 有两种不同的标准来表示它们,比特币同时使用这两种标准:

  • ASN.1 DER 格式。 DER 是一种通用编码,包含“标签”和“长度”元数据以及取决于数值的可变长度数据,这里是 r 和 s; 对于 secp256k1,通常这种编码通常是 70 到 72 个八位字节,但偶尔会更少。 然而,为了避免某些“延展性”攻击,当前的比特币需要使用小于曲线顺序一半的“s”值,通常称为“low-s”,这将 ASN.1 DER 编码的最大长度减少到 71 个八位字节。 比特币将其用于交易签名,并在其后面添加一个“sighash”字节(在“scriptsig”又名赎回脚本中),指示有关签名计算方式的某些选项(因此应该进行验证)。

  • “普通”或 P1363 格式。 这是固定长度的,仅由作为固定长度块的 r 和 s 值组成; 对于 secp256k1,这是 64 个八位字节。 比特币将此用于消息签名,但它在开头添加了一个“恢复”字节,以便在必要时从消息和签名中确定公钥,总共 65 个八位字节。

https://bitcoin.stackexchange.com/questions/38351/ecdsa-vrs-what-is-v/38909https://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always -65-13232 字节长

如果您的 python 库是为通用 ECDSA 而不是比特币设计的,并且需要 64 字节的签名,那几乎可以肯定是“普通”格式,它对应于删除第一个字节的比特币消息签名(此处从 base64 解码)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM