Ejemplo n.º 1
0
def main():
    # generate 16 bytes of entropy and
    # convert to a mnemonic phrase (12 words)
    entropy = bytes([urandom.getrandbits(8) for i in range(16)])
    mnemonic = bip39.mnemonic_from_bytes(entropy)
    # or just define hardcoded:
    mnemonic = "alien visual jealous source coral memory embark certain radar capable clip edit"
    print(mnemonic)
    # convert to seed, empty password
    seed = bip39.mnemonic_to_seed(mnemonic)
    # convert to the root key
    # you can define the version - x/y/zprv for desired network
    root = bip32.HDKey.from_seed(seed, version=NETWORKS["test"]["xprv"])
    print(root.to_base58())

    print("\nBIP-44 - legacy")
    # derive account according to bip44
    bip44_xprv = root.derive("m/44h/1h/0h")
    print(bip44_xprv.to_base58())
    # corresponding master public key:
    bip44_xpub = bip44_xprv.to_public()
    print(bip44_xpub.to_base58())
    # first 5 receiving addresses
    for i in range(5):
        # .key member is a public key for HD public keys
        #            and a private key for HD private keys
        pub = bip44_xpub.derive("m/0/%d" % i).key
        sc = script.p2pkh(pub)
        print(sc.address(NETWORKS["test"]))

    print("\nBIP-84 - native segwit")
    # derive account according to bip84
    bip84_xprv = root.derive("m/84h/1h/0h")
    # you can also change version of the key to get zpub (vpub on testnet)
    bip84_xprv.version = NETWORKS["test"]["zprv"]
    print(bip84_xprv.to_base58())
    # corresponding master public key:
    bip84_xpub = bip84_xprv.to_public()
    print(bip84_xpub.to_base58())
    # first 5 receiving addresses
    for i in range(5):
        pub = bip84_xpub.derive("m/0/%d" % i).key
        sc = script.p2wpkh(pub)
        print(sc.address(NETWORKS["test"]))

    print("\nBIP-49 - nested segwit")
    # derive account according to bip49
    bip49_xprv = root.derive("m/49h/1h/0h")
    # you can also change version of the key to get ypub (upub on testnet)
    bip49_xprv.version = NETWORKS["test"]["yprv"]
    print(bip49_xprv.to_base58())
    # corresponding master public key:
    bip49_xpub = bip49_xprv.to_public()
    print(bip49_xpub.to_base58())
    # first 5 receiving addresses
    for i in range(5):
        pub = bip49_xpub.derive("m/0/%d" % i).key
        # use p2sh(p2wpkh(pubkey)) to get nested segwit scriptpubkey
        sc = script.p2sh(script.p2wpkh(pub))
        print(sc.address(NETWORKS["test"]))
Ejemplo n.º 2
0
def main():
    # all from the same private key
    prv = ec.PrivateKey.from_wif(
        "L2e5y14ZD3U1J7Yr62t331RtYe2hRW2TBBP8qNQHB8nSPBNgt6dM")
    pub = prv.get_public_key()
    print("Public key:")
    print(hexlify(pub.serialize()))

    # we will generate regtest addresses
    network = NETWORKS['regtest']

    print("Legacy (pay to pubkey hash):")
    sc = script.p2pkh(pub)
    # default network is main
    print(sc.address(network))

    print("Segwit (pay to witness pubkey hash):")
    sc = script.p2wpkh(pub)
    print(sc.address(network))

    print("Nested segwit (p2sh-p2wpkh):")
    sc = script.p2sh(script.p2wpkh(pub))
    print(sc.address(network))

    print("\nMiltisig address (2 of 3):")
    # unsorted
    pubs = [
        ec.PublicKey.parse(
            unhexlify(
                "02edd7a58d2ff1e483d35f92a32e53607423f936b29bf95613cab24b0b7f92e0f1"
            )),
        ec.PublicKey.parse(
            unhexlify(
                "03a4a6d360acc45cb281e0022b03218fad6ee93881643488ae39d22b854d9fa261"
            )),
        ec.PublicKey.parse(
            unhexlify(
                "02e1fdc3b011effbba4b0771eb0f7193dee24cfe101ab7e8b64516d83f7116a615"
            )),
    ]
    # 2 of 3 multisig script
    sc = script.multisig(2, pubs)
    print("Legacy, unsorted (p2sh):")
    redeem_sc = script.p2sh(sc)
    print(redeem_sc.address(network))

    print("Native segwit, sorted (p2wsh):")
    sc = script.multisig(2, sorted(pubs))
    witness_sc = script.p2wsh(sc)
    print(witness_sc.address(network))

    print("Nested segwit, sorted (p2sh-p2wsh):")
    sc = script.multisig(2, sorted(pubs))
    witness_sc = script.p2wsh(sc)
    redeem_sc = script.p2sh(witness_sc)
    print(redeem_sc.address(network))
