Exemple #1
0
    def test_p2pkh_from_pubkey(self):
        # https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
        pub = "02 50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
        addr = p2pkh(pub)
        self.assertEqual(addr, b'1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs')
        _, h160, _, _ = h160_from_b58address(addr)
        self.assertEqual(h160, hash160(pub))

        uncompr_pub = bytes_from_point(
            point_from_octets(pub), compressed=False)
        addr = p2pkh(uncompr_pub, compressed=False)
        self.assertEqual(addr, b'16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM')
        _, h160, _, _ = h160_from_b58address(addr)
        self.assertEqual(h160, hash160(uncompr_pub))

        # trailing/leading spaces in string
        pub = '  02 50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352'
        addr = p2pkh(pub)
        self.assertEqual(addr, b'1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs')
        _, h160, _, _ = h160_from_b58address(addr)
        self.assertEqual(h160, hash160(pub))

        pub = '02 50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352  '
        addr = p2pkh(pub)
        self.assertEqual(addr, b'1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs')
Exemple #2
0
    def test_p2wpkh(self):

        # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
        # leading/trailing spaces should be tolerated
        pub = " 0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2" "815B16F81798"
        addr = b"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
        self.assertEqual(addr, p2wpkh(pub))
        addr = b"tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"
        self.assertEqual(addr, p2wpkh(pub, "testnet"))

        # http://bitcoinscri.pt/pages/segwit_native_p2wpkh
        pub = "02 530c548d402670b13ad8887ff99c294e67fc18097d236d57880c69" "261b42def7"
        addr = b"bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck"
        self.assertEqual(addr, p2wpkh(pub))

        _, wp, _, _ = witness_from_b32address(addr)
        self.assertEqual(bytes(wp), hash160(pub))

        # Wrong size (65-bytes) for compressed SEC key
        uncompr_pub = bytes_from_point(point_from_octets(pub),
                                       compressed=False)
        self.assertRaises(ValueError, p2wpkh, uncompr_pub)
        # p2wpkh(uncompr_pub)

        # Wrong pubkey size: 34 instead of 33
        self.assertRaises(ValueError, p2wpkh, pub + "00")
        # p2wpkh(pub + '00')

        # Witness program length (21) is not 20
        self.assertRaises(ValueError, b32address_from_witness, 0,
                          hash160(pub) + b"\x00")
    def test_p2sh(self):

        script_type = "p2sh"

        # self-consistency
        pubkey = "02" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf"
        pubkey_hash = hash160(pubkey)
        redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash)
        payload = hash160(redeem_script)
        script = encode(["OP_HASH160", payload, "OP_EQUAL"])

        # straight to the scriptPubKey
        scriptPubKey = p2sh(redeem_script)
        self.assertEqual(scriptPubKey.hex(), script.hex())

        # to the scriptPubKey in two steps (through payload)
        scriptPubKey = scriptPubKey_from_payload(script_type, payload)
        self.assertEqual(scriptPubKey.hex(), script.hex())

        # back from the scriptPubKey to the payload
        script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey)
        self.assertEqual(script_type, script_type2)
        self.assertEqual(0, m2)
        self.assertEqual(payload.hex(), payload2.hex())
        script_type2, payload2, m2 = payload_from_scriptPubKey(script)
        self.assertEqual(script_type, script_type2)
        self.assertEqual(0, m2)
        self.assertEqual(payload.hex(), payload2.hex())

        # data -> payload is not invertible (hash functions)

        # address
        network = "mainnet"
        address = base58address.p2sh(decode(redeem_script), network)
        address2 = address_from_scriptPubKey(scriptPubKey, network)
        self.assertEqual(address, address2)
        prefix = NETWORKS[network]["p2sh"]
        address2 = b58address_from_h160(prefix, payload, network)
        self.assertEqual(address, address2)

        scriptPubKey2, network2 = scriptPubKey_from_address(address)
        self.assertEqual(scriptPubKey2, scriptPubKey)
        self.assertEqual(network2, network)

        # documented test case: https://learnmeabitcoin.com/guide/p2sh
        payload = "748284390f9e263a4b766a75d0633c50426eb875"
        script = "a914748284390f9e263a4b766a75d0633c50426eb87587"
        scriptPubKey = scriptPubKey_from_payload(script_type, payload)
        self.assertEqual(scriptPubKey.hex(), script)
        network = "mainnet"
        address = b"3CK4fEwbMP7heJarmU4eqA3sMbVJyEnU3V"
        address2 = address_from_scriptPubKey(scriptPubKey, network)
        self.assertEqual(address, address2)
        scriptPubKey2, network2 = scriptPubKey_from_address(address)
        self.assertEqual(scriptPubKey2, scriptPubKey)
        self.assertEqual(network2, network)

        # invalid size: 21 bytes instead of 20
        self.assertRaises(ValueError, scriptPubKey_from_payload, "00" * 21,
                          "p2sh")
