an online/offline cryptocurrency wallet for the command line https://mmgen-wallet.cc

philemon 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
doc 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
scripts afa3fe609a Code cleanups 11 years ago
tests aa66a44066 TX scripts updates; import address feature added 11 years ago
wordlists 1da4504373 modified: mmgen/mn_electrum.py 11 years ago
MANIFEST 3302ac774f Various bugfixes, better password handling 11 years ago
README.md 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen-addrgen 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen-addrimport 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen-passchg 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen-pywallet 9a64bf42e2 Improved handling of user input; code cleanups 11 years ago
mmgen-txcreate 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen-txsend 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen-txsign 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen-walletchk 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
mmgen-walletgen 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago
setup.py 536bfb5221 Modified README.md. Various fixes, improvements. 11 years ago

README.md

MMGen = Multi-Mode GENerator

a Bitcoin cold storage solution for the command line

Description

MMGen is implemented as a suite of lightweight Python command-line scripts that require only a bare minimum of system resources. The scripts function in tandem with a modified bitcoind running on an online computer and a standard bitcoind running offline to provide a robust solution for securely storing, tracking, spending and receiving your Bitcoins. "Non-MMGen" addresses can be tracked and spent as well, creating an easy migration path from other wallets.

The online bitcoin daemon is modified to support watch-only addresses, a feature soon to be included in the mainline Satoshi build. In the meantime, instructions are provided below for compiling the watch-only bitcoind, which under Linux is surprisingly easy.

MMGen uses the reference Satoshi daemon, rather than less-reliable third-party software, to do all the "heavy lifting" of tracking and signing transactions. And unlike other online/offline wallet solutions, the MMGen system is completely self-contained, relying on no external server to do its work; no third party will know which addresses you're tracking.

Like all deterministic wallets, MMGen can generate a virtually unlimited number of address/key pairs from a single seed. Your wallet never changes, so you need back it up only once. Transactions are signed offline: your private keys never touch an online computer.

At the heart of the MMGen system is the seed, the "master key" providing access to all your Bitcoins. The seed can be stored in four different ways:

1) as a wallet with a password encrypted using the crack-resistant scrypt hash function. Scrypt's parameters can be adjusted on the command line, making your wallet's password virtually impossible to crack should it fall into the wrong hands. The wallet is a tiny text file suitable for printing or even writing out by hand;

2) as a seed file: a one-line base-58 representation of your unencrypted seed plus a checksum;

3) as an Electrum-like mnemonic of 12, 18 or 24 words; or

4) as a brainwallet password (this option is recommended for expert users only).

The best part is that all these methods can be combined. If you forget your mnemonic, for example, you can regenerate it and your keys from the stored wallet or seed file. Correspondingly, a lost wallet can be regenerated from the mnemonic or seed or a lost seed from the wallet or mnemonic.

Download/Install

Install on Microsoft Windows

Install on Debian/Ubuntu Linux

Using MMGen

Generate a wallet (offline computer):

On your offline computer, generate a wallet with a random seed:

    $ mmgen-walletgen
    ...
    Wallet saved to file '89ABCDEF-76543210[256,3].mmdat'

"89ABCDEF" is the Seed ID; "76543210" is the Key ID. These are randomly generated, so your IDs will of course be different than the fictitious ones used here.

The Seed ID never changes and will be used to identify all keys/addresses generated by this seed. 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 values are configurable: type mmgen-walletgen --help for details.

Generate addresses (offline computer):

Now generate ten addresses with your just-created wallet:

    $ mmgen-addrgen 89ABCDEF-76543210[256,3].mmdat 1-10
    ...
    Address data saved to file '89ABCDEF[1-10].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
    }

Note that the address range, "1-10", is reflected in the resulting filename. MMGen addresses are identified by their seed ID plus number, separated by a colon. In this example, "89ABCDEF:1" is the MMGen equivalent of Bitcoin address 16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE, "89ABCDEF:2" the equivalent of 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc, and so forth.