Ejemplo n.º 3
0
    async def showaddr(self,
                       paths: list,
                       script_type: str,
                       redeem_script=None,
                       show_screen=None) -> str:
        if redeem_script is not None:
            redeem_script = script.Script(unhexlify(redeem_script))
        # first check if we have corresponding wallet:
        # - just take last 2 indexes of the derivation
        # and see if redeem script matches
        address = None
        if redeem_script is not None:
            if script_type == b"wsh":
                address = script.p2wsh(redeem_script).address(
                    NETWORKS[self.network])
            elif script_type == b"sh-wsh":
                address = script.p2sh(script.p2wsh(redeem_script)).address(
                    NETWORKS[self.network])
            else:
                raise HostError("Unsupported script type: %s" % script_type)
        # in our wallets every key
        # has the same two last indexes for derivation
        path = paths[0]
        if not path.startswith(b"m/"):
            path = b"m" + path[8:]
        derivation = bip32.parse_path(path.decode())

        # if not multisig:
        if address is None and len(paths) == 1:
            pub = self.keystore.get_xpub(derivation)
            if script_type == b"wpkh":
                address = script.p2wpkh(pub).address(NETWORKS[self.network])
            elif script_type == b"sh-wpkh":
                address = script.p2sh(
                    script.p2wpkh(pub).address(NETWORKS[self.network]))
            else:
                raise WalletError("Unsupported script type: %s" % script_type)

        if len(derivation) >= 2:
            derivation = derivation[-2:]
        else:
            raise WalletError("Invalid derivation")
        if address is None:
            raise WalletError("Can't derive address. Provide redeem script.")
        try:
            change = bool(derivation[0])
            w = self.find_wallet_from_address(address,
                                              derivation[1],
                                              change=change)
        except Exception as e:
            raise WalletError("%s" % e)
        if show_screen is not None:
            await show_screen(
                WalletScreen(w, self.network, derivation[1], change=change))
        return address
Ejemplo n.º 4
0
def derive_address_from_keypath(keypath, address_pubkey, network):
    address_type_keypath = get_address_type_keypath(keypath)
    if address_type_keypath == BIP_44_KEYPATH:
        return p2pkh(address_pubkey).address(NETWORKS[network])
    elif address_type_keypath == BIP_49_KEYPATH:
        redeem_script = p2wpkh(address_pubkey)
        return p2sh(redeem_script).address(NETWORKS[network])
    elif address_type_keypath == BIP_84_KEYPATH:
        return p2wpkh(address_pubkey).address(NETWORKS[network])
    else:
        raise Exception("Invalid keypath")
Ejemplo n.º 5
0
 def scriptpubkey(self, derivation):
     """Derivation should be an array of two ints: [change 0 or 1, index]"""
     if len(derivation) != 2:
         raise ScriptError("Derivation should be of len 2")
     change, idx = derivation
     if change not in [0, 1] or idx < 0:
         raise ScriptError("Invalid change or index")
     pub = self.key.derive([change, idx])
     return script.p2wpkh(pub)
