Exemplo n.º 1
0
def test_wif_from_prv_key() -> None:
    prv_key = "0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D"
    test_vectors: List[Tuple[str, str, bool]] = [
        ("KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617", "mainnet",
         True),
        ("cMzLdeGd5vEqxB8B6VFQoRopQ3sLAAvEzDAoQgvX54xwofSWj1fx", "testnet",
         True),
        ("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ", "mainnet",
         False),
        ("91gGn1HgSap6CbU12F6z3pJri26xzp7Ay1VW6NHCoEayNXwRpu2", "testnet",
         False),
        (" KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617", "mainnet",
         True),
        ("KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617 ", "mainnet",
         True),
    ]
    for v in test_vectors:
        assert v[0].strip() == b58.wif_from_prv_key(prv_key, v[1], v[2])
        q, network, compressed = prv_keyinfo_from_prv_key(v[0])
        assert q == int(prv_key, 16)
        assert network == v[1]
        assert compressed == v[2]

    bad_q = ec.n.to_bytes(ec.n_size, byteorder="big", signed=False)
    with pytest.raises(BTClibValueError, match="private key not in 1..n-1: "):
        b58.wif_from_prv_key(bad_q, "mainnet", True)

    payload = b"\x80" + bad_q
    badwif = b58encode(payload)
    with pytest.raises(BTClibValueError, match="not a private key: "):
        prv_keyinfo_from_prv_key(badwif)

    # not a private key: 33 bytes
    bad_q = 33 * b"\x02"
    with pytest.raises(BTClibValueError, match="not a private key: "):
        b58.wif_from_prv_key(bad_q, "mainnet", True)
    payload = b"\x80" + bad_q
    badwif = b58encode(payload)
    with pytest.raises(BTClibValueError, match="not a private key: "):
        prv_keyinfo_from_prv_key(badwif)

    # Not a WIF: missing leading 0x80
    good_q = 32 * b"\x02"
    payload = b"\x81" + good_q
    badwif = b58encode(payload)
    with pytest.raises(BTClibValueError, match="not a private key: "):
        prv_keyinfo_from_prv_key(badwif)

    # Not a compressed WIF: missing trailing 0x01
    payload = b"\x80" + good_q + b"\x00"
    badwif = b58encode(payload)
    with pytest.raises(BTClibValueError, match="not a private key: "):
        prv_keyinfo_from_prv_key(badwif)

    # Not a WIF: wrong size (35)
    payload = b"\x80" + good_q + b"\x01\x00"
    badwif = b58encode(payload)
    with pytest.raises(BTClibValueError, match="not a private key: "):
        prv_keyinfo_from_prv_key(badwif)
