Browse Source

modified: README.md
modified: mmgen-keygen
modified: mmgen-walletchk
modified: mmgen/utils.py

philemon 11 years ago
parent
commit
c8fcbdfcdc
4 changed files with 245 additions and 23 deletions
  1. 213 2
      README.md
  2. 2 2
      mmgen-keygen
  3. 9 10
      mmgen-walletchk
  4. 21 9
      mmgen/utils.py

+ 213 - 2
README.md

@@ -1,2 +1,213 @@
-mmgen
-=====
+#  mmgen = Multi-Mode GENerator
+## command-line Bitcoin cold storage solution
+
+NOTE: for the time being, MMGen should be considered Alpha software.
+Downloading and testing it out is easy, risk-free and encouraged.
+However, spending significant amounts of BTC into your mmgen-generated
+addresses is done at your own risk.
+
+### Features:
+
+> As with all deterministic wallets, mmgen can generate an unlimited number
+> of address/key pairs from a single seed.  You back up your wallet only once.
+
+> MMGen gives you four ways to access your Bitcoins:
+
+>> 1) with a wallet encrypted using the crack-resistant scrypt hash function
+>> + AES256. The wallet's password and hash strength can be changed.
+
+>> 2) from a one-line seed file (unencrypted);
+
+>> 3) from an Electrum-like mnemonic of 12, 18 or 24 words; or
+
+>> 4) from a brain password (recommended for expert users only).
+
+> Furthermore, these methods can all be combined.  If you forget your
+> Electrum-like mnemonic, for example, you can regenerate it and your
+> keys from a stored wallet or seed.  Correspondingly, a lost wallet or
+> seed can be recovered from the mnemonic.
+
+> The wallet and seed are short, simple text files suitable for printing
+> or even writing out by hand.  The base-58-encoded seed is short enough
+> to memorize, providing another brain storage alternative.
+
+> Implemented as a suite of python scripts, MMGen is super-lightweight.
+> Combined with bitcoind compiled with the watch-only address feature
+> (see below), it provides a complete solution for securely storing
+> Bitcoins offline and tracking and spending them online.
+
+
+### Instructions for Linux/Unix:
+
+### Download:
+> `git clone https://github.com/mmgen/mmgen.git`
+
+### Install:
+>  Install the ecdsa, scrypt and pycrypto modules:
+>> `sudo pip install ecdsa scrypt pycrypto`
+
+>  Install mmgen:
+>> `cd mmgen; sudo ./setup.py install`
+
+### Getting Started:
+> On your offline computer:
+
+> Generate a wallet with a random seed:
+
+            $ mmgen-walletgen
+            ...
+            Wallet saved to file '89ABCDEF-76543210[256,3].dat'
+
+
+> "89ABCDEF" is the Seed ID; "76543210" is the Key ID.
+> The Seed ID never changes and will be used to identify all
+> keys/addresses generated by this wallet.
+> The Key ID changes when the wallet's password or hash preset are changed.
+> "256" is the seed length; "3" is the scrypt hash preset.
+> These are configurable.
+
+
+> Generate ten addresses with the wallet:
+
+            $ mmgen-addrgen 89ABCDEF-76543210[256,3].dat 1-10
+            ...
+            Address data saved to file '89ABCDEF[1-10].addrs'
+
+
+> Note that the address range, "1-10", is indicated in the filename.
+> To generate addresses 1000 through 2000 (for example), specify
+> "1000-2000" on the command line and the filename will be
+> '89ABCDEF[1000-2000].addrs'
+
+            $ cat '89ABCDEF[1-10].addrs'
+            89ABCDEF {
+              1     16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE
+              2     1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc
+              3     1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N
+              4     14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s
+              5     1PeI55vtp2bX2uKDkAAR2c6ekHNYe4Hcq7
+              6     1FEqfEsSILwXPfMvVvVuUovzTaaST62Mnf
+              7     1LTTzuhMqPLwQ4IGCwwugny6ZMtUQJSJ1
+              8     1F9495H8EJLb54wirgZkVgI47SP7M2RQWv
+              9     1JbrCyt7BdxRE9GX1N7GiEct8UnIjPmpYd
+              10    1H7vVTk4ejUbQXw45I6g5qvPBSe9bsjDqh
+            }
+
+
+> To store your Bitcoins, spend them into these addresses from whatever
+> wallets/software you're currently using.  If you have lots of BTC,
+> generate lots of addresses so that each address will have only a
+> relatively small balance.
+
+### Spending your stored coins:
+> Take address 1 out of cold storage by generating a key for it:
+
+            $ mmgen-keygen 89ABCDEF-76543210[256,3].dat 1
+            ...
+            Key data saved to file '89ABCDEF[1].akeys'
+
+            $ cat 89ABCDEF[1].akeys
+            89ABCDEF {
+              1  sec:  5JCAfK1pjRoJgmpmd2HEMNwHxAzprGIXeQt8dz5qt3iLvU2KCbS
+                 addr: 16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE
+            }
+
+> Save the \*.akeys file to a USB stick and transfer it to your online computer.
+
+> On your online computer, import the secret key into
+> a running bitcoind or bitcoin-qt:
+
+            $ bitcoind importprivkey 5JCAfK1pjRoJgmpmd2HEMNwHxAzprGIXeQt8dz5qt3iLvU2KCbS
+
+> That's all there is to it!
+
+> OPTIONAL: To track balances without exposing secret keys on your
+> online computer, download and compile sipa's bitcoind patched for
+> watch-only addresses:
+
+	        $ git clone https://github.com/sipa/bitcoin
+            $ git branch mywatchonly remotes/origin/watchonly
+            $ git checkout mywatchonly
+
+            (build, install)
+
+> Import your addresses from '89ABCDEF[1-10].addrs':
+
+            $ bitcoind importaddress 16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE
+            $ bitcoind importaddress 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc
+            $ ...
+
+### Using the mnemonic and seed features:
+
+> Using our example above,
+
+> Generate a mnemonic from the wallet:
+
+            $ mmgen-walletchk -m '89ABCDEF-76543210[256,3].dat'
+            ...
+            Mnemonic data saved to file '89ABCDEF.words'
+
+            $ cat 89ABCDEF.words
+            pleasure tumble spider laughter many stumble secret bother
+            after search float relationship path strong curtain savior
+            worst suspend bright touch away dirty measure thorn
+
+> Note: a 128-bit or 192-bit seed will generate a shorter mnemonic of 12
+> or 18 words.  Generate a wallet with a shorter seed by using
+> `mmgen-walletgen -l`.  Whether you consider 128 or 192 bytes of
+> entropy to be enough is up to you.
+
+> Generate addresses 1-11 using the mnemonic instead of the wallet:
+
+            $ mmgen-addrgen -m 89ABCDEF.words 1-11
+            ...
+            Address data saved to file '89ABCDEF[1-11].addrs'
+
+> Compare the first ten addresses with those earlier generated from the
+> wallet.  You'll see they're the same.
+
+> Recover a lost wallet using the mnemonic:
+
+            $ mmgen-walletgen -m 89ABCDEF.words
+            ...
+            Wallet saved to file '89ABCDEF-01234567[256,3].dat'
+
+> Note that the regenerated wallet has a different Key ID but
+> of course the same Seed ID.
+
+> Seeds are generated the same way as mnemonics.  Just change the
+> '-m' option to '-s' in the preceding commands.
+
+> A seed file for a 256-bit seed looks like this:
+
+            $ cat 8B7392ED.mmseed
+            f4c84b C5ZT wWpT Jsoi wRVw 2dm9 Aftd WLb8 FggQ eC8h Szjd da9L
+
+> And for a 128-bit seed:
+
+            $ cat 8E0DFB78.mmseed
+            0fe02f XnyC NfPH piuW dQ2d nM47 VU
+
+> The latter is short enough to be memorized or written down.
+
+> The first word is a checksum.
+> To check that you've written or memorized the seed correctly, take the
+> first 3 bytes of a sha256 hash of the remainder of the line (with
+> spaces removed).
+
+#### Mnemonics and seeds — additional information:
+> Mnemonic and seed data may be entered at the prompt instead of from a
+> file.  Just omit the filename on the command line.
+
+> Mnemonic and seed data may be printed to standard output instead of a
+> file with `mmgen-walletchk -S`
+
+> Mnemonic and seed files may be output to a directory besides the
+> current one with `mmgen-walletchk -d`
+
+> Bear in mind that mnemonic and seed data is unencrypted.  If it's
+> compromised, your Bitcoins can easily be stolen.  Make sure no one's
+> looking when you print mnemonic or seed data to screen.  Securely
+> delete your mnemonic and seed files.  In Linux, you can achieve
+> additional security by writing the files to volatile memory in
+> '/dev/shm' instead of disk.