Ejemplo n.º 6
0
    async def showaddr(self,
                       paths: list,
                       script_type: str,
                       redeem_script=None,
                       show_screen=None) -> str:
        net = self.Networks[self.network]
        if redeem_script is not None:
            redeem_script = script.Script(unhexlify(redeem_script))
        # first check if we have corresponding wallet:
        address = None
        if redeem_script is not None:
            if script_type == b"wsh":
                address = script.p2wsh(redeem_script).address(net)
            elif script_type == b"sh-wsh":
                address = script.p2sh(script.p2wsh(redeem_script)).address(net)
            elif script_type == b"sh":
                address = script.p2sh(redeem_script).address(net)
            else:
                raise WalletError("Unsupported script type: %s" % script_type)

        else:
            if len(paths) != 1:
                raise WalletError("Invalid number of paths, expected 1")
            path = paths[0]
            if not path.startswith("m/"):
                path = "m" + path[8:]
            derivation = bip32.parse_path(path)
            pub = self.keystore.get_xpub(derivation)
            if script_type == b"wpkh":
                address = script.p2wpkh(pub).address(net)
            elif script_type == b"sh-wpkh":
                address = script.p2sh(script.p2wpkh(pub)).address(net)
            elif script_type == b"pkh":
                address = script.p2pkh(pub).address(net)
            else:
                raise WalletError("Unsupported script type: %s" % script_type)

        w, (idx, branch_idx) = self.find_wallet_from_address(address,
                                                             paths=paths)
        if show_screen is not None:
            await show_screen(
                WalletScreen(w, self.network, idx, branch_index=branch_idx))
        addr, _ = w.get_address(idx, self.network, branch_idx)
        return addr
Ejemplo n.º 7
0
 def parse_psbt(self, tx):
     # our result will be a dict of the form:
     # {
     #   "total_in": amount_in_sat,
     #   "spending": amount_in_sat,
     #   "spending_outputs": [ (address, amount_in_sat), ... ],
     #   "fee": amount_in_sat
     # }
     res = {}
     # print how much we are spending and where
     total_in = 0
     for inp in tx.inputs:
         total_in += inp.witness_utxo.value
     res["total_in"] = total_in
     change_out = 0  # value that goes back to us
     send_outputs = []
     for i, out in enumerate(tx.outputs):
         # check if it is a change or not:
         change = False
         # should be one or zero for single-key addresses
         for pub in out.bip32_derivations:
             # check if it is our key
             if out.bip32_derivations[pub].fingerprint == self.fingerprint:
                 hdkey = self.root.derive(
                     out.bip32_derivations[pub].derivation)
                 mypub = hdkey.key.get_public_key()
                 if mypub != pub:
                     raise ValueError("Derivation path doesn't look right")
                 # now check if provided scriptpubkey matches
                 sc = script.p2wpkh(mypub)
                 if sc == tx.tx.vout[i].script_pubkey:
                     change = True
                     continue
         if change:
             change_out += tx.tx.vout[i].value
         else:
             send_outputs.append(tx.tx.vout[i])
     res["spending"] = total_in - change_out
     res["spending_outputs"] = []
     fee = total_in - change_out
     for out in send_outputs:
         fee -= out.value
         res["spending_outputs"].append(
             (out.script_pubkey.address(self.network), out.value))
     res["fee"] = fee
     return res
