BIP85 - Added test_bip85.py

- Updates to get_bip85_child_mnemonic
      - Updates to BIP-85 naming used
      - Modified the flow for BIP-85 Child to use one display per function
      - fix to BIP85 Index input wasn't deleting the first two characters
This commit is contained in:
jase100k
2022-04-27 21:18:38 +10:00
parent e6a321f321
commit 1330d67627
5 changed files with 127 additions and 35 deletions
+4 -4
View File
@@ -1577,7 +1577,7 @@ class MultisigWalletDescriptorScreen(ButtonListScreen):
@dataclass
class SeedExportBIP85GetIndexScreen(BaseTopNavScreen):
title: str = "BIP85 Seed Index"
title: str = "BIP-85 Index"
bip85_index: str = ""
def __post_init__(self):
@@ -1693,10 +1693,10 @@ class SeedExportBIP85GetIndexScreen(BaseTopNavScreen):
elif ret_val in Keyboard.ADDITIONAL_KEYS and input == HardwareButtonsConstants.KEY_PRESS:
if ret_val == Keyboard.KEY_BACKSPACE["code"]:
if len(self.bip85_index) <= 2:
if cursor_position == 0:
pass
elif cursor_position == len(self.bip85_index):
self.derivation_path = self.bip85_index[:-1]
self.bip85_index = self.bip85_index[:-1]
cursor_position -= 1
else:
self.bip85_index = self.bip85_index[:cursor_position - 1] + self.bip85_index[
@@ -1737,7 +1737,7 @@ class BIP85SeedWordsScreen(WarningEdgesMixin, ButtonListScreen):
def __post_init__(self):
self.title = f"BIP85 Words: {self.page_index+1}/{self.num_pages}"
self.title = f"BIP-85 Words: {self.page_index+1}/{self.num_pages}"
super().__post_init__()
#index = 0
+5 -5
View File
@@ -122,19 +122,19 @@ class Seed:
return xpub
# Derives a BIP85 mnemonic (seed word) from the master seed words using embit functions
def get_bip85_child_mnemonic(self, bip85_index: int, bip85_num_words: int, wallet_path: str = '/',
network: str = SettingsConstants.MAINNET):
def get_bip85_child_mnemonic(self, bip85_index: int, bip85_num_words: int):
passphrase = self._passphrase
# language = 'english'
# lang_code = 0
# Need to add language later for path, defaults to English (0)
path = "m/83696968'/39'/0'/{bip85_num_words}'/{bip85_index}'".format(bip85_num_words=bip85_num_words,
bip85_index=bip85_index)
seed = bip39.mnemonic_to_seed(self.mnemonic_str, password=self._passphrase, wordlist=self.wordlist)
xprv = embit.bip32.HDKey.from_seed(seed)
#seed = bip39.mnemonic_to_seed(self.mnemonic_str, password=self._passphrase, wordlist=self.wordlist)
# xprv = embit.bip32.HDKey.from_seed(seed)
root = bip32.HDKey.from_seed(self.seed_bytes, version=NETWORKS[SettingsConstants.map_network_to_embit(network)]["xprv"])
# Derive k
xprv = xprv.derive(path)
xprv = root.derive(path)
entropy = hmac_sha512(xprv.secret)
width = round(bip85_num_words / 12 * 16)
return bip39.mnemonic_from_bytes(entropy[:width])
+3 -3
View File
@@ -149,7 +149,7 @@ class SettingsConstants:
SETTING__SIG_TYPES = "sig_types"
SETTING__SCRIPT_TYPES = "script_types"
SETTING__XPUB_DETAILS = "xpub_details"
SETTING__GEN_BIP85 = "Generate BIP85"
SETTING__BIP85_CHILD_SEEDS = "BIP-85_child_seeds"
SETTING__PASSPHRASE = "passphrase"
SETTING__CAMERA_ROTATION = "camera_rotation"
SETTING__COMPACT_SEEDQR = "compact_seedqr"
@@ -394,8 +394,8 @@ class SettingsDefinition:
default_value=SettingsConstants.OPTION__ENABLED),
SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES,
attr_name=SettingsConstants.SETTING__GEN_BIP85,
display_name="Generate BIP85",
attr_name=SettingsConstants.SETTING__BIP85_CHILD_SEEDS,
display_name="BIP-85 child seeds",
visibility=SettingsConstants.VISIBILITY__ADVANCED,
default_value=SettingsConstants.OPTION__DISABLED),
+92 -23
View File
@@ -350,7 +350,7 @@ class SeedOptionsView(View):
VERIFY_ADDRESS = "Verify Addr"
EXPORT_XPUB = "Export Xpub"
BACKUP = ("Backup Seed", None, None, None, SeedSignerCustomIconConstants.SMALL_CHEVRON_RIGHT)
GENBIP85 = ("Gen BIP85 Child seed")
BIP85_CHILD_SEED = "BIP-85 Child Seed"
DISCARD = ("Discard Seed", None, None, "red")
button_data = []
@@ -382,8 +382,8 @@ class SeedOptionsView(View):
if self.settings.get_value(SettingsConstants.SETTING__XPUB_EXPORT) == SettingsConstants.OPTION__ENABLED:
button_data.append(EXPORT_XPUB)
if self.settings.get_value(SettingsConstants.SETTING__GEN_BIP85) == SettingsConstants.OPTION__ENABLED:
button_data.append(GENBIP85)
if self.settings.get_value(SettingsConstants.SETTING__BIP85_CHILD_SEEDS) == SettingsConstants.OPTION__ENABLED:
button_data.append(BIP85_CHILD_SEED)
button_data.append(BACKUP)
button_data.append(DISCARD)
@@ -418,36 +418,92 @@ class SeedOptionsView(View):
elif button_data[selected_menu_num] == DISCARD:
return Destination(SeedDiscardView, view_args={"seed_num": self.seed_num})
elif button_data[selected_menu_num] == GENBIP85:
return Destination(SeedExportBIP85View, view_args={"seed_num": self.seed_num})
elif button_data[selected_menu_num] == BIP85_CHILD_SEED:
return Destination(BIP85ApplicationModeView, view_args={"seed_num": self.seed_num})
"""****************************************************************************
Export BIP85 Child Flow
****************************************************************************"""
# This will ask user word number and display warning if neccessary before displaying the words
class SeedExportBIP85View(View):
BIP85 - Derive child mnemonic (seed) flow
****************************************************************************
* Ask the user the application type as defined in the BIP0085 spec.
* Currently only Word mode of 12, 24 words.
* Possible future additions are
* WIF (HDSEED)
* XPRV (BIP32)"""
class BIP85ApplicationModeView(View):
def __init__(self, seed_num: int):
super().__init__()
self.seed_num = seed_num
self.num_words = 0
self.bip85_index = ""
self.bip85_index = 0
self.bip85_app_no = None
def run(self):
WORDS_12 = "12 Words"
WORDS_24 = "24 Words"
button_data=[WORDS_12, WORDS_24]
# Need to setup width as 32
WIF = "WIF"
#Need to setup width as 64
XPRV = "XPRV"
# Future enhancement to display WIF (HD-SEED) and XPRV (Bip32)
#button_data=[WORDS_12, WORDS_24, WIF, XPRV]
button_data = [WORDS_12, WORDS_24]
selected_menu_num = ButtonListScreen(
title="Generate BIP85 Seed",
title="BIP-85 Num Words",
button_data=button_data
).display()
if selected_menu_num == RET_CODE__BACK_BUTTON:
return Destination(BackStackView)
if button_data[selected_menu_num] == WORDS_12:
self.bip85_app_no = "words"
self.num_words = 12
elif button_data[selected_menu_num] == WORDS_24:
self.bip85_app_no = "words"
self.num_words = 24
elif button_data[selected_menu_num] == WIF:
print("WIF")
self.bip85_app_no = "wif"
return(Destination(NotYetImplementedView))
elif button_data[selected_menu_num] == XPRV:
self.bip85_app_no = "xprv"
return(Destination(NotYetImplementedView))
destination = Destination(
BIP85ChildSeedIndexView,
view_args={"seed_num": self.seed_num, "num_words": self.num_words, "bip85_app_no" : self.bip85_app_no,
"bip85_index": self.bip85_index})
#skip_current_view=True, # Prevent going BACK to WarningViews
return(destination)
##
# View to retrieve the derived seed index
class BIP85ChildSeedIndexView(View):
def __init__(self, seed_num: int, num_words: int, bip85_app_no: str, bip85_index: int):
super().__init__()
self.bip85_app_no = bip85_app_no
self.seed_num = seed_num
self.num_words = num_words
self.bip85_index = bip85_index
#if self.seed_num is None:
# self.seed = self.controller.storage.get_pending_seed()
#else:
# self.seed = self.controller.get_seed(self.seed_num)
#self.num_pages=int(self.num_words/4)
def run(self):
args = {"seed_num": self.seed_num, "num_words": self.num_words, "bip85_app_no" : self.bip85_app_no, "bip85_index": self.bip85_index}
# Change this later to use the generic Screen input keyboard
ret = seed_screens.SeedExportBIP85GetIndexScreen(
).display()
@@ -457,17 +513,31 @@ class SeedExportBIP85View(View):
# ret should be the bip85_index let's convert to int
self.bip85_index = int(ret)
if button_data[selected_menu_num] == WORDS_12:
self.num_words = 12
return Destination(
BIP85ChildSeedWarningView,
view_args={"seed_num": self.seed_num, "num_words": self.num_words,
"bip85_index": self.bip85_index}
)
elif button_data[selected_menu_num] == WORDS_24:
self.num_words = 24
class BIP85ChildSeedWarningView(View):
def __init__(self, seed_num: int, num_words: int, bip85_index: int):
super().__init__()
self.seed_num = seed_num
self.num_words = num_words
self.bip85_index = bip85_index
# if self.seed_num is None:
# self.seed = self.controller.storage.get_pending_seed()
# else:
# self.seed = self.controller.get_seed(self.seed_num)
destination = Destination(
BIP85SeedWordsView,
view_args={"seed_num": self.seed_num, "page_index": 0, "num_words": self.num_words,
"bip85_index": self.bip85_index},
skip_current_view=True, # Prevent going BACK to WarningViews
# self.num_pages=int(self.num_words/4)
def run(self):
args = {"seed_num": self.seed_num, "num_words": self.num_words, "bip85_index": self.bip85_index}
##
destination = Destination(BIP85SeedWordsView, view_args={"seed_num": self.seed_num, "page_index": 0, "num_words": self.num_words,
"bip85_index": self.bip85_index}, skip_current_view=True, # Prevent going BACK to WarningViews
)
if self.settings.get_value(SettingsConstants.SETTING__DIRE_WARNINGS) == SettingsConstants.OPTION__DISABLED:
@@ -486,7 +556,6 @@ class SeedExportBIP85View(View):
return Destination(BackStackView)
class BIP85SeedWordsView(View):
def __init__(self, seed_num: int, num_words: int, bip85_index: int, page_index: int = 0):
super().__init__()
+23
View File
@@ -0,0 +1,23 @@
import pytest
from mock import MagicMock
from seedsigner.models import Seed
from embit import bip39
from seedsigner.models.settings import SettingsConstants
def test_derive_child_mnemonic():
expected = "unusual topic foot figure pulp target glimpse core electric spot neglect fame"
seed = Seed(mnemonic="resource timber firm banner horror pupil frozen main pear direct pioneer broken grid core insane begin sister pony end debate task silk empty curious".split())
actual = seed.get_bip85_child_mnemonic(0, 12)
assert actual == expected
expected = "imitate post very mandate retreat prevent tiny snow fetch canvas town shrug fix food summer library symptom occur slam style cruise wolf phone key"
seed = Seed(mnemonic="resource timber firm banner horror pupil frozen main pear direct pioneer broken grid core insane begin sister pony end debate task silk empty curious".split())
actual = seed.get_bip85_child_mnemonic(0, 24)
assert actual == expected