Exemplo n.º 2
0
def test_msgsign_p2pkh() -> None:
    msg = "test message".encode()
    # sigs are taken from (Electrum and) Bitcoin Core

    q = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"

    # uncompressed
    wif1u = b58.wif_from_prv_key(q, "mainnet", False)
    assert wif1u == "5KMWWy2d3Mjc8LojNoj8Lcz9B1aWu8bRofUgGwQk959Dw5h2iyw"
    add1u = b58.p2pkh(wif1u)
    assert add1u == "1HUBHMij46Hae75JPdWjeZ5Q7KaL7EFRSD"
    bms_sig1u = bms.sign(msg, wif1u)
    assert bms.verify(msg, add1u, bms_sig1u)
    assert bms_sig1u.rf == 27
    exp_sig1u = "G/iew/NhHV9V9MdUEn/LFOftaTy1ivGPKPKyMlr8OSokNC755fAxpSThNRivwTNsyY9vPUDTRYBPc2cmGd5d4y4="
    assert bms_sig1u.b64encode() == exp_sig1u

    # compressed
    wif1c = b58.wif_from_prv_key(q, "mainnet", True)
    assert wif1c == "L41XHGJA5QX43QRG3FEwPbqD5BYvy6WxUxqAMM9oQdHJ5FcRHcGk"
    add1c = b58.p2pkh(wif1c)
    assert add1c == "14dD6ygPi5WXdwwBTt1FBZK3aD8uDem1FY"
    bms_sig1c = bms.sign(msg, wif1c)
    assert bms.verify(msg, add1c, bms_sig1c)
    assert bms_sig1c.rf == 31
    exp_sig1c = "H/iew/NhHV9V9MdUEn/LFOftaTy1ivGPKPKyMlr8OSokNC755fAxpSThNRivwTNsyY9vPUDTRYBPc2cmGd5d4y4="
    assert bms_sig1c.b64encode() == exp_sig1c

    assert not bms.verify(msg, add1c, bms_sig1u)
    assert not bms.verify(msg, add1u, bms_sig1c)

    bms_sig = bms.Sig(bms_sig1c.rf + 1, bms_sig1c.dsa_sig)
    assert not bms.verify(msg, add1c, bms_sig)

    # malleate s
    s = ec.n - bms_sig1c.dsa_sig.s
    dsa_sig = dsa.Sig(bms_sig1c.dsa_sig.r, s, bms_sig1c.dsa_sig.ec)
    # without updating rf verification will fail, even with lower_s=False
    bms_sig = bms.Sig(bms_sig1c.rf, dsa_sig)
    assert not bms.verify(msg, add1c, bms_sig, lower_s=False)

    # update rf to satisfy above malleation
    i = 1 if bms_sig1c.rf % 2 else -1
    bms_sig = bms.Sig(bms_sig1c.rf + i, dsa_sig)
    assert bms.verify(msg, add1c, bms_sig, lower_s=False)

    # anyway, with lower_s=True malleation does fail verification
    err_msg = "not a low s"
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.assert_as_valid(msg, add1c, bms_sig, lower_s=True)
Exemplo n.º 3
0
def test_p2pkh_from_wif() -> None:
    seed = b"\x00" * 32  # better be a documented test case
    rxprv = bip32.rootxprv_from_seed(seed)
    path = "m/0h/0h/12"
    xprv = bip32.derive(rxprv, path)
    wif = b58.wif_from_prv_key(xprv)
    assert wif == "L2L1dqRmkmVtwStNf5wg8nnGaRn3buoQr721XShM4VwDbTcn9bpm"
    pub_key, _ = pub_keyinfo_from_prv_key(wif)
    address = b58.p2pkh(pub_key)
    xpub = bip32.xpub_from_xprv(xprv)
    assert address == slip132.address_from_xpub(xpub)

    err_msg = "not a private key: "
    with pytest.raises(BTClibValueError, match=err_msg):
        b58.wif_from_prv_key(xpub)
Exemplo n.º 4
0
def test_address_from_wif() -> None:

    q = 0x19E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725

    test_cases: List[Tuple[bool, str, str, str]] = [
        (
            False,
            "mainnet",
            "5J1geo9kcAUSM6GJJmhYRX1eZEjvos9nFyWwPstVziTVueRJYvW",
            "1LPM8SZ4RQDMZymUmVSiSSvrDfj1UZY9ig",
        ),
        (
            True,
            "mainnet",
            "Kx621phdUCp6sgEXPSHwhDTrmHeUVrMkm6T95ycJyjyxbDXkr162",
            "1HJC7kFvXHepkSzdc8RX6khQKkAyntdfkB",
        ),
        (
            False,
            "testnet",
            "91nKEXyJCPYaK9maw7bTJ7ZcCu6dy2gybvNtUWF1LTCYggzhZgy",
            "mzuJRVe3ERecM6F6V4R6GN9B5fKiPC9HxF",
        ),
        (
            True,
            "testnet",
            "cNT1UjhUuGWN37hnmr754XxvPWwtAJTSq8bcCQ4pUrdxqxbA1iU1",
            "mwp9QoLuLK65XZUFKhPtvfujBjmgkZnmPx",
        ),
    ]
    for compressed, network, wif, address in test_cases:
        assert wif == b58.wif_from_prv_key(q, network, compressed)
        assert prv_keyinfo_from_prv_key(wif) == (q, network, compressed)
        assert address == b58.p2pkh(wif)
        script_type, payload, net = b58.h160_from_address(address)
        assert net == network
        assert script_type == "p2pkh"

        if compressed:
            b32_address = b32.p2wpkh(wif)
            assert (0, payload, net) == b32.witness_from_address(b32_address)

            b58_address = b58.p2wpkh_p2sh(wif)
            script_bin = hash160(b"\x00\x14" + payload)
            assert ("p2sh", script_bin,
                    net) == b58.h160_from_address(b58_address)

        else:
            err_msg = "not a private or compressed public key: "
            with pytest.raises(BTClibValueError, match=err_msg):
                b32.p2wpkh(wif)  # type: ignore
            with pytest.raises(BTClibValueError, match=err_msg):
                b58.p2wpkh_p2sh(wif)  # type: ignore
