Skip to content

Optionally pass BIP388 policy to signtx #792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion hwilib/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def signmessage_handler(args: argparse.Namespace, client: HardwareWalletClient)
return signmessage(client, message=args.message, path=args.path)

def signtx_handler(args: argparse.Namespace, client: HardwareWalletClient) -> Dict[str, Union[bool, str]]:
return signtx(client, psbt=args.psbt)
return signtx(client, psbt=args.psbt, policy_name=args.policy_name, descriptor_template=args.policy_desc, keys_info=args.key, hmac=args.hmac)

def wipe_device_handler(args: argparse.Namespace, client: HardwareWalletClient) -> Dict[str, bool]:
return wipe_device(client)
Expand Down Expand Up @@ -161,6 +161,11 @@ def get_parser() -> HWIArgumentParser:

signtx_parser = subparsers.add_parser('signtx', help='Sign a PSBT')
signtx_parser.add_argument('psbt', help='The Partially Signed Bitcoin Transaction to sign')
signtx_policy_group = signtx_parser.add_argument_group("BIP388 policy")
signtx_policy_group.add_argument('--policy-name', help='Registered policy name')
signtx_policy_group.add_argument('--policy-desc', help='Registered policy descriptor template')
signtx_policy_group.add_argument('--key', help='Registered policy key information', action='append')
signtx_policy_group.add_argument('--hmac', help='Registered policy hmac, obtained via register command')
signtx_parser.set_defaults(func=signtx_handler)

getxpub_parser = subparsers.add_parser('getxpub', help='Get an extended public key')
Expand Down
9 changes: 7 additions & 2 deletions hwilib/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,12 @@ def getmasterxpub(client: HardwareWalletClient, addrtype: AddressType = AddressT
"""
return {"xpub": client.get_master_xpub(addrtype, account).to_string()}

def signtx(client: HardwareWalletClient, psbt: str) -> Dict[str, Union[bool, str]]:
def signtx(client: HardwareWalletClient,
psbt: str,
policy_name: str,
descriptor_template: str,
keys_info: List[str],
hmac: str) -> Dict[str, Union[bool, str]]:
"""
Sign a Partially Signed Bitcoin Transaction (PSBT) with the client.

Expand All @@ -195,7 +200,7 @@ def signtx(client: HardwareWalletClient, psbt: str) -> Dict[str, Union[bool, str
# Deserialize the transaction
tx = PSBT()
tx.deserialize(psbt)
result = client.sign_tx(tx).serialize()
result = client.sign_tx(tx, policy_name, descriptor_template, keys_info, hmac).serialize()
return {"psbt": result, "signed": result != psbt}

def getxpub(client: HardwareWalletClient, path: str, expert: bool = False) -> Dict[str, Any]:
Expand Down
25 changes: 24 additions & 1 deletion hwilib/devices/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,12 @@ def get_pubkey_at_path(self, path: str) -> ExtendedKey:
return ExtendedKey.deserialize(xpub_str)

@ledger_exception
def sign_tx(self, tx: PSBT) -> PSBT:
def sign_tx(self,
tx: PSBT,
policy_name: str,
descriptor_template: str,
keys_info: List[str],
hmac: str) -> PSBT:
"""
Sign a transaction with a Ledger device. Not all transactions can be signed by a Ledger.

Expand All @@ -198,6 +203,8 @@ def sign_tx(self, tx: PSBT) -> PSBT:
For application versions 2.1.x and above:

- Only keys derived with standard BIP 44, 49, 84, and 86 derivation paths are supported for single signature addresses.

BIP388 policy arguments are optional, but if one is provided, all must be.
"""
master_fp = self.get_master_fingerprint()

Expand Down Expand Up @@ -264,6 +271,22 @@ def legacy_sign_tx() -> PSBT:
else:
continue

policy_args = [policy_name, descriptor_template, keys_info, hmac]
if policy_args != [None] * len(policy_args):
if any(arg is None for arg in policy_args):
raise BadArgumentError("Either all BIP388 policy arguments must be used or none")
policy = WalletPolicy(name=policy_name, descriptor_template=descriptor_template, keys_info=keys_info)
if policy.id not in wallets:
wallets[policy.id] = (
signing_priority[script_addrtype],
script_addrtype,
policy,
bytes.fromhex(hmac),
)
continue

# No BIP388 policy provided, construct on the fly

# Check if P2WSH
if is_p2wsh(scriptcode):
if len(psbt_in.witness_script) == 0:
Expand Down
6 changes: 5 additions & 1 deletion hwilib/hwwclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,11 @@ def get_pubkey_at_path(self, bip32_path: str) -> ExtendedKey:
raise NotImplementedError("The HardwareWalletClient base class "
"does not implement this method")

def sign_tx(self, psbt: PSBT) -> PSBT:
def sign_tx(self, psbt: PSBT,
policy_name=None,
descriptor_template=None,
keys_info=None,
hmac=None) -> PSBT:
"""
Sign a partially signed bitcoin transaction (PSBT).

Expand Down
Loading