Ejemplo n.º 1
1
def test_duplicate_xfp(N, offer_ms_import, need_keypress, test_ms_show_addr):
    # it's legit to have duplicate XFP values! Not hard to make either!

    # new wallet will all having same XFP, but different xpubs
    pk = BIP32Node.from_wallet_key(simulator_fixed_xprv)

    keys = [(simulator_fixed_xfp, pk, pk.subkey(45, is_hardened=True, as_private=False))]
    lst = [keys[0][-1]]
    for idx in range(N-1):
        h = BIP32Node.from_hwif(pk.hwif(as_private=True))        # deepcopy
        h._chain_code = b'chain code is 32 bytes: %08d' % idx
        subkey = h.subkey(45, is_hardened=True, as_private=False)
        lst.append(subkey)

        xfp = unpack("<I", pk.fingerprint())[0]
        keys.append( (xfp, h, subkey) )

    #print(lst)

    # bare, no fingerprints
    # - no xfps
    # - no meta data
    config = '\n'.join(sk.hwif(as_private=False) for sk in lst)
    title, story = offer_ms_import(config)
    assert f'Policy: {N} of {N}\n' in story
    need_keypress('y')

    test_ms_show_addr(N, keys)
Ejemplo n.º 2
0
 def test_streams(self):
     m0 = BIP32Node.from_master_secret("foo bar baz".encode("utf8"))
     pm0 = m0.public_copy()
     self.assertEqual(m0.wallet_key(), pm0.wallet_key())
     m1 = m0.subkey()
     pm1 = pm0.subkey()
     for i in range(4):
         m = m1.subkey(i=i)
         pm = pm1.subkey(i=i)
         self.assertEqual(m.wallet_key(), pm.wallet_key())
         self.assertEqual(m.bitcoin_address(), pm.bitcoin_address())
         m2 = BIP32Node.from_wallet_key(m.wallet_key(as_private=True))
         m3 = m2.public_copy()
         self.assertEqual(m.wallet_key(as_private=True), m2.wallet_key(as_private=True))
         self.assertEqual(m.wallet_key(), m3.wallet_key())
         print(m.wallet_key(as_private=True))
         for j in range(2):
             k = m.subkey(i=j)
             k2 = BIP32Node.from_wallet_key(k.wallet_key(as_private=True))
             k3 = BIP32Node.from_wallet_key(k.wallet_key())
             k4 = k.public_copy()
             self.assertEqual(k.wallet_key(as_private=True), k2.wallet_key(as_private=True))
             self.assertEqual(k.wallet_key(), k2.wallet_key())
             self.assertEqual(k.wallet_key(), k3.wallet_key())
             self.assertEqual(k.wallet_key(), k4.wallet_key())
             print("   %s %s" % (k.bitcoin_address(), k.wif()))
Ejemplo n.º 3
0
def test_b9p_vectors(dev,
                     set_seed_words,
                     need_keypress,
                     vector,
                     pw='RoZert'[::-1].upper()):
    # Test all BIP39 vectors. Slow.
    _, words, cooked, xprv = vector

    seed = Mnemonic.to_seed(words, passphrase=pw)
    assert seed == a2b_hex(cooked)

    set_seed_words(words)

    dev.send_recv(CCProtocolPacker.bip39_passphrase(pw), timeout=None)

    need_keypress('y')

    xpub = None
    while xpub == None:
        time.sleep(0.050)
        xpub = dev.send_recv(CCProtocolPacker.get_passphrase_done(),
                             timeout=None)

    # check our math (ignore testnet vs. mainnet)
    got = BIP32Node.from_wallet_key(xpub)
    exp = BIP32Node.from_wallet_key(xprv)

    assert got.public_pair() == exp.public_pair()
Ejemplo n.º 4
0
def test_public(sim_execfile):
    "verify contents of public 'dump' file"
    from pycoin.key.BIP32Node import BIP32Node
    from pycoin.contrib.segwit_addr import encode as sw_encode
    from pycoin.contrib.segwit_addr import decode as sw_decode
    from pycoin.encoding import a2b_hashed_base58, hash160

    pub = sim_execfile('devtest/dump_public.py')
    assert 'Error' not in pub

    #print(pub)

    pub, dev = pub.split('#DEBUG#', 1)
    assert 'pub' in pub
    assert 'prv' not in pub
    assert 'prv' in dev

    lines = [i.strip() for i in pub.split('\n')]

    for ln in lines:
        if ln[1:4] == 'pub':
            node_pub = BIP32Node.from_wallet_key(ln)
            break

    node_prv = BIP32Node.from_wallet_key(dev.strip())

    # pub and private are linked
    assert node_prv.hwif(as_private=False) == node_pub.hwif()

    # check every path we derived
    count = 0
    for ln in lines:
        if ln[0:1] == 'm' and '=>' in ln:
            subpath, result = ln.split(' => ', 1)

            sk = node_prv.subkey_for_path(subpath[2:])

            if result[0:2] in {'tp', 'xp'}:
                expect = BIP32Node.from_wallet_key(result)
                assert sk.hwif(as_private=False) == result
            elif result[0] in '1mn':
                assert result == sk.address(False)
            elif result[0:3] in {'bc1', 'tb1'}:
                h20 = sk.hash160()
                assert result == sw_encode(result[0:2], 0, h20)
            elif result[0] in '23':
                h20 = hash160(b'\x00\x14' + sk.hash160())
                assert h20 == a2b_hashed_base58(result)[1:]
            else:
                raise ValueError(result)

            count += 1
            print("OK: %s" % ln)

    assert count > 12