Exemplo n.º 5
0
def gen_keys(
    prv_key: Optional[PrvKey] = None,
    network: Optional[str] = None,
    compressed: Optional[bool] = None,
) -> Tuple[str, str]:
    """Return a private/public key pair.

    The private key is a WIF, the public key is a base58 P2PKH address.
    """

    if prv_key is None:
        if network is None:
            network = "mainnet"
        ec = NETWORKS[network].curve
        # q in the range [1, ec.n-1]
        q = 1 + secrets.randbelow(ec.n - 1)
        wif = wif_from_prv_key(q, network, compressed)
    else:
        wif = wif_from_prv_key(prv_key, network, compressed)

    address = p2pkh(wif)

    return wif, address
Exemplo n.º 6
0
print(f" s3: {hex(sig3.dsa_sig.s).upper()}")

bsmsig3 = sig3.serialize()
print("4. Serialized signature:")
print("     bytes:", bsmsig3)
print("hex-string:", bsmsig3.hex().upper())

print("5. Verify signature")
print("Bitcoin Core p2pkh:", verify(msg, address1, sig3))
print("BIP137 p2wpkh_p2sh:", verify(msg, address2, sig3))
print("BIP137 p2wpkh     :", verify(msg, address3, sig3))


# uncompressed WIF / P2PKH address
q, network, _ = prv_keyinfo_from_prv_key(wif)
wif2 = wif_from_prv_key(q, network, compressed=False)
print("\n1. Uncompressed WIF          :", wif2)
pubkey, network = pub_keyinfo_from_prv_key(wif2)

address4 = p2pkh(pubkey)
print("2. Uncompressed P2PKH address:", address4)

print("3. Sign message with uncompressed p2pkh:")
sig4 = sign(msg, wif2, address4)
print(f"rf4: {sig4.rf}")
print(f" r4: {hex(sig4.dsa_sig.r).upper()}")
print(f" s4: {hex(sig4.dsa_sig.s).upper()}")