Exemple #4
0
    def test_selfconsistency(self):

        # OP_RETURN
        data = "time-stamped data".encode().hex()
        # opcodes = ['OP_RETURN', data.hex()]
        opcodes = nulldata_scriptPubKey(data)
        scriptPubKey = encode(opcodes)
        opcodes2 = decode(scriptPubKey)
        self.assertEqual(opcodes, opcodes2)

        # p2pk
        pubkey = "04 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4"
        # opcodes = [pubkey, 'OP_CHECKSIG']
        opcodes = p2pk_scriptPubKey(pubkey)
        scriptPubKey = encode(opcodes)
        opcodes2 = decode(scriptPubKey)
        self.assertEqual(opcodes, opcodes2)

        # multi-sig
        pubkey2 = "04 61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765 19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af"
        # opcodes = [1, pubkey, pubKey2, 2, 'OP_CHECKMULTISIG']
        opcodes = p2ms_scriptPubKey(1, (pubkey, pubkey2))
        scriptPubKey = encode(opcodes)
        opcodes2 = decode(scriptPubKey)
        self.assertEqual(opcodes, opcodes2)

        # p2pkh
        pubkey_hash = hash160(pubkey).hex()
        # opcodes = ['OP_DUP', 'OP_HASH160', pubkey_hash.hex(), 'OP_EQUALVERIFY', 'OP_CHECKSIG']
        opcodes = p2pkh_scriptPubKey(pubkey_hash)
        scriptPubKey = encode(opcodes)
        opcodes2 = decode(scriptPubKey)
        self.assertEqual(opcodes, opcodes2)

        # p2sh (p2pkh-p2sh)
        redeem_script_hash = hash160(scriptPubKey).hex()
        # opcodes = ['OP_HASH160', redeem_script_hash.hex(), 'OP_EQUAL']
        opcodes = p2sh_scriptPubKey(redeem_script_hash)
        scriptPubKey = encode(opcodes)
        opcodes2 = decode(scriptPubKey)
        self.assertEqual(opcodes, opcodes2)

        # p2wpkh
        # opcodes = [0, pubkey_hash.hex()]
        opcodes = p2wpkh_scriptPubKey(pubkey_hash)
        scriptPubKey = encode(opcodes)
        self.assertEqual(scriptPubKey.hex(), "0014"+pubkey_hash)
        opcodes2 = decode(scriptPubKey)
        self.assertEqual(opcodes, opcodes2)

        # p2wsh
        witness_script = [pubkey, 'OP_CHECKSIG']
        witness_script_bytes = encode(witness_script)
        witness_script_hash = sha256(witness_script_bytes)
        # opcodes = [0, witness_script_hash.hex()]
        opcodes = p2wsh_scriptPubKey(witness_script_hash.hex())
        scriptPubKey = encode(opcodes)
        self.assertEqual(scriptPubKey.hex(), "0020"+witness_script_hash.hex())
        opcodes2 = decode(scriptPubKey)
        self.assertEqual(opcodes, opcodes2)
Exemple #5
0
    def test_address_scriptPubKey(self):

        pubkey = "03 a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f"
        pubkey_hash = hash160(pubkey).hex()

        opcodes = [0, pubkey_hash]
        address_from_scriptPubKey(opcodes)
        opcodes2, _ = scriptPubKey_from_address(address_from_scriptPubKey(opcodes))
        self.assertEqual(opcodes, opcodes2)

        opcodes = ['OP_DUP', 'OP_HASH160', pubkey_hash, 'OP_EQUALVERIFY', 'OP_CHECKSIG']
        opcodes2, _ = scriptPubKey_from_address(address_from_scriptPubKey(opcodes))
        self.assertEqual(opcodes, opcodes2)

        script_hash = hash160(encode(opcodes)).hex()
        opcodes = ['OP_HASH160',script_hash, 'OP_EQUAL']
        opcodes2, _ = scriptPubKey_from_address(address_from_scriptPubKey(opcodes))
        self.assertEqual(opcodes, opcodes2)

        script_hash = sha256(encode(opcodes)).hex()
        opcodes = [0, script_hash]
        opcodes2, _ = scriptPubKey_from_address(address_from_scriptPubKey(opcodes))
        self.assertEqual(opcodes, opcodes2)

        # Unknown script
        opcodes = [16, pubkey_hash]
        self.assertRaises(ValueError, address_from_scriptPubKey, opcodes)
        #address_from_scriptPubKey(opcodes)

        # Unhandled witness version (16)
        wp = hash160(pubkey)[2:]
        addr = b32address_from_witness(16, wp)
        self.assertRaises(ValueError, scriptPubKey_from_address, addr)