Ejemplo n.º 5
0
    def doit(given_addr, path=None, addr_fmt=None, script=None):
        if not script:
            try:
                # prefer using xpub if we can
                mk = BIP32Node.from_wallet_key(master_xpub)
                sk = mk.subkey_for_path(path[2:])
            except PublicPrivateMismatchError:
                mk = BIP32Node.from_wallet_key(simulator_fixed_xprv)
                sk = mk.subkey_for_path(path[2:])


        if addr_fmt == AF_CLASSIC:
            # easy
            assert sk.address() == given_addr

        elif addr_fmt & AFC_PUBKEY:

            pkh = sk.hash160(use_uncompressed=False)

            if addr_fmt == AF_P2WPKH:
                hrp, data = bech32_decode(given_addr)
                decoded = convertbits(data[1:], 5, 8, False)
                assert hrp in {'tb', 'bc' }
                assert bytes(decoded[-20:]) == pkh
            else:
                assert addr_fmt == AF_P2WPKH_P2SH
                assert given_addr[0] in '23'
                expect = a2b_hashed_base58(given_addr)[1:]
                assert len(expect) == 20
                assert hash160(b'\x00\x14' + pkh) == expect

        elif addr_fmt & AFC_SCRIPT:
            assert script, 'need a redeem/witness script'
            if addr_fmt == AF_P2SH:
                assert given_addr[0] in '23'
                expect = a2b_hashed_base58(given_addr)[1:]
                assert hash160(script) == expect

            elif addr_fmt == AF_P2WSH:
                hrp, data = bech32_decode(given_addr)
                assert hrp in {'tb', 'bc' }
                decoded = convertbits(data[1:], 5, 8, False)
                assert bytes(decoded[-32:]) == sha256(script).digest()

            elif addr_fmt == AF_P2WSH_P2SH:
                assert given_addr[0] in '23'
                expect = a2b_hashed_base58(given_addr)[1:]
                assert hash160(b'\x00\x20' + sha256(script).digest()) == expect

            else:
                raise pytest.fail(f'not ready for {addr_fmt:x} yet')
        else:
            raise ValueError(addr_fmt)

        return sk if not script else None
Ejemplo n.º 6
0
def test_export_electrum(mode, dev, cap_menu, pick_menu_item, goto_home,
                         cap_story, need_keypress, microsd_path):
    # lightly test electrum wallet export

    goto_home()
    pick_menu_item('Advanced')
    pick_menu_item('MicroSD Card')
    pick_menu_item('Export Wallet')
    pick_menu_item('Electrum Wallet')

    time.sleep(0.1)
    title, story = cap_story()

    assert 'This saves a skeleton Electrum wallet' in story

    need_keypress('y')

    time.sleep(0.1)
    pick_menu_item(mode)

    time.sleep(0.1)
    title, story = cap_story()

    assert 'wallet file written' in story
    fname = story.split('\n')[-1]

    need_keypress('y')

    path = microsd_path(fname)
    with open(path, 'rt') as fp:
        obj = json.load(fp)

        ks = obj['keystore']
        assert ks['ckcc_xfp'] == simulator_fixed_xfp

        assert ks['hw_type'] == 'coldcard'
        assert ks['type'] == 'hardware'

        deriv = ks['derivation']
        assert deriv.startswith('m/')
        assert int(deriv.split("/")[1][:-1]) in {44, 84, 49}  # weak

        xpub = ks['xpub']
        assert xpub[1:4] == 'pub'

        if xpub[0] in 'tx':
            # no slip132 here

            got = BIP32Node.from_wallet_key(xpub)
            expect = BIP32Node.from_wallet_key(
                simulator_fixed_xprv).subkey_for_path(deriv[2:])

            assert got.sec() == expect.sec()

    os.unlink(path)
Ejemplo n.º 7
0
Archivo: Key.py Proyecto: Zibbo/pycoin
    def from_text(class_, text, is_compressed=True):
        """
        This function will accept a BIP0032 wallet string, a WIF, or a bitcoin address.

        The "is_compressed" parameter is ignored unless a public address is passed in.
        """

        data = a2b_hashed_base58(text)
        netcode, key_type = netcode_and_type_for_data(data)
        data = data[1:]

        if key_type in ("pub32", "prv32"):
            # TODO: fix this... it doesn't belong here
            from pycoin.key.BIP32Node import BIP32Node
            return BIP32Node.from_wallet_key(text)

        if key_type == 'wif':
            is_compressed = (len(data) > 32)
            if is_compressed:
                data = data[:-1]
            return Key(
                secret_exponent=from_bytes_32(data),
                prefer_uncompressed=not is_compressed, netcode=netcode)
        if key_type == 'address':
            return Key(hash160=data, is_compressed=is_compressed, netcode=netcode)
        raise EncodingError("unknown text: %s" % text)
Ejemplo n.º 8
0
def test_sign_msg_microsd_good(sign_on_microsd, master_xpub, msg, path, addr_vs_path, addr_fmt=AF_CLASSIC):

    # cases we expect to work
    sig, addr = sign_on_microsd(msg, path)

    raw = b64decode(sig)
    assert 40 <= len(raw) <= 65

    if addr_fmt != AF_CLASSIC:
        # TODO
        # - need bech32 decoder here
        # - pycoin can't do signature decode
        if addr_fmt & AFC_BECH32:
            assert '1' in addr
        return

    if path is None:
        path = 'm'

    if "'" not in path and 'p' not in path:
        # check expected addr was used
        mk = BIP32Node.from_wallet_key(master_xpub)
        sk = mk.subkey_for_path(path[2:])

        addr_vs_path(addr, path, addr_fmt)
    
        # verify signature
        assert verify_message(sk, sig, message=msg) == True
    else:
        # just verify signature
        assert verify_message(addr, sig, message=msg) == True
Ejemplo n.º 9
0
def master_xpub(dev):
    r = dev.send_recv(CCProtocolPacker.get_xpub('m'), timeout=None, encrypt=1)

    assert r[1:4] == 'pub', r

    if r[0:4] == dev.master_xpub[0:4]:
        assert r == dev.master_xpub
    elif dev.master_xpub:
        # testnet vs. mainnet difference
        from pycoin.key.BIP32Node import BIP32Node
        a = BIP32Node.from_wallet_key(r)
        b = BIP32Node.from_wallet_key(dev.master_xpub)

        assert a.secret_exponent() == b.secret_exponent()

    return r
Ejemplo n.º 10
0
Archivo: Key.py Proyecto: wpr101/pycoin
    def from_text(class_, text, is_compressed=True):
        """
        This function will accept a BIP0032 wallet string, a WIF, or a bitcoin address.

        The "is_compressed" parameter is ignored unless a public address is passed in.
        """

        data = a2b_hashed_base58(text)
        netcode, key_type, length = netcode_and_type_for_data(data)
        data = data[1:]

        if key_type in ("pub32", "prv32"):
            # TODO: fix this... it doesn't belong here
            from pycoin.key.BIP32Node import BIP32Node
            return BIP32Node.from_wallet_key(text)

        if key_type == 'wif':
            is_compressed = (len(data) > 32)
            if is_compressed:
                data = data[:-1]
            return Key(
                secret_exponent=from_bytes_32(data),
                prefer_uncompressed=not is_compressed, netcode=netcode)
        if key_type == 'address':
            return Key(hash160=data, is_compressed=is_compressed, netcode=netcode)
        raise EncodingError("unknown text: %s" % text)
