Как подписать и проверить подпись с помощью ecdsa в Python

Мне нужно подписать хэш размером 256 бит с ECDSA, используя закрытый ключ на 256 бит, как это делает биткойн, и я дохожу до отчаяния из-за отсутствия документации ecdsa в python.

Я нашел много кодов в Интернете, но не было ничего проще, чем просто 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 говорят, что возвращает подпись с заданным значением, секретным показателем, и одноразовым значением. Он говорит, что очень важно иметь одноразовый номер, но я просто не могу понять, где это одноразовый номер.

Есть ли какой-либо простой однострочный способ подписать и проверить подписи ECDSA с использованием любой доверенной библиотеки в python для Windows?


person Jorky10    schedule 24.12.2015    source источник
comment
вы не можете подписать его с помощью openssl?   -  person Padraic Cunningham    schedule 24.12.2015
comment
каковы преимущества использования openssl вместо ecdsa?   -  person Jorky10    schedule 24.12.2015
comment
Я предполагаю, что библиотека ecdsa использует openssl, поэтому нет никакой разницы, у вас будет доступ ко всему, что вам нужно, используя openssl openssl.org/docs/manmaster/crypto/ecdsa.html guyrutenberg.com/2013/12/28/   -  person Padraic Cunningham    schedule 24.12.2015
comment
Я согласен с тем, что вам не нужно писать такой подробный код, как код в вашем примере, только для того, чтобы использовать ECDSA. Вы видели эту библиотеку Python ECDSA? github.com/warner/python-ecdsa   -  person David Grayson    schedule 24.12.2015


Ответы (3)


Вы можете попробовать использовать пакет 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.

person k26dr    schedule 02.01.2017
comment
Вы также можете использовать sign_digest и verify_digest для переваренных данных, например, если вы передаете хэш sha256 в двоичном формате. - person John Smith; 31.07.2017
comment
Есть ли способ сделать ключи меньше? Например, определить их максимальный размер? - person Nuclear_Man_D; 29.09.2017
comment
@ k26dr Спасибо. Черт! Я использую его для блокчейна .... И я уже достаточно написал, что блокчейн не работает, просто без проверки открытого ключа. Для такого длинного открытого ключа нет места ... Значит, существующий блокчейн - мусор. Ну ладно, лол. - person Nuclear_Man_D; 09.10.2017
comment
@Nuclear_Man_D, если вы имеете в виду, что открытый ключ, генерируемый в этом примере, слишком длинный для цепочки блоков, то вы правы. вот почему Биткойн делает некоторые дополнительные действия с открытым ключом! - person Finlay Roelofs; 02.12.2017
comment
Небольшая опечатка. Необходимо import ecdsa в обоих образцах, иначе будет выдана NameError: name 'ecdsa' is not defined ошибка. - person user1045085; 23.08.2018

Как его установить:

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

person rcmstark    schedule 31.01.2019

вы также можете использовать библиотеку sep256k1 в Python для подписи и проверки 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 (типизация) или int как одноразовый номер, но можно использовать любой массив байтов или строку. строки необходимо преобразовать в байты.

person GraphicalDot    schedule 21.09.2018