Let's say you've decided to transfer some BTC into the first four addresses above. Your first step, then, will be to import these addresses into the tracking wallet on your online machine. You've chosen to provide the addresses with the labels "Donations", "Storage 1", "Storage 2" and "Storage 3" for convenient identification.

Make a copy of the file:

    $ cp '89ABCDEF[1-10].addrs' my_addrs_for_import

and edit the copy using your favorite text editor. The result will look something like this:

    $ cat my_addrs_for_import
    89ABCDEF {
      1    16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE  Donations
      2    1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc  Storage 1
      3    1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N  Storage 2
      4    14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s  Storage 3
    }

Note that rows in the list may be arranged in any order; addresses need not be consecutive.

Copy this file onto a USB stick and transfer it to your online computer.

Import addresses (online computer):

On your online computer, start bitcoind and import the addresses into the tracking wallet:

    $ mmgen-addrimport my_addrs_for_import

These addresses are now being "tracked". Any BTC transferred to them will show up in our listing of unspent outputs.

You'll want to track your existing addresses with balances too. Make a plain list of these addresses, one address per line, and import the list into the tracking wallet using the same command with the '-l' option:

    $ mmgen-addrimport -l my_existing_addrs_with_balances

Since the importing process is slow, you may want to do it in stages, a few addresses at a time.

For your convenience, comments beginning with a '#' symbol may be included in address lists. Continue in this fashion until you've imported all addresses with balances into your tracking wallet.

Create a transaction (online computer):

Now that your existing addresses are imported, you're ready to create a test transaction using the mmgen-txcreate command. Note that transactions are harmless until they're signed and broadcast to the network, so feel free to experiment with different transactions using different combinations of inputs and outputs.

First of all, you'll probably want to examine your balances:

    $ mmgen-txcreate -i

A list of all your unspent outputs will appear, along with a menu allowing you to sort the outputs by four criteria: transaction ID, address, amount and transaction age. Your overall balance in BTC appears at the top of the screen. The list may be viewed in a pager or printed to file. If you have ten unspent outputs, your display will look something like this:

    UNSPENT OUTPUTS (sort order: reverse amount)  Total BTC: 39.72
     Num  TX id  Vout    Address                            Amount (BTC)  Age(days)
     1)   04f97185... 2  1F93Znz8PI5Pnvv8ZAJsb74EzKpmRMLFbk  10           320
     2)   dd900544... 1  194Fceqx86jqIWumphUmfVyFMjAAbMLcSE   9.9287435   7
     3)   7ec81a8f... 0  1FhIkRabPSZhhUsA6qvukmfK4T4PZLbC4M   7.26        17
     4)   64094b55... 0  16JSUJdGMbxUBEQatAR5sGE89tbSIsLHqg   3.15        140
     5)   fd687c65... 1  1QKAtU66aUntCBx9m6TfEIf3gQuCNWCVDY   3.15        140
     6)   9a8f20e2... 1  1FMNDFz1yUywjJSprjvYY9t1yxkE8GGIwT   3.15        140
     7)   03a7c51a... 3  1svxnSdKVIcMs6qWYA7qLzA29orXbzXUm    1.6382466   54
     8)   9955f06c... 2  18nWPLQGUzI7X1Rcm4zmVV6Z3xhokdYx9G   1.2         27
     9)   8a4ab4f5... 0  13S9HNu7PQn1aJ4qILfhqRSakXwvSTnbwJ   0.23033     3
     10)  5bfe5621... 1  1FV1Lhs6Dnc9gMxjJTo6h4nTeIjJbQ1PgV   0.01        42

    Sort options: [t]xid, [a]mount, a[d]dress, [A]ge, [r]everse, [M]mgen addr
    View options: [g]roup, show [m]mgen addr
    (Type 'q' to quit sorting, 'p' to print to file, 'v' to view in pager):

Now let's actually create a transaction. Let's say you've decided to gradually begin spending your 39.72 BTC balance into your shiny new MMGen wallet with seed ID 89ABCDEF.