Ejemplo n.º 11
0
    def mitm_verify(self, sig, expected_xpub):
        # First try with Pycoin
        try:
            from pycoin.key.BIP32Node import BIP32Node
            from pycoin.contrib.msg_signing import verify_message
            from pycoin.encoding import from_bytes_32
            from base64 import b64encode

            mk = BIP32Node.from_wallet_key(expected_xpub)
            return verify_message(mk,
                                  b64encode(sig),
                                  msg_hash=from_bytes_32(self.session_key))
        except ImportError:
            pass

        # If Pycoin is not available, do it using ecdsa
        from ecdsa import BadSignatureError, SECP256k1, VerifyingKey
        pubkey, chaincode = decode_xpub(expected_xpub)
        vk = VerifyingKey.from_string(get_pubkey_string(pubkey),
                                      curve=SECP256k1)
        try:
            ok = vk.verify_digest(sig[1:], self.session_key)
        except BadSignatureError:
            ok = False

        return ok
Ejemplo n.º 12
0
def test_stub_menu(sim_execfile, goto_address_explorer, need_keypress,
                   cap_menu, mk_common_derivations, parse_display_screen,
                   validate_address):
    # For a given wallet, ensure the explorer shows the correct stub addresses
    node_prv = BIP32Node.from_wallet_key(
        sim_execfile('devtest/dump_private.py').strip())
    common_derivs = mk_common_derivations(node_prv.netcode())

    # capture menu address stubs
    goto_address_explorer()
    need_keypress('4')
    time.sleep(.01)
    m = cap_menu()

    for idx, (path, addr_format) in enumerate(common_derivs):
        # derive index=0 address
        subpath = path.format(account=0, change=0,
                              idx=0)  # e.g. "m/44'/1'/0'/0/0"
        sk = node_prv.subkey_for_path(subpath[2:])

        # capture full index=0 address from display screen & validate it
        goto_address_explorer(click_idx=idx)
        addr_dict = parse_display_screen(0, 10)
        if subpath not in addr_dict:
            raise Exception(
                'Subpath ("%s") not found in address explorer display' %
                subpath)
        expected_addr = addr_dict[subpath]
        validate_address(expected_addr, sk)

        # validate that stub is correct
        [start, end] = m[idx].split('-')
        assert expected_addr.startswith(start)
        assert expected_addr.endswith(end)
Ejemplo n.º 13
0
    def doit(given_addr, path, addr_fmt):
        mk = BIP32Node.from_wallet_key(master_xpub)
        sk = mk.subkey_for_path(path[2:])

        if addr_fmt == AF_CLASSIC:
            # easy
            assert sk.address() == given_addr

        elif addr_fmt & AFC_PUBKEY:

            pkh = sk.hash160(use_uncompressed=False)

            if addr_fmt == AF_P2WPKH:
                hrp, data = bech32_decode(given_addr)
                decoded = convertbits(data[1:], 5, 8, False)
                assert hrp in {'tb', 'bc'}
                assert bytes(decoded[-20:]) == pkh
            else:
                assert addr_fmt == AF_P2WPKH_P2SH
                assert given_addr[0] in '23'
                expect = a2b_hashed_base58(given_addr)[1:]
                assert len(expect) == 20
                assert hash160(b'\x00\x14' + pkh) == expect

        elif addr_fmt & AFC_SCRIPT:
            raise pytest.fail('multisig/p2sh addr not handled')
        else:
            raise ValueError(addr_fmt)
Ejemplo n.º 14
0
def test_account_menu(account_num, sim_execfile, pick_menu_item,
                      goto_address_explorer, need_keypress, cap_menu,
                      mk_common_derivations, parse_display_screen,
                      validate_address):
    # Try a few sub-accounts
    node_prv = BIP32Node.from_wallet_key(
        sim_execfile('devtest/dump_private.py').strip())
    common_derivs = mk_common_derivations(node_prv.netcode())

    # capture menu address stubs
    goto_address_explorer()
    time.sleep(.01)
    # skip warning
    need_keypress('4')
    time.sleep(.01)

    m = cap_menu()
    pick_menu_item([i for i in m if i.startswith('Account')][0])

    # enter account number
    time.sleep(0.1)
    for d in str(account_num):
        need_keypress(d)
    need_keypress('y')
    time.sleep(0.1)

    m = cap_menu()
    assert f'Account: {account_num}' in m

    which = 0
    for idx, (path, addr_format) in enumerate(common_derivs[1:]):
        # derive index=0 address
        assert '{account}' in path

        subpath = path.format(account=account_num, change=0,
                              idx=0)  # e.g. "m/44'/1'/X'/0/0"
        sk = node_prv.subkey_for_path(subpath[2:])

        # capture full index=0 address from display screen & validate it

        # go down menu to expected derivation spot
        m = cap_menu()
        pick_menu_item(m[idx])
        time.sleep(0.1)

        addr_dict = parse_display_screen(0, 10)
        if subpath not in addr_dict:
            raise Exception(
                'Subpath ("%s") not found in address explorer display' %
                subpath)
        expected_addr = addr_dict[subpath]
        validate_address(expected_addr, sk)

        # validate that stub is correct
        [start, end] = m[idx].split('-')
        assert expected_addr.startswith(start)
        assert expected_addr.endswith(end)

        need_keypress('x')
