inital commit, already did quite a few things.

This commit is contained in:
pablo 2021-12-28 12:31:58 +01:00
commit a3619df8cf
6 changed files with 2321 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,100 @@
from typing import List, Dict, Tuple
def get_words_from_file(file_path) -> Tuple[dict, dict]:
with open(file_path, "r") as words_file:
lines_contents = words_file.read().splitlines()
words = {index: word for index, word in enumerate(lines_contents)}
indexes = {word: index for index, word in enumerate(lines_contents)}
return words, indexes
WORDS, INDEXES = get_words_from_file("bip39-english-words.txt")
class MnemonicWord:
def __init__(self, word: str):
word = word.lstrip().rstrip().lower()
if word not in WORDS.values():
raise ValueError(f"'{word}' is not a valid bip39 word.")
self.word = word
def as_int(self):
return INDEXES[self.word]
def as_binary(self):
return bin(INDEXES[self.word])
class MnemonicPhrase:
allowed_phrase_lengths = [12, 18, 24]
def __init__(self, words: List[MnemonicWord]):
if len(words) not in self.allowed_phrase_lengths:
raise ValueError(
f"The mnemonic phrase length should be one of {self.allowed_phrase_lengths}, but it was {len(words)}"
)
self.words = {index: word for index, word in enumerate(words)}
def __iter__(self):
for index, word in self.words.items():
yield word
def __getitem__(self, item):
return self.words[item]
def as_bin(self):
binary_representation = "0b" + "".join(
[word.as_binary()[2:] for word in self]
)
return binary_representation
def as_int(self):
return int(
self.as_bin(), base=2
)
class Seed:
def __init__(self, seed_as_int: int):
self._seed_as_int = seed_as_int
@property
def as_mnemonic(self) -> List[str]:
return self._seed_as_mnemonic(self._seed)
pass
@property
def as_integer(self) -> int:
return self._seed_as_int
@property
def as_binary(self) -> str:
return bin(self._seed_as_int)
@property
def as_hex(self) -> str:
return hex(self._seed_as_int)
@classmethod
def from_mnemonic(cls, mnemonic_phrase: MnemonicPhrase):
seed_as_int = mnemonic_phrase.as_int()
return cls(seed_as_int)
@classmethod
def from_binary(cls, binary_seed_representation: str):
return cls(int(binary_seed_representation, base=2))
@classmethod
def from_integer(cls, int_seed_representation: int):
return cls(int_seed_representation)
@classmethod
def from_hex(cls, hex_seed_representation: str):
return cls(int(hex_seed_representation, base=16))

View file

@ -0,0 +1,101 @@
import pytest
from seed_playground import WORDS, MnemonicWord, MnemonicPhrase
def is_a_bin_num_with_0b(possible_bin_num):
allowed_chars = {"0", "1", "b"}
if possible_bin_num[:2] == "0b" and set(possible_bin_num) <= allowed_chars:
return True
return False
@pytest.fixture()
def twelve_valid_words():
raw_words = [
"primary",
"find",
"roof",
"forget",
"subject",
"present",
"pipe",
"primary",
"flavor",
"grant",
"remain",
"present",
]
mnemonic_words = [MnemonicWord(a_word) for a_word in raw_words]
return mnemonic_words
@pytest.fixture()
def a_valid_mnemonic_phrase(twelve_valid_words):
return MnemonicPhrase(twelve_valid_words)
def test_reading_the_file_works():
there_are_2048_words = len(WORDS) == 2048
first_word_is_abandon = WORDS[0] == "abandon"
last_word_is_zoo = WORDS[2047] == "zoo"
word_1957_is_virus = WORDS[1956] == "virus"
assert (
there_are_2048_words
and first_word_is_abandon
and last_word_is_zoo
and word_1957_is_virus
)
def test_passing_bip39_valid_word_instantiates_mnemonic_word_correctly():
word = MnemonicWord("abandon")
assert isinstance(word, MnemonicWord)
def test_passing_random_word_to_mnemonic_word_raises_exception():
with pytest.raises(ValueError):
word = MnemonicWord("Machiavelli")
def test_mnemonic_word_can_be_represented_as_binary():
word = MnemonicWord("abandon")
word_as_bin = word.as_binary()
assert is_a_bin_num_with_0b(word_as_bin)
def test_mnemonic_word_can_be_represented_as_int():
word = MnemonicWord("abandon")
word_as_int = word.as_int()
assert isinstance(word_as_int, int)
def test_mnemonic_phrase_instantiates_properly_with_12_words(
twelve_valid_words
):
phrase = MnemonicPhrase(twelve_valid_words)
assert isinstance(phrase, MnemonicPhrase)
def test_mnemonic_phrase_fails_with_13_words(twelve_valid_words):
twelve_valid_words.append(MnemonicWord("abandon"))
thirteen_valid_words = twelve_valid_words
with pytest.raises(ValueError):
phrase = MnemonicPhrase(thirteen_valid_words)
def test_mnemonic_phrase_is_iterable(a_valid_mnemonic_phrase):
for word in a_valid_mnemonic_phrase:
word
def test_mnemonic_phrase_as_bin_returns_a_valid_bin(a_valid_mnemonic_phrase):
bin_representation = a_valid_mnemonic_phrase.as_bin()
assert is_a_bin_num_with_0b(bin_representation)