Ejemplo n.º 1
0
def parse_key(key: str) -> BIP32:
    """
    Try to parse an extended key, whether it is in xpub, xpriv or mnemonic format.
    """
    try:
        private_key = BIP32.from_xpriv(key)
        print('🔑  Read master private key successfully')
        return private_key
    except Exception:
        pass

    try:
        public_key = BIP32.from_xpub(key)
        print('🔑  Read master public key successfully')
        return public_key
    except Exception:
        pass

    try:
        language = Mnemonic.detect_language(key)
        seed = Mnemonic(language).to_seed(key)
        private_key = BIP32.from_seed(seed)
        print('🔑  Read mnemonic successfully')
        return private_key
    except Exception:
        pass

    raise ValueError(
        'The key is invalid or the format isn\'t recognized. Make sure it\'s a mnemonic, xpriv or xpub.'
    )
Ejemplo n.º 2
0
def test_sanity_tests():
    seed = bytes.fromhex(
        "1077a46dc8545d372f22d9e110ae6c5c2bf7620fe9c4c911f5404d112233e1aa270567dd3554092e051ba3ba86c303590b0309116ac89964ff284db2219d7511"
    )
    first_bip32 = BIP32.from_seed(seed)
    sec_bip32 = BIP32.from_xpriv(
        "xprv9s21ZrQH143K3o4KUs47P2x9afhH31ekMo2foNTYwrU9wwZ8g5EatR9bn6YmCacdvnHWMnPFUqieQrnunrzuF5UfgGbhbEW43zRnhpPDBUL"
    )
    assert first_bip32.get_master_xpriv() == sec_bip32.get_master_xpriv()
    assert first_bip32.get_master_xpub() == sec_bip32.get_master_xpub()
    # Fuzz it a bit
    for i in range(50):
        path = [int.from_bytes(os.urandom(3), "big") for _ in range(5)]
        h_path = [
            HARDENED_INDEX + int.from_bytes(os.urandom(3), "big")
            for _ in range(5)
        ]
        mixed_path = [int.from_bytes(os.urandom(3), "big") for _ in range(5)]
        for i in mixed_path:
            if int.from_bytes(os.urandom(32), "big") % 2:
                i += HARDENED_INDEX
        assert first_bip32.get_xpriv_from_path(
            path) == sec_bip32.get_xpriv_from_path(path)
        assert first_bip32.get_xpub_from_path(
            path) == sec_bip32.get_xpub_from_path(path)
        assert first_bip32.get_xpriv_from_path(
            h_path) == sec_bip32.get_xpriv_from_path(h_path)
        assert first_bip32.get_xpub_from_path(
            h_path) == sec_bip32.get_xpub_from_path(h_path)
        assert first_bip32.get_xpriv_from_path(
            mixed_path) == sec_bip32.get_xpriv_from_path(mixed_path)
        assert first_bip32.get_xpub_from_path(
            mixed_path) == sec_bip32.get_xpub_from_path(mixed_path)
    # Taken from iancoleman's website
    bip32 = BIP32.from_seed(
        bytes.fromhex(
            "ac8c2377e5cde867d7e420fbe04d8906309b70d51b8fe58d6844930621a9bc223929155dcfebb4da9d62c86ec0d15adf936a663f4f0cf39cbb0352e7dac073d6"
        ))
    assert bip32.get_master_xpriv() == bip32.get_xpriv_from_path(
        []
    ) == "xprv9s21ZrQH143K2GzaKJsW7DQsxeDpY3zqgusaSx6owWGC19k4mhwnVAsm4qPsCw43NkY2h1BzVLyxWHt9NKF86QRyBj53vModdGcNxtpD6KX"
    assert bip32.get_master_xpub() == bip32.get_xpub_from_path(
        []
    ) == "xpub661MyMwAqRbcEm53RLQWUMMcWg4JwWih48oBFLWRVqoAsx5DKFG32yCEv8iH29TWpmo5KTcpsjXcea6Zx4Hc6PAbGnHjEDCf3yHbj7qdpnf"
    # Sanity checks for m/0'/0'/14/0'/18
    xpriv = bip32.get_xpriv_from_path(
        [HARDENED_INDEX, HARDENED_INDEX, 14, HARDENED_INDEX, 18])
    xpub = bip32.get_xpub_from_path(
        [HARDENED_INDEX, HARDENED_INDEX, 14, HARDENED_INDEX, 18])
    assert xpriv == "xprvA2YVbLvEeKaPedw7F6RLwG3RgYnTq1xGCyDNMgZNWdEQnSUBQmKEuLyA6TSPsggt5xvyJHLD9L25tNLpQiP4Q8ZkQNo8ueAgeYj5zYq8hSm"
    assert xpub == "xpub6FXqzrT8Uh8gs81aM7xMJPzAEacxEUg7aC8yA4xz4xmPfEoKxJdVT9Hdwm3LwVQrSos2rhGDt8aGGHvdLr5LLAjK8pXFkbSpzGoGTXjd4z9"
    # Now if we our master is m/0'/0'/14, we should derive the same keys for
    # m/0'/18 !
    xpriv2 = bip32.get_xpriv_from_path([HARDENED_INDEX, HARDENED_INDEX, 14])
    assert xpriv2 == "xprv9yQJmvQMywM5i7UNuZ4RQ1A9rEMwAJCExPardkmBCB46S3vBqNEatSwLUrwLNLHBu1Kd9aGxGKDD5YAfs6hRzpYthciAHjtGadxgV2PeqY9"
    bip32 = BIP32.from_xpriv(xpriv2)
    assert bip32.get_master_xpriv() == xpriv2
    assert bip32.get_xpriv_from_path([HARDENED_INDEX, 18]) == xpriv
    assert bip32.get_xpub_from_path([HARDENED_INDEX, 18]) == xpub