Before doing anything else, you should back up your MMGen wallet in several places and possibly on several media too: paper, flash memory or CD-ROM, for example. Of course the wallet should have a passphrase. Otherwise, anyone who gains physical control of one of your backups can easily steal your coins.

Recall that there's no limit to the number of addresses you can generate with your seed. You've wisely determined that having many addresses with relatively small balances is a Good Idea. You've decided to begin by breaking up your address with the largest balance, 10 BTC, into three roughly equal parts, sending it to the addresses labeled "Storage 1", "Storage 2" and "Storage 3" (89ABCDEF:1, 89ABCDEF:2 and 89ABCDEF:3).

To refresh our memory, here are the three addresses in question:

    89ABCDEF {
      2    1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc  Storage 1
      3    1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N  Storage 2
      4    14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s  Storage 3
    }

The following command will send 3.3 BTC to the first two addresses and the remainder of the transaction's inputs to the third, subtracting a default transaction fee of 0.001 BTC:

    $ mmgen-txcreate 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc,3.3 1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N,3.3 14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s

The third address has the amount left out, making it a change address. MMGen will compute the change amount (3.399 BTC in this case) automatically.

Alternatively, and more conveniently, you can write the addresses in MMGen format:

    $ mmgen-txcreate -a addrs 89ABCDEF:2,3.3 89ABCDEF:3,3.3 89ABCDEF:4

'addrs' is an MMGen address file containing the requested output addresses. Any unneeded addresses in the file will be ignored.

Now hit ENTER, choose the transaction's input from the list (10 BTC, address 1F9495H8EJLb54wirgZkVgI47SP7M2RQWv, txid 04f97185...,2), and confirm. If all goes well, the command will exit with a message like this:

    Transaction data saved to file 'tx_1EDCBA[6.6].raw'

Note that the transaction has a unique ID, and the non-change output amount, 6.6 BTC, is conveniently included in the filename.

Sign the transaction (offline computer):

Now copy the raw transaction you've just created to a USB stick and transfer it to your offline computer for signing. You need to find the key for your transaction's one input address, 1F9495H8EJLb54wirgZkVgI47SP7M2RQWv. If the key in question is in a bitcoin 'wallet.dat', there's an included command that will conveniently extract the key for you:

    $ mmgen-pywallet -k wallet.dat
    ...
    wallet.dat secret keys saved to file wd_EDBC983A[102].keys

You've in fact extracted a list of all of the wallet's 102 keys here, but that's not a problem, as the unused keys will be ignored. Now go ahead and sign the transaction using this list of keys.

    $ mmgen-txsign -k wd_EDBC983A[102].keys tx_1EDCBA[6.6].raw
    ...
    Signed transaction saved to file tx_1EDCBA[6.6].sig

Note that mmgen-pywallet's output is just a flat list of keys. So if you have several Bitcoin wallets with balances, you can just dump all their keys and concatenate them into a single file which you can use to sign all your future transactions involving wallet.dat inputs:

    $ mmgen-pywallet -k wallet1.dat
    $ mmgen-pywallet -k wallet2.dat
    $ mmgen-pywallet -k wallet3.dat
    $ cat wd_*.keys > all_keys

For transactions whose inputs are MMGen addresses, an MMGen seed source (i.e. wallet, mnemonic or seed file) is listed on the command line after the transaction file, and the required keys are automatically generated:

    $ mmgen-txsign tx_9D2C3A[1.23].raw B73B58EA-125FB230[256,3].mmdat

Transactions may contain a mixture of MMGen and non-MMGen inputs as well as inputs with more than one MMGen seed ID. Just provide a seed source for each seed ID on the command line.

Eventually, when you've placed all your BTC under MMGen control, you'll never have to deal with keys again. MMGen just generates them on the fly as the need arises.

Send the transaction (online computer):

