Major DecodeQR refactoring

This commit is contained in:
kdmukai
2022-02-20 22:30:39 -06:00
parent 5e62059861
commit 873dc1d98f
11 changed files with 463 additions and 549 deletions
+3 -3
View File
@@ -59,8 +59,8 @@ class ScanScreen(BaseTopNavScreen):
frame = self.camera.read_video_stream(as_image=True)
if frame is not None:
scan_text = self.instructions_text
if self.decoder.getPercentComplete() > 0 and self.decoder.isPSBT():
scan_text = str(self.decoder.getPercentComplete()) + "% Complete"
if self.decoder.get_percent_complete() > 0 and self.decoder.is_psbt:
scan_text = str(self.decoder.get_percent_complete()) + "% Complete"
# TODO: Render TopNav & instructions_background w/transparency
# img = Image.new(mode='RGBA', size=(self.canvas_width, self.canvas_height))
@@ -80,7 +80,7 @@ class ScanScreen(BaseTopNavScreen):
while True:
frame = self.camera.read_video_stream()
if frame is not None:
status = self.decoder.addImage(frame)
status = self.decoder.add_image(frame)
if status in (DecodeQRStatus.COMPLETE, DecodeQRStatus.INVALID):
self.camera.stop_video_stream_mode()
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -56,14 +56,14 @@ class EncodeQR:
self.encoder: BaseQrEncoder = None
# PSBT formats
if self.qr_type == QRType.PSBTSPECTER:
if self.qr_type == QRType.PSBT__SPECTER:
self.encoder = SpecterPsbtQrEncoder(psbt=self.psbt, qr_density=self.qr_density)
elif self.qr_type == QRType.PSBTUR2:
elif self.qr_type == QRType.PSBT__UR2:
self.encoder = UrPsbtQrEncoder(psbt=self.psbt, qr_density=self.qr_density)
# XPUB formats
elif self.qr_type == QRType.XPUBQR:
elif self.qr_type == QRType.XPUB:
self.encoder = XpubQrEncoder(
seed_phrase=self.seed_phrase,
passphrase=self.passphrase,
@@ -72,7 +72,7 @@ class EncodeQR:
wordlist_language_code=self.wordlist_language_code
)
elif self.qr_type == QRType.URXPUBQR:
elif self.qr_type == QRType.XPUB__UR:
self.encoder = UrXpubQrEncoder(
qr_density=self.qr_density,
seed_phrase=self.seed_phrase,
@@ -82,7 +82,7 @@ class EncodeQR:
wordlist_language_code=self.wordlist_language_code
)
elif self.qr_type == QRType.SPECTERXPUBQR:
elif self.qr_type == QRType.XPUB__SPECTER:
self.encoder = SpecterXPubQrEncoder(
qr_density=self.qr_density,
seed_phrase=self.seed_phrase,
@@ -94,11 +94,11 @@ class EncodeQR:
# SeedQR formats
elif self.qr_type == QRType.SEEDQR:
elif self.qr_type == QRType.SEED__SEEDQR:
self.encoder = SeedQrEncoder(seed_phrase=self.seed_phrase,
wordlist_language_code=self.wordlist_language_code)
elif self.qr_type == QRType.COMPACTSEEDQR:
elif self.qr_type == QRType.SEED__COMPACTSEEDQR:
self.encoder = CompactSeedQrEncoder(seed_phrase=self.seed_phrase,
wordlist_language_code=self.wordlist_language_code)
@@ -120,7 +120,7 @@ class EncodeQR:
def next_part_image(self, width=240, height=240, border=3, background_color="bdbdbd"):
part = self.next_part()
if self.qr_type == QRType.SEEDQR:
if self.qr_type == QRType.SEED__SEEDQR:
return self.qr.qrimage(part, width, height, border)
else:
return self.qr.qrimage_io(part, width, height, border, background_color=background_color)
+27 -25
View File
@@ -1,27 +1,29 @@
from enum import IntEnum
class QRType:
"""
Used with DecodeQR and EncodeQR to communicate qr encoding type
"""
PSBT__BASE64 = "psbt__base64"
PSBT__SPECTER = "psbt__specter"
PSBT__LEGACY_UR = "psbt__legacy_ur"
PSBT__BASE43 = "psbt__base43"
PSBT__UR2 = "psbt__ur2"
###
### QRType Class IntEum
### Purpose: used with DecodeQR and EncodeQR to communicate qr encoding type
###
SEED__SEEDQR = "seed__seedqr"
SEED__COMPACTSEEDQR = "seed__compactseedqr"
SEED__UR2 = "seed__ur2"
SEED__MNEMONIC = "seed__mnemonic"
SEED__FOUR_LETTER_MNEMONIC = "seed__four_letter_mnemonic"
class QRType(IntEnum):
PSBTBASE64 = 1
PSBTSPECTER = 2
PSBTURLEGACY = 3
PSBTBASE43 = 4
PSBTUR2 = 5
SEEDQR = 6
COMPACTSEEDQR = 10
SEEDUR2 = 7
SEEDMNEMONIC = 8
SEED4LETTERMNEMONIC = 9
SETTINGS = 23
XPUBQR = 20
SPECTERXPUBQR = 21
URXPUBQR = 22
BITCOINADDRESSQR = 30
SPECTERWALLETQR = 40
URWALLETQR = 41
BLUEWALLETQR = 42
INVALID = 100
SETTINGS = "settings"
XPUB = "xpub"
XPUB__SPECTER = "xpub__specter"
XPUB__UR = "xpub__ur"
BITCOIN_ADDRESS = "bitcoin_address"
WALLET__SPECTER = "wallet__specter"
WALLET__UR = "wallet__ur"
WALLET__BLUEWALLET = "wallet__bluewallet"
INVALID = "invalid"
+2 -2
View File
@@ -339,9 +339,9 @@ class PSBTSignedQRDisplayView(View):
self.coordinator = coordinator
def run(self):
qr_psbt_type = QRType.PSBTUR2
qr_psbt_type = QRType.PSBT__UR2
if self.coordinator == SettingsConstants.COORDINATOR__SPECTER_DESKTOP:
qr_psbt_type = QRType.PSBTSPECTER
qr_psbt_type = QRType.PSBT__SPECTER
qr_encoder = EncodeQR(
psbt=self.controller.psbt,
+18 -10
View File
@@ -5,7 +5,7 @@ from seedsigner.models.settings import SettingsConstants
from seedsigner.views.psbt_views import PSBTSelectSeedView
from seedsigner.views.seed_views import SeedAddPassphrasePromptView, SeedAddPassphraseView
from .view import BackStackView, MainMenuView, View, Destination
from .view import BackStackView, MainMenuView, NotYetImplementedView, View, Destination
from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON
from seedsigner.models import DecodeQR, Seed
@@ -24,9 +24,9 @@ class ScanView(View):
screen = ScanScreen(decoder=self.decoder)
screen.display()
if self.decoder.isComplete():
if self.decoder.isSeed():
seed_mnemonic = self.decoder.getSeedPhrase()
if self.decoder.is_complete:
if self.decoder.is_seed:
seed_mnemonic = self.decoder.get_seed_phrase()
if not seed_mnemonic:
# seed is not valid, Exit if not valid with message
raise Exception("Not yet implemented!")
@@ -44,13 +44,13 @@ class ScanView(View):
else:
return Destination(SeedValidView)
elif self.decoder.isPSBT():
psbt = self.decoder.getPSBT()
elif self.decoder.is_psbt:
psbt = self.decoder.get_psbt()
self.controller.psbt = psbt
self.controller.psbt_parser = None
return Destination(PSBTSelectSeedView)
elif self.decoder.qr_type == QRType.SETTINGS:
elif self.decoder.is_settings:
from seedsigner.models.settings import Settings
settings = self.decoder.get_settings_data()
Settings.get_instance().update(new_settings=settings)
@@ -59,10 +59,18 @@ class ScanView(View):
return Destination(SettingsUpdatedView, {"config_name": self.decoder.get_settings_config_name()})
elif self.decoder.qr_type == QRType.BITCOINADDRESSQR:
elif self.decoder.is_wallet_descriptor:
# TODO
print("Implement QR scanning for wallet descriptors!")
return Destination(NotYetImplementedView)
elif self.decoder.is_address:
# TODO: Reserved for Nick!
raise Exception("Not yet implemented!")
print("Implement QR scanning for Bitcoin addresses!")
return Destination(NotYetImplementedView)
else:
return Destination(NotYetImplementedView)
return Destination(MainMenuView)
+6 -6
View File
@@ -739,9 +739,9 @@ class SeedToolsView(View):
def seed_phrase_as_qr(self, seed_phrase, is_compact_seedqr=False):
if is_compact_seedqr:
e = EncodeQR(seed_phrase=seed_phrase, qr_type=QRType.COMPACTSEEDQR, wordlist=self.controller.settings.wordlist)
e = EncodeQR(seed_phrase=seed_phrase, qr_type=QRType.SEED__COMPACTSEEDQR, wordlist=self.controller.settings.wordlist)
else:
e = EncodeQR(seed_phrase=seed_phrase, qr_type=QRType.SEEDQR, wordlist=self.controller.settings.wordlist)
e = EncodeQR(seed_phrase=seed_phrase, qr_type=QRType.SEED__SEEDQR, wordlist=self.controller.settings.wordlist)
data = e.next_part()
qr = QR()
image = qr.qrimage(
@@ -907,7 +907,7 @@ class SeedToolsView(View):
frame = self.controller.camera.read_video_stream(as_image=True)
if frame is not None:
self.renderer.show_image_with_text(frame.resize((240,240)), "Scan Seed QR", font=Fonts.get_font("Assistant-Medium", 22), text_color=self.color, text_background=(0,0,0,225))
status = decoder.addImage(frame)
status = decoder.add_image(frame)
if status in (DecodeQRStatus.COMPLETE, DecodeQRStatus.INVALID):
break
@@ -917,9 +917,9 @@ class SeedToolsView(View):
self.words = []
return self.words[:]
if decoder.isComplete() and decoder.isSeed():
self.words = decoder.getSeedPhrase()
elif not decoder.isPSBT():
if decoder.is_complete and decoder.is_seed:
self.words = decoder.get_seed_phrase()
elif not decoder.is_psbt:
self.draw_modal(["Not a valid Seed QR"], "", "Right to Exit")
input = self.buttons.wait_for([B.KEY_RIGHT])
else:
+4 -4
View File
@@ -3,7 +3,7 @@ import embit
from binascii import hexlify
from seedsigner.gui.components import FontAwesomeIconConstants
from seedsigner.models.decode_qr import SeedQR
from seedsigner.models.decode_qr import SeedQrDecoder
from .view import NotYetImplementedView, View, Destination, BackStackView, MainMenuView
@@ -458,11 +458,11 @@ class SeedExportXpubQRDisplayView(View):
self.seed = self.controller.get_seed(seed_num)
if coordinator == SettingsConstants.COORDINATOR__SPECTER_DESKTOP:
qr_type = QRType.SPECTERXPUBQR
qr_type = QRType.XPUB__SPECTER
elif coordinator == SettingsConstants.COORDINATOR__BLUE_WALLET:
qr_type = QRType.XPUBQR
qr_type = QRType.XPUB
else:
qr_type = QRType.URXPUBQR
qr_type = QRType.XPUB__UR
self.qr_encoder = EncodeQR(
seed_phrase=self.seed.mnemonic_list,
File diff suppressed because one or more lines are too long
+6 -6
View File
@@ -12,7 +12,7 @@ def test_ur_qr_encode():
tx = psbt.PSBT.parse(a2b_base64(base64_psbt))
e = EncodeQR(psbt=tx, qr_type=QRType.PSBTUR2)
e = EncodeQR(psbt=tx, qr_type=QRType.PSBT__UR2)
cnt = 0
while cnt <= 10:
@@ -27,7 +27,7 @@ def test_specter_qr_encode():
tx = psbt.PSBT.parse(a2b_base64(base64_psbt))
e = EncodeQR(psbt=tx, qr_type=QRType.PSBTSPECTER)
e = EncodeQR(psbt=tx, qr_type=QRType.PSBT__SPECTER)
cnt = 0
while cnt <= 10:
@@ -62,7 +62,7 @@ def test_seedsigner_qr():
mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash"
e = EncodeQR(seed_phrase=mnemonic.split(" "), qr_type=QRType.SEEDQR)
e = EncodeQR(seed_phrase=mnemonic.split(" "), qr_type=QRType.SEED__SEEDQR)
print(e.next_part())
@@ -72,7 +72,7 @@ def test_xpub_qr():
mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash"
e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.XPUBQR, network="test", derivation="m/48h/1h/0h/2h")
e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.XPUB, network="test", derivation="m/48h/1h/0h/2h")
assert e.next_part() == "[c49122a5/48h/1h/0h/2h]Vpub5mXgECaX5yYDNc5VnUG4jVNptyEg65qUjuofWchQeuMWWiq8rcPBoMxfrVggXj5NJmaNEToWpax8GMMucozvAdqf1bW1JsZsfdBzsK3VUC5"
@@ -80,7 +80,7 @@ def test_specter_xpub_qr():
mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash"
e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.SPECTERXPUBQR, network="test", derivation="m/48h/1h/0h/2h", qr_density=EncodeQR.DENSITY__LOW)
e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.XPUB__SPECTER, network="test", derivation="m/48h/1h/0h/2h", qr_density=EncodeQR.DENSITY__LOW)
assert e.next_part() == "p1of4 [c49122a5/48h/1h/0h/2h]Vpub5mXgECaX5yYDN"
assert e.next_part() == "p2of4 c5VnUG4jVNptyEg65qUjuofWchQeuMWWiq8rcPBo"
@@ -91,7 +91,7 @@ def test_ur_xpub_qr():
mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash"
e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.URXPUBQR, network="test", derivation="m/48h/1h/0h/2h", qr_density=EncodeQR.DENSITY__MEDIUM)
e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.XPUB__UR, network="test", derivation="m/48h/1h/0h/2h", qr_density=EncodeQR.DENSITY__MEDIUM)
assert e.next_part() == "UR:CRYPTO-ACCOUNT/1-4/LPADAACSJKCYYNRDRTYAHDCAOEADCYSSMECPONAOLYTAADMETAADDLOXAXHDCLAOKSRLNLKPUEGYATHPMNRTAAOLAH"
assert e.next_part() == "UR:CRYPTO-ACCOUNT/2-4/LPAOAACSJKCYYNRDRTYAHDCASNKKGHZMLUZORPVDGUOTECSTTKTOLPCWPTNTLKZTTIZTBEAAHDCXVDTPMYQDLAWNGL"
+18 -17
View File
@@ -6,6 +6,7 @@ from seedsigner.helpers.ur2.bytewords import decode
from seedsigner.models.decode_qr import DecodeQR, DecodeQRStatus
from seedsigner.models.encode_qr import EncodeQR
from seedsigner.models.qr_type import QRType
from seedsigner.models.settings import SettingsConstants
def run_encode_decode_test(entropy: bytes, mnemonic_length, qr_type):
@@ -27,11 +28,11 @@ def run_encode_decode_test(entropy: bytes, mnemonic_length, qr_type):
border=3
)
decoder = DecodeQR(wordlist=bip39.WORDLIST)
status = decoder.addImage(image)
decoder = DecodeQR(wordlist_language_code=SettingsConstants.LANGUAGE__ENGLISH)
status = decoder.add_image(image)
assert status == DecodeQRStatus.COMPLETE
decoded_seed_phrase = decoder.getSeedPhrase()
decoded_seed_phrase = decoder.get_seed_phrase()
print(decoded_seed_phrase)
assert seed_phrase == decoded_seed_phrase
@@ -42,10 +43,10 @@ def test_standard_seedqr_encode_decode_():
them back again to their original mnemonic seed phrase.
"""
# 24-word seed
run_encode_decode_test(os.urandom(32), mnemonic_length=24, qr_type=QRType.SEEDQR)
run_encode_decode_test(os.urandom(32), mnemonic_length=24, qr_type=QRType.SEED__SEEDQR)
# 12-word seed
run_encode_decode_test(os.urandom(16), mnemonic_length=12, qr_type=QRType.SEEDQR)
run_encode_decode_test(os.urandom(16), mnemonic_length=12, qr_type=QRType.SEED__SEEDQR)
@@ -54,10 +55,10 @@ def test_compact_seedqr_encode_decode():
them back again to their original mnemonic seed phrase.
"""
# 24-word seed
run_encode_decode_test(os.urandom(32), mnemonic_length=24, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(os.urandom(32), mnemonic_length=24, qr_type=QRType.SEED__COMPACTSEEDQR)
# 12-word seed
run_encode_decode_test(os.urandom(16), mnemonic_length=12, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(os.urandom(16), mnemonic_length=12, qr_type=QRType.SEED__COMPACTSEEDQR)
@@ -67,40 +68,40 @@ def test_compact_seedqr_handles_null_bytes():
"""
# 24-word seed, null bytes at the front
entropy = b'\x00' + os.urandom(31)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.SEED__COMPACTSEEDQR)
# 24-word seed, null bytes in the middle
entropy = os.urandom(10) + b'\x00' + os.urandom(21)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.SEED__COMPACTSEEDQR)
# 24-word seed, null bytes at the end
entropy = os.urandom(31) + b'\x00'
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.SEED__COMPACTSEEDQR)
# 24-word seed, multiple null bytes
entropy = os.urandom(5) + b'\x00' + os.urandom(5) + b'\x00' + os.urandom(20)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.SEED__COMPACTSEEDQR)
# 24-word seed, multiple null bytes in a row
entropy = os.urandom(10) + b'\x00\x00' + os.urandom(20)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=24, qr_type=QRType.SEED__COMPACTSEEDQR)
# 12-word seed, null bytes at the beginning
entropy = b'\x00' + os.urandom(15)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.SEED__COMPACTSEEDQR)
# 12-word seed, null bytes in the middle
entropy = os.urandom(5) + b'\x00' + os.urandom(10)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.SEED__COMPACTSEEDQR)
# 12-word seed, null bytes at the end
entropy = os.urandom(15) + b'\x00'
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.SEED__COMPACTSEEDQR)
# 12-word seed, multiple null bytes
entropy = os.urandom(5) + b'\x00' + os.urandom(5) + b'\x00' + os.urandom(4)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.SEED__COMPACTSEEDQR)
# 12-word seed, multiple null bytes in a row
entropy = os.urandom(10) + b'\x00\x00' + os.urandom(4)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.COMPACTSEEDQR)
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.SEED__COMPACTSEEDQR)