Ejemplo n.º 3
0
    def __init__(self, master_key: BIP32, utxos: List[scanner.Utxo],
                 address: str, amount_in_sat: int):
        """
        Craft and sign a transaction that spends all the UTXOs and sends the requested funds to a specific address.
        """
        output_script = scripts.build_output_script_from_address(address)
        if output_script is None:
            raise ValueError(
                'The address is invalid or the format isn\'t recognized.')

        if amount_in_sat < NON_SEGWIT_DUST:
            raise ValueError('Not enough funds to create a sweep transaction.')

        self.outputs = [(amount_in_sat, output_script)]
        self.inputs = []

        for index in range(len(utxos)):
            utxo = utxos[index]

            # Build the inputs for signing: they should all have empty scripts, save for the input that we are signing,
            # which should have the output script of a P2PKH output.
            pubkey = master_key.get_pubkey_from_path(utxo.path.to_list())
            script = scripts.ScriptType.LEGACY.build_output_script(pubkey)
            inputs = [(u, script if u == utxo else b'', []) for u in utxos]

            if utxo.script_type == scripts.ScriptType.LEGACY:
                # If this is a legacy input, then the transaction digest is just the wire format serialization.
                tx = _serialize_tx(inputs, self.outputs, include_witness=False)
            else:
                # If this is a segwit input (native or not), then the transaction digest is the one defined in BIP143.
                tx = _serialize_tx_for_segwit_signing(index, inputs,
                                                      self.outputs)

            # To produce the final message digest we need to append the sig-hash type, and double sha256 the message.
            tx.extend(SIGHASH_ALL.to_bytes(4, 'little'))
            hash = scripts.sha256(scripts.sha256(bytes(tx)))

            privkey = master_key.get_privkey_from_path(utxo.path.to_list())
            signature = coincurve.PrivateKey(privkey).sign(hash, hasher=None)

            extended_signature = bytearray(signature)
            extended_signature.append(SIGHASH_ALL)
            extended_signature = bytes(extended_signature)

            self.inputs.append(
                (utxo,
                 utxo.script_type.build_input_script(pubkey,
                                                     extended_signature),
                 utxo.script_type.build_witness(pubkey, extended_signature)))
Ejemplo n.º 4
0
    def Init(self, request, context):

        node = Node()
        node.hsm_secret = request.hsm_secret.data

        # on chain wallet
        hkdf = HKDF(key=node.hsm_secret)
        r = hkdf.extract_key(info='bip32 seed'.encode(), length=32)
        logger.debug("bip32_key seed: %s" % r.hex())
        node.bip32_key = BIP32.from_seed(r, network=self.network)

        # node pubkey, node msg sign
        r = hkdf.extract_key(info='nodeid'.encode(), length=32)
        node.node_privkey = r
        node.node_pk = r
        logger.info("new node privkey %s" % r.hex())

        node_pk = coincurve.PrivateKey(secret=r)
        node.pubkey = node_pk.public_key.format()
        node.nodeid = binascii.hexlify(node.pubkey)
        logger.info("new node id %s" % node.nodeid)

        # channel secret_base
        node.secret_base = hkdf.extract_key(info='peer seed'.encode(),
                                            length=32)
        logger.debug("new channel secret base %s" % node.secret_base.hex())

        if not self.nodes.get(node.pubkey) or request.coldstart:
            self.nodes[node.pubkey] = node

        reply = remotesigner_pb2.InitReply()
        reply.node_id.data = node.pubkey
        return reply
Ejemplo n.º 5
0
def test_vector_3():
    seed = bytes.fromhex(
        "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be"
    )
    bip32 = BIP32.from_seed(seed)
    # Chain m
    assert (
        bip32.get_xpub_from_path([]) ==
        "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"
    )
    assert (
        bip32.get_xpriv_from_path([]) ==
        "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6"
    )
    assert (bip32.get_xpub_from_path("m") == bip32.get_xpub_from_path([]))
    assert (bip32.get_xpriv_from_path("m") == bip32.get_xpriv_from_path([]))
    # Chain m/0H
    assert (
        bip32.get_xpub_from_path([HARDENED_INDEX]) ==
        "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"
    )
    assert (
        bip32.get_xpriv_from_path([HARDENED_INDEX]) ==
        "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L"
    )
    assert (bip32.get_xpub_from_path("m/0H") == bip32.get_xpub_from_path(
        [HARDENED_INDEX]))
    assert (bip32.get_xpriv_from_path("m/0H") == bip32.get_xpriv_from_path(
        [HARDENED_INDEX]))
