def get_xpub(self, bip32_path, xtype): self.checkDevice() # bip32_path is of the form 44'/0'/1' # S-L-O-W - we don't handle the fingerprint directly, so compute # it manually from the previous node # This only happens once so it's bearable #self.get_client() # prompt for the PIN before displaying the dialog if necessary #self.handler.show_message("Computing master public key") if xtype in ['p2wpkh', 'p2wsh'] and not self.supports_native_segwit(): raise UserFacingException(MSG_NEEDS_FW_UPDATE_SEGWIT) if xtype in ['p2wpkh-p2sh', 'p2wsh-p2sh'] and not self.supports_segwit(): raise UserFacingException(MSG_NEEDS_FW_UPDATE_SEGWIT) bip32_path = bip32.normalize_bip32_derivation(bip32_path) bip32_intpath = bip32.convert_bip32_path_to_list_of_uint32(bip32_path) bip32_path = bip32_path[2:] # cut off "m/" if len(bip32_intpath) >= 1: prevPath = bip32.convert_bip32_intpath_to_strpath(bip32_intpath[:-1])[2:] nodeData = self.dongleObject.getWalletPublicKey(prevPath) publicKey = compress_public_key(nodeData['publicKey']) fingerprint_bytes = hash_160(publicKey)[0:4] childnum_bytes = bip32_intpath[-1].to_bytes(length=4, byteorder="big") else: fingerprint_bytes = bytes(4) childnum_bytes = bytes(4) nodeData = self.dongleObject.getWalletPublicKey(bip32_path) publicKey = compress_public_key(nodeData['publicKey']) depth = len(bip32_intpath) return BIP32Node(xtype=xtype, eckey=ecc.ECPubkey(bytes(publicKey)), chaincode=nodeData['chainCode'], depth=depth, fingerprint=fingerprint_bytes, child_number=childnum_bytes).to_xpub()
def sign_message(self, keypath: str, message: bytes, script_type: str) -> bytes: if self.bitbox02_device is None: raise Exception( "Need to setup communication first before attempting any BitBox02 calls" ) try: simple_type = { "p2wpkh-p2sh":bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH, "p2wpkh": bitbox02.btc.BTCScriptConfig.P2WPKH, }[script_type] except KeyError: raise UserFacingException("The BitBox02 does not support signing messages for this address type: {}".format(script_type)) _, _, signature = self.bitbox02_device.btc_sign_msg( self._get_coin(), bitbox02.btc.BTCScriptConfigWithKeypath( script_config=bitbox02.btc.BTCScriptConfig( simple_type=simple_type, ), keypath=bip32.convert_bip32_path_to_list_of_uint32(keypath), ), message, ) return signature
def get_password_for_storage_encryption(self) -> str: derivation = get_derivation_used_for_hw_device_encryption() derivation_list = bip32.convert_bip32_path_to_list_of_uint32( derivation) xpub = self.bitbox02_device.electrum_encryption_key(derivation_list) node = bip32.BIP32Node.from_xkey( xpub, net=constants.BitcoinMainnet()).subkey_at_public_derivation( ()) return node.eckey.get_public_key_bytes(compressed=True).hex()
def show_address(self, bip32_path_prefix, sequence, txin_type): self.authenticate() path = bip32.convert_bip32_path_to_list_of_uint32(bip32_path_prefix) path.extend(sequence) script_variant = self._convertAddrType(txin_type, multisig=False) address = self.jade.get_receive_address(self._network(), path, variant=script_variant) return address
def get_xpub(self, bip32_path, xtype): self.authenticate() # Jade only provides traditional xpubs ... path = bip32.convert_bip32_path_to_list_of_uint32(bip32_path) xpub = self.jade.get_xpub(self._network(), path) # ... so convert to relevant xtype locally node = bip32.BIP32Node.from_xkey(xpub) return node._replace(xtype=xtype).to_xkey()
def sign_message(self, bip32_path_prefix, sequence, message): self.authenticate() path = bip32.convert_bip32_path_to_list_of_uint32(bip32_path_prefix) path.extend(sequence) if isinstance(message, bytes) or isinstance(message, bytearray): message = message.decode('utf-8') # Signature verification does not work with anti-exfil, so stick with default (rfc6979) sig = self.jade.sign_message(path, message) return base64.b64decode(sig)
def get_xpub(self, bip32_path: str, xtype: str, *, display: bool = False) -> str: if self.bitbox02_device is None: self.pairing_dialog() if self.bitbox02_device is None: raise Exception( "Need to setup communication first before attempting any BitBox02 calls" ) self.fail_if_not_initialized() xpub_keypath = bip32.convert_bip32_path_to_list_of_uint32(bip32_path) coin_network = self.coin_network_from_electrum_network() if xtype == "p2wpkh": if coin_network == bitbox02.btc.BTC: out_type = bitbox02.btc.BTCPubRequest.ZPUB else: out_type = bitbox02.btc.BTCPubRequest.VPUB elif xtype == "p2wpkh-p2sh": if coin_network == bitbox02.btc.BTC: out_type = bitbox02.btc.BTCPubRequest.YPUB else: out_type = bitbox02.btc.BTCPubRequest.UPUB elif xtype == "p2wsh-p2sh": if coin_network == bitbox02.btc.BTC: out_type = bitbox02.btc.BTCPubRequest.CAPITAL_YPUB else: out_type = bitbox02.btc.BTCPubRequest.CAPITAL_UPUB elif xtype == "p2wsh": if coin_network == bitbox02.btc.BTC: out_type = bitbox02.btc.BTCPubRequest.CAPITAL_ZPUB else: out_type = bitbox02.btc.BTCPubRequest.CAPITAL_VPUB # The other legacy types are not supported else: raise Exception("invalid xtype:{}".format(xtype)) return self.bitbox02_device.btc_xpub( keypath=xpub_keypath, xpub_type=out_type, coin=coin_network, display=display, )
def show_address( self, bip32_path: str, address_type: str, wallet: Deterministic_Wallet ) -> str: if self.bitbox02_device is None: raise Exception( "Need to setup communication first before attempting any BitBox02 calls" ) address_keypath = bip32.convert_bip32_path_to_list_of_uint32(bip32_path) coin_network = self.coin_network_from_electrum_network() if address_type == "p2wpkh": script_config = bitbox02.btc.BTCScriptConfig( simple_type=bitbox02.btc.BTCScriptConfig.P2WPKH ) elif address_type == "p2wpkh-p2sh": script_config = bitbox02.btc.BTCScriptConfig( simple_type=bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH ) elif address_type == "p2wsh": if type(wallet) is Multisig_Wallet: script_config = self.btc_multisig_config( coin_network, address_keypath, wallet ) else: raise Exception("Can only use p2wsh with multisig wallets") else: raise Exception( "invalid address xtype: {} is not supported by the BitBox02".format( address_type ) ) return self.bitbox02_device.btc_address( keypath=address_keypath, coin=coin_network, script_config=script_config, display=True, )
def expand_path(n): return convert_bip32_path_to_list_of_uint32(n)
def test_convert_bip32_path_to_list_of_uint32(self): self.assertEqual([0, 0x80000001, 0x80000001], convert_bip32_path_to_list_of_uint32("m/0/-1/1'")) self.assertEqual([], convert_bip32_path_to_list_of_uint32("m/")) self.assertEqual([2147483692, 2147488889, 221], convert_bip32_path_to_list_of_uint32("m/44'/5241'/221"))
def test_convert_bip32_path_to_list_of_uint32(self): self.assertEqual([0, 0x80000001, 0x80000001], convert_bip32_path_to_list_of_uint32("m/0/-1/1'")) self.assertEqual([], convert_bip32_path_to_list_of_uint32("m/")) self.assertEqual([2147483692, 2147488889, 221], convert_bip32_path_to_list_of_uint32("m/44'/5241h/221"))