Beispiel #1
0
def p2pkh(key: Key,
          network: Optional[str] = None,
          compressed: Optional[bool] = None) -> str:
    "Return the p2pkh base58 address corresponding to a public key."
    pub_key, network = pub_keyinfo_from_key(key,
                                            network,
                                            compressed=compressed)
    return address_from_h160("p2pkh", hash160(pub_key), network)
def fingerprint(key: Key, network: Optional[str] = None) -> bytes:
    """Return the public key fingerprint from a private/public key.

    The fingerprint is the last four bytes
    of the compressed public key HASH160.
    """

    pub_key, _ = pub_keyinfo_from_key(key, network, compressed=True)
    return hash160(pub_key)[:4]
def hash160_from_key(key: Key,
                     network: Optional[str] = None,
                     compressed: Optional[bool] = None) -> H160_Net:
    """Return (public key HASH160, nettwork) from a private/public key.

    HASH160 is RIPEMD160(SHA256).
    """
    pub_key, network = pub_keyinfo_from_key(key, network, compressed)
    return hash160(pub_key), network
Beispiel #4
0
def test_derive_exceptions() -> None:
    # root key, zero depth
    rootmxprv = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
    xprv = BIP32KeyData.b58decode(rootmxprv)
    # FIXME
    # assert xprv == _derive(xprv, "m")
    assert rootmxprv == derive(xprv, "m")
    assert rootmxprv == derive(xprv, "")

    fingerprint = hashes.hash160(pub_keyinfo_from_key(xprv)[0])[:4]
    assert fingerprint == _derive(xprv,
                                  bytes.fromhex("80000000")).parent_fingerprint

    for der_path in ("/1", "800000", "80000000"):
        xkey = _derive(xprv, der_path)
        assert fingerprint == xkey.parent_fingerprint

    err_msg = "invalid literal for int"
    for der_path in (";/0", "invalid index"):
        with pytest.raises(ValueError, match=err_msg):
            derive(xprv, der_path)

    with pytest.raises(BTClibValueError, match="depth greater than 255: "):
        derive(xprv, "m" + 256 * "/0")

    with pytest.raises(BTClibValueError,
                       match="index are not a multiple of 4-bytes: "):
        derive(xprv, b"\x00" * 5)

    for index in (2**32, 0x8000000000):
        with pytest.raises(OverflowError, match="int too big to convert"):
            derive(xprv, index)

    xprv = _derive(xprv, "1")
    err_msg = "final depth greater than 255: "
    with pytest.raises(BTClibValueError, match=err_msg):
        derive(xprv, "m" + 255 * "/0")

    rootxprv = "xprv9s21ZrQH143K2ZP8tyNiUtgoezZosUkw9hhir2JFzDhcUWKz8qFYk3cxdgSFoCMzt8E2Ubi1nXw71TLhwgCfzqFHfM5Snv4zboSebePRmLS"

    temp = base58.b58decode(rootxprv)
    bad_xprv = base58.b58encode(temp[:45] + b"\x02" + temp[46:], 78)
    err_msg = "invalid private key prefix: "
    with pytest.raises(BTClibValueError, match=err_msg):
        derive(bad_xprv, 0x80000000)

    xpub = xpub_from_xprv(rootxprv)
    temp = base58.b58decode(xpub)
    bad_xpub = base58.b58encode(temp[:45] + b"\x00" + temp[46:], 78)
    err_msg = r"invalid public key prefix not in \(0x02, 0x03\): "
    with pytest.raises(BTClibValueError, match=err_msg):
        derive(bad_xpub, 0x80000000)

    err_msg = "hardened derivation from public key"
    with pytest.raises(BTClibValueError, match=err_msg):
        derive(xpub, 0x80000000)
 def p2pk(
     cls: Type[_ScriptPubKey],
     key: Key,
     network: Optional[str] = None,
     check_validity: bool = True,
 ) -> _ScriptPubKey:
     "Return the p2pk ScriptPubKey of the provided Key."
     payload, network = pub_keyinfo_from_key(key, network)
     script = serialize([payload, "OP_CHECKSIG"])
     return cls(script, network, check_validity)
    def p2wpkh(
        cls: Type["ScriptPubKey"],
        key: Key,
        check_validity: bool = True,
    ) -> "ScriptPubKey":
        """Return the p2wpkh ScriptPubKey of the provided key.

        If the provided key is a public one, it must be compressed.
        """

        pub_key, network = pub_keyinfo_from_key(key, compressed=True)
        script = serialize(["OP_0", hash160(pub_key)])
        return cls(script, network, check_validity)
    def p2ms(
        cls: Type["ScriptPubKey"],
        m: int,
        keys: Sequence[Key],
        network: Optional[str] = None,
        compressed: Optional[bool] = None,
        lexi_sort: bool = True,
        check_validity: bool = True,
    ) -> "ScriptPubKey":
        """Return the m-of-n multi-sig ScriptPubKey of the provided keys.

        BIP67 endorses lexicographica key sorting
        according to compressed key representation.

        Note that sorting uncompressed keys (leading 0x04 byte) results
        in a different order than sorting the same keys in compressed
        (leading 0x02 or 0x03 bytes) representation.

        https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki
        """
        n = len(keys)
        if not 0 < n < 17:
            raise BTClibValueError(f"invalid n in m-of-n: {n}")
        if not 0 < m <= n:
            raise BTClibValueError(f"invalid m in m-of-n: {m}-of-{n}")

        # if network is None, then first key sets the network
        pub_key, network = pub_keyinfo_from_key(keys[0], network, compressed)
        pub_keys = [pub_key] + [
            pub_keyinfo_from_key(k, network, compressed)[0] for k in keys[1:]
        ]
        if lexi_sort:
            pub_keys = sorted(pub_keys)

        script = serialize(
            [op_int(m), *pub_keys,
             op_int(n), "OP_CHECKMULTISIG"])
        return cls(script, network, check_validity)
