在比特币维基上,我发现比特币使用的是ECDSA算法和Secp256k1曲线。
相关链接:
在第一个链接上,它表示私钥应为32字节,公钥为64字节,签名通常为71-73字节。它表示签名可能更小,概率很小。
但是,当我运行以下python3代码
时>>> from ecdsa import SigningKey, SECP256k1
>>> private_key = SigningKey.generate(curve=SECP256k1)
>>> public_key = private_key.get_verifying_key()
>>> signature = private_key.sign(b'message')
>>> print((len(private_key.to_string()), len(public_key.to_string()), len(signature)))
我得到(32,64,64)作为输出。我希望得到像(32,64,72)这样的东西。
我认为发生了以下情况之一:
前两个更有可能。
任何人都可以向我解释为什么我的期望与我实际得到的不匹配?
答案 0 :(得分:3)
ECDSA签名由两个数字r和s组成,它们是[1..n-1]范围内的数字,其中n是曲线的阶数。 n是[2 ^(k-1)... 2 ^ k-1]范围内的(已知)数,其中k是密钥大小。因此,r和s的大小通常是相同的,有时候也会像键大小一样小。
现在r和s可以用多种方式编码,其中两种是常见的:
因此,大小的差异只是因为值r和s的编码方式不同。当然,在验证签名之前,您需要知道编码类型。
由于r和s完全相同的编码,在两个版本之间进行转换相对简单(如果你可以调用需要生成或解析DER编码的ASN.1结构的任何东西"简单&#34 34。)
类型1已在ANSI X9.62中标准化,类型2(通常称为平面编码)通常用于嵌入式平台或智能卡。
r和s只是可能与n /密钥大小相同的大小,但原则上它们可以是例如数字3.发生这种情况的可能性非常小。但是,你应该不对r和s的大小进行任何测试。如果它们中的任何一个小于8个字节,那么你可能会开始划伤你的头,因为发生这种情况的可能性在1/2 ^ 63和1/2 ^ 64之间,即极不太可能。
所以:
不,wiki文章假定ANSI X9.62的标准化编码。
不,python-ecdsa包只使用不同的编码,你会感到惊讶。
不,比特币维基假定为其协议选择了特定的编码。
绝对不是;至少不是关于签名的大小。
现在了解实施细节;以下是文档:
还有多种方式来表示签名。默认
sk.sign()
和vk.verify()
方法将其显示为短字符串,以简化和最小开销。要使用其他方案,请使用sk.sign(sigencode =)和vk.verify(sigdecode =)参数。 " ecdsa.util"中有辅助功能。这个模块很有用。
因此,请尝试使用sigencode=sigencode_der
来获取Wiki文章所期望的格式。 util.py
来源包含您可能需要的所有转化。它使用number_to_string
创建静态大小的数字。此功能在PKCS#1(RSA)中也称为I2OSP或整数到八位字符串原语。请注意"字符串"在代码中引用八位字符串,也称为字节数组 - 而不是文本字符串。
答案 1 :(得分:0)
python-ecdsa的唯一问题是性能,因为它太慢了。
更好的库:starkbank-ecdsa
如何安装:
pip install starkbank-ecdsa
如何使用它:
# Generate Keys
privateKey = PrivateKey()
publicKey = privateKey.publicKey()
message = "My test message"
# Generate Signature
signature = Ecdsa.sign(message, privateKey)
# Verify if signature is valid
print Ecdsa.verify(message, signature, publicKey)