def map_to_curve(x, P=curve_secp256k1.p()): """ Maps an integer to an elliptic curve. PARAMS ------ x: (int) number to be mapped into E. P: (ecdsa.curves.curve_secp256k1.p) Modulo for elliptic curve. RETURNS ------- (ecdsa.ellipticcurve.Point) Point in Curve """ x = x - 1 found = False while not found: x = x + 1 alpha = (((pow(x, 3, P) + (curve_secp256k1.a() * x))) + curve_secp256k1.b()) % P try: beta = numbertheory.square_root_mod_prime(alpha, P) if [beta % 2 == 0] != [x % 2 != 0]: y = beta else: y = P - beta found = True except Exception as e: pass return ecdsa.ellipticcurve.Point(curve_secp256k1, x, y)
def verifying_key_from_hex(key: bytes): """Load the VerifyingKey from a compressed or uncompressed hex public key. """ id_byte = key[0] if not isinstance(id_byte, int): id_byte = ord(id_byte) if id_byte == 4: # Uncompressed public point # 1B ID + 32B x coord + 32B y coord = 65 B if len(key) != 65: raise Exception("Invalid key length") return create_verifying_key(int(hexlify(key[1:33]), 16), int(hexlify(key[33:]), 16)) elif id_byte in [2, 3]: # Compressed public point if len(key) != 33: raise Exception("Invalid key length") y_odd = bool(id_byte & 0x01) # 0 even, 1 odd x = int(hexlify(key[1:]), 16) # The following x-to-pair algorithm was lifted from pycoin # I still need to sit down an understand it. It is also described # in http://www.secg.org/collateral/sec1_final.pdf curve = SECP256k1.curve p = curve.p() # For SECP256k1, curve.a() is 0 and curve.b() is 7, so this is # effectively (x ** 3 + 7) % p, but the full equation is kept # for just-in-case-the-curve-is-broken future-proofing alpha = (pow(x, 3, p) + curve.a() * x + curve.b()) % p beta = square_root_mod_prime(alpha, p) y_even = not y_odd if y_even == bool(beta & 1): return create_verifying_key(x, p - beta) else: return create_verifying_key(x, beta) raise Exception("The given key is not in a known format.")
def extract_coordinates(g, curve): """ Return the coordinates x and y as integers, regardless of the point format of string g. Second expected parameter is a CurveFp. """ p = curve.p() point_format = g[0] point = g[1:] if point_format == '\x04': point_len = len(point) if point_len % 2 != 0: raise Exception("Point length is not even.") x_bytes = point[:point_len >> 1] x = pkcs_os2ip(x_bytes) % p y_bytes = point[point_len >> 1:] y = pkcs_os2ip(y_bytes) % p elif point_format in ['\x02', '\x03']: x_bytes = point x = pkcs_os2ip(x_bytes) % p # perform the y coordinate computation with self.tls_ec y_square = (x * x * x + curve.a() * x + curve.b()) % p y = square_root_mod_prime(y_square, p) y_parity = ord(point_format) % 2 # \x02 means even, \x03 means odd if y % 2 != y_parity: y = -y % p else: raise Exception("Point starts with %s. This encoding " "is not recognized." % repr(point_format)) if not curve.contains_point(x, y): raise Exception("The point we extracted does not belong on the curve!") return x, y
def uncompress_public_key(public_key): """ Uncompress the compressed public key. :param public_key: compressed public key :return: uncompressed public key """ is_even = public_key.startswith(b'\x02') x = string_to_number(public_key[1:]) curve = ecdsa.NIST256p.curve order = ecdsa.NIST256p.order p = curve.p() alpha = (pow(x, 3, p) + (curve.a() * x) + curve.b()) % p beta = square_root_mod_prime(alpha, p) if is_even == bool(beta & 1): y = p - beta else: y = beta point = ellipticcurve.Point(curve, x, y, order) from ecdsa.util import number_to_string return b''.join([ number_to_string(point.x(), order), number_to_string(point.y(), order) ])
def from_sec(string, curve=curves.SECP256k1, hashfunc=sha1, validate_point=True): """Convert a public key in SEC binary format to a verifying key.""" # based on code from https://github.com/richardkiss/pycoin if string.startswith(b('\x04')): # uncompressed return VerifyingKey.from_string(string[1:], curve, hashfunc, validate_point) elif string.startswith(b('\x02')) or string.startswith(b('\x03')): # compressed is_even = string.startswith(b('\x02')) x = string_to_number(string[1:]) order = curve.order p = curve.curve.p() alpha = (pow(x, 3, p) + (curve.curve.a() * x) + curve.curve.b()) % p beta = square_root_mod_prime(alpha, p) if is_even == bool(beta & 1): y = p - beta else: y = beta if validate_point: assert ecdsa.point_is_valid(curve.generator, x, y) point = ellipticcurve.Point(curve.curve, x, y, order) return VerifyingKey.from_public_point(point, curve, hashfunc)
def get_ecdsa_verifying_key(pub): #some shenanigans required to validate a transaction sig; see #python.ecdsa PR #54. This will be a lot simpler when that's merged. #https://github.com/warner/python-ecdsa/pull/54/files if not pub[0] in ["\x02", "\x03"]: log.debug("Invalid pubkey") return None is_even = pub.startswith('\x02') x = string_to_number(pub[1:]) order = SECP256k1.order p = SECP256k1.curve.p() alpha = (pow(x, 3, p) + (SECP256k1.curve.a() * x) + SECP256k1.curve.b()) % p beta = square_root_mod_prime(alpha, p) if is_even == bool(beta & 1): y = p - beta else: y = beta if not point_is_valid(SECP256k1.generator, x, y): return None point = Point(SECP256k1.curve, x, y, order) return VerifyingKey.from_public_point(point, SECP256k1, hashfunc=hashlib.sha256)
def extract_coordinates(g, curve): """ Return the coordinates x and y as integers, regardless of the point format of string g. Second expected parameter is a CurveFp. """ p = curve.p() point_format = g[0] point = g[1:] if point_format == '\x04': point_len = len(point) if point_len % 2 != 0: raise Exception("Point length is not even.") x_bytes = point[:point_len>>1] x = pkcs_os2ip(x_bytes) % p y_bytes = point[point_len>>1:] y = pkcs_os2ip(y_bytes) % p elif point_format in ['\x02', '\x03']: x_bytes = point x = pkcs_os2ip(x_bytes) % p # perform the y coordinate computation with self.tls_ec y_square = (x*x*x + curve.a()*x + curve.b()) % p y = square_root_mod_prime(y_square, p) y_parity = ord(point_format) % 2 # \x02 means even, \x03 means odd if y % 2 != y_parity: y = -y % p else: raise Exception("Point starts with %s. This encoding " "is not recognized." % repr(point_format)) if not curve.contains_point(x, y): raise Exception("The point we extracted does not belong on the curve!") return x, y
def map_to_curve(x, P=curve_secp256k1.p()): """ Maps an integer to an elliptic curve. Using the try and increment algorithm, not quite as efficient as I would like, but c'est la vie. PARAMS ------ x: (int) number to be mapped into E. P: (ecdsa.curves.curve_secp256k1.p) Modulo for elliptic curve. RETURNS ------- (ecdsa.ellipticcurve.Point) Point in Curve """ x -= 1 y = 0 found = False while not found: x += 1 f_x = (x * x * x + 7) % P try: y = numbertheory.square_root_mod_prime(f_x, P) found = True except Exception as e: pass return ecdsa.ellipticcurve.Point(curve_secp256k1, x, y)
def decode_point(point, curve=BASE_CURVE): # See http://www.secg.org/download/aid-780/sec1-v2.pdf section 2.3.4 elliptic_curve = curve order = elliptic_curve.q base_length = orderlen(order) if point[0] == 4: # 3 x_str = point[1:base_length + 1] y_str = point[base_length + 1:] return Point(string_to_number(x_str), string_to_number(y_str), curve=elliptic_curve) else: # 2.3 if point[0] == 2: yp = 0 elif point[0] == 3: yp = 1 else: return None # 2.2 x_str = point[1:base_length + 1] x = string_to_number(x_str) # 2.4.1 alpha = ((x * x * x) + (elliptic_curve.a * x) + elliptic_curve.b) % elliptic_curve.p beta = numbertheory.square_root_mod_prime(alpha, elliptic_curve.p) if (beta - yp) % 2 == 0: y = beta else: y = elliptic_curve.p - beta return Point(x, y, curve=elliptic_curve)
def pubkey2point(pubkey): x = int(tohex(pubkey)[2:],16) fx = (x * x * x + C.a() * x + C.b()) % C.p() y = numbertheory.square_root_mod_prime(fx,C.p()) P = ellipticcurve.Point(C,x,y) if point2pubkey(P) != toraw(pubkey): P = ellipticcurve.Point(C,x,C.p()-y) return P
def point_decompress(curve, data): prefix = data[0] assert (prefix in ['\x02', '\x03']) parity = 1 if prefix == '\x02' else -1 x = util.string_to_number(data[1:]) y = numbertheory.square_root_mod_prime( (x * x * x + curve.a() * x + curve.b()) % curve.p(), curve.p()) y = parity * y % curve.p() return ellipticcurve.Point(curve, x, y)
def point_decompress(curve, data): prefix = data[0] assert(prefix in ['\x02', '\x03']) parity = 1 if prefix == '\x02' else -1 x = util.string_to_number(data[1:]) y = numbertheory.square_root_mod_prime( ( x * x * x + curve.a() * x + curve.b() ) % curve.p(), curve.p() ) y = parity * y % curve.p() return ellipticcurve.Point(curve, x, y)
def from_hex_key(cls, key, network=BitcoinMainNet): """Load the PublicKey from a compressed or uncompressed hex key. This format is defined in PublicKey.get_key() """ if len(key) == 130 or len(key) == 66: # It might be a hexlified byte array try: key = unhexlify(ensure_bytes(key)) except (TypeError, binascii.Error): pass key = ensure_bytes(key) compressed = False id_byte = key[0] if not isinstance(id_byte, six.integer_types): id_byte = ord(id_byte) if id_byte == 4: # Uncompressed public point # 1B ID + 32B x coord + 32B y coord = 65 B if len(key) != 65: raise KeyParseError("Invalid key length") public_pair = PublicPair(long_or_int(hexlify(key[1:33]), 16), long_or_int(hexlify(key[33:]), 16)) elif id_byte in [2, 3]: # Compressed public point! compressed = True if len(key) != 33: raise KeyParseError("Invalid key length") y_odd = bool(id_byte & 0x01) # 0 even, 1 odd x = long_or_int(hexlify(key[1:]), 16) # The following x-to-pair algorithm was lifted from pycoin # I still need to sit down an understand it. It is also described # in http://www.secg.org/collateral/sec1_final.pdf curve = SECP256k1.curve p = curve.p() # For SECP256k1, curve.a() is 0 and curve.b() is 7, so this is # effectively (x ** 3 + 7) % p, but the full equation is kept # for just-in-case-the-curve-is-broken future-proofing alpha = (pow(x, 3, p) + curve.a() * x + curve.b()) % p beta = square_root_mod_prime(alpha, p) y_even = not y_odd if y_even == bool(beta & 1): public_pair = PublicPair(x, p - beta) else: public_pair = PublicPair(x, beta) else: raise KeyParseError("The given key is not in a known format.") return cls.from_public_pair(public_pair, network=network, compressed=compressed)
def from_hex_key(cls, key, network=BitcoinMainNet): """Load the PublicKey from a compressed or uncompressed hex key. This format is defined in PublicKey.get_key() """ if len(key) == 130 or len(key) == 66: # It might be a hexlified byte array try: key = unhexlify(ensure_bytes(key)) except (TypeError, binascii.Error): pass key = ensure_bytes(key) compressed = False id_byte = key[0] if not isinstance(id_byte, six.integer_types): id_byte = ord(id_byte) if id_byte == 4: # Uncompressed public point # 1B ID + 32B x coord + 32B y coord = 65 B if len(key) != 65: raise KeyParseError("Invalid key length") public_pair = PublicPair( long_or_int(hexlify(key[1:33]), 16), long_or_int(hexlify(key[33:]), 16)) elif id_byte in [2, 3]: # Compressed public point! compressed = True if len(key) != 33: raise KeyParseError("Invalid key length") y_odd = bool(id_byte & 0x01) # 0 even, 1 odd x = long_or_int(hexlify(key[1:]), 16) # The following x-to-pair algorithm was lifted from pycoin # I still need to sit down an understand it. It is also described # in http://www.secg.org/collateral/sec1_final.pdf curve = SECP256k1.curve p = curve.p() # For SECP256k1, curve.a() is 0 and curve.b() is 7, so this is # effectively (x ** 3 + 7) % p, but the full equation is kept # for just-in-case-the-curve-is-broken future-proofing alpha = (pow(x, 3, p) + curve.a() * x + curve.b()) % p beta = square_root_mod_prime(alpha, p) y_even = not y_odd if y_even == bool(beta & 1): public_pair = PublicPair(x, p - beta) else: public_pair = PublicPair(x, beta) else: raise KeyParseError("The given key is not in a known format.") return cls.from_public_pair(public_pair, network=network, compressed=compressed)
def point_decompress(curve, data): prefix = data[0] assert(prefix in ['\x02', '\x03']) is_even = prefix == '\x02' x = util.string_to_number(data[1:]) y = numbertheory.square_root_mod_prime( ( x * x * x + curve.a() * x + curve.b() ) % curve.p(), curve.p() ) if is_even == bool(y & 1): return ellipticcurve.Point(curve, x, curve.p() - y) return ellipticcurve.Point(curve, x, y)
def from_bytes(cls, data: bytes): """ Generates either a HDPublicKey from the underlying bytes. The serialization must conform to the description in: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format """ if len(data) < 78: raise ValueError("b must be at least 78 bytes long.") version = int.from_bytes(data[:4], 'big') depth = data[4] parent_fingerprint = data[5:9] index = int.from_bytes(data[9:13], 'big') chain_code = data[13:45] key_bytes = data[45:78] if version != HDPublicKey.__VERSION: raise ValueError('invalid HD Public Key.') if key_bytes[0] != 0x02 and key_bytes[0] != 0x03: raise ValueError("First byte of public key must be 0x02 or 0x03!") # The curve of points satisfying y^2 = x^3 + a*x + b (mod p). curve = ecdsa.curve_256 x = util.string_to_number(key_bytes[1:]) y = (x * x * x + curve.a() * x + curve.b()) % curve.p() y = numbertheory.square_root_mod_prime(y, curve.p()) if (key_bytes[0] == 0x03 and y % 2 == 0) or (key_bytes[0] == 0x02 and y % 2 != 0): y = (y * -1) % curve.p() order = curves.NIST256p.order s_key = util.number_to_string(x, order) + util.number_to_string( y, order) public_key = VerifyingKey.from_string(string=s_key, curve=curves.NIST256p) rv = cls(public_key=public_key, chain_code=chain_code, index=index, depth=depth, parent_fingerprint=parent_fingerprint) return rv
def from_sec(string, curve=curves.SECP256k1, hashfunc=sha1, validate_point=True): """Convert a public key in SEC binary format to a verifying key.""" # based on code from https://github.com/richardkiss/pycoin if string.startswith(b("\x04")): # uncompressed return VerifyingKey.from_string(string[1:], curve, hashfunc, validate_point) elif string.startswith(b("\x02")) or string.startswith(b("\x03")): # compressed is_even = string.startswith(b("\x02")) x = string_to_number(string[1:]) order = curve.order p = curve.curve.p() alpha = (pow(x, 3, p) + (curve.curve.a() * x) + curve.curve.b()) % p beta = square_root_mod_prime(alpha, p) if is_even == bool(beta & 1): y = p - beta else: y = beta if validate_point: assert ecdsa.point_is_valid(curve.generator, x, y) point = ellipticcurve.Point(curve.curve, x, y, order) return VerifyingKey.from_public_point(point, curve, hashfunc)
def uncompress(string: bytes, curve=SECP256k1) -> Point: if string[:1] not in (b'\x02', b'\x03'): raise MalformedPoint("Malformed compressed point encoding") is_even = string[:1] == b'\x02' x = string_to_number(string[1:]) order = curve.order p = curve.curve.p() alpha = (pow(x, 3, p) + (curve.curve.a() * x) + curve.curve.b()) % p try: beta = square_root_mod_prime(alpha, p) except SquareRootError as e: raise MalformedPoint( "Encoding does not correspond to a point on curve", e ) if is_even == bool(beta & 1): y = p - beta else: y = beta if not ecdsa.point_is_valid(curve.generator, x, y): raise MalformedPoint("Point does not lie on curve") return point_to_pubkey_bytes(Point(curve.curve, x, y, order))
def _verifying_key_from_pubkey(cls, pubkey): """ Converts a 33-byte compressed pubkey into an ecdsa.VerifyingKey object. """ if not isinstance(pubkey, (bytes, bytearray)): raise TypeError('pubkey must be raw bytes') if len(pubkey) != 33: raise ValueError('pubkey must be 33 bytes') if pubkey[0] not in (2, 3): raise ValueError('invalid pubkey prefix byte') curve = cls.CURVE.curve is_odd = pubkey[0] == 3 x = bytes_to_int(pubkey[1:]) # p is the finite field order a, b, p = curve.a(), curve.b(), curve.p() # pylint: disable=invalid-name y2 = pow(x, 3, p) + b # pylint: disable=invalid-name assert a == 0 # Otherwise y2 += a * pow(x, 2, p) y = NT.square_root_mod_prime(y2 % p, p) if bool(y & 1) != is_odd: y = p - y point = EC.Point(curve, x, y) return ecdsa.VerifyingKey.from_public_point(point, curve=cls.CURVE)
def curve25519_x_to_y(x): t = (x**3 + CURVE_A * x**2 + x) % CURVE_P try: return square_root_mod_prime(t, CURVE_P) except SquareRootError: return None
def _curve25519_x_to_y(self, x): t = (x ** 3 + self.CURVE_A * x ** 2 + x) % self.CURVE_P try: return square_root_mod_prime( t, self.CURVE_P) except SquareRootError: return None
def curve25519_x_to_y(x): t = (x ** 3 + CURVE_A * x ** 2 + x) % CURVE_P try: return square_root_mod_prime(t, CURVE_P) except SquareRootError: return None