Is python-ecdsa signature size correct?

与世无争的帅哥 提交于 2020-04-11 05:03:23

问题


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

Relevant Links:

  • https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm
  • https://en.bitcoin.it/wiki/Secp256k1

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?


回答1:


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.




回答2:


The only problem with python-ecdsa is performance, because it's too slow.

A better library: starkbank-ecdsa

How to install it:

pip install starkbank-ecdsa

How to use it:

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

Full reference: https://github.com/starkbank/ecdsa-python



来源:https://stackoverflow.com/questions/50304509/is-python-ecdsa-signature-size-correct

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!