web-dev-qa-db-ja.com

pythonでecdsaを使用して署名および署名を検証する方法

ビットコインと同じように、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のコメントには、値、秘密の指数およびnonceを指定すると署名が返されると記載されています。ナンスを持つことは非常に重要であると述べていますが、私はそのナンスがどこにあるのか分かりません。

Windowsのpythonにある信頼できるライブラリを使用して、ECDSA署名に署名して検証する簡単な1行の方法はありますか?

13
Jorky10

Python3を使用して、python ecdsaパッケージを使用して試すことができます。

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

message = b"message"
public_key = '98cedbb266d9fc38e41a169362708e0509e06b3040a5dfff6e08196f8d9e49cebfb4f4cb12aa7ac34b19f3b29a17f4e5464873f151fd699c2524e0b7843eb383'
sig = '740894121e1c7f33b174153a7349f6899d0a1d2730e9cc59f674921d8aef73532f63edb9c5dba4877074a937448a37c5c485e0d53419297967e95e9b1bef630d'

vk = ecdsa.VerifyingKey.from_string(bytes.fromhex(public_key), curve=ecdsa.SECP256k1)
vk.verify(bytes.fromhex(sig), message) # True

パッケージはPython 2にも対応しています。

23
k26dr

インストール方法:

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

2
rcmstark

Python to ecdsa sign and verifyでsep256k1ライブラリを使用することもできます。公開鍵と秘密鍵は、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を使用しましたが、任意のバイト配列または文字列を使用できます。文字列はバイトに変換する必要があります。

0
GraphicalDot