Ejemplo n.º 6
0
def test_vector_1():
    seed = bytes.fromhex("000102030405060708090a0b0c0d0e0f")
    bip32 = BIP32.from_seed(seed)
    # Chain m
    assert (
        bip32.get_master_xpub() ==
        "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
    )
    assert (
        bip32.get_master_xpriv() ==
        "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
    )
    # Chain m/0H
    assert (
        bip32.get_xpub_from_path([HARDENED_INDEX]) ==
        "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"
    )
    assert (
        bip32.get_xpriv_from_path([HARDENED_INDEX]) ==
        "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"
    )
    # m/0H/1
    assert (
        bip32.get_xpub_from_path([HARDENED_INDEX, 1]) ==
        "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"
    )
    assert (
        bip32.get_xpriv_from_path([HARDENED_INDEX, 1]) ==
        "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"
    )
    # m/0H/1/2H
    assert (
        bip32.get_xpub_from_path([HARDENED_INDEX, 1, HARDENED_INDEX + 2]) ==
        "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"
    )
    assert (
        bip32.get_xpriv_from_path([HARDENED_INDEX, 1, HARDENED_INDEX + 2]) ==
        "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"
    )
    # m/0H/1/2H/2
    assert (
        bip32.get_xpub_from_path([HARDENED_INDEX, 1, HARDENED_INDEX + 2, 2]) ==
        "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"
    )
    assert (
        bip32.get_xpriv_from_path([HARDENED_INDEX, 1, HARDENED_INDEX + 2,
                                   2]) ==
        "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"
    )
    # m/0H/1/2H/2/1000000000
    assert (
        bip32.get_xpub_from_path(
            [HARDENED_INDEX, 1, HARDENED_INDEX + 2, 2, 1000000000]) ==
        "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"
    )
    assert (
        bip32.get_xpriv_from_path(
            [HARDENED_INDEX, 1, HARDENED_INDEX + 2, 2, 1000000000]) ==
        "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"
    )
Ejemplo n.º 7
0
    def load_from_mnemonic(self, words):
        print 'mnemonic', words
        seed = mnemonic.Mnemonic('english').decode(words)
        print 'seed', seed

        xprv = BIP32.get_xprv_from_seed(seed)
        self.struct.seed.CopyFrom(xprv)
Ejemplo n.º 8
0
    def _script_at(self, master_key: BIP32, index: int, account: int) -> Script:
        """
        Render the script at a specific index and account pair.
        """
        pubkey = master_key.get_pubkey_from_path(self.path.to_list(index, account))
        script = self.script_type.build_output_script(pubkey)

        return Script(script, index, account, self)
Ejemplo n.º 9
0
def get_address(words, strange=10):
    address_list = []
    mnemo = Mnemonic("english")
    seed = mnemo.to_seed(words, passphrase="")
    bip32 = BIP32.from_seed(seed)
    for i in range(0, strange):
        path = "m/44'/313'/0'/0/%i" % i
        pab_key = bip32.get_pubkey_from_path(path)
        key = zilkey.ZilKey(public_key=pab_key.hex())
        address_list.append(key.address)
    return address_list
Ejemplo n.º 10
0
    def __init__(self,
                 mnemonic: str,
                 language: str = "english",
                 passphrase: str = ""):
        """
        BIP44 HD wallet with a master mnemonic.

        :param mnemonic (str): The master mnemonic to derive keys
        :param language (str, optional): The mnemonic's language, default: "english"
        :param passphrase (str, optional): The mnemonic's passphrase, default: ""
        """
        self._seed = Mnemonic(language).to_seed(mnemonic, passphrase)
        self._bip32 = BIP32.from_seed(self._seed)
Ejemplo n.º 11
0
def create_wallet(testnet=False):
    path = "m/44'/1'/0'/0/0" if testnet else "m/44'/0'/0'/0/0"

    mnemo = Mnemonic("english")
    words = mnemo.generate()
    seed = mnemo.to_seed(words, passphrase="")

    bip32 = BIP32.from_seed(seed)

    privkey = bip32.get_privkey_from_path(path)
    pubkey = base64.b64encode(bip32.get_pubkey_from_path(path)).decode('utf-8')
    definition = ['sig', {"pubkey": pubkey}]

    print(f"privkey: {privkey}")
    print(f"pubkey: {pubkey}")
    print(f"address: {get_chash_160(definition)}")
Ejemplo n.º 12
0
    def from_mnemonic(cls, words: str, path="m/44'/494'/0'/0/0") -> PrivateKey:
        """
        Create a PrivateKey instance from a given mnemonic phrase and a HD derivation path.
        If path is not given, default to Band's HD prefix 494 and all other indexes being zeroes.

        :param words: the mnemonic phrase for recover private key
        :param path: the HD path that follows the BIP32 standard

        :return: Initialized PrivateKey object
        """
        seed = Mnemonic("english").to_seed(words)
        self = cls(_error_do_not_use_init_directly=True)
        self.signing_key = SigningKey.from_string(
            BIP32.from_seed(seed).get_privkey_from_path(path),
            curve=SECP256k1,
            hashfunc=hashlib.sha256,
        )
        return self
Ejemplo n.º 13
0
def test_vault_address(vault_factory):
    wallets = vault_factory.get_wallets()
    # FIXME: separate the Bitcoin backends !!
    bitcoind = wallets[0].bitcoind
    for wallet in wallets:
        # It's burdensome to our xpub to be None in the list, but it allows us
        # to know which of the stakeholders we are, so..
        all_xpubs = [keychain.get_master_xpub() if keychain
                     else wallet.our_bip32.get_master_xpub()
                     for keychain in wallet.keychains]
        # bitcoind should always return the same address as us
        for i in range(3):
            wallet_first_address = wallet.getnewaddress()
            bitcoind_first_address = bitcoind.addmultisigaddress(4, [
                b2x(BIP32.from_xpub(xpub).get_pubkey_from_path([i]))
                for xpub in all_xpubs
            ])["address"]
            assert wallet_first_address == bitcoind_first_address
