python-ecdsa签名大小是否正确?

时间:2018-05-12 09:00:04

标签: python cryptography bitcoin ecdsa

在比特币维基上,我发现比特币使用的是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)这样的东西。

我认为发生了以下情况之一:

  • 我误解了维基文章。
  • 我错误地使用了python-ecdsa
  • 比特币维基不正确
  • python-ecdsa未正确实施

前两个更有可能。

任何人都可以向我解释为什么我的期望与我实际得到的不匹配?

2 个答案:

答案 0 :(得分:3)

ECDSA签名由两个数字r和s组成,它们是[1..n-1]范围内的数字,其中n是曲线的阶数。 n是[2 ^(k-1)... 2 ^ k-1]范围内的(已知)数,其中k是密钥大小。因此,r和s的大小通常是相同的,有时候也会像键大小一样小。

现在r和s可以用多种方式编码,其中两种是常见的:

  1. r和s在一个ASN.1 SEQUENCE中被编码为两个ASN.1签名的INTEGER类型。
  2. r和s被编码为两个静态大小的无符号整数,其大小与密钥大小(或顺序)以八位字节或字节相同。
  3. 因此,大小的差异只是因为值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

    不,python-ecdsa包只使用不同的编码,你会感到惊讶。

    • 比特币维基不正确

    不,比特币维基假定为其协议选择了特定的编码。

    • 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)

完整参考:https://github.com/starkbank/ecdsa-python