Beispiel #8
0
def test_p2w_p2sh() -> None:

    pub_key_str = "03 a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f"
    pub_key, network = pub_keyinfo_from_key(pub_key_str, compressed=True)
    witness_program = hash160(pub_key)
    b58addr = b58.p2wpkh_p2sh(pub_key, network)
    assert b58addr == "36NvZTcMsMowbt78wPzJaHHWaNiyR73Y4g"

    script_pub_key = serialize([
        "OP_DUP", "OP_HASH160", witness_program, "OP_EQUALVERIFY",
        "OP_CHECKSIG"
    ])
    b58addr = b58.p2wsh_p2sh(script_pub_key, network)
    assert b58addr == "3QHRam4Hvp1GZVkgjoKWUC1GEd8ck8e4WX"
Beispiel #9
0
def input_script_sig(
    internal_pubkey: Optional[Key], script_tree: TaprootScriptTree, script_num: int
) -> Tuple[bytes, bytes]:
    parity_bit = output_pubkey(internal_pubkey, script_tree)[1]
    if internal_pubkey:
        pub_key_bytes = pub_keyinfo_from_key(internal_pubkey, compressed=True)[0][1:]
    else:
        h_str = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"
        pub_key_bytes = bytes.fromhex(h_str)
    (leaf_version, script), path = tree_helper(script_tree)[0][script_num]
    control = (parity_bit + leaf_version).to_bytes(1, "big")
    control += pub_key_bytes
    control += path
    return script, control
Beispiel #10
0
    def p2pkh(
        cls: Type["ScriptPubKey"],
        key: Key,
        compressed: Optional[bool] = None,
        network: Optional[str] = None,
        check_validity: bool = True,
    ) -> "ScriptPubKey":
        "Return the p2pkh ScriptPubKey of the provided key."

        pub_key, network = pub_keyinfo_from_key(key,
                                                network,
                                                compressed=compressed)
        script = serialize([
            "OP_DUP", "OP_HASH160",
            hash160(pub_key), "OP_EQUALVERIFY", "OP_CHECKSIG"
        ])
        return cls(script, network, check_validity)
Beispiel #11
0
def output_pubkey(
    internal_pubkey: Optional[Key] = None,
    script_tree: Optional[TaprootScriptTree] = None,
    ec: Curve = secp256k1,
) -> Tuple[bytes, int]:
    if not internal_pubkey and not script_tree:
        raise BTClibValueError("Missing data")
    if internal_pubkey:
        pubkey = pub_keyinfo_from_key(internal_pubkey, compressed=True)[0][1:]
    else:
        h_str = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"
        pubkey = bytes.fromhex(h_str)
    if script_tree:
        _, h = tree_helper(script_tree)
    else:
        h = tagged_hash(b"TapTweak", pubkey)
    t = int.from_bytes(tagged_hash(b"TapTweak", pubkey + h), "big")
    # edge case that cannot be reproduced in the test suite
    if t >= ec.n:
        raise BTClibValueError("Invalid script tree hash")  # pragma: no cover
    x = int.from_bytes(pubkey, "big")
    Q = ec.add((x, ec.y_even(x)), mult(t))
    return Q[0].to_bytes(32, "big"), Q[1] % 2