Ejemplo n.º 8
0
def host_callback(data):
    # close all existing popups
    popups.close_all_popups()

    if data=="fingerprint":
        usb_host.respond(hexlify(keystore.fingerprint).decode('ascii'))
        return

    if data.startswith("xpub "):
        path = data[5:].strip(" /\r\n")
        try:
            if path == "m":
                hd = keystore.root.to_public()
            else:
                hd = keystore.get_xpub(path)
            xpub = hd.to_base58(network["xpub"])
            usb_host.respond(xpub)

            show_xpub("Master key requested from host:", path, hd)
        except Exception as e:
            print(e)
            usb_host.respond("error: bad derivation path '%s'" % path)
        return

    if data.startswith("sign "):
        def success_cb(signed_tx):
            usb_host.respond(signed_tx)
        def error_cb(error):
            usb_host.respond("error: %s" % error)
        parse_transaction(data[5:], success_callback=success_cb, error_callback=error_cb)
        return

    if data.startswith("showaddr "):
        arr = data.split(" ")
        path = arr[-1].strip()
        addrtype = "wpkh"
        if len(arr) > 2:
            addrtype = arr[-2].strip()
        # TODO: detect wallet this address belongs to
        try:
            key = keystore.get_xpub(path)
            if addrtype == "wpkh":
                sc = script.p2wpkh(key)
            elif addrtype == "pkh":
                sc = script.p2pkh(key)
            elif addrtype == "sh-wpkh":
                sc = script.p2sh(script.p2wpkh(key))
            else:
                raise RuntimeError()
            addr=sc.address(network)
            usb_host.respond(addr)
            popups.qr_alert("Address with path %s\n(requested by host)" % (path),
                            "bitcoin:"+addr, message_text=addr)

        except Exception as e:
            print(e)
            usb_host.respond("error: invalid argument")
        return

    if data.startswith("importwallet "):
        parse_new_wallet(data[13:])
Ejemplo n.º 9
0
def main():
    # all from the same private key
    prv = ec.PrivateKey.from_wif("L2e5y14ZD3U1J7Yr62t331RtYe2hRW2TBBP8qNQHB8nSPBNgt6dM")
    pub = prv.get_public_key()
    inputs = [
        # legacy
        {
            "txid": unhexlify("7f0c7538e898bbe5531fa47d4057b52c914ec45e20ae1a5572ea1005a8ba50f8"),
            "vout": 0,
            "value": int(1e8),
            "script": script.p2pkh(pub)
        },
        # native segwit
        {
            "txid": unhexlify("f51e6fc2392558a70ae970e93538f368828ad2800a7370f372a652de463429fc"),
            "vout": 0,
            "value": int(2e8),
            "script": script.p2wpkh(pub)
        },
        # nested segwit
        {
            "txid": unhexlify("2e4cb680ed008b6e529c4c83f00d55326a2e68b48ddf11267e3f5323006966a6"),
            "vout": 1,
            "value": int(3e8),
            "script": script.p2sh(script.p2wpkh(pub)),
            "redeem": script.p2wpkh(pub)
        }
    ]
    # sending back almost the same amount
    vin = [TransactionInput(inp["txid"], inp["vout"]) for inp in inputs]
    vout = [TransactionOutput(inp["value"]-1500, inp["script"]) for inp in inputs]
    tx = Transaction(vin=vin,vout=vout)
    print("Unsigned transaction:")
    print(hexlify(tx.serialize()).decode('utf-8'))

    for i in range(len(inputs)):
        inp = inputs[i]
        script_type = inp["script"].script_type()
        # legacy input
        if script_type == "p2pkh":
            h = tx.sighash_legacy(i, inp["script"])
            sig = prv.sign(h)
            tx.vin[i].script_sig = script.script_sig_p2pkh(sig, pub)
        # native segwit
        elif script_type == "p2wpkh":
            sc = script.p2pkh_from_p2wpkh(inp["script"])
            h = tx.sighash_segwit(i, sc, inp["value"])
            sig = prv.sign(h)
            tx.vin[i].witness = script.witness_p2wpkh(sig, pub)
        # nested segwit
        elif script_type == "p2sh":
            if "redeem" in inp and inp["redeem"].script_type() == "p2wpkh":
                sc = script.p2pkh_from_p2wpkh(inp["redeem"])
                h = tx.sighash_segwit(i, sc, inp["value"])
                sig = prv.sign(h)
                tx.vin[i].script_sig = script.script_sig_p2sh(inp["redeem"])
                tx.vin[i].witness = script.witness_p2wpkh(sig, pub)
            else:
                raise NotImplementedError("Script type is not supported")
        else:
            raise NotImplementedError("Script type is not supported")

    print("Signed transaction:")
    print(hexlify(tx.serialize()).decode('utf-8'))
