WIF store testing

This commit is contained in:
scgbckbone 2026-03-05 18:46:35 +01:00 committed by Peter D. Gray
parent 01629e1396
commit 12e0af3f5c
No known key found for this signature in database
GPG Key ID: A2DCD558C2BE5D7C
8 changed files with 378 additions and 373 deletions

View File

@ -3024,6 +3024,7 @@ from test_drv_entro import derive_bip85_secret, activate_bip85_ephemeral
from test_ephemeral import generate_ephemeral_words, import_ephemeral_xprv, goto_eph_seed_menu
from test_ephemeral import ephemeral_seed_disabled_ui, restore_main_seed, confirm_tmp_seed
from test_ephemeral import verify_ephemeral_secret_ui, get_identity_story, get_seed_value_ux, seed_vault_enable
from test_hobble import set_hobble
from test_msg import verify_msg_sign_story, sign_msg_from_text, msg_sign_export, sign_msg_from_address
from test_multisig import import_ms_wallet, make_multisig, offer_ms_import, fake_ms_txn
from test_multisig import make_ms_address, clear_ms, make_myself_wallet, import_multisig

View File

@ -367,7 +367,7 @@ def main():
for test_module in sorted(list(test_modules)):
sim_args = DEFAULT_SIMULATOR_ARGS
if test_module in ["test_bsms.py", "test_address_explorer.py", "test_export.py",
"test_multisig.py", "test_ux.py"]:
"test_multisig.py", "test_ux.py", "test_wif.py"]:
sim_args = DEFAULT_SIMULATOR_ARGS + ["--set", "vidsk=1"]
if test_module == "test_vdisk.py":
sim_args = ["--eject"] + DEFAULT_SIMULATOR_ARGS + ["--set", "vidsk=1"]

View File

