def test_point_from_bip340pubkey() -> None: q, x_Q = ssa.gen_keys() Q = mult(q) # Integer (int) assert ssa.point_from_bip340pubkey(x_Q) == Q # Integer (bytes) assert ssa.point_from_bip340pubkey(x_Q.to_bytes(32, byteorder="big")) == Q # Integer (hex-str) assert ssa.point_from_bip340pubkey( x_Q.to_bytes(32, byteorder="big").hex()) == Q # tuple Point assert ssa.point_from_bip340pubkey(Q) == Q # 33 bytes assert ssa.point_from_bip340pubkey(bytes_from_point(Q)) == Q # 33 bytes hex-string assert ssa.point_from_bip340pubkey(bytes_from_point(Q).hex()) == Q # 65 bytes assert ssa.point_from_bip340pubkey(bytes_from_point(Q, compressed=False)) == Q # 65 bytes hex-string assert ssa.point_from_bip340pubkey( bytes_from_point(Q, compressed=False).hex()) == Q xpub_data = BIP32KeyData.deserialize( "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" ) xpub_data.key = bytes_from_point(Q) # BIP32KeyData assert ssa.point_from_bip340pubkey(xpub_data) == Q # BIP32Key encoded str xpub = xpub_data.serialize() assert ssa.point_from_bip340pubkey(xpub) == Q # BIP32Key str assert ssa.point_from_bip340pubkey(xpub.decode("ascii")) == Q
def test_point_from_bip340pubkey() -> None: q, x_Q = ssa.gen_keys() P = mult(q) # Integer (int) assert ssa.point_from_bip340pubkey(x_Q) == P # Integer (bytes) assert ssa.point_from_bip340pubkey(x_Q.to_bytes(32, byteorder="big")) == P # Integer (hex-str) assert ssa.point_from_bip340pubkey( x_Q.to_bytes(32, byteorder="big").hex()) == P # tuple Point assert ssa.point_from_bip340pubkey(P) == P # 33 bytes assert ssa.point_from_bip340pubkey(bytes_from_point(P)) == P # 33 bytes hex-string assert ssa.point_from_bip340pubkey(bytes_from_point(P).hex()) == P # 65 bytes assert ssa.point_from_bip340pubkey(bytes_from_point(P, compressed=False)) == P # 65 bytes hex-string assert ssa.point_from_bip340pubkey( bytes_from_point(P, compressed=False).hex()) == P xpub_dict = bip32.deserialize( "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" ) xpub_dict["key"] = bytes_from_point(P) # BIP32KeyDict assert ssa.point_from_bip340pubkey(xpub_dict) == P # BIP32Key encoded str xpub = bip32.serialize(xpub_dict) assert ssa.point_from_bip340pubkey(xpub) == P # BIP32Key str assert ssa.point_from_bip340pubkey(xpub.decode()) == P
def test_key_deployment(self): """GEC 2: Test Vectors for SEC 1, section 4.1 http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf """ # 4.1.1 # ec = secp160r1 # hf = sha1 # 4.1.2 dU = 971761939728640320549601132085879836204587084162 self.assertEqual(format(dU, str(ec.psize) + 'x'), 'aa374ffc3ce144e6b073307972cb6d57b2a4e982') QU = mult(dU, ec.G, ec) self.assertEqual(QU, (466448783855397898016055842232266600516272889280, 1110706324081757720403272427311003102474457754220)) self.assertEqual( bytes_from_point(QU, True, ec).hex(), '0251b4496fecc406ed0e75a24a3c03206251419dc0') # 4.1.3 dV = 399525573676508631577122671218044116107572676710 self.assertEqual(format(dV, str(ec.psize) + 'x'), '45fb58a92a17ad4b15101c66e74f277e2b460866') QV = mult(dV, ec.G, ec) self.assertEqual(QV, (420773078745784176406965940076771545932416607676, 221937774842090227911893783570676792435918278531)) self.assertEqual( bytes_from_point(QV, True, ec).hex(), '0349b41e0e9c0369c2328739d90f63d56707c6e5bc') # expected results z_exp = 1155982782519895915997745984453282631351432623114 zstr = 'ca7c0f8c3ffa87a96e1b74ac8e6af594347bb40a' size = 20 keying_data_exp = '744ab703f5bc082e59185f6d049d2d367db245c2' # 4.1.4 z, _ = mult(dU, QV, ec) # x coordinate only self.assertEqual(z, z_exp) self.assertEqual(format(z, str(ec.psize) + 'x'), zstr) keyingdata = dh.ansi_x963_kdf(z.to_bytes(ec.psize, 'big'), size, ec, hf) self.assertEqual(keyingdata.hex(), keying_data_exp) # 4.1.5 z, _ = mult(dV, QU, ec) # x coordinate only self.assertEqual(z, z_exp) self.assertEqual(format(z, str(ec.psize) + 'x'), zstr) keyingdata = dh.ansi_x963_kdf(z.to_bytes(ec.psize, 'big'), size, ec, hf) self.assertEqual(keyingdata.hex(), keying_data_exp)
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)
def test_gec_2() -> None: """GEC 2: Test Vectors for SEC 1, section 4.1 http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf """ # 4.1.1 ec = CURVES["secp160r1"] hf = sha1 # 4.1.2 dU = 971761939728640320549601132085879836204587084162 assert dU == 0xAA374FFC3CE144E6B073307972CB6D57B2A4E982 QU = mult(dU, ec.G, ec) assert QU == ( 466448783855397898016055842232266600516272889280, 1110706324081757720403272427311003102474457754220, ) assert ( bytes_from_point(QU, ec).hex() == "0251b4496fecc406ed0e75a24a3c03206251419dc0" ) # 4.1.3 dV = 399525573676508631577122671218044116107572676710 assert dV == 0x45FB58A92A17AD4B15101C66E74F277E2B460866 QV = mult(dV, ec.G, ec) assert QV == ( 420773078745784176406965940076771545932416607676, 221937774842090227911893783570676792435918278531, ) assert ( bytes_from_point(QV, ec).hex() == "0349b41e0e9c0369c2328739d90f63d56707c6e5bc" ) # expected results z_exp = 1155982782519895915997745984453282631351432623114 assert z_exp == 0xCA7C0F8C3FFA87A96E1B74AC8E6AF594347BB40A size = 20 # 4.1.4 z, _ = mult(dU, QV, ec) # x coordinate only assert z == z_exp keyingdata = ansi_x9_63_kdf(z.to_bytes(ec.psize, "big"), size, hf, None) assert keyingdata.hex() == "744ab703f5bc082e59185f6d049d2d367db245c2" # 4.1.5 z, _ = mult(dV, QU, ec) # x coordinate only assert z == z_exp keyingdata = ansi_x9_63_kdf(z.to_bytes(ec.psize, "big"), size, hf, None) assert keyingdata.hex() == "744ab703f5bc082e59185f6d049d2d367db245c2"
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_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')
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")
def test_gec(self): """GEC 2: Test Vectors for SEC 1, section 2 http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf """ # 2.1.1 Scheme setup ec = secp160r1 hf = sha1 # 2.1.2 Key Deployment for U dU = 971761939728640320549601132085879836204587084162 self.assertEqual(format(dU, str(ec.psize) + 'x'), 'aa374ffc3ce144e6b073307972cb6d57b2a4e982') QU = mult(dU, ec.G, ec) self.assertEqual(QU, (466448783855397898016055842232266600516272889280, 1110706324081757720403272427311003102474457754220)) self.assertEqual( bytes_from_point(QU, True, ec).hex(), '0251b4496fecc406ed0e75a24a3c03206251419dc0') # 2.1.3 Signing Operation for U msg = b'abc' k = 702232148019446860144825009548118511996283736794 exp_sig = (0xCE2873E5BE449563391FEB47DDCBA2DC16379191, 0x3480EC1371A091A464B31CE47DF0CB8AA2D98B54) sig = dsa.sign(msg, dU, k, ec, hf) r, s = sig self.assertEqual(r, exp_sig[0]) self.assertIn(s, (exp_sig[1], ec.n - exp_sig[1])) # 2.1.4 Verifying Operation for V self.assertTrue(dsa.verify(msg, QU, sig, ec, hf))
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))
def test_invalid_schnorr(): sighash = bytes.fromhex("00" * 32) sig = ssa.serialize(*ssa._sign(sighash, 1)) pubkey = bytes_from_point(mult(1)) pubkey_hash = hash256(pubkey) script = Script([ [0x00, 0x00, pubkey], [0x01, 0x00, sig], [0x02, 0x00, pubkey_hash], # push pubkey_hash [0x03, 0x02, b"\x00"], # hash of pub key from unlocking script [0xFF, 0x01, b"\x03\x02"], # check equality [0xFF, 0x04, b"\xff"], # exit if not equal [0xFF, 0x03, b"\x00\x01"], # schnorr verify [0xFF, 0x04, b"\xff"], ] # exit if not equal]) # push signature ) assert script.execute(memory={0x100: sighash})
def test_gec() -> None: """GEC 2: Test Vectors for SEC 1, section 2 http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf """ # 2.1.1 Scheme setup ec = CURVES["secp160r1"] hf = sha1 # 2.1.2 Key Deployment for U dU = 971761939728640320549601132085879836204587084162 assert format(dU, str(ec.nsize) + "x") == "aa374ffc3ce144e6b073307972cb6d57b2a4e982" QU = mult(dU, ec.G, ec) assert QU == ( 466448783855397898016055842232266600516272889280, 1110706324081757720403272427311003102474457754220, ) assert (bytes_from_point( QU, ec).hex() == "0251b4496fecc406ed0e75a24a3c03206251419dc0") # 2.1.3 Signing Operation for U msg = b"abc" k = 702232148019446860144825009548118511996283736794 exp_sig = ( 0xCE2873E5BE449563391FEB47DDCBA2DC16379191, 0x3480EC1371A091A464B31CE47DF0CB8AA2D98B54, ) low_s = False sig = dsa._sign(reduce_to_hlen(msg, hf), dU, k, low_s, ec, hf) r, s = sig assert r == exp_sig[0] assert s == exp_sig[1] # 2.1.4 Verifying Operation for V assert dsa.verify(msg, QU, sig, ec, hf)
def test_pubkeyinfo_from_key(self): # prvkeys xprv = ( "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiC" "hkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").encode() xprv_str = xprv.decode("ascii") xprv_dict = bip32.deserialize(xprv) q, network, _ = _prvkeyinfo_from_xprv(xprv) ec = NETWORKS[network]["curve"] q_bytes = q.to_bytes(ec.nsize, "big") wif1 = wif_from_prvkey(q, network, True) wif2 = wif_from_prvkey(q, network, False) # pubkeys Q = mult(q, ec.G, ec) xpub = bip32.xpub_from_xprv(xprv) xpub_str = xpub.decode("ascii") xpub_dict = bip32.deserialize(xpub) Q_compr = xpub_dict["key"] Q_compr_hexstr = Q_compr.hex() Q_uncompr = bytes_from_point(Q, ec, False) Q_uncompr_hexstr = Q_uncompr.hex() # int prvkey, compressed result self.assertEqual(pubkeyinfo_from_key(q)[0], Q_compr) self.assertEqual(pubkeyinfo_from_key(q_bytes)[0], Q_compr) # int prvkey, uncompressed result self.assertEqual( pubkeyinfo_from_key(q, compressed=False)[0], Q_uncompr) self.assertEqual( pubkeyinfo_from_key(q_bytes, compressed=False)[0], Q_uncompr) # compressed wif prvkey, both results self.assertEqual(pubkeyinfo_from_key(wif1)[0], Q_compr) self.assertRaises(ValueError, pubkeyinfo_from_key, wif1, compressed=False) # uncompressed wif prvkey, both results self.assertRaises(ValueError, pubkeyinfo_from_key, wif2, compressed=True) self.assertEqual(pubkeyinfo_from_key(wif2)[0], Q_uncompr) # (compressed) BIP32 prvkey, compressed results self.assertEqual(pubkeyinfo_from_key(xprv)[0], Q_compr) self.assertEqual(pubkeyinfo_from_key(xprv_str)[0], Q_compr) self.assertEqual(pubkeyinfo_from_key(" " + xprv_str + " ")[0], Q_compr) self.assertEqual(pubkeyinfo_from_key(xprv_dict)[0], Q_compr) # (compressed) BIP32 prvkey, uncompressed result self.assertRaises(ValueError, pubkeyinfo_from_key, xprv, compressed=False) self.assertRaises(ValueError, pubkeyinfo_from_key, xprv_str, compressed=False) self.assertRaises(ValueError, pubkeyinfo_from_key, " " + xprv_str + " ", compressed=False) self.assertRaises(ValueError, pubkeyinfo_from_key, xprv_dict, compressed=False) # (compressed) BIP32 pubkey, compressed results self.assertEqual(pubkeyinfo_from_key(xpub)[0], Q_compr) self.assertEqual(pubkeyinfo_from_key(xpub_str)[0], Q_compr) self.assertEqual(pubkeyinfo_from_key(" " + xpub_str + " ")[0], Q_compr) self.assertEqual(pubkeyinfo_from_key(xpub_dict)[0], Q_compr) # (compressed) BIP32 pubkey, uncompressed result self.assertRaises(ValueError, pubkeyinfo_from_key, xpub, compressed=False) self.assertRaises(ValueError, pubkeyinfo_from_key, xpub_str, compressed=False) self.assertRaises(ValueError, pubkeyinfo_from_key, " " + xpub_str + " ", compressed=False) self.assertRaises(ValueError, pubkeyinfo_from_key, xpub_dict, compressed=False) # compressed SEC Octets (pubkey), compressed results self.assertEqual(pubkeyinfo_from_key(Q_compr)[0], Q_compr) self.assertEqual(pubkeyinfo_from_key(Q_compr_hexstr)[0], Q_compr) self.assertEqual( pubkeyinfo_from_key(" " + Q_compr_hexstr + " ")[0], Q_compr) # compressed SEC Octets (pubkey), uncompressed results self.assertRaises(ValueError, pubkeyinfo_from_key, Q_compr, compressed=False) self.assertRaises(ValueError, pubkeyinfo_from_key, Q_compr_hexstr, compressed=False) self.assertRaises( ValueError, pubkeyinfo_from_key, " " + Q_compr_hexstr + " ", compressed=False, ) self.assertRaises(ValueError, pubkeyinfo_from_key, b"\x00" + Q_compr) self.assertRaises(ValueError, pubkeyinfo_from_key, Q_compr_hexstr + "00") # uncompressed SEC Octets (pubkey), uncompressed results self.assertEqual(pubkeyinfo_from_key(Q_uncompr)[0], Q_uncompr) self.assertEqual(pubkeyinfo_from_key(Q_uncompr_hexstr)[0], Q_uncompr) self.assertEqual( pubkeyinfo_from_key(" " + Q_uncompr_hexstr + " ")[0], Q_uncompr) # uncompressed SEC Octets (pubkey), compressed results self.assertRaises(ValueError, pubkeyinfo_from_key, Q_uncompr, compressed=True) self.assertRaises(ValueError, pubkeyinfo_from_key, Q_uncompr_hexstr, compressed=True) self.assertRaises( ValueError, pubkeyinfo_from_key, " " + Q_uncompr_hexstr + " ", compressed=True, ) self.assertRaises(ValueError, pubkeyinfo_from_key, b"\x00" + Q_uncompr) self.assertRaises(ValueError, pubkeyinfo_from_key, Q_uncompr_hexstr + "00") # native tuple input, both results self.assertEqual(pubkeyinfo_from_key(Q)[0], Q_compr) self.assertEqual( pubkeyinfo_from_key(Q, compressed=False)[0], Q_uncompr) # pubkeyinfo_from_pubkey does not accept prvkey inputs self.assertRaises(TypeError, pubkeyinfo_from_pubkey, q) self.assertRaises(ValueError, pubkeyinfo_from_pubkey, q_bytes) self.assertRaises(ValueError, pubkeyinfo_from_pubkey, xprv) self.assertRaises(ValueError, pubkeyinfo_from_pubkey, xprv_str) self.assertRaises(ValueError, pubkeyinfo_from_pubkey, xprv_dict) self.assertRaises(ValueError, pubkeyinfo_from_pubkey, wif1) self.assertRaises(ValueError, pubkeyinfo_from_pubkey, wif2) # Not a public key: xpub_dict_bad = copy.copy(xpub_dict) xpub_dict_bad["key"] = b"\x00" + xpub_dict["key"][1:] self.assertRaises(ValueError, _pubkeyinfo_from_xpub, xpub_dict_bad) # _pubkeyinfo_from_xpub(xpub_dict_bad) # Invalid point: 7 is not a field element Q = INF self.assertRaises(ValueError, pubkeyinfo_from_key, Q) Q_compr = b"\x02" + Q[0].to_bytes(ec.psize, "big") self.assertRaises(ValueError, pubkeyinfo_from_key, Q_compr) Q_uncompr = (b"\x04" + Q[0].to_bytes(ec.psize, "big") + Q[1].to_bytes(ec.psize, "big")) self.assertRaises(ValueError, pubkeyinfo_from_key, Q_uncompr) Q_compr_hexstr = Q_compr.hex() self.assertRaises(ValueError, pubkeyinfo_from_key, Q_compr_hexstr) Q_uncompr_hexstr = Q_uncompr.hex() self.assertRaises(ValueError, pubkeyinfo_from_key, Q_uncompr_hexstr) t = xpub_dict["version"] t += xpub_dict["depth"].to_bytes(1, "big") t += xpub_dict["parent_fingerprint"] t += xpub_dict["index"] t += xpub_dict["chain_code"] t += Q_compr xpub = b58encode(t, 78) self.assertRaises(ValueError, pubkeyinfo_from_key, xpub) xpub_str = xpub.decode("ascii") self.assertRaises(ValueError, pubkeyinfo_from_key, xpub_str)
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 pubkey in [Q] + plain_pub_keys: assert Q == point_from_pubkey(pubkey) with pytest.raises(BTClibValueError): point_from_pubkey(pubkey, secp256r1) assert m_c == pubkeyinfo_from_pubkey(pubkey) assert m_c == pubkeyinfo_from_pubkey(pubkey, "mainnet") assert m_c == pubkeyinfo_from_pubkey(pubkey, "mainnet", compressed=True) assert m_c == pubkeyinfo_from_pubkey(pubkey, compressed=True) assert m_unc == pubkeyinfo_from_pubkey(pubkey, "mainnet", compressed=False) assert m_unc == pubkeyinfo_from_pubkey(pubkey, compressed=False) assert t_c == pubkeyinfo_from_pubkey(pubkey, "testnet") assert t_c == pubkeyinfo_from_pubkey(pubkey, "testnet", compressed=True) assert t_unc == pubkeyinfo_from_pubkey(pubkey, "testnet", compressed=False) for pubkey in [xpub_data] + compressed_pub_keys: assert Q == point_from_pubkey(pubkey) with pytest.raises(BTClibValueError): point_from_pubkey(pubkey, secp256r1) assert m_c == pubkeyinfo_from_pubkey(pubkey) assert m_c == pubkeyinfo_from_pubkey(pubkey, "mainnet") assert m_c == pubkeyinfo_from_pubkey(pubkey, "mainnet", compressed=True) assert m_c == pubkeyinfo_from_pubkey(pubkey, compressed=True) with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(pubkey, "mainnet", compressed=False) with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(pubkey, compressed=False) with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(pubkey, "testnet", compressed=False) for pubkey in uncompressed_pub_keys: assert Q == point_from_pubkey(pubkey) with pytest.raises(BTClibValueError): point_from_pubkey(pubkey, secp256r1) assert m_unc == pubkeyinfo_from_pubkey(pubkey) assert m_unc == pubkeyinfo_from_pubkey(pubkey, "mainnet") with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(pubkey, "mainnet", compressed=True) with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(pubkey, compressed=True) assert m_unc == pubkeyinfo_from_pubkey(pubkey, "mainnet", compressed=False) assert m_unc == pubkeyinfo_from_pubkey(pubkey, compressed=False) with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(pubkey, "testnet", compressed=True) for pubkey in [xpub_data] + net_aware_pub_keys: assert Q == point_from_pubkey(pubkey) with pytest.raises(BTClibValueError): point_from_pubkey(pubkey, secp256r1) assert pubkeyinfo_from_pubkey(pubkey) in (m_c, m_unc) assert pubkeyinfo_from_pubkey(pubkey, "mainnet") in (m_c, m_unc) with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(pubkey, "testnet") for pubkey in net_unaware_pub_keys: assert Q == point_from_pubkey(pubkey) with pytest.raises(BTClibValueError): point_from_pubkey(pubkey, secp256r1) assert pubkeyinfo_from_pubkey(pubkey) in (m_c, m_unc) assert pubkeyinfo_from_pubkey(pubkey, "mainnet") in (m_c, m_unc) assert pubkeyinfo_from_pubkey(pubkey, "testnet") in (t_c, t_unc) for invalid_pub_key in [INF, INF_xpub_data] + invalid_pub_keys: with pytest.raises(BTClibValueError): point_from_pubkey(invalid_pub_key) with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(invalid_pub_key) 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_pubkey(not_a_pub_key) with pytest.raises(BTClibValueError): pubkeyinfo_from_pubkey(not_a_pub_key) for key in [Q] + plain_pub_keys + [q] + plain_prv_keys: assert Q == point_from_key(key) assert m_c == pubkeyinfo_from_key(key) assert m_c == pubkeyinfo_from_key(key, "mainnet") assert m_c == pubkeyinfo_from_key(key, "mainnet", compressed=True) assert m_c == pubkeyinfo_from_key(key, compressed=True) assert m_unc == pubkeyinfo_from_key(key, "mainnet", compressed=False) assert m_unc == pubkeyinfo_from_key(key, compressed=False) assert t_c == pubkeyinfo_from_key(key, "testnet") assert t_c == pubkeyinfo_from_key(key, "testnet", compressed=True) assert t_unc == pubkeyinfo_from_key(key, "testnet", compressed=False) for key in compressed_pub_keys + [xpub_data, xprv_data ] + compressed_prv_keys: assert Q == point_from_key(key) with pytest.raises(BTClibValueError): point_from_key(key, secp256r1) assert m_c == pubkeyinfo_from_key(key) assert m_c == pubkeyinfo_from_key(key, "mainnet") assert m_c == pubkeyinfo_from_key(key, "mainnet", compressed=True) assert m_c == pubkeyinfo_from_key(key, compressed=True) with pytest.raises(BTClibValueError): pubkeyinfo_from_key(key, "mainnet", compressed=False) with pytest.raises(BTClibValueError): pubkeyinfo_from_key(key, compressed=False) for key in uncompressed_pub_keys + uncompressed_prv_keys: assert Q == point_from_key(key) with pytest.raises(BTClibValueError): point_from_key(key, secp256r1) assert m_unc == pubkeyinfo_from_key(key) assert m_unc == pubkeyinfo_from_key(key, "mainnet") with pytest.raises(BTClibValueError): pubkeyinfo_from_key(key, "mainnet", compressed=True) with pytest.raises(BTClibValueError): pubkeyinfo_from_key(key, compressed=True) assert m_unc == pubkeyinfo_from_key(key, "mainnet", compressed=False) assert m_unc == pubkeyinfo_from_key(key, compressed=False) for key in net_aware_pub_keys + [xpub_data, xprv_data ] + net_aware_prv_keys: assert Q == point_from_key(key) with pytest.raises(BTClibValueError): point_from_key(key, secp256r1) assert pubkeyinfo_from_key(key) in (m_c, m_unc) assert pubkeyinfo_from_key(key, "mainnet") in (m_c, m_unc) with pytest.raises(BTClibValueError): pubkeyinfo_from_key(key, "testnet") for key in [q] + net_unaware_prv_keys + net_unaware_pub_keys: assert Q == point_from_key(key) assert pubkeyinfo_from_key(key) in (m_c, m_unc) assert pubkeyinfo_from_key(key, "mainnet") in (m_c, m_unc) assert pubkeyinfo_from_key(key, "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) with pytest.raises(BTClibValueError): pubkeyinfo_from_key(invalid_key) 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) with pytest.raises(BTClibValueError): pubkeyinfo_from_key(not_a_key)
def test_point_from_key(self): # prvkeys xprv = b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" xprv_str = xprv.decode('ascii') xprv_dict = bip32.deserialize(xprv) q, network, _ = _prvkey_info_from_xprv(xprv) ec = curve_from_network(network) q_bytes = q.to_bytes(ec.psize, 'big') wif1 = wif_from_prvkey(q, network, True) wif2 = wif_from_prvkey(q, network, False) # pubkeys Q = mult(q, ec.G, ec) xpub = bip32.xpub_from_xprv(xprv) xpub_str = xpub.decode('ascii') xpub_dict = bip32.deserialize(xpub) Q_compr = xpub_dict['key'] Q_compr_hexstr = Q_compr.hex() Q_uncompr = bytes_from_point(Q, ec, False) Q_uncompr_hexstr = Q_uncompr.hex() # int prvkey self.assertEqual(point_from_key(q, ec), Q) self.assertEqual(point_from_key(q_bytes, ec), Q) # wif prvkey self.assertEqual(point_from_key(wif1, ec), Q) self.assertEqual(point_from_key(wif2, ec), Q) # BIP32 prvkey self.assertEqual(point_from_key(xprv, ec), Q) self.assertEqual(point_from_key(xprv_str, ec), Q) self.assertEqual(point_from_key(' ' + xprv_str + ' ', ec), Q) self.assertEqual(point_from_key(xprv_dict, ec), Q) # BIP32 pubkey self.assertEqual(point_from_key(xpub, ec), Q) self.assertEqual(point_from_key(xpub_str, ec), Q) self.assertEqual(point_from_key(' ' + xpub_str + ' ', ec), Q) self.assertEqual(point_from_key(xpub_dict, ec), Q) # compressed SEC Octets (bytes or hex-string, with 02 or 03 prefix) self.assertEqual(point_from_key(Q_compr, ec), Q) self.assertRaises(ValueError, point_from_key, b'\x00' + Q_compr, ec) self.assertEqual(point_from_key(Q_compr_hexstr, ec), Q) self.assertEqual(point_from_key(' ' + Q_compr_hexstr + ' ', ec), Q) self.assertRaises(ValueError, point_from_key, Q_compr_hexstr + '00', ec) # uncompressed SEC Octets (bytes or hex-string, with 04 prefix) self.assertEqual(point_from_key(Q_uncompr, ec), Q) self.assertRaises(ValueError, point_from_key, b'\x00' + Q_uncompr, ec) self.assertEqual(point_from_key(Q_uncompr_hexstr, ec), Q) self.assertEqual(point_from_key( ' ' + Q_uncompr_hexstr + ' ', ec), Q) self.assertRaises(ValueError, point_from_key, Q_uncompr_hexstr + '00', ec) # native tuple self.assertEqual(point_from_key(Q, ec), Q) # Invalid point: 7 is not a field element Q = INF self.assertRaises(ValueError, point_from_key, Q, ec) Q_compr = b'\x02' + Q[0].to_bytes(ec.psize, 'big') self.assertRaises(ValueError, point_from_key, Q_compr, ec) Q_uncompr = b'\x04' + \ Q[0].to_bytes(ec.psize, 'big') + Q[1].to_bytes(ec.psize, 'big') self.assertRaises(ValueError, point_from_key, Q_uncompr, ec) Q_compr_hexstr = Q_compr.hex() self.assertRaises(ValueError, point_from_key, Q_compr_hexstr, ec) Q_uncompr_hexstr = Q_uncompr.hex() self.assertRaises(ValueError, point_from_key, Q_uncompr_hexstr, ec) t = xpub_dict['version'] t += xpub_dict['depth'].to_bytes(1, 'big') t += xpub_dict['parent_fingerprint'] t += xpub_dict['index'] t += xpub_dict['chain_code'] t += Q_compr xpub = b58encode(t) self.assertRaises(ValueError, point_from_key, xpub, ec) xpub_str = xpub.decode('ascii') self.assertRaises(ValueError, point_from_key, xpub_str, ec) # pubkey input self.assertRaises(ValueError, point_from_pubkey, xprv, ec) self.assertRaises(ValueError, point_from_pubkey, xprv_dict, ec)
def test_bytes_from_key(self): # prvkeys xprv = b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" xprv_str = xprv.decode('ascii') xprv_dict = bip32.deserialize(xprv) q, network, _ = _prvkey_info_from_xprv(xprv) ec = curve_from_network(network) q_bytes = q.to_bytes(ec.psize, 'big') wif1 = wif_from_prvkey(q, network, True) wif2 = wif_from_prvkey(q, network, False) # pubkeys Q = mult(q, ec.G, ec) xpub = bip32.xpub_from_xprv(xprv) xpub_str = xpub.decode('ascii') xpub_dict = bip32.deserialize(xpub) Q_compr = xpub_dict['key'] Q_compr_hexstr = Q_compr.hex() Q_uncompr = bytes_from_point(Q, ec, False) Q_uncompr_hexstr = Q_uncompr.hex() # int prvkey, compressed result self.assertEqual(bytes_from_key(q)[0], Q_compr) self.assertEqual(bytes_from_key(q_bytes)[0], Q_compr) # int prvkey, uncompressed result self.assertEqual(bytes_from_key(q, compressed=False)[0], Q_uncompr) self.assertEqual(bytes_from_key( q_bytes, compressed=False)[0], Q_uncompr) # compressed wif prvkey, both results self.assertEqual(bytes_from_key(wif1)[0], Q_compr) self.assertRaises(ValueError, bytes_from_key, wif1, compressed=False) # uncompressed wif prvkey, both results self.assertRaises(ValueError, bytes_from_key, wif2, compressed=True) self.assertEqual(bytes_from_key(wif2)[0], Q_uncompr) # (compressed) BIP32 prvkey, compressed results self.assertEqual(bytes_from_key(xprv)[0], Q_compr) self.assertEqual(bytes_from_key(xprv_str)[0], Q_compr) self.assertEqual(bytes_from_key(' ' + xprv_str + ' ')[0], Q_compr) self.assertEqual(bytes_from_key(xprv_dict)[0], Q_compr) # (compressed) BIP32 prvkey, uncompressed result self.assertRaises(ValueError, bytes_from_key, xprv, compressed=False) self.assertRaises(ValueError, bytes_from_key, xprv_str, compressed=False) self.assertRaises(ValueError, bytes_from_key, ' ' + xprv_str + ' ', compressed=False) self.assertRaises(ValueError, bytes_from_key, xprv_dict, compressed=False) # (compressed) BIP32 pubkey, compressed results self.assertEqual(bytes_from_key(xpub)[0], Q_compr) self.assertEqual(bytes_from_key(xpub_str)[0], Q_compr) self.assertEqual(bytes_from_key(' ' + xpub_str + ' ')[0], Q_compr) self.assertEqual(bytes_from_key(xpub_dict)[0], Q_compr) # (compressed) BIP32 pubkey, uncompressed result self.assertRaises(ValueError, bytes_from_key, xpub, compressed=False) self.assertRaises(ValueError, bytes_from_key, xpub_str, compressed=False) self.assertRaises(ValueError, bytes_from_key, ' ' + xpub_str + ' ', compressed=False) self.assertRaises(ValueError, bytes_from_key, xpub_dict, compressed=False) # compressed SEC Octets (pubkey), compressed results self.assertEqual(bytes_from_key(Q_compr)[0], Q_compr) self.assertEqual(bytes_from_key(Q_compr_hexstr)[0], Q_compr) self.assertEqual(bytes_from_key( ' ' + Q_compr_hexstr + ' ')[0], Q_compr) # compressed SEC Octets (pubkey), uncompressed results self.assertRaises(ValueError, bytes_from_key, Q_compr, compressed=False) self.assertRaises(ValueError, bytes_from_key, Q_compr_hexstr, compressed=False) self.assertRaises(ValueError, bytes_from_key, ' ' + Q_compr_hexstr + ' ', compressed=False) self.assertRaises(ValueError, bytes_from_key, b'\x00' + Q_compr) self.assertRaises(ValueError, bytes_from_key, Q_compr_hexstr + '00') # uncompressed SEC Octets (pubkey), uncompressed results self.assertEqual(bytes_from_key(Q_uncompr)[0], Q_uncompr) self.assertEqual(bytes_from_key(Q_uncompr_hexstr)[0], Q_uncompr) self.assertEqual(bytes_from_key( ' ' + Q_uncompr_hexstr + ' ')[0], Q_uncompr) # uncompressed SEC Octets (pubkey), compressed results self.assertRaises(ValueError, bytes_from_key, Q_uncompr, compressed=True) self.assertRaises(ValueError, bytes_from_key, Q_uncompr_hexstr, compressed=True) self.assertRaises(ValueError, bytes_from_key, ' ' + Q_uncompr_hexstr + ' ', compressed=True) self.assertRaises(ValueError, bytes_from_key, b'\x00' + Q_uncompr) self.assertRaises(ValueError, bytes_from_key, Q_uncompr_hexstr + '00') # native tuple input, both results self.assertEqual(bytes_from_key(Q)[0], Q_compr) self.assertEqual(bytes_from_key(Q, compressed=False)[0], Q_uncompr) # bytes_from_pubkey does not accept prvkey inputs self.assertRaises(TypeError, bytes_from_pubkey, q) self.assertRaises(ValueError, bytes_from_pubkey, q_bytes) self.assertRaises(ValueError, bytes_from_pubkey, xprv) self.assertRaises(ValueError, bytes_from_pubkey, xprv_str) self.assertRaises(ValueError, bytes_from_pubkey, xprv_dict) self.assertRaises(ValueError, bytes_from_pubkey, wif1) self.assertRaises(ValueError, bytes_from_pubkey, wif2) # Not a public key: xpub_dict_bad = copy.copy(xpub_dict) xpub_dict_bad['key'] = b'\x00' + xpub_dict['key'][1:] self.assertRaises(ValueError, _bytes_from_xpub, xpub_dict_bad) # _bytes_from_xpub(xpub_dict_bad) # Invalid point: 7 is not a field element Q = INF self.assertRaises(ValueError, bytes_from_key, Q) Q_compr = b'\x02' + Q[0].to_bytes(ec.psize, 'big') self.assertRaises(ValueError, bytes_from_key, Q_compr) Q_uncompr = b'\x04' + \ Q[0].to_bytes(ec.psize, 'big') + Q[1].to_bytes(ec.psize, 'big') self.assertRaises(ValueError, bytes_from_key, Q_uncompr) Q_compr_hexstr = Q_compr.hex() self.assertRaises(ValueError, bytes_from_key, Q_compr_hexstr) Q_uncompr_hexstr = Q_uncompr.hex() self.assertRaises(ValueError, bytes_from_key, Q_uncompr_hexstr) t = xpub_dict['version'] t += xpub_dict['depth'].to_bytes(1, 'big') t += xpub_dict['parent_fingerprint'] t += xpub_dict['index'] t += xpub_dict['chain_code'] t += Q_compr xpub = b58encode(t) self.assertRaises(ValueError, bytes_from_key, xpub) xpub_str = xpub.decode('ascii') self.assertRaises(ValueError, bytes_from_key, xpub_str)
def unlock_p2pkh(sighash, prvkey): sig = ssa.serialize(*ssa._sign(sighash, prvkey)) pubkey = bytes_from_point(mult(prvkey)) return Script( [[0x00, OP_PUSHDATA, pubkey], [0x01, OP_PUSHDATA, sig]] ) # push signature
def pubkey_hash_from_prvkey(prvkey): pubkey = bytes_from_point(mult(prvkey)) pubkey_hash = hash256(pubkey) return pubkey_hash.hex()
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)
def test_point_from_key(self): # prvkeys xprv = ( "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiC" "hkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").encode() xprv_str = xprv.decode("ascii") xprv_dict = bip32.deserialize(xprv) q, network, _ = _prvkeyinfo_from_xprv(xprv) ec = NETWORKS[network]["curve"] q_bytes = q.to_bytes(ec.nsize, "big") wif1 = wif_from_prvkey(q, network, True) wif2 = wif_from_prvkey(q, network, False) # pubkeys Q = mult(q, ec.G, ec) xpub = bip32.xpub_from_xprv(xprv) xpub_str = xpub.decode("ascii") xpub_dict = bip32.deserialize(xpub) Q_compr = xpub_dict["key"] Q_compr_hexstr = Q_compr.hex() Q_uncompr = bytes_from_point(Q, ec, False) Q_uncompr_hexstr = Q_uncompr.hex() # int prvkey self.assertEqual(point_from_key(q, ec), Q) self.assertEqual(point_from_key(q_bytes, ec), Q) # wif prvkey self.assertEqual(point_from_key(wif1, ec), Q) self.assertEqual(point_from_key(wif2, ec), Q) # BIP32 prvkey self.assertEqual(point_from_key(xprv, ec), Q) self.assertEqual(point_from_key(xprv_str, ec), Q) self.assertEqual(point_from_key(" " + xprv_str + " ", ec), Q) self.assertEqual(point_from_key(xprv_dict, ec), Q) # BIP32 pubkey self.assertEqual(point_from_key(xpub, ec), Q) self.assertEqual(point_from_key(xpub_str, ec), Q) self.assertEqual(point_from_key(" " + xpub_str + " ", ec), Q) self.assertEqual(point_from_key(xpub_dict, ec), Q) # compressed SEC Octets (bytes or hex-string, with 02 or 03 prefix) self.assertEqual(point_from_key(Q_compr, ec), Q) self.assertRaises(ValueError, point_from_key, b"\x00" + Q_compr, ec) self.assertEqual(point_from_key(Q_compr_hexstr, ec), Q) self.assertEqual(point_from_key(" " + Q_compr_hexstr + " ", ec), Q) self.assertRaises(ValueError, point_from_key, Q_compr_hexstr + "00", ec) # uncompressed SEC Octets (bytes or hex-string, with 04 prefix) self.assertEqual(point_from_key(Q_uncompr, ec), Q) self.assertRaises(ValueError, point_from_key, b"\x00" + Q_uncompr, ec) self.assertEqual(point_from_key(Q_uncompr_hexstr, ec), Q) self.assertEqual(point_from_key(" " + Q_uncompr_hexstr + " ", ec), Q) self.assertRaises(ValueError, point_from_key, Q_uncompr_hexstr + "00", ec) # native tuple self.assertEqual(point_from_key(Q, ec), Q) # Invalid point: 7 is not a field element Q = INF self.assertRaises(ValueError, point_from_key, Q, ec) Q_compr = b"\x02" + Q[0].to_bytes(ec.psize, "big") self.assertRaises(ValueError, point_from_key, Q_compr, ec) Q_uncompr = (b"\x04" + Q[0].to_bytes(ec.psize, "big") + Q[1].to_bytes(ec.psize, "big")) self.assertRaises(ValueError, point_from_key, Q_uncompr, ec) Q_compr_hexstr = Q_compr.hex() self.assertRaises(ValueError, point_from_key, Q_compr_hexstr, ec) Q_uncompr_hexstr = Q_uncompr.hex() self.assertRaises(ValueError, point_from_key, Q_uncompr_hexstr, ec) t = xpub_dict["version"] t += xpub_dict["depth"].to_bytes(1, "big") t += xpub_dict["parent_fingerprint"] t += xpub_dict["index"] t += xpub_dict["chain_code"] t += Q_compr xpub = b58encode(t, 78) self.assertRaises(ValueError, point_from_key, xpub, ec) xpub_str = xpub.decode("ascii") self.assertRaises(ValueError, point_from_key, xpub_str, ec) # pubkey input self.assertRaises(ValueError, point_from_pubkey, xprv, ec) self.assertRaises(ValueError, point_from_pubkey, xprv_dict, ec)
def test_exceptions() -> None: # from creator example psbt_encoded = "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAAAAAA=" psbt = Psbt.decode(psbt_encoded) psbt.outputs[0].redeem_script = "bad script" # type: ignore with pytest.raises(BTClibValueError, match="invalid redeem script"): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.inputs[0].witness_script = "bad script" # type: ignore with pytest.raises(BTClibValueError, match="invalid witness script"): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.outputs[0].unknown = {"bad key": b""} # type: ignore with pytest.raises(BTClibValueError, match="invalid key in unknown"): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.outputs[0].unknown = {b"deadbeef": "bad value"} # type: ignore with pytest.raises(BTClibValueError, match="invalid value in unknown"): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.inputs[0].sighash = 101 with pytest.raises(BTClibValueError, match="invalid sighash: "): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.inputs[0].final_script_sig = "bad script" # type: ignore with pytest.raises(BTClibValueError, match="invalid final script_sig"): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.inputs[0].final_script_witness = "bad script" # type: ignore with pytest.raises(BTClibValueError, match="invalid final script witness"): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.inputs[0].final_script_witness = [b"", ""] # type: ignore with pytest.raises(BTClibValueError, match="invalid final script witness"): psbt.serialize() psbt = Psbt.decode(psbt_encoded) _, Q = dsa.gen_keys() pubkey = secpoint.bytes_from_point(Q) r = s = int.from_bytes(bytes.fromhex("FF" * 32), "big") sig_bytes = der._serialize_scalar(r) sig_bytes += der._serialize_scalar(s) sig_bytes = b"\x30" + len(sig_bytes).to_bytes(1, byteorder="big") + sig_bytes psbt.inputs[0].partial_signatures = {pubkey: sig_bytes} with pytest.raises(BTClibValueError, match="invalid partial signature: "): psbt.serialize() pubkey = bytes.fromhex("02" + 31 * "00" + "07") psbt.inputs[0].partial_signatures = {pubkey: sig_bytes} with pytest.raises(BTClibValueError, match="invalid partial signature pubkey: "): psbt.serialize() psbt = Psbt.decode(psbt_encoded) err_msg = "invalid version: " psbt.version = -1 with pytest.raises(BTClibValueError, match=err_msg): psbt.serialize() psbt.version = 0xFFFFFFFF + 1 with pytest.raises(BTClibValueError, match=err_msg): psbt.serialize() psbt.version = 1 # TODO: add to test vectors with pytest.raises(BTClibValueError, match="invalid non-zero version: "): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt_bin = psbt.serialize() psbt_bin = psbt_bin.replace(PSBT_SEPARATOR, PSBT_DELIMITER) # TODO: add to test vectors with pytest.raises(BTClibValueError, match="malformed psbt: missing separator"): Psbt.deserialize(psbt_bin) psbt = Psbt.decode(psbt_encoded) psbt.inputs.pop() err_msg = "mismatched number of tx.vin and psbt_in" # TODO: add to test vectors with pytest.raises(BTClibValueError, match=err_msg): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.tx.vin[0].txinwitness = [b""] err_msg = "non empty txinwitness" # TODO: add to test vectors with pytest.raises(BTClibValueError, match=err_msg): psbt.serialize() psbt = Psbt.decode(psbt_encoded) psbt.outputs.pop() err_msg = "mismatched number of tx.vout and psbt_out" # TODO: add to test vectors with pytest.raises(BTClibValueError, match=err_msg): psbt.serialize()
depth = b"\x00" # This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key) child_number = b"\x00\x00\x00\x00" # the fingerprint of the parent's public key (0x00000000 if master key) fingerprint = b"\x00\x00\x00\x00" idf = depth + fingerprint + child_number # master private key, master public key, chain code hd = hmac.digest(b"Bitcoin seed", seed.to_bytes(seed_bytes, byteorder="big"), "sha512") qbytes = hd[:32] q = int(qbytes.hex(), 16) % ec.n qbytes = b"\x00" + q.to_bytes(32, byteorder="big") Q = mult(q, ec.G) qbytes = b"\x00" + q.to_bytes(32, byteorder="big") Qbytes = bytes_from_point(Q) chain_code = hd[32:] # extended keys ext_prv = b58encode(xprv + idf + chain_code + qbytes) print("\nm") print(ext_prv) ext_pub = b58encode(xpub + idf + chain_code + Qbytes) print("M") print(ext_pub) assert ( ext_prv == b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" ), "failure" assert ( ext_pub ==
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'
def test_to_pub_bytes(self): xpub = b'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8' xpub_str = xpub.decode('ascii') xpub_dict = bip32.deserialize(xpub) P_compr = xpub_dict['key'] P_compr_hexstr = P_compr.hex() P = xpub_dict['Q'] P_uncompr = bytes_from_point(P, False, ec) P_uncompr_hexstr = P_uncompr.hex() # BIP32 input, compressed result self.assertEqual(to_pubkey_bytes(xpub, True, ec), P_compr) self.assertEqual(to_pubkey_bytes(xpub_str, True, ec), P_compr) self.assertEqual(to_pubkey_bytes(' ' + xpub_str + ' ', True, ec), P_compr) self.assertEqual(to_pubkey_bytes(xpub_dict, True, ec), P_compr) # compressed SEC Octets input, compressed result self.assertEqual(to_pubkey_bytes(P_compr, True, ec), P_compr) self.assertRaises(ValueError, to_pubkey_bytes, b'\x00' + P_compr, True, ec) self.assertEqual(to_pubkey_bytes(P_compr_hexstr, True, ec), P_compr) self.assertEqual(to_pubkey_bytes(' ' + P_compr_hexstr + ' ', True, ec), P_compr) self.assertRaises(ValueError, to_pubkey_bytes, P_compr_hexstr + '00', True, ec) # uncompressed SEC Octets input, compressed result self.assertRaises(ValueError, to_pubkey_bytes, P_uncompr, True, ec) self.assertRaises(ValueError, to_pubkey_bytes, P_uncompr_hexstr, True, ec) self.assertRaises(ValueError, to_pubkey_bytes, ' ' + P_uncompr_hexstr + ' ', True, ec) # native tuple input, compressed result self.assertEqual(to_pubkey_bytes(P, True, ec), P_compr) # BIP32 input, uncompressed result self.assertRaises(ValueError, to_pubkey_bytes, xpub, False, ec) self.assertRaises(ValueError, to_pubkey_bytes, xpub_str, False, ec) self.assertRaises(ValueError, to_pubkey_bytes, ' ' + xpub_str + ' ', False, ec) self.assertRaises(ValueError, to_pubkey_bytes, xpub_dict, False, ec) # compressed SEC Octets input, uncompressed result self.assertRaises(ValueError, to_pubkey_bytes, P_compr, False, ec) self.assertRaises(ValueError, to_pubkey_bytes, P_compr_hexstr, False, ec) self.assertRaises(ValueError, to_pubkey_bytes, ' ' + P_compr_hexstr + ' ', False, ec) # uncompressed SEC Octets input, uncompressed result self.assertEqual(to_pubkey_bytes(P_uncompr, False, ec), P_uncompr) self.assertRaises(ValueError, to_pubkey_bytes, b'\x00' + P_uncompr, False, ec) self.assertEqual(to_pubkey_bytes(P_uncompr_hexstr, False, ec), P_uncompr) self.assertEqual(to_pubkey_bytes(' ' + P_uncompr_hexstr + ' ', False, ec), P_uncompr) self.assertRaises(ValueError, to_pubkey_bytes, P_uncompr_hexstr + '00', False, ec) # native tuple input, uncompressed result self.assertEqual(to_pubkey_bytes(P, False, ec), P_uncompr) # pubkey input xprv = b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" self.assertRaises(ValueError, to_pubkey_bytes, xprv, True, ec) xprv_dict = bip32.deserialize(xprv) self.assertRaises(ValueError, to_pubkey_bytes, xprv_dict, True, ec) # Invalid point: 7 is not a field element P = INF self.assertRaises(ValueError, to_pubkey_bytes, P, True, ec) P_compr = b'\x02' + P[0].to_bytes(ec.psize, 'big') self.assertRaises(ValueError, to_pubkey_bytes, P_compr, True, ec) P_uncompr = b'\x04' + P[0].to_bytes(ec.psize, 'big') + P[1].to_bytes(ec.psize, 'big') self.assertRaises(ValueError, to_pubkey_bytes, P_uncompr, True, ec) P_compr_hexstr = P_compr.hex() self.assertRaises(ValueError, to_pubkey_bytes, P_compr_hexstr, True, ec) P_uncompr_hexstr = P_uncompr.hex() self.assertRaises(ValueError, to_pubkey_bytes, P_uncompr_hexstr, True, ec) t = xpub_dict['version'] t += xpub_dict['depth'].to_bytes(1, 'big') t += xpub_dict['parent_fingerprint'] t += xpub_dict['index'] t += xpub_dict['chain_code'] t += P_compr xpub = b58encode(t) self.assertRaises(ValueError, to_pubkey_bytes, xpub, True, ec) xpub_str = xpub.decode('ascii') self.assertRaises(ValueError, to_pubkey_bytes, xpub_str, True, ec)
def pubkey_from_prvkey(prvkey): pubkey = bytes_from_point(mult(prvkey)) return pubkey.hex()