diff --git a/README.md b/README.md index c80374b18..abb67c265 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Bitcoin Hardware Wallet Interface +# Dash Hardware Wallet Interface [![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/HWI.svg)](https://cirrus-ci.com/github/bitcoin-core/HWI) [![Documentation Status](https://readthedocs.org/projects/hwi/badge/?version=latest)](https://hwi.readthedocs.io/en/latest/?badge=latest) -The Bitcoin Hardware Wallet Interface is a Python library and command line tool for interacting with hardware wallets. +The Dash Hardware Wallet Interface is a Python library and command line tool for interacting with hardware wallets. It provides a standard way for software to work with hardware wallets without needing to implement device specific drivers. Python software can use the provided library (`hwilib`). Software in other languages can execute the `hwi` tool. @@ -31,7 +31,7 @@ brew install libusb ## Install ``` -git clone https://github.com/bitcoin-core/HWI.git +git clone https://github.com/dashpay/HWI.git cd HWI poetry install # or 'pip3 install .' or 'python3 setup.py install' ``` @@ -93,10 +93,11 @@ Documentation for HWI can be found on [readthedocs.io](https://hwi.readthedocs.i For documentation on devices supported and how they are supported, please check the [device support page](https://hwi.readthedocs.io/en/latest/devices/index.html#support-matrix) -### Using with Bitcoin Core +### Using with Dash Core See [Using Bitcoin Core with Hardware Wallets](https://hwi.readthedocs.io/en/latest/examples/bitcoin-core-usage.html). ## License +This project is a fork of Bitcoin HWI: https://github.com/bitcoin-core/hwi This project is available under the MIT License, Copyright Andrew Chow. diff --git a/hwilib/_cli.py b/hwilib/_cli.py index e0afa7dd2..53503d5fc 100644 --- a/hwilib/_cli.py +++ b/hwilib/_cli.py @@ -155,7 +155,8 @@ def get_parser() -> HWIArgumentParser: enumerate_parser.set_defaults(func=enumerate_handler) getmasterxpub_parser = subparsers.add_parser('getmasterxpub', help='Get the extended public key for BIP 44 standard derivation paths. Convenience function to get xpubs given the address type, account, and chain type.') - getmasterxpub_parser.add_argument("--addr-type", help="Get the master xpub used to derive addresses for this address type", type=AddressType.argparse, choices=list(AddressType), default=AddressType.WIT) # type: ignore + # [DASHIFIED] default address type is changed to legacy + getmasterxpub_parser.add_argument("--addr-type", help="Get the master xpub used to derive addresses for this address type", type=AddressType.argparse, choices=list(AddressType), default=AddressType.LEGACY) # type: ignore getmasterxpub_parser.add_argument("--account", help="The account number", type=int, default=0) getmasterxpub_parser.set_defaults(func=getmasterxpub_handler) @@ -178,7 +179,8 @@ def get_parser() -> HWIArgumentParser: kparg_group.add_argument('--nokeypool', action='store_false', dest='keypool', help='Indicates that the keys are not to be imported to the keypool', default=False) getkeypool_parser.add_argument('--internal', action='store_true', help='Indicates that the keys are change keys') kp_type_group = getkeypool_parser.add_mutually_exclusive_group() - kp_type_group.add_argument("--addr-type", help="The address type (and default derivation path) to produce descriptors for", type=AddressType.argparse, choices=list(AddressType), default=AddressType.WIT) # type: ignore + # [DASHIFIED] default address type is changed to legacy + kp_type_group.add_argument("--addr-type", help="The address type (and default derivation path) to produce descriptors for", type=AddressType.argparse, choices=list(AddressType), default=AddressType.LEGACY) # type: ignore kp_type_group.add_argument('--all', action='store_true', help='Generate addresses for all standard address types (default paths: ``m/{44,49,84}h/0h/0h/[0,1]/*)``') getkeypool_parser.add_argument('--account', help='BIP43 account', type=int, default=0) getkeypool_parser.add_argument('--path', help='Derivation path, default follows BIP43 convention, e.g. ``m/84h/0h/0h/1/*`` with --addr-type wpkh --internal. If this argument and --internal is not given, both internal and external keypools will be returned.') @@ -194,7 +196,8 @@ def get_parser() -> HWIArgumentParser: group = displayaddr_parser.add_mutually_exclusive_group(required=True) group.add_argument('--desc', help='Output Descriptor. E.g. wpkh([00000000/84h/0h/0h]xpub.../0/0), where 00000000 must match --fingerprint and xpub can be obtained with getxpub. See doc/descriptors.md in Bitcoin Core') group.add_argument('--path', help='The BIP 32 derivation path of the key embedded in the address, default follows BIP43 convention, e.g. ``m/84h/0h/0h/1/*``') - displayaddr_parser.add_argument("--addr-type", help="The address type to display", type=AddressType.argparse, choices=list(AddressType), default=AddressType.WIT) # type: ignore + # [DASHIFIED] default address type is changed to legacy + displayaddr_parser.add_argument("--addr-type", help="The address type to display", type=AddressType.argparse, choices=list(AddressType), default=AddressType.LEGACY) # type: ignore displayaddr_parser.set_defaults(func=displayaddress_handler) setupdev_parser = subparsers.add_parser('setup', help='Setup a device. Passphrase protection uses the password given by -p. Requires interactive mode') diff --git a/hwilib/commands.py b/hwilib/commands.py index 6d192aa5f..f6cdb2b64 100644 --- a/hwilib/commands.py +++ b/hwilib/commands.py @@ -173,7 +173,8 @@ def find_device( pass # Ignore things we wouldn't get fingerprints for return None -def getmasterxpub(client: HardwareWalletClient, addrtype: AddressType = AddressType.WIT, account: int = 0) -> Dict[str, str]: +# [DASHIFIED] default address type is changed to legacy +def getmasterxpub(client: HardwareWalletClient, addrtype: AddressType = AddressType.LEGACY, account: int = 0) -> Dict[str, str]: """ Get the master extended public key from a client @@ -238,7 +239,8 @@ def getkeypool_inner( internal: bool = False, keypool: bool = True, account: int = 0, - addr_type: AddressType = AddressType.WIT + # [DASHIFIED] default address type is changed to legacy + addr_type: AddressType = AddressType.LEGACY ) -> List[Dict[str, Any]]: """ :meta private: @@ -276,7 +278,8 @@ def getdescriptor( master_fpr: bytes, path: Optional[str] = None, internal: bool = False, - addr_type: AddressType = AddressType.WIT, + # [DASHIFIED] default address type is changed to legacy + addr_type: AddressType = AddressType.LEGACY, account: int = 0, start: Optional[int] = None, end: Optional[int] = None @@ -334,12 +337,12 @@ def getdescriptor( p &= ~HARDENED_FLAG path_suffix += "/{}{}".format(p, "h" if hardened else "") path_suffix += "/*" - # Get the key at the base if client.xpub_cache.get(path_base) is None: client.xpub_cache[path_base] = client.get_pubkey_at_path(path_base).to_string() pubkey = PubkeyProvider(origin, client.xpub_cache.get(path_base, ""), path_suffix) + # [DASHIFIED] default address type is changed to legacy if addr_type is AddressType.LEGACY: return PKHDescriptor(pubkey) elif addr_type is AddressType.SH_WIT: @@ -361,7 +364,8 @@ def getkeypool( internal: bool = False, keypool: bool = True, account: int = 0, - addr_type: AddressType = AddressType.WIT, + # [DASHIFIED] default address type is changed to legacy + addr_type: AddressType = AddressType.LEGACY, addr_all: bool = False ) -> List[Dict[str, Any]]: """ @@ -416,7 +420,6 @@ def getdescriptors( :raises: BadArgumentError: if an argument is malformed or missing. """ master_fpr = client.get_master_fingerprint() - result = {} for internal in [False, True]: @@ -441,7 +444,8 @@ def displayaddress( client: HardwareWalletClient, path: Optional[str] = None, desc: Optional[str] = None, - addr_type: AddressType = AddressType.WIT + # [DASHIFIED] default address type is changed to legacy + addr_type: AddressType = AddressType.LEGACY ) -> Dict[str, str]: """ Display an address on the device for client. @@ -459,6 +463,7 @@ def displayaddress( return {"address": client.display_singlesig_address(path, addr_type)} elif desc is not None: descriptor = parse_descriptor(desc) + # [DASHIFIED] default address type is changed to legacy addr_type = AddressType.LEGACY is_sh = isinstance(descriptor, SHDescriptor) is_wsh = isinstance(descriptor, WSHDescriptor) diff --git a/hwilib/common.py b/hwilib/common.py index 0c5c00606..cc659d36c 100644 --- a/hwilib/common.py +++ b/hwilib/common.py @@ -14,11 +14,12 @@ class Chain(Enum): """ The blockchain network to use """ - MAIN = 0 #: Bitcoin Main network - TEST = 1 #: Bitcoin Test network - REGTEST = 2 #: Bitcoin Core Regression Test network - SIGNET = 3 #: Bitcoin Signet - TESTNET4 = 4 #: Bitcoin Test network + # [DASHIFIED] removed SIGNET, TESTNET4 and changed comments + MAIN = 0 #: Dash Main network + TEST = 1 #: Dash Test network + REGTEST = 2 #: Dash Core Regression Test network +# SIGNET = 3 #: Bitcoin Signet +# TESTNET4 = 4 #: Bitcoin Test network def __str__(self) -> str: return str(self.name).lower() @@ -38,10 +39,11 @@ class AddressType(Enum): """ The type of address to use """ + # [DASHIFIED] removed WIT, SH_WIT and TAP addresses LEGACY = 1 #: Legacy address type. P2PKH for single sig, P2SH for scripts. - WIT = 2 #: Native segwit v0 address type. P2WPKH for single sig, P2WSH for scripts. - SH_WIT = 3 #: Nested segwit v0 address type. P2SH-P2WPKH for single sig, P2SH-P2WSH for scripts. - TAP = 4 #: Segwit v1 Taproot address type. P2TR always. +# WIT = 2 #: Native segwit v0 address type. P2WPKH for single sig, P2WSH for scripts. +# SH_WIT = 3 #: Nested segwit v0 address type. P2SH-P2WPKH for single sig, P2SH-P2WSH for scripts. +# TAP = 4 #: Segwit v1 Taproot address type. P2TR always. def __str__(self) -> str: return str(self.name).lower() diff --git a/hwilib/devices/jade.py b/hwilib/devices/jade.py index 2530ebb34..973d6f3e1 100644 --- a/hwilib/devices/jade.py +++ b/hwilib/devices/jade.py @@ -93,9 +93,9 @@ class JadeClient(HardwareWalletClient): MIN_SUPPORTED_FW_VERSION = semver.VersionInfo(0, 1, 32) PSBT_SUPPORTED_FW_VERSION = semver.VersionInfo(0, 1, 47) + # [DASHIFIED] Signet is hidden NETWORKS = {Chain.MAIN: 'mainnet', Chain.TEST: 'testnet', - Chain.SIGNET: 'testnet', # same as far as Jade is concerned Chain.REGTEST: 'localtest'} def _network(self) -> str: @@ -103,13 +103,11 @@ def _network(self) -> str: raise BadArgumentError(f'Unhandled network: {self.chain}') return self.NETWORKS[self.chain] - ADDRTYPES = {AddressType.LEGACY: 'pkh(k)', - AddressType.WIT: 'wpkh(k)', - AddressType.SH_WIT: 'sh(wpkh(k))'} + # [DASHIFIED] only legacy type is kept + ADDRTYPES = {AddressType.LEGACY: 'pkh(k)'} - MULTI_ADDRTYPES = {AddressType.LEGACY: 'sh(multi(k))', - AddressType.WIT: 'wsh(multi(k))', - AddressType.SH_WIT: 'sh(wsh(multi(k)))'} + # [DASHIFIED] only legacy type is kept + MULTI_ADDRTYPES = {AddressType.LEGACY: 'sh(multi(k))'} @classmethod def _convertAddrType(cls, addrType: AddressType, multisig: bool) -> str: diff --git a/hwilib/devices/ledger.py b/hwilib/devices/ledger.py index d3cf46325..038e931ae 100644 --- a/hwilib/devices/ledger.py +++ b/hwilib/devices/ledger.py @@ -112,13 +112,14 @@ def check_keypath(key_path: str) -> bool: ] # The priority of address types we want for signing. +# [DASHIFIED] re-ordered address types priorities. We have legacy only # We want to do Taproot first, then segwit, then legacy # Higher number is lower priority so that sort does not require reversing. signing_priority = { - AddressType.TAP: 0, - AddressType.WIT: 1, - AddressType.SH_WIT: 2, - AddressType.LEGACY: 3, + AddressType.LEGACY: 0, +# AddressType.TAP: 0, +# AddressType.WIT: 1, +# AddressType.SH_WIT: 2, } def handle_chip_exception(e: Union[BTChipException, ApduException], func_name: str) -> bool: diff --git a/hwilib/devices/ledger_bitcoin/client.py b/hwilib/devices/ledger_bitcoin/client.py index 64bbe3adc..afd51bbe1 100644 --- a/hwilib/devices/ledger_bitcoin/client.py +++ b/hwilib/devices/ledger_bitcoin/client.py @@ -289,8 +289,9 @@ def createClient(comm_client: Optional[TransportClient] = None, chain: Chain = C base_client = Client(comm_client, chain) app_name, app_version, _ = base_client.get_version() - if app_name not in ["Bitcoin", "Bitcoin Test", "Bitcoin Legacy", "Bitcoin Test Legacy", "app"]: - raise NotSupportedError(0x6A82, None, "Ledger is not in either the Bitcoin or Bitcoin Testnet app") + # [DASHIFIED] The name of app is updated + if app_name not in ["Dash", "Dash Test", "app"]: + raise NotSupportedError(0x6A82, None, "Ledger is not in either the Dash or Dash Testnet app") app_version_major, app_version_minor, _ = app_version.split(".", 2) diff --git a/hwilib/hwwclient.py b/hwilib/hwwclient.py index 565afcf44..6b54d68e6 100644 --- a/hwilib/hwwclient.py +++ b/hwilib/hwwclient.py @@ -37,14 +37,16 @@ def __init__(self, path: str, password: Optional[str], expert: bool, chain: Chai """ self.path = path self.password = password - self.message_magic = b"\x18Bitcoin Signed Message:\n" + # [DASHIFIED] prefix for message signing + self.message_magic = b"\x19DarkCoin Signed Message:\n" self.chain = chain self.fingerprint: Optional[str] = None # {bip32_path: } self.xpub_cache: Dict[str, str] = {} self.expert = expert - def get_master_xpub(self, addrtype: AddressType = AddressType.WIT, account: int = 0) -> ExtendedKey: + # [DASHIFIED] default address type is changed to legacy + def get_master_xpub(self, addrtype: AddressType = AddressType.LEGACY, account: int = 0) -> ExtendedKey: """ Retrieves a BIP 44 master public key diff --git a/hwilib/key.py b/hwilib/key.py index cb89e3926..e1c5904e9 100644 --- a/hwilib/key.py +++ b/hwilib/key.py @@ -369,14 +369,15 @@ def get_bip44_purpose(addrtype: AddressType) -> int: :param addrtype: The address type """ + # [DASHIFIED] commented out unused types of addresses if addrtype == AddressType.LEGACY: return 44 - elif addrtype == AddressType.SH_WIT: - return 49 - elif addrtype == AddressType.WIT: - return 84 - elif addrtype == AddressType.TAP: - return 86 +# elif addrtype == AddressType.SH_WIT: +# return 49 +# elif addrtype == AddressType.WIT: +# return 84 +# elif addrtype == AddressType.TAP: +# return 86 else: raise ValueError("Unknown address type") @@ -385,26 +386,28 @@ def get_bip44_chain(chain: Chain) -> int: """ Determine the BIP 44 coin type based on the Bitcoin chain type. - For the Bitcoin mainnet chain, this returns 0. For the other chains, this returns 1. + For the Dash mainnet chain, this returns 5. For the other chains, this returns 1. :param chain: The chain """ + # [DASHIFIED] changed type of chain to 5 (from 0 [bitcoin]) if chain == Chain.MAIN: - return 0 + return 5 else: return 1 def get_addrtype_from_bip44_purpose(index: int) -> Optional[AddressType]: purpose = index & ~HARDENED_FLAG + # [DASHIFIED] commented out unused types of addresses if purpose == 44: return AddressType.LEGACY - elif purpose == 49: - return AddressType.SH_WIT - elif purpose == 84: - return AddressType.WIT - elif purpose == 86: - return AddressType.TAP +# elif purpose == 49: +# return AddressType.SH_WIT +# elif purpose == 84: +# return AddressType.WIT +# elif purpose == 86: +# return AddressType.TAP else: return None