Ejemplo n.º 14
0
 def get_wallets(self, emergency_privkeys=None):
     """Get 4 vaults, one for each stakeholder. Spin up the servers."""
     bip32s = [BIP32.from_seed(os.urandom(32), "test") for _ in range(4)]
     xpubs = [bip32.get_master_xpub() for bip32 in bip32s]
     if emergency_privkeys is None:
         emergency_privkeys = [CKey(os.urandom(32)) for _ in range(4)]
     emergency_pubkeys = [k.pub for k in emergency_privkeys]
     self.vaults = []
     # Generate some random 'OK' addresses
     acked_addresses = [self.bitcoind.getnewaddress() for _ in range(5)]
     for bip32 in bip32s:
         xpriv = bip32.get_master_xpriv()
         conf = self.bitcoind.rpc.__btc_conf_file__
         cosigner_url = "http://localhost:{}".format(self.cosigning_port)
         sigserv_url = "http://localhost:{}".format(self.sigserver_port)
         self.vaults.append(
             Vault(xpriv, xpubs, emergency_pubkeys, conf, cosigner_url,
                   sigserv_url, acked_addresses))
     return self.vaults
Ejemplo n.º 15
0
    def next_script(
            self,
            master_key: BIP32) -> Optional[Tuple[bytes, Path, ScriptType]]:
        """
        Fetch the next script for the current descriptor.
        """
        if self.index > self.max_index or self.account > self.max_account:
            return None

        # derive the next script
        path = self.path.with_account(self.account)
        pubkey = master_key.get_pubkey_from_path(path.to_list(self.index))
        script = self.script_type.build_output_script(pubkey)

        # Since traversing the entire [0; MAX_INDEX] x [0; MAX_ACCOUNT] space of combinations might take a while, we
        # walk the (index, account) grid in diagonal order. This order prioritizes the most probable combinations
        # (ie. low index, low account), while letting us explore a large space in the long run.
        #
        #           0     1     2
        #         ↙     ↙     ↙
        #    (0,0) (1,0) (2,0)  3
        #   ↙     ↙     ↙     ↙
        #    (0,1) (1,1) (2,1)  4
        #   ↙     ↙     ↙     ↙
        #    (0,2) (1,2) (2,2)  5
        #   ↙     ↙     ↙     ↙
        #    (0,3) (1,3) (2,3)
        #   ↙     ↙     ↙

        if self.index == 0 or self.account == self.max_account:
            # if we reached the border, start in the next diagonal
            diagonal_total = self.index + self.account + 1
            self.index = min(diagonal_total, self.max_index)
            self.account = diagonal_total - self.index
        else:
            # go down the diagonal
            self.index -= 1
            self.account += 1

        return script, path, self.script_type
Ejemplo n.º 16
0
    def get_node(self):
        """Return decrypted HDNodeType (from stored mnemonic or encrypted HDNodeType)"""
        if not self.is_initialized():
            raise NotInitializedException("Device not initalized")

        if self.is_locked():
            raise Exception("Passphrase required")

        if self.struct.HasField("mnemonic") and self.struct.HasField("node"):
            raise Exception("Cannot have both mnemonic and node at the same time")

        if self.session.has_node():
            # If we've already unlocked node, let's use it
            return self.session.node

        if self.struct.HasField("mnemonic"):
            print "Loading mnemonic"
            seed = Mnemonic(self.struct.language).to_seed(
                self.struct.mnemonic, passphrase=self.session.get_passphrase()
            )
            self.session.set_node(BIP32.get_node_from_seed(seed))
        else:
            print "Loading node"
            passphrase = self.session.get_passphrase()
            if passphrase:
                secret = PBKDF2(
                    passphrase, "TREZORHD", iterations=2048, macmodule=hmac, digestmodule=hashlib.sha512
                ).read(64)
                node = types.HDNodeType()
                node.CopyFrom(self.struct.node)
                aes_key = secret[:32]
                aes_iv = secret[32:48]
                aescbc = pyaes.AESModeOfOperationCBC(key=aes_key, iv=aes_iv)
                node.chain_code = aescbc.decrypt(node.chain_code[:16]) + aescbc.decrypt(node.chain_code[16:])
                node.private_key = aescbc.decrypt(node.private_key[:16]) + aescbc.decrypt(node.private_key[16:])
                self.session.set_node(node)
            else:
                self.session.set_node(self.struct.node)

        return self.session.node
Ejemplo n.º 17
0
    def get_node(self):
        '''Return decrypted HDNodeType (from stored mnemonic or encrypted HDNodeType)'''
        if not self.is_initialized():
            raise NotInitializedException("Device not initalized")

        if self.is_locked():
            raise Exception("Passphrase required")

        if self.struct.HasField('mnemonic') and self.struct.HasField('node'):
            raise Exception("Cannot have both mnemonic and node at the same time")
        
        if self.session.has_node():
            # If we've already unlocked node, let's use it
            return self.session.node

        if self.struct.HasField('mnemonic'):
            print "Loading mnemonic"
            seed = Mnemonic(self.struct.language).to_seed(self.struct.mnemonic, passphrase=self.session.get_passphrase())
            self.session.set_node(BIP32.get_node_from_seed(seed))
        else:
            print "Loading node"
            self.session.set_node(self.struct.node)

        return self.session.node