Ejemplo n.º 15
0
    def doit(num_ins, num_outs, master_xpub, subpath="0/%d", fee=10000):
        psbt = BasicPSBT()
        txn = Tx(2, [], [])

        # we have a key; use it to provide "plausible" value inputs
        from pycoin.key.BIP32Node import BIP32Node
        mk = BIP32Node.from_wallet_key(master_xpub)
        xfp = mk.fingerprint()

        psbt.inputs = [BasicPSBTInput(idx=i) for i in range(num_ins)]
        psbt.outputs = [BasicPSBTOutput(idx=i) for i in range(num_outs)]

        for i in range(num_ins):
            # make a fake txn to supply each of the inputs
            # - each input is 1BTC

            # addr where the fake money will be stored.
            subkey = mk.subkey_for_path(subpath % i)
            sec = subkey.sec()
            assert len(sec) == 33, "expect compressed"
            assert subpath[0:2] == '0/'

            psbt.inputs[i].bip32_paths[sec] = xfp + pack('<II', 0, i)

            # UTXO that provides the funding for to-be-signed txn
            supply = Tx(2, [TxIn(pack('4Q', 0xdead, 0xbeef, 0, 0), 73)], [])

            scr = bytes([0x76, 0xa9, 0x14]) + subkey.hash160() + bytes(
                [0x88, 0xac])
            supply.txs_out.append(TxOut(1E8, scr))

            with BytesIO() as fd:
                supply.stream(fd)
                psbt.inputs[i].utxo = fd.getvalue()

            if 0:
                with BytesIO() as fd:
                    supply.stream(fd, include_witness_data=True)
                    psbt.inputs[i].witness_utxo = fd.getvalue()

            spendable = TxIn(supply.hash(), 0)
            txn.txs_in.append(spendable)

        for i in range(num_outs):
            # random P2PKH
            scr = bytes([0x76, 0xa9, 0x14]) + pack(
                'I', i + 1) + bytes(16) + bytes([0x88, 0xac])
            h = TxOut(round(((1E8 * num_ins) - fee) / num_outs, 4), scr)
            txn.txs_out.append(h)

        with BytesIO() as b:
            txn.stream(b)
            psbt.txn = b.getvalue()

        rv = BytesIO()
        psbt.serialize(rv)
        assert rv.tell() <= MAX_TXN_LEN, 'too fat'

        return rv.getvalue()
Ejemplo n.º 16
0
def test_export_public_txt(dev, cap_menu, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path, addr_vs_path):
    from pycoin.contrib.segwit_addr import encode as sw_encode

    # test UX and values produced.
    goto_home()
    pick_menu_item('Advanced')
    pick_menu_item('MicroSD Card')
    pick_menu_item('Dump Summary')

    time.sleep(0.1)
    title, story = cap_story()

    assert 'Saves a text file to' in story
    need_keypress('y')

    time.sleep(0.1)
    title, story = cap_story()

    assert 'Summary file' in story
    fname = story.split('\n')[-1]
    assert 'public' in fname

    xfp = xfp2str(simulator_fixed_xfp).upper()

    root = BIP32Node.from_wallet_key(simulator_fixed_xprv)
    path = microsd_path(fname)
    with open(path, 'rt') as fp:
        for ln in fp.readlines():
            if 'fingerprint' in ln:
                assert ln.strip().endswith(xfp)

            if '=>' not in ln:
                continue

            lhs, rhs = ln.strip().split(' => ')
            assert lhs.startswith('m/')
            rhs = rhs.split('#')[0].strip()

            if 'SLIP-132' in ln:
                rhs, _, f, _ = slip132undo(rhs)
            else:
                f = None

            if rhs[1:4] == 'pub':
                expect = root.subkey_for_path(lhs[2:])
                assert expect.hwif(as_private=False) == rhs
                continue

            if not f:
                if rhs[0] in 'mn':
                    f = AF_CLASSIC
                elif rhs[0:3] == 'tb1':
                    f = AF_P2WPKH
                elif rhs[0] == '2':
                    f = AF_P2WPKH_P2SH
                else:
                    raise ValueError(rhs)

            addr_vs_path(rhs, path=lhs, addr_fmt=f)
Ejemplo n.º 17
0
def test_export_wasbi(dev, cap_menu, pick_menu_item, goto_home, cap_story,
                      need_keypress, microsd_path):
    # test UX and operation of the 'wasabi wallet export'

    goto_home()
    pick_menu_item('Advanced')
    pick_menu_item('MicroSD Card')
    pick_menu_item('Wasabi Wallet')

    time.sleep(0.1)
    title, story = cap_story()

    assert 'This saves a skeleton Wasabi' in story

    need_keypress('y')

    time.sleep(0.1)
    title, story = cap_story()

    assert 'wallet file written' in story
    fname = story.split('\n')[-1]

    need_keypress('y')

    path = microsd_path(fname)
    with open(path, 'rt') as fp:
        obj = json.load(fp)

        assert 'MasterFingerprint' in obj
        assert 'ExtPubKey' in obj
        assert 'BlockchainState' in obj
        assert obj['BlockchainState']['Network']

        xpub = obj['ExtPubKey']
        assert xpub.startswith('xpub')  # even for testnet

        assert int(obj['MasterFingerprint'], 16) == simulator_fixed_xfp

        got = BIP32Node.from_wallet_key(xpub)
        expect = BIP32Node.from_wallet_key(
            simulator_fixed_xprv).subkey_for_path("84'/0'/0'.pub")

        assert got.sec() == expect.sec()

    os.unlink(path)
Ejemplo n.º 18
0
def cosign_spend_request(xprvkey_or_wallet, req_keys, inputs, xpub_check):
    '''
        Sign the inputs of a transaction, given the sighashs and subkey paths for each input

    Args:
        xprvkey_or_wallet = 111-char base58 encoded serialization of BIP32 wallet
                            or pycoin.key.BIP32Node object (w/ private key)

        req_keys = dictionary: key is subpath ('a/b/c', but only 'a' for now as a string)
                    value is tuple: (address, public pair) ... optional checking data

        inputs = list of by transaction input: (subpath, sighash_all value)

    Returns:
        list of 3-tuples: (der-encoded signature, sighash, subpath)

    '''

    # We need just these features from pycoin <https://github.com/richardkiss/pycoin>
    from pycoin import ecdsa
    from pycoin.key.BIP32Node import BIP32Node
    from pycoin.tx.script import der

    # We need a BIP32 "wallet" for the root of all keys.
    if isinstance(xprvkey_or_wallet, basestring):
        wallet = BIP32Node.from_wallet_key(xprvkey_or_wallet.strip())
    else:
        wallet = xprvkey_or_wallet

    # Verify we are looking at the right extended private key
    check = wallet.hwif(as_private=False)[-len(xpub_check):]
    if check != xpub_check:
        raise ValueError("This private key isn't the right one for xpub...%s" %
                         xpub_check)

    # Make the right subkey for each inputs
    wallets = {}
    for sp, (addr_check, ppair) in req_keys.items():
        w = wallet.subkey_for_path(sp)
        assert w.bitcoin_address() == addr_check
        assert w.public_pair() == tuple(ppair)
        wallets[sp] = w

    # Generate a signature for each input required
    sigs = []
    SIGHASH_ALL = 1
    order = ecdsa.generator_secp256k1.order()
    for sp, sighash in inputs:
        sighash_int = int(sighash, 16)
        r, s = ecdsa.sign(ecdsa.generator_secp256k1,
                          wallets[sp].secret_exponent(), sighash_int)
        if s + s > order:
            s = order - s
        sig = der.sigencode_der(r, s) + chr(SIGHASH_ALL)
        sigs.append((sig.encode('hex'), sighash, sp))

    return sigs
