def __init__(self, wordfile = 'wordlist.txt'): # Read create the mnemonic wordlist object self.mnemonic = Mnemonic("english") # Set up a default reference wallet self.wallet = Wallet.from_master_secret(bytes(0)) # Set up a Polly communication pipe self.polly = PollyCom() # Default print padding self.PAD = "{:35}"
def __init__(self, wordfile='wordlist.txt'): # Read create the mnemonic wordlist object self.mnemonic = Mnemonic("english") # Set up a default reference wallet self.wallet = Wallet.from_master_secret(bytes(0)) # Set up a Polly communication pipe self.polly = PollyCom() # Default print padding self.PAD = "{:35}"
def test_is_public_private_bip32_valid(self): WALLET_KEYS = ["foo", "1", "2", "3", "4", "5"] # not all networks support BIP32 yet for netcode in "BTC XTN DOGE".split(): for wk in WALLET_KEYS: wallet = Wallet.from_master_secret(wk.encode("utf8"), netcode=netcode) text = wallet.wallet_key(as_private=True) self.assertEqual(is_private_bip32_valid(text, allowable_netcodes=NETWORK_NAMES), netcode) self.assertEqual(is_public_bip32_valid(text, allowable_netcodes=NETWORK_NAMES), None) a = text[:-1] + chr(ord(text[-1])+1) self.assertEqual(is_private_bip32_valid(a, allowable_netcodes=NETWORK_NAMES), None) self.assertEqual(is_public_bip32_valid(a, allowable_netcodes=NETWORK_NAMES), None) text = wallet.wallet_key(as_private=False) self.assertEqual(is_private_bip32_valid(text, allowable_netcodes=NETWORK_NAMES), None) self.assertEqual(is_public_bip32_valid(text, allowable_netcodes=NETWORK_NAMES), netcode) a = text[:-1] + chr(ord(text[-1])+1) self.assertEqual(is_private_bip32_valid(a, allowable_netcodes=NETWORK_NAMES), None) self.assertEqual(is_public_bip32_valid(a, allowable_netcodes=NETWORK_NAMES), None)
def test_is_public_private_bip32_valid(self): WALLET_KEYS = ["foo", "1", "2", "3", "4", "5"] # not all networks support BIP32 yet for netcode in "BTC XTN DOGE".split(): for wk in WALLET_KEYS: wallet = Wallet.from_master_secret(wk.encode("utf8"), netcode=netcode) text = wallet.wallet_key(as_private=True) self.assertEqual( is_private_bip32_valid(text, allowable_netcodes=NETWORK_NAMES), netcode) self.assertEqual( is_public_bip32_valid(text, allowable_netcodes=NETWORK_NAMES), None) a = text[:-1] + chr(ord(text[-1]) + 1) self.assertEqual( is_private_bip32_valid(a, allowable_netcodes=NETWORK_NAMES), None) self.assertEqual( is_public_bip32_valid(a, allowable_netcodes=NETWORK_NAMES), None) text = wallet.wallet_key(as_private=False) self.assertEqual( is_private_bip32_valid(text, allowable_netcodes=NETWORK_NAMES), None) self.assertEqual( is_public_bip32_valid(text, allowable_netcodes=NETWORK_NAMES), netcode) a = text[:-1] + chr(ord(text[-1]) + 1) self.assertEqual( is_private_bip32_valid(a, allowable_netcodes=NETWORK_NAMES), None) self.assertEqual( is_public_bip32_valid(a, allowable_netcodes=NETWORK_NAMES), None)
def test_set_seed(self, wordlist): """ Sets the wallet seed for Polly and the reference wallet. Note: Subsequent tests will use the seed set by this routine. wordlist - a space separated string of 18 mnemonic words from the Polly wordlist. Note: the checksum must be correct (part of the 18th word) - see BIP0039. gen_wordlist can be used to generate a wordlist including the proper checksum. """ assert len(wordlist.split(" ")) == 18, "expecting 18 words" assert self.mnemonic.check(wordlist) == True, "invalid word list" print (self.PAD.format("Set seed"), end='') # Set polly self.polly.send_set_master_seed(wordlist) print (self.__outok()) # Set the reference wallet seed = self.mnemonic.to_seed(wordlist) self.wallet = Wallet.from_master_secret(seed)
def test_set_seed(self, wordlist): """ Sets the wallet seed for Polly and the reference wallet. Note: Subsequent tests will use the seed set by this routine. wordlist - a space separated string of 18 mnemonic words from the Polly wordlist. Note: the checksum must be correct (part of the 18th word) - see BIP0039. gen_wordlist can be used to generate a wordlist including the proper checksum. """ assert len(wordlist.split(" ")) == 18, "expecting 18 words" assert self.mnemonic.check(wordlist) == True, "invalid word list" print(self.PAD.format("Set seed"), end='') # Set polly self.polly.send_set_master_seed(wordlist) print(self.__outok()) # Set the reference wallet seed = self.mnemonic.to_seed(wordlist) self.wallet = Wallet.from_master_secret(seed)
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: args.inputfile = sys.stdin.buffer network = 'T' if args.t else 'M' 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 = Wallet.from_wallet_key(args.wallet_key_file.readline()[:-1]) elif args.wallet_key: wallet = Wallet.from_wallet_key(args.wallet_key) else: wallet = Wallet.from_master_secret(bytes(entropy), netcode=network) try: if args.subkey: wallet = wallet.subkey_for_path(args.subkey) if wallet.child_number >= 0x80000000: wc = wallet.child_number - 0x80000000 child_index = "%dp (%d)" % (wc, wallet.child_number) else: child_index = "%d" % wallet.child_number 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)) if wallet.is_test: print("test network") else: print("main network") 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.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(compressed=False)) print("Bitcoin address: %s" % wallet.bitcoin_address()) print(" uncompressed: %s" % wallet.bitcoin_address(compressed=False)) elif args.address: print(wallet.bitcoin_address(compressed=not 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])
def main(): networks = "MTLD" parser = argparse.ArgumentParser( description='Crypto coin utility ku ("key utility") to show' ' information about Bitcoin or other cryptocoin data structures.', epilog='Known networks codes:\n ' \ + ', '.join(['%s (%s)'%(i, full_network_name_for_netcode(i)) for i in NETWORK_NAMES]) ) parser.add_argument('-w', "--wallet", help='show just Bitcoin wallet key', action='store_true') parser.add_argument('-W', "--wif", help='show just Bitcoin WIF', action='store_true') parser.add_argument('-a', "--address", help='show just Bitcoin address', action='store_true') parser.add_argument('-u', "--uncompressed", help='show output in uncompressed form', action='store_true') parser.add_argument('-P', "--public", help='only show public version of wallet keys', action='store_true') parser.add_argument('-j', "--json", help='output as JSON', action='store_true') parser.add_argument('-s', "--subkey", help='subkey path (example: 0H/2/15-20)') parser.add_argument('-n', "--network", help='specify network (default: BTC = Bitcoin)', default='BTC', choices=NETWORK_NAMES) parser.add_argument("--override-network", help='override detected network type', default=None, choices=NETWORK_NAMES) parser.add_argument( 'item', nargs="+", help='a BIP0032 wallet key string;' ' a WIF;' ' a bitcoin address;' ' an SEC (ie. a 66 hex chars starting with 02, 03 or a 130 hex chars starting with 04);' ' the literal string "create" to create a new wallet key using strong entropy sources;' ' P:wallet passphrase (NOT RECOMMENDED);' ' H:wallet passphrase in hex (NOT RECOMMENDED);' ' secret_exponent (in decimal or hex);' ' x,y where x,y form a public pair (y is a number or one of the strings "even" or "odd");' ' hash160 (as 40 hex characters)') args = parser.parse_args() if args.override_network: # force network arg to match override, but also will override decoded data below. args.network = args.override_network PREFIX_TRANSFORMS = ( ("P:", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret( s.encode("utf8"), netcode=args.network))), ("H:", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret( h2b(s), netcode=args.network))), ("create", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret( get_entropy(), netcode=args.network))), ) for item in args.item: key = None for k, f in PREFIX_TRANSFORMS: if item.startswith(k): try: key = f(item[len(k):]) break except Exception: pass else: try: key = Key.from_text(item) except encoding.EncodingError: pass if key is None: secret_exponent = parse_as_secret_exponent(item) if secret_exponent: key = Key(secret_exponent=secret_exponent, netcode=args.network) if SEC_RE.match(item): key = Key.from_sec(h2b(item)) if key is None: public_pair = parse_as_public_pair(item) if public_pair: key = Key(public_pair=public_pair, netcode=args.network) if HASH160_RE.match(item): key = Key(hash160=h2b(item), netcode=args.network) if key is None: print("can't parse %s" % item, file=sys.stderr) continue if args.override_network: # Override the network value, so we can take the same xpubkey and view what # the values would be on each other network type. # XXX public interface for this is needed... key._netcode = args.override_network key._hierarchical_wallet.netcode = args.override_network for key in key.subkeys(args.subkey or ""): if args.public: key = key.public_copy() output_dict, output_order = create_output(item, key) if args.json: print(json.dumps(output_dict, indent=3, sort_keys=True)) elif args.wallet: print(output_dict["wallet_key"]) elif args.wif: print(output_dict["wif_uncompressed" if args. uncompressed else "wif"]) elif args.address: print(output_dict[args.network.lower() + "_address" + ("_uncompressed" if args.uncompressed else "")]) else: dump_output(output_dict, output_order)
def main(): networks = "MTLD" parser = argparse.ArgumentParser( description='Crypto coin utility ku ("key utility") to show' ' information about Bitcoin or other cryptocoin data structures.') parser.add_argument('-w', "--wallet", help='show just Bitcoin wallet key', action='store_true') parser.add_argument('-W', "--wif", help='show just Bitcoin WIF', action='store_true') parser.add_argument('-a', "--address", help='show just Bitcoin address', action='store_true') parser.add_argument( '-u', "--uncompressed", help='show output in uncompressed form', action='store_true') parser.add_argument( '-P', "--public", help='only show public version of wallet keys', action='store_true') parser.add_argument('-j', "--json", help='output as JSON', action='store_true') parser.add_argument('-s', "--subkey", help='subkey path (example: 0H/2/15-20)') parser.add_argument('-n', "--network", help='specify network (one of %s)' % networks, default='M') parser.add_argument( 'item', nargs="+", help='a BIP0032 wallet key string;' ' a WIF;' ' a bitcoin address;' ' an SEC (ie. a 66 hex chars starting with 02, 03 or a 130 hex chars starting with 04);' ' the literal string "create" to create a new wallet key using strong entropy sources;' ' P:wallet passphrase (NOT RECOMMENDED);' ' H:wallet passphrase in hex (NOT RECOMMENDED);' ' secret_exponent (in decimal or hex);' ' x,y where x,y form a public pair (y is a number or one of the strings "even" or "odd");' ' hash160 (as 40 hex characters)') args = parser.parse_args() PREFIX_TRANSFORMS = ( ("P:", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret(s.encode("utf8"), netcode=args.network))), ("H:", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret(h2b(s), netcode=args.network))), ("create", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret(get_entropy(), netcode=args.network))), ) for item in args.item: key = None for k, f in PREFIX_TRANSFORMS: if item.startswith(k): try: key = f(item[len(k):]) break except Exception: pass else: try: key = Key.from_text(item) except encoding.EncodingError: pass if key is None: secret_exponent = parse_as_secret_exponent(item) if secret_exponent: key = Key(secret_exponent=secret_exponent, netcode=args.network) if SEC_RE.match(item): key = Key.from_sec(h2b(item)) if key is None: public_pair = parse_as_public_pair(item) if public_pair: key = Key(public_pair=public_pair, netcode=args.network) if HASH160_RE.match(item): key = Key(hash160=h2b(item), netcode=args.network) if key is None: print("can't parse %s" % item, file=sys.stderr) continue for key in key.subkeys(args.subkey or ""): if args.public: key = key.public_copy() output_dict, output_order = create_output(item, key) if args.json: print(json.dumps(output_dict, indent=3)) elif args.wallet: print(output_dict["wallet_key"]) elif args.wif: print(output_dict["wif_uncompressed" if args.uncompressed else "wif"]) elif args.address: print(output_dict[ "bitcoin_address_uncompressed" if args.uncompressed else "bitcoin_address"]) else: dump_output(output_dict, output_order)
def main(): networks = "MTLD" parser = argparse.ArgumentParser( description='Crypto coin utility ku ("key utility") to show' ' information about Bitcoin or other cryptocoin data structures.', epilog='Known networks codes:\n ' \ + ', '.join(['%s (%s)'%(i, full_network_name_for_netcode(i)) for i in NETWORK_NAMES]) ) parser.add_argument('-w', "--wallet", help='show just Bitcoin wallet key', action='store_true') parser.add_argument('-W', "--wif", help='show just Bitcoin WIF', action='store_true') parser.add_argument('-a', "--address", help='show just Bitcoin address', action='store_true') parser.add_argument( '-u', "--uncompressed", help='show output in uncompressed form', action='store_true') parser.add_argument( '-P', "--public", help='only show public version of wallet keys', action='store_true') parser.add_argument('-j', "--json", help='output as JSON', action='store_true') parser.add_argument('-s', "--subkey", help='subkey path (example: 0H/2/15-20)') parser.add_argument('-n', "--network", help='specify network (default: BTC = Bitcoin)', default='BTC', choices=NETWORK_NAMES) parser.add_argument("--override-network", help='override detected network type', default=None, choices=NETWORK_NAMES) parser.add_argument( 'item', nargs="+", help='a BIP0032 wallet key string;' ' a WIF;' ' a bitcoin address;' ' an SEC (ie. a 66 hex chars starting with 02, 03 or a 130 hex chars starting with 04);' ' the literal string "create" to create a new wallet key using strong entropy sources;' ' P:wallet passphrase (NOT RECOMMENDED);' ' H:wallet passphrase in hex (NOT RECOMMENDED);' ' secret_exponent (in decimal or hex);' ' x,y where x,y form a public pair (y is a number or one of the strings "even" or "odd");' ' hash160 (as 40 hex characters)') args = parser.parse_args() if args.override_network: # force network arg to match override, but also will override decoded data below. args.network = args.override_network PREFIX_TRANSFORMS = ( ("P:", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret(s.encode("utf8"), netcode=args.network))), ("H:", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret(h2b(s), netcode=args.network))), ("create", lambda s: Key(hierarchical_wallet=Wallet.from_master_secret(get_entropy(), netcode=args.network))), ) for item in args.item: key = None for k, f in PREFIX_TRANSFORMS: if item.startswith(k): try: key = f(item[len(k):]) break except Exception: pass else: try: key = Key.from_text(item) except encoding.EncodingError: pass if key is None: secret_exponent = parse_as_secret_exponent(item) if secret_exponent: key = Key(secret_exponent=secret_exponent, netcode=args.network) if SEC_RE.match(item): key = Key.from_sec(h2b(item)) if key is None: public_pair = parse_as_public_pair(item) if public_pair: key = Key(public_pair=public_pair, netcode=args.network) if HASH160_RE.match(item): key = Key(hash160=h2b(item), netcode=args.network) if key is None: print("can't parse %s" % item, file=sys.stderr) continue if args.override_network: # Override the network value, so we can take the same xpubkey and view what # the values would be on each other network type. # XXX public interface for this is needed... key._netcode = args.override_network key._hierarchical_wallet.netcode = args.override_network for key in key.subkeys(args.subkey or ""): if args.public: key = key.public_copy() output_dict, output_order = create_output(item, key) if args.json: print(json.dumps(output_dict, indent=3, sort_keys=True)) elif args.wallet: print(output_dict["wallet_key"]) elif args.wif: print(output_dict["wif_uncompressed" if args.uncompressed else "wif"]) elif args.address: print(output_dict[ args.network.lower() + "_address" + ("_uncompressed" if args.uncompressed else "")]) else: dump_output(output_dict, output_order)
#!/usr/bin/python import os from pycoin.key.bip32 import Wallet from pycoin.encoding import public_pair_to_hash160_sec, hash160_sec_to_bitcoin_address from pycoin.networks import address_prefix_for_netcode, alternate_hash_for_netcode from binascii import hexlify import bitcoinrpc import socket secret = os.urandom(64) wallet = Wallet.from_master_secret(bytes(secret), 'BLC') sec = public_pair_to_hash160_sec(wallet.public_pair) pubkey = ''.join('{:02x}'.format(ord(x)) for x in sec) addr_blc = hash160_sec_to_bitcoin_address(sec, address_prefix=address_prefix_for_netcode('BLC'), internal_hash=alternate_hash_for_netcode('BLC')) addr_pho = hash160_sec_to_bitcoin_address(sec, address_prefix=address_prefix_for_netcode('PHO'), internal_hash=alternate_hash_for_netcode('PHO')) addr_bbtc = hash160_sec_to_bitcoin_address(sec, address_prefix=address_prefix_for_netcode('BBTC'), internal_hash=alternate_hash_for_netcode('BBTC')) addr_xdq = hash160_sec_to_bitcoin_address(sec, address_prefix=address_prefix_for_netcode('XDQ'), internal_hash=alternate_hash_for_netcode('XDQ')) addr_elt = hash160_sec_to_bitcoin_address(sec, address_prefix=address_prefix_for_netcode('ELT'), internal_hash=alternate_hash_for_netcode('ELT')) addr_umo = hash160_sec_to_bitcoin_address(sec, address_prefix=address_prefix_for_netcode('UMO'), internal_hash=alternate_hash_for_netcode('UMO')) addresses = { 'blakecoin': addr_blc, 'photon': addr_pho, 'blakebitcoin': addr_bbtc, 'dirac': addr_xdq, 'electron': addr_elt, 'universalmolecule': addr_umo }
def test_sign(self, keynums_satoshi, out_addr, out_satoshi, change_keynum, change_satoshi, prevtx_keynums, prevtx_outputs, prevtx_inputs): """ Performs a tx signing test, comparing Polly's signed tx against the reference wallet. Basic tx signing parameters: keynums_satoshi - list of tuples (keynum, satoshis) with key indices and their unspent value to use as tx inputs. Funding above out_satoshi + change_satoshi will be fees. out_addr - output address in bitcoin address format. out_satoshi - output amount in satoshis. change_keynum - change key index in the wallet, use None for no change. change_satoshi - change amount in satoshis, use 0 for no change. Supporting (previous) txs will be created to fund keynums and are controlled by these parameters: prevtx_keynums - keynums will show up as outputs of previous txs. A number randomly picked from this list controls how many keynums are chosen to include per prev tx. prevtx_outputs - in addition to previous tx outputs funding keynums, other outputs may be present. A number randomly picked from this list controls how many ignored outputs are injected per keynum. prevtx_inputs - previous txs need inputs too. A number randomly picked from this list controls how many inputs are chosen per previous tx. """ total_in_satoshi = sum(satoshi for _, satoshi in keynums_satoshi) fee_satoshi = total_in_satoshi - out_satoshi - change_satoshi chain0 = self.wallet.subkey(0, is_hardened = True).subkey(0) chain1 = self.wallet.subkey(0, is_hardened = True).subkey(1) assert total_in_satoshi >= out_satoshi + change_satoshi assert len(keynums_satoshi) <= 32 # # Step 1: send the inputs and outputs to use in the signed tx # # Create the (key num, compressed public key) tuple, input keys assume an m/0h/0/keynum path for now. keys = [(keynum, encoding.public_pair_to_sec(chain0.subkey(keynum).public_pair)) for (keynum, _) in keynums_satoshi] # Convert base58 address to raw hex address out_addr_160 = encoding.bitcoin_address_to_hash160_sec(out_addr) print() print("Sign tx parameters:", "") for i, (keynum, satoshi) in enumerate(keynums_satoshi): print("{:<10}{:16.8f} btc < key {}".format (" inputs" if 0 == i else "", satoshi / 100000000, keynum)) print("{:<10}{:16.8f} btc > {}".format (" output", out_satoshi / 100000000, self.hexstr(out_addr_160))) print("{:<10}{:16.8f} btc > key {}".format (" change", change_satoshi / 100000000, change_keynum)) print("{:<10}{:16.8f} btc".format (" fee", fee_satoshi / 100000000)) print("{:<10}{:16.8f} btc".format (" total", total_in_satoshi / 100000000)) print() print(self.PAD.format("Send tx parameters"), end='') # ---> send to Polly self.polly.send_sign_tx(keys, out_addr_160, out_satoshi, change_keynum, change_satoshi) print(self.__outok()) # # Step 2: send previous txs to fund the inputs # print() cur = 0 prevtx_info = [] while cur < len(keynums_satoshi) : prevtx_outputs_satoshi = [] # Calculate how many keynums will be associated with this prev tx end = min(cur + random.choice(prevtx_keynums), len(keynums_satoshi)) # Create the prev tx output list for keynum, satoshi in keynums_satoshi[cur:end] : # Inject a random number of outputs not associated with tx input keynums for _ in range(0, random.choice(prevtx_outputs)) : prevtx_outputs_satoshi.append((random.randint(0, 0x7FFFFFFF), random.randint(0, 2099999997690000))) # Add the outputs funding the tx input keynums prevtx_outputs_satoshi.append((keynum, satoshi)) # Create output script addr = chain0.subkey(keynum, as_private = True).bitcoin_address() script = standard_tx_out_script(addr) # Capture some info we'll use later to verify the signed tx prevtx_info.append((keynum, satoshi, script, 0, # This is the hash and will be replaced later len(prevtx_outputs_satoshi) - 1)) # Index of the valid output print("{:30}{}".format("Make prev tx for keys", " ".join(str(keynum) for (keynum, _, _, _, _) in prevtx_info[cur:]))) # Create the prev tx prevtx = self.create_prev_tx(win = Wallet.from_master_secret(bytes(0)), # create a dummy wallet in_keynum = list(range(0, random.choice(prevtx_inputs))), sources_per_input = 1, wout = chain0, out_keynum_satoshi = prevtx_outputs_satoshi, fees_satoshi = random.randint(100, 1000)) # We have built the prev tx, calculate its hash (and reverse the bytes) prevtx_hash = encoding.double_sha256(prevtx)[::-1] # Update the hashes now that we have a full prev tx for i, (keynum, satoshi, script, _, outidx) in enumerate(prevtx_info[cur:]) : prevtx_info[i + cur] = (keynum, satoshi, script, prevtx_hash, outidx) # Create the index table that matches a keynum index with an ouput index in this prev tx idx_table = [(keynum_idx + cur, outidx) for keynum_idx, (_, _, _, _, outidx) in enumerate(prevtx_info[cur:])] print(self.PAD.format("Send prev tx "), end='') # ---> send to Polly self.polly.send_prev_tx(idx_table, prevtx) print(self.__outok()) cur = end # # Step 3: generate a signed tx with the reference wallet and compare against Polly's # spendables = [] wifs = [] # Make sure that the inputs add up correctly, and prep the input_sources for reference wallet signing for (keynum, satoshi, script, prevtx_hash, outidx) in prevtx_info: spendables.append(Spendable(satoshi, script, prevtx_hash, outidx)) wifs.append(chain0.subkey(keynum, as_private = True).wif()) change_addr = chain1.subkey(change_keynum).bitcoin_address() payables = [(out_addr, out_satoshi), (change_addr, change_satoshi)] print() print(self.PAD.format("Make reference signature")) signed_tx = create_signed_tx(spendables, payables, wifs, fee_satoshi) signed_tx = self.get_tx_bytes(signed_tx) print(self.PAD.format("Get signed tx"), end='', flush = True) # <--- get the signed tx from Polly polly_signed_tx = self.polly.send_get_signed_tx() #print(self.txstr(polly_signed_tx)) #print(self.txstr(signed_tx)) print(self.__outok()) # Compare reference wallet signed tx with polly's assert signed_tx == polly_signed_tx, "test_sign: signature mismatch\nExpected:\n" + self.hexstr(signed_tx) + "\n\nActual:\n" + self.hexstr(polly_signed_tx)
def test_ref_bip32(self): """ Performs a test of the reference wallet's BIP32 key generation capability. """ # BIP32 test vectors, see https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Test_Vectors # Vector 1 m = Wallet.from_master_secret( bytes.fromhex("000102030405060708090a0b0c0d0e0f")) assert m.wallet_key( ) == "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" assert m.wallet_key( as_private=True ) == "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" assert m.bitcoin_address() == "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma" assert m.wif( ) == "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW" m0h = m.subkey(is_hardened=True) assert m0h.wallet_key( ) == "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw" assert m0h.wallet_key( as_private=True ) == "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7" m0h1 = m0h.subkey(i=1) assert m0h1.wallet_key( ) == "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ" assert m0h1.wallet_key( as_private=True ) == "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs" m0h1_1_2h = m0h1.subkey(i=2, is_hardened=True) assert m0h1_1_2h.wallet_key( ) == "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5" assert m0h1_1_2h.wallet_key( as_private=True ) == "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM" m0h1_1_2h_2 = m0h1_1_2h.subkey(i=2) assert m0h1_1_2h_2.wallet_key( ) == "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV" assert m0h1_1_2h_2.wallet_key( as_private=True ) == "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334" m0h1_1_2h_2_1000000000 = m0h1_1_2h_2.subkey(i=1000000000) assert m0h1_1_2h_2_1000000000.wallet_key( ) == "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" assert m0h1_1_2h_2_1000000000.wallet_key( as_private=True ) == "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76" # Vector 2 m = Wallet.from_master_secret( bytes.fromhex( "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542" )) assert m.wallet_key( ) == "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" assert m.wallet_key( as_private=True ) == "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U" m0 = m.subkey() assert m0.wallet_key( ) == "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" assert m0.wallet_key( as_private=True ) == "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt" m0_2147483647p = m0.subkey(i=2147483647, is_hardened=True) assert m0_2147483647p.wallet_key( ) == "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a" assert m0_2147483647p.wallet_key( as_private=True ) == "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9" m0_2147483647p_1 = m0_2147483647p.subkey(i=1) assert m0_2147483647p_1.wallet_key( ) == "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon" assert m0_2147483647p_1.wallet_key( as_private=True ) == "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef" m0_2147483647p_1_2147483646p = m0_2147483647p_1.subkey( i=2147483646, is_hardened=True) assert m0_2147483647p_1_2147483646p.wallet_key( ) == "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL" assert m0_2147483647p_1_2147483646p.wallet_key( as_private=True ) == "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc" m0_2147483647p_1_2147483646p_2 = m0_2147483647p_1_2147483646p.subkey( i=2) assert m0_2147483647p_1_2147483646p_2.wallet_key( ) == "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt" assert m0_2147483647p_1_2147483646p_2.wallet_key( as_private=True ) == "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"
def test_sign(self, keynums_satoshi, out_addr, out_satoshi, change_keynum, change_satoshi, prevtx_keynums, prevtx_outputs, prevtx_inputs): """ Performs a tx signing test, comparing Polly's signed tx against the reference wallet. Basic tx signing parameters: keynums_satoshi - list of tuples (keynum, satoshis) with key indices and their unspent value to use as tx inputs. Funding above out_satoshi + change_satoshi will be fees. out_addr - output address in bitcoin address format. out_satoshi - output amount in satoshis. change_keynum - change key index in the wallet, use None for no change. change_satoshi - change amount in satoshis, use 0 for no change. Supporting (previous) txs will be created to fund keynums and are controlled by these parameters: prevtx_keynums - keynums will show up as outputs of previous txs. A number randomly picked from this list controls how many keynums are chosen to include per prev tx. prevtx_outputs - in addition to previous tx outputs funding keynums, other outputs may be present. A number randomly picked from this list controls how many ignored outputs are injected per keynum. prevtx_inputs - previous txs need inputs too. A number randomly picked from this list controls how many inputs are chosen per previous tx. """ total_in_satoshi = sum(satoshi for _, satoshi in keynums_satoshi) fee_satoshi = total_in_satoshi - out_satoshi - change_satoshi chain0 = self.wallet.subkey(0, is_hardened=True).subkey(0) chain1 = self.wallet.subkey(0, is_hardened=True).subkey(1) assert total_in_satoshi >= out_satoshi + change_satoshi assert len(keynums_satoshi) <= 32 # # Step 1: send the inputs and outputs to use in the signed tx # # Create the (key num, compressed public key) tuple, input keys assume an m/0h/0/keynum path for now. keys = [ (keynum, encoding.public_pair_to_sec(chain0.subkey(keynum).public_pair)) for (keynum, _) in keynums_satoshi ] # Convert base58 address to raw hex address out_addr_160 = encoding.bitcoin_address_to_hash160_sec(out_addr) print() print("Sign tx parameters:", "") for i, (keynum, satoshi) in enumerate(keynums_satoshi): print("{:<10}{:16.8f} btc < key {}".format( " inputs" if 0 == i else "", satoshi / 100000000, keynum)) print("{:<10}{:16.8f} btc > {}".format(" output", out_satoshi / 100000000, self.hexstr(out_addr_160))) print("{:<10}{:16.8f} btc > key {}".format(" change", change_satoshi / 100000000, change_keynum)) print("{:<10}{:16.8f} btc".format(" fee", fee_satoshi / 100000000)) print("{:<10}{:16.8f} btc".format(" total", total_in_satoshi / 100000000)) print() print(self.PAD.format("Send tx parameters"), end='') # ---> send to Polly self.polly.send_sign_tx(keys, out_addr_160, out_satoshi, change_keynum, change_satoshi) print(self.__outok()) # # Step 2: send previous txs to fund the inputs # print() cur = 0 prevtx_info = [] while cur < len(keynums_satoshi): prevtx_outputs_satoshi = [] # Calculate how many keynums will be associated with this prev tx end = min(cur + random.choice(prevtx_keynums), len(keynums_satoshi)) # Create the prev tx output list for keynum, satoshi in keynums_satoshi[cur:end]: # Inject a random number of outputs not associated with tx input keynums for _ in range(0, random.choice(prevtx_outputs)): prevtx_outputs_satoshi.append( (random.randint(0, 0x7FFFFFFF), random.randint(0, 2099999997690000))) # Add the outputs funding the tx input keynums prevtx_outputs_satoshi.append((keynum, satoshi)) # Create output script addr = chain0.subkey(keynum, as_private=True).bitcoin_address() script = standard_tx_out_script(addr) # Capture some info we'll use later to verify the signed tx prevtx_info.append(( keynum, satoshi, script, 0, # This is the hash and will be replaced later len(prevtx_outputs_satoshi) - 1)) # Index of the valid output print("{:30}{}".format( "Make prev tx for keys", " ".join( str(keynum) for (keynum, _, _, _, _) in prevtx_info[cur:]))) # Create the prev tx prevtx = self.create_prev_tx( win=Wallet.from_master_secret( bytes(0)), # create a dummy wallet in_keynum=list(range(0, random.choice(prevtx_inputs))), sources_per_input=1, wout=chain0, out_keynum_satoshi=prevtx_outputs_satoshi, fees_satoshi=random.randint(100, 1000)) # We have built the prev tx, calculate its hash (and reverse the bytes) prevtx_hash = encoding.double_sha256(prevtx)[::-1] # Update the hashes now that we have a full prev tx for i, (keynum, satoshi, script, _, outidx) in enumerate(prevtx_info[cur:]): prevtx_info[i + cur] = (keynum, satoshi, script, prevtx_hash, outidx) # Create the index table that matches a keynum index with an ouput index in this prev tx idx_table = [ (keynum_idx + cur, outidx) for keynum_idx, (_, _, _, _, outidx) in enumerate(prevtx_info[cur:]) ] print(self.PAD.format("Send prev tx "), end='') # ---> send to Polly self.polly.send_prev_tx(idx_table, prevtx) print(self.__outok()) cur = end # # Step 3: generate a signed tx with the reference wallet and compare against Polly's # spendables = [] wifs = [] # Make sure that the inputs add up correctly, and prep the input_sources for reference wallet signing for (keynum, satoshi, script, prevtx_hash, outidx) in prevtx_info: spendables.append(Spendable(satoshi, script, prevtx_hash, outidx)) wifs.append(chain0.subkey(keynum, as_private=True).wif()) change_addr = chain1.subkey(change_keynum).bitcoin_address() payables = [(out_addr, out_satoshi), (change_addr, change_satoshi)] print() print(self.PAD.format("Make reference signature")) signed_tx = create_signed_tx(spendables, payables, wifs, fee_satoshi) signed_tx = self.get_tx_bytes(signed_tx) print(self.PAD.format("Get signed tx"), end='', flush=True) # <--- get the signed tx from Polly polly_signed_tx = self.polly.send_get_signed_tx() #print(self.txstr(polly_signed_tx)) #print(self.txstr(signed_tx)) print(self.__outok()) # Compare reference wallet signed tx with polly's assert signed_tx == polly_signed_tx, "test_sign: signature mismatch\nExpected:\n" + self.hexstr( signed_tx) + "\n\nActual:\n" + self.hexstr(polly_signed_tx)
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 = Wallet.from_wallet_key(args.wallet_key_file.readline()[:-1]) elif args.wallet_key: wallet = Wallet.from_wallet_key(args.wallet_key) else: wallet = Wallet.from_master_secret(bytes(entropy), netcode=network) try: if args.subkey: wallet = wallet.subkey_for_path(args.subkey) if wallet.child_number >= 0x80000000: wc = wallet.child_number - 0x80000000 child_index = "%dp (%d)" % (wc, wallet.child_number) else: child_index = "%d" % wallet.child_number 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.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(compressed=False)) print("Bitcoin address: %s" % wallet.bitcoin_address()) print(" uncompressed: %s" % wallet.bitcoin_address(compressed=False)) elif args.address: print(wallet.bitcoin_address(compressed=not 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])
#!/usr/bin/python import os from pycoin.key.bip32 import Wallet from pycoin.encoding import public_pair_to_hash160_sec, hash160_sec_to_bitcoin_address from pycoin.networks import address_prefix_for_netcode, alternate_hash_for_netcode from binascii import hexlify import bitcoinrpc import socket secret = os.urandom(64) wallet = Wallet.from_master_secret(bytes(secret), 'BLC') sec = public_pair_to_hash160_sec(wallet.public_pair) pubkey = ''.join('{:02x}'.format(ord(x)) for x in sec) addr_blc = hash160_sec_to_bitcoin_address( sec, address_prefix=address_prefix_for_netcode('BLC'), internal_hash=alternate_hash_for_netcode('BLC')) addr_pho = hash160_sec_to_bitcoin_address( sec, address_prefix=address_prefix_for_netcode('PHO'), internal_hash=alternate_hash_for_netcode('PHO')) addr_bbtc = hash160_sec_to_bitcoin_address( sec, address_prefix=address_prefix_for_netcode('BBTC'), internal_hash=alternate_hash_for_netcode('BBTC')) addr_xdq = hash160_sec_to_bitcoin_address( sec, address_prefix=address_prefix_for_netcode('XDQ'),
def test_ref_bip32(self): """ Performs a test of the reference wallet's BIP32 key generation capability. """ # BIP32 test vectors, see https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Test_Vectors # Vector 1 m = Wallet.from_master_secret(bytes.fromhex("000102030405060708090a0b0c0d0e0f")) assert m.wallet_key() == "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" assert m.wallet_key(as_private=True) == "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" assert m.bitcoin_address() == "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma" assert m.wif() == "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW" m0h = m.subkey(is_hardened=True) assert m0h.wallet_key() == "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw" assert m0h.wallet_key(as_private=True) == "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7" m0h1 = m0h.subkey(i=1) assert m0h1.wallet_key() == "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ" assert m0h1.wallet_key(as_private=True) == "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs" m0h1_1_2h = m0h1.subkey(i=2, is_hardened=True) assert m0h1_1_2h.wallet_key() == "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5" assert m0h1_1_2h.wallet_key(as_private=True) == "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM" m0h1_1_2h_2 = m0h1_1_2h.subkey(i=2) assert m0h1_1_2h_2.wallet_key() == "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV" assert m0h1_1_2h_2.wallet_key(as_private=True) == "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334" m0h1_1_2h_2_1000000000 = m0h1_1_2h_2.subkey(i=1000000000) assert m0h1_1_2h_2_1000000000.wallet_key() == "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" assert m0h1_1_2h_2_1000000000.wallet_key(as_private=True) == "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76" # Vector 2 m = Wallet.from_master_secret(bytes.fromhex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542")) assert m.wallet_key() == "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" assert m.wallet_key(as_private=True) == "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U" m0 = m.subkey() assert m0.wallet_key() == "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" assert m0.wallet_key(as_private=True) == "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt" m0_2147483647p = m0.subkey(i=2147483647, is_hardened=True) assert m0_2147483647p.wallet_key() == "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a" assert m0_2147483647p.wallet_key(as_private=True) == "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9" m0_2147483647p_1 = m0_2147483647p.subkey(i=1) assert m0_2147483647p_1.wallet_key() == "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon" assert m0_2147483647p_1.wallet_key(as_private=True) == "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef" m0_2147483647p_1_2147483646p = m0_2147483647p_1.subkey(i=2147483646, is_hardened=True) assert m0_2147483647p_1_2147483646p.wallet_key() == "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL" assert m0_2147483647p_1_2147483646p.wallet_key(as_private=True) == "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc" m0_2147483647p_1_2147483646p_2 = m0_2147483647p_1_2147483646p.subkey(i=2) assert m0_2147483647p_1_2147483646p_2.wallet_key() == "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt" assert m0_2147483647p_1_2147483646p_2.wallet_key(as_private=True) == "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"