def f(public_pair): yield ("public_pair_x", '%d' % public_pair[0], None) yield ("public_pair_y", '%d' % public_pair[1], None) yield ("public_pair_x_hex", '%x' % public_pair[0], " x as hex") yield ("public_pair_y_hex", '%x' % public_pair[1], " y as hex") yield ("y_parity", "odd" if (public_pair[1] & 1) else "even", None) key = Key(public_pair=public_pair) yield ("key_pair_as_sec", b2h(key.sec(is_compressed=True)), None) yield ("key_pair_as_sec_uncompressed", b2h(key.sec(is_compressed=False)), " uncompressed") network_name = network.network_name hash160_u = key.hash160(is_compressed=False) hash160_c = key.hash160(is_compressed=True) yield ("hash160", b2h(hash160_c), None) if hash160_c and hash160_u: yield ("hash160_uncompressed", b2h(hash160_u), " uncompressed") address = network.address.for_p2pkh(hash160_c) yield ("address", address, "%s address" % network_name) yield ("%s_address" % network.symbol, address, "legacy") address = key.address(is_compressed=False) yield ("address_uncompressed", address, "%s address uncompressed" % network_name) yield ("%s_address_uncompressed" % network.symbol, address, "legacy") # don't print segwit addresses unless we're sure we have a compressed key if hash160_c and hasattr(network.address, "for_p2pkh_wit"): address_segwit = network.address.for_p2pkh_wit(hash160_c) if address_segwit: # this network seems to support segwit yield ("address_segwit", address_segwit, "%s segwit address" % network_name) yield ("%s_address_segwit" % network.symbol, address_segwit, "legacy") p2sh_script = network.contract.for_p2pkh_wit(hash160_c) p2s_address = network.address.for_p2s(p2sh_script) if p2s_address: yield ("p2sh_segwit", p2s_address, None) p2sh_script_hex = b2h(p2sh_script) yield ("p2sh_segwit_script", p2sh_script_hex, " corresponding p2sh script")
class KeyPair(object): """ ECDSA key pair. Args: pkey (str): hexadecimal representation of the private key (secret exponent). secret (str): master password. Attributes: keypair (:py:class:`pycoin.key.Key.Key`): BIP0032-style hierarchical wallet. Raises: NotImplementedError when a randomness source is not found. """ def __init__(self, pkey=None, secret=None): if secret is not None: pkey = format( BIP32Node.from_master_secret( secret.encode('utf-8')).secret_exponent(), "064x") elif pkey is None: try: pkey = format( BIP32Node.from_master_secret( urandom(4096)).secret_exponent(), '064x') except NotImplementedError as e: raise ValueError('No randomness source found: %s' % e) self.keypair = Key(secret_exponent=int(pkey, 16)) @property def node_id(self): """(str): NodeID derived from the public key (RIPEMD160 hash of public key).""" return b2h(self.keypair.hash160()) @property def public_key(self): """(str): public key.""" return b2h(self.keypair.sec(use_uncompressed=False)) @property def private_key(self): """(str): private key.""" return format(self.keypair.secret_exponent(), '064x') @property def address(self): """(): base58 encoded bitcoin address version of the nodeID.""" return self.keypair.address(use_uncompressed=False) def sign(self, message, compact=True): """Signs the supplied message with the private key""" if compact: fd = io.BytesIO() stream_bc_string(fd, bytearray('Bitcoin Signed Message:\n', 'ascii')) stream_bc_string(fd, bytearray(message, 'utf-8')) mhash = from_bytes_32(double_sha256(fd.getvalue())) G = generator_secp256k1 n = G.order() k = from_bytes_32(os.urandom(32)) p1 = k * G r = p1.x() if r == 0: raise RuntimeError("amazingly unlucky random number r") s = (numbertheory.inverse_mod(k, n) * (mhash + (self.keypair.secret_exponent() * r) % n)) % n if s == 0: raise RuntimeError("amazingly unlucky random number s") y_odd = p1.y() % 2 assert y_odd in (0, 1) first = 27 + y_odd + ( 4 if not self.keypair._use_uncompressed(False) else 0) sig = binascii.b2a_base64( bytearray([first]) + to_bytes_32(r) + to_bytes_32(s)).strip() if not isinstance(sig, str): # python3 b2a wrongness sig = str(sig, 'ascii') return sig else: return keys.sign_sha256(self.private_key, message)