This commit is contained in:
scgbckbone 2025-06-17 15:53:38 +02:00
parent f70b3247e4
commit 9cd60433e7
2 changed files with 20 additions and 45 deletions

View File

@ -218,11 +218,9 @@ class MiniScriptWallet(BaseStorageWallet):
return branch, idx
def get_my_deriv(self, my_xfp):
# TODO we can have more our keys in descriptor
# maybe lowest account/change index should be chosen
for e in self.xfp_paths():
if e[0] == my_xfp:
return keypath_to_str(e)
# lowest public key from lexicographically sorted list is at index 0
mine = self.xpubs_from_xfp(my_xfp)
return mine[0].origin.str_derivation()
def derive_desc(self, xfp_paths):
branch, idx = self.subderivation_indexes(xfp_paths)
@ -625,53 +623,38 @@ class MiniScriptWallet(BaseStorageWallet):
if xfp == k.origin.cc_fp:
res.append(k)
return res
assert res, "missing xfp %s" % xfp2str(xfp)
# returned is list of keys with corresponding master xfp
# key in list are lexicographically sorted based on their public keys
# lowes public key first
return sorted(res, key=lambda o: o.serialize())
def kt_make_rxkey(self, xfp):
# Derive the receiver's pubkey from preshared xpub and a special derivation
# - also provide the keypair we're using from our side of connection
# - returns 4 byte nonce which is sent un-encrypted, his_pubkey and my_keypair
ri = ngu.random.uniform(1<<28)
keys = self.xpubs_from_xfp(xfp)
if not keys:
raise RuntimeError("missing xfp")
elif len(keys) > 1:
# what to do here, out key is there more than once but has different origin derivation
print("len keys is more than 1", keys)
# sorted lexicographically, always use the lowest pubkey from the list at index 0
keys = self.xpubs_from_xfp(xfp)
k = keys[0]
k = k.derive(KT_RXPUBKEY_DERIV).derive(ri)
pubkey = k.node.pubkey()
kp = self.kt_my_keypair(ri)
#print("psbt sender: ri=%d toward xfp: %s ... %s" % (ri, xfp2str(xfp), B2A(pubkey)))
return ri.to_bytes(4, 'big'), pubkey, kp
def kt_my_keypair(self, ri):
# Calc my keypair for sending PSBT files.
#
my_xfp = settings.get('xfp')
keys = self.xpubs_from_xfp(my_xfp)
assert keys
the_key = keys[0]
# including xfp(bytes) at index 0
deriv = the_key.origin.psbt_derivation()
deriv.append(KT_RXPUBKEY_DERIV)
deriv.append(ri)
# skip index 0 where xfp is
path = keypath_to_str(deriv)
# sorted lexicographically, always use the lowest pubkey from the list at index 0
keys = self.xpubs_from_xfp(settings.get('xfp'))
subpath = "/%d/%d" % (KT_RXPUBKEY_DERIV, ri)
path = keys[0].origin.str_derivation() + subpath
with stash.SensitiveValues() as sv:
node = sv.derive_path(path)
kp = ngu.secp256k1.keypair(node.privkey())
#print("my keypair: ri=%d my_xfp=%s ... %s" % (
# ri, xfp2str(my_xfp), B2A(kp.pubkey().to_bytes())))
return kp
@classmethod
@ -691,17 +674,12 @@ class MiniScriptWallet(BaseStorageWallet):
kp = msc.kt_my_keypair(ri)
for k in msc.keys:
kk = Key.from_string(k)
if kk.origin.cc_fp == my_xfp: continue
if kk.origin.cc_fp == my_xfp:
continue
kk = kk.derive(KT_RXPUBKEY_DERIV).derive(ri)
his_pubkey = kk.node.pubkey()
#print("try decode: ri=%d toward xfp: %s ... from %s <= to %s" % (
# ri, xfp2str(xfp), B2A(his_pubkey), B2A(kp.pubkey().to_bytes())), end=' ... ')
# if implied session key decodes the checksum, it is right
ses_key, body = decode_step1(kp, his_pubkey, payload[4:])
if ses_key:
return ses_key, body, kk.origin.cc_fp

View File

@ -723,7 +723,7 @@ def test_send_backup(testcase, rx_start, tx_start, cap_menu, enter_complex, pick
@pytest.mark.parametrize("taproot", [True, False])
@pytest.mark.parametrize("keys", [True, False, None])
@pytest.mark.parametrize("policy", [
"thresh(4,pk(@0),s:pk(@1),s:pk(@2),s:pk(@3),sln:older(SEQ))",
"thresh(4,pk(@0),s:pk(@1),s:pk(@2),s:pk(@3),sln:older(12960))",
])
def test_teleport_miniscript_sign(dev, taproot, policy, get_cc_key, bitcoind, use_regtest,
clear_miniscript, set_bip39_pw, press_select, pick_menu_item,
@ -734,15 +734,12 @@ def test_teleport_miniscript_sign(dev, taproot, policy, get_cc_key, bitcoind, us
reset_seed_words()
use_regtest()
clear_miniscript()
sequence = 5
locktime = 0
policy = policy.replace("SEQ", str(sequence))
# bitcoin core is PSBT provider
name = "msc_tele"
wo = bitcoind.create_wallet(name, disable_private_keys=True, blank=True)
deriv = "86h/%dh/0h" if taproot else "48h/1h/%dh/2h"
deriv = "86h/1h/%dh" if taproot else "48h/1h/%dh/2h"
if keys is True:
# actually just 2 signers - both with 2 keys with different subderivation (change based)
deriv = deriv % 0
@ -758,7 +755,7 @@ def test_teleport_miniscript_sign(dev, taproot, policy, get_cc_key, bitcoind, us
signers = [keys[0], keys[2]]
elif keys is False:
# 3 signers, account based
# 3 signers, 1 signer has two keys with different account derivation index
keys = [get_cc_key(deriv % 0)]
for i in range(1, 3):
seed = Mnemonic.to_seed(simulator_fixed_words, passphrase=str(i)+str(i))
@ -827,7 +824,7 @@ def test_teleport_miniscript_sign(dev, taproot, policy, get_cc_key, bitcoind, us
psbt_resp = wo.walletcreatefundedpsbt(
[],
[{bitcoind.supply_wallet.getnewaddress(): 2.5}],
locktime,
0,
{"fee_rate": 2, "change_type": af},
)
psbt = psbt_resp.get("psbt")