Ejemplo n.º 18
0
def seed_to_privkey(seed: str, path: str = DEFAULT_DERIVATION_PATH) -> bytes:
    """Get a private key from a mnemonic seed and a derivation path.

    Assumes a BIP39 mnemonic seed with no passphrase. Raises
    `ecdsa.MalformedPointError` if the resulting private key is invalid.
    """
    seed_bytes = mnemonic.Mnemonic.to_seed(seed, passphrase="")

    # Generate wallet master key as per BIP32
    bip32_magic_string = b"Bitcoin seed"
    seed_hmac = hmac.new(bip32_magic_string,
                         seed_bytes,
                         digestmod=hashlib.sha512).digest()
    master_key = seed_hmac[:32]
    chain_code = seed_hmac[32:]

    # Derive a private key from the given path
    derived_privkey = BIP32(chain_code,
                            privkey=master_key).get_privkey_from_path(path)

    # Validate the derived private key. Can raise ecdsa.MalformedPointError here.
    ecdsa.SigningKey.from_string(derived_privkey, curve=ecdsa.SECP256k1)

    return derived_privkey
Ejemplo n.º 19
0
    def __init__(self,
                 xpriv,
                 xpubs,
                 emergency_pubkeys,
                 bitcoin_conf_path,
                 cosigning_url,
                 sigserver_url,
                 acked_addresses,
                 current_index=0,
                 birthdate=None):
        """
        We need the xpub of all the other stakeholders to derive their pubkeys.

        :param xpriv: Who am I ? Has to correspond to one of the following
                      xpub. As str.
        :param xpubs: A list of the xpub of all the stakeholders (as str), in
                      the following order: 1) first trader 2) second trader
                      3) first "normie" stakeholder 4) second "normie"
                      stakeholder.
        :param emergency_pubkeys: A list of the four offline keys of the
                                  stakeholders, as bytes.
        :param bitcoin_conf_path: Path to bitcoin.conf.
        :param cosigning_url: The url of the cosigning server.
        :param sigserver_url: The url of the server to post / get the sigs from
                              other stakeholders.
        :param acked_addresses: Addresses to which we accept to spend.
        :param birthdate: The timestamp at which this wallet has been created.
                          If not passed, will assume newly-created wallet.
        """
        assert len(xpubs) == 4
        self.our_bip32 = BIP32.from_xpriv(xpriv)
        self.keychains = []
        for xpub in xpubs:
            if xpub != self.our_bip32.get_master_xpub():
                self.keychains.append(BIP32.from_xpub(xpub))
            else:
                self.keychains.append(None)
        self.all_xpubs = xpubs
        self.emergency_pubkeys = emergency_pubkeys
        # Ok, shitload of indexes. The current one is the lower bound of the
        # range we will import to bitcoind as watchonly. The max one is the
        # upper bond, the current "gen" one is to generate new addresses.
        self.current_index = current_index
        self.current_gen_index = self.current_index
        self.max_index = current_index + 500
        self.index_treshold = self.max_index

        self.birthdate = int(time.time()) if birthdate is None else birthdate

        self.bitcoind = BitcoindApi(bitcoin_conf_path)

        # First of all, watch the emergency vault
        self.watch_emergency_vault()
        # And store the corresponding address..
        txo = emergency_txout(self.emergency_pubkeys, 0)
        self.emergency_address = str(
            CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey))

        # The cosigning server, asked for its signature for the spend_tx
        self.cosigner = CosigningApi(cosigning_url)
        self.cosigner_pubkey = self.cosigner.get_pubkey()

        # The "sig" server, used to store and exchange signatures between
        # vaults and which provides us a feerate.
        # Who am I ?
        stk_id = self.keychains.index(None) + 1
        self.sigserver = ServerApi(sigserver_url, stk_id)

        self.vault_addresses = []
        self.unvault_addresses = []
        self.update_watched_addresses()

        # We keep track of each vault, see below when we fill it for details
        # about what it contains. Basically all the transactions, the
        # signatures and some useful fields (like "are all txs signed ?").
        self.vaults = []
        self.vaults_lock = threading.Lock()

        # Poll for funds until we die
        self.funds_poller_stop = threading.Event()
        self.funds_poller = threading.Thread(target=self.poll_for_funds,
                                             daemon=True)
        self.funds_poller.start()

        # Poll for spends until we die
        self.acked_addresses = acked_addresses
        self.acked_spends = []
        self.spends_poller_stop = threading.Event()
        self.spends_poller = threading.Thread(target=self.poll_for_spends,
                                              daemon=True)
        self.spends_poller.start()

        # Don't start polling for signatures just yet, we don't have any vault!
        self.update_sigs_stop = threading.Event()
        self.update_sigs_thread =\
            threading.Thread(target=self.update_all_signatures, daemon=True)

        self.stopped = False