Beispiel #12
0
def p2wpkh_p2sh(key: Key, network: Optional[str] = None) -> str:
    "Return the p2wpkh-p2sh base58 address corresponding to a public key."
    pub_key, network = pub_keyinfo_from_key(key, network, compressed=True)
    witness_program = hash160(pub_key)
    return _address_from_v0_witness(witness_program, network)
Beispiel #13
0
def test_from_key() -> None:

    secp256r1 = CURVES["secp256r1"]
    m_c = bytes_from_point(Q, compressed=True), "mainnet"
    m_unc = bytes_from_point(Q, compressed=False), "mainnet"
    t_c = bytes_from_point(Q, compressed=True), "testnet"
    t_unc = bytes_from_point(Q, compressed=False), "testnet"
    for pub_key in [Q, *plain_pub_keys]:
        assert Q == point_from_pub_key(pub_key)
        with pytest.raises(BTClibValueError):
            point_from_pub_key(pub_key, secp256r1)
        assert m_c == pub_keyinfo_from_pub_key(pub_key)
        assert m_c == pub_keyinfo_from_pub_key(pub_key, "mainnet")
        assert m_c == pub_keyinfo_from_pub_key(pub_key,
                                               "mainnet",
                                               compressed=True)
        assert m_c == pub_keyinfo_from_pub_key(pub_key, compressed=True)
        assert m_unc == pub_keyinfo_from_pub_key(pub_key,
                                                 "mainnet",
                                                 compressed=False)
        assert m_unc == pub_keyinfo_from_pub_key(pub_key, compressed=False)
        assert t_c == pub_keyinfo_from_pub_key(pub_key, "testnet")
        assert t_c == pub_keyinfo_from_pub_key(pub_key,
                                               "testnet",
                                               compressed=True)
        assert t_unc == pub_keyinfo_from_pub_key(pub_key,
                                                 "testnet",
                                                 compressed=False)

    for prv_key2 in [xpub_data, *compressed_pub_keys]:
        assert Q == point_from_pub_key(prv_key2)
        with pytest.raises(BTClibValueError):
            point_from_pub_key(prv_key2, secp256r1)
        assert m_c == pub_keyinfo_from_pub_key(prv_key2)
        assert m_c == pub_keyinfo_from_pub_key(prv_key2, "mainnet")
        assert m_c == pub_keyinfo_from_pub_key(prv_key2,
                                               "mainnet",
                                               compressed=True)
        assert m_c == pub_keyinfo_from_pub_key(prv_key2, compressed=True)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(prv_key2, "mainnet", compressed=False)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(prv_key2, compressed=False)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(prv_key2, "testnet", compressed=False)

    for prv_key3 in uncompressed_pub_keys:
        assert Q == point_from_pub_key(prv_key3)
        with pytest.raises(BTClibValueError):
            point_from_pub_key(prv_key3, secp256r1)
        assert m_unc == pub_keyinfo_from_pub_key(prv_key3)
        assert m_unc == pub_keyinfo_from_pub_key(prv_key3, "mainnet")
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(prv_key3, "mainnet", compressed=True)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(prv_key3, compressed=True)
        assert m_unc == pub_keyinfo_from_pub_key(prv_key3,
                                                 "mainnet",
                                                 compressed=False)
        assert m_unc == pub_keyinfo_from_pub_key(prv_key3, compressed=False)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(prv_key3, "testnet", compressed=True)

    for prv_key4 in [xpub_data, *net_aware_pub_keys]:
        assert Q == point_from_pub_key(prv_key4)
        with pytest.raises(BTClibValueError):
            point_from_pub_key(prv_key4, secp256r1)
        assert pub_keyinfo_from_pub_key(prv_key4) in (m_c, m_unc)
        assert pub_keyinfo_from_pub_key(prv_key4, "mainnet") in (m_c, m_unc)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(prv_key4, "testnet")

    for prv_key5 in net_unaware_pub_keys:
        assert Q == point_from_pub_key(prv_key5)
        with pytest.raises(BTClibValueError):
            point_from_pub_key(prv_key5, secp256r1)
        assert pub_keyinfo_from_pub_key(prv_key5) in (m_c, m_unc)
        assert pub_keyinfo_from_pub_key(prv_key5, "mainnet") in (m_c, m_unc)
        assert pub_keyinfo_from_pub_key(prv_key5, "testnet") in (t_c, t_unc)

    for invalid_pub_key in [INF, INF_xpub_data, *invalid_pub_keys]:
        with pytest.raises(BTClibValueError):
            point_from_pub_key(invalid_pub_key)  # type: ignore
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(invalid_pub_key)  # type: ignore

    for not_a_pub_key in [
            INF,
            INF_xpub_data,
            *not_a_pub_keys,
            q,
            q0,
            qn,
            *plain_prv_keys,
            xprv_data,
            xprv0_data,
            xprvn_data,
            *compressed_prv_keys,
            *uncompressed_prv_keys,
    ]:
        with pytest.raises(BTClibValueError):
            point_from_pub_key(not_a_pub_key)  # type: ignore
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_pub_key(not_a_pub_key)  # type: ignore

    for key in [Q, *plain_pub_keys, q, *plain_prv_keys]:
        assert Q == point_from_key(key)
        assert m_c == pub_keyinfo_from_key(key)
        assert m_c == pub_keyinfo_from_key(key, "mainnet")
        assert m_c == pub_keyinfo_from_key(key, "mainnet", compressed=True)
        assert m_c == pub_keyinfo_from_key(key, compressed=True)
        assert m_unc == pub_keyinfo_from_key(key, "mainnet", compressed=False)
        assert m_unc == pub_keyinfo_from_key(key, compressed=False)
        assert t_c == pub_keyinfo_from_key(key, "testnet")
        assert t_c == pub_keyinfo_from_key(key, "testnet", compressed=True)
        assert t_unc == pub_keyinfo_from_key(key, "testnet", compressed=False)

    for key2 in [
            *compressed_pub_keys, xpub_data, xprv_data, *compressed_prv_keys
    ]:
        assert Q == point_from_key(key2)
        with pytest.raises(BTClibValueError):
            point_from_key(key2, secp256r1)
        assert m_c == pub_keyinfo_from_key(key2)
        assert m_c == pub_keyinfo_from_key(key2, "mainnet")
        assert m_c == pub_keyinfo_from_key(key2, "mainnet", compressed=True)
        assert m_c == pub_keyinfo_from_key(key2, compressed=True)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_key(key2, "mainnet", compressed=False)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_key(key2, compressed=False)

    for key3 in [*uncompressed_pub_keys, *uncompressed_prv_keys]:
        assert Q == point_from_key(key3)
        with pytest.raises(BTClibValueError):
            point_from_key(key3, secp256r1)
        assert m_unc == pub_keyinfo_from_key(key3)
        assert m_unc == pub_keyinfo_from_key(key3, "mainnet")
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_key(key3, "mainnet", compressed=True)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_key(key3, compressed=True)
        assert m_unc == pub_keyinfo_from_key(key3, "mainnet", compressed=False)
        assert m_unc == pub_keyinfo_from_key(key3, compressed=False)

    for key4 in [
            *net_aware_pub_keys, xpub_data, xprv_data, *net_aware_prv_keys
    ]:
        assert Q == point_from_key(key4)
        with pytest.raises(BTClibValueError):
            point_from_key(key4, secp256r1)
        assert pub_keyinfo_from_key(key4) in (m_c, m_unc)
        assert pub_keyinfo_from_key(key4, "mainnet") in (m_c, m_unc)
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_key(key4, "testnet")

    for key5 in [q, *net_unaware_prv_keys, *net_unaware_pub_keys]:
        assert Q == point_from_key(key5)
        assert pub_keyinfo_from_key(key5) in (m_c, m_unc)
        assert pub_keyinfo_from_key(key5, "mainnet") in (m_c, m_unc)
        assert pub_keyinfo_from_key(key5, "testnet") in (t_c, t_unc)

    for invalid_key in [
            INF,
            INF_xpub_data,
            *invalid_pub_keys,
            q0,
            qn,
            xprv0_data,
            xprvn_data,
            *invalid_prv_keys,
    ]:
        with pytest.raises(BTClibValueError):
            point_from_key(invalid_key)  # type: ignore
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_key(invalid_key)  # type: ignore

    for not_a_key in [
            q0,
            qn,
            xprv0_data,
            xprvn_data,
            INF,
            INF_xpub_data,
            *not_a_pub_keys,
    ]:
        with pytest.raises(BTClibValueError):
            point_from_key(not_a_key)  # type: ignore
        with pytest.raises(BTClibValueError):
            pub_keyinfo_from_key(not_a_key)  # type: ignore
Beispiel #14
0
def p2wpkh(key: Key, network: Optional[str] = None) -> str:
    "Return the p2wpkh bech32 address corresponding to a public key."
    pub_key, network = pub_keyinfo_from_key(key, network, compressed=True)
    return address_from_witness(0, hash160(pub_key), network)