Ejemplo n.º 19
0
 def pycoinWallet(public_key=None,
                  public=True,
                  testnet=settings.BTC_TESTNET,
                  password=None):
     netcode = 'XTN' if testnet else 'BTC'
     if public:
         return BIP32Node.from_wallet_key(public_key)
     else:
         assert not password is None
         return BIP32Node.from_master_secret(password, netcode=netcode)
Ejemplo n.º 20
0
def cosign_spend_request(xprvkey_or_wallet, req_keys, inputs, xpub_check):
    """
        Sign the inputs of a transaction, given the sighashs and subkey paths for each input

    Args:
        xprvkey_or_wallet = 111-char base58 encoded serialization of BIP32 wallet
                            or pycoin.key.BIP32Node object (w/ private key)

        req_keys = dictionary: key is subpath ('a/b/c', but only 'a' for now as a string)
                    value is tuple: (address, public pair) ... optional checking data

        inputs = list of by transaction input: (subpath, sighash_all value)

    Returns:
        list of 3-tuples: (der-encoded signature, sighash, subpath)

    """

    # We need just these features from pycoin <https://github.com/richardkiss/pycoin>
    from pycoin import ecdsa
    from pycoin.key.BIP32Node import BIP32Node
    from pycoin.tx.script import der

    # We need a BIP32 "wallet" for the root of all keys.
    if isinstance(xprvkey_or_wallet, basestring):
        wallet = BIP32Node.from_wallet_key(xprvkey_or_wallet.strip())
    else:
        wallet = xprvkey_or_wallet

    # Verify we are looking at the right extended private key
    check = wallet.hwif(as_private=False)[-len(xpub_check) :]
    if check != xpub_check:
        raise ValueError("This private key isn't the right one for xpub...%s" % xpub_check)

    # Make the right subkey for each inputs
    wallets = {}
    for sp, (addr_check, ppair) in req_keys.items():
        w = wallet.subkey_for_path(sp)
        assert w.bitcoin_address() == addr_check
        assert w.public_pair() == tuple(ppair)
        wallets[sp] = w

    # Generate a signature for each input required
    sigs = []
    SIGHASH_ALL = 1
    order = ecdsa.generator_secp256k1.order()
    for sp, sighash in inputs:
        sighash_int = int(sighash, 16)
        r, s = ecdsa.sign(ecdsa.generator_secp256k1, wallets[sp].secret_exponent(), sighash_int)
        if s + s > order:
            s = order - s
        sig = der.sigencode_der(r, s) + chr(SIGHASH_ALL)
        sigs.append((sig.encode("hex"), sighash, sp))

    return sigs
Ejemplo n.º 21
0
def test_export_unchained(dev, cap_menu, pick_menu_item, goto_home, cap_story,
                          need_keypress, microsd_path):
    # test UX and operation of the 'unchained capital export'

    goto_home()
    pick_menu_item('Advanced')
    pick_menu_item('MicroSD Card')
    pick_menu_item('Export Wallet')
    pick_menu_item('Unchained Capital')

    time.sleep(0.1)
    title, story = cap_story()

    assert 'Unchained Capital' in story

    need_keypress('y')

    time.sleep(0.1)
    title, story = cap_story()

    assert 'Unchained Capital file' in story
    fname = story.split('\n')[-1]
    assert 'unchained' in fname

    need_keypress('y')

    root = BIP32Node.from_wallet_key(simulator_fixed_xprv)
    path = microsd_path(fname)
    with open(path, 'rt') as fp:
        obj = json.load(fp)

        assert obj['xfp'] == xfp2str(simulator_fixed_xfp)
        assert obj['account'] == 0

        assert obj['p2sh_deriv'] == "m/45'"
        for k in ['p2sh_p2wsh', 'p2sh', 'p2wsh']:
            xpub = slip132undo(obj[k])[0] if k != 'p2sh' else obj[k]
            node = BIP32Node.from_wallet_key(xpub)
            assert xpub == node.hwif(as_private=False)
            sk = root.subkey_for_path(obj[f'{k}_deriv'][2:] + '.pub')
            #assert node.chain_code() == sk.chain_code()
            assert node.hwif() == sk.hwif()
Ejemplo n.º 22
0
def master_xpub(dev):
    if hasattr(dev.dev, 'pipe'):
        # this works better against simulator in HSM mode, where the xpub cmd may be disabled
        return simulator_fixed_xpub

    r = dev.send_recv(CCProtocolPacker.get_xpub('m'), timeout=None, encrypt=1)

    assert r[1:4] == 'pub', r

    if r[0:4] == dev.master_xpub[0:4]:
        assert r == dev.master_xpub
    elif dev.master_xpub:
        # testnet vs. mainnet difference
        from pycoin.key.BIP32Node import BIP32Node
        a = BIP32Node.from_wallet_key(r)
        b = BIP32Node.from_wallet_key(dev.master_xpub)

        assert a.secret_exponent() == b.secret_exponent()

    return r