Exemple #6
0
def test_p2wpkh() -> None:

    # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
    # leading/trailing spaces should be tolerated
    pub = " 02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
    addr = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
    assert addr == b32.p2wpkh(pub)
    addr = "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"
    assert addr == b32.p2wpkh(pub, "testnet")

    # http://bitcoinscri.pt/pages/segwit_native_p2wpkh
    pub = "02 530c548d402670b13ad8887ff99c294e67fc18097d236d57880c69261b42def7"
    addr = "bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck"
    assert addr == b32.p2wpkh(pub)

    _, wit_prg, _ = b32.witness_from_address(addr)
    assert wit_prg == hash160(pub)

    uncompr_pub = bytes_from_point(point_from_octets(pub), compressed=False)
    err_msg = "not a private or compressed public key: "
    with pytest.raises(BTClibValueError, match=err_msg):
        b32.p2wpkh(uncompr_pub)
    with pytest.raises(BTClibValueError, match=err_msg):
        b32.p2wpkh(pub + "00")

    err_msg = "invalid size: "
    with pytest.raises(BTClibValueError, match=err_msg):
        b32.address_from_witness(0, hash160(pub) + b"\x00")
def test_p2pkh_from_pub_key() -> None:
    # https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
    pub_key = "02 50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
    address = "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
    assert address == b58.p2pkh(pub_key)
    assert address == b58.p2pkh(pub_key, compressed=True)
    _, h160, _ = b58.h160_from_address(address)
    assert h160 == hash160(pub_key)

    # trailing/leading spaces in address string
    assert address == b58.p2pkh(" " + pub_key)
    assert h160 == hash160(" " + pub_key)
    assert address == b58.p2pkh(pub_key + " ")
    assert h160 == hash160(pub_key + " ")

    uncompr_pub_key = bytes_from_point(point_from_octets(pub_key),
                                       compressed=False)
    uncompr_address = "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
    assert uncompr_address == b58.p2pkh(uncompr_pub_key, compressed=False)
    assert uncompr_address == b58.p2pkh(uncompr_pub_key)
    _, uncompr_h160, _ = b58.h160_from_address(uncompr_address)
    assert uncompr_h160 == hash160(uncompr_pub_key)

    err_msg = "not a private or uncompressed public key: "
    with pytest.raises(BTClibValueError, match=err_msg):
        assert uncompr_address == b58.p2pkh(pub_key, compressed=False)

    err_msg = "not a private or compressed public key: "
    with pytest.raises(BTClibValueError, match=err_msg):
        assert address == b58.p2pkh(uncompr_pub_key, compressed=True)
Exemple #8
0
 def test_utils(self):
     s_spaces = " 0C 28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D  "
     b = bytes_from_octets(s_spaces)
     s = b.hex()  # lower case, no spaces
     self.assertNotEqual(s, s_spaces)
     self.assertEqual(hash160(s_spaces), hash160(bytes_from_octets(s)))
     self.assertEqual(hash256(s_spaces), hash256(bytes_from_octets(s)))
    def test_p2wpkh_address(self):

        # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
        # leading/trailing spaces should be tolerated
        pub = " 0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
        addr = b'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
        self.assertEqual(addr, p2wpkh_address(pub))
        addr = b'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx'
        self.assertEqual(addr, p2wpkh_address(pub, 'testnet'))

        # http://bitcoinscri.pt/pages/segwit_native_p2wpkh_address
        pub = "02530c548d402670b13ad8887ff99c294e67fc18097d236d57880c69261b42def7"
        addr = b'bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck'
        self.assertEqual(addr, p2wpkh_address(pub))

        _, _, wp = _decode(addr)
        self.assertEqual(bytes(wp), hash160(pub))

        # Uncompressed pubkey
        uncompr_pub = octets_from_point(point_from_octets(pub, ec), False, ec)
        self.assertRaises(ValueError, p2wpkh_address, uncompr_pub)
        # p2wpkh_address(uncompr_pub)

        # Wrong pubkey size: 34 instead of 33
        self.assertRaises(ValueError, p2wpkh_address, pub + '00')
        # p2wpkh_address(pub + '00')

        # Witness program length (21) is not 20
        self.assertRaises(ValueError, _p2wpkh_address,
                          hash160(pub) + b'\x00', True, "mainnet")
Exemple #10
0
def test_hash160_hash256() -> None:
    test_vectors = (plain_prv_keys + net_unaware_compressed_pub_keys +
                    net_unaware_uncompressed_pub_keys)
    for hexstring in test_vectors:
        b = bytes_from_octets(hexstring)
        s = b.hex()  # lower case, no spaces
        assert hash160(hexstring) == hash160(s)
        assert hash256(hexstring) == hash256(s)
