Ejemplo n.º 1
0
    def _make_multisig(self, addrtype):
        if addrtype == "legacy":
            coin_type = 0
            desc_prefix = "sh("
            desc_suffix = ")"
        elif addrtype == "p2sh-segwit":
            coin_type = 1 if self.emulator.strict_bip48 else 0
            desc_prefix = "sh(wsh("
            desc_suffix = "))"
        elif addrtype == "bech32":
            coin_type = 2 if self.emulator.strict_bip48 else 0
            desc_prefix = "wsh("
            desc_suffix = ")"
        else:
            self.fail(f"Unknown address type {addrtype}")

        desc_pubkeys = []
        xpubs: Dict[bytes, KeyOriginInfo] = {}
        for account in range(0, 3 if self.emulator.supports_device_multiple_multisig else 1):
            path = f"/48h/1h/{account}h/{coin_type}h"
            origin = '{}{}'.format(self.emulator.fingerprint, path)
            xpub = self.do_command(self.dev_args + ["getxpub", "m{}".format(path)])
            desc_pubkeys.append("[{}]{}/0/0".format(origin, xpub["xpub"]))
            if self.emulator.include_xpubs:
                extkey = ExtendedKey.deserialize(xpub["xpub"])
                xpubs[extkey.serialize()] = KeyOriginInfo.from_string(origin)

        if not self.emulator.supports_device_multiple_multisig:
            # If the device does not support itself in the multisig more than once,
            # we need to fetch a key from Core, and use another key that will not be signed with
            counter_descs = self.wpk_rpc.listdescriptors()["descriptors"]
            desc = parse_descriptor(counter_descs[0]["desc"])
            pubkey_prov = None
            while pubkey_prov is None:
                if len(desc.pubkeys) > 0:
                    pubkey_prov = desc.pubkeys[0]
                else:
                    desc = desc.subdescriptors[0]
            assert pubkey_prov.extkey is not None
            assert pubkey_prov.origin is not None
            pubkey_prov.deriv_path = "/0/0"
            desc_pubkeys.append(pubkey_prov.to_string())
            if self.emulator.include_xpubs:
                xpubs[pubkey_prov.extkey.serialize()] = pubkey_prov.origin

            # A fixed key
            fixed_extkey = ExtendedKey.deserialize("tpubDCBWBScQPGv4Xk3JSbhw6wYYpayMjb2eAYyArpbSqQTbLDpphHGAetB6VQgVeftLML8vDSUEWcC2xDi3qJJ3YCDChJDvqVzpgoYSuT52MhJ")
            fixed_origin = KeyOriginInfo(b"\xde\xad\xbe\xef", [0x80000000])
            desc_pubkeys.append(PubkeyProvider(fixed_origin, fixed_extkey.to_string(), "/0/0").to_string())
            if self.emulator.include_xpubs:
                xpubs[fixed_extkey.serialize()] = fixed_origin

        desc = AddChecksum(f"{desc_prefix}sortedmulti(2,{desc_pubkeys[0]},{desc_pubkeys[1]},{desc_pubkeys[2]}){desc_suffix}")

        return desc, self.rpc.deriveaddresses(desc)[0], xpubs
Ejemplo n.º 2
0
    def test_deriv(self):
        for test in self.data["deriv"]:
            with self.subTest(test=test):
                # Deser
                par_xpub = ExtendedKey.deserialize(test["parent_xpub"])
                par_xprv = ExtendedKey.deserialize(test["parent_xprv"])

                # Derive
                i = test["index"]
                child_xpub = test["child_xpub"]
                xpub_der = par_xpub.derive_pub(i)
                self.assertEqual(xpub_der.to_string(), child_xpub)
                xprv_der = par_xprv.derive_pub(i)
                self.assertEqual(xprv_der.to_string(), child_xpub)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
 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