Ejemplo n.º 23
0
def get_address_by_path(key, path):
    '''
    gets key = xpub or xpriv and path
    returns JSON
    xprv: {"address":"1qwerty...", "priv_key":"Kqwert...", "path":"1/2"}
    xpub: {"address":"1qwerty...", "priv_key":None, "path":"1/2"}
    '''
    da_key = BIP32Node.from_wallet_key(key)
    btc_address = da_key.subkey_for_path(path).bitcoin_address()
    btc_private = da_key.subkey_for_path(path).wif()
    return {"address":btc_address, "priv_key":btc_private, "path":path}
Ejemplo n.º 24
0
def test_crypto_unittest(sim_eval, sim_exec):
    # unit test for AES key generation from SDCard and master secret
    card = sim_exec(
        'import files; from h import b2a_hex; cs = files.CardSlot().__enter__(); RV.write(b2a_hex(cs.get_id_hash())); cs.__exit__()'
    )

    # known value for simulator, generally unknown on random SD cards
    assert card == '95a60b9ff0c944ec2c23a28e599f794e95bb376a451b6037b054f8230b405fb0'
    salt = a2b_hex(card)

    # read key simulator calculates
    key = sim_exec('''\
import files; from h import b2a_hex; \
from pwsave import PassphraseSaver; \
cs = files.CardSlot().__enter__(); \
p=PassphraseSaver(); p._calc_key(cs); RV.write(b2a_hex(p.key)); cs.__exit__()'''
                   )

    assert len(key) == 64
    #assert key == '234af2aa2ab43af83667dfc6e11d08223e0f486ef34539b41a045dd9eb3ea664'

    from pycoin.key.BIP32Node import BIP32Node
    from pycoin.encoding import from_bytes_32, to_bytes_32
    from hashlib import sha256

    mk = BIP32Node.from_wallet_key(simulator_fixed_xprv)

    sk = mk.subkey_for_path('2147431408p/0p')

    md = sha256()
    md.update(salt)
    md.update(to_bytes_32(sk.secret_exponent()))
    md.update(salt)

    expect = sha256(md.digest()).hexdigest()

    assert expect == key

    # check that key works for decrypt / that the file was actually encrypted

    with open(SIM_FNAME, 'rb') as fd:
        raw = fd.read()

    import pyaes
    d = pyaes.AESModeOfOperationCTR(a2b_hex(expect), pyaes.Counter(0)).decrypt
    txt = str(bytearray(d(raw)), 'utf8')

    print(txt)
    assert txt[0] == '[' and txt[-1] == ']'
    import json
    j = json.loads(txt)
    assert isinstance(j, list)
    assert j[0]['pw']
    assert j[0]['xfp']
Ejemplo n.º 25
0
def test_xpub_good(dev, master_xpub, path):
    # get some xpubs and validate the derivations

    xpub = dev.send_recv(CCProtocolPacker.get_xpub(path), timeout=None)

    assert xpub[1:4] == 'pub'
    assert len(xpub) > 100

    # check the derive using pycoin
    k = BIP32Node.from_wallet_key(xpub)

    assert k.hwif() == xpub

    if "'" not in path:
        mk = BIP32Node.from_wallet_key(master_xpub)
        sk = mk.subkey_for_path(path[2:])
        assert sk.hwif() == xpub

    if len(path) <= 2:
        assert mk.fingerprint() == struct.pack('<I', dev.master_fingerprint)
Ejemplo n.º 26
0
def test_export_airgap(goto_home, cap_story, pick_menu_item, cap_menu,
                       need_keypress, microsd_path):
    # test UX and math for bip45 export
    import json

    goto_home()
    pick_menu_item('Settings')
    pick_menu_item('Multisig Wallets')
    pick_menu_item('Export XPUB')

    time.sleep(.1)
    title, story = cap_story()
    assert 'BIP45' in story
    assert "m/45'" in story
    assert "m/48'/" in story

    need_keypress('y')

    time.sleep(.1)
    title, story = cap_story()
    fname = story.split('\n')[-1]

    assert fname.startswith('ccxp-')
    assert fname.endswith('.json')

    with open(microsd_path(fname), 'rt') as fp:
        rv = json.load(fp)

    assert 'xfp' in rv
    assert len(rv) >= 7

    n = BIP32Node.from_wallet_key(rv['p2sh'])

    assert n.tree_depth() == 1
    assert n.child_index() == 45 | (1 << 31)
    mxfp = unpack("<I", n.parent_fingerprint())[0]
    assert hex(mxfp) == hex(simulator_fixed_xfp)

    e = BIP32Node.from_wallet_key(simulator_fixed_xprv)
    expect = e.subkey_for_path("45'.pub")
    assert expect.hwif() == n.hwif()
Ejemplo n.º 27
0
    def doit(M, addr_fmt=None, do_import=True):
        passwords = ['Me', 'Myself', 'And I', '']

        if 0:
            # WORKING, but slow .. and it's constant data
            keys = []
            for pw in passwords:
                xfp = set_bip39_pw(pw)

                sk = dev.send_recv(CCProtocolPacker.get_xpub("m/45'"))
                node = BIP32Node.from_wallet_key(sk)

                keys.append((xfp, None, node))

            assert len(set(x for x,_,_ in keys)) == 4, keys
            pprint(keys)
        else:
            # Much, FASTER!
            assert dev.is_simulator
            keys = [(3503269483, None,
                        BIP32Node.from_hwif('tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9')),
                     (2389277556, None,
                        BIP32Node.from_hwif('tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc')),
                 (3190206587, None,
                        BIP32Node.from_hwif('tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa')),
                (1130956047, None,
                        BIP32Node.from_hwif('tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n')),
            ]

        if do_import:
            # render as a file for import
            config = f"name: Myself-{M}\npolicy: {M} / 4\n\n"

            if addr_fmt:
                config += f'format: {addr_fmt.upper()}\n'

            config += '\n'.join('%s: %s' % (xfp2str(xfp), sk.hwif()) for xfp, _, sk in keys)
            #print(config)

            title, story = offer_ms_import(config)
            #print(story)

            # dont care if update or create; accept it.
            time.sleep(.1)
            need_keypress('y')

        def select_wallet(idx):
            # select to specific pw
            xfp = set_bip39_pw(passwords[idx])
            assert xfp == keys[idx][0]

        return (keys, select_wallet)
