mmgen-wallet/mmgen-txsign
philemon a3c4bd8731 New feature: export wallet to incognito format
Incognito wallet is 48, 56 or 64 bytes of apparently random data.

  Allows user to hide wallet data in a pre-existing file or on a disk
  partition (preferably filled in advance with random data).

  Can be used to hide wallet securely in unencrypted cloud storage or
  on paper, without revealing the nature of the data.

  Data may be written at a user-specified offset into the file or
  partition, in which case user must remember the offset.

  Each export operation uses a new random init vector to create different
  data each time.  This allows the user to hide wallets at different
  locations on the Net without detection.

  User must remember hash preset in addition to passphrase (though trial
  and error can be used if it's forgotten).

  Fully integrated with address generation and tx signing operations.
2014-07-14 18:31:00 +04:00

162 lines
5.9 KiB
Python
Executable file

#!/usr/bin/env python
#
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
mmgen-txsign: Sign a Bitcoin transaction generated by mmgen-txcreate
"""
import sys
from mmgen.Opts import *
from mmgen.license import *
import mmgen.config as g
from mmgen.tx import *
from mmgen.util import msg,qmsg
help_data = {
'prog_name': sys.argv[0].split("/")[-1],
'desc': "Sign a Bitcoin transaction generated by mmgen-txcreate",
'usage': "[opts] <transaction file> [mmgen wallet/seed/words/brain file]...",
'options': """
-h, --help Print this help message
-d, --outdir d Specify an alternate directory 'd' for output
-e, --echo-passphrase Print passphrase to screen when typing it
-i, --info Display information about the transaction and exit
-I, --tx-id Display transaction ID and exit
-k, --keys-from-file k Provide additional key data from file 'k'
-P, --passwd-file f Get passphrase from file 'f'
-q, --quiet Suppress warnings; overwrite files without
prompting
-V, --skip-key-preverify Skip optional key pre-verification step
-b, --from-brain l,p Generate keys from a user-created password,
i.e. a "brainwallet", using seed length 'l' and
hash preset 'p'
-w, --use-wallet-dat Get keys from a running bitcoind
-g, --from-incognito Generate keys from an incognito-format wallet
-m, --from-mnemonic Generate keys from an electrum-like mnemonic
-s, --from-seed Generate keys from a seed in .{} format
Transactions with either mmgen or non-mmgen input addresses may be signed.
For non-mmgen inputs, the bitcoind wallet.dat is used as the key source.
For mmgen inputs, key data is generated from your seed as with the
mmgen-addrgen and mmgen-keygen utilities.
Data for the --from-<what> options will be taken from a file if a second
file is specified on the command line. Otherwise, the user will be
prompted to enter the data.
In cases of transactions with mixed mmgen and non-mmgen inputs, non-mmgen
keys must be supplied in a separate file (WIF format, one key per line)
using the '--keys-from-file' option. Alternatively, one may get keys from
a running bitcoind using the '--force-wallet-dat' option. First import the
required mmgen keys using 'bitcoind importprivkey'.
For transaction outputs that are MMGen addresses, MMGen-to-Bitcoin address
mappings are verified. Therefore, seed material for these addresses must
be supplied on the command line.
Seed data supplied in files must have the following extensions:
wallet: '.{}'
seed: '.{}'
mnemonic: '.{}'
brainwallet: '.{}'
""".format(g.seed_ext,g.wallet_ext,g.seed_ext,g.mn_ext,g.brain_ext)
}
short_opts = "hd:eiIk:P:qVb:wgms"
long_opts = "help","outdir=","echo_passphrase","info","tx_id",\
"keys_from_file=","passwd_file=","quiet","skip_key_preverify",\
"from_brain=","use_wallet_dat",\
"from_incognito","from_mnemonic","from_seed"
opts,infiles = process_opts(sys.argv,help_data,short_opts,long_opts)
if "quiet" in opts: g.quiet = True
check_opts(opts,long_opts)
if not infiles: usage(help_data)
for i in infiles: check_infile(i)
c = connect_to_bitcoind()
tx_file = infiles.pop(0)
m = "" if 'tx_id' in opts else "transaction data"
tx_data = get_lines_from_file(tx_file,m)
metadata,tx_hex,inputs_data,b2m_map = parse_tx_data(tx_data,tx_file)
if 'tx_id' in opts:
msg(metadata[0])
sys.exit(0)
if 'info' in opts:
view_tx_data(c,inputs_data,tx_hex,b2m_map,metadata)
sys.exit(0)
do_license_msg(immed=True)
# Are inputs mmgen addresses?
mmgen_addrs = [i for i in inputs_data if parse_mmgen_label(i['account'])[0]]
other_addrs = [i for i in inputs_data if not parse_mmgen_label(i['account'])[0]]
keys = get_lines_from_file(opts['keys_from_file'],"key data",remove_comments=True) \
if 'keys_from_file' in opts else []
if other_addrs and not keys and not 'use_wallet_dat' in opts:
missing_keys_errormsg(other_addrs)
sys.exit(2)
if other_addrs and keys and not 'skip_key_preverify' in opts:
a = [i['address'] for i in other_addrs]
preverify_keys(a, keys)
seeds = {}
check_mmgen_to_btc_addr_mappings(inputs_data,b2m_map,infiles,seeds,opts)
qmsg("Successfully opened transaction file '%s'" % tx_file)
prompt = "View transaction data? (y)es, (N)o, (v)iew in pager"
reply = prompt_and_get_char(prompt,"YyNnVv",enter_ok=True)
if reply and reply in "YyVv":
p = True if reply in "Vv" else False
view_tx_data(c,inputs_data,tx_hex,b2m_map,metadata,pager=p)
sig_data = [
{"txid":i['txid'],"vout":i['vout'],"scriptPubKey":i['scriptPubKey']}
for i in inputs_data]
if mmgen_addrs:
ml = [i['account'].split()[0] for i in mmgen_addrs]
keys += get_keys_for_mmgen_addrs(ml,infiles,seeds,opts)
if 'use_wallet_dat' in opts:
sig_tx = sign_tx_with_bitcoind_wallet(c,tx_hex,sig_data,keys,opts)
else:
sig_tx = sign_transaction(c,tx_hex,sig_data,keys)
elif other_addrs:
if keys:
sig_tx = sign_transaction(c,tx_hex,sig_data,keys)
else:
sig_tx = sign_tx_with_bitcoind_wallet(c,tx_hex,sig_data,keys,opts)
if sig_tx['complete']:
prompt = "OK\nSave signed transaction?"
if user_confirm(prompt,default_yes=True):
print_signed_tx_to_file(tx_hex,sig_tx['hex'],metadata,opts)
else:
msg("failed\nSome keys were missing. Transaction could not be signed.")
sys.exit(3)