def address_type(addr): if addr.startswith(('1', '2', '3', 'm', 'n')): try: address = base58.decode(addr).rjust(25, b'\x00') except Base58DecodeError as e: raise InvalidAddress(f"{addr} : {e}") from None payload, checksum = address[:-4], address[-4:] version_byte, digest = payload[0:1], payload[1:].rjust(20, b'\x00') if len(digest) != 20: raise InvalidAddress(f"{addr} : Bad Payload") from None if sha256(sha256(payload))[:4] != checksum: raise InvalidAddress(f"{addr} : Invalid checksum") from None try: return {network('keyhash'): ADDRESS.P2PKH, network('scripthash'): ADDRESS.P2SH}[version_byte] except KeyError: raise InvalidAddress(f"{addr} : Invalid version byte") from None elif addr.startswith(network('hrp')): try: witness_version, witness_program = bech32.decode(network('hrp'), addr) except Bech32DecodeError as e: raise InvalidAddress(f"{addr} : {e}") from None if not witness_version == 0x00: raise InvalidAddress(f"{addr} : Invalid witness version") from None if len(witness_program) == 20: return ADDRESS.P2WPKH elif len(witness_program) == 32: return ADDRESS.P2WSH else: raise InvalidAddress(f"{addr} : Invalid witness program") from None else: raise InvalidAddress(f"{addr} : Invalid leading character") from None
def _receive(self, value: int): """Creates an output that sends to this address""" addr_type = self.type() output = Output(value=value, script=b'') if addr_type == ADDRESS.P2PKH: address = base58.decode(self.address).rjust(25, b'\x00') keyhash = address[1:-4] output.script = OP.DUP.byte + OP.HASH160.byte + push(keyhash) + OP.EQUALVERIFY.byte + OP.CHECKSIG.byte elif addr_type == ADDRESS.P2SH: address = base58.decode(self.address).rjust(25, b'\x00') scripthash = address[1:-4] output.script = OP.HASH160.byte + push(scripthash) + OP.EQUAL.byte elif addr_type in (ADDRESS.P2WPKH, ADDRESS.P2WSH): witness_version, witness_program = bech32.decode(network('hrp'), self.address) output.script = OP(bytes_to_int(witness_byte(witness_version))).byte + push(bytes(witness_program)) else: raise ValidationError(f"Cannot create output of type {addr_type}") return output
def from_wif(cls, wif: str) -> 'PrivateKey': from cryptotools.BTC import base58, sha256 from cryptotools.BTC.network import network bts = base58.decode(wif) network_byte, key, checksum = bts[0:1], bts[1:-4], bts[-4:] assert sha256(sha256(network_byte + key))[:4] == checksum, 'Invalid Checksum' assert network_byte == network('wif'), 'Invalid Network byte' if key.endswith(b'\x01'): key = key[:-1] compressed = True # TODO else: compressed = False # TODO return cls(key)
def decode(cls, string: str) -> 'ExtendedKey': bts = base58.decode(string) assert len(bts) == 82, f'Invalid length {len(bts)})' data, checksum = bts[:78], bts[78:] assert sha256(sha256(data)).startswith(checksum), 'Invalid checksum' return cls.deserialize(data)