Exemple #11
0
    def test_utils(self):
        b = bytes_from_octets(int_with_whitespaces)
        s = b.hex()  # lower case, no spaces
        self.assertNotEqual(int_with_whitespaces, s)
        self.assertEqual(hash160(int_with_whitespaces), hash160(s))
        self.assertEqual(hash256(int_with_whitespaces), hash256(s))

        i = secrets.randbits(256)
        self.assertEqual(i, int_from_integer(i))
        self.assertEqual(i, int_from_integer(i.to_bytes(32, "big")))
        self.assertEqual(i, int_from_integer(hex(i)))
def assert_as_valid(msg: Octets,
                    addr: String,
                    sig: Union[Sig, String],
                    lower_s: bool = True) -> None:
    # Private function for test/dev purposes
    # It raises Errors, while verify should always return True or False

    if isinstance(sig, Sig):
        sig.assert_valid()
    else:
        sig = Sig.b64decode(sig)

    # first two bits in rf are reserved for key_id
    #    key_id = 00;     key_id = 01;     key_id = 10;     key_id = 11
    # 27-27 = 000000;  28-27 = 000001;  29-27 = 000010;  30-27 = 000011
    # 31-27 = 000100;  32-27 = 000101;  33-27 = 000110;  34-27 = 000111
    # 35-27 = 001000;  36-27 = 001001;  37-27 = 001010;  38-27 = 001011
    # 39-27 = 001100;  40-27 = 001101;  41-27 = 001110;  42-27 = 001111
    key_id = sig.rf - 27 & 0b11
    magic_msg = magic_message(msg)
    Q = dsa.recover_pub_key(key_id, magic_msg, sig.dsa_sig, lower_s, sha256)
    compressed = sig.rf > 30
    # signature is valid only if the provided address is matched
    pub_key = bytes_from_point(Q, compressed=compressed)

    if has_segwit_prefix(addr):
        wit_ver, h160, _ = witness_from_address(addr)
        if wit_ver != 0 or len(h160) != 20:
            raise BTClibValueError(f"not a p2wpkh address: {addr!r}")
        if not (30 < sig.rf < 35 or sig.rf > 38):
            raise BTClibValueError(
                f"invalid p2wpkh address recovery flag: {sig.rf}")
        if hash160(pub_key) != h160:
            raise BTClibValueError(f"invalid p2wpkh address: {addr!r}")
        return

    script_type, h160, _ = h160_from_address(addr)

    if script_type == "p2pkh":
        if sig.rf > 34:
            raise BTClibValueError(
                f"invalid p2pkh address recovery flag: {sig.rf}")
        if hash160(pub_key) != h160:
            raise BTClibValueError(f"invalid p2pkh address: {addr!r}")
        return

    # must be P2WPKH-P2SH
    if not 30 < sig.rf < 39:
        raise BTClibValueError(
            f"invalid p2wpkh-p2sh address recovery flag: {sig.rf}")
    script_pk = b"\x00\x14" + hash160(pub_key)
    if hash160(script_pk) != h160:
        raise BTClibValueError(f"invalid p2wpkh-p2sh address: {addr!r}")
    def assert_signable(self) -> None:

        self.assert_valid()

        for i, tx_in in enumerate(self.tx.vin):

            non_witness_utxo = self.inputs[i].non_witness_utxo
            witness_utxo = self.inputs[i].witness_utxo
            redeem_script = self.inputs[i].redeem_script

            if witness_utxo:
                script_pub_key = witness_utxo.script_pub_key
                script_type, payload = type_and_payload(script_pub_key.script)
                if script_type == "p2sh":
                    script_type, _ = type_and_payload(redeem_script)
                if script_type not in ("p2wpkh", "p2wsh"):
                    raise BTClibValueError(
                        "script type not it ('p2wpkh', 'p2wsh')")
            elif non_witness_utxo:
                script_pub_key = non_witness_utxo.vout[
                    tx_in.prev_out.vout].script_pub_key
                _, payload = type_and_payload(script_pub_key.script)
            else:
                err_msg = "missing script_pub_key"
                raise BTClibValueError(err_msg)

            if redeem_script and payload != hash160(redeem_script):
                raise BTClibValueError("invalid redeem script hash160")

            if self.inputs[i].witness_script:
                if redeem_script:
                    _, payload = type_and_payload(redeem_script)
                if payload != sha256(self.inputs[i].witness_script):
                    raise BTClibValueError("invalid witness script sha256")