Ejemplo n.º 20
0
def test_vector_2():
    seed = bytes.fromhex(
        "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"
    )
    bip32 = BIP32.from_seed(seed)
    # Chain m
    assert (
        bip32.get_master_xpub() ==
        "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"
    )
    assert (
        bip32.get_master_xpriv() ==
        "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"
    )
    # Chain m/0
    assert (
        bip32.get_xpub_from_path([0]) ==
        "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"
    )
    assert (
        bip32.get_xpriv_from_path([0]) ==
        "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"
    )
    assert (bip32.get_xpriv_from_path("m/0") == bip32.get_xpriv_from_path([0]))
    assert (bip32.get_xpub_from_path("m/0") == bip32.get_xpub_from_path([0]))
    # Chain m/0/2147483647H
    assert (
        bip32.get_xpub_from_path([0, HARDENED_INDEX + 2147483647]) ==
        "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"
    )
    assert (
        bip32.get_xpriv_from_path([0, HARDENED_INDEX + 2147483647]) ==
        "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"
    )
    assert (bip32.get_xpub_from_path("m/0/2147483647H") ==
            bip32.get_xpub_from_path([0, HARDENED_INDEX + 2147483647]))
    assert (bip32.get_xpriv_from_path("m/0/2147483647H") ==
            bip32.get_xpriv_from_path([0, HARDENED_INDEX + 2147483647]))
    # Chain m/0/2147483647H/1
    assert (
        bip32.get_xpub_from_path([0, HARDENED_INDEX + 2147483647, 1]) ==
        "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"
    )
    assert (
        bip32.get_xpriv_from_path([0, HARDENED_INDEX + 2147483647, 1]) ==
        "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"
    )
    assert (bip32.get_xpub_from_path("m/0/2147483647H/1") ==
            bip32.get_xpub_from_path([0, HARDENED_INDEX + 2147483647, 1]))
    assert (bip32.get_xpriv_from_path("m/0/2147483647H/1") ==
            bip32.get_xpriv_from_path([0, HARDENED_INDEX + 2147483647, 1]))
    # Chain m/0/2147483647H/1/2147483646H
    assert (
        bip32.get_xpub_from_path(
            [0, HARDENED_INDEX + 2147483647, 1,
             HARDENED_INDEX + 2147483646]) ==
        "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"
    )
    assert (
        bip32.get_xpriv_from_path(
            [0, HARDENED_INDEX + 2147483647, 1,
             HARDENED_INDEX + 2147483646]) ==
        "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"
    )
    assert (bip32.get_xpub_from_path(
        "m/0/2147483647H/1/2147483646H") == bip32.get_xpub_from_path(
            [0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646]))
    assert (bip32.get_xpriv_from_path(
        "m/0/2147483647H/1/2147483646H") == bip32.get_xpriv_from_path(
            [0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646]))
    # Chain m/0/2147483647H/1/2147483646H/2
    assert (
        bip32.get_xpub_from_path([
            0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646, 2
        ]) ==
        "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"
    )
    assert (
        bip32.get_xpriv_from_path([
            0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646, 2
        ]) ==
        "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"
    )
    assert (bip32.get_xpub_from_path(
        "m/0/2147483647H/1/2147483646H/2") == bip32.get_xpub_from_path([
            0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646, 2
        ]))
    assert (bip32.get_xpriv_from_path(
        "m/0/2147483647H/1/2147483646H/2") == bip32.get_xpriv_from_path([
            0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646, 2
        ]))