@ -18,7 +18,6 @@
#
import pytest, time, os, pdb
from bip32 import BIP32Node
from base58 import encode_base58_checksum
from constants import simulator_fixed_words, simulator_fixed_xprv
from test_ephemeral import SEEDVAULT_TEST_DATA, WORDLISTS
from test_ephemeral import confirm_tmp_seed, verify_ephemeral_secret_ui
@ -395,38 +394,6 @@ def test_h_tempseeds(mode, set_hobble, pick_menu_item, cap_menu, settings_set, i
press_select()
@pytest.mark.parametrize('en_okeys', [ True, False])
def test_h_wif_store(en_okeys, set_hobble, settings_remove, import_wif_to_store, goto_home,
cap_menu, pick_menu_item):
settings_remove("wifs")
wif_list = [
encode_base58_checksum(bytes([239]) + os.urandom(32) + b'\x01')
for _ in range(3)
]
import_wif_to_store(wif_list)
goto_home()
set_hobble(True, {'okeys'} if en_okeys else {})
pick_menu_item("Advanced/Tools")
if en_okeys:
pick_menu_item("WIF Store")
time.sleep(.1)
menu = cap_menu()
# check it is read-only
assert "Import WIF" not in menu
assert "Clear All" not in menu
pick_menu_item(menu[0])
time.sleep(.1)
menu = cap_menu()
assert "Delete" not in menu
else:
assert "WIF Store" not in cap_menu()
@pytest.mark.parametrize('en_okeys', [ True, False])
def test_h_usbcmds(en_okeys, set_hobble, dev):
# test various usb commands are blocked during hobble

View File

@ -6,7 +6,6 @@ import pytest, time, os, itertools, hashlib, json
from bip32 import BIP32Node
from msg import verify_message, RFC_SIGNATURE_TEMPLATE, sign_message, parse_signed_message
from base64 import b64encode, b64decode
from base58 import encode_base58_checksum
from ckcc_protocol.protocol import CCProtocolPacker, CCProtoError, CCUserRefused
from ckcc_protocol.constants import *
from constants import addr_fmt_names, msg_sign_unmap_addr_fmt
@ -1041,65 +1040,4 @@ def test_verify_scanned_signed_msg(msg, scan_a_qr, need_keypress, goto_home, cap
assert "Good signature by address" in story
assert addr == addr_from_display_format(story.split("\n")[-1])
@pytest.mark.parametrize("way,af", [
("sd", "P2SH-Segwit"),
("input", "Segwit P2WPKH"),
("nfc", "Classic P2PKH")
])
def test_sign_msg_with_wif_store_key(way, af, settings_remove, import_wif_to_store, cap_menu,
pick_menu_item, cap_story, need_keypress, press_nfc,
enter_complex, garbage_collector, microsd_path, nfc_write_text,
verify_msg_sign_story, msg_sign_export, press_select, goto_home):
settings_remove("wifs")
msg = "Coinkite"
n = BIP32Node.from_master_secret(os.urandom(32))
privkey = n.node.private_key
import_wif_to_store([encode_base58_checksum(bytes([239]) + bytes(privkey) + b'\x01')])
menu = cap_menu()
assert len(menu) == 2
pick_menu_item(menu[1])
pick_menu_item("Sign MSG")
pick_menu_item(af)
if way == "input":
need_keypress("0")
enter_complex(msg, apply=False, b39pass=False)
elif way == "sd":
name = "msg_to_sign.txt"
pth = microsd_path(name)
with open(pth, "w") as f:
f.write(msg)
need_keypress("1")
pick_menu_item(name)
elif way == "nfc":
press_nfc()
time.sleep(0.2)
nfc_write_text(msg)
time.sleep(0.3)
else:
raise NotImplementedError
time.sleep(.1)
title, story = cap_story()
addr_fmt = {"P2SH-Segwit": "p2sh-p2wpkh",
"Segwit P2WPKH": "p2wpkh",
"Classic P2PKH": "p2pkh"}[af]
target_addr = n.address(addr_fmt=addr_fmt)
verify_msg_sign_story(story, msg, "m", addr=target_addr)
press_select()
res = msg_sign_export(way if way != "input" else "sd")
assert target_addr in res
pmsg, addr, sig = parse_signed_message(res)
assert pmsg == msg
assert verify_message(addr, sig, msg) is True
goto_home()
# EOF

View File

@ -4275,68 +4275,4 @@ def test_txin_explorer_our_sig(dev, fake_ms_txn, start_sign, settings_set, clear
start_sign(psbt)
txin_explorer(num_ins, [(af, inp_amount, 0, "XTN", (M,N), None, None, False, [my_xfp])])
@pytest.mark.parametrize("addr_fmt", ["p2wsh", "p2sh-p2wsh", "p2sh"])
def test_wif_store(addr_fmt, dev, fake_ms_txn, start_sign, settings_set, clear_ms,
cap_story, pytestconfig, import_ms_wallet, end_sign, settings_remove):
# TODO This test MUST be run with --psbt2 flag on and off
clear_ms()
settings_remove("wifs")
M, N = 3, 5
if addr_fmt == AF_P2SH:
dd = "m/45h"
elif addr_fmt == AF_P2WSH:
dd = "m/48h/1h/0h/2h"
else:
dd = "m/48h/1h/0h/1h"
def path_mapper(idx):
kk = str_to_path(dd)
return kk + [0,0]
keys = import_ms_wallet(M, N, name='wif_store', accept=True, netcode="XTN",
descriptor=True, addr_fmt=addr_fmt, common=dd)
psbt = fake_ms_txn(1, 1, M, keys, inp_af=unmap_addr_fmt[addr_fmt],
path_mapper=path_mapper, psbt_v2=pytestconfig.getoption('psbt2'))
# sign with master key first - nothing in WIF store
# without warning
# one signature from master added
start_sign(psbt)
title, story = cap_story()
assert "warning" not in story
signed = end_sign()
po = BasicPSBT().parse(signed)
assert len(po.inputs[0].part_sigs) == 1
# add privkey from 0th & 1st node to WIF store
der_node0 = keys[0][1].subkey_for_path(dd[2:] + "/0/0")
sk0 = bytes(der_node0.node.private_key).hex()
pk0 = der_node0.node.private_key.K.sec().hex()
der_node1 = keys[1][1].subkey_for_path(dd[2:] + "/0/0")
sk1 = bytes(der_node1.node.private_key).hex()
pk1 = der_node1.node.private_key.K.sec().hex()
settings_set("wifs", [(pk0,sk0), (pk1,sk1)])
# ofe of the private keys will be used for signing
# only one as we cannot sign with 2 keys in one sitting
start_sign(signed)
title, story = cap_story()
assert "warning" in story
assert "WIF store" in story
signed = end_sign()
po = BasicPSBT().parse(signed)
assert len(po.inputs[0].part_sigs) == 2
# sign with other key - keys that already have signatures are ignored
# that is why we can proceed with this iterative method
start_sign(signed, finalize=True)
title, story = cap_story()
assert "warning" in story
assert "WIF store" in story
end_sign(finalize=True)
# EOF

View File

@ -699,65 +699,4 @@ def test_named_wallet_search(wname, valid, method, clear_ms, import_ms_wallet, i
assert "1 wallet(s)" in story
assert 'without finding a match' in story
@pytest.mark.parametrize("addr_fmt", ["p2wpkh", "p2sh-p2wpkh", "p2pkh"])
@pytest.mark.parametrize("idx", [1, 3])
def test_wif_store(addr_fmt, idx, is_q1, goto_home, pick_menu_item, scan_a_qr, cap_story, need_keypress,
src_root_dir, sim_root_dir, nfc_write, settings_remove, import_wif_to_store,
load_shared_mod, cap_screen_qr, press_cancel):
settings_remove("wifs")
n = BIP32Node.from_master_secret(os.urandom(32))
privkey = n.node.private_key
addr = n.address(addr_fmt=addr_fmt)
wif = encode_base58_checksum(bytes([239]) + bytes(privkey) + b'\x01')
wif1 = encode_base58_checksum(bytes([239]) + os.urandom(32) + b'\x01')
wif2 = encode_base58_checksum(bytes([239]) + os.urandom(32) + b'\x01')
if idx == 1:
wif_list = [wif, wif1, wif2]
else:
wif_list = [wif1, wif2, wif]
import_wif_to_store(wif_list)
goto_home()
if is_q1:
pick_menu_item('Scan Any QR Code')
scan_a_qr(addr)
time.sleep(1)
title, story = cap_story()
assert addr == addr_from_display_format(story.split("\n\n")[0])
assert '(1) to verify ownership' in story
need_keypress('1')
else:
cc_ndef = load_shared_mod('cc_ndef', f'{src_root_dir}/shared/ndef.py')
n = cc_ndef.ndefMaker()
n.add_text(addr)
ccfile = n.bytes()
pick_menu_item('Advanced/Tools')
pick_menu_item('NFC Tools')
pick_menu_item('Verify Address')
with open(f'{sim_root_dir}/debug/nfc-addr.ndef', 'wb') as f:
f.write(ccfile)
nfc_write(ccfile)
time.sleep(1)
title, story = cap_story()
assert addr == addr_from_display_format(story.split("\n\n")[0])
assert f"Found in WIF store at index {idx}" in story
need_keypress(KEY_QR if is_q1 else '1')
addr_qr = cap_screen_qr().decode()
if addr_fmt == "p2wpkh":
addr_qr = addr_qr.lower()
assert addr == addr_qr
press_cancel()
# EOF

View File

@ -21,7 +21,6 @@ from txn import *
from ctransaction import CTransaction, CTxOut, CTxIn, COutPoint
from ckcc_protocol.constants import STXN_VISUALIZE, STXN_SIGNED
from charcodes import KEY_QR, KEY_RIGHT, KEY_LEFT
from bip322 import bip322_msg_hash
SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22)
@ -3667,152 +3666,4 @@ def test_txid_qr(fake_txn, start_sign, cap_story, press_cancel, press_select):
assert "(6) for QR Code of TXID" in story
press_cancel()
@pytest.mark.parametrize("num_ins", [1, 5])
@pytest.mark.parametrize("addr_fmt", ["p2pkh", "p2wpkh", "p2sh-p2wpkh"])
def test_wif_store_signing(num_ins, addr_fmt, fake_txn, goto_home, pick_menu_item, need_keypress,
start_sign, end_sign, cap_menu, cap_story, press_cancel, settings_remove,
press_select, import_wif_to_store):
settings_remove("wifs")
wrap = False
if addr_fmt == "p2pkh":
sw = False
elif addr_fmt == "p2wpkh":
sw = True
elif addr_fmt == "p2sh-p2wpkh":
wrap = True
sw = True
else:
raise ValueError
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(num_ins, 1, segwit_in=sw, wrapped=wrap, master_xpub=node.hwif())
wifs = []
privkeys = []
for i in range(num_ins):
n = node.subkey_for_path("0/%d" % i)
sk = n.node.private_key
privkeys.append(sk)
wifs.append(n.node.private_key.wif(testnet=True))
import_wif_to_store(wifs)
menu = cap_menu()
assert menu[0] == "Import WIF"
start_sign(psbt, finalize=True)
time.sleep(.1)
title, story = cap_story()
assert "warning" in story
if num_ins == 1:
assert "WIF store: 0" in story
else:
assert f"WIF store: {', '.join([str(i) for i in range(num_ins)])}" in story
end_sign(finalize=True)
@pytest.mark.parametrize("der_paths", [True, False])
@pytest.mark.parametrize("complete", [True, False])
def test_wif_store_multi(der_paths, complete, fake_txn, start_sign, end_sign, cap_story, settings_set):
wifs = []
hack = None
if der_paths:
def hack(psbt):
new_paths = {}
for k, v in psbt.inputs[0].bip32_paths.items():
new_paths[k] = b"\x01" * 8 # garbage (do not use zero xfp here)
psbt.inputs[0].bip32_paths = new_paths
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=True, master_xpub=node.hwif(), psbt_v2=True, outvals=[1E8*3],
psbt_hacker=hack)
po = BasicPSBT().parse(psbt)
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=False, master_xpub=node.hwif(), psbt_v2=True, psbt_hacker=hack)
tmp = BasicPSBT().parse(psbt)
po.inputs += tmp.inputs
po.input_count += 1
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=True, wrapped=True, master_xpub=node.hwif(), psbt_v2=True,
psbt_hacker=hack)
tmp = BasicPSBT().parse(psbt)
po.inputs += tmp.inputs
po.input_count += 1
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
# pretend we have those imported
if not complete:
wifs = wifs[:-1]
settings_set("wifs", wifs)
start_sign(po.as_bytes(), finalize=complete)
title, story = cap_story()
assert "warning" in story
if complete:
assert "WIF store: 0, 1, 2" in story
else:
assert "WIF store: 0, 1" in story
assert "Limited Signing" in story
end_sign(finalize=complete)
def test_wif_store_with_master(fake_txn, start_sign, end_sign, cap_story, settings_set):
# signs both master key and keys from WIF store
wifs = []
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=True, master_xpub=node.hwif(), psbt_v2=True, outvals=[1E8*3])
po = BasicPSBT().parse(psbt)
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=False, master_xpub=node.hwif(), psbt_v2=True)
tmp = BasicPSBT().parse(psbt)
po.inputs += tmp.inputs
po.input_count += 1
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
# add simulator input
psbt = fake_txn(1, 1, segwit_in=True, psbt_v2=True)
tmp = BasicPSBT().parse(psbt)
po.inputs += tmp.inputs
po.input_count += 1
settings_set("wifs", wifs)
# convert to v0 PSBT just for fun
start_sign(po.to_v0(), finalize=True)
title, story = cap_story()
assert "warning" in story
assert "WIF store: 0, 1" in story
end_sign(finalize=True)
# EOF

