Skip to content

Commit

Permalink
Merge pull request #29 from jdlcdl/pr_432_tests
Browse files Browse the repository at this point in the history
Pr 432 tests and fixes from @jdlcdl !
  • Loading branch information
tadeubas authored Aug 14, 2024
2 parents add60f8 + 638965b commit 0284380
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/krux/bip39.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
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:
if len(words) % 3 != 0 or not 12 <= len(words) <= 24:
raise ValueError("Invalid recovery phrase")

accumulator = 0
Expand Down
80 changes: 55 additions & 25 deletions tests/test_bip39.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,23 @@
from embit import bip39
from embit.wordlists.bip39 import WORDLIST
import secrets
import pytest


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
)
for numwords in (12, 15, 18, 21, 24):
for word in WORDLIST:
mnemonic = (word + " ") * numwords
assert kruxbip39.mnemonic_is_valid(mnemonic) == bip39.mnemonic_is_valid(
mnemonic
)


def test_edge_cases():
cases = [8, 16] # 12w and 24w
cases = [16, 20, 24, 28, 32] # 12w, 15w, 18w, 21w 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")
ALL_ZERO_BYTES = b"\x00" * case
ALL_ONE_BYTES = b"\xff" * case

assert (
kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(ALL_ZERO_BYTES))
Expand All @@ -33,24 +29,58 @@ def test_edge_cases():
== ALL_ONE_BYTES
)

int_val = max_val = int.from_bytes(ALL_ONE_BYTES)
int_val = max_val = int.from_bytes(ALL_ONE_BYTES, "big")
while int_val > 0:
int_val = int_val // 2
b = int_val.to_bytes(16, "big")
b = int_val.to_bytes(case, "big")
assert kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(b)) == b

b = (max_val - int_val).to_bytes(16, "big")
b = (max_val - int_val).to_bytes(case, "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)
for size in (16, 20, 24, 28, 32):
token_bytes = secrets.token_bytes(size)
assert (
kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(token_bytes))
== token_bytes
)

assert (
kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(token12w)) == token12w
)
assert (
kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(token24w)) == token24w
)

def test_random_cases_custom_wordlist():
wordlist = tuple(kruxbip39.WORDLIST)
for _ in range(200):
for size in (16, 20, 24, 28, 32):
token_bytes = secrets.token_bytes(size)
assert (
kruxbip39.mnemonic_to_bytes(
bip39.mnemonic_from_bytes(token_bytes), wordlist=wordlist
)
== token_bytes
)


def test_invalid_words():
cases = [
"not all twelve of these words are in the english bip39 wordslist",
"not all fifteen of these words are in the english bip39 wordslist thirteen fourteen fifteen",
"not all eighteen of these words are in the english bip39 wordslist thirteen fourteen fifteen sixteen seventeen eighteen",
"not all twenty-one of these words are in the english bip39 wordslist thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twenty-one",
"not all twenty-four of these words are in the english bip39 wordslist thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twenty-one twenty-two twenty-three twenty-four",
]
for case in cases:
with pytest.raises(ValueError, match=" is not in the dictionary"):
kruxbip39.mnemonic_to_bytes(case)


def test_invalid_mnemonic_length():
cases = [
"nine is divisible by three but is not valid",
"thirteen is between twelve and twenty-four but it is not divisible by three",
"twenty-seven is divisible by three but it is not a mnemonic with valid length because bip39 support mnemonics of length twelve fifteen eighteen twenty-one and twenty-four only",
]
for case in cases:
with pytest.raises(ValueError, match="Invalid recovery phrase"):
kruxbip39.mnemonic_to_bytes(case)

0 comments on commit 0284380

Please sign in to comment.