Ejemplo n.º 28
0
def test_dump_addresses(generate_addresses_file, mk_common_derivations,
                        sim_execfile, validate_address, click_idx):
    # Validate  addresses dumped to text file
    node_prv = BIP32Node.from_wallet_key(
        sim_execfile('devtest/dump_private.py').strip())

    common_derivs = mk_common_derivations(node_prv.netcode())

    # Generate the addresses file and get each line in a list
    for subpath, addr in generate_addresses_file(click_idx):
        # derive the subkey and validate the corresponding address
        sk = node_prv.subkey_for_path(subpath[2:])
        validate_address(addr, sk)
Ejemplo n.º 29
0
def olsign(key, proposal, url, upload, html, output):

    if not url and not proposal:
        raise click.BadParameter(
            "Need a URL to fetch proposal from (--url), or the file itself (-i file.json)"
        )

    # get the proposal JSON
    try:
        if url:
            proposal = requests.get(url).json()
        else:
            proposal = simplejson.load(proposal)
    except JSONDecodeError:
        raise click.UsageError("Does not contain valid JSON")

    # unwrap signature, checking it as we go
    proposal = check_sig_and_unwrap(proposal)

    click.echo('''
   Co-signing as: {cosigner}
Required xpubkey: ...{xpubkey_check}
'''.format(**proposal))

    # unpack their private key (to test if suitable)
    wallet = BIP32Node.from_wallet_key(key.read().strip())
    check = wallet.hwif(as_private=False)[-8:]
    if check != proposal['xpubkey_check']:
        raise click.UsageError(
            'This private key is not the one we need as this co-signer.')

    #pprint(proposal.keys())

    # present a summary of what will happen
    if html: show_page(proposal)

    sigs = do_signing(wallet, proposal['req_keys'], proposal['inputs'])

    package = package_for_ck(wallet, proposal, sigs)

    if output:
        output.write(package)
        click.echo("Wrote result to: %s" % output.name)

    if upload:
        upload_to_ck(package)

    if not output and not upload:
        click.echo("JSON response:\n\n%s" % package)
Ejemplo n.º 30
0
    def doit(M, N, unique=0):
        keys = []

        for i in range(N-1):
            pk = BIP32Node.from_master_secret(b'CSW is a fraud %d - %d' % (i, unique), 'XTN')

            xfp = unpack("<I", pk.fingerprint())[0]

            sub = pk.subkey(45, is_hardened=True, as_private=True)
            keys.append((xfp, pk, sub))

        pk = BIP32Node.from_wallet_key(simulator_fixed_xprv)
        keys.append((simulator_fixed_xfp, pk, pk.subkey(45, is_hardened=True, as_private=True)))

        return keys
Ejemplo n.º 31
0
def olsign(key, proposal, url, upload, html, output):

    if not url and not proposal:
        raise click.BadParameter(
            "Need a URL to fetch proposal from (--url), or the file itself (-i file.json)")


    # get the proposal JSON
    try:
        if url:
            proposal = requests.get(url).json()
        else:
            proposal = simplejson.load(proposal)
    except JSONDecodeError:
        raise click.UsageError("Does not contain valid JSON")

    # unwrap signature, checking it as we go
    proposal = check_sig_and_unwrap(proposal)

    click.echo('''
   Co-signing as: {cosigner}
Required xpubkey: ...{xpubkey_check}
'''.format(**proposal))

    # unpack their private key (to test if suitable)
    wallet = BIP32Node.from_wallet_key(key.read().strip())
    check = wallet.hwif(as_private = False)[-8:]
    if check != proposal['xpubkey_check']:
        raise click.UsageError('This private key is not the one we need as this co-signer.')
    
    #pprint(proposal.keys())

    # present a summary of what will happen
    if html: show_page(proposal)

    sigs = do_signing(wallet, proposal['req_keys'], proposal['inputs'])

    package = package_for_ck(wallet, proposal, sigs)

    if output:
        output.write(package)
        click.echo("Wrote result to: %s" % output.name)

    if upload:
        upload_to_ck(package)

    if not output and not upload:
        click.echo("JSON response:\n\n%s" % package)
Ejemplo n.º 32
0
    def mitm_verify(self, sig, expected_xpub):
        # replace this with your own library, as needed.
        try:
            from pycoin.key.BIP32Node import BIP32Node
            from pycoin.contrib.msg_signing import verify_message
            from pycoin.encoding import from_bytes_32
            from base64 import b64encode
        except ImportError:
            raise RuntimeError("Missing pycoin for signature checking")

        mk = BIP32Node.from_wallet_key(expected_xpub)
        ok = verify_message(mk,
                            b64encode(sig),
                            msg_hash=from_bytes_32(self.session_key))

        return ok
Ejemplo n.º 33
0
    def doit(pw):
        # reset from previous runs
        words = reset_seed_words()

        # optimization
        if pw == '':
            return simulator_fixed_xfp

        print(f"Setting BIP39 pw: {pw}")
        dev.send_recv(CCProtocolPacker.bip39_passphrase(pw), timeout=None)

        if pw:
            time.sleep(0.050)
            title, body = cap_story()

            assert pw not in body

            # verify display of passphrase
            need_keypress('2')
            time.sleep(0.050)
            title, body = cap_story()
            assert pw in body

        need_keypress('y')

        done = None
        while done == None:
            time.sleep(0.050)
            done = dev.send_recv(CCProtocolPacker.get_passphrase_done(),
                                 timeout=None)

        xpub = done
        assert xpub[1:4] == 'pub'
        got = BIP32Node.from_wallet_key(xpub)

        # what it should be
        seed = Mnemonic.to_seed(words, passphrase=pw)
        expect = BIP32Node.from_master_secret(seed)

        assert got.public_pair() == expect.public_pair()

        xfp, = struct.unpack('I', expect.fingerprint())

        return xfp
