Python的签名大小正确吗?

2024-07-08 11:19:04 发布

您现在位置:Python中文网/ 问答频道 /正文

在比特币wiki上,我发现比特币使用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未正确实现

前两个是更有可能的。在

有谁能解释一下为什么我的期望值和实际值不匹配?在


Tags: keyhttpslen字节链接wikiitprivate
2条回答

ECDSA签名由两个数字组成,r和s是在[1..n-1]范围内的数字,其中n是曲线的顺序。n是[2^(k-1)…2^k-1]范围内的(已知)数字,其中k是密钥大小。因此r和s的大小通常是相同的,有时会比密钥大小(字节)小一些。在

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

  1. r和s在一个ASN.1序列中被DER编码为两个ASN.1有符号整数类型。在
  2. r和s被编码为两个静态大小的无符号整数,其大小与密钥大小(或顺序)相同(以八位字节或字节为单位)。在

所以大小的不同仅仅是因为r和s的编码方式不同。当然,在验证签名之前,您需要知道编码的类型。在

由于r和s完全独立于编码,所以在两个版本之间转换相对简单(如果您可以将任何需要生成或解析DER编码的ASN.1结构称为“simple”)。在

类型1在ansix9.62中已经被标准化,而类型2,通常称为平面编码,通常用于嵌入式平台或智能卡。在


r和s很可能与n/密钥大小相同,但原则上,它们可以是数字3。这种情况发生的可能性微乎其微。但是,您应该对r和s的大小执行任何测试。如果其中任何一个小于8字节,那么您可能会开始挠头,因为发生这种情况的可能性在1/2^63和1/2^64之间,即极不可能。在


所以:

  • 我误解了维基的文章。在

不,wiki文章假设标准化编码是ansix9.62。在

  • 我错误地使用了python ecdsa

不,python ecdsa包只是使用了不同的编码,您会感到惊讶。在

  • 比特币维基不正确

不,比特币wiki假设他们的协议选择了一种特定的编码方式。在

  • python ecdsa未正确实现

绝对没有;至少在签名的大小上没有。在


现在了解实施细节;文档中包含以下内容:

There are also multiple ways to represent a signature. The default sk.sign() and vk.verify() methods present it as a short string, for simplicity and minimal overhead. To use a different scheme, use the sk.sign(sigencode=) and vk.verify(sigdecode=) arguments. There are helper functions in the "ecdsa.util" module that can be useful here.

所以尝试使用sigencode=sigencode_der来获得wiki文章所期望的格式。^{}源具有您可能需要的所有转换。它使用number_to_string来创建静态大小的数字。此函数在PKCS#1(RSA)中也称为I2OSP或整数到八位字节字符串原语。请注意,代码中的“字符串”指的是八位字节字符串,也称为字节数组,而不是文本字符串。在

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

相关问题 更多 >

    热门问题