예제 #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
예제 #2
0
def b58decode(v: String, out_size: Optional[int] = None) -> bytes:
    """Decode a Base58Check encoded bytes-like object or ASCII string.

    Optionally, it also ensures required output size.
    """

    if isinstance(v, str):
        # do not trim spaces
        v = v.encode("ascii")

    result = _b58decode(v)
    if len(result) < 4:
        err_msg = "not enough bytes for checksum, "
        err_msg += f"invalid base58 decoded size: {len(result)}"
        raise BTClibValueError(err_msg)

    result, checksum = result[:-4], result[-4:]
    h256 = hash256(result)
    if checksum != h256[:4]:
        err_msg = f"invalid checksum: 0x{checksum.hex()} instead of 0x{h256[:4].hex()}"
        raise BTClibValueError(err_msg)

    if out_size is None or len(result) == out_size:
        return result

    err_msg = "valid checksum, invalid decoded size: "
    err_msg += f"{len(result)} bytes instead of {out_size}"
    raise BTClibValueError(err_msg)
예제 #3
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
예제 #4
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
예제 #5
0
def __b32decode(bech: String) -> Tuple[str, List[int], List[int]]:
    "Determine a bech32 string HRP, data and checksum."

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

    # 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"no separator character: {bech}")
    if pos == 0:
        raise BTClibValueError(f"empty HRP: {bech}")
    if pos + 7 > len(bech):
        raise BTClibValueError(f"too short checksum: {bech}")

    if not all(47 < ord(x) < 123 for x in bech[:pos]):
        raise BTClibValueError(f"HRP character out of range: {bech}")
    if bech.lower() != bech and bech.upper() != bech:
        raise BTClibValueError(f"mixed case: {bech}")

    bech = bech.lower()
    hrp = bech[:pos]

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

    return hrp, data[:-6], data[-6:]
예제 #6
0
파일: bms.py 프로젝트: btclib-org/btclib
    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
    def nulldata(
        cls: Type[_ScriptPubKey],
        data: String,
        check_validity: bool = True,
    ) -> _ScriptPubKey:
        "Return the nulldata ScriptPubKey of the provided data."

        if isinstance(data, str):
            # do not strip spaces
            data = data.encode()

        if len(data) > 80:
            err_msg = f"invalid nulldata payload length: {len(data)} bytes "
            raise BTClibValueError(err_msg)

        script = serialize(["OP_RETURN", data])
        return cls(script, check_validity=check_validity)
예제 #8
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)
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
예제 #10
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
예제 #11
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)