diff --git a/releases/ChangeLog.md b/releases/ChangeLog.md index 04502843..0503c8b9 100644 --- a/releases/ChangeLog.md +++ b/releases/ChangeLog.md @@ -11,7 +11,8 @@ - Bugfix: remove label from Bitcoin Core `importdescriptors` export as it is no longer supported with ranged descriptors in version `24.1` of Core. - Bugfix: empty number during BIP-39 passphrase entry could cause crash. -- Bugfix: UX: Signing with BIP39 Passphrase showed master fingerprint as integer. Fixed to show hex. +- Bugfix: UX: Signing with BIP39 Passphrase showed master fingerprint as integer. Fixed to show hex. +- Bugfix: Fixed inability to generate paper wallet without secrets ## 5.1.2 - 2023-04-07 diff --git a/shared/auth.py b/shared/auth.py index 889e9ca8..d23d5231 100644 --- a/shared/auth.py +++ b/shared/auth.py @@ -156,28 +156,29 @@ def sign_message_digest(digest, subpath, prompt, addr_fmt=AF_CLASSIC, pk=None): if prompt: dis.fullscreen(prompt, percent=.25) - with stash.SensitiveValues() as sv: - dis.progress_bar_show(.50) - if pk is None: - # if private key is provided, derivation subpath is ignored - # and provided private key is used for signing + if pk is None: + with stash.SensitiveValues() as sv: + # if private key is provided, derivation subpath is ignored + # and provided private key is used for signing node = sv.derive_path(subpath) + dis.progress_bar_show(.50) pk = node.privkey() - else: - node = ngu.hdnode.HDNode().from_chaincode_privkey(bytes(32), pk) + else: + node = ngu.hdnode.HDNode().from_chaincode_privkey(bytes(32), pk) + dis.progress_bar_show(.50) - addr = chains.current_chain().address(node, addr_fmt) - sv.register(pk) + ch = chains.current_chain() + addr = ch.address(node, addr_fmt) - dis.progress_bar_show(.75) - rv = ngu.secp256k1.sign(pk, digest, 0).to_bytes() - # AF_CLASSIC header byte base 31 is returned by default from ngu - NOOP - if addr_fmt != AF_CLASSIC: - header_byte, rs = rv[0], rv[1:] - # ngu only produces header base for compressed p2pkh, anyways get only rec_id - rec_id = (header_byte - 27) & 0x03 - new_header_byte = rec_id + sv.chain.sig_hdr_base(addr_fmt=addr_fmt) - rv = bytes([new_header_byte]) + rs + dis.progress_bar_show(.75) + rv = ngu.secp256k1.sign(pk, digest, 0).to_bytes() + # AF_CLASSIC header byte base 31 is returned by default from ngu - NOOP + if addr_fmt != AF_CLASSIC: + header_byte, rs = rv[0], rv[1:] + # ngu only produces header base for compressed p2pkh, anyways get only rec_id + rec_id = (header_byte - 27) & 0x03 + new_header_byte = rec_id + ch.sig_hdr_base(addr_fmt=addr_fmt) + rv = bytes([new_header_byte]) + rs dis.progress_bar_show(1) diff --git a/testing/test_paper.py b/testing/test_paper.py index dc80ebce..6873ccda 100644 --- a/testing/test_paper.py +++ b/testing/test_paper.py @@ -2,9 +2,12 @@ # # Tests for paper-wallet feature # +# Paper wallet features MUST work on both device with and without secrets. +# This module can and should be run with `-l` and without it. +# import random -import pytest, time, struct, os, shutil, re +import pytest, time, struct, os, shutil, re, json from pycoin.key.Key import Key from pycoin.encoding import from_bytes_32 from base64 import b64encode @@ -13,18 +16,20 @@ from hashlib import sha256 from ckcc_protocol.protocol import CCProtocolPacker, CCProtoError, CCUserRefused from ckcc_protocol.constants import * from helpers import xfp2str -import json from conftest import simulator_fixed_xfp, simulator_fixed_xprv from bech32 import bech32_decode, convertbits, Encoding -@pytest.mark.parametrize('mode', [ "classic", 'segwit']) -@pytest.mark.parametrize('pdf', [ False, True]) -def test_generate(mode, pdf, dev, cap_menu, pick_menu_item, goto_home, cap_story, need_keypress, - microsd_path, verify_detached_signature_file): +@pytest.mark.parametrize('mode', ["classic", 'segwit']) +@pytest.mark.parametrize('pdf', [False, True]) +@pytest.mark.parametrize('netcode', ["XTN", "BTC"]) +def test_generate(mode, pdf, netcode, dev, cap_menu, pick_menu_item, goto_home, cap_story, + need_keypress, microsd_path, verify_detached_signature_file, settings_set): # test UX and operation of the 'bitcoin core' wallet export mx = "Don't make PDF" + settings_set("chain", netcode) + goto_home() pick_menu_item('Advanced/Tools') try: @@ -111,7 +116,7 @@ def test_generate(mode, pdf, dev, cap_menu, pick_menu_item, goto_home, cap_story assert hrp in {'tb', 'bc', 'bcrt'} assert enc == Encoding.BECH32 decoded = convertbits(data[1:], 5, 8, False)[-20:] - addr = Key(hash160=bytes(decoded), is_compressed=True, netcode='XTN') + addr = Key(hash160=bytes(decoded), is_compressed=True, netcode=netcode) elif hdr == 'Private key:': # for QR case assert val == wif elif 'Private key' in hdr and 'WIF=Wallet' in hdr: @@ -217,10 +222,14 @@ def test_dice_generate_failure_distribution(rolls, dev, cap_menu, pick_menu_item "".join([str(random.SystemRandom().randint(1,6)) for _ in range(99)]), "".join([str(random.SystemRandom().randint(1,6)) for _ in range(99)]), ]) -def test_dice_generate(rolls, dev, cap_menu, pick_menu_item, goto_home, cap_story, need_keypress, - microsd_path, verify_detached_signature_file): +@pytest.mark.parametrize('netcode', ["XTN", "BTC"]) +def test_dice_generate(rolls, netcode, dev, cap_menu, pick_menu_item, goto_home, + cap_story, need_keypress, microsd_path, + verify_detached_signature_file, settings_set): # verify the math for dice rolling method + settings_set("chain", netcode) + goto_home() pick_menu_item('Advanced/Tools') try: @@ -281,12 +290,11 @@ def test_dice_generate(rolls, dev, cap_menu, pick_menu_item, goto_home, cap_stor assert len(hx) == 1 val, = hx - k2 = Key(secret_exponent=from_bytes_32(a2b_hex(val)), is_compressed=True, netcode='XTN') + k2 = Key(secret_exponent=from_bytes_32(a2b_hex(val)), is_compressed=True, netcode=netcode) assert addr == k2.address() assert val == sha256(rolls.encode('ascii')).hexdigest() os.unlink(path) - # EOF