Ejemplo n.º 1
0
def witness_from_address(b32addr: String) -> Tuple[int, bytes, str]:
    "Return the witness from a bech32 native SegWit address."

    if isinstance(b32addr, str):
        b32addr = b32addr.strip()

    # the following check was originally in b32decode
    # but it does not pertain there
    if len(b32addr) > 90:
        raise BTClibValueError(
            f"invalid bech32 address length: {len(b32addr)} > 90")

    hrp, data = b32decode(b32addr)

    # check that it is a known SegWit address type
    network = network_from_key_value("hrp", hrp)
    if network is None:
        raise BTClibValueError(f"invalid hrp: {hrp}")

    if len(data) == 0:
        raise BTClibValueError(f"empty data in bech32 address: {b32addr!r}")

    wit_ver = data[0]
    wit_prg = bytes(power_of_2_base_conversion(data[1:], 5, 8, False))
    return wit_ver, check_witness(wit_ver, wit_prg), network
Ejemplo n.º 2
0
    def b58decode(
        cls: Type["BIP32KeyData"], address: String, check_validity: bool = True
    ) -> "BIP32KeyData":

        if isinstance(address, str):
            address = address.strip()

        xkey_bin = base58.b58decode(address)
        # pylance cannot grok the following line
        return cls.parse(xkey_bin, check_validity)  # type: ignore
Ejemplo n.º 3
0
    def b64decode(cls: Type[_Psbt],
                  psbt_str: String,
                  check_validity: bool = True) -> _Psbt:

        if isinstance(psbt_str, str):
            psbt_str = psbt_str.strip()

        psbt_decoded = base64.b64decode(psbt_str)
        # pylance cannot grok the following line
        return cls.parse(psbt_decoded, check_validity)  # type: ignore
Ejemplo n.º 4
0
    def b64decode(cls: Type["Sig"],
                  data: String,
                  check_validity: bool = True) -> "Sig":
        """Return the verified components of the provided BMS signature.

        The address-based BMS signature can be represented
        as (rf, r, s) tuple or as base64-encoding of the compact format
        [1-byte rf][32-bytes r][32-bytes s].
        """

        if isinstance(data, str):
            data = data.strip()

        data_decoded = base64.b64decode(data)
        # pylance cannot grok the following line
        return cls.parse(data_decoded, check_validity)  # type: ignore
Ejemplo n.º 5
0
def h160_from_address(b58addr: String) -> Tuple[str, bytes, str]:
    "Return the payload from a base58 address."

    if isinstance(b58addr, str):
        b58addr = b58addr.strip()
    payload = b58decode(b58addr, 21)
    prefix = payload[:1]

    for script_type in ("p2pkh", "p2sh"):
        # with pytohn>=3.8 use walrus operator
        # if network := network_from_key_value(script_type, prefix):
        network = network_from_key_value(script_type, prefix)
        if network:
            return script_type, payload[1:], network

    err_msg = f"invalid base58 address prefix: 0x{prefix.hex()}"
    raise BTClibValueError(err_msg)
Ejemplo n.º 6
0
def _prv_keyinfo_from_wif(wif: String,
                          network: Optional[str] = None,
                          compressed: Optional[bool] = None) -> PrvkeyInfo:
    """Return private key tuple(int, compressed, network) from a WIF.

    WIF is always compressed and includes network information:
    here the 'network, compressed' input parameters are passed
    only to allow consistency checks.
    """

    if isinstance(wif, str):
        wif = wif.strip()

    payload = b58decode(wif)

    net = network_from_key_value("wif", payload[:1])
    if net is None:
        raise BTClibValueError(f"invalid wif prefix: {payload[:1]!r}")
    if network is not None and net != network:
        raise BTClibValueError(f"not a {network} wif: {wif!r}")

    ec = NETWORKS[net].curve

    if len(payload) == ec.n_size + 2:  # compressed WIF
        compr = True
        if payload[-1] != 0x01:  # must have a trailing 0x01
            raise BTClibValueError(
                "not a compressed WIF: missing trailing 0x01")
        prv_key = payload[1:-1]
    elif len(payload) == ec.n_size + 1:  # uncompressed WIF
        compr = False
        prv_key = payload[1:]
    else:
        raise BTClibValueError(f"wrong WIF size: {len(payload)}")

    if compressed is not None and compr != compressed:
        raise BTClibValueError("compression requirement mismatch")

    q = int.from_bytes(prv_key, byteorder="big")
    if not 0 < q < ec.n:
        raise BTClibValueError(f"private key {hex(q)} not in [1, n-1]")

    return q, net, compr