def test_p2wpkh() -> None:

    # self-consistency
    pub_key = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf"
    payload = hash160(pub_key)
    script_pub_key = serialize(["OP_0", payload])
    assert_p2wpkh(script_pub_key)
    assert script_pub_key == ScriptPubKey.p2wpkh(pub_key).script
    assert ("p2wpkh", payload) == type_and_payload(script_pub_key)

    # bech32 address
    network = "mainnet"
    addr = b32.p2wpkh(pub_key, network)
    assert addr == address(script_pub_key, network)
    assert addr == b32.address_from_witness(0, payload, network)

    # back from the address to the script_pub_key
    assert script_pub_key == ScriptPubKey.from_address(addr).script
    assert network == ScriptPubKey.from_address(addr).network

    # p2sh-wrapped base58 address
    addr = b58.p2wpkh_p2sh(pub_key, network)
    assert addr == b58.address_from_v0_witness(payload, network)

    err_msg = "invalid witness version: "
    with pytest.raises(BTClibValueError, match=err_msg):
        assert_p2wpkh(b"\x33" + script_pub_key[1:])

    err_msg = "invalid pub_key hash length marker: "
    with pytest.raises(BTClibValueError, match=err_msg):
        assert_p2wpkh(script_pub_key[:1] + b"\x00" + script_pub_key[2:])
Exemple #15
0
    def test_witness(self):

        pub = "03 a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f"
        b58addr = p2wpkh_p2sh(pub)
        _, h160, network, is_script_hash = h160_from_b58address(b58addr)
        self.assertEqual(network, 'mainnet')
        self.assertEqual(is_script_hash, True)  #?!?!?
        self.assertEqual(len(h160), 20)

        b58addr = _b58segwitaddress(hash160(to_pubkey_bytes(pub, True, ec)),
                                    network)
        _, h160_2, network, is_script_hash = h160_from_b58address(b58addr)
        self.assertEqual(network, 'mainnet')
        self.assertEqual(is_script_hash, True)  #?!?!?
        self.assertEqual(len(h160), 20)
        self.assertEqual(h160.hex(), h160_2.hex())

        wscript = "a8a58c2d034b28bf90c8803f5a53f769a4"
        b58addr = p2wsh_p2sh(wscript)
        _, h160, network, is_script_hash = h160_from_b58address(b58addr)
        self.assertEqual(network, 'mainnet')
        self.assertEqual(is_script_hash, True)  #?!?!?
        self.assertEqual(len(h160), 20)

        b58addr = _b58segwitaddress(sha256(wscript), network)
        _, h160_2, network, is_script_hash = h160_from_b58address(b58addr)
        self.assertEqual(network, 'mainnet')
        self.assertEqual(is_script_hash, True)  #?!?!?
        self.assertEqual(len(h160), 20)
        self.assertEqual(h160.hex(), h160_2.hex())

        # Invalid witness program length (19)
        self.assertRaises(ValueError, _b58segwitaddress, h160[:-1], network)
def test_p2sh() -> None:
    # https://medium.com/@darosior/bitcoin-raw-transactions-part-2-p2sh-94df206fee8d
    network = "mainnet"
    address = "37k7toV1Nv4DfmQbmZ8KuZDQCYK9x5KpzP"
    script_pub_key = serialize([
        "OP_2DUP",
        "OP_EQUAL",
        "OP_NOT",
        "OP_VERIFY",
        "OP_SHA1",
        "OP_SWAP",
        "OP_SHA1",
        "OP_EQUAL",
    ])

    assert script_pub_key.hex() == "6e879169a77ca787"
    assert address == b58.p2sh(script_pub_key, network)

    script_hash = hash160(script_pub_key)
    assert ("p2sh", script_hash, network) == b58.h160_from_address(address)
    assert ("p2sh", script_hash,
            network) == b58.h160_from_address(" " + address + " ")

    assert script_hash.hex() == "4266fc6f2c2861d7fe229b279a79803afca7ba34"
    script_sig: List[Command] = ["OP_HASH160", script_hash.hex(), "OP_EQUAL"]
    serialize(script_sig)
Exemple #17
0
def test_p2wsh() -> None:

    # self-consistency
    pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf"
    pubkey_hash = hash160(pubkey)
    redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash)
    payload = sha256(redeem_script)
    scriptPubKey = script.encode([0, payload])
    assert scriptPubKey == p2wsh(script.decode(redeem_script))

    # to the scriptPubKey in two steps (through payload)
    script_type = "p2wsh"
    assert scriptPubKey == scriptPubKey_from_payload(script_type, payload)

    # back from the scriptPubKey to the payload
    assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey)

    # bech32 address
    network = "mainnet"
    address = bech32address.p2wsh(redeem_script, network)
    assert address == address_from_scriptPubKey(scriptPubKey, network)
    wit_ver = 0
    assert address == b32address_from_witness(wit_ver, payload, network)

    # back from the address to the scriptPubKey
    assert (scriptPubKey, network) == scriptPubKey_from_address(address)

    # p2sh-wrapped base58 address
    address = base58address.p2wsh_p2sh(redeem_script, network)
    assert address == b58address_from_witness(payload, network)