bsmsig4 = sig4.serialize()
print("4. Serialized signature:")
print("     bytes:", bsmsig4)
Exemplo n.º 7
0
def test_one_prv_key_multiple_addresses() -> None:

    msg = "Paolo is afraid of ephemeral random numbers".encode()

    # Compressed WIF
    wif = "Kx45GeUBSMPReYQwgXiKhG9FzNXrnCeutJp4yjTd5kKxCitadm3C"
    b58_p2pkh_compressed = b58.p2pkh(wif)
    b58_p2wpkh_p2sh = b58.p2wpkh_p2sh(wif)
    b32_p2wpkh = b32.p2wpkh(wif)

    # sign with no address
    sig1 = bms.sign(msg, wif)
    # True for Bitcoin Core
    bms.assert_as_valid(msg, b58_p2pkh_compressed, sig1)
    assert bms.verify(msg, b58_p2pkh_compressed, sig1)
    # True for Electrum p2wpkh_p2sh
    bms.assert_as_valid(msg, b58_p2wpkh_p2sh, sig1)
    assert bms.verify(msg, b58_p2wpkh_p2sh, sig1)
    # True for Electrum p2wpkh
    bms.assert_as_valid(msg, b32_p2wpkh, sig1)
    assert bms.verify(msg, b32_p2wpkh, sig1)

    # sign with p2pkh address
    sig1 = bms.sign(msg, wif, b58_p2pkh_compressed)
    # True for Bitcoin Core
    bms.assert_as_valid(msg, b58_p2pkh_compressed, sig1)
    assert bms.verify(msg, b58_p2pkh_compressed, sig1)
    # True for Electrum p2wpkh_p2sh
    bms.assert_as_valid(msg, b58_p2wpkh_p2sh, sig1)
    assert bms.verify(msg, b58_p2wpkh_p2sh, sig1)
    # True for Electrum p2wpkh
    bms.assert_as_valid(msg, b32_p2wpkh, sig1)
    assert bms.verify(msg, b32_p2wpkh, sig1)
    assert sig1 == bms.sign(msg, wif, b58_p2pkh_compressed.encode("ascii"))

    # sign with p2wpkh_p2sh address (BIP137)
    sig2 = bms.sign(msg, wif, b58_p2wpkh_p2sh)
    # False for Bitcoin Core
    err_msg = "invalid p2pkh address recovery flag: "
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.assert_as_valid(msg, b58_p2pkh_compressed, sig2)
    assert not bms.verify(msg, b58_p2pkh_compressed, sig2)
    # True for BIP137 p2wpkh_p2sh
    bms.assert_as_valid(msg, b58_p2wpkh_p2sh, sig2)
    assert bms.verify(msg, b58_p2wpkh_p2sh, sig2)
    # False for BIP137 p2wpkh
    err_msg = "invalid p2wpkh address recovery flag: "
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.assert_as_valid(msg, b32_p2wpkh, sig2)
    assert not bms.verify(msg, b32_p2wpkh, sig2)
    assert sig2 == bms.sign(msg, wif, b58_p2wpkh_p2sh.encode("ascii"))

    # sign with p2wpkh address (BIP137)
    sig3 = bms.sign(msg, wif, b32_p2wpkh)
    # False for Bitcoin Core
    err_msg = "invalid p2pkh address recovery flag: "
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.assert_as_valid(msg, b58_p2pkh_compressed, sig3)
    assert not bms.verify(msg, b58_p2pkh_compressed, sig3)
    # False for BIP137 p2wpkh_p2sh
    err_msg = "invalid p2wpkh-p2sh address recovery flag: "
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.assert_as_valid(msg, b58_p2wpkh_p2sh, sig3)
    assert not bms.verify(msg, b58_p2wpkh_p2sh, sig3)
    # True for BIP137 p2wpkh
    bms.assert_as_valid(msg, b32_p2wpkh, sig3)
    assert bms.verify(msg, b32_p2wpkh, sig3)
    assert sig3 == bms.sign(msg, wif, b32_p2wpkh.encode("ascii"))

    # uncompressed WIF / p2pkh address
    q, network, _ = prv_keyinfo_from_prv_key(wif)
    wif2 = b58.wif_from_prv_key(q, network, False)
    b58_p2pkh_uncompressed = b58.p2pkh(wif2)

    # sign with uncompressed p2pkh
    sig4 = bms.sign(msg, wif2, b58_p2pkh_uncompressed)
    # False for Bitcoin Core compressed p2pkh
    with pytest.raises(BTClibValueError, match="invalid p2pkh address: "):
        bms.assert_as_valid(msg, b58_p2pkh_compressed, sig4)
    assert not bms.verify(msg, b58_p2pkh_compressed, sig4)
    # False for BIP137 p2wpkh_p2sh
    err_msg = "invalid p2wpkh-p2sh address recovery flag: "
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.assert_as_valid(msg, b58_p2wpkh_p2sh, sig4)
    assert not bms.verify(msg, b58_p2wpkh_p2sh, sig4)
    # False for BIP137 p2wpkh
    err_msg = "invalid p2wpkh address recovery flag: "
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.assert_as_valid(msg, b32_p2wpkh, sig4)
    assert not bms.verify(msg, b32_p2wpkh, sig4)
    # True for Bitcoin Core uncompressed p2pkh
    bms.assert_as_valid(msg, b58_p2pkh_uncompressed, sig4)
    assert bms.verify(msg, b58_p2pkh_uncompressed, sig4)
    assert sig4 == bms.sign(msg, wif2, b58_p2pkh_uncompressed.encode("ascii"))

    # unrelated different wif
    wif3 = "KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617"
    b58_p2pkh_compressed = b58.p2pkh(wif3)
    b58_p2wpkh_p2sh = b58.p2wpkh_p2sh(wif3)
    b32_p2wpkh = b32.p2wpkh(wif3)

    # False for Bitcoin Core compressed p2pkh
    with pytest.raises(BTClibValueError, match="invalid p2pkh address: "):
        bms.assert_as_valid(msg, b58_p2pkh_compressed, sig1)
    assert not bms.verify(msg, b58_p2pkh_compressed, sig1)
    # False for BIP137 p2wpkh_p2sh
    with pytest.raises(BTClibValueError, match="invalid p2wpkh-p2sh address: "):
        bms.assert_as_valid(msg, b58_p2wpkh_p2sh, sig1)
    assert not bms.verify(msg, b58_p2wpkh_p2sh, sig1)
    # False for BIP137 p2wpkh
    with pytest.raises(BTClibValueError, match="invalid p2wpkh address: "):
        bms.assert_as_valid(msg, b32_p2wpkh, sig1)
    assert not bms.verify(msg, b32_p2wpkh, sig1)

    # FIXME: puzzling error message
    err_msg = "not a private or compressed public key for mainnet: "
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.sign(msg, wif2, b58_p2pkh_compressed)

    err_msg = "mismatch between private key and address"
    with pytest.raises(BTClibValueError, match=err_msg):
        bms.sign(msg, wif, b58_p2pkh_uncompressed)