def sign(self, hash, random_k): """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 = self.public_key.generator n = G.order() k = random_k % n p1 = k * G r = p1.x() if r == 0: raise RuntimeError, "amazingly unlucky random number r" s = ( numbertheory.inverse_mod( k, n ) * \ ( hash + ( self.secret_multiplier * r ) % n ) ) % n if s == 0: raise RuntimeError, "amazingly unlucky random number s" return Signature(r, s)
def __add__(self, other): """Add one point to another point.""" # X9.62 B.3: if other == INFINITY: return self if self == INFINITY: return other assert self.__curve == other.__curve if self.__x == other.__x: if (self.__y + other.__y) % self.__curve.p() == 0: return INFINITY else: return self.double() p = self.__curve.p() l = ((other.__y - self.__y) * \ numbertheory.inverse_mod(other.__x - self.__x, p)) % p x3 = (l * l - self.__x - other.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p return Point(self.__curve, x3, y3)
def sign( self, hash, random_k ): """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 = self.public_key.generator n = G.order() k = random_k % n p1 = k * G r = p1.x() if r == 0: raise RuntimeError, "amazingly unlucky random number r" s = ( numbertheory.inverse_mod( k, n ) * \ ( hash + ( self.secret_multiplier * r ) % n ) ) % n if s == 0: raise RuntimeError, "amazingly unlucky random number s" return Signature( r, s )
def double(self): """Return a new point that is twice the old.""" # X9.62 B.3: p = self.__curve_p a = self.__curve_a l = ((3 * self.__x * self.__x + a) * \ numbertheory.inverse_mod(2 * self.__y, p)) % p x3 = (l * l - 2 * self.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p return Point(self.__curve_p, self.__curve_a, self.__curve_b, x3, y3)
def double(self): """Return a new point that is twice the old.""" if self == INFINITY: return INFINITY p = self.__curve.p() a = self.__curve.a() l = ((3 * self.__x * self.__x + a) * numbertheory.inverse_mod(2 * self.__y, p)) % p x3 = (l * l - 2 * self.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p return Point(self.__curve, x3, y3)
def double(self): """Return a new point that is twice the old.""" if self == INFINITY: return INFINITY # X9.62 B.3: p = self.__curve.p() a = self.__curve.a() l = ((3 * self.__x * self.__x + a) * numbertheory.inverse_mod(2 * self.__y, p)) % p x3 = (l * l - 2 * self.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p return Point(self.__curve, x3, y3)
def verify_message(self, address, signature, message): """ See http://www.secg.org/download/aid-780/sec1-v2.pdf for the math """ from ecdsa import numbertheory, ellipticcurve, util import msqr curve = curve_secp256k1 G = generator_secp256k1 order = G.order() # extract r,s from signature sig = base64.b64decode(signature) if len(sig) != 65: raise BaseException("Wrong encoding") r, s = util.sigdecode_string(sig[1:], order) nV = ord(sig[0]) if nV < 27 or nV >= 35: raise BaseException("Bad encoding") if nV >= 31: compressed = True nV -= 4 else: compressed = False recid = nV - 27 # 1.1 x = r + (recid / 2) * order # 1.3 alpha = (x * x * x + curve.a() * x + curve.b()) % curve.p() beta = msqr.modular_sqrt(alpha, curve.p()) y = beta if (beta - recid) % 2 == 0 else curve.p() - beta # 1.4 the constructor checks that nR is at infinity R = ellipticcurve.Point(curve, x, y, order) # 1.5 compute e from message: h = Hash(msg_magic(message)) e = string_to_number(h) minus_e = -e % order # 1.6 compute Q = r^-1 (sR - eG) inv_r = numbertheory.inverse_mod(r, order) Q = inv_r * (s * R + minus_e * G) public_key = ecdsa.VerifyingKey.from_public_point(Q, curve=SECP256k1) # check that Q is the public key public_key.verify_digest(sig[1:], h, sigdecode=ecdsa.util.sigdecode_string) # check that we get the original signing address addr = public_key_to_bc_address(encode_point(public_key, compressed)) if address != addr: raise BaseException("Bad signature")
def verify_message(self, address, signature, message): """ See http://www.secg.org/download/aid-780/sec1-v2.pdf for the math """ from ecdsa import numbertheory, ellipticcurve, util import msqr curve = curve_secp256k1 G = generator_secp256k1 order = G.order() # extract r,s from signature sig = base64.b64decode(signature) if len(sig) != 65: raise BaseException("Wrong encoding") r,s = util.sigdecode_string(sig[1:], order) nV = ord(sig[0]) if nV < 27 or nV >= 35: raise BaseException("Bad encoding") if nV >= 31: compressed = True nV -= 4 else: compressed = False recid = nV - 27 # 1.1 x = r + (recid/2) * order # 1.3 alpha = ( x * x * x + curve.a() * x + curve.b() ) % curve.p() beta = msqr.modular_sqrt(alpha, curve.p()) y = beta if (beta - recid) % 2 == 0 else curve.p() - beta # 1.4 the constructor checks that nR is at infinity R = ellipticcurve.Point(curve, x, y, order) # 1.5 compute e from message: h = Hash( msg_magic(message) ) e = string_to_number(h) minus_e = -e % order # 1.6 compute Q = r^-1 (sR - eG) inv_r = numbertheory.inverse_mod(r,order) Q = inv_r * ( s * R + minus_e * G ) public_key = ecdsa.VerifyingKey.from_public_point( Q, curve = SECP256k1 ) # check that Q is the public key public_key.verify_digest( sig[1:], h, sigdecode = ecdsa.util.sigdecode_string) # check that we get the original signing address addr = public_key_to_bc_address( encode_point(public_key, compressed) ) if address != addr: raise BaseException("Bad signature")
def verifies( self, hash, signature ): """Verify that signature is a valid signature of hash. Return True if the signature is valid. """ # From X9.62 J.3.1. G = self.generator n = G.order() r = signature.r s = signature.s if r < 1 or r > n-1: return False if s < 1 or s > n-1: return False c = numbertheory.inverse_mod( s, n ) u1 = ( hash * c ) % n u2 = ( r * c ) % n xy = u1 * G + u2 * self.point v = xy.x() % n return v == r
def verifies(self, hash, signature): """Verify that signature is a valid signature of hash. Return True if the signature is valid. """ # From X9.62 J.3.1. G = self.generator n = G.order() r = signature.r s = signature.s if r < 1 or r > n - 1: return False if s < 1 or s > n - 1: return False c = numbertheory.inverse_mod(s, n) u1 = (hash * c) % n u2 = (r * c) % n xy = u1 * G + u2 * self.point v = xy.x() % n return v == r
def __add__(self, other): if other == INFINITY: return self if self == INFINITY: return other # assert self.__curve == other.__curve if self.__x == other.__x: if (self.__y + other.__y) % self.__curve_p == 0: return INFINITY else: return self.double() p = self.__curve_p l = ((other.__y - self.__y) * \ numbertheory.inverse_mod(other.__x - self.__x, p)) % p x3 = (l * l - self.__x - other.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p return Point(self.__curve_p, self.__curve_a, self.__curve_b, x3, y3)
def sign(self, hash, random_k, ensure_low_s_according_to_bip62): """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 = self.public_key.generator n = G.order() k = random_k % n p1 = k * G r = p1.x() if r == 0: raise RuntimeError("amazingly unlucky random number r") s = (numbertheory.inverse_mod(k, n) * (hash + (self.secret_multiplier * r) % n)) % n if s == 0: raise RuntimeError("amazingly unlucky random number s") # https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures if ensure_low_s_according_to_bip62: # q == n, just used `q` since that is what is in litterature: # https://bitcoin.stackexchange.com/questions/38252/the-complement-of-s-when-s-curve-order-2 # https://bitcoin.stackexchange.com/questions/50980/test-r-s-values-for-signature-generation # https://bitcointalk.org/index.php?topic=285142.msg3299061#msg3299061 q = G.order() if s > (q / 2): s = q - s return Signature(r, s)
def __add__( self, other ): """Add one point to another point.""" # X9.62 B.3: if other == INFINITY: return self if self == INFINITY: return other assert self.__curve == other.__curve if self.__x == other.__x: if ( self.__y + other.__y ) % self.__curve.p() == 0: return INFINITY else: return self.double() p = self.__curve.p() l = ( ( other.__y - self.__y ) * \ numbertheory.inverse_mod( other.__x - self.__x, p ) ) % p x3 = ( l * l - self.__x - other.__x ) % p y3 = ( l * ( self.__x - x3 ) - self.__y ) % p return Point( self.__curve, x3, y3 )
def inverse(self, a): """ scalar inversion in Fp, overload for 'p' specific optimizations """ # this is a generic inverse_mod 7 times faster # than pow(a, self.p-2, self.p) return inverse_mod(a, self.p)
def inverse(self, a): """ scalar inversion in Fp - overload for 'p' specific optimizations """ return inverse_mod(a, self.p) # this is a generic inverse_mod