Ejemplo n.º 5
0
def parse_multisig(
    script: bytes,
    tx_xpubs: Dict[bytes, KeyOriginInfo],
    psbt_scope: Union[PartiallySignedInput, PartiallySignedOutput],
) -> Tuple[bool, Optional[messages.MultisigRedeemScriptType]]:
    # at least OP_M pub OP_N OP_CHECKMULTISIG
    if len(script) < 37:
        return (False, None)
    # Get m
    m = script[0] - 80
    if m < 1 or m > 15:
        return (False, None)

    # Get pubkeys and build HDNodePathType
    pubkeys = []
    offset = 1
    while True:
        pubkey_len = script[offset]
        if pubkey_len != 33:
            break
        offset += 1
        key = script[offset : offset + 33]
        offset += 33

        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=key,
        )
        pubkeys.append(messages.HDNodePathType(node=hd_node, address_n=[]))

    # Check things at the end
    n = script[offset] - 80
    if n != len(pubkeys):
        return (False, None)
    offset += 1
    op_cms = script[offset]
    if op_cms != 174:
        return (False, None)

    # check if we know corresponding xpubs from global scope
    for pub in pubkeys:
        if pub.node.public_key in psbt_scope.hd_keypaths:
            derivation = psbt_scope.hd_keypaths[pub.node.public_key]
            for xpub in tx_xpubs:
                hd = ExtendedKey.deserialize(base58.encode(xpub + hash256(xpub)[:4]))
                origin = tx_xpubs[xpub]
                # check fingerprint and derivation
                if (origin.fingerprint == derivation.fingerprint) and (
                    origin.path == derivation.path[: len(origin.path)]
                ):
                    # all good - populate node and break
                    pub.address_n = list(derivation.path[len(origin.path) :])
                    pub.node = messages.HDNodeType(
                        depth=hd.depth,
                        fingerprint=int.from_bytes(hd.parent_fingerprint, "big"),
                        child_num=hd.child_num,
                        chain_code=hd.chaincode,
                        public_key=hd.pubkey,
                    )
                    break
    # Build MultisigRedeemScriptType and return it
    multisig = messages.MultisigRedeemScriptType(
        m=m, signatures=[b""] * n, pubkeys=pubkeys
    )
    return (True, multisig)
Ejemplo n.º 6
0
 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
Ejemplo n.º 7
0
    def test_serialization(self):
        for key in self.data["serialization"]:
            xpub = key["xpub"]
            xprv = key["xprv"]
            deser = key["deser"]
            with self.subTest(key=key):
                key_pub = ExtendedKey.deserialize(xpub)
                key_prv = ExtendedKey.deserialize(xprv)

                # Make sure they roundtrip
                self.assertEqual(key_pub.to_string(), xpub)
                self.assertEqual(key_prv.to_string(), xprv)

                # Make sure they agree
                self.assertEqual(key_pub.is_testnet, key_prv.is_testnet)
                self.assertEqual(key_pub.depth, key_prv.depth)
                self.assertEqual(key_pub.parent_fingerprint,
                                 key_prv.parent_fingerprint)
                self.assertEqual(key_pub.child_num, key_prv.child_num)
                self.assertEqual(key_pub.chaincode, key_prv.chaincode)
                self.assertEqual(key_pub.pubkey, key_prv.pubkey)

                # Make sure they are correct
                self.assertEqual(key_pub.version, deser["pub_version"])
                self.assertEqual(key_pub.is_testnet, deser["is_testnet"])
                self.assertEqual(key_pub.is_private, False)
                self.assertEqual(key_pub.depth, deser["depth"])
                self.assertEqual(key_pub.parent_fingerprint,
                                 deser["parent_fingerprint"])
                self.assertEqual(key_pub.child_num, deser["child_num"])
                self.assertEqual(key_pub.chaincode, deser["chaincode"])
                self.assertEqual(key_pub.pubkey, deser["pubkey"])
                self.assertEqual(key_prv.version, deser["priv_version"])
                self.assertEqual(key_prv.is_testnet, deser["is_testnet"])
                self.assertEqual(key_prv.is_private, True)
                self.assertEqual(key_prv.depth, deser["depth"])
                self.assertEqual(key_prv.parent_fingerprint,
                                 deser["parent_fingerprint"])
                self.assertEqual(key_prv.child_num, deser["child_num"])
                self.assertEqual(key_prv.chaincode, deser["chaincode"])
                self.assertEqual(key_prv.pubkey, deser["pubkey"])
                self.assertEqual(key_prv.privkey, deser["privkey"])

                # Make sure the printable dict is right
                key_dict = key_pub.get_printable_dict()
                self.assertEqual(key_dict["testnet"], deser["is_testnet"])
                self.assertEqual(key_dict["private"], False)
                self.assertEqual(key_dict["depth"], deser["depth"])
                self.assertEqual(key_dict["parent_fingerprint"],
                                 deser["hex_parent_fingerprint"])
                self.assertEqual(key_dict["child_num"], deser["child_num"])
                self.assertEqual(key_dict["chaincode"], deser["hex_chaincode"])
                self.assertEqual(key_dict["pubkey"], deser["hex_pubkey"])
                key_dict = key_prv.get_printable_dict()
                self.assertEqual(key_dict["testnet"], deser["is_testnet"])
                self.assertEqual(key_dict["private"], True)
                self.assertEqual(key_dict["depth"], deser["depth"])
                self.assertEqual(key_dict["parent_fingerprint"],
                                 deser["hex_parent_fingerprint"])
                self.assertEqual(key_dict["child_num"], deser["child_num"])
                self.assertEqual(key_dict["chaincode"], deser["hex_chaincode"])
                self.assertEqual(key_dict["pubkey"], deser["hex_pubkey"])
                self.assertEqual(key_dict["privkey"], deser["hex_privkey"])