work in progress

This commit is contained in:
newtonick
2021-09-07 02:26:49 +00:00
parent fd21e953cb
commit 27a6c72a7d
12 changed files with 67 additions and 49 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
setuptools.setup(
name="seedsigner",
version="0.4.1",
version="0.4.4",
author="SeedSigner",
author_email="author@example.com",
description="Build an offline, airgapped Bitcoin signing device for less than $50!",
+9 -9
View File
@@ -174,7 +174,7 @@ class Controller(Singleton):
### Generate Last Word 12 / 24 Menu
def show_generate_last_word_tool(self) -> int:
seed = Seed()
seed = Seed(wordlist=self.settings.wordlist)
ret_val = 0
while True:
@@ -215,7 +215,7 @@ class Controller(Singleton):
### Create a Seed w/ Dice Screen
def show_create_seed_with_dice_tool(self) -> int:
seed = Seed()
seed = Seed(wordlist=self.settings.wordlist)
ret_val = True
while True:
@@ -249,7 +249,7 @@ class Controller(Singleton):
### Create a Seed w/ Image
def show_create_seed_with_image_tool(self) -> int:
seed = Seed()
seed = Seed(wordlist=self.settings.wordlist)
ret_val = True
while True:
@@ -287,7 +287,7 @@ class Controller(Singleton):
### Store a seed (temp) Menu
def show_store_a_seed_tool(self):
seed = Seed()
seed = Seed(wordlist=self.settings.wordlist)
ret_val = 0
display_saved_seed = False
ret_val = self.menu_view.display_saved_seed_menu(self.storage, 1, "... [ Return to Seed Tools ]")
@@ -410,7 +410,7 @@ class Controller(Singleton):
### Generate XPUB
def show_generate_xpub(self):
seed = Seed()
seed = Seed(wordlist=self.settings.wordlist)
# If there is a saved seed, ask to use saved seed
if self.storage.num_of_saved_seeds() > 0:
@@ -487,7 +487,7 @@ class Controller(Singleton):
qr_xpub_type = self.settings.qr_xpub_type
self.signing_tools_view.draw_modal(["Generating xPub QR ..."])
e = EncodeQR(seed_phrase=seed.mnemonic_list, passphrase=seed.passphrase, derivation=self.settings.derivation, network=self.settings.network, policy=self.settings.script_policy, qr_type=qr_xpub_type, qr_density=self.settings.qr_density)
e = EncodeQR(seed_phrase=seed.mnemonic_list, passphrase=seed.passphrase, derivation=self.settings.derivation, network=self.settings.network, policy=self.settings.script_policy, qr_type=qr_xpub_type, qr_density=self.settings.qr_density, wordlist=self.settings.wordlist)
while e.totalParts() > 1:
image = e.nextPartImage(240,240,2)
@@ -506,7 +506,7 @@ class Controller(Singleton):
### Sign Transactions
def show_sign_transaction(self):
seed = Seed()
seed = Seed(wordlist=self.settings.wordlist)
used_saved_seed = False
# reusable qr scan function
@@ -514,7 +514,7 @@ class Controller(Singleton):
# Scan QR using Camera
self.menu_view.draw_modal(["Initializing Camera"])
self.camera.start_video_stream_mode(resolution=(480, 480), framerate=12, format="rgb")
decoder = DecodeQR()
decoder = DecodeQR(wordlist=self.settings.wordlist)
def live_preview(camera, decoder, scan_text):
while True:
@@ -714,7 +714,7 @@ class Controller(Singleton):
# Display Animated QR Code
self.menu_view.draw_modal(["Generating PSBT QR ..."])
e = EncodeQR(psbt=trimmed_psbt, qr_type=self.settings.qr_psbt_type, qr_density=self.settings.qr_density)
e = EncodeQR(psbt=trimmed_psbt, qr_type=self.settings.qr_psbt_type, qr_density=self.settings.qr_density, wordlist=self.settings.wordlist)
while True:
image = e.nextPartImage(240,240,1)
View.DispShowImage(image)
@@ -2,11 +2,9 @@ from embit import bip39
from embit.bip39 import mnemonic_to_bytes, mnemonic_from_bytes
import unicodedata
from seedsigner.models import Settings
def calculate_checksum(partial_mnemonic: list):
def calculate_checksum(partial_mnemonic: list, wordlist):
# Provide 11- or 23-word mnemonic, returns complete mnemonic w/checksum
if len(partial_mnemonic) not in [11, 23]:
raise Exception("Pass in a 11- or 23-word mnemonic")
@@ -16,7 +14,7 @@ def calculate_checksum(partial_mnemonic: list):
mnemonic_copy.append("abandon")
# Ignores the final checksum word and recalcs
mnemonic_bytes = bip39.mnemonic_to_bytes(unicodedata.normalize("NFKD", " ".join(mnemonic_copy)), ignore_checksum=True, wordlist=Settings.get_instance().wordlist)
mnemonic_bytes = bip39.mnemonic_to_bytes(unicodedata.normalize("NFKD", " ".join(mnemonic_copy)), ignore_checksum=True, wordlist=wordlist)
# Return as a list
return bip39.mnemonic_from_bytes(mnemonic_bytes).split()
+3 -3
View File
@@ -1,7 +1,7 @@
from .qr_type import *
from .seed import *
from .decode_qr import *
from .encode_qr import *
from .settings import *
from .psbt_parser import *
from .seed import *
from .seed_storage import *
from .seed_storage import *
from .settings import *
+29 -18
View File
@@ -8,7 +8,6 @@ from binascii import a2b_base64, b2a_base64
from seedsigner.helpers.ur2.ur_decoder import URDecoder
from seedsigner.helpers.bcur import (cbor_decode, bc32decode)
from seedsigner.models.qr_type import QRType
from seedsigner.models.settings import Settings
from seedsigner.models.seed import Seed
###
@@ -25,11 +24,18 @@ class DecodeQR:
self.specter_qr = SpecterDecodePSBTQR() # Specter Desktop PSBT QR base64 decoder
self.legacy_ur = LegacyURDecodeQR() # UR Legacy decoder
self.base64_qr = Base64DecodeQR() # Single Segments Base64
self.seedqr = SeedQR()
self.wordlist = None
for key, value in kwargs.items():
if key == "qr_type":
self.qr_type = value
if key == "wordlist":
self.wordlist = value
if self.wordlist == None:
raise Exception('Wordlist Required')
self.seedqr = SeedQR(wordlist=self.wordlist)
def addImage(self, image):
qr_str = DecodeQR.QR2Str(image)
@@ -42,7 +48,7 @@ class DecodeQR:
if qr_str == None:
return DecodeQRStatus.FALSE
qr_type = DecodeQR.SegmentType(qr_str)
qr_type = DecodeQR.SegmentType(qr_str, wordlist=self.wordlist)
if self.qr_type == None:
self.qr_type = qr_type
@@ -188,27 +194,29 @@ class DecodeQR:
return barcode.data.decode("utf-8")
@staticmethod
def SegmentType(s):
_WORDLIST = Settings.get_instance().wordlist
_4LETTER_WORDLIST = [word[:4].strip() for word in _WORDLIST]
def SegmentType(s, wordlist=None):
# PSBT
if re.search("^UR:CRYPTO-PSBT/", s, re.IGNORECASE):
return QRType.PSBTUR2
elif re.search(r'^p(\d+)of(\d+) ', s, re.IGNORECASE):
return QRType.PSBTSPECTER
elif re.search("^UR:BYTES/", s, re.IGNORECASE):
return QRType.PSBTURLEGACY
elif re.search(r'\d{48,96}', s):
elif DecodeQR.isBase64PSBT(s):
return QRType.PSBTBASE64
_4LETTER_WORDLIST = [word[:4].strip() for word in wordlist]
# Seed
if re.search(r'\d{48,96}', s):
return QRType.SEEDSSQR
elif all(x in _WORDLIST for x in s.strip().split(" ")):
elif all(x in wordlist for x in s.strip().split(" ")):
# checks if all words in list are in bip39 word list
return QRType.SEEDMNEMONIC
elif all(x in _4LETTER_WORDLIST for x in s.strip().split(" ")):
# checks if all 4 letter words are in list are in 4 letter bip39 word list
return QRType.SEED4LETTERMNEMONIC
elif DecodeQR.isBase64PSBT(s):
return QRType.PSBTBASE64
else:
return QRType.INVALID
@@ -422,16 +430,19 @@ class Base64DecodeQR:
class SeedQR:
def __init__(self):
def __init__(self, wordlist=None):
self.total_segments = 1
self.collected_segments = 0
self.complete = False
self.seed_phrase = []
self.wordlist = wordlist
if self.wordlist == None:
raise Exception('Wordlist Required')
def add(self, segment, qr_type=QRType.SEEDSSQR):
_WORDLIST = Settings.get_instance().wordlist
_4LETTER_WORDLIST = [word[:4].strip() for word in _WORDLIST]
_4LETTER_WORDLIST = [word[:4].strip() for word in self.wordlist]
if qr_type == QRType.SEEDSSQR:
@@ -442,7 +453,7 @@ class SeedQR:
num_words = int(len(segment) / 4)
for i in range(0, num_words):
index = int(segment[i * 4: (i*4) + 4])
word = _WORDLIST[index]
word = self.wordlist[index]
self.seed_phrase.append(word)
if len(self.seed_phrase) > 0:
if self.is1224Phrase() == False:
@@ -459,7 +470,7 @@ class SeedQR:
try:
# embit mnemonic code to validate
seed = Seed(segment, passphrase="")
seed = Seed(segment, passphrase="", wordlist=self.wordlist)
if not seed:
# seed is not valid, return invalid
return DecodeQRStatus.INVALID
@@ -478,10 +489,10 @@ class SeedQR:
sl = segment.strip().split(" ")
words = []
for s in sl:
words.append(_WORDLIST[_4LETTER_WORDLIST.index(s)])
words.append(self.wordlist[_4LETTER_WORDLIST.index(s)])
# embit mnemonic code to validate
seed = Seed(words, passphrase="")
seed = Seed(words, passphrase="", wordlist=self.wordlist)
if not seed:
# seed is not valid, return invalid
return DecodeQRStatus.INVALID
+7 -3
View File
@@ -8,7 +8,6 @@ from seedsigner.helpers.ur2.ur import UR
from seedsigner.helpers.bcur import (bc32encode, cbor_encode, bcur_encode)
from seedsigner.helpers.qr import QR
from seedsigner.models.qr_type import QRType, EncodeQRDensity
from seedsigner.models.settings import Settings
from seedsigner.models.seed import Seed
###
@@ -21,7 +20,6 @@ class EncodeQR:
WORDLIST = None
def __init__(self, **kwargs):
EncodeQR.WORDLIST = Settings.get_instance().wordlist
self.psbt = None
self.seed_phrase = None
self.passphrase = None
@@ -31,6 +29,7 @@ class EncodeQR:
self.qr_type = None
self.qr_density = None
self.qr = QR()
self.wordlist = None
for key, value in kwargs.items():
if key == "psbt":
@@ -49,6 +48,11 @@ class EncodeQR:
self.qr_type = value
elif key == "qr_density":
self.qr_density = value
elif key == "wordlist":
self.wordlist = value
if self.wordlist == None:
raise Exception('Wordlist Required')
if self.qr_type == None:
raise Exception('Encoder Type Required')
@@ -217,7 +221,7 @@ class XPubQR:
self.sent_complete = False
self.network = network
self.seed = Seed(self.seed_phrase, self.passphrase)
self.seed = Seed(mnemonic=self.seed_phrase, passphrase=self.passphrase, wordlist=self.wordlist)
self.root = bip32.HDKey.from_seed(self.seed.seed, version=NETWORKS[self.network]["xprv"])
self.fingerprint = self.root.child(0).fingerprint
self.bip48_xprv = self.root.derive(self.derivation)
-2
View File
@@ -2,8 +2,6 @@ from embit import psbt, script, ec, bip32, bip39
from embit.networks import NETWORKS
from io import BytesIO
from seedsigner.models.seed import Seed
class PSBTParser():
def __init__(self, p, seed: Seed, network="main"):
+4 -5
View File
@@ -9,11 +9,10 @@ class Seed:
self._valid = False
self.passphrase = passphrase
self.mnemonic = mnemonic
if wordlist == None:
from seedsigner.models.settings import Settings
self._wordlist = Settings.get_instance().wordlist
else:
self._wordlist = wordlist
self.wordlist = wordlist
if self.wordlist == None:
raise Exception('Wordlist Required')
self._valid = self._generate_seed()
self._init_complete = True
+1 -1
View File
@@ -665,7 +665,7 @@ class SeedToolsView(View):
###
def display_last_word(self, partial_seed_phrase) -> list:
finalseed = mnemonic_generation.calculate_checksum(partial_seed_phrase)
finalseed = mnemonic_generation.calculate_checksum(partial_seed_phrase, wordlist=self.controller.settings.wordlist)
last_word = finalseed[-1]
self.draw.rectangle((0, 0, View.canvas_width, View.canvas_height), outline=0, fill=0)
+1 -1
View File
@@ -1,8 +1,8 @@
import pytest
from mock import MagicMock
from seedsigner.models.seed import Seed
from seedsigner.models.decode_qr import DecodeQR, QRType, DecodeQRStatus
from seedsigner.models.psbt_parser import PSBTParser
from seedsigner.models.seed import Seed
from embit import psbt, bip39
+2 -2
View File
@@ -23,10 +23,10 @@ def test_calculate_checksum():
"""
# Test mnemonics from https://iancoleman.io/bip39/
partial_mnemonic = "crawl focus rescue cable view pledge rather dinner cousin unfair day"
mnemonic = mnemonic_generation.calculate_checksum(partial_mnemonic.split(" "))
mnemonic = mnemonic_generation.calculate_checksum(partial_mnemonic.split(" "), wordlist=bip39.WORDLIST)
assert bip39.mnemonic_is_valid(" ".join(mnemonic))
partial_mnemonic = "bubble father debate ankle injury fence mesh evolve section wet coyote violin pyramid flower rent arrow round clutch myth safe base skin mobile"
mnemonic = mnemonic_generation.calculate_checksum(partial_mnemonic.split(" "))
mnemonic = mnemonic_generation.calculate_checksum(partial_mnemonic.split(" "), wordlist=bip39.WORDLIST)
assert bip39.mnemonic_is_valid(" ".join(mnemonic))
+8
View File
@@ -0,0 +1,8 @@
import pytest
from mock import MagicMock
from seedsigner.models.psbt_parser import PSBTParser
from embit import psbt
def test_sig_count():
print("test")