diff --git a/src/krux/bip39.py b/src/krux/bip39.py index 0fe2e9ea..c52a21b1 100644 --- a/src/krux/bip39.py +++ b/src/krux/bip39.py @@ -1,5 +1,5 @@ # Mnemonic convertion to seed and to/from bytes -#pylint: disable=W0102 +# pylint: disable=W0102 import hashlib from embit.wordlists.bip39 import WORDLIST @@ -7,9 +7,7 @@ WORDINDEX = {word: i for i, word in enumerate(WORDLIST)} -def mnemonic_to_bytes( - mnemonic: str, ignore_checksum: bool = False, wordlist=WORDLIST -): +def mnemonic_to_bytes(mnemonic: str, ignore_checksum: bool = False, wordlist=WORDLIST): """Verifies the mnemonic checksum and returns it in bytes""" words = mnemonic.strip().split() if len(words) % 3 != 0 or len(words) < 12: diff --git a/src/krux/wallet.py b/src/krux/wallet.py index 8ee075f6..92ebc609 100644 --- a/src/krux/wallet.py +++ b/src/krux/wallet.py @@ -462,7 +462,6 @@ def is_double_mnemonic(mnemonic: str): words = mnemonic.split(" ") if len(words) > 12: - from embit import bip39 from krux import bip39 as kruxbip39 # use an optimized version of mnemonic_to_bytes() via kruxbip39 @@ -471,12 +470,6 @@ def is_double_mnemonic(mnemonic: str): and kruxbip39.mnemonic_is_valid(" ".join(words[12:])) and kruxbip39.mnemonic_is_valid(mnemonic) ): - # verify the well-known/well-tested version from embit.bip39 - if ( - bip39.mnemonic_is_valid(" ".join(words[:12])) - and bip39.mnemonic_is_valid(" ".join(words[12:])) - and bip39.mnemonic_is_valid(mnemonic) - ): - return True + return True return False diff --git a/tests/test_bip39.py b/tests/test_bip39.py new file mode 100644 index 00000000..527c58e0 --- /dev/null +++ b/tests/test_bip39.py @@ -0,0 +1,56 @@ +from krux import bip39 as kruxbip39 +from embit import bip39 +from embit.wordlists.bip39 import WORDLIST +import secrets + + +def test_one_word_mnemonics(): + for word in WORDLIST: + mnemonic = (word + " ") * 12 + assert kruxbip39.mnemonic_is_valid(mnemonic) == bip39.mnemonic_is_valid( + mnemonic + ) + + for word in WORDLIST: + mnemonic = (word + " ") * 24 + assert kruxbip39.mnemonic_is_valid(mnemonic) == bip39.mnemonic_is_valid( + mnemonic + ) + + +def test_edge_cases(): + cases = [8, 16] # 12w and 24w + for case in cases: + ALL_ZERO_BYTES = int(0).to_bytes(16, "big") + ALL_ONE_BYTES = int.from_bytes(bytearray([255] * case)).to_bytes(16, "big") + + assert ( + kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(ALL_ZERO_BYTES)) + == ALL_ZERO_BYTES + ) + assert ( + kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(ALL_ONE_BYTES)) + == ALL_ONE_BYTES + ) + + int_val = max_val = int.from_bytes(ALL_ONE_BYTES) + while int_val > 0: + int_val = int_val // 2 + b = int_val.to_bytes(16, "big") + assert kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(b)) == b + + b = (max_val - int_val).to_bytes(16, "big") + assert kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(b)) == b + + +def test_random_cases(): + for _ in range(20000): + token12w = secrets.token_bytes(16) + token24w = secrets.token_bytes(32) + + assert ( + kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(token12w)) == token12w + ) + assert ( + kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(token24w)) == token24w + )