246 lines
9.4 KiB
Python
246 lines
9.4 KiB
Python
import binascii
|
|
from unittest import TestCase
|
|
|
|
import base58
|
|
|
|
from multimerchant.network import BitcoinMainNet
|
|
from multimerchant.network import BitcoinTestNet
|
|
from multimerchant.network import DogecoinMainNet
|
|
from multimerchant.network import LitecoinMainNet
|
|
from multimerchant.wallet.keys import ChecksumException
|
|
from multimerchant.wallet.keys import IncompatibleNetworkException
|
|
from multimerchant.wallet.keys import KeyParseError # TODO test this
|
|
from multimerchant.wallet.keys import PrivateKey
|
|
from multimerchant.wallet.keys import PublicKey
|
|
from multimerchant.wallet.utils import ensure_bytes
|
|
from multimerchant.wallet.utils import long_or_int
|
|
|
|
|
|
class _TestPrivateKeyBase(TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
# This private key chosen from the bitcoin docs:
|
|
# https://en.bitcoin.it/wiki/Wallet_import_format
|
|
cls.expected_key = \
|
|
b"0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d"
|
|
cls.key = PrivateKey(long_or_int(cls.expected_key, 16))
|
|
|
|
|
|
class _TestPublicKeyBase(TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
# This private key chosen from the bitcoin docs:
|
|
# https://en.bitcoin.it/wiki/Wallet_import_format
|
|
cls.expected_private_key = \
|
|
b"18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725"
|
|
cls.private_key = PrivateKey(
|
|
long_or_int(cls.expected_private_key, 16))
|
|
cls.public_key = PublicKey.from_hex_key(
|
|
"04"
|
|
"50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
|
|
"2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6")
|
|
|
|
|
|
class TestPrivateKey(_TestPrivateKeyBase):
|
|
def test_raw_key_hex(self):
|
|
exp = self.key._private_key.privkey.secret_multiplier
|
|
self.assertEqual(PrivateKey(exp), self.key)
|
|
|
|
def test_raw_key_hex_bytes(self):
|
|
key = binascii.unhexlify(self.key.get_key())
|
|
self.assertEqual(PrivateKey.from_hex_key(key), self.key)
|
|
|
|
def test_from_master_password(self):
|
|
password = "correct horse battery staple"
|
|
expected_wif = "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS"
|
|
expected_pub_address = "1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T"
|
|
|
|
key = PrivateKey.from_master_password(password)
|
|
self.assertEqual(key.export_to_wif(), expected_wif)
|
|
self.assertEqual(
|
|
key.get_public_key().to_address(), expected_pub_address)
|
|
|
|
def test_invalid_exponent(self):
|
|
self.assertRaises(ValueError, PrivateKey, 'abcd')
|
|
|
|
|
|
class TestWIF(_TestPrivateKeyBase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super(TestWIF, cls).setUpClass()
|
|
cls.expected_wif = \
|
|
'5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ'
|
|
|
|
def test_export_to_wif(self):
|
|
self.assertEqual(
|
|
self.key.export_to_wif(),
|
|
self.expected_wif)
|
|
|
|
def test_import_wif(self):
|
|
key = PrivateKey.from_wif(self.expected_wif)
|
|
self.assertEqual(key, self.key)
|
|
|
|
def test_import_wif_invalid_network(self):
|
|
self.assertRaises(
|
|
IncompatibleNetworkException, PrivateKey.from_wif,
|
|
self.key.export_to_wif(), BitcoinTestNet)
|
|
|
|
def test_import_wif_network(self):
|
|
# Make a wif for bitcoin testnet:
|
|
testnet_key = PrivateKey(
|
|
self.key._private_key.privkey.secret_multiplier,
|
|
network=BitcoinTestNet)
|
|
testnet_wif = testnet_key.export_to_wif()
|
|
# We should be able to load it properly
|
|
key = PrivateKey.from_wif(testnet_wif, BitcoinTestNet)
|
|
self.assertEqual(testnet_key, key)
|
|
|
|
def test_bad_checksum(self):
|
|
wif = self.key.export_to_wif()
|
|
bad_checksum = base58.b58encode(binascii.unhexlify('FFFFFFFF'))
|
|
wif = wif[:-8] + bad_checksum
|
|
self.assertRaises(ChecksumException, PrivateKey.from_wif, wif)
|
|
|
|
|
|
class TestPublicKey(_TestPublicKeyBase):
|
|
def test_leading_zeros(self):
|
|
"""This zero-leading x coordinate generated by:
|
|
|
|
pvk = '18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725' # nopep8
|
|
from ecdsa import SECP256k1
|
|
from ecdsa.ecdsa import Public_key
|
|
from multimerchant.wallet.utils import long_to_hex
|
|
|
|
pubkey = Public_key(
|
|
SECP256k1.generator,
|
|
SECP256k1.generator * long(pvk, 16))
|
|
for i in range(1, 10000):
|
|
p = pubkey.point * i
|
|
x = p.x()
|
|
k = long_to_hex(x, 64)
|
|
if k.startswith('0'):
|
|
print(i)
|
|
print(long_to_hex(p.x(), 64))
|
|
print(long_to_hex(p.y(), 64))
|
|
break
|
|
"""
|
|
expected_key = ensure_bytes(
|
|
"04"
|
|
"02cbfd5410fd04973c096a4275bf75070955ebd689f316a6fbd449980ba7b756"
|
|
"c559764e5c367c03e002751aaf4ef8ec40fe97cda9b2d3f14fdd4cd244e8fcd2")
|
|
public_key = PublicKey.from_hex_key(expected_key)
|
|
self.assertEqual(public_key.get_key(), expected_key)
|
|
|
|
def test_address(self):
|
|
expected_address = "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
|
|
actual_address = self.public_key.to_address()
|
|
self.assertEqual(expected_address, actual_address)
|
|
|
|
def test_private_to_public(self):
|
|
self.assertEqual(
|
|
self.private_key.get_public_key(),
|
|
self.public_key)
|
|
|
|
def test_unhexlified_key(self):
|
|
key_bytes = binascii.unhexlify(self.public_key.get_key())
|
|
self.assertEqual(
|
|
PublicKey.from_hex_key(key_bytes),
|
|
self.public_key)
|
|
|
|
def test_bad_key(self):
|
|
self.assertRaises(KeyParseError, PublicKey.from_hex_key, 'badkey')
|
|
|
|
def test_bad_network_key(self):
|
|
key = self.public_key.get_key()
|
|
# Change the network constant
|
|
key = b"00" + key[2:]
|
|
self.assertRaises(KeyParseError,
|
|
PublicKey.from_hex_key, key)
|
|
|
|
def test_compressed(self):
|
|
compressed_key = self.public_key.get_key(compressed=True)
|
|
self.assertEqual(len(compressed_key), 66)
|
|
self.assertEqual(
|
|
PublicKey.from_hex_key(compressed_key), self.public_key)
|
|
|
|
def test_point(self):
|
|
self.assertEqual(PublicKey.from_point(self.public_key.to_point()),
|
|
self.public_key)
|
|
|
|
def test_public_pair(self):
|
|
self.assertEqual(
|
|
PublicKey.from_public_pair(self.public_key.to_public_pair()),
|
|
self.public_key)
|
|
|
|
|
|
class TestVectors(TestCase):
|
|
"""Test vectors
|
|
from https://github.com/bitcoin/bitcoin/blob/master/src/test/key_tests.cpp
|
|
"""
|
|
def _test(self, network, secret, address, compressed):
|
|
key = PrivateKey.from_wif(secret, network=network)
|
|
self.assertEqual(key.compressed, compressed)
|
|
self.assertEqual(address, key.get_public_key().to_address())
|
|
|
|
def test_1(self):
|
|
secret = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"
|
|
address = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"
|
|
self._test(BitcoinMainNet, secret, address, False)
|
|
|
|
def test_2(self):
|
|
secret = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"
|
|
address = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"
|
|
self._test(BitcoinMainNet, secret, address, False)
|
|
|
|
def test_3(self):
|
|
secret = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"
|
|
address = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"
|
|
self._test(BitcoinMainNet, secret, address, True)
|
|
|
|
def test_4(self):
|
|
secret = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"
|
|
address = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"
|
|
self._test(BitcoinMainNet, secret, address, True)
|
|
|
|
# https://github.com/dogecoin/dogecoin/blob/master-1.5/src/test/key_tests.cpp # nopep8
|
|
def test_dogecoin_1(self):
|
|
secret = "6JFPe8b4jbpup7petSB98M8tcaqXCigji8fGrC8bEbbDQxQkQ68"
|
|
address = "DSpgzjPyfQB6ZzeSbMWpaZiTTxGf2oBCs4"
|
|
self._test(DogecoinMainNet, secret, address, False)
|
|
|
|
def test_dogecoin_2(self):
|
|
secret = "6KLE6U3w8x3rM7nA1ZQxR4KnyEzeirPEt4YaXWdY4roF7Tt96rq"
|
|
address = "DR9VqfbWgEHZhNst34KQnABQXpPWXeLAJD"
|
|
self._test(DogecoinMainNet, secret, address, False)
|
|
|
|
def test_dogecoin_3(self):
|
|
secret = "QP8WvtVMV2iU6y7LE27ksRspp4MAJizPWYovx88W71g1nfSdAhkV"
|
|
address = "D8jZ6R8uuyQwiybupiVs3eDCedKdZ5bYV3"
|
|
self._test(DogecoinMainNet, secret, address, True)
|
|
|
|
def test_dogecoin_4(self):
|
|
secret = "QTuro8Pwx5yaonvJmU4jbBfwuEmTViyAGNeNyfnG82o7HWJmnrLj"
|
|
address = "DP7rGcDbpAvMb1dKup981zNt1heWUuVLP7"
|
|
self._test(DogecoinMainNet, secret, address, True)
|
|
|
|
# https://github.com/litecoin-project/litecoin/blob/master-0.8/src/test/key_tests.cpp # nopep8
|
|
def test_litecoin_1(self):
|
|
secret = "6uu5bsZLA2Lm6yCxgwxDxHyZmhYeqBMLQT83Fyq738YhYucQPQf"
|
|
address = "LWaFezDtucfCA4xcVEfs3R3xfgGWjSwcZr"
|
|
self._test(LitecoinMainNet, secret, address, False)
|
|
|
|
def test_litecoin_2(self):
|
|
secret = "6vZDRwYgTNidWzmKs9x8QzQGeWCqbdUtNRpEKZMaP67ZSn8XMjb"
|
|
address = "LXwHM6mRd432EzLJYwuKQMPhTzrgr7ur9K"
|
|
self._test(LitecoinMainNet, secret, address, False)
|
|
|
|
def test_litecoin_3(self):
|
|
secret = "T6UsJv9hYpvDfM5noKYkB3vfeHxhyegkeWJ4y7qKeQJuyXMK11XX"
|
|
address = "LZWK8h7C166niP6GmpUmiGrvn4oxPqQgFV"
|
|
self._test(LitecoinMainNet, secret, address, True)
|
|
|
|
def test_litecoin_4(self):
|
|
secret = "T9PBs5kq9QrkBPxeGNWKitMi4XuFVr25jaXTnuopLVZxCUAJbixA"
|
|
address = "Lgb6tdqmdW3n5E12johSuEAqRMt4kAr7yu"
|
|
self._test(LitecoinMainNet, secret, address, True)
|