Ejemplo n.º 10
0
        self.title.set_text("Address #%d" % (idx+1))
        self.title.align(self, lv.ALIGN.IN_TOP_MID, 0, 50)
        pub = self.account.derive([int(change), idx]).key
        addr = self.script_fn(pub).address(network=self.network)
        self.qr.set_text("bitcoin:"+addr)
        self.lbl.set_text(addr)
        self.lbl.set_align(lv.label.ALIGN.CENTER)
        self.lbl.align(self.qr, lv.ALIGN.OUT_BOTTOM_MID, 0, 20)
        self.prev_btn.set_state(lv.btn.STATE.INA if idx == 0 else lv.btn.STATE.REL)
        self.next_btn.align(self.qr, lv.ALIGN.OUT_BOTTOM_MID, 90, 70)
        self.prev_btn.align(self.qr, lv.ALIGN.OUT_BOTTOM_MID, -90, 70)

    def next_address(self, obj, event):
        if event == lv.EVENT.RELEASED:
            self._index += 1
            self.show_address(self._index)
            
    def prev_address(self, obj, event):
        if event == lv.EVENT.RELEASED and self._index > 0:
            self._index -= 1
            self.show_address(self._index)

scr = AddressNavigator(root.derive("m/49h/1h/0h").to_public(),         # bip-49 account xpub
                script_fn=lambda pub: script.p2sh(script.p2wpkh(pub)), # p2sh-p2wpkh
                network=NETWORKS["test"]                               # testnet
                )

lv.scr_load(scr)


Ejemplo n.º 11
0
# for Electrum and others who cares about SLIP-0132
# used for bip-84 by many wallets
print("\nYour zpub:", account_pub.to_base58(version=NETWORKS["test"]["zpub"]))

print("\nLegacy addresses:")
xpub_bip44 = root_key.derive("m/44h/1h/0h").to_public()
print("Legacy xpub:", xpub_bip44.to_base58(version=network["xpub"]))
for i in range(5):
    # m/0/i is used for receiving addresses and m/1/i for change addresses
    pub = xpub_bip44.derive("m/0/%d" % i)
    # get p2pkh script
    sc = script.p2pkh(pub)
    print("Address %i: %s" % (i, sc.address(network)))

print("\nSegwit addresses:")
xpub_bip84 = root_key.derive("m/84h/1h/0h").to_public()
print("Segwit zpub:", xpub_bip84.to_base58(version=network["zpub"]))
for i in range(5):
    pub = xpub_bip84.derive("m/0/%d" % i)
    # get p2wsh script
    sc = script.p2wpkh(pub)
    print("Address %i: %s" % (i, sc.address(network)))

print("\nNested segwit addresses:")
xpub_bip49 = root_key.derive("m/49h/1h/0h").to_public()
print("Nested Segwit ypub:", xpub_bip49.to_base58(version=network["ypub"]))
for i in range(5):
    pub = xpub_bip49.derive("m/0/%d" % i)
    # get p2sh(p2wpkh) script
    sc = script.p2sh(script.p2wpkh(pub))
    print("Address %i: %s" % (i, sc.address(network)))
Ejemplo n.º 12
0
print("Inputs:", total_in, "satoshi")
change_out = 0  # value that goes back to us
send_outputs = []
for i, out in enumerate(tx.outputs):
    # check if it is a change or not:
    change = False
    # should be one or zero for single-key addresses
    for pub in out.bip32_derivations:
        # check if it is our key
        if out.bip32_derivations[pub].fingerprint == fingerprint:
            hdkey = root.derive(out.bip32_derivations[pub].derivation)
            mypub = hdkey.key.get_public_key()
            if mypub != pub:
                raise ValueError("Derivation path doesn't look right")
            # now check if provided scriptpubkey matches
            sc = script.p2wpkh(mypub)
            if sc == tx.tx.vout[i].script_pubkey:
                change = True
                continue
    if change:
        change_out += tx.tx.vout[i].value
    else:
        send_outputs.append(tx.tx.vout[i])
print("Spending", total_in - change_out, "satoshi")
fee = total_in - change_out
for out in send_outputs:
    fee -= out.value
    print(out.value, "to", out.script_pubkey.address(NETWORKS["test"]))
