Esempio n. 1
0
    def test_octets2point(self):
        for ec in all_curves.values():
            Q = mult(ec.p, ec.G, ec)  # just a random point, not INF

            Q_bytes = b'\x03' if Q[1] & 1 else b'\x02'
            Q_bytes += Q[0].to_bytes(ec.psize, byteorder='big')
            R = point_from_octets(Q_bytes, ec)
            self.assertEqual(R, Q)
            self.assertEqual(bytes_from_point(R, ec), Q_bytes)

            Q_hex_str = Q_bytes.hex()
            R = point_from_octets(Q_hex_str, ec)
            self.assertEqual(R, Q)

            Q_bytes = b'\x04' + Q[0].to_bytes(ec.psize, byteorder='big')
            Q_bytes += Q[1].to_bytes(ec.psize, byteorder='big')
            R = point_from_octets(Q_bytes, ec)
            self.assertEqual(R, Q)
            self.assertEqual(bytes_from_point(R, ec, False), Q_bytes)

            Q_hex_str = Q_bytes.hex()
            R = point_from_octets(Q_hex_str, ec)
            self.assertEqual(R, Q)

            # scalar in point multiplication can be int, str, or bytes
            t = tuple()
            self.assertRaises(TypeError, mult, t, ec.G, ec)

            # not a compressed point
            Q_bytes = b'\x01' * (ec.psize + 1)
            self.assertRaises(ValueError, point_from_octets, Q_bytes, ec)
            # not a point
            Q_bytes += b'\x01'
            self.assertRaises(ValueError, point_from_octets, Q_bytes, ec)
            # not an uncompressed point
            Q_bytes = b'\x01' * 2 * (ec.psize + 1)
            self.assertRaises(ValueError, point_from_octets, Q_bytes, ec)

        # invalid x coordinate
        ec = CURVES['secp256k1']
        x = 0xEEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34
        xstr = format(x, '32X')
        self.assertRaises(ValueError, point_from_octets, "03" + xstr, ec)
        self.assertRaises(ValueError, point_from_octets, "04" + 2 * xstr, ec)
        self.assertRaises(ValueError, bytes_from_point, (x, x), ec)
        self.assertRaises(ValueError, bytes_from_point, (x, x), ec, False)

        # Point must be a tuple[int, int]
        P = x, x, x
        self.assertRaises(ValueError, ec.is_on_curve, P)

        # y-coordinate not in (0, p)
        P = x, ec.p + 1
        self.assertRaises(ValueError, ec.is_on_curve, P)
Esempio n. 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_p2wpkh() -> None:

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

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

    _, wp, _, _ = witness_from_b32address(addr)
    assert bytes(wp) == 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):
        p2wpkh(uncompr_pub)
    with pytest.raises(BTClibValueError, match=err_msg):
        p2wpkh(pub + "00")

    err_msg = "invalid witness program length for witness v0: "
    with pytest.raises(BTClibValueError, match=err_msg):
        b32address_from_witness(0, hash160(pub) + b"\x00")
Esempio n. 4
0
def test_forge_hash_sig() -> None:
    """forging valid hash signatures"""

    ec = CURVES["secp256k1"]

    # see https://twitter.com/pwuille/status/1063582706288586752
    # Satoshi's key
    key = "03 11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"
    Q = point_from_octets(key, ec)

    # pick u1 and u2 at will
    u1 = 1
    u2 = 2
    R = double_mult(u2, Q, u1, ec.G, ec)
    r = R[0] % ec.n
    u2inv = mod_inv(u2, ec.n)
    s = r * u2inv % ec.n
    e = s * u1 % ec.n
    dsa.__assert_as_valid(e, (Q[0], Q[1], 1), r, s, ec)

    # pick u1 and u2 at will
    u1 = 1234567890
    u2 = 987654321
    R = double_mult(u2, Q, u1, ec.G, ec)
    r = R[0] % ec.n
    u2inv = mod_inv(u2, ec.n)
    s = r * u2inv % ec.n
    e = s * u1 % ec.n
    dsa.__assert_as_valid(e, (Q[0], Q[1], 1), r, s, ec)