View File

@ -1,10 +1,14 @@
# (c) Copyright 2026 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
import pytest, time, os, re, hashlib, shutil
import pytest, time, os
from helpers import prandom, addr_from_display_format
from charcodes import KEY_DOWN, KEY_QR, KEY_NFC, KEY_DELETE, KEY_UP
from charcodes import KEY_QR, KEY_NFC, KEY_UP
from constants import unmap_addr_fmt, AF_P2WSH, AF_P2SH
from bip32 import BIP32Node, PrivateKey
from base58 import encode_base58_checksum
from msg import verify_message, parse_signed_message
from psbt import BasicPSBT
from helpers import str_to_path
def make_fake_wif(prefix=239):
@ -352,7 +356,7 @@ def test_wif_store_import_duplicate(settings_remove, import_wif_to_store, settin
@pytest.mark.parametrize("way", ["qr", "sd", "nfc"])
def test_wif_store_export_all(way, goto_home, settings_remove, import_wif_to_store, pick_menu_item,
load_export):
load_export, press_cancel):
goto_home()
settings_remove("wifs")
@ -364,5 +368,374 @@ def test_wif_store_export_all(way, goto_home, settings_remove, import_wif_to_sto
conts = load_export(way, "WIF Store", is_json=False, sig_check=False)
assert wif_list == conts.split("\n")
press_cancel()
@pytest.mark.parametrize('en_okeys', [ True, False])
def test_hobbled_wif_store(en_okeys, set_hobble, settings_remove, import_wif_to_store, goto_home,
cap_menu, pick_menu_item):
goto_home()
settings_remove("wifs")
wif_list = [
encode_base58_checksum(bytes([239]) + os.urandom(32) + b'\x01')
for _ in range(3)
]
import_wif_to_store(wif_list)
goto_home()
set_hobble(True, {'okeys'} if en_okeys else {})
pick_menu_item("Advanced/Tools")
if en_okeys:
pick_menu_item("WIF Store")
time.sleep(.1)
menu = cap_menu()
# check it is read-only
assert "Import WIF" not in menu
assert "Clear All" not in menu
pick_menu_item(menu[0])
time.sleep(.1)
menu = cap_menu()
assert "Delete" not in menu
else:
assert "WIF Store" not in cap_menu()
@pytest.mark.parametrize("way,af", [
("sd", "P2SH-Segwit"),
("input", "Segwit P2WPKH"),
("nfc", "Classic P2PKH")
])
def test_sign_msg_with_wif_store_key(way, af, settings_remove, import_wif_to_store, cap_menu,
pick_menu_item, cap_story, need_keypress, press_nfc,
enter_complex, garbage_collector, microsd_path, nfc_write_text,
verify_msg_sign_story, msg_sign_export, press_select, goto_home):
settings_remove("wifs")
msg = "Coinkite"
n = BIP32Node.from_master_secret(os.urandom(32))
privkey = n.node.private_key
import_wif_to_store([encode_base58_checksum(bytes([239]) + bytes(privkey) + b'\x01')])
menu = cap_menu()
assert len(menu) == 2
pick_menu_item(menu[1])
pick_menu_item("Sign MSG")
pick_menu_item(af)
if way == "input":
need_keypress("0")
enter_complex(msg, apply=False, b39pass=False)
elif way == "sd":
name = "msg_to_sign.txt"
pth = microsd_path(name)
with open(pth, "w") as f:
f.write(msg)
need_keypress("1")
pick_menu_item(name)
elif way == "nfc":
press_nfc()
time.sleep(0.2)
nfc_write_text(msg)
time.sleep(0.3)
else:
raise NotImplementedError
time.sleep(.1)
title, story = cap_story()
addr_fmt = {"P2SH-Segwit": "p2sh-p2wpkh",
"Segwit P2WPKH": "p2wpkh",
"Classic P2PKH": "p2pkh"}[af]
target_addr = n.address(addr_fmt=addr_fmt)
verify_msg_sign_story(story, msg, "m", addr=target_addr)
press_select()
res = msg_sign_export(way if way != "input" else "sd")
assert target_addr in res
pmsg, addr, sig = parse_signed_message(res)
assert pmsg == msg
assert verify_message(addr, sig, msg) is True
goto_home()
@pytest.mark.parametrize("addr_fmt", ["p2wsh", "p2sh-p2wsh", "p2sh"])
def test_multisig_wif_store(addr_fmt, dev, fake_ms_txn, start_sign, settings_set, clear_ms,
cap_story, pytestconfig, import_ms_wallet, end_sign, settings_remove):
# TODO This test MUST be run with --psbt2 flag on and off
clear_ms()
settings_remove("wifs")
M, N = 3, 5
if addr_fmt == AF_P2SH:
dd = "m/45h"
elif addr_fmt == AF_P2WSH:
dd = "m/48h/1h/0h/2h"
else:
dd = "m/48h/1h/0h/1h"
def path_mapper(idx):
kk = str_to_path(dd)
return kk + [0,0]
keys = import_ms_wallet(M, N, name='wif_store', accept=True, netcode="XTN",
descriptor=True, addr_fmt=addr_fmt, common=dd)
psbt = fake_ms_txn(1, 1, M, keys, inp_af=unmap_addr_fmt[addr_fmt],
path_mapper=path_mapper, psbt_v2=pytestconfig.getoption('psbt2'))
# sign with master key first - nothing in WIF store
# without warning
# one signature from master added
start_sign(psbt)
title, story = cap_story()
assert "warning" not in story
signed = end_sign()
po = BasicPSBT().parse(signed)
assert len(po.inputs[0].part_sigs) == 1
# add privkey from 0th & 1st node to WIF store
der_node0 = keys[0][1].subkey_for_path(dd[2:] + "/0/0")
sk0 = bytes(der_node0.node.private_key).hex()
pk0 = der_node0.node.private_key.K.sec().hex()
der_node1 = keys[1][1].subkey_for_path(dd[2:] + "/0/0")
sk1 = bytes(der_node1.node.private_key).hex()
pk1 = der_node1.node.private_key.K.sec().hex()
settings_set("wifs", [(pk0,sk0), (pk1,sk1)])
# ofe of the private keys will be used for signing
# only one as we cannot sign with 2 keys in one sitting
start_sign(signed)
title, story = cap_story()
assert "warning" in story
assert "WIF store" in story
signed = end_sign()
po = BasicPSBT().parse(signed)
assert len(po.inputs[0].part_sigs) == 2
# sign with other key - keys that already have signatures are ignored
# that is why we can proceed with this iterative method
start_sign(signed, finalize=True)
title, story = cap_story()
assert "warning" in story
assert "WIF store" in story
end_sign(finalize=True)
@pytest.mark.parametrize("addr_fmt", ["p2wpkh", "p2sh-p2wpkh", "p2pkh"])
@pytest.mark.parametrize("idx", [1, 3])
def test_wif_store_ownership(addr_fmt, idx, is_q1, goto_home, pick_menu_item, scan_a_qr, cap_story,
need_keypress, src_root_dir, sim_root_dir, nfc_write, settings_remove,
import_wif_to_store, load_shared_mod, cap_screen_qr, press_cancel):
settings_remove("wifs")
n = BIP32Node.from_master_secret(os.urandom(32))
privkey = n.node.private_key
addr = n.address(addr_fmt=addr_fmt)
wif = encode_base58_checksum(bytes([239]) + bytes(privkey) + b'\x01')
wif1 = encode_base58_checksum(bytes([239]) + os.urandom(32) + b'\x01')
wif2 = encode_base58_checksum(bytes([239]) + os.urandom(32) + b'\x01')
if idx == 1:
wif_list = [wif, wif1, wif2]
else:
wif_list = [wif1, wif2, wif]
import_wif_to_store(wif_list)
goto_home()
if is_q1:
pick_menu_item('Scan Any QR Code')
scan_a_qr(addr)
time.sleep(1)
title, story = cap_story()
assert addr == addr_from_display_format(story.split("\n\n")[0])
assert '(1) to verify ownership' in story
need_keypress('1')
else:
cc_ndef = load_shared_mod('cc_ndef', f'{src_root_dir}/shared/ndef.py')
n = cc_ndef.ndefMaker()
n.add_text(addr)
ccfile = n.bytes()
pick_menu_item('Advanced/Tools')
pick_menu_item('NFC Tools')
pick_menu_item('Verify Address')
with open(f'{sim_root_dir}/debug/nfc-addr.ndef', 'wb') as f:
f.write(ccfile)
nfc_write(ccfile)
time.sleep(1)
title, story = cap_story()
assert addr == addr_from_display_format(story.split("\n\n")[0])
assert f"Found in WIF store at index {idx}" in story
need_keypress(KEY_QR if is_q1 else '1')
addr_qr = cap_screen_qr().decode()
if addr_fmt == "p2wpkh":
addr_qr = addr_qr.lower()
assert addr == addr_qr
press_cancel()
@pytest.mark.parametrize("num_ins", [1, 5])
@pytest.mark.parametrize("addr_fmt", ["p2pkh", "p2wpkh", "p2sh-p2wpkh"])
def test_wif_store_signing(num_ins, addr_fmt, fake_txn, goto_home, pick_menu_item, need_keypress,
start_sign, end_sign, cap_menu, cap_story, press_cancel, settings_remove,
press_select, import_wif_to_store):
settings_remove("wifs")
wrap = False
if addr_fmt == "p2pkh":
sw = False
elif addr_fmt == "p2wpkh":
sw = True
elif addr_fmt == "p2sh-p2wpkh":
wrap = True
sw = True
else:
raise ValueError
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(num_ins, 1, segwit_in=sw, wrapped=wrap, master_xpub=node.hwif())
wifs = []
privkeys = []
for i in range(num_ins):
n = node.subkey_for_path("0/%d" % i)
sk = n.node.private_key
privkeys.append(sk)
wifs.append(n.node.private_key.wif(testnet=True))
import_wif_to_store(wifs)
menu = cap_menu()
assert menu[0] == "Import WIF"
start_sign(psbt, finalize=True)
time.sleep(.1)
title, story = cap_story()
assert "warning" in story
if num_ins == 1:
assert "WIF store: 0" in story
else:
assert f"WIF store: {', '.join([str(i) for i in range(num_ins)])}" in story
end_sign(finalize=True)
@pytest.mark.parametrize("der_paths", [True, False])
@pytest.mark.parametrize("complete", [True, False])
def test_wif_store_signing_multi(der_paths, complete, fake_txn, start_sign, end_sign, cap_story,
settings_set):
wifs = []
hack = None
if der_paths:
def hack(psbt):
new_paths = {}
for k, v in psbt.inputs[0].bip32_paths.items():
new_paths[k] = b"\x01" * 8 # garbage (do not use zero xfp here)
psbt.inputs[0].bip32_paths = new_paths
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=True, master_xpub=node.hwif(), psbt_v2=True, outvals=[1E8*3],
psbt_hacker=hack)
po = BasicPSBT().parse(psbt)
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=False, master_xpub=node.hwif(), psbt_v2=True, psbt_hacker=hack)
tmp = BasicPSBT().parse(psbt)
po.inputs += tmp.inputs
po.input_count += 1
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=True, wrapped=True, master_xpub=node.hwif(), psbt_v2=True,
psbt_hacker=hack)
tmp = BasicPSBT().parse(psbt)
po.inputs += tmp.inputs
po.input_count += 1
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
# pretend we have those imported
if not complete:
wifs = wifs[:-1]
settings_set("wifs", wifs)
start_sign(po.as_bytes(), finalize=complete)
title, story = cap_story()
assert "warning" in story
if complete:
assert "WIF store: 0, 1, 2" in story
else:
assert "WIF store: 0, 1" in story
assert "Limited Signing" in story
end_sign(finalize=complete)
def test_wif_store_signing_with_master(fake_txn, start_sign, end_sign, cap_story, settings_set):
# signs both master key and keys from WIF store
wifs = []
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=True, master_xpub=node.hwif(), psbt_v2=True, outvals=[1E8*3])
po = BasicPSBT().parse(psbt)
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
node = BIP32Node.from_master_secret(os.urandom(32))
psbt = fake_txn(1, 1, segwit_in=False, master_xpub=node.hwif(), psbt_v2=True)
tmp = BasicPSBT().parse(psbt)
po.inputs += tmp.inputs
po.input_count += 1
n = node.subkey_for_path("0/0")
sk = bytes(n.node.private_key).hex()
pk = n.node.private_key.K.sec().hex()
wifs.append((pk, sk))
# add simulator input
psbt = fake_txn(1, 1, segwit_in=True, psbt_v2=True)
tmp = BasicPSBT().parse(psbt)
po.inputs += tmp.inputs
po.input_count += 1
settings_set("wifs", wifs)
# convert to v0 PSBT just for fun
start_sign(po.to_v0(), finalize=True)
title, story = cap_story()
assert "warning" in story
assert "WIF store: 0, 1" in story
end_sign(finalize=True)
# EOF