def test_imported_privkey(setup_wallets): for n in ["mainnet", "testnet"]: privkey = "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401" jm_single().config.set("BLOCKCHAIN", "network", n) password = "******" password_key = bitcoin.bin_dbl_sha256(password) wifprivkey = bitcoin.wif_compressed_privkey(privkey, get_p2pk_vbyte()) #mainnet is "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi" #to verify use from_wif_privkey and privkey_to_address if n == "mainnet": iaddr = "1LDsjB43N2NAQ1Vbc2xyHca4iBBciN8iwC" else: iaddr = "mzjq2E92B3oRB7yDKbwM7XnPaAnKfRERw2" privkey_bin = bitcoin.from_wif_privkey( wifprivkey, vbyte=get_p2pk_vbyte()).decode('hex')[:-1] encrypted_privkey = encryptData(password_key, privkey_bin) encrypted_privkey_bad = encryptData(password_key, privkey_bin[:6]) walletdir = "wallets" testwalletname = "test" + n pathtowallet = os.path.join(walletdir, testwalletname) seed = bitcoin.sha256("\xaa" * 64)[:32] encrypted_seed = encryptData(password_key, seed.decode('hex')) timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") for ep in [encrypted_privkey, encrypted_privkey_bad]: walletfilejson = { 'creator': 'joinmarket project', 'creation_time': timestamp, 'encrypted_seed': encrypted_seed.encode('hex'), 'network': n, 'index_cache': [[0, 0]] * 5, 'imported_keys': [{ 'encrypted_privkey': ep.encode('hex'), 'mixdepth': 0 }] } walletfile = json.dumps(walletfilejson) if not os.path.exists(walletdir): os.makedirs(walletdir) with open(pathtowallet, "wb") as f: f.write(walletfile) if ep == encrypted_privkey_bad: with pytest.raises(Exception) as e_info: Wallet(testwalletname, password, 5, 6, False, False) continue newwallet = Wallet(testwalletname, password, 5, 6, False, False) assert newwallet.seed == seed #test accessing the key from the addr assert newwallet.get_key_from_addr( iaddr) == bitcoin.from_wif_privkey(wifprivkey, vbyte=get_p2pk_vbyte()) if n == "testnet": jm_single().bc_interface.sync_wallet(newwallet) load_program_config()
def cli_receive(filename): wif_privkey = raw_input("Enter private key in WIF compressed format: ") try: privkey = btc.from_wif_privkey(wif_privkey, vbyte=get_p2pk_vbyte()) except: print("Could not parse WIF privkey, quitting.") return amount = raw_input("Enter amount of utxo being spent, in satoshis: ") valid_coinjoins = scan_for_coinjoins(privkey, int(amount), filename) if not valid_coinjoins: print("Found no valid coinjoins") return for vc in valid_coinjoins: addr, priv, tx = vc print("Found signable coinjoin with destination address: ", addr) #TODO find a more sensible file naming fn = btc.txhash(tx) + ".txt" with open(fn, "wb") as f: f.write("SNICKER output file for receiver\n" "================================\n") f.write("The serialized transaction in hex:\n") f.write(tx + "\n") f.write("YOUR DESTINATION: " + addr + "\n") f.write("PRIVATE KEY FOR THIS DESTINATION ADDRESS:\n") f.write( btc.wif_compressed_privkey(priv, vbyte=get_p2pk_vbyte()) + "\n") f.write("The decoded transaction:\n") f.write(pformat(btc.deserialize(tx)) + "\n") print("The partially signed transaction and the private key for your " "output are stored in the file: " + fn) print( "Pass the transaction hex to `signrawtransaction` in Bitcoin Core " "or similar if you wish to broadcast the transaction.")
def get_utxo_info(upriv): """Verify that the input string parses correctly as (utxo, priv) and return that. """ try: u, priv = upriv.split(',') u = u.strip() priv = priv.strip() txid, n = u.split(':') assert len(txid) == 64 assert len(n) in range(1, 4) n = int(n) assert n in range(256) except: #not sending data to stdout in case privkey info jmprint("Failed to parse utxo information for utxo", "error") raise try: hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte()) except: jmprint( "failed to parse privkey, make sure it's WIF compressed format.", "error") raise return u, priv
def sign(utxo, priv, destaddrs, segwit=True): """Sign a tx sending the amount amt, from utxo utxo, equally to each of addresses in list destaddrs, after fees; the purpose is to create a large number of utxos. If segwit=True the (single) utxo is assumed to be of type segwit p2sh/p2wpkh. """ results = validate_utxo_data([(utxo, priv)], retrieve=True, segwit=segwit) if not results: return False assert results[0][0] == utxo amt = results[0][1] ins = [utxo] # TODO extend to other utxo types txtype = 'p2sh-p2wpkh' if segwit else 'p2pkh' estfee = estimate_tx_fee(1, len(destaddrs), txtype=txtype) outs = [] share = int((amt - estfee) / len(destaddrs)) fee = amt - share * len(destaddrs) assert fee >= estfee log.info("Using fee: " + str(fee)) for i, addr in enumerate(destaddrs): outs.append({'address': addr, 'value': share}) unsigned_tx = btc.mktx(ins, outs) amtforsign = amt if segwit else None return btc.sign(unsigned_tx, 0, btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte()), amount=amtforsign)
def validate_utxo_data(utxo_datas, retrieve=False, segwit=False): """For each txid: N, privkey, first convert the privkey and convert to address, then use the blockchain instance to look up the utxo and check that its address field matches. If retrieve is True, return the set of utxos and their values. """ results = [] for u, priv in utxo_datas: jmprint('validating this utxo: ' + str(u), "info") hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte()) if segwit: addr = btc.pubkey_to_p2sh_p2wpkh_address( btc.privkey_to_pubkey(hexpriv), get_p2sh_vbyte()) else: addr = btc.privkey_to_address(hexpriv, magicbyte=get_p2pk_vbyte()) jmprint('claimed address: ' + addr, "info") res = jm_single().bc_interface.query_utxo_set([u]) if len(res) != 1 or None in res: jmprint("utxo not found on blockchain: " + str(u), "error") return False if res[0]['address'] != addr: jmprint("privkey corresponds to the wrong address for utxo: " + str(u), "error") jmprint("blockchain returned address: {}".format(res[0]['address']), "error") jmprint("your privkey gave this address: " + addr, "error") return False if retrieve: results.append((u, res[0]['value'])) jmprint('all utxos validated OK', "success") if retrieve: return results return True
def generate_single_podle_sig(u, priv, i): """Make a podle entry for key priv at index i, using a dummy utxo value. This calls the underlying 'raw' code based on the class PoDLE, not the library 'generate_podle' which intelligently searches and updates commitments. """ #Convert priv to hex hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte()) podle = PoDLE(u, hexpriv) r = podle.generate_podle(i) return (r['P'], r['P2'], r['sig'], r['e'], r['commit'])
def test_wif_privkeys_invalid(): #first try to create wif privkey from key of wrong length bad_privs = [b'\x01\x02' * 17] #some silly private key but > 33 bytes #next try to create wif with correct length but wrong compression byte bad_privs.append(b'\x07' * 32 + b'\x02') for priv in bad_privs: with pytest.raises(Exception) as e_info: fake_wif = btc.wif_compressed_privkey( binascii.hexlify(priv).decode('ascii')) #Create a wif with wrong length bad_wif1 = btc.bin_to_b58check(b'\x01\x02' * 34, b'\x80') #Create a wif with wrong compression byte bad_wif2 = btc.bin_to_b58check(b'\x07' * 33, b'\x80') for bw in [bad_wif1, bad_wif2]: with pytest.raises(Exception) as e_info: fake_priv = btc.from_wif_privkey(bw) #Some invalid b58 from bitcoin repo; #none of these are valid as any kind of key or address with open(os.path.join(testdir, "base58_keys_invalid.json"), "r") as f: json_data = f.read() invalid_key_list = json.loads(json_data) for k in invalid_key_list: bad_key = k[0] for netval in ["mainnet", "testnet"]: #if using pytest -s ; sanity check to see what's actually being tested print('testing this key: ' + bad_key) #should throw exception with pytest.raises(Exception) as e_info: from_wif_key = btc.from_wif_privkey( bad_key, btc.get_version_byte(bad_key)) #in case the b58 check encoding is valid, we should #also check if the leading version byte is in the #expected set, and throw an error if not. if chr(btc.get_version_byte(bad_key)) not in b'\x80\xef': raise Exception("Invalid version byte")
def test_wif_privkeys_valid(): with open(os.path.join(testdir, "base58_keys_valid.json"), "r") as f: json_data = f.read() valid_keys_list = json.loads(json_data) for a in valid_keys_list: key, hex_key, prop_dict = a if prop_dict["isPrivkey"]: netval = "testnet" if prop_dict["isTestnet"] else "mainnet" print 'testing this key: ' + key assert chr(btc.get_version_byte( key)) in '\x80\xef', "not valid network byte" comp = prop_dict["isCompressed"] from_wif_key = btc.from_wif_privkey( key, compressed=comp, vbyte=btc.get_version_byte(key) - 128) expected_key = hex_key if comp: expected_key += '01' assert from_wif_key == expected_key, "Incorrect key decoding: " + \ str(from_wif_key) + ", should be: " + str(expected_key)
print('hexseed = ' + hexseed) words = mn_encode(hexseed) print('Wallet recovery seed\n\n' + ' '.join(words) + '\n') elif method == 'importprivkey': print('WARNING: This imported key will not be recoverable with your 12 ' + 'word mnemonic seed. Make sure you have backups.') print('WARNING: Handling of raw ECDSA bitcoin private keys can lead to ' 'non-intuitive behaviour and loss of funds.\n Recommended instead ' 'is to use the \'sweep\' feature of sendpayment.py ') privkeys = raw_input('Enter private key(s) to import: ') privkeys = privkeys.split(',') if ',' in privkeys else privkeys.split() # TODO read also one key for each line for privkey in privkeys: # TODO is there any point in only accepting wif format? check what # other wallets do privkey_bin = btc.from_wif_privkey(privkey, vbyte=get_p2pk_vbyte()).decode('hex')[:-1] encrypted_privkey = encryptData(wallet.password_key, privkey_bin) if 'imported_keys' not in wallet.walletdata: wallet.walletdata['imported_keys'] = [] wallet.walletdata['imported_keys'].append( {'encrypted_privkey': encrypted_privkey.encode('hex'), 'mixdepth': options.mixdepth}) if wallet.walletdata['imported_keys']: fd = open(wallet.path, 'w') fd.write(json.dumps(wallet.walletdata)) fd.close() print('Private key(s) successfully imported') elif method == 'dumpprivkey': if options.hd_path.startswith('m/0/'): m, forchange, k = [int(y) for y in options.hd_path[4:].split('/')] key = wallet.get_key(m, forchange, k)