ビットコインと同じように、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行の方法はありますか?
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にも対応しています。
インストール方法:
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
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を使用しましたが、任意のバイト配列または文字列を使用できます。文字列はバイトに変換する必要があります。