print("Fee:", fee, "satoshi")

# sign the transaction
Ejemplo n.º 13
0
 def address(self, idx, change=False):
     sc = script.p2wpkh(self.account.derive([int(change), idx]))
     return sc.address(self.network)
Ejemplo n.º 14
0
def main():
    # get root key from the mnemonic
    mnemonic = "alien visual jealous source coral memory embark certain radar capable clip edit"
    seed = bip39.mnemonic_to_seed(mnemonic)
    root = bip32.HDKey.from_seed(seed, version=NETWORKS["test"]["xprv"])

    # get bip84-xpub to import to Bitcoin Core:
    # we will use the form [fingerprint/derivation]xpub
    # to import to Bitcoin Core with descriptors

    # first let's get the root fingerprint
    # we can get it from any child of the root key
    fingerprint = root.child(0).fingerprint
    hardened_derivation = "m/84h/1h/0h"
    # derive account according to bip84
    bip84_xprv = root.derive(hardened_derivation)
    # corresponding master public key:
    bip84_xpub = bip84_xprv.to_public()
    print("[%s%s]%s" % (hexlify(fingerprint).decode('utf-8'),
                        hardened_derivation[1:], bip84_xpub.to_base58()))

    # parse psbt transaction
    b64_psbt = "cHNidP8BAHICAAAAAY3LB6teEH6qJHluFYG3AQe8n0HDUcUSEuw2WIJ1ECDUAAAAAAD/////AoDDyQEAAAAAF6kU882+nVMDKGj4rKzjDB6NjyJqSBCHaPMhCgAAAAAWABQUbW8/trQg4d3PKL8WLi2kUa1BqAAAAAAAAQEfAMLrCwAAAAAWABTR6Cr4flM2A0LMGjGiaZ+fhod37SIGAhHf737H1jCUjkJ1K5DqFkaY0keihxeWBQpm1kDtVZyxGLMX7IZUAACAAQAAgAAAAIAAAAAAAAAAAAAAIgIDPtTTi27VFw59jdmWDV8b1YciQzhYGO7m8zB9CvD0brcYsxfshlQAAIABAACAAAAAgAEAAAAAAAAAAA=="
    # first convert it to binary
    raw = a2b_base64(b64_psbt)
    # then parse
    tx = psbt.PSBT.parse(raw)

    # print how much we are spending and where
    total_in = 0
    for inp in tx.inputs:
        total_in += inp.witness_utxo.value
    print("Inputs:", total_in, "satoshi")
    change_out = 0  # value that goes back to us
    send_outputs = []
    for i, out in enumerate(tx.outputs):
        # check if it is a change or not:
        change = False
        # should be one or zero for single-key addresses
        for pub in out.bip32_derivations:
            # check if it is our key
            if out.bip32_derivations[pub].fingerprint == fingerprint:
                hdkey = root.derive(out.bip32_derivations[pub].derivation)
                mypub = hdkey.key.get_public_key()
                if mypub != pub:
                    raise ValueError("Derivation path doesn't look right")
                # now check if provided scriptpubkey matches
                sc = script.p2wpkh(mypub)
                if sc == tx.tx.vout[i].script_pubkey:
                    change = True
                    continue
        if change:
            change_out += tx.tx.vout[i].value
        else:
            send_outputs.append(tx.tx.vout[i])
    print("Spending", total_in - change_out, "satoshi")
    fee = total_in - change_out
    for out in send_outputs:
        fee -= out.value
        print(out.value, "to", out.script_pubkey.address(NETWORKS["test"]))
    print("Fee:", fee, "satoshi")

    # sign the transaction
    tx.sign_with(root)
    raw = tx.serialize()
    # convert to base64
    b64_psbt = b2a_base64(raw)
    # somehow b2a ends with \n...
    if b64_psbt[-1:] == b"\n":
        b64_psbt = b64_psbt[:-1]
    # print
    print("\nSigned transaction:")
    print(b64_psbt.decode('utf-8'))