Esempio n. 5
0
    def test_forge_hash_sig(self):
        """forging valid hash signatures"""

        # see https://twitter.com/pwuille/status/1063582706288586752
        # Satoshi's key
        P = point_from_octets(
            "03 11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c",
            ec)

        u1 = 1
        u2 = 2  # pick them at will
        R = double_mult(u2, P, u1, ec.G, ec)
        r = R[0] % ec.n
        u2inv = mod_inv(u2, ec.n)
        s = r * u2inv % ec.n
        sig = r, s
        e = s * u1 % ec.n
        dsa._verhlp(e, (P[0], P[1], 1), r, s, ec)

        u1 = 1234567890
        u2 = 987654321  # pick them at will
        R = double_mult(u2, P, u1, ec.G, ec)
        r = R[0] % ec.n
        u2inv = mod_inv(u2, ec.n)
        s = r * u2inv % ec.n
        sig = r, s
        e = s * u1 % ec.n
        dsa._verhlp(e, (P[0], P[1], 1), r, s, ec)
Esempio n. 6
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')
Esempio n. 7
0
    def test_all_curves(self):
        for ec in all_curves.values():
            self.assertEqual(mult(0, ec.G, ec), INF)
            self.assertEqual(mult(0, ec.G, ec), INF)

            self.assertEqual(mult(1, ec.G, ec), ec.G)
            self.assertEqual(mult(1, ec.G, ec), ec.G)

            Gy_odd = ec.y_odd(ec.G[0], True)
            self.assertEqual(Gy_odd % 2, 1)
            Gy_even = ec.y_odd(ec.G[0], False)
            self.assertEqual(Gy_even % 2, 0)
            self.assertTrue(ec.G[1] in (Gy_odd, Gy_even))

            Gbytes = bytes_from_point(ec.G, ec)
            G2 = point_from_octets(Gbytes, ec)
            self.assertEqual(ec.G, G2)

            Gbytes = bytes_from_point(ec.G, ec, False)
            G2 = point_from_octets(Gbytes, ec)
            self.assertEqual(ec.G, G2)

            P = ec.add(INF, ec.G)
            self.assertEqual(P, ec.G)
            P = ec.add(ec.G, INF)
            self.assertEqual(P, ec.G)
            P = ec.add(INF, INF)
            self.assertEqual(P, INF)

            P = ec.add(ec.G, ec.G)
            self.assertEqual(P, mult(2, ec.G, ec))

            P = mult(ec.n - 1, ec.G, ec)
            self.assertEqual(ec.add(P, ec.G), INF)
            self.assertEqual(mult(ec.n, ec.G, ec), INF)

            self.assertEqual(mult(0, INF, ec), INF)
            self.assertEqual(mult(1, INF, ec), INF)
            self.assertEqual(mult(25, INF, ec), INF)

            ec_repr = repr(ec)
            if ec in low_card_curves.values() or ec.psize < 24:
                ec_repr = ec_repr[:-1] + ", False)"
            ec2 = eval(ec_repr)
            self.assertEqual(str(ec), str(ec2))
