Skip to content
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
12 changes: 12 additions & 0 deletions hwilib/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
getdescriptors,
prompt_pin,
toggle_passphrase,
register,
restore_device,
send_pin,
setup_device,
Expand All @@ -22,6 +23,7 @@
)
from .common import (
AddressType,
BIP388Policy,
Chain,
)
from .errors import (
Expand Down Expand Up @@ -59,6 +61,10 @@ def backup_device_handler(args: argparse.Namespace, client: HardwareWalletClient
def displayaddress_handler(args: argparse.Namespace, client: HardwareWalletClient) -> Dict[str, str]:
return displayaddress(client, desc=args.desc, path=args.path, addr_type=args.addr_type)

def register_handler(args: argparse.Namespace, client: HardwareWalletClient) -> Dict[str, str]:
policy = BIP388Policy(name=args.name, descriptor_template=args.desc, keys_info=args.key)
return register(client, bip388_policy=policy)

def enumerate_handler(args: argparse.Namespace) -> List[Dict[str, Any]]:
return enumerate(password=args.password, expert=args.expert, chain=args.chain, allow_emulators=args.allow_emulators)

Expand Down Expand Up @@ -197,6 +203,12 @@ def get_parser() -> HWIArgumentParser:
displayaddr_parser.add_argument("--addr-type", help="The address type to display", type=AddressType.argparse, choices=list(AddressType), default=AddressType.WIT) # type: ignore
displayaddr_parser.set_defaults(func=displayaddress_handler)

register_parser = subparsers.add_parser('register', help='Register a BIP388 wallet policy')
register_parser.add_argument('--name', help='Name for the policy')
register_parser.add_argument('--desc', help='Descriptor template, e.g. tr(musig(@0,@1)')
register_parser.add_argument('--key', help='Key information, e.g. [00000000/84h/0h/0h]xpub...', action='append')
register_parser.set_defaults(func=register_handler)

setupdev_parser = subparsers.add_parser('setup', help='Setup a device. Passphrase protection uses the password given by -p. Requires interactive mode')
setupdev_parser.add_argument('--label', '-l', help='The name to give to the device', default='')
setupdev_parser.add_argument('--backup_passphrase', '-b', help='The passphrase to use for the backup, if applicable', default='')
Expand Down
18 changes: 18 additions & 0 deletions hwilib/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
from .devices import __all__ as all_devs
from .common import (
AddressType,
BIP388Policy,
Chain,
)
from .hwwclient import HardwareWalletClient
Expand Down Expand Up @@ -494,6 +495,23 @@ def displayaddress(
return {"address": client.display_singlesig_address(pubkey.get_full_derivation_path(0), addr_type)}
raise BadArgumentError("Missing both path and descriptor")

def register(
client: HardwareWalletClient,
bip388_policy: BIP388Policy,
) -> Dict[str, str]:
"""
Register a BIP388 policy on the device for client.

:param name: Name for the policy
:param desc: Descriptor template
:return: A dictionary containing policy HMAC.
Returned as ``{"hmac": <hex string>}``.
:raises: BadArgumentError: if an argument is malformed, missing, or conflicts.
"""
assert bip388_policy.hmac is None

return {"hmac": client.register_bip388_policy(bip388_policy)}

def setup_device(client: HardwareWalletClient, label: str = "", backup_passphrase: str = "") -> Dict[str, bool]:
"""
Setup a device that has not yet been initialized.
Expand Down
18 changes: 16 additions & 2 deletions hwilib/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
****************************
"""

from dataclasses import dataclass

import hashlib

from enum import Enum

from typing import Union

from typing import (
List,
Optional,
Union,
)

class Chain(Enum):
"""
Expand Down Expand Up @@ -56,6 +61,15 @@ def argparse(s: str) -> Union['AddressType', str]:
except KeyError:
return s

@dataclass
class BIP388Policy:
"""
Serialization agnostic BIP388 policy.
"""
name: str
descriptor_template: str
keys_info: List[str]
hmac: Optional[str] = None

def sha256(s: bytes) -> bytes:
"""
Expand Down
19 changes: 19 additions & 0 deletions hwilib/devices/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
)
from ..common import (
AddressType,
BIP388Policy,
Chain,
)
from .ledger_bitcoin.client import (
Expand Down Expand Up @@ -479,6 +480,24 @@ def format_key_info(pubkey: PubkeyProvider) -> str:

return self.client.get_wallet_address(multisig_wallet, registered_hmac, change, address_index, True)

@ledger_exception
def register_bip388_policy(
self,
bip388_policy: BIP388Policy,
) -> str:
if isinstance(self.client, LegacyClient):
raise BadArgumentError("Registering a BIP388 policy not supported by this version of the Bitcoin App")

wallet_policy = WalletPolicy(
name=bip388_policy.name,
descriptor_template=bip388_policy.descriptor_template,
keys_info=bip388_policy.keys_info
)

_, registered_hmac = self.client.register_wallet(wallet_policy)

return registered_hmac.hex()

def setup_device(self, label: str = "", passphrase: str = "") -> bool:
"""
Ledgers do not support setup via software.
Expand Down
17 changes: 16 additions & 1 deletion hwilib/hwwclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
get_bip44_chain,
)
from .psbt import PSBT
from .common import AddressType, Chain
from .common import (
AddressType,
BIP388Policy,
Chain,
)


class HardwareWalletClient(object):
Expand Down Expand Up @@ -135,6 +139,17 @@ def display_multisig_address(
raise NotImplementedError("The HardwareWalletClient base class "
"does not implement this method")

def register_bip388_policy(
self,
bip388_policy: BIP388Policy,
) -> str:
"""
Register a BIP388 policy.

:return: The policy HMAC
"""
raise NotImplementedError("This device does not support BIP388 policies or it's not yet implemented")

def wipe_device(self) -> bool:
"""
Wipe the device.
Expand Down
Loading