Ejemplo n.º 21
0
def test_sanity_tests():
    seed = bytes.fromhex(
        "1077a46dc8545d372f22d9e110ae6c5c2bf7620fe9c4c911f5404d112233e1aa270567dd3554092e051ba3ba86c303590b0309116ac89964ff284db2219d7511"
    )
    first_bip32 = BIP32.from_seed(seed)
    sec_bip32 = BIP32.from_xpriv(
        "xprv9s21ZrQH143K3o4KUs47P2x9afhH31ekMo2foNTYwrU9wwZ8g5EatR9bn6YmCacdvnHWMnPFUqieQrnunrzuF5UfgGbhbEW43zRnhpPDBUL"
    )
    assert first_bip32.get_master_xpriv() == sec_bip32.get_master_xpriv()
    assert first_bip32.get_master_xpub() == sec_bip32.get_master_xpub()
    # Fuzz it a bit
    for i in range(50):
        path = [int.from_bytes(os.urandom(3), "big") for _ in range(5)]
        h_path = [
            HARDENED_INDEX + int.from_bytes(os.urandom(3), "big")
            for _ in range(5)
        ]
        mixed_path = [int.from_bytes(os.urandom(3), "big") for _ in range(5)]
        for i in mixed_path:
            if int.from_bytes(os.urandom(32), "big") % 2:
                i += HARDENED_INDEX
        assert first_bip32.get_xpriv_from_path(
            path) == sec_bip32.get_xpriv_from_path(path)
        assert first_bip32.get_xpub_from_path(
            path) == sec_bip32.get_xpub_from_path(path)
        assert first_bip32.get_xpriv_from_path(
            h_path) == sec_bip32.get_xpriv_from_path(h_path)
        assert first_bip32.get_xpub_from_path(
            h_path) == sec_bip32.get_xpub_from_path(h_path)
        assert first_bip32.get_xpriv_from_path(
            mixed_path) == sec_bip32.get_xpriv_from_path(mixed_path)
        assert first_bip32.get_xpub_from_path(
            mixed_path) == sec_bip32.get_xpub_from_path(mixed_path)
    # Taken from iancoleman's website
    bip32 = BIP32.from_seed(
        bytes.fromhex(
            "ac8c2377e5cde867d7e420fbe04d8906309b70d51b8fe58d6844930621a9bc223929155dcfebb4da9d62c86ec0d15adf936a663f4f0cf39cbb0352e7dac073d6"
        ))
    assert bip32.get_master_xpriv() == bip32.get_xpriv_from_path(
        []
    ) == "xprv9s21ZrQH143K2GzaKJsW7DQsxeDpY3zqgusaSx6owWGC19k4mhwnVAsm4qPsCw43NkY2h1BzVLyxWHt9NKF86QRyBj53vModdGcNxtpD6KX"
    assert bip32.get_master_xpub() == bip32.get_xpub_from_path(
        []
    ) == "xpub661MyMwAqRbcEm53RLQWUMMcWg4JwWih48oBFLWRVqoAsx5DKFG32yCEv8iH29TWpmo5KTcpsjXcea6Zx4Hc6PAbGnHjEDCf3yHbj7qdpnf"
    # Sanity checks for m/0'/0'/14/0'/18
    xpriv = bip32.get_xpriv_from_path(
        [HARDENED_INDEX, HARDENED_INDEX, 14, HARDENED_INDEX, 18])
    xpub = bip32.get_xpub_from_path(
        [HARDENED_INDEX, HARDENED_INDEX, 14, HARDENED_INDEX, 18])
    assert xpriv == "xprvA2YVbLvEeKaPedw7F6RLwG3RgYnTq1xGCyDNMgZNWdEQnSUBQmKEuLyA6TSPsggt5xvyJHLD9L25tNLpQiP4Q8ZkQNo8ueAgeYj5zYq8hSm"
    assert xpub == "xpub6FXqzrT8Uh8gs81aM7xMJPzAEacxEUg7aC8yA4xz4xmPfEoKxJdVT9Hdwm3LwVQrSos2rhGDt8aGGHvdLr5LLAjK8pXFkbSpzGoGTXjd4z9"
    # Now if we our master is m/0'/0'/14, we should derive the same keys for
    # m/0'/18 !
    xpriv2 = bip32.get_xpriv_from_path([HARDENED_INDEX, HARDENED_INDEX, 14])
    assert xpriv2 == "xprv9yQJmvQMywM5i7UNuZ4RQ1A9rEMwAJCExPardkmBCB46S3vBqNEatSwLUrwLNLHBu1Kd9aGxGKDD5YAfs6hRzpYthciAHjtGadxgV2PeqY9"
    bip32 = BIP32.from_xpriv(xpriv2)
    assert bip32.get_master_xpriv() == xpriv2
    assert bip32.get_xpriv_from_path([HARDENED_INDEX, 18]) == xpriv
    assert bip32.get_xpub_from_path([HARDENED_INDEX, 18]) == xpub
    # We should recognize the networks..
    # .. for xprivs:
    bip32 = BIP32.from_xpriv(
        "xprv9wHokC2KXdTSpEepFcu53hMDUHYfAtTaLEJEMyxBPAMf78hJg17WhL5FyeDUQH5KWmGjGgEb2j74gsZqgupWpPbZgP6uFmP8MYEy5BNbyET"
    )
    assert bip32.network == "main"
    bip32 = BIP32.from_xpriv(
        "tprv8ZgxMBicQKsPeCBsMzQCCb5JcW4S49MVL3EwhdZMF1RF71rgisZU4ZRvrHX6PZQEiNUABDLvYqpx8Lsccq8aGGR59qHAoLoE3iXYuDa8JTP"
    )
    assert bip32.network == "test"
    # .. for xpubs:
    bip32 = BIP32.from_xpub(
        "xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU"
    )
    assert bip32.network == "main"
    bip32 = BIP32.from_xpub(
        "tpubD6NzVbkrYhZ4WN3WiKRjeo2eGyYNiKNg8vcQ1UjLNJJaDvoFhmR1XwJsbo5S4vicSPoWQBThR3Rt8grXtP47c1AnoiXMrEmFdRZupxJzH1j"
    )
    assert bip32.network == "test"
    # We should create valid network encoding..
    assert BIP32.from_seed(os.urandom(32),
                           "test").get_master_xpub().startswith("tpub")
    assert BIP32.from_seed(os.urandom(32),
                           "test").get_master_xpriv().startswith("tprv")
    assert BIP32.from_seed(os.urandom(32),
                           "main").get_master_xpub().startswith("xpub")
    assert BIP32.from_seed(os.urandom(32),
                           "main").get_master_xpriv().startswith("xprv")
