def obscured_commit_num(opener_payment_basepoint: coincurve.PublicKey, non_opener_payment_basepoint: coincurve.PublicKey, commitnum: int) -> int: # BOLT #3: # The 48-bit commitment number is obscured by `XOR` with the lower 48 bits of: # # SHA256(payment_basepoint from open_channel || payment_basepoint from accept_channel) shabytes = sha256(opener_payment_basepoint.format() + non_opener_payment_basepoint.format()).digest()[-6:] obscurer = struct.unpack('>Q', bytes(2) + shabytes)[0] return commitnum ^ obscurer
def sort_by_keys(key_one: coincurve.PublicKey, key_two: coincurve.PublicKey, val_one: Any, val_two: Any) -> Tuple[Any, Any]: """In many places we have to sort elements into key or nodeid order""" # BOLT #3: # ## Funding Transaction Output # # * The funding output script is a P2WSH to: `2 <pubkey1> <pubkey2> 2 # OP_CHECKMULTISIG` # * Where `pubkey1` is the lexicographically lesser of the two # `funding_pubkey` in compressed format, and where `pubkey2` is the # lexicographically greater of the two. if key_one.format() < key_two.format(): return val_one, val_two else: return val_two, val_one
def parse_fromwallet(cls, kds, vds): """Class method to parse entry from wallet entry :param kds: BCDatastream object for keys :type kds: BCDataStream :param vds: BCDataStream object for values :type vds: BCDataStream :return: KeyPair :rtype: KeyPair """ pubkeyraw = kds.read_bytes(kds.read_compact_size()) privkeyraw = vds.read_bytes(vds.read_compact_size()) if len(privkeyraw) == 279: sec = privkeyraw[9:41] else: sec = privkeyraw[8:40] privkey = PrivateKey(sec) pubkey = PublicKey(pubkeyraw) if len(pubkeyraw) == 33: compress = True else: compress = False if pubkey == privkey.public_key: pubkey = privkey.public_key.format(compressed=compress) return cls( rawkey=pubkeyraw, rawvalue=privkeyraw, pubkey=pubkey, privkey=privkey, sec=sec, compressed=compress, ) else: raise KeypairError(message="Pubkey {} error".format(pubkey.format(compressed=compress).hex()))
def verify_ecdsa(message, signature, pub): """Checks if the signature from signEcdsa is correct.""" if not isinstance(message, (bytes, bytearray)): raise TypeError(f"Invalid message") if len(message) != 32: raise ValueError(f"Invalid length message: {len(message)} != 32") if not isinstance(signature, (bytes, bytearray)): raise TypeError(f"Invalid signature key") if len(signature) != 65: raise ValueError(f"Invalid length signature key: {len(signature)} != 65") if not isinstance(pub, (bytes, bytearray)): raise TypeError(f"Invalid signature key") if len(pub) != 64: raise ValueError(f"Invalid length signature key: {len(pub)} != 64") pubkey = PublicKey(b"\x04" + pub) r = _big_endian_to_int(signature[0:32]) s = _big_endian_to_int(signature[32:64]) low_s = _coerce_low_s(s) der_encoded_signature = bytes(_two_int_sequence_encoder(r, low_s)) return verify_signature( der_encoded_signature, message, pubkey.format(compressed=False), hasher=None )
def derive(private_key: PrivateKey, peer_public_key: PublicKey) -> bytes: """ Key exchange between private key and peer's public key, `derive(k1, k2.public_key)` should be equal to `derive(k2, k1.public_key)`. Parameters ---------- private_key: coincurve.PrivateKey A secp256k1 private key peer_public_key: coincurve.PublicKey Peer's public key Returns ------- bytes A secret key used for symmetric encryption >>> from coincurve import PrivateKey >>> ke1 = generate_eth_key() >>> ke2 = generate_eth_key() >>> k1 = hex2prv(ke1.to_hex()) >>> k2 = hex2prv(ke2.to_hex()) >>> derive(k1, k2.public_key) == derive(k2, k1.public_key) True """ return private_key.ecdh(peer_public_key.format())
def _convert_key(public_key: bytes, compressed: bool) -> bytes: """Convert key between compressed and uncompressed keys :param public_key: compressed or uncompressed key :return: the counterpart key of a given public_key """ public_key_object = PublicKey(public_key) return public_key_object.format(compressed=not compressed)
def from_xpub( xpub: str, xpub_type: Optional[XpubType] = None, path: Optional[str] = None, ) -> 'HDKey': """ Instantiate an HDKey from an xpub. Populates all possible fields Args: xpub (str): the xpub path (str): the path if it's known. useful for calling derive_path Returns: (HDKey): the key object May raise: - XPUBError if there is a problem with decoding the xpub """ xpub_bytes = b58decode(xpub) if len(xpub_bytes) < 78: raise XPUBError(f'Given XPUB {xpub} is too small') try: pubkey = PublicKey(xpub_bytes[45:78]) except ValueError as e: raise XPUBError(str(e)) from e result = _parse_prefix(xpub_bytes[0:4]) if not result.is_public: raise XPUBError('Given xpub is an extended private key') if result.network != 'mainnet': raise XPUBError('Given xpub is not for the bitcoin mainnet') hint = result.hint if xpub_type is not None and xpub_type.matches_prefix( xpub[0:4]) is False: # the given type does not match the prefix, re-encode with correct pref new_xpub = bytearray() new_xpub.extend(xpub_type.prefix_bytes()) new_xpub.extend(xpub_bytes[4:]) new_xpub_bytes = new_xpub hint = xpub_type.prefix() xpub = b58encode(bytes(new_xpub_bytes)).decode('ascii') return HDKey( path=path, network=result.network, depth=xpub_bytes[4], parent_fingerprint=xpub_bytes[5:9], index=int.from_bytes(xpub_bytes[9:13], byteorder='big'), parent=None, chain_code=xpub_bytes[13:45], fingerprint=hash160(pubkey.format(COMPRESSED_PUBKEY))[:4], xpriv=None, xpub=xpub, privkey=None, pubkey=pubkey, hint=hint, )
def parse_fromckey(cls, pubkey, privkey, encryptedkey, crypted=True): """Parse keypair from ckey (encrypted) values from wallet :param pubkey: :type pubkey: :param privkey: :type privkey: :param encryptedkey: :type encryptedkey: :param crypted: :type crypted: :return: :rtype: """ pkey = PublicKey(pubkey) if len(pubkey) == 33: compress = True else: compress = False if crypted: return cls( rawkey=pubkey, rawvalue=None, pubkey=pkey.format(compressed=compress), sec=None, encryptedkey=encryptedkey, compressed=compress, ) else: if len(privkey) == 279: sec = privkey[9:41] else: sec = privkey[8:40] prkey = PrivateKey(sec) if pkey == prkey.public_key: pkey = prkey.public_key.format(compressed=compress) return cls( rawkey=pubkey, rawvalue=privkey, pubkey=pkey, privkey=prkey, sec=sec, compressed=compress, ) else: print("Wrong decryption password") return cls( rawkey=pubkey, rawvalue=None, pubkey=pkey, sec=None, encryptedkey=encryptedkey, compressed=compress, )
class PublicKey(object): def __init__(self, public_key): public_key = unhexlify(public_key.encode()) self.public_key = PubKey(public_key) def to_hex(self): return hexlify(self.public_key.format()).decode() @classmethod def from_passphrase(cls, passphrase): private_key = PrivateKey.from_passphrase(passphrase) return private_key.public_key @classmethod def from_hex(cls, public_key): return cls(public_key)
def _make_child_xpub(self, child_pubkey: PublicKey, index: int, chain_code: bytes) -> str: """ Makes a child xpub based on the current key and the child key info. Args: child_pubkey (bytes): the child pubkey index (int): the child index chain_code (bytes): the child chain code Returns (str): the child xpub """ xpub = bytearray() xpub.extend(b58decode(cast(str, self.xpub))[0:4]) # prefix xpub.extend([cast(int, self.depth) + 1]) # depth xpub.extend(self.fingerprint) # fingerprint xpub.extend(index.to_bytes(4, byteorder='big')) # index xpub.extend(chain_code) # chain_code xpub.extend(child_pubkey.format(COMPRESSED_PUBKEY)) # pubkey (comp) return b58encode(bytes(xpub)).decode('ascii')
def from_xpub(xpub: str, path: Optional[str] = None) -> 'HDKey': """ Instantiate an HDKey from an xpub. Populates all possible fields Args: xpub (str): the xpub path (str): the path if it's known. useful for calling derive_path Returns: (HDKey): the key object May raise: - XPUBError if there is a problem with decoding the xpub """ xpub_bytes = b58decode(xpub) if len(xpub_bytes) < 78: raise XPUBError(f'Given XPUB {xpub} is too small') try: pubkey = PublicKey(xpub_bytes[45:78]) except ValueError as e: raise XPUBError(str(e)) from e result = _parse_prefix(xpub_bytes[0:4]) if not result.is_public: raise XPUBError('Given xpub is an extended private key') return HDKey( path=path, network=result.network, depth=xpub_bytes[4], parent_fingerprint=xpub_bytes[5:9], index=int.from_bytes(xpub_bytes[9:13], byteorder='big'), parent=None, chain_code=xpub_bytes[13:45], fingerprint=hash160(pubkey.format(COMPRESSED_PUBKEY))[:4], xpriv=None, xpub=xpub, privkey=None, pubkey=pubkey, hint=result.hint, )
def get_ephem_key(self, raw_pubkey: bytes) -> Tuple[bytes, bytes, bytes]: """ Get ephemeral elliptic curve key and derived keys for encryption and MAC tagging. Key :param raw_pubkey: Recipient's raw public key (64 bytes) :return: Tuple with the following values: - encoding key (16 bytes) - mac key (32 bytes) - public key with leading '\x04' byte (65 bytes) """ if self.last_cleanup_time < time.time() - self.timeout: ECIESKeyManager.get_ephem_key.cache_clear() self.last_cleanup_time = time.time() ephem = HashablePrivateKey() ephem_raw_pubkey = ephem.public_key.format(compressed=False) pubkey = PublicKey(b'\x04' + raw_pubkey) key_material = self.ecdh(ephem, pubkey.format()) assert len(key_material) == 32 enc_key, mac_key = self.get_derived_keys(key_material) return enc_key, mac_key, ephem_raw_pubkey
def create_address(self, public_key: PublicKey) -> str: serialized_pub = public_key.format(compressed=False) hashed_pub = hashlib.sha3_256(serialized_pub[1:]).hexdigest() return f"hx{hashed_pub[-40:]}"
def get_address(public_key: PublicKey) -> str: """Derive an Ethereum-style address from the given public key.""" return '0x' + sha3_256(public_key.format(False)[1:]).hexdigest()[-40:]
def public_key_to_address(public_key: PublicKey) -> Address: """Converts a public key to an Ethereum address.""" key_bytes = public_key.format(compressed=False) return Address(keccak(key_bytes[1:])[-20:])
def derive(private_key: PrivateKey, peer_public_key: PublicKey) -> bytes: return private_key.ecdh(peer_public_key.format())
def decapsulate(public_key: PublicKey, peer_private_key: PrivateKey) -> bytes: shared_point = public_key.multiply(peer_private_key.secret) master = public_key.format(compressed=False) + shared_point.format( compressed=False) derived = HKDF(master, AES_KEY_BYTES_LEN, b"", SHA256) return derived # type: ignore