【问题标题】:How to sign and verify signature with ecdsa in python如何在python中使用ecdsa签名和验证签名
【发布时间】:2016-03-30 19:19:59
【问题描述】:

我需要使用 256 位的私钥使用 ECDSA 签署一个 256 位的哈希,就像比特币一样,由于 python 中缺少 ecdsa 的文档,我感到绝望。

我在互联网上找到了很多代码,但没有什么比ecdsa.sign(msg, privkey) 或类似的简单,我找到的所有东西都是很多我不懂的数学代码,但他们使用 ecdsa库(我不知道他们为什么不在用于签名的库中添加签名功能,而是在使用库时需要一页代码?)。

这是迄今为止我发现的最好的代码:

def ecdsa_sign(val, secret_exponent):
    """Return a signature for the provided hash, using the provided
    random nonce. It is absolutely vital that random_k be an unpredictable
    number in the range [1, self.public_key.point.order()-1].  If
    an attacker can guess random_k, he can compute our private key from a
    single signature. Also, if an attacker knows a few high-order
    bits (or a few low-order bits) of random_k, he can compute our private
    key from many signatures. The generation of nonces with adequate
    cryptographic strength is very difficult and far beyond the scope
    of this comment.

    May raise RuntimeError, in which case retrying with a new
    random value k is in order.
    """
    G = ecdsa.SECP256k1
    n = G.order()
    k = deterministic_generate_k(n, secret_exponent, val)
    p1 = k * G
    r = p1.x()
    if r == 0: raise RuntimeError("amazingly unlucky random number r")
    s = ( ecdsa.numbertheory.inverse_mod( k, n ) * ( val + ( secret_exponent * r ) % n ) ) % n
    if s == 0: raise RuntimeError("amazingly unlucky random number s")

    return signature_to_der(r, s)

def deterministic_generate_k(generator_order, secret_exponent, val, hash_f=hashlib.sha256):
    """
    Generate K value according to https://tools.ietf.org/html/rfc6979
    """
    n = generator_order
    order_size = (bit_length(n) + 7) // 8
    hash_size = hash_f().digest_size
    v = b'\x01' * hash_size
    k = b'\x00' * hash_size
    priv = intbytes.to_bytes(secret_exponent, length=order_size)
    shift = 8 * hash_size - bit_length(n)
    if shift > 0:
        val >>= shift
    if val > n:
        val -= n
    h1 = intbytes.to_bytes(val, length=order_size)
    k = hmac.new(k, v + b'\x00' + priv + h1, hash_f).digest()
    v = hmac.new(k, v, hash_f).digest()
    k = hmac.new(k, v + b'\x01' + priv + h1, hash_f).digest()
    v = hmac.new(k, v, hash_f).digest()

    while 1:
        t = bytearray()

        while len(t) < order_size:
            v = hmac.new(k, v, hash_f).digest()
            t.extend(v)

        k1 = intbytes.from_bytes(bytes(t))

        k1 >>= (len(t)*8 - bit_length(n))
        if k1 >= 1 and k1 < n:
            return k1

        k = hmac.new(k, v + b'\x00', hash_f).digest()
        v = hmac.new(k, v, hash_f).digest()

但我就是不能相信这样的代码,因为我不知道它的作用。此外,ecdsa_sign 中的 cmets 表示返回给定值、秘密指数、和随机数的签名。它说拥有一个 nonce 非常重要,但我就是不知道那个 nonce 在哪里。

是否有任何简单的单行方法可以在 windows 上使用 python 中的任何受信任库来签署和验证 ECDSA 签名?

【问题讨论】:

标签: python ecdsa


【解决方案1】:

您可以尝试使用python ecdsa包,使用Python3:

pip3 install ecdsa

用法:

import ecdsa

# SECP256k1 is the Bitcoin elliptic curve
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1) 
vk = sk.get_verifying_key()
sig = sk.sign(b"message")
vk.verify(sig, b"message") # True

使用公钥验证现有签名:

import ecdsa
from hashlib import sha256
message = b"message"
public_key = '98cedbb266d9fc38e41a169362708e0509e06b3040a5dfff6e08196f8d9e49cebfb4f4cb12aa7ac34b19f3b29a17f4e5464873f151fd699c2524e0b7843eb383'
sig = '740894121e1c7f33b174153a7349f6899d0a1d2730e9cc59f674921d8aef73532f63edb9c5dba4877074a937448a37c5c485e0d53419297967e95e9b1bef630d'

vk = ecdsa.VerifyingKey.from_string(bytes.fromhex(public_key), curve=ecdsa.SECP256k1, hashfunc=sha256) # the default is sha1
vk.verify(bytes.fromhex(sig), message) # True

该软件包也与 Python 2 兼容

【讨论】:

  • 您也可以使用 sign_digest 和 verify_digest 来处理摘要数据,例如,如果您以二进制形式传递 sha256 哈希。
  • 有什么办法可以让按键变小?例如,定义它们的最大尺寸?
  • @k26dr 谢谢。当!我将它用于区块链......而且我已经写了足够多的区块链工作,只是没有公钥验证。这么长的公钥没有空间……所以现有的区块链是垃圾。哦,好吧,大声笑。
  • @Nuclear_Man_D 如果你的意思是这个例子生成的公钥对于区块链来说太长了,那么你是对的。这就是为什么比特币会用公钥做一些额外的事情!
  • 小错字。两个样本都需要import ecdsa,否则会抛出NameError: name 'ecdsa' is not defined错误。
【解决方案2】:

如何安装:

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

【讨论】:

    【解决方案3】:

    您还可以使用 Python 中的 sep256k1 库来进行 ecdsa 签名和验证。公钥和私钥是从 Bip32 规范生成的密钥和从 Bip39 规范生成的种子。

     Private key  is  1149ab92fbc40993f21336206ca184a9dc2d5231eb575d2a0a6d56773bf0f356
     Public key  is  03c7ac999403591bceacca3d37598886f7c41943c8045c7e1cb5a9295d0003cc5b
    
    
    from sawtooth_signing.secp256k1 import Secp256k1PrivateKey
    from sawtooth_signing.secp256k1 import Secp256k1PublicKey
    
    def sign_nonce(hex_private_key):
       nonce = random.randint(2**10, 2**32)
       checksum = hashlib.sha3_512(str(nonce).encode()).hexdigest()
    
       private_key = Secp256k1PrivateKey.from_hex(hex_private_key)
       message = private_key.secp256k1_private_key.ecdsa_sign(str(nonce).encode())
       serialized_message = private_key.secp256k1_private_key.ecdsa_serialize(message)
       hex_message = binascii.hexlify(serialized_message)
       return nonce, checksum, hex_message
    
    
    def verify_nonce(nonce, checksum, message, hex_public_key):
       ##message is hex encoded
       message = binascii.unhexlify(message)
       public_key = Secp256k1PublicKey.from_hex(hex_public_key)
       unserialized = public_key.secp256k1_public_key.ecdsa_deserialize(message)
       result = public_key.secp256k1_public_key.ecdsa_verify(str(nonce).encode(),    unserialized)
      return result
    

    根据验证结果将是 True 或 False。 我使用 uint32(typings) 或 int 作为随机数,但可以使用任何字节数组或字符串。字符串需要转换为字节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-11
      • 2018-01-17
      • 1970-01-01
      • 2020-07-11
      • 2014-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多