I need to sign a 256-bit hash with ECDSA using a 256-bit private key, just like bitcoin, and I despaired of the lack of ecdsa documentation in python.
I found a lot of codes on the Internet, but it was not as simple as ecdsa.sign(msg, privkey) or the like, all I found was a lot of code of mathematical material, which I do not understand, but still they use ecdsa (I donβt know why they didnβt add a signature function to the library that will be used to sign the material, instead you need a code page when using the library?).
This is the best code I've 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 such a code, because I have no idea what it does. In addition, comments in ecdsa_sign say it returns a signature based on value, secret exponent, and nonce . It says that it is very important to have nonce, but I just can't figure out where the nonce is.
Is there a simple, one-line way to sign and verify ECDSA signatures using any trusted library in python in windows?