Exemple #18
0
    def test_p2sh(self):
        # https://medium.com/@darosior/bitcoin-raw-transactions-part-2-p2sh-94df206fee8d
        script = ['OP_2DUP', 'OP_EQUAL', 'OP_NOT', 'OP_VERIFY',
                  'OP_SHA1', 'OP_SWAP', 'OP_SHA1', 'OP_EQUAL']
        script_bytes = encode(script)
        self.assertEqual(script_bytes.hex(), '6e879169a77ca787')

        network = 'mainnet'
        addr = p2sh(script_bytes, network)
        self.assertEqual(addr, b'37k7toV1Nv4DfmQbmZ8KuZDQCYK9x5KpzP')

        _, redeem_script_hash, network2, is_p2sh = h160_from_b58address(addr)
        self.assertEqual(network, network2)
        self.assertTrue(is_p2sh)
        self.assertEqual(redeem_script_hash, hash160(script_bytes))

        self.assertEqual(redeem_script_hash.hex(),
                         '4266fc6f2c2861d7fe229b279a79803afca7ba34')
        output_script = ['OP_HASH160', redeem_script_hash.hex(), 'OP_EQUAL']
        _ = encode(output_script)

        # address with trailing/leading spaces
        _, h160, _, _ = h160_from_b58address(
            ' 37k7toV1Nv4DfmQbmZ8KuZDQCYK9x5KpzP ')
        self.assertEqual(redeem_script_hash, h160)
    def test_p2pkh(self):

        script_type = 'p2pkh'

        # self-consistency
        pubkey = "04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4"
        payload = hash160(pubkey)
        script = encode(['OP_DUP', 'OP_HASH160', payload,
                         'OP_EQUALVERIFY', 'OP_CHECKSIG'])

        # straight to the scriptPubKey
        scriptPubKey = p2pkh(pubkey)
        self.assertEqual(scriptPubKey.hex(), script.hex())

        # to the scriptPubKey in two steps (through payload)
        scriptPubKey = scriptPubKey_from_payload(script_type, payload)
        self.assertEqual(scriptPubKey.hex(), script.hex())

        # back from the scriptPubKey to the payload
        script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey)
        self.assertEqual(script_type, script_type2)
        self.assertEqual(0, m2)
        self.assertEqual(payload.hex(), payload2.hex())
        script_type2, payload2, m2 = payload_from_scriptPubKey(script)
        self.assertEqual(script_type, script_type2)
        self.assertEqual(0, m2)
        self.assertEqual(payload.hex(), payload2.hex())

        # data -> payload is not invertible (hash functions)

        # address
        network = 'mainnet'
        address = base58address.p2pkh(pubkey, network)
        address2 = address_from_scriptPubKey(scriptPubKey, network)
        self.assertEqual(address, address2)
        prefix = p2pkh_prefix_from_network(network)
        address2 = b58address_from_h160(prefix, payload)
        self.assertEqual(address, address2)

        scriptPubKey2, network2 = scriptPubKey_from_address(address)
        self.assertEqual(scriptPubKey2, scriptPubKey)
        self.assertEqual(network2, network)

        # documented test case: https://learnmeabitcoin.com/guide/p2pkh
        payload = "12ab8dc588ca9d5787dde7eb29569da63c3a238c"
        script = "76a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac"
        scriptPubKey = scriptPubKey_from_payload(script_type, payload)
        self.assertEqual(scriptPubKey.hex(), script)
        network = 'mainnet'
        address = b"12higDjoCCNXSA95xZMWUdPvXNmkAduhWv"
        address2 = address_from_scriptPubKey(scriptPubKey, network)
        self.assertEqual(address, address2)
        scriptPubKey2, network2 = scriptPubKey_from_address(address)
        self.assertEqual(scriptPubKey2, scriptPubKey)
        self.assertEqual(network2, network)

        # Invalid size: 11 bytes instead of 20
        self.assertRaises(
            ValueError, scriptPubKey_from_payload, "00" * 11, 'p2pkh')
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
Exemple #22
0
def test_exceptions() -> None:

    pubkey = "02 50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
    payload = b"\xf5" + hash160(pubkey)
    invalid_address = b58encode(payload)
    with pytest.raises(ValueError, match="invalid base58 address prefix: "):
        h160_from_b58address(invalid_address)

    with pytest.raises(ValueError, match="not a private or public key: "):
        p2pkh(pubkey + "00")