Now we're ready for the final step: broadcasting the transaction to the network. Copy the *.sig file to your online computer, start bitcoind, if it's not running, and execute the command

    $ mmgen-txsend tx_1EDCBA[6.6].sig

Like all mmgen commands, mmgen-txsend is interactive, so you'll be asked for confirmation before the transaction is actually sent.

Once the transaction's confirmed by the network, your three new MMGen addresses will appear on the listing of mmgen-txcreate -i. Type 'm' at the menu and they'll be displayed in MMGen format.

Congratulations! You've performed your first MMGen transaction.

Additional Features

Using the mnemonic and seed features:

Continuing our example above, generate a mnemonic from the wallet:

    $ mmgen-walletchk -m '89ABCDEF-76543210[256,3].mmdat'
    ...
    Mnemonic data saved to file '89ABCDEF.mmwords'

    $ cat 89ABCDEF.mmwords
    pleasure tumble spider laughter many stumble secret bother
    after search float absent path strong curtain savior
    worst suspend bright touch away dirty measure thorn

Note: a 128- or 192-bit seed will generate a shorter mnemonic of 12 or 18 words. You may generate a wallet with a these seed lengths using the '-l' option to mmgen-walletgen.

Though some consider 128 bits of entropy to provide adequate security for the foreseeable future, you should stick to the default 256-bit seed length if you're not planning to use the mnemonic feature.

NOTE: MMGen mnemonics are generated from the Electrum wordlist, only using ordinary base conversion instead of Electrum's more complicated algorithm.

Generate addresses 1-11 using the mnemonic instead of the wallet:

    $ mmgen-addrgen 89ABCDEF.mmwords 1-11
    ...
    Address data saved to file '89ABCDEF[1-11].addrs'

Compare the first ten addresses with those earlier generated by the wallet. You'll see they're the same.

Recover a lost wallet using the mnemonic:

    $ mmgen-walletgen 89ABCDEF.mmwords
    ...
    Wallet saved to file '89ABCDEF-01234567[256,3].mmdat'

Note that the regenerated wallet has a different Key ID but of course the same Seed ID.

Seed files bear the extension '*.mmseed' and are listed on the command line the same way as mnemonic files are.

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

As you can see, the latter is short enough to practically be memorized. From the unix command line, you can test your memory using the seed's checksum ('0fe02f' in this example) as follows:

    $ echo -n XnyCNfPHpiuWdQ2dnM47VU | sha256sum | cut -c 1-6
    0fe02f

Mnemonics and seeds — additional information:

With the '-m' or '-s' option, MMGen commands that take mnemonic and seed data may receive the data from a prompt instead of a file.

MMGen commands that produce mnemonic and seed data may be forced to print it to standard output instead of file with the '-S' option. This feature was intentionally made optional to safeguard against looking-over-the-shoulder, Van Eyck phreaking and other side-channel attacks. MMGen commands never print private data to the screen unless explicitly asked to.

The output file of any MMGen command may be written to a directory of your choice using the '-d' option. For example, on a Linux system you could use '-d /dev/shm' to write key and seed data to volatile memory instead of disk. This also has obvious security benefits, ensuring that no sensitive data remains on disk after your computer's been powered down.

Test suite:

To see what tests are available, run the scripts in the 'tests' directory with no arguments. You might find the following tests to be of interest:

Compare 10 addresses generated by 'keyconv' with mmgen's internally-generated ones:

tests/bitcoin.py keyconv_compare_randloop 10

Convert a string to base 58 and back:

tests/bitcoin.py strtob58 'a string'

Convert a hex number to base 58 and back:

tests/bitcoin.py hextob58 deadbeef

Perform 1000 hex -> base58 -> hex conversions, comparing results stringwise:

tests/bitcoin.py hextob58_pad_randloop 1000

Generate a 12-word mnemonic from a random 128-bit seed:

tests/mnemonic.py random128

or an 18-word mnemonic from a random 192-bit seed:

tests/mnemonic.py random192

or a 24-word mnemonic from a random 256-bit seed:

tests/mnemonic.py random256