Esempio n. 8
0
def test_octets2point():
    for ec in all_curves.values():

        Gbytes = bytes_from_point(ec.G, ec)
        G2 = point_from_octets(Gbytes, ec)
        assert ec.G == G2

        Gbytes = bytes_from_point(ec.G, ec, False)
        G2 = point_from_octets(Gbytes, ec)
        assert ec.G == G2

        # just a random point, not INF
        q = 1 + secrets.randbelow(ec.n - 1)
        Q = _mult_aff(q, ec.G, ec)

        Q_bytes = b"\x03" if Q[1] & 1 else b"\x02"
        Q_bytes += Q[0].to_bytes(ec.psize, byteorder="big")
        R = point_from_octets(Q_bytes, ec)
        assert R == Q
        assert bytes_from_point(R, ec) == Q_bytes

        Q_hex_str = Q_bytes.hex()
        R = point_from_octets(Q_hex_str, ec)
        assert R == Q

        Q_bytes = b"\x04" + Q[0].to_bytes(ec.psize, byteorder="big")
        Q_bytes += Q[1].to_bytes(ec.psize, byteorder="big")
        R = point_from_octets(Q_bytes, ec)
        assert R == Q
        assert bytes_from_point(R, ec, False) == Q_bytes

        Q_hex_str = Q_bytes.hex()
        R = point_from_octets(Q_hex_str, ec)
        assert R == Q

        t = tuple()
        err_msg = "'<' not supported between instances of 'tuple' and 'int'"
        with pytest.raises(TypeError, match=err_msg):
            _mult_aff(t, ec.G, ec)

        Q_bytes = b"\x01" + b"\x01" * ec.psize
        with pytest.raises(ValueError, match="not a point: "):
            point_from_octets(Q_bytes, ec)

        Q_bytes = b"\x01" + b"\x01" * 2 * ec.psize
        with pytest.raises(ValueError, match="not a point: "):
            point_from_octets(Q_bytes, ec)

        Q_bytes = b"\x04" + b"\x01" * ec.psize
        with pytest.raises(ValueError,
                           match="invalid size for uncompressed point: "):
            point_from_octets(Q_bytes, ec)

        Q_bytes = b"\x02" + b"\x01" * 2 * ec.psize
        with pytest.raises(ValueError,
                           match="invalid size for compressed point: "):
            point_from_octets(Q_bytes, ec)

        Q_bytes = b"\x03" + b"\x01" * 2 * ec.psize
        with pytest.raises(ValueError,
                           match="invalid size for compressed point: "):
            point_from_octets(Q_bytes, ec)

    # invalid x_Q coordinate
    ec = CURVES["secp256k1"]
    x_Q = 0xEEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34
    xstr = format(x_Q, "32X")
    with pytest.raises(ValueError, match="invalid x-coordinate: "):
        point_from_octets("03" + xstr, ec)
    with pytest.raises(ValueError, match="point not on curve: "):
        point_from_octets("04" + 2 * xstr, ec)
    with pytest.raises(ValueError, match="point not on curve"):
        bytes_from_point((x_Q, x_Q), ec)
    with pytest.raises(ValueError, match="point not on curve"):
        bytes_from_point((x_Q, x_Q), ec, False)