Exemple #23
0
def test_p2sh() -> None:

    # self-consistency
    pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf"
    pubkey_hash = hash160(pubkey)
    redeem_script = script_pubkey_from_payload("p2pkh", pubkey_hash)
    payload = hash160(redeem_script)
    script_pubkey = script.serialize(["OP_HASH160", payload, "OP_EQUAL"])
    assert script_pubkey == p2sh(redeem_script)

    # to the script_pubkey in two steps (through payload)
    script_type = "p2sh"
    assert script_pubkey == script_pubkey_from_payload(script_type, payload)

    # back from the script_pubkey to the payload
    assert (script_type, payload,
            0) == payload_from_script_pubkey(script_pubkey)

    # base58 address
    network = "mainnet"
    address = base58address.p2sh(script.deserialize(redeem_script), network)
    assert address == address_from_script_pubkey(script_pubkey, network)
    prefix = NETWORKS[network].p2sh
    assert address == b58address_from_h160(prefix, payload, network)

    # back from the address to the script_pubkey
    assert (script_pubkey, network) == script_pubkey_from_address(address)

    # documented test case: https://learnmeabitcoin.com/guide/p2sh
    payload = "748284390f9e263a4b766a75d0633c50426eb875"
    script_pubkey = "a914" + payload + "87"
    assert script_pubkey == script_pubkey_from_payload(script_type,
                                                       payload).hex()
    address = b"3CK4fEwbMP7heJarmU4eqA3sMbVJyEnU3V"
    assert address == address_from_script_pubkey(script_pubkey, network)
    assert (bytes.fromhex(script_pubkey),
            network) == script_pubkey_from_address(address)

    # invalid size: 21 bytes instead of 20
    err_msg = "invalid size: "
    with pytest.raises(BTClibValueError, match=err_msg):
        script_pubkey_from_payload(script_type, "00" * 21)
    def p2sh(
        cls: Type[_ScriptPubKey],
        redeem_script: Octets,
        network: str = "mainnet",
        check_validity: bool = True,
    ) -> _ScriptPubKey:
        "Return the p2sh ScriptPubKey of the provided redeem script."

        script_h160 = hash160(redeem_script)
        script = serialize(["OP_HASH160", script_h160, "OP_EQUAL"])
        return cls(script, network, check_validity)
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
Exemple #26
0
    def test_exceptions(self):

        # Invalid base58 address prefix b'\xf5'
        payload = b'\xf5'
        pubkey = "02 50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
        payload += hash160(pubkey)
        invalid_address = b58encode(payload)
        self.assertRaises(ValueError, h160_from_b58address, invalid_address)
        # _h160_from_b58address(invalid_address)

        # Invalid SEC pubkey length: 34-bytes
        self.assertRaises(ValueError, p2pkh, pubkey + '00', True)
def __ckd(xkey: _ExtendedBIP32KeyData, index: int) -> None:

    xkey.depth += 1
    xkey.index = index
    if xkey.key[0] == 0:  # private key
        Q_bytes = bytes_from_point(mult(xkey.prv_key_int))
        xkey.parent_fingerprint = hash160(Q_bytes)[:4]
        if xkey.is_hardened():  # hardened derivation
            hmac_ = hmac.new(
                xkey.chain_code,
                xkey.key + index.to_bytes(4, byteorder="big", signed=False),
                "sha512",
            ).digest()
        else:  # normal derivation
            hmac_ = hmac.new(
                xkey.chain_code,
                Q_bytes + index.to_bytes(4, byteorder="big", signed=False),
                "sha512",
            ).digest()
        xkey.chain_code = hmac_[32:]
        offset = int.from_bytes(hmac_[:32], byteorder="big", signed=False)
        xkey.prv_key_int = (xkey.prv_key_int + offset) % ec.n
        xkey.key = b"\x00" + xkey.prv_key_int.to_bytes(
            32, byteorder="big", signed=False)
        xkey.pub_key_point = INF
    else:  # public key
        xkey.parent_fingerprint = hash160(xkey.key)[:4]
        if xkey.is_hardened():
            raise BTClibValueError(
                "invalid hardened derivation from public key")
        hmac_ = hmac.new(
            xkey.chain_code,
            xkey.key + index.to_bytes(4, byteorder="big", signed=False),
            "sha512",
        ).digest()
        xkey.chain_code = hmac_[32:]
        offset = int.from_bytes(hmac_[:32], byteorder="big", signed=False)
        xkey.pub_key_point = ec.add(xkey.pub_key_point, mult(offset))
        xkey.key = bytes_from_point(xkey.pub_key_point)
        xkey.prv_key_int = 0
