diff --git a/tests/bip0039_fixtures.py b/tests/bip0039_fixtures.py new file mode 100644 index 0000000..d9440b5 --- /dev/null +++ b/tests/bip0039_fixtures.py @@ -0,0 +1,74 @@ +import pytest +import random + + +#@pytest.fixture +#def gen_entropy(bit_size): + #rnd = random.systemRandom(123456) + #return rnd.randint(0, 255) + +@pytest.fixture +def mnemonic_128(): + return ['nurse', 'fortune', 'immune', 'rapid', 'trash', + 'very', 'turkey', 'romance', 'short', 'clutch', 'hunt', 'wait'] + +@pytest.fixture +def mnemonic_160(): + return ['mail', 'paddle', 'wine', 'fox', 'various', 'absent', + 'manage', 'divert', 'awful', 'push', 'mystery', + 'mule', 'arrest', 'lawsuit', 'orient'] + +@pytest.fixture +def mnemonic_192(): + return ['craft', 'first', 'champion', 'border', 'rely', + 'dance', 'tag', 'voyage', 'category', 'orbit', + 'hungry', 'caught', 'occur', 'wonder', 'history', + 'jacket', 'first', 'plunge'] + +@pytest.fixture +def mnemonic_224(): + return ['liberty', 'family', 'lobster', 'omit', 'glide', + 'vague', 'market', 'cancel', 'exotic', 'jazz', + 'sausage', 'elite', 'tuition', 'grief', 'typical', + 'hobby', 'local', 'impact', 'leopard', 'basic', 'obscure'] + +@pytest.fixture +def mnemonic_256(): + return ['neck', 'adjust', 'town', 'ticket', 'sunset', 'pulse', + 'space', 'dolphin', 'farm', 'absent', 'cat', 'adult', + 'erupt', 'student', 'globe', 'tooth', 'tackle', 'group', + 'sponsor', 'dice', 'add', 'maid', 'illegal', 'major'] + +@pytest.fixture +def entropy_128(): + return b'\x97\x8bq\xc6\xd8\xfew\xe5\xfa\xad\xdc\xc6\xc5\x91\xbd\xfb' + +@pytest.fixture +def entropy_160(): + return b'\x863\xdb\xee./\x18\x01a\xb9\xfe\x10\xb5\xd6I\xc8\xa0\xc6\xfcg' + +@pytest.fixture +def entropy_192(): + return b'2\n\xec\x98\x0c\xebVn\xb7O\xb0$3}\xbd\x129\x8d\xfa\x1b\x0b\xb8Wt' + +@pytest.fixture +def entropy_224(): + return b'\x80\xeaR\x0c\xcd61\xe1b\t\tP\x0e\xee\xfe\xa4\x0e\xa2\xcd:\xfbb\x83N:\x01\t\x89' + +@pytest.fixture +def entropy_256(): + return b'\x93\xa0s\x99p\xdd\x99[4\x12\x06S \x14\x8f\x01\xe4\xcf\xae\xd8\xd7&\xdd\x0c\xdfI\x9e\xb03\x0c\x1cD' + + +@pytest.yield_fixture +def wordlist(): + f = None + def select_wordlist(filename): + nonlocal f + assert f is None + f = open(filename) + return f + yield select_wordlist + if f is not None: + f.close() + diff --git a/tests/test_bip0039.py b/tests/test_bip0039.py new file mode 100644 index 0000000..4ae3587 --- /dev/null +++ b/tests/test_bip0039.py @@ -0,0 +1,113 @@ +import os +import random +import hashlib +import hmac +from binascii import hexlify, unhexlify +from pybtc.hdwallet import * + + + +def test_recovery_from_passphrase_12(entropy_128, mnemonic_128): + passphrase = ' '.join(mnemonic_128) + entropy = mnemonic2bytes(passphrase, 'english') + assert entropy == entropy_128 + + +def test_recovery_from_passphrase_15(entropy_160, mnemonic_160): + passphrase = ' '.join(mnemonic_160) + entropy = mnemonic2bytes(passphrase, 'english') + assert entropy == entropy_160 + + +def test_recovery_from_passphrase_18(entropy_192, mnemonic_192): + passphrase = ' '.join(mnemonic_192) + entropy = mnemonic2bytes(passphrase, 'english') + assert entropy == entropy_192 + + +def test_recovery_from_passphrase_21(entropy_224, mnemonic_224): + passphrase = ' '.join(mnemonic_224) + entropy = mnemonic2bytes(passphrase, 'english') + assert entropy == entropy_224 + + +def test_recovery_from_passphrase_24(entropy_256, mnemonic_256): + passphrase = ' '.join(mnemonic_256) + entropy = mnemonic2bytes(passphrase, 'english') + assert entropy == entropy_256 + + +def test_create_mnemonic(entropy_128, entropy_160, entropy_192, entropy_224, entropy_256): + mnemonic = create_mnemonic(entropy_128, 'english') + assert len(mnemonic) == 12 + + mnemonic = create_mnemonic(entropy_160, 'english') + assert len(mnemonic) == 15 + + mnemonic = create_mnemonic(entropy_192, 'english') + assert len(mnemonic) == 18 + + mnemonic = create_mnemonic(entropy_224, 'english') + assert len(mnemonic) == 21 + + mnemonic = create_mnemonic(entropy_256, 'english') + assert len(mnemonic) == 24 + + +def test_create_wordlist(): + wordlist_en = create_wordlist('english') + wordlist_fr = create_wordlist('french') + wordlist_it = create_wordlist('italian') + wordlist_sp = create_wordlist('spanish') + assert 'abandon' in wordlist_en + assert 'abaisser' in wordlist_fr + assert 'abaco' in wordlist_it + assert 'ábaco' in wordlist_sp + + + +def test_create_passphrase(): + passphrase = create_passphrase(128, 'english') + assert len(passphrase.split()) == 12 + + passphrase = create_passphrase(160, 'english') + assert len(passphrase.split()) == 15 + + passphrase = create_passphrase(192, 'english') + assert len(passphrase.split()) == 18 + + passphrase = create_passphrase(224, 'english') + assert len(passphrase.split()) == 21 + + passphrase = create_passphrase(256, 'english') + assert len(passphrase.split()) == 24 + + +def test_add_checksum(entropy_128, entropy_160, entropy_192, entropy_224, entropy_256): + ent_add_chksum = add_checksum(entropy_128) + ent_hash = hashlib.sha256(entropy_128).hexdigest() + fb = unhexlify(ent_hash)[0] + assert (fb >> 4) & ent_add_chksum + + ent_add_chksum = add_checksum(entropy_160) + ent_hash = hashlib.sha256(entropy_160).hexdigest() + fb = unhexlify(ent_hash)[0] + assert (fb >> 3) & ent_add_chksum + + ent_add_chksum = add_checksum(entropy_192) + ent_hash = hashlib.sha256(entropy_192).hexdigest() + fb = unhexlify(ent_hash)[0] + assert (fb >> 2) & ent_add_chksum + + ent_add_chksum = add_checksum(entropy_224) + ent_hash = hashlib.sha256(entropy_224).hexdigest() + fb = unhexlify(ent_hash)[0] + assert (fb >> 1) & ent_add_chksum + + ent_add_chksum = add_checksum(entropy_256) + ent_hash = hashlib.sha256(entropy_256).hexdigest() + fb = unhexlify(ent_hash)[0] + assert fb & ent_add_chksum + + +