Skip to content

Commit 04112e4

Browse files
committed
Merge branch 'dashify-v1' (#1)
It tested to work with Ledger Nano S if Dash Core is built from dashpay/dash#6019 Steps to test: 1. Get built dash-qt from develop 2. Clone hwi repo from this PR: #1 3. Enter your pin & open dash app on device, dash app should be installed in advance. I tested so far with Ledger Nano S Plus. 4. Call script `./hwi.py enumerate` to be sure that your device is shown in the list. Probably you need to setup udev rules and some extra python libraries; hidapi has been required to install for ledger on my workstation. 5. start Dash Qt: `src/qt/dash-qt -signer=FULL_PATH_TO_dash-hwi/hwi.py` 6. create new wallet; click checkbox "external signer" * **Documentation** * Updated product name, repository URL, and documentation to reflect Dash Hardware Wallet Interface. * **Configuration** * Default address type for key generation and display operations changed to LEGACY format. * Removed support for Signet network and advanced address type variants. * Updated message signing standard. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
2 parents 4e342db + f9468e2 commit 04112e4

9 files changed

Lines changed: 67 additions & 51 deletions

File tree

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# Bitcoin Hardware Wallet Interface
1+
# Dash Hardware Wallet Interface
22

33
[![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/HWI.svg)](https://cirrus-ci.com/github/bitcoin-core/HWI)
44
[![Documentation Status](https://readthedocs.org/projects/hwi/badge/?version=latest)](https://hwi.readthedocs.io/en/latest/?badge=latest)
55

6-
The Bitcoin Hardware Wallet Interface is a Python library and command line tool for interacting with hardware wallets.
6+
The Dash Hardware Wallet Interface is a Python library and command line tool for interacting with hardware wallets.
77
It provides a standard way for software to work with hardware wallets without needing to implement device specific drivers.
88
Python software can use the provided library (`hwilib`). Software in other languages can execute the `hwi` tool.
99

@@ -31,7 +31,7 @@ brew install libusb
3131
## Install
3232

3333
```
34-
git clone https://github.com/bitcoin-core/HWI.git
34+
git clone https://github.com/dashpay/HWI.git
3535
cd HWI
3636
poetry install # or 'pip3 install .' or 'python3 setup.py install'
3737
```
@@ -93,10 +93,11 @@ Documentation for HWI can be found on [readthedocs.io](https://hwi.readthedocs.i
9393

9494
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)
9595

96-
### Using with Bitcoin Core
96+
### Using with Dash Core
9797

9898
See [Using Bitcoin Core with Hardware Wallets](https://hwi.readthedocs.io/en/latest/examples/bitcoin-core-usage.html).
9999

100100
## License
101101

102+
This project is a fork of Bitcoin HWI: https://github.com/bitcoin-core/hwi
102103
This project is available under the MIT License, Copyright Andrew Chow.

hwilib/_cli.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ def get_parser() -> HWIArgumentParser:
155155
enumerate_parser.set_defaults(func=enumerate_handler)
156156

157157
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.')
158-
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
158+
# [DASHIFIED] default address type is changed to legacy
159+
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
159160
getmasterxpub_parser.add_argument("--account", help="The account number", type=int, default=0)
160161
getmasterxpub_parser.set_defaults(func=getmasterxpub_handler)
161162

@@ -178,7 +179,8 @@ def get_parser() -> HWIArgumentParser:
178179
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)
179180
getkeypool_parser.add_argument('--internal', action='store_true', help='Indicates that the keys are change keys')
180181
kp_type_group = getkeypool_parser.add_mutually_exclusive_group()
181-
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
182+
# [DASHIFIED] default address type is changed to legacy
183+
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
182184
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]/*)``')
183185
getkeypool_parser.add_argument('--account', help='BIP43 account', type=int, default=0)
184186
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:
194196
group = displayaddr_parser.add_mutually_exclusive_group(required=True)
195197
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')
196198
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/*``')
197-
displayaddr_parser.add_argument("--addr-type", help="The address type to display", type=AddressType.argparse, choices=list(AddressType), default=AddressType.WIT) # type: ignore
199+
# [DASHIFIED] default address type is changed to legacy
200+
displayaddr_parser.add_argument("--addr-type", help="The address type to display", type=AddressType.argparse, choices=list(AddressType), default=AddressType.LEGACY) # type: ignore
198201
displayaddr_parser.set_defaults(func=displayaddress_handler)
199202

200203
setupdev_parser = subparsers.add_parser('setup', help='Setup a device. Passphrase protection uses the password given by -p. Requires interactive mode')

hwilib/commands.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ def find_device(
173173
pass # Ignore things we wouldn't get fingerprints for
174174
return None
175175

176-
def getmasterxpub(client: HardwareWalletClient, addrtype: AddressType = AddressType.WIT, account: int = 0) -> Dict[str, str]:
176+
# [DASHIFIED] default address type is changed to legacy
177+
def getmasterxpub(client: HardwareWalletClient, addrtype: AddressType = AddressType.LEGACY, account: int = 0) -> Dict[str, str]:
177178
"""
178179
Get the master extended public key from a client
179180
@@ -238,7 +239,8 @@ def getkeypool_inner(
238239
internal: bool = False,
239240
keypool: bool = True,
240241
account: int = 0,
241-
addr_type: AddressType = AddressType.WIT
242+
# [DASHIFIED] default address type is changed to legacy
243+
addr_type: AddressType = AddressType.LEGACY
242244
) -> List[Dict[str, Any]]:
243245
"""
244246
:meta private:
@@ -276,7 +278,8 @@ def getdescriptor(
276278
master_fpr: bytes,
277279
path: Optional[str] = None,
278280
internal: bool = False,
279-
addr_type: AddressType = AddressType.WIT,
281+
# [DASHIFIED] default address type is changed to legacy
282+
addr_type: AddressType = AddressType.LEGACY,
280283
account: int = 0,
281284
start: Optional[int] = None,
282285
end: Optional[int] = None
@@ -334,12 +337,12 @@ def getdescriptor(
334337
p &= ~HARDENED_FLAG
335338
path_suffix += "/{}{}".format(p, "h" if hardened else "")
336339
path_suffix += "/*"
337-
338340
# Get the key at the base
339341
if client.xpub_cache.get(path_base) is None:
340342
client.xpub_cache[path_base] = client.get_pubkey_at_path(path_base).to_string()
341343

342344
pubkey = PubkeyProvider(origin, client.xpub_cache.get(path_base, ""), path_suffix)
345+
# [DASHIFIED] default address type is changed to legacy
343346
if addr_type is AddressType.LEGACY:
344347
return PKHDescriptor(pubkey)
345348
elif addr_type is AddressType.SH_WIT:
@@ -361,7 +364,8 @@ def getkeypool(
361364
internal: bool = False,
362365
keypool: bool = True,
363366
account: int = 0,
364-
addr_type: AddressType = AddressType.WIT,
367+
# [DASHIFIED] default address type is changed to legacy
368+
addr_type: AddressType = AddressType.LEGACY,
365369
addr_all: bool = False
366370
) -> List[Dict[str, Any]]:
367371
"""
@@ -416,7 +420,6 @@ def getdescriptors(
416420
:raises: BadArgumentError: if an argument is malformed or missing.
417421
"""
418422
master_fpr = client.get_master_fingerprint()
419-
420423
result = {}
421424

422425
for internal in [False, True]:
@@ -441,7 +444,8 @@ def displayaddress(
441444
client: HardwareWalletClient,
442445
path: Optional[str] = None,
443446
desc: Optional[str] = None,
444-
addr_type: AddressType = AddressType.WIT
447+
# [DASHIFIED] default address type is changed to legacy
448+
addr_type: AddressType = AddressType.LEGACY
445449
) -> Dict[str, str]:
446450
"""
447451
Display an address on the device for client.
@@ -459,6 +463,7 @@ def displayaddress(
459463
return {"address": client.display_singlesig_address(path, addr_type)}
460464
elif desc is not None:
461465
descriptor = parse_descriptor(desc)
466+
# [DASHIFIED] default address type is changed to legacy
462467
addr_type = AddressType.LEGACY
463468
is_sh = isinstance(descriptor, SHDescriptor)
464469
is_wsh = isinstance(descriptor, WSHDescriptor)

hwilib/common.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ class Chain(Enum):
1414
"""
1515
The blockchain network to use
1616
"""
17-
MAIN = 0 #: Bitcoin Main network
18-
TEST = 1 #: Bitcoin Test network
19-
REGTEST = 2 #: Bitcoin Core Regression Test network
20-
SIGNET = 3 #: Bitcoin Signet
21-
TESTNET4 = 4 #: Bitcoin Test network
17+
# [DASHIFIED] removed SIGNET, TESTNET4 and changed comments
18+
MAIN = 0 #: Dash Main network
19+
TEST = 1 #: Dash Test network
20+
REGTEST = 2 #: Dash Core Regression Test network
21+
# SIGNET = 3 #: Bitcoin Signet
22+
# TESTNET4 = 4 #: Bitcoin Test network
2223

2324
def __str__(self) -> str:
2425
return str(self.name).lower()
@@ -38,10 +39,11 @@ class AddressType(Enum):
3839
"""
3940
The type of address to use
4041
"""
42+
# [DASHIFIED] removed WIT, SH_WIT and TAP addresses
4143
LEGACY = 1 #: Legacy address type. P2PKH for single sig, P2SH for scripts.
42-
WIT = 2 #: Native segwit v0 address type. P2WPKH for single sig, P2WSH for scripts.
43-
SH_WIT = 3 #: Nested segwit v0 address type. P2SH-P2WPKH for single sig, P2SH-P2WSH for scripts.
44-
TAP = 4 #: Segwit v1 Taproot address type. P2TR always.
44+
# WIT = 2 #: Native segwit v0 address type. P2WPKH for single sig, P2WSH for scripts.
45+
# SH_WIT = 3 #: Nested segwit v0 address type. P2SH-P2WPKH for single sig, P2SH-P2WSH for scripts.
46+
# TAP = 4 #: Segwit v1 Taproot address type. P2TR always.
4547

4648
def __str__(self) -> str:
4749
return str(self.name).lower()

hwilib/devices/jade.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,21 @@ class JadeClient(HardwareWalletClient):
9393
MIN_SUPPORTED_FW_VERSION = semver.VersionInfo(0, 1, 32)
9494
PSBT_SUPPORTED_FW_VERSION = semver.VersionInfo(0, 1, 47)
9595

96+
# [DASHIFIED] Signet is hidden
9697
NETWORKS = {Chain.MAIN: 'mainnet',
9798
Chain.TEST: 'testnet',
98-
Chain.SIGNET: 'testnet', # same as far as Jade is concerned
9999
Chain.REGTEST: 'localtest'}
100100

101101
def _network(self) -> str:
102102
if self.chain not in self.NETWORKS:
103103
raise BadArgumentError(f'Unhandled network: {self.chain}')
104104
return self.NETWORKS[self.chain]
105105

106-
ADDRTYPES = {AddressType.LEGACY: 'pkh(k)',
107-
AddressType.WIT: 'wpkh(k)',
108-
AddressType.SH_WIT: 'sh(wpkh(k))'}
106+
# [DASHIFIED] only legacy type is kept
107+
ADDRTYPES = {AddressType.LEGACY: 'pkh(k)'}
109108

110-
MULTI_ADDRTYPES = {AddressType.LEGACY: 'sh(multi(k))',
111-
AddressType.WIT: 'wsh(multi(k))',
112-
AddressType.SH_WIT: 'sh(wsh(multi(k)))'}
109+
# [DASHIFIED] only legacy type is kept
110+
MULTI_ADDRTYPES = {AddressType.LEGACY: 'sh(multi(k))'}
113111

114112
@classmethod
115113
def _convertAddrType(cls, addrType: AddressType, multisig: bool) -> str:

hwilib/devices/ledger.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,14 @@ def check_keypath(key_path: str) -> bool:
112112
]
113113

114114
# The priority of address types we want for signing.
115+
# [DASHIFIED] re-ordered address types priorities. We have legacy only
115116
# We want to do Taproot first, then segwit, then legacy
116117
# Higher number is lower priority so that sort does not require reversing.
117118
signing_priority = {
118-
AddressType.TAP: 0,
119-
AddressType.WIT: 1,
120-
AddressType.SH_WIT: 2,
121-
AddressType.LEGACY: 3,
119+
AddressType.LEGACY: 0,
120+
# AddressType.TAP: 0,
121+
# AddressType.WIT: 1,
122+
# AddressType.SH_WIT: 2,
122123
}
123124

124125
def handle_chip_exception(e: Union[BTChipException, ApduException], func_name: str) -> bool:

hwilib/devices/ledger_bitcoin/client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,9 @@ def createClient(comm_client: Optional[TransportClient] = None, chain: Chain = C
289289
base_client = Client(comm_client, chain)
290290
app_name, app_version, _ = base_client.get_version()
291291

292-
if app_name not in ["Bitcoin", "Bitcoin Test", "Bitcoin Legacy", "Bitcoin Test Legacy", "app"]:
293-
raise NotSupportedError(0x6A82, None, "Ledger is not in either the Bitcoin or Bitcoin Testnet app")
292+
# [DASHIFIED] The name of app is updated
293+
if app_name not in ["Dash", "Dash Test", "app"]:
294+
raise NotSupportedError(0x6A82, None, "Ledger is not in either the Dash or Dash Testnet app")
294295

295296
app_version_major, app_version_minor, _ = app_version.split(".", 2)
296297

hwilib/hwwclient.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,16 @@ def __init__(self, path: str, password: Optional[str], expert: bool, chain: Chai
3737
"""
3838
self.path = path
3939
self.password = password
40-
self.message_magic = b"\x18Bitcoin Signed Message:\n"
40+
# [DASHIFIED] prefix for message signing
41+
self.message_magic = b"\x19DarkCoin Signed Message:\n"
4142
self.chain = chain
4243
self.fingerprint: Optional[str] = None
4344
# {bip32_path: <xpub string>}
4445
self.xpub_cache: Dict[str, str] = {}
4546
self.expert = expert
4647

47-
def get_master_xpub(self, addrtype: AddressType = AddressType.WIT, account: int = 0) -> ExtendedKey:
48+
# [DASHIFIED] default address type is changed to legacy
49+
def get_master_xpub(self, addrtype: AddressType = AddressType.LEGACY, account: int = 0) -> ExtendedKey:
4850
"""
4951
Retrieves a BIP 44 master public key
5052

hwilib/key.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -369,14 +369,15 @@ def get_bip44_purpose(addrtype: AddressType) -> int:
369369
370370
:param addrtype: The address type
371371
"""
372+
# [DASHIFIED] commented out unused types of addresses
372373
if addrtype == AddressType.LEGACY:
373374
return 44
374-
elif addrtype == AddressType.SH_WIT:
375-
return 49
376-
elif addrtype == AddressType.WIT:
377-
return 84
378-
elif addrtype == AddressType.TAP:
379-
return 86
375+
# elif addrtype == AddressType.SH_WIT:
376+
# return 49
377+
# elif addrtype == AddressType.WIT:
378+
# return 84
379+
# elif addrtype == AddressType.TAP:
380+
# return 86
380381
else:
381382
raise ValueError("Unknown address type")
382383

@@ -385,26 +386,28 @@ def get_bip44_chain(chain: Chain) -> int:
385386
"""
386387
Determine the BIP 44 coin type based on the Bitcoin chain type.
387388
388-
For the Bitcoin mainnet chain, this returns 0. For the other chains, this returns 1.
389+
For the Dash mainnet chain, this returns 5. For the other chains, this returns 1.
389390
390391
:param chain: The chain
391392
"""
393+
# [DASHIFIED] changed type of chain to 5 (from 0 [bitcoin])
392394
if chain == Chain.MAIN:
393-
return 0
395+
return 5
394396
else:
395397
return 1
396398

397399
def get_addrtype_from_bip44_purpose(index: int) -> Optional[AddressType]:
398400
purpose = index & ~HARDENED_FLAG
399401

402+
# [DASHIFIED] commented out unused types of addresses
400403
if purpose == 44:
401404
return AddressType.LEGACY
402-
elif purpose == 49:
403-
return AddressType.SH_WIT
404-
elif purpose == 84:
405-
return AddressType.WIT
406-
elif purpose == 86:
407-
return AddressType.TAP
405+
# elif purpose == 49:
406+
# return AddressType.SH_WIT
407+
# elif purpose == 84:
408+
# return AddressType.WIT
409+
# elif purpose == 86:
410+
# return AddressType.TAP
408411
else:
409412
return None
410413

0 commit comments

Comments
 (0)