def map2curve_simple_swu(alpha: bytearray, i: int=1) -> ecc.Point: '''Maps the octet bytearray alpha into the elliptic curve, and returns a point from the elliptic curve. ''' t = HashToBase(alpha, i) alpha = pow(t, 2, PRIME) alpha = -alpha % PRIME right = (pow(alpha, 2, PRIME) + alpha) % PRIME right = pow(right, PRIME-2, PRIME) # right^(-1) % PRIME right = (right + 1) % PRIME left = -B % PRIME left = (left * pow(A, PRIME-2, PRIME)) % PRIME # (left * A^-1) % PRIME x2 = (left * right) % PRIME x3 = (alpha * x2) % PRIME h2 = pow(x2, 3, PRIME) # x2 ^ 3 % PRIME i2 = (x2 * A) % PRIME i2 = (i2 + B) % PRIME h2 = (h2 + i2) % PRIME h3 = pow(x3, 3, PRIME) # x3 ^ 3 % PRIME i3 = (x3 * A) % PRIME i3 = (i3 + B) % PRIME h3 = (h3 + i3) % PRIME y1 = pow(h2, (PRIME+1) // 4, PRIME) # h2 ^ ((p + 1) / 4) % PRIME y2 = pow(h3, (PRIME+1) // 4, PRIME) # h3 ^ ((p + 1) / 4) % PRIME if pow(y1, 2, PRIME) == h2: return ecc.Point(curve_256, x2, y1) else: return ecc.Point(curve_256, x3, y2)
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_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 vk_from_point(x: bytes, y: bytes): curve = ecdsa_curves.NIST256p x = int(x.hex(), 16) y = int(y.hex(), 16) p = ellipticcurve.Point(curve.curve, x, y) key = VerifyingKey.from_public_point(p, curve) return key
def ecdsa_cose_to_key(encoded: bytes) -> VerifyingKey: decoded = loads(encoded) kty = decoded[CoseKey.KTY] curve = _ecdsa_curves[decoded[CoseKey.CRV]] x = int(decoded[CoseKey.X].hex(), 16) y = int(decoded[CoseKey.Y].hex(), 16) p = ellipticcurve.Point(curve.curve, x, y) key = VerifyingKey.from_public_point(p, curve) return key
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 readkeys(self, path): """ read private keys from a directory, which must containser private.key, address and public.key """ self.address = open(path + "/address").read() self.private_key_js = open(path + "/private.key").read() self.public_key_js = open(path + "/public.key").read() sk_obj = json.loads(self.private_key_js) X = int(sk_obj['X']) Y = int(sk_obj['Y']) D = int(sk_obj['D']) self.public_key = VerifyingKey.from_public_point(ellipticcurve.Point(NIST256p.curve, X, Y), NIST256p, double_sha256) self.private_key = SigningKey.from_secret_exponent(D, NIST256p, double_sha256)
def secp224k1(): _a = 0x0000000000000000000000000000000000000000000000000000000000 _b = 0x0000000000000000000000000000000000000000000000000000000005 _p = 0x00fffffffffffffffffffffffffffffffffffffffffffffffeffffe56d _Gx = 0x00a1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45c _Gy = 0x007e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5 _r = 0x010000000000000000000000000001dce8d2ec6184caf0a971769fb1f7 curve_secp224k1 = ellipticcurve.CurveFp(_p, _a, _b) generator_secp224k1 = ellipticcurve.Point(curve_secp224k1, _Gx, _Gy, _r) secp224k1_instance = curves.Curve("SECP224k1", curve_secp224k1, generator_secp224k1, (1, 3, 132, 0, 20), "secp256k1") return secp224k1_instance
def FromCoordinates(cls, x: int, y: int) -> IPoint: """ Construct class from point coordinates. Args: x (int): X coordinate of the point y (int): Y coordinate of the point Returns: IPoint: IPoint object """ return cls( ellipticcurve.PointJacobi.from_affine( ellipticcurve.Point(curve_256, x, y)))
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 derive_pub_key(x, y, curve, hashfunc): """ Not sure if this actually works, examples provided on the github page are wrong (see issues) :param x: X coordinate of the elliptic curve :param y: Y coordinate of the elliptic curve :param curve: Which curve to use :param hashfunc: Which hash function used for hashing the data before signing :return: A public key """ x = base64decode(x) x = binascii.hexlify(x) y = base64decode(y) y = binascii.hexlify(y) x = int(x, 16) y = int(y, 16) point = ellipticcurve.Point(curves.NIST256p, x, y) return keys.VerifyingKey.from_public_point(point, curves.NIST256p, hashfunc=sha256)
def FromPoint(cls, key_point: IPoint) -> IPublicKey: """ Construct class from key point. Args: key_point (IPoint object): Key point Returns: IPublicKey: IPublicKey object Raises: ValueError: If key point is not valid """ try: return cls( ecdsa.VerifyingKey.from_public_point(ellipticcurve.Point( curve_256, key_point.X(), key_point.Y()), curve=curves.NIST256p)) except keys.MalformedPointError as ex: raise ValueError("Invalid public key point") from ex
def validate_keys(sk: int, vk: Point) -> bool: std_sk = SigningKey.from_secret_exponent(sk, SECP256k1, sha256) std_vk = std_sk.get_verifying_key() std_point = ellipticcurve.Point(SECP256k1.curve, vk[0].value, vk[1].value) std_vk_from_point = VerifyingKey.from_public_point(std_point, SECP256k1, sha256) public_keys_match = std_vk_from_point.to_string() == std_vk.to_string() print( f"Your private key is {sk} and the respective public key is {represent_point(vk)}." ) if public_keys_match: print( f"This private key generates the same public key using py-ecdsa.") else: print( f"The public key generated using py-ecdsa is {str(std_vk.pubkey.point)}" ) return public_keys_match
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 toPoint( x, y): return ellipticcurve.Point(ecdsa.ecdsa.generator_256.curve(), x, y, ecdsa.ecdsa.generator_256.order())
def generate_symmetric_key(vk_hex, sk): sk = int(sk, 16) vk_point = ellipticcurve.Point(_curve, int(vk_hex[:64], 16), int(vk_hex[64:], 16), _order) shared_key = vk_point * sk return shared_key
from ecdsa import ellipticcurve from ecdsa.util import randrange #from ecdsa.ecdsa import curve_secp256k1 from ecdsa.curves import SECP256k1 from ecdsa import numbertheory # Certicom secp256-k1 _a = 0x0000000000000000000000000000000000000000000000000000000000000000 _b = 0x0000000000000000000000000000000000000000000000000000000000000007 _p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f _Gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 _Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 _r = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 curve_secp256k1 = ellipticcurve.CurveFp(_p, _a, _b) generator_secp256k1 = ellipticcurve.Point(curve_secp256k1, _Gx, _Gy, _r) def ring_signature(siging_key, key_idx, M, y, G=SECP256k1.generator, hash_func=hashlib.sha3_256): """ Generates a ring signature for a message given a specific set of public keys and a signing key belonging to one of the public keys in the set. PARAMS ------ signing_key: (int) The with which the message is to be anonymously signed. key_idx: (int) The index of the public key corresponding to the signature private key over the list of public keys that compromise the signature.
def ecdsa_pub(x, y): """Create a public key from a public point""" point = ellipticcurve.Point(SECP256k1, x, y) return VerifyingKey.from_public_point(point, curve=SECP256k1)
import ecdsa import ecdsa.ellipticcurve as EC curve = ecdsa.SECP256k1 x = int('11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c', 16) y = int('b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3', 16) point = EC.Point(curve.curve, x, y) pubkey = ecdsa.VerifyingKey.from_public_point(point, curve) hash1 = 90774958364900180671716888080665726921328827653065727390791155349203800699667 r1 = 97921318692748166969765893503724782362221860890089306445657980140065784098104 s1 = 17870770544568028453805091504963125490615703388985597936947183001452377396233 sig = ecdsa.ecdsa.Signature(r1, s1) if pubkey.pubkey.verifies(hash1, sig): print("Good") else: print("Bad") hash1 = 70438975929202441702137589012525894517177874894451752259863210250765743151652 r1 = 67469108926628898148530592947733862172872496318648607111578457920563549925544 s1 = 48322980310687297275040392060954045679965067960426297271026705220954611568793 sig = ecdsa.ecdsa.Signature(r1, s1) if pubkey.pubkey.verifies(hash1, sig): print("Good") else: print("Bad")
_b = 0x0000000000000000000000000000000000000000000000000000000000000007 # Curve's generator point is: _Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 _Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 # prime number of points in the group (the order) _order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 # The ECDSA curve (secp256k1) is: # Note that we could get that from ecdsa lib, e.g.: # SECP256k1.__dict__['curve'] _curve = ellipticcurve.CurveFp(_p, _a, _b) # The generator base point is: # Note that we could get that from ecdsa lib, e.g.: # SECP256k1.__dict__['generator'] _G = ellipticcurve.Point(_curve, _Gx, _Gy, _order) # method used by both PrivateKey and PublicKey - TODO clean - add in another module? def add_magic_prefix(message): magic_prefix = b'\x18Bitcoin Signed Message:\n' message_size = len(message).to_bytes(1, byteorder='big') message_encoded = message.encode('utf-8') message_magic = magic_prefix + message_size + message_encoded return message_magic class PrivateKey: """Represents an ECDSA private key. Attributes
def verify_message(self, address, signature, message): """Creates a public key from a message signature and verifies message Bitcoin uses a compact format for message signatures (for tx sigs it uses normal DER format). The format has the normal r and s parameters that ECDSA signatures have but also includes a prefix which encodes extra information. Using the prefix the public key can be reconstructed from the signature. | Prefix values: | 27 - 0x1B = first key with even y | 28 - 0x1C = first key with odd y | 29 - 0x1D = second key with even y | 30 - 0x1E = second key with odd y If key is compressed add 4 (31 - 0x1F, 32 - 0x20, 33 - 0x21, 34 - 0x22 respectively) Raises ------ ValueError If signature is invalid """ sig = b64decode(signature.encode('utf-8')) if len(sig) != 65: raise ValueError('Invalid signature size') # get signature prefix, compressed and recid (which key is odd/even) prefix = sig[0] if prefix < 27 or prefix > 35: return False if prefix >= 31: compressed = True recid = prefix - 31 else: compressed = False recid = prefix - 27 # create message digest -- note double hashing message_magic = add_magic_prefix(message) message_digest = hashlib.sha256( hashlib.sha256(message_magic).digest()).digest() # # use recid, r and s to get the point in the curve # # get signature's r and s r, s = sigdecode_string(sig[1:], _order) # ger R's x coordinate x = r + (recid // 2) * _order # get R's y coordinate (y**2 = x**3 + 7) y_values = sqrt_mod((x**3 + 7) % _p, _p, True) if (y_values[0] - recid) % 2 == 0: y = y_values[0] else: y = y_values[1] # get R (recovered ephemeral key) from x,y R = ellipticcurve.Point(_curve, x, y, _order) # get e (hash of message encoded as big integer) e = int(hexlify(message_digest), 16) # compute public key Q = r^-1 (sR - eG) # because Point substraction is not defined we will instead use: # Q = r^-1 (sR + (-eG) ) minus_e = -e % _order inv_r = numbertheory.inverse_mod(r, _order) Q = inv_r * (s * R + minus_e * _G) # instantiate the public key and verify message public_key = VerifyingKey.from_public_point(Q, curve=SECP256k1) key_hex = hexlify(public_key.to_string()).decode('utf-8') pubkey = PublicKey.from_hex('04' + key_hex) if not pubkey.verify(signature, message): return False # confirm that the address provided corresponds to that public key if pubkey.get_address(compressed=compressed).to_string() != address: return False return True