Ejemplo n.º 7
0
def b32decode(bech: String) -> Tuple[str, List[int]]:
    "Validate a bech32 string, and determine HRP and data."

    if isinstance(bech, str):
        bech = bech.strip()

    if isinstance(bech, bytes):
        bech = bech.decode("ascii")

    if not all(47 < ord(x) < 123 for x in bech):
        raise BTClibValueError(f"ASCII character outside [48-122]: {bech}")
    if bech.lower() != bech and bech.upper() != bech:
        raise BTClibValueError(f"mixed case: {bech}")
    bech = bech.lower()

    # it is fine to limit bech32 _bitcoin_addresses_ at 90 chars,
    # but it should be enforced when working with addresses,
    # not here at bech32 level.
    # e.g. Lightning Network uses bech32 without such limitation
    # if len(bech) > 90:
    #     raise BTClibValueError(f"Bech32 string length ({len(bech)}) > 90")

    pos = bech.rfind("1")  # find the separator between hrp and data
    if pos == -1:
        raise BTClibValueError(f"missing HRP: {bech}")
    if pos == 0:
        raise BTClibValueError(f"empty HRP: {bech}")
    if pos + 7 > len(bech):
        raise BTClibValueError(f"too short checksum: {bech}")

    hrp = bech[:pos]

    if any(x not in _ALPHABET for x in bech[pos + 1:]):
        raise BTClibValueError(f"invalid data characters: {bech}")
    data = [_ALPHABET.find(x) for x in bech[pos + 1:]]

    if _verify_checksum(hrp, data):
        return hrp, data[:-6]
    raise BTClibValueError(f"invalid checksum: {bech}")
Ejemplo n.º 8
0
def witness_from_address(b32addr: String) -> Tuple[int, bytes, str]:
    """Return the witness from a bech32 native SegWit address.

    The returned data structure is: version, program, network.
    """

    if isinstance(b32addr, str):
        b32addr = b32addr.strip()

    # the following check was originally in b32decode
    # but it does not pertain there
    if len(b32addr) > 90:
        raise BTClibValueError(
            f"invalid bech32 address length: {len(b32addr)} > 90")

    hrp, data, checksum = __b32decode(b32addr)

    if len(data) == 0:
        raise BTClibValueError(f"empty data in bech32 address: {b32addr!r}")

    wit_ver = data[0]
    wit_prog = bytes(power_of_2_base_conversion(data[1:], 5, 8, False))
    wit_prog = check_witness(wit_ver, wit_prog)

    if wit_ver == 0:
        if not b32_verify_checksum(hrp, data + checksum):
            raise BTClibValueError(f"invalid checksum: {b32addr!r}")
    else:
        if not bech32m_verify_checksum(hrp, data + checksum):
            raise BTClibValueError(f"invalid checksum: {b32addr!r}")

    # check that it is a known SegWit address type
    network = network_from_key_value("hrp", hrp)
    if network is None:
        raise BTClibValueError(f"invalid hrp: {hrp}")

    return wit_ver, wit_prog, network
Ejemplo n.º 9
0
def has_segwit_prefix(addr: String) -> bool:

    str_addr = addr.strip().lower() if isinstance(
        addr, str) else addr.decode("ascii")
    return any(
        str_addr.startswith(NETWORKS[net].hrp + "1") for net in NETWORKS)