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.
162 lines
5.9 KiB
Python
Executable file
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)
|