Esempio n. 9
0
    def test_second_generator(self):
        """
        important remark on secp256-zkp prefix for compressed encoding of the second generator:
        https://github.com/garyyu/rust-secp256k1-zkp/wiki/Pedersen-Commitment
        """

        ec = secp256k1
        hf = sha256

        H = pedersen.second_generator(ec, hf)
        self.assertEqual(
            H,
            point_from_octets(
                "02 50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
                ec))

        # 0*G + 1*H
        T = double_mult(1, H, 0, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
                ec))

        # 0*G + 2*H
        T = double_mult(2, H, 0, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "03 fad265e0a0178418d006e247204bcf42edb6b92188074c9134704c8686eed37a",
                ec))
        T = mult(2, H, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "03 fad265e0a0178418d006e247204bcf42edb6b92188074c9134704c8686eed37a",
                ec))

        # 0*G + 3*H
        T = double_mult(3, H, 0, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 5ef47fcde840a435e831bbb711d466fc1ee160da3e15437c6c469a3a40daacaa",
                ec))
        T = mult(3, H, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 5ef47fcde840a435e831bbb711d466fc1ee160da3e15437c6c469a3a40daacaa",
                ec))

        # 1*G+0*H
        T = double_mult(0, H, 1, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
                ec))
        T = ec.G
        self.assertEqual(
            T,
            point_from_octets(
                "02 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
                ec))

        # 2*G+0*H
        T = double_mult(0, H, 2, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
                ec))
        T = mult(2, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
                ec))

        # 3*G+0*H
        T = double_mult(0, H, 3, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
                ec))
        T = mult(3, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
                ec))

        # 0*G+5*H
        T = double_mult(5, H, 0, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "03 9e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e",
                ec))
        T = mult(5, H, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "03 9e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e",
                ec))

        # 0*G-5*H
        T = double_mult(-5, H, 0, ec.G, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 9e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e",
                ec))
        T = mult(-5, H, ec)
        self.assertEqual(
            T,
            point_from_octets(
                "02 9e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e",
                ec))

        # 1*G-5*H
        U = double_mult(-5, H, 1, ec.G, ec)
        self.assertEqual(
            U,
            point_from_octets(
                "02 b218ddacb34d827c71760e601b41d309bc888cf7e3ab7cc09ec082b645f77e5a",
                ec))
        U = ec.add(ec.G, T)  # reusing previous T value
        self.assertEqual(
            U,
            point_from_octets(
                "02 b218ddacb34d827c71760e601b41d309bc888cf7e3ab7cc09ec082b645f77e5a",
                ec))

        H = pedersen.second_generator(secp256r1, hf)
        H = pedersen.second_generator(secp384r1, sha384)
Esempio n. 10
0
from btclib import base58wif, bip32, bip39, btcmsg, der, slip32
from btclib.secpoint import bytes_from_point, point_from_octets
from btclib.utils import bytes_from_octets

mnemonic = "token output grass below such awake census safe orphan device other meat"
passphrase = ""
seed = bip39.seed_from_mnemonic(mnemonic, passphrase)
rxprv = bip32.rootxprv_from_seed(seed)
rxpub = bip32.xpub_from_xprv(rxprv)
assert rxpub == b"xpub661MyMwAqRbcFzL26X6G7bySxgU1oV6GviUrNnhbeAS3ULQq35KEV6uSf1aJXEHjFYy6LXUPrYnfR9bSKWdFZ5VnYaEb3AbHPmXFVAoKKYT", rxpub

firmware_xprv = bip32.derive(rxprv, "m/0")
firmware_xpub = bip32.derive(rxpub, "m/0")
assert firmware_xpub == bip32.xpub_from_xprv(bip32.derive(rxprv, "m/0"))
firmware_pubkey = bip32.deserialize(firmware_xpub)['key']
assert bytes_from_point(point_from_octets(firmware_pubkey), False).hex(
) == "042374b3b6b06b65a3b831f857634ea135bf10b014d5bba0f935cb9eb26a4b6547ed3b37f277427a0ab23bda0ca79c5785dc54d2387fa3f295f4d5674d5b637de2"
assert bytes_from_point(point_from_octets(firmware_pubkey), True).hex(
) == "022374b3b6b06b65a3b831f857634ea135bf10b014d5bba0f935cb9eb26a4b6547"
firmware_wif = base58wif.wif_from_xprv(firmware_xprv)
firmware_address = slip32.address_from_xpub(firmware_xpub)

app_xprv = bip32.derive(rxprv, "m/1")
app_xpub = bip32.derive(rxpub, "m/1")
assert app_xpub == bip32.xpub_from_xprv(bip32.derive(rxprv, "m/1"))
app_pubkey = bip32.deserialize(app_xpub)['key']
assert bytes_from_point(point_from_octets(app_pubkey), False).hex(
) == "04ae3d0d5c669ed364636e79e72abc012a33be63e537babddf56bfd393256acf6dba0fac21da6386513674573a2d7baff4375c9b6d2498383853c52f0565f97f1a"
app_wif = base58wif.wif_from_xprv(app_xprv)
app_address = slip32.address_from_xpub(app_xpub)
assert app_address == b'1J6674MtZBpfHytdNofLUX6sLHAUaG33uK'