def ser_to_point(ser: bytes) -> Tuple[int, int]: if ser[0] not in (0x02, 0x03, 0x04): raise ValueError('Unexpected first byte: {}'.format(ser[0])) if ser[0] == 0x04: return string_to_number(ser[1:33]), string_to_number(ser[33:]) x = string_to_number(ser[1:]) return x, get_y_coord_from_x(x, ser[0] == 0x03)
def add_mod_n(d, c): assert len(d) == 32 # Truncate prefix byte order = generator_secp256k1.order() d = string_to_number(d) c = string_to_number(c) return number_to_string((d + c) % order, order)
def from_extended_key(klass, extended_key): decoded = base58.b58decode(extended_key, 78+4) assert(decoded) ekdata = decoded[:78] checksum = decoded[78:78+4] # validate checksum valid_checksum = hashlib.sha256(hashlib.sha256(ekdata).digest()).digest()[:4] assert (checksum == valid_checksum) version = util.string_to_number(ekdata[0:0+4]) depth = util.string_to_number(ekdata[4:4+1]) parentfp = ekdata[5:5+4] childnum = util.string_to_number(ekdata[9:9+4]) chaincode = ekdata[13:13+32] data = ekdata[45:45+33] testnet = version in (0x043587CF, 0x04358394) if version in (0x0488B21E, 0x043587CF): # data contains pubkey assert data[0] in ('\x02', '\x03') key = point_decompress(SECP256k1.curve, data) elif version in (0x0488ADE4, 0x04358394): # data contains privkey assert data[0] == '\x00' key = util.string_to_number(data[1:]) else: raise Exception('unknown version') return klass(key, chaincode, testnet=testnet, depth=depth, childnum=childnum, parentfp=parentfp)
def _get_subnode(cls, node, i): # Child key derivation (CKD) algorithm of BIP32 i_as_bytes = struct.pack(">L", i) if cls.is_prime(i): # Prime derivation data = '\0' + node.private_key + i_as_bytes I64 = hmac.HMAC(key=node.chain_code, msg=data, digestmod=hashlib.sha512).digest() else: # Public derivation data = node.public_key + i_as_bytes I64 = hmac.HMAC(key=node.chain_code, msg=data, digestmod=hashlib.sha512).digest() I_left_as_exponent = string_to_number(I64[:32]) secexp = (I_left_as_exponent + string_to_number(node.private_key)) % SECP256k1.order if I_left_as_exponent >= SECP256k1.order: raise Exception("Il cannot be bigger than order") if secexp == 0: raise Exception("secexp cannot be zero") node_out = types.HDNodeType() node_out.depth = node.depth + 1 node_out.child_num = i node_out.chain_code = I64[32:] node_out.private_key = number_to_string(secexp, SECP256k1.order) node_out.public_key = cls._get_pubkey(node_out.private_key) node_out.fingerprint = bip32_fingerprint(node.public_key) return node_out
def _CKD_priv(k, c, s, is_prime): order = generator_secp256k1.order() keypair = EC_KEY(k) cK = GetPubKey(keypair.pubkey,True) data = chr(0) + k + s if is_prime else cK + s I = hmac.new(c, data, hashlib.sha512).digest() k_n = number_to_string( (string_to_number(I[0:32]) + string_to_number(k)) % order , order ) c_n = I[32:] return k_n, c_n
def ser_to_point(Aser): curve = curve_secp256k1 generator = generator_secp256k1 _r = generator.order() assert Aser[0] in ['\x02','\x03','\x04'] if Aser[0] == '\x04': return Point( curve, string_to_number(Aser[1:33]), string_to_number(Aser[33:]), _r ) Mx = string_to_number(Aser[1:]) return Point( curve, Mx, ECC_YfromX(Mx, curve, Aser[0]=='\x03')[0], _r )
def CKD(k, c, n): import hmac from ecdsa.util import string_to_number, number_to_string order = generator_secp256k1.order() keypair = EC_KEY(string_to_number(k)) K = GetPubKey(keypair.pubkey,True) I = hmac.new(c, K + rev_hex(int_to_hex(n,4)).decode('hex'), hashlib.sha512).digest() k_n = number_to_string( (string_to_number(I[0:32]) * string_to_number(k)) % order , order ) c_n = I[32:] return k_n, c_n
def convert_point(Q): Q = decompress_public_key(Q)[1:] assert len(Q) == 64 Q_x = Q[:32] Q_y = Q[32:] assert len(Q_x) == 32 assert len(Q_y) == 32 Q_x = string_to_number(Q_x) Q_y = string_to_number(Q_y) curve = curve_secp256k1 return ecdsa.ellipticcurve.Point(curve, Q_x, Q_y, ec_order)
def __init__(self, k): secret = string_to_number(k) self.pubkey = ecdsa.ecdsa.Public_key( generator_secp256k1, generator_secp256k1 * secret) self.privkey = ecdsa.ecdsa.Private_key( self.pubkey, secret) self.secret = secret
def get_subnode(node, i): # Public Child key derivation (CKD) algorithm of BIP32 i_as_bytes = struct.pack(">L", i) if is_prime(i): raise Exception("Prime derivation not supported") # Public derivation data = node.public_key + i_as_bytes I64 = hmac.HMAC(key=node.chain_code, msg=data, digestmod=hashlib.sha512).digest() I_left_as_exponent = string_to_number(I64[:32]) node_out = proto_types.HDNodeType() node_out.depth = node.depth + 1 node_out.child_num = i node_out.chain_code = I64[32:] node_out.fingerprint = fingerprint(node.public_key) # BIP32 magic converts old public key to new public point x, y = sec_to_public_pair(node.public_key) point = I_left_as_exponent * SECP256k1.generator + \ Point(SECP256k1.curve, x, y, SECP256k1.order) if point == INFINITY: raise Exception("Point cannot be INFINITY") # Convert public point to compressed public key node_out.public_key = point_to_pubkey(point) return node_out
def CKD(k, c, n): import hmac from ecdsa.util import string_to_number, number_to_string order = generator_secp256k1.order() keypair = EC_KEY(k) K = GetPubKey(keypair.pubkey,True) if n & BIP32_PRIME: # We want to make a "secret" address that can't be determined from K data = chr(0) + k + rev_hex(int_to_hex(n,4)).decode('hex') I = hmac.new(c, data, hashlib.sha512).digest() else: # We want a "non-secret" address that can be determined from K I = hmac.new(c, K + rev_hex(int_to_hex(n,4)).decode('hex'), hashlib.sha512).digest() k_n = number_to_string( (string_to_number(I[0:32]) + string_to_number(k)) % order , order ) c_n = I[32:] return k_n, c_n
def test_vector_bip32(self): import pycoin.wallet as pywallet seed = unhexlify('000102030405060708090a0b0c0d0e0f') # seed = unhexlify('fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542') bip32 = BIP32.from_seed(seed) self.assertEqual(string_to_number(bip32.node.private_key), int('e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', 16)) self.assertEqual(bip32.get_address(BTC, []), '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma') self.assertEqual(bip32.get_address(BTC, [bip32.prime(0)]), '19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh') seed = unhexlify('fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542') bip32 = BIP32.from_seed(seed) self.assertEqual(bip32.get_address(BTC, [0]), '19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ') self.assertEqual(bip32.get_address(BTC, [0, bip32.prime(2147483647)]), '1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk') pw = pywallet.Wallet(chain_code=bip32.node.chain_code, secret_exponent_bytes=bip32.node.private_key, parent_fingerprint=struct.pack('I', bip32.node.fingerprint), depth=bip32.node.depth, child_number=bip32.node.child_num, is_private=True, is_test=False) privkey1 = hexlify(pw.subkey(0, is_prime=True, as_private=True).secret_exponent_bytes) privkey2 = hexlify(bip32._get_subnode(bip32.node, bip32.prime(0)).private_key) self.assertEqual(privkey1, privkey2)
def from_signature(klass, sig, recid, h, curve): # TODO use libsecp?? """ See http://www.secg.org/download/aid-780/sec1-v2.pdf, chapter 4.1.6 """ from ecdsa import util, numbertheory from . import msqr curveFp = curve.curve G = curve.generator order = G.order() # extract r,s from signature r, s = util.sigdecode_string(sig, order) # 1.1 x = r + (recid//2) * order # 1.3 alpha = ( x * x * x + curveFp.a() * x + curveFp.b() ) % curveFp.p() beta = msqr.modular_sqrt(alpha, curveFp.p()) y = beta if (beta - recid) % 2 == 0 else curveFp.p() - beta # 1.4 the constructor checks that nR is at infinity try: R = Point(curveFp, x, y, order) except: raise InvalidECPointException() # 1.5 compute e from 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) try: Q = inv_r * ( s * R + minus_e * G ) except: raise InvalidECPointException() return klass.from_public_point( Q, curve )
def CKD(k, c, n): import hmac from ecdsa.util import string_to_number, number_to_string order = generator_secp256k1.order() keypair = EC_KEY(string_to_number(k)) K = GetPubKey(keypair.pubkey, True) if n & BIP32_PRIME: data = chr(0) + k + rev_hex(int_to_hex(n, 4)).decode("hex") I = hmac.new(c, data, hashlib.sha512).digest() else: I = hmac.new(c, K + rev_hex(int_to_hex(n, 4)).decode("hex"), hashlib.sha512).digest() k_n = number_to_string((string_to_number(I[0:32]) + string_to_number(k)) % order, order) c_n = I[32:] return k_n, c_n
def ser_to_point(Aser): curve = curve_secp256k1 generator = generator_secp256k1 _r = generator.order() assert Aser[0] in ["\x02", "\x03", "\x04"] if Aser[0] == "\x04": return Point(curve, str_to_long(Aser[1:33]), str_to_long(Aser[33:]), _r) Mx = string_to_number(Aser[1:]) return Point(curve, Mx, ECC_YfromX(Mx, curve, Aser[0] == "\x03")[0], _r)
def _CKD_pub(cK, c, s): order = generator_secp256k1.order() I = hmac.new(c, cK + s, hashlib.sha512).digest() curve = SECP256k1 pubkey_point = string_to_number(I[0:32])*curve.generator + ser_to_point(cK) public_key = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 ) c_n = I[32:] cK_n = GetPubKey(public_key.pubkey,True) return cK_n, c_n
def test_subkey_simple(self): seed = unhexlify('000102030405060708090a0b0c0d0e0f') bip32 = BIP32.from_seed(seed) secexp1 = string_to_number(BIP32._get_subkey(bip32.xprv, 0).private_key) wallet = pywallet.Wallet.from_master_secret(seed) secexp2 = wallet.subkey(0, is_prime=True, as_private=True).secret_exponent self.assertEqual(secexp1, secexp2)
def diffie_hellman(e, Q): Q = decompress_public_key(Q) curve = SECP256k1 public_key = ecdsa.VerifyingKey.from_string(Q[1:], curve=curve) point = public_key.pubkey.point #e_int = int("0x" + e.encode("hex"), 16) e_int = string_to_number(e) point = e_int * point # convert x point to bytes result = "\x03" + ("%x" % point.x()).decode("hex") assert len(result) == 33 return result
def set_secret(self, secret): self._secret = secret secret = string_to_number(secret) pkey = EC_KEY(secret) #sec = "L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF" #pkey = obelisk.regenerate_key(sec) secexp = pkey.secret self._private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve=SECP256k1) self._public_key = self._private_key.get_verifying_key()
def __init__(self, privkey_bytes: bytes): assert_bytes(privkey_bytes) if len(privkey_bytes) != 32: raise Exception('unexpected size for secret. should be 32 bytes, not {}'.format(len(privkey_bytes))) secret = string_to_number(privkey_bytes) if not is_secret_within_curve_range(secret): raise InvalidECPointException('Invalid secret scalar (not within curve order)') self.secret_scalar = secret point = generator_secp256k1 * secret super().__init__(point_to_ser(point)) self._privkey = ecdsa.ecdsa.Private_key(self._pubkey, secret)
def _get_subkey(cls, xprv, i): # Key derivation algorithm of BIP32 if i < 0: i_as_bytes = struct.pack(">l", i) else: i &= 0x7fffffff i |= 0x80000000 i_as_bytes = struct.pack(">L", i) data = b'\0' + xprv.private_key + i_as_bytes I64 = hmac.HMAC(key=xprv.chain_code, msg=data, digestmod=hashlib.sha512).digest() I_left_as_exponent = string_to_number(I64[:32]) secexp = (I_left_as_exponent + string_to_number(xprv.private_key)) % SECP256k1.generator.order() xprv_out = proto.XprvType() xprv_out.version = xprv.version xprv_out.depth = xprv.depth + 1 xprv_out.child_num = i xprv_out.chain_code = I64[32:] xprv_out.private_key = number_to_string(secexp, SECP256k1.generator.order()) return xprv_out
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 test_subkey_path(self): seed = unhexlify('000102030405060708090a0b0c0d0e0f') path = [1, 1, 2] bip32 = BIP32.from_seed(seed) private_key = bip32.get_private_key(path) secexp1 = string_to_number(private_key) path_string = '/'.join([ "%d'" % p for p in path]) wallet = pywallet.Wallet.from_master_secret(seed) secexp2 = wallet.subkey_for_path(path_string) self.assertEqual(secexp1, secexp2.secret_exponent)
def generate_pub_key(_pk): # convert_pk = SigningKey.from_string(_pk, curve=NIST256p) _pk_unhex = binascii.unhexlify(_pk) secexp = string_to_number(_pk_unhex) origin_pk = SigningKey.from_secret_exponent(secexp, curve=NIST256p) vk = origin_pk.get_verifying_key() vk_string = vk.to_string() pub_key = binascii.hexlify(vk_string) return pub_key, vk
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 do_sign(self, msg): # Basic checks passed, let's sign that shit! version = 1 lock_time = 0 serialized_tx = '' coin = coindef.types[msg.coin_name] outtx = StreamTransactionSerialize(len(msg.inputs), len(msg.outputs), version, lock_time) # Sign inputs index = 0 self.layout.show_progress(index, len(msg.inputs), clear=True, logo=logo) for inp in msg.inputs: self.layout.show_progress(index, len(msg.inputs), clear=False) tx = StreamTransactionSign(index, len(msg.inputs), len(msg.outputs), version, lock_time) for i in msg.inputs: print '.', if i == inp: address = self.bip32.get_address(coin, list(i.address_n)) private_key = self.bip32.get_private_node(list(i.address_n)).private_key print "ADDRESS", address print "PRIVKEY", binascii.hexlify(private_key) secexp = string_to_number(private_key) tx.serialize_input(i, address, secexp) else: tx.serialize_input(i) for o in msg.outputs: print '.', tx.serialize_output(compile_TxOutput(o)) (signature, pubkey) = tx.sign() serialized_tx += outtx.serialize_input(inp, signature, pubkey) print "SIGNATURE", binascii.hexlify(signature) print "PUBKEY", binascii.hexlify(pubkey) index += 1 for out in msg.outputs: print '.', serialized_tx += outtx.serialize_output(compile_TxOutput(out)) self.layout.show_logo() self.set_main_state() return proto.TxRequest(request_type=proto_types.TXFINISHED, serialized=proto_types.TxRequestSerializedType(serialized_tx=serialized_tx))
def verify_message(self, address, signature, message): """See http://www.secg.org/download/aid-780/sec1-v2.pdf for the math""" 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 = ecdsa.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 = ecdsa.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 = ecdsa.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 CKD_prime(K, c, n): import hmac from ecdsa.util import string_to_number, number_to_string order = generator_secp256k1.order() K_public_key = ecdsa.VerifyingKey.from_string( K, curve = SECP256k1 ) K_compressed = GetPubKey(K_public_key.pubkey,True) I = hmac.new(c, K_compressed + rev_hex(int_to_hex(n,4)).decode('hex'), hashlib.sha512).digest() #pubkey = ecdsa.ecdsa.Public_key( generator_secp256k1, string_to_number(I[0:32]) * K_public_key.pubkey.point ) public_key = ecdsa.VerifyingKey.from_public_point( string_to_number(I[0:32]) * K_public_key.pubkey.point, curve = SECP256k1 ) K_n = public_key.to_string() K_n_compressed = GetPubKey(public_key.pubkey,True) c_n = I[32:] return K_n, K_n_compressed, c_n
def sec_to_public_pair(pubkey): """Convert a public key in sec binary format to a public pair.""" x = string_to_number(pubkey[1:33]) sec0 = pubkey[:1] if sec0 not in (b'\2', b'\3'): raise Exception("Compressed pubkey expected") def public_pair_for_x(generator, x, is_even): curve = generator.curve() p = curve.p() alpha = (pow(x, 3, p) + curve.a() * x + curve.b()) % p beta = ecdsa.numbertheory.square_root_mod_prime(alpha, p) if is_even == bool(beta & 1): return (x, p - beta) return (x, beta) return public_pair_for_x(ecdsa.ecdsa.generator_secp256k1, x, is_even=(sec0 == b'\2'))
def child(self, i): assert( 0 <= i <= 2**32-1) priv_deriv = (i & 0x80000000) != 0 if (priv_deriv and not self.__prvkey): raise Exception('Unable to do private derivation') # only allow up to a depth of 255 assert(self.__depth < 0xff) str_i = util.number_to_string(i, 2**32-1) if priv_deriv: str_k = util.number_to_string(self.__prvkey, SECP256k1.order) deriv = hmac.new(key=self.__chain, msg='\x00' + str_k + str_i, digestmod=hashlib.sha512).digest() else: str_K = point_compress(self.point()) deriv = hmac.new(key=self.__chain, msg=str_K + str_i, digestmod=hashlib.sha512).digest() childChain = deriv[32:] childModifier = util.string_to_number(deriv[:32]) if childModifier >= SECP256k1.order: raise Exception('This is higly unprovable IL >= n, but it did happen') if self.__prvkey: childPrvkey = (self.__prvkey + childModifier) % SECP256k1.order if childPrvkey == 0: raise Exception('This is higly unprovable ki = 0, but it did happen') childKey = childPrvkey else: childPubkey = self.point() + SECP256k1.generator * childModifier if childPubkey == ellipticcurve.INFINITY: raise Exception('This is higly unprovable Ki = INFINITY, but it did happen') childKey = childPubkey return self.__class__(childKey, childChain, testnet=self.__testnet, depth=self.__depth + 1, parentfp=self.fingerprint(), childnum=i)
def is_secret_within_curve_range(secret: Union[int, bytes]) -> bool: if isinstance(secret, bytes): secret = string_to_number(secret) return 0 < secret < CURVE_ORDER
def stretch_key(self, seed): oldseed = seed for i in range(100000): seed = hashlib.sha256(seed + oldseed).digest() return string_to_number(seed)
def restore_from_privkey(self, secret_string): "restore key pair from private key expressed in a hex form" self.private_key = string_to_number(bytes.fromhex(secret_string)) self.eck = EC_KEY(bytes.fromhex(secret_string)) self.public_key = point_to_ser(self.private_key*self.G, True)
def fingerprint(pubkey): return string_to_number(tools.hash_160(pubkey)[:4])
def __init__(self, k): secret = string_to_number(k) self.pubkey = ecdsa.ecdsa.Public_key(generator_secp256k1, generator_secp256k1 * secret) self.privkey = ecdsa.ecdsa.Private_key(self.pubkey, secret) self.secret = secret
def get_sequence(self, sequence, mpk): for_change, n = sequence return string_to_number( Hash("%d:%d:" % (n, for_change) + mpk.decode('hex')))
def point_add(Q, c): Q = convert_point(Q) c = string_to_number(c) return Q + c * generator_secp256k1
from ecdsa.util import sigdecode_string, string_to_number inv = numbertheory.inverse_mod def decode_sig(sig): r, s = sigdecode_string(sig, SECP256k1.generator.order()) return r, s user = b"lol" r1, s1 = decode_sig( bytes.fromhex( "cac6d0d70a88b0c95fd9c6c03261faf01aa51231864017b9b32fea67cf3ffc19316d2cea71faadad8046e37482bafa965ec92f446668acae232763ec7b948c90" )) z1 = string_to_number(hashlib.sha1(user).digest()) user2 = b"lol2" r2, s2 = decode_sig( bytes.fromhex( "cac6d0d70a88b0c95fd9c6c03261faf01aa51231864017b9b32fea67cf3ffc196ecde7dc924e2d1c18275db0f5c84c41bc298ac191475c55d4d29d3632d7a7f8" )) z2 = string_to_number(hashlib.sha1(user2).digest()) assert r1 == r2, "Different nonce was used" k = (z1 - z2) * inv(s1 - s2, SECP256k1.generator.order()) print(k % SECP256k1.generator.order()) secret_key = ( (s1 * k - z1) * inv(r1, SECP256k1.generator.order())) % SECP256k1.generator.order()
def get_sequence(self, n, for_change): return string_to_number( Hash("%d:%d:" % (n, for_change) + self.master_public_key))
def normalize_secret_bytes(cls, privkey_bytes: bytes) -> bytes: scalar = string_to_number(privkey_bytes) % CURVE_ORDER if scalar == 0: raise Exception('invalid EC private key scalar: zero') privkey_32bytes = number_to_string(scalar, CURVE_ORDER) return privkey_32bytes