Ejemplo n.º 22
0
    def setup_device(self, mnemonic, passphrase, wallet_manager, testnet):
        seed = Mnemonic.to_seed(mnemonic)
        xprv = seed_to_hd_master_key(seed, testnet=testnet)
        wallet_name = os.path.join(wallet_manager.cli_path + '_hotstorage', self.alias)
        wallet_manager.cli.createwallet(wallet_name, False, True)
        cli = wallet_manager.cli.wallet(wallet_name)
        # TODO: Maybe more than 1000? Maybe add mechanism to add more later.
        ## NOTE: This will work only on the network the device was added, so hot devices should be filtered out by network.
        coin = int(testnet)
        cli.importmulti([
            { 'desc': AddChecksum('sh(wpkh({}/49h/{}h/0h/0/*))'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'},
            { 'desc': AddChecksum('sh(wpkh({}/49h/{}h/0h/1/*))'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'},
            { 'desc': AddChecksum('wpkh({}/84h/{}h/0h/0/*)'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'},
            { 'desc': AddChecksum('wpkh({}/84h/{}h/0h/1/*)'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'},
            { 'desc': AddChecksum('sh(wpkh({}/48h/{}h/0h/1h/0/*))'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'},
            { 'desc': AddChecksum('sh(wpkh({}/48h/{}h/0h/1h/1/*))'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'},
            { 'desc': AddChecksum('wpkh({}/48h/{}h/0h/2h/0/*)'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'},
            { 'desc': AddChecksum('wpkh({}/48h/{}h/0h/2h/1/*)'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'},
        ])
        if passphrase:
            cli.encryptwallet(passphrase)

        bip32 = BIP32.from_seed(seed)
        xpubs = ""
        master_fpr = get_xpub_fingerprint(bip32.get_xpub_from_path('m/0h')).hex()

        if not testnet:
            # Nested Segwit
            xpub = bip32.get_xpub_from_path('m/49h/0h/0h')
            ypub = convert_xpub_prefix(xpub, b'\x04\x9d\x7c\xb2')
            xpubs += "[%s/49'/0'/0']%s\n" % (master_fpr, ypub)
            # native Segwit
            xpub = bip32.get_xpub_from_path('m/84h/0h/0h')
            zpub = convert_xpub_prefix(xpub, b'\x04\xb2\x47\x46')
            xpubs += "[%s/84'/0'/0']%s\n" % (master_fpr, zpub)
            # Multisig nested Segwit
            xpub = bip32.get_xpub_from_path('m/48h/0h/0h/1h')
            Ypub = convert_xpub_prefix(xpub, b'\x02\x95\xb4\x3f')
            xpubs += "[%s/48'/0'/0'/1']%s\n" % (master_fpr, Ypub)
            # Multisig native Segwit
            xpub = bip32.get_xpub_from_path('m/48h/0h/0h/2h')
            Zpub = convert_xpub_prefix(xpub, b'\x02\xaa\x7e\xd3')
            xpubs += "[%s/48'/0'/0'/2']%s\n" % (master_fpr, Zpub)
        else:
            # Testnet nested Segwit
            xpub = bip32.get_xpub_from_path('m/49h/1h/0h')
            upub = convert_xpub_prefix(xpub, b'\x04\x4a\x52\x62')
            xpubs += "[%s/49'/1'/0']%s\n" % (master_fpr, upub)
            # Testnet native Segwit
            xpub = bip32.get_xpub_from_path('m/84h/1h/0h')
            vpub = convert_xpub_prefix(xpub, b'\x04\x5f\x1c\xf6')
            xpubs += "[%s/84'/1'/0']%s\n" % (master_fpr, vpub)
            # Testnet multisig nested Segwit
            xpub = bip32.get_xpub_from_path('m/48h/1h/0h/1h')
            Upub = convert_xpub_prefix(xpub, b'\x02\x42\x89\xef')
            xpubs += "[%s/48'/1'/0'/1']%s\n" % (master_fpr, Upub)
            # Testnet multisig native Segwit
            xpub = bip32.get_xpub_from_path('m/48h/1h/0h/2h')
            Vpub = convert_xpub_prefix(xpub, b'\x02\x57\x54\x83')
            xpubs += "[%s/48'/1'/0'/2']%s\n" % (master_fpr, Vpub)

        keys, failed = Key.parse_xpubs(xpubs)
        if len(failed) > 0:
            # TODO: This should never occur, but just in case, we must make sure to catch it properly so it doesn't crash the app no matter what.
            raise Exception("Failed to parse these xpubs:\n" + "\n".join(failed))
        else:
            self.add_keys(keys)
Ejemplo n.º 23
0
    def SignFundingTx(self, request, context):
        """BOLT #3 - Funding Transaction
        Sign the funding transaction
        TODO this must be done after we know the remote signature on the
        commitment tx - need an API call that provides this to the
        signer.
        """

        node_id = request.node_id.data
        node = self.nodes.get(node_id)
        logger.debug("SignFundingTx node:%s" % node_id)

        xpub = node.bip32_key.get_xpriv_from_path('m/0/0')
        onchain_bip32_key = BIP32.from_xpriv(xpub)

        tx = request.tx
        tx = Transaction.import_raw(tx.raw_tx_bytes, self.network)

        reply = remotesigner_pb2.SignFundingTxReply()
        witnesses = remotesigner_pb2.Witness()

        local_prv = None
        local_key = None
        logger.debug(request)
        logger.debug(request.tx.raw_tx_bytes.hex())
        for i, input_desc in enumerate(request.tx.input_descs):
            key_index = input_desc.key_loc.key_index
            spend_type = input_desc.spend_type
            amount = input_desc.prev_output.value_sat
            channel_nonce = input_desc.close_info.channel_nonce.data
            commitment_point = input_desc.close_info.commitment_point.data
            channel = node.channels.get(channel_nonce)

            if key_index != 0:
                local_prv = onchain_bip32_key.get_privkey_from_path("m/%d" %
                                                                    key_index)
                local_key = Key(import_key=local_prv, is_private=True)
            elif channel:
                if commitment_point:
                    local_priv_key = derive_priv_key(
                        commitment_point, payment_basepoint,
                        channel.basepoints.keys.payment_basepoint_secret)
                    local_key = Key(import_key=local_priv_key, is_private=True)
                else:
                    local_key = Key(import_key=channel.basepoints.keys.
                                    payment_basepoint_secret,
                                    is_private=True)
            else:
                witnesses.signature.data = b''
                witnesses.pubkey.data = b''
                reply.witnesses.extend([witnesses])
                continue

            spend_type = spend_type_to_string(spend_type)
            tx.inputs[i].script_type = spend_type
            logger.debug("funding signature: %s" % spend_type)
            tx.inputs[i].witness_type = "segwit"
            tx.inputs[i].sigs_required = 1
            tx.inputs[i].value = amount
            if spend_type == 'p2pkh':
                tx.witness_type = 'legacy'
            else:
                tx.witness_type = 'segwit'
            tx.sign(keys=[local_key], tid=i)

            witnesses.signature.data = tx.inputs[i].witnesses[0]
            witnesses.pubkey.data = tx.inputs[i].witnesses[1]

            logger.debug("funding signature: %s" %
                         tx.inputs[i].signatures[0].as_der_encoded().hex())
            logger.debug("funding public key %s" %
                         tx.inputs[i].as_dict()['public_keys'])
            reply.witnesses.extend([witnesses])
        logger.debug(reply)
        return reply