问题
I need to sign a hash of 256 bits with ECDSA using a private key of 256 bits, just as bitcoin does, and I am reaching desperation because of the lack of documentation of ecdsa in python.
I found a lot of codes on the internet, but there was nothing as easy as just ecdsa.sign(msg, privkey)
or similar, everything I found is a lot of code of mathematical stuff I don't understand, but yet they use the ecdsa library (I don't know why they wouldn't add a signing function in a library that is going to be used to sign stuff, instead a page of code is needed when using the library?).
This is the best code I found so far:
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()
But I just can't trust a code like that because I have no idea what it does. Also, the comments in ecdsa_sign says that returns a signature given the value, the secret exponent, and a nonce. It says its very important to have a nonce, but I just can't figure out where that nonce is.
Is there any simple, one-line way to sign and verify ECDSA signatures using whatever trusted library in python on windows?
回答1:
You can try using the python ecdsa package, using Python3:
pip3 install ecdsa
Usage:
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
To verify an existing signature with a public key:
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
The package is compatible with Python 2 as well
回答2:
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
回答3:
you can also use sep256k1 library in Python to ecdsa sign and verify. The public and private keys are the keys generated from Bip32 specifications and seed from Bip39 specifications.
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
The result will be True or False depending upon the verification. i have used uint32(typings) or int as a nonce, but any byte array or string can be used. strings need to be converted to bytes.
来源:https://stackoverflow.com/questions/34451214/how-to-sign-and-verify-signature-with-ecdsa-in-python