+ 2 - 2
mmgen-keygen

@@ -168,8 +168,8 @@ if 'stdout' in opts:
 	if invoked_as == "keygen" and not 'quiet' in opts:
 		confirm = True
 	else: confirm = False
-	write_to_stdout(addr_data_str,confirm)
+	write_to_stdout(addr_data_str,"secret keys",confirm)
 elif not sys.stdout.isatty():
-	write_to_stdout(addr_data_str,confirm=False)
+	write_to_stdout(addr_data_str,"secret keys",confirm=False)
 else:
 	write_addr_data_to_file(seed, addr_data_str, start, end, opts)

+ 9 - 10
mmgen-walletchk

@@ -32,18 +32,23 @@ help_data = {
 	'usage':   "[opts] [filename]",
 	'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
 -m, --export-mnemonic  Export the wallet's mnemonic to file
 -s, --export-seed      Export the wallet's seed to file
+-S, --stdout           Print seed or mnemonic data to standard output
 -v, --verbose          Produce more verbose output
 """
 }
 
-short_opts = "hemsv"
-long_opts  = "help","echo_passphrase","export_mnemonic","export_seed","verbose"
+short_opts = "hd:emsSv"
+long_opts  = "help","outdir=","echo_passphrase","export_mnemonic",\
+			  "export_seed","stdout","verbose"
 
 opts,cmd_args = Opts.process_opts(sys.argv,help_data,short_opts,long_opts)
 
+check_opts(opts, ('outdir',))
+
 if len(cmd_args) != 1:
 	msg("One input file must be specified")
 	sys.exit(2)
@@ -63,13 +68,7 @@ if 'export_mnemonic' in opts:
 	p = True if debug else False
 	mn = get_mnemonic_from_seed(seed, wl, default_wl, print_info=p)
 
-	write_mnemonic_to_file(mn, seed, opts)
-
-	if debug: print "Mnemonic:\n%s" % " ".join(mn)
+	write_mnemonic(mn, seed, opts)
 
 if 'export_seed' in opts:
-	write_seed_to_file(seed, opts)
-
-	if debug:
-		from mmgen.bitcoin import b58encode_pad
-		print "Seed: %s" % col4(b58encode_pad(seed))
+	write_seed(seed, opts)

+ 21 - 9
mmgen/utils.py

@@ -342,14 +342,14 @@ def encrypt_seed(seed, key, opts):
 	return enc_seed
 
 
-def	write_to_stdout(data, confirm=True):
+def	write_to_stdout(data, what, confirm=True):
 	if sys.stdout.isatty() and confirm:
-		confirm_or_exit("",'output secret keys to screen')
+		confirm_or_exit("",'output {} to screen'.format(what))
 	elif not sys.stdout.isatty():
 		import os
 		of = os.readlink("/proc/%d/fd/1" % os.getpid())
 		msg("Writing data to file '%s'" % of)
-	sys.stdout.write("\n" + data)
+	sys.stdout.write(data)
 
 
 def get_default_wordlist():
@@ -386,7 +386,7 @@ def write_to_file(outfile,data,confirm=False):
 	f.close
 
 
-def write_seed_to_file(seed, opts):
+def write_seed(seed, opts):
 
 	outfile = "%s.%s" % (make_chksum_8(seed).upper(),seed_ext)
 	if 'outdir' in opts:
@@ -396,20 +396,32 @@ def write_seed_to_file(seed, opts):
 	data = col4(b58encode_pad(seed))
 	chk = _make_chksum_6(b58encode_pad(seed))
 
-	write_to_file(outfile, "%s %s\n" % (chk,data))
+	o = "%s %s\n" % (chk,data)
 
-	msg("%s data saved to file '%s'" % ("Seed",outfile))
+	if 'stdout' in opts:
+		write_to_stdout(o,"seed data",confirm=True)
+	elif not sys.stdout.isatty():
+		write_to_stdout(o,"seed data",confirm=False)
+	else:
+		write_to_file(outfile,o)
+		msg("%s data saved to file '%s'" % ("Seed",outfile))
 
 
-def write_mnemonic_to_file(mn, seed, opts):
+def write_mnemonic(mn, seed, opts):
 
 	outfile = "%s.words" % make_chksum_8(seed).upper()
 	if 'outdir' in opts:
 		outfile = "%s/%s" % (opts['outdir'], outfile)
 
-	write_to_file(outfile," ".join(mn) + "\n")
+	o = " ".join(mn) + "\n"
 
-	msg("%s data saved to file '%s'" % ("Mnemonic",outfile))
+	if 'stdout' in opts:
+		write_to_stdout(o,"mnemonic data",confirm=True)
+	elif not sys.stdout.isatty():
+		write_to_stdout(o,"mnemonic data",confirm=False)
+	else:
+		write_to_file(outfile,o)
+		msg("%s data saved to file '%s'" % ("Mnemonic",outfile))
 
 
 def _display_control_data(label,metadata,hash_preset,salt,enc_seed):