Exemple #28
0
    def test_p2wsh(self):

        script_type = "p2wsh"

        # self-consistency
        pubkey = "02" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf"
        pubkey_hash = hash160(pubkey)
        redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash)
        payload = sha256(redeem_script)
        script = encode([0, payload])

        # straight to the scriptPubKey
        scriptPubKey = p2wsh(decode(redeem_script))
        self.assertEqual(scriptPubKey.hex(), script.hex())

        # to the scriptPubKey in two steps (through payload)
        scriptPubKey = scriptPubKey_from_payload(script_type, payload)
        self.assertEqual(scriptPubKey.hex(), script.hex())

        # back from the scriptPubKey to the payload
        script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey)
        self.assertEqual(script_type, script_type2)
        self.assertEqual(0, m2)
        self.assertEqual(payload.hex(), payload2.hex())
        script_type2, payload2, m2 = payload_from_scriptPubKey(script)
        self.assertEqual(script_type, script_type2)
        self.assertEqual(0, m2)
        self.assertEqual(payload.hex(), payload2.hex())

        # data -> payload is not invertible (hash functions)

        # bech32 address
        network = "mainnet"
        address = bech32address.p2wsh(redeem_script, network)
        address2 = address_from_scriptPubKey(scriptPubKey, network)
        self.assertEqual(address, address2)
        address2 = b32address_from_witness(0, payload, network)
        self.assertEqual(address, address2)

        scriptPubKey2, network2 = scriptPubKey_from_address(address)
        self.assertEqual(scriptPubKey2, scriptPubKey)
        self.assertEqual(network2, network)

        # p2sh-wrapped base58 address
        address = base58address.p2wsh_p2sh(redeem_script, network)
        address2 = b58address_from_witness(payload, network)
        self.assertEqual(address, address2)
def crack_prv_key(parent_xpub: BIP32Key, child_xprv: BIP32Key) -> str:

    if isinstance(parent_xpub, BIP32KeyData):
        p = copy.copy(parent_xpub)
    else:
        p = BIP32KeyData.b58decode(parent_xpub)

    if p.key[0] not in (2, 3):
        err_msg = "extended parent key is not a public key: "
        err_msg += f"{p.b58encode()}"
        raise BTClibValueError(err_msg)

    if isinstance(child_xprv, BIP32KeyData):
        c = child_xprv
    else:
        c = BIP32KeyData.b58decode(child_xprv)

    if c.key[0] != 0:
        err_msg = "extended child key is not a private key: "
        err_msg += f"{c.b58encode()}"
        raise BTClibValueError(err_msg)

    # check depth
    if c.depth != p.depth + 1:
        raise BTClibValueError("not a parent's child: wrong depths")

    # check fingerprint
    if c.parent_fingerprint != hash160(p.key)[:4]:
        raise BTClibValueError(
            "not a parent's child: wrong parent fingerprint")

    if c.is_hardened():
        raise BTClibValueError("hardened child derivation")

    p.version = c.version

    hmac_ = hmac.new(
        p.chain_code,
        p.key + c.index.to_bytes(4, byteorder="big", signed=False),
        "sha512",
    ).digest()
    child_q = int.from_bytes(c.key[1:], byteorder="big", signed=False)
    offset = int.from_bytes(hmac_[:32], byteorder="big", signed=False)
    parent_q = (child_q - offset) % ec.n
    p.key = b"\x00" + parent_q.to_bytes(32, byteorder="big", signed=False)

    return p.b58encode()
def test_p2pkh() -> None:

    # self-consistency
    pub_key = (
        "04 "
        "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf"
        "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4")
    payload = hash160(pub_key)
    script_pub_key = serialize(
        ["OP_DUP", "OP_HASH160", payload, "OP_EQUALVERIFY", "OP_CHECKSIG"])
    assert_p2pkh(script_pub_key)
    assert script_pub_key == ScriptPubKey.p2pkh(pub_key).script
    assert ("p2pkh", payload) == type_and_payload(script_pub_key)

    # base58 address
    network = "mainnet"
    addr = b58.p2pkh(pub_key, network)
    assert addr == address(script_pub_key, network)
    assert addr == b58.address_from_h160("p2pkh", payload, network)

    # back from the address to the script_pub_key
    assert script_pub_key == ScriptPubKey.from_address(addr).script
    assert network == ScriptPubKey.from_address(addr).network

    # documented test case: https://learnmeabitcoin.com/guide/p2pkh
    payload = bytes.fromhex("12ab8dc588ca9d5787dde7eb29569da63c3a238c")
    script_pub_key = bytes.fromhex("76a914") + payload + bytes.fromhex("88ac")
    assert_p2pkh(script_pub_key)
    addr = "12higDjoCCNXSA95xZMWUdPvXNmkAduhWv"
    assert addr == address(script_pub_key, network)
    assert script_pub_key == ScriptPubKey.from_address(addr).script
    assert network == ScriptPubKey.from_address(addr).network

    err_msg = "missing final OP_EQUALVERIFY, OP_CHECKSIG"
    with pytest.raises(BTClibValueError, match=err_msg):
        assert_p2pkh(script_pub_key[:-2] + b"\x40\x40")

    err_msg = "missing leading OP_DUP, OP_HASH160"
    with pytest.raises(BTClibValueError, match=err_msg):
        assert_p2pkh(b"\x40\x40" + script_pub_key[2:])

    err_msg = "invalid pub_key hash length marker: "
    with pytest.raises(BTClibValueError, match=err_msg):
        assert_p2pkh(script_pub_key[:2] + b"\x40" + script_pub_key[3:])