def display_singlesig_address( self, keypath: str, addr_type: AddressType, ) -> str: self._check_unlocked() # Script type if addr_type == AddressType.SH_WIT: script_type = messages.InputScriptType.SPENDP2SHWITNESS elif addr_type == AddressType.WIT: script_type = messages.InputScriptType.SPENDWITNESS elif addr_type == AddressType.LEGACY: script_type = messages.InputScriptType.SPENDADDRESS else: raise BadArgumentError("Unknown address type") expanded_path = parse_path(keypath) try: address = btc.get_address( self.client, self.coin_name, expanded_path, show_display=True, script_type=script_type, multisig=None, ) assert isinstance(address, str) return address except Exception: pass raise BadArgumentError("No path supplied matched device keys")
def display_singlesig_address(self, bip32_path: str, addr_type: AddressType) -> str: path = parse_path(bip32_path) addr_type = self._convertAddrType(addr_type) address = self.jade.get_receive_address( self._network(), path, variant=addr_type ) return address
def get_pubkey_at_path(self, path: str) -> ExtendedKey: self._check_unlocked() try: expanded_path = parse_path(path) except ValueError as e: raise BadArgumentError(str(e)) output = btc.get_public_node( self.client, expanded_path, coin_name=self.coin_name ) xpub = ExtendedKey.deserialize(output.xpub) if self.chain != Chain.MAIN: xpub.version = ExtendedKey.TESTNET_PUBLIC return xpub
def test_deriv_path(self): for test in self.data["deriv_path"]: with self.subTest(test=test): # Deser par_xpub = ExtendedKey.deserialize(test["parent_xpub"]) par_xprv = ExtendedKey.deserialize(test["parent_xprv"]) # Parse the path path = parse_path(test["path"]) # Derive child_xpub = test["child_xpub"] xpub_der = par_xpub.derive_pub_path(path) self.assertEqual(xpub_der.to_string(), child_xpub) xprv_der = par_xprv.derive_pub_path(path) self.assertEqual(xprv_der.to_string(), child_xpub)
def display_multisig_address( self, addr_type: AddressType, multisig: MultisigDescriptor, ) -> str: self._check_unlocked() der_pks = list( zip([p.get_pubkey_bytes(0) for p in multisig.pubkeys], multisig.pubkeys) ) if multisig.is_sorted: der_pks = sorted(der_pks) pubkey_objs = [] for pk, p in der_pks: if p.extkey is not None: xpub = p.extkey hd_node = messages.HDNodeType( depth=xpub.depth, fingerprint=int.from_bytes(xpub.parent_fingerprint, "big"), child_num=xpub.child_num, chain_code=xpub.chaincode, public_key=xpub.pubkey, ) pubkey_objs.append( messages.HDNodePathType( node=hd_node, address_n=parse_path( "m" + p.deriv_path if p.deriv_path is not None else "" ), ) ) else: hd_node = messages.HDNodeType( depth=0, fingerprint=0, child_num=0, chain_code=b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", public_key=pk, ) pubkey_objs.append(messages.HDNodePathType(node=hd_node, address_n=[])) trezor_ms = messages.MultisigRedeemScriptType( m=multisig.thresh, signatures=[b""] * len(pubkey_objs), pubkeys=pubkey_objs ) # Script type if addr_type == AddressType.SH_WIT: script_type = messages.InputScriptType.SPENDP2SHWITNESS elif addr_type == AddressType.WIT: script_type = messages.InputScriptType.SPENDWITNESS elif addr_type == AddressType.LEGACY: script_type = messages.InputScriptType.SPENDMULTISIG else: raise BadArgumentError("Unknown address type") for p in multisig.pubkeys: keypath = p.origin.get_derivation_path() if p.origin is not None else "m/" keypath += p.deriv_path if p.deriv_path is not None else "" path = parse_path(keypath) try: address = btc.get_address( self.client, self.coin_name, path, show_display=True, script_type=script_type, multisig=trezor_ms, ) assert isinstance(address, str) return address except Exception: pass raise BadArgumentError("No path supplied matched device keys")
def sign_message(self, message: Union[str, bytes], keypath: str) -> str: self._check_unlocked() path = parse_path(keypath) result = btc.sign_message(self.client, self.coin_name, path, message) return base64.b64encode(result.signature).decode("utf-8")
def display_multisig_address( self, addr_type: AddressType, multisig: MultisigDescriptor, ) -> str: signer_origins = [] signers = [] paths = [] for pubkey in multisig.pubkeys: if pubkey.extkey is None: raise BadArgumentError( "Blockstream Jade can only generate addresses for multisigs with full extended keys" ) if pubkey.origin is None: raise BadArgumentError( "Blockstream Jade can only generate addresses for multisigs with key origin information" ) if pubkey.deriv_path is None: raise BadArgumentError( "Blockstream Jade can only generate addresses for multisigs with key origin derivation path information" ) # Tuple to derive deterministic name for the registrtion signer_origins.append((pubkey.origin.fingerprint, pubkey.origin.path)) # We won't include the additional path in the multisig registration signers.append( { "fingerprint": pubkey.origin.fingerprint, "derivation": pubkey.origin.path, "xpub": pubkey.pubkey, "path": [], } ) # Instead hold it as the address path path = ( pubkey.deriv_path[1:] if pubkey.deriv_path[0] == "/" else pubkey.deriv_path ) paths.append(parse_path(path)) # sort origins, signers and paths according to origins (like in _get_multisig_name) signer_origins, signers, paths = [ list(a) for a in zip(*sorted(zip(signer_origins, signers, paths))) ] # Get a deterministic name for this multisig wallet script_variant = self._convertAddrType(addr_type, multisig=True) multisig_name = self._get_multisig_name( script_variant, multisig.thresh, signer_origins ) # Need to ensure this multisig wallet is registered first # (Note: 're-registering' is a no-op) self.jade.register_multisig( self._network(), multisig_name, script_variant, True, # always use sorted multisig.thresh, signers, ) address = self.jade.get_receive_address( self._network(), paths, multisig_name=multisig_name ) return str(address)
def sign_message(self, message: Union[str, bytes], bip32_path: str) -> str: path = parse_path(bip32_path) if isinstance(message, bytes) or isinstance(message, bytearray): message = message.decode("utf-8") signature = self.jade.sign_message(path, message) return signature
def get_pubkey_at_path(self, bip32_path: str) -> ExtendedKey: path = parse_path(bip32_path) xpub = self.jade.get_xpub(self._network(), path) ext_key = ExtendedKey.deserialize(xpub) return ext_key