Ejemplo n.º 34
0
def main():
    parser = argparse.ArgumentParser(description="Generate a private wallet key. WARNING: obsolete. Use ku instead.")

    parser.add_argument('-a', "--address", help='show as Bitcoin address', action='store_true')
    parser.add_argument('-i', "--info", help='show metadata', action='store_true')
    parser.add_argument('-j', "--json", help='output metadata as JSON', action='store_true')
    parser.add_argument('-w', "--wif", help='show as Bitcoin WIF', action='store_true')
    parser.add_argument('-f', "--wallet-key-file", help='initial wallet key', type=argparse.FileType('r'))
    parser.add_argument('-k', "--wallet-key", help='initial wallet key')
    parser.add_argument('-g', "--gpg", help='use gpg --gen-random to get additional entropy', action='store_true')
    parser.add_argument('-u', "--dev-random", help='use /dev/random to get additional entropy', action='store_true')
    parser.add_argument('-n', "--uncompressed", help='show in uncompressed form', action='store_true')
    parser.add_argument('-p', help='generate wallet key from passphrase. NOT RECOMMENDED', metavar='passphrase')
    parser.add_argument('-s', "--subkey", help='subkey path (example: 0p/2/1)')
    parser.add_argument('-t', help='generate test key', action="store_true")
    parser.add_argument('inputfile', help='source of entropy. stdin by default', type=argparse.FileType(mode='r+b'), nargs='?')
    args = parser.parse_args()

    # args.inputfile doesn't like binary when "-" is passed in. Deal with this.
    if args.inputfile == sys.stdin and hasattr(sys.stdin, "buffer"):
        args.inputfile = sys.stdin.buffer

    network = 'XTN' if args.t else 'BTC'

    entropy = bytearray()
    if args.gpg:
        entropy.extend(gpg_entropy())
    if args.dev_random:
        entropy.extend(dev_random_entropy())
    if args.inputfile:
        entropy.extend(args.inputfile.read())
    if args.p:
        entropy.extend(args.p.encode("utf8"))
    if len(entropy) == 0 and not args.wallet_key and not args.wallet_key_file:
        parser.error("you must specify at least one source of entropy")
    if args.wallet_key and len(entropy) > 0:
        parser.error("don't specify both entropy and a wallet key")
    if args.wallet_key_file:
        wallet = BIP32Node.from_wallet_key(args.wallet_key_file.readline()[:-1])
    elif args.wallet_key:
        wallet = BIP32Node.from_wallet_key(args.wallet_key)
    else:
        wallet = BIP32Node.from_master_secret(bytes(entropy), netcode=network)
    try:
        if args.subkey:
            wallet = wallet.subkey_for_path(args.subkey)
        if wallet.child_index() >= 0x80000000:
            wc = wallet.child_index() - 0x80000000
            child_index = "%dp (%d)" % (wc, wallet.child_index())
        else:
            child_index = "%d" % wallet.child_index()
        if args.json:
            d = dict(
                wallet_key=wallet.wallet_key(as_private=wallet.is_private()),
                public_pair_x=wallet.public_pair[0],
                public_pair_y=wallet.public_pair[1],
                tree_depth=wallet.depth,
                fingerprint=b2h(wallet.fingerprint()),
                parent_fingerprint=b2h(wallet.parent_fingerprint),
                child_index=child_index,
                chain_code=b2h(wallet.chain_code),
                bitcoin_addr=wallet.bitcoin_address(),
                bitcoin_addr_uncompressed=wallet.bitcoin_address(compressed=False),
                network="test" if wallet.is_test else "main",
            )
            if wallet.is_private():
                d.update(dict(
                    key="private",
                    secret_exponent=wallet.secret_exponent,
                    WIF=wallet.wif(),
                    WIF_uncompressed=wallet.wif(compressed=False)
                ))
            else:
                d.update(dict(key="public"))
            print(json.dumps(d, indent=3))
        elif args.info:
            print(wallet.wallet_key(as_private=wallet.is_private()))
            print(full_network_name_for_netcode(wallet.netcode()))
            if wallet.is_private():
                print("private key")
                print("secret exponent: %d" % wallet.secret_exponent())
            else:
                print("public key only")
            print("public pair x:   %d\npublic pair y:   %d" % wallet.public_pair())
            print("tree depth:      %d" % wallet.tree_depth())
            print("fingerprint:     %s" % b2h(wallet.fingerprint()))
            print("parent f'print:  %s" % b2h(wallet.parent_fingerprint()))
            print("child index:     %s" % child_index)
            print("chain code:      %s" % b2h(wallet.chain_code()))
            if wallet.is_private():
                print("WIF:             %s" % wallet.wif())
                print("  uncompressed:  %s" % wallet.wif(use_uncompressed=True))
            print("Bitcoin address: %s" % wallet.bitcoin_address())
            print("  uncompressed:  %s" % wallet.bitcoin_address(use_uncompressed=True))
        elif args.address:
            print(wallet.bitcoin_address(use_uncompressed=args.uncompressed))
        elif args.wif:
            print(wallet.wif(compressed=not args.uncompressed))
        else:
            print(wallet.wallet_key(as_private=wallet.is_private()))
    except PublicPrivateMismatchError as ex:
        print(ex.args[0])
Ejemplo n.º 35
0
#!/usr/bin/env python

import unittest

from pycoin.key import bip32
from pycoin.serialize import h2b

from pycoin.key.BIP32Node import BIP32Node

def Wallet(*args, **kwargs):
    return BIP32Node(*args, **kwargs)
Wallet.from_master_secret = lambda *args, **kwargs: BIP32Node.from_master_secret(*args, **kwargs)
Wallet.from_wallet_key = lambda *args, **kwargs: BIP32Node.from_wallet_key(*args, **kwargs)
bip32.Wallet = Wallet

class Bip0032TestCase(unittest.TestCase):

    def test_vector_1(self):
        master = bip32.Wallet.from_master_secret(h2b("000102030405060708090a0b0c0d0e0f"))
        self.assertEqual(master.wallet_key(as_private=True), "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi")
        self.assertEqual(master.bitcoin_address(), "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma")
        self.assertEqual(master.wif(), "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW")

        self.assertEqual(master.wallet_key(), "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8")

        m0p = master.subkey(is_hardened=True)
        self.assertEqual(m0p.wallet_key(), "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw")
        self.assertEqual(m0p.wallet_key(as_private=True), "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7")
        self.assertEqual(master.subkey_for_path("0p").wallet_key(), m0p.wallet_key())

        pub_mp0 = master.subkey(is_hardened=True, as_private=False)
Ejemplo n.º 36
0
def generate_bip32_address_from_extended_pubkey(extended_pubkey, branch, index):

    ext_key = BIP32Node.from_wallet_key(extended_pubkey)

    return ext_key.subkey_for_path('%d/%d' % (branch, index)).address()