python-ecdsa签名大小正确吗? [英] Is python-ecdsa signature size correct?

查看:289
本文介绍了python-ecdsa签名大小正确吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在比特币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
  • 比特币Wiki不正确
  • python-ecdsa实施不正确

前两个是更可能的.

有人可以向我解释为什么我的期望值与实际获得的值不匹配吗?

解决方案

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

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

  1. r和s被DER编码为ASN.1 SEQUENCE中的两个ASN.1带符号的INTEGER类型.
  2. r和s编码为两个静态大小的无符号整数,其大小与键大小(或顺序)相同,以八位字节或字节为单位.

所以大小上的差异只是因为值r和s编码不同.当然,在验证签名之前,您需要知道编码的类型.

由于r和s完全独立于编码,因此在两个版本之间进行转换相对简单(如果您可以将任何需要生成或解析DER编码的ASN.1结构的调用称为简单")./p>

类型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软件包仅使用了不同的编码,您会感到惊讶.

  • 比特币Wiki不正确

不,比特币Wiki假定为其协议选择了特定的编码.

  • 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或八进制字符串的整数"原语.请注意,代码中的字符串"是指八位字节字符串,也称为字节数组-不是文本字符串.

On the bitcoin wiki I found that bitcoin uses the ECDSA algorithm with the Secp256k1 curve.

Relevant Links:

On the first link, it says private key should be 32 bytes, public key 64 bytes, and the signature typically between 71-73 bytes. It says the signature can be smaller with small probability.

However, when I run the following python3 code

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

I get (32, 64, 64) as output. I'd expect to get something like (32, 64, 72).

I figure one of the following is happening:

  • I am misunderstanding the wiki article.
  • I am using python-ecdsa incorrectly
  • the bitcoin wiki is incorrect
  • python-ecdsa is not implemented correctly

The first two are the more likely ones.

Can anyone explain to me why I am getting a mismatch between what I expect, and what I am actually getting?

解决方案

An ECDSA signature consists of two numbers, r and s which are numbers in the range [1..n-1] where n is the order of the curve. n is a (known) number in the range [2^(k-1)..2^k-1] where k is the key size. So the size of r and s are generally the same and sometimes somewhat smaller as the key size in bytes.

Now r and s can be encoded in multiple ways, of which two are common:

  1. r and s are DER encoded as two ASN.1 signed INTEGER types within an ASN.1 SEQUENCE.
  2. r and s are encoded as two statically sized, unsigned integers with the same size as the key size (or order) in octets or bytes.

So the difference in size is just because the values r and s are encoded differently. Of course, you need to know the type of encoding before you can verify the signature.

As r and s are exactly the same independents of the encoding it is relatively simple to convert between the two versions (if you can call anything that requires generation or parsing of DER-encoded ASN.1 structures "simple").

Type 1 has been standardized in ANSI X9.62 and type 2, often called a flat encoding, is commonly used on embedded platforms or smart cards.


r and s are just very likely the same size as n / the key size, but in principle, they could be e.g. a number 3. The chance of that happening is abysmally small. You should, however, not perform any tests on the size of r and s. If either of them is more than 8 bytes smaller then you may start to scratch your head because the chance of that happening is between 1/2^63 and 1/2^64, i.e. extremely unlikely.


So:

  • I am misunderstanding the wiki article.

No, the wiki article assumes the standardized encoding of ANSI X9.62.

  • I am using python-ecdsa incorrectly

No, the python-ecdsa package just uses a different encoding and you are surprised.

  • the bitcoin wiki is incorrect

No, the bitcoin wiki assumed a particular encoding chosen for their protocol.

  • python-ecdsa is not implemented correctly

Definitely not; at least not with regards to the size of the signature.


Now for the implementation details; the following is in the documentation:

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.

So try to use sigencode=sigencode_der to get the format expected by the wiki article. The util.py source has all the conversions you are likely to need. It uses number_to_string to create statically sized numbers. This function is also known as I2OSP or Integer to Octet String primitive in PKCS#1 (RSA). Note that "strings" in the code refer to octet strings, also known as byte arrays - not text strings.

这篇关于python-ecdsa签名大小正确吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