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.
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 and index 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 so their balances will be visible. For convenient identification, you've chosen to provide the addresses with the labels "Donations", "Storage 1", "Storage 2" and "Storage 3".
Make a copy of the file:
$ cp '89ABCDEF[1-10].addrs' my_addrs
and edit the copy using your favorite text editor to look like this:
$ cat my_addrs
# My first MMGen addresses
89ABCDEF {
1 16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE Donations
2 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc Storage 1
3 1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N Storage 2
4 14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s Storage 3
}
Note the comment beginning with a '#' symbol. Comments may be placed at the ends of lines as well. Note also 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.
On your online computer, start bitcoind and import the addresses into the tracking wallet with the command:
$ mmgen-addrimport my_addrs
These addresses will now be tracked by bitcoind. Any BTC transferred to them will show up in your listing of unspent outputs.
If you have any existing addresses with balances, you'll want to track them too.
Make a plain list of these addresses, one address per line, and import the list
into the tracking wallet using mmgen-addrimport -l
.
$ 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.
Continue in this fashion until you've imported all addresses with balances into your tracking wallet.
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 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 moving your 39.72 BTC balance into your shiny new MMGen wallet with seed ID 89ABCDEF.
Before moving any funds into your MMGen wallet, you should back it up 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 access to 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. So you've decided to begin by breaking up the 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:2, 89ABCDEF:3 and 89ABCDEF:4).
To refresh your memory, here are the three addresses in question:
$ cat my_addrs
# My first MMGen addresses
89ABCDEF {
1 16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE Donations
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 10 BTC input to the third, subtracting a default transaction fee of 0.001 BTC:
$ mmgen-txcreate 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc,3.3 1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N,3.3 14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s
The bare address with no amount is the change address. MMGen will compute the change amount (3.399 BTC in this case) automatically.
Alternatively, and more conveniently, you can list your three addresses in MMGen format:
$ mmgen-txcreate -a my_addrs 89ABCDEF:2,3.3 89ABCDEF:3,3.3 89ABCDEF:4
Note that an MMGen address file containing the requested output addresses must be provided on the command line. In this example, the extra address in the file is ignored.
Now hit ENTER, choose the transaction's input from the list (10 BTC, address
1F9495H8EJL..., txid 04f97185
...,2), and confirm. If all goes well,
mmgen-txcreate
will exit with the message:
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.
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, 1F9495H8EJL.... If the key in question is in a bitcoin 'wallet.dat', there's an included command (a modified version of the well-known pywallet utility) that will conveniently extract it 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, since 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 merge them into a single file which you can use to sign all future transactions with wallet.dat inputs:
$ mmgen-pywallet -k wallet1.dat
$ mmgen-pywallet -k wallet2.dat
$ mmgen-pywallet -k wallet3.dat
$ cat wd_*.keys > all_keys
For your future transactions with MMGen address inputs, you'll list the MMGen seed source (wallet, mnemonic or seed file) on the command line after the transaction file, and the required keys will be generated automatically:
$ 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 deal with keys directly again, because MMGen generates all keys on the fly using the seed.
Now you'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 to
see them displayed in MMGen format.
Congratulations! You've performed your first MMGen transaction.
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 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 file is short enough to 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
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 has
intentionally been 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.
The test suite can be run from within the MMGen source directory. You might find the following tests to be of interest:
Show available tests:
mmgen/tests/bitcoin.py
Compare 10 addresses generated by 'keyconv' with mmgen's internally-generated ones:
mmgen/tests/bitcoin.py keyconv_compare_randloop 10
Convert a string to base 58 and back:
mmgen/tests/bitcoin.py strtob58 'a string'
Convert a hex number to base 58 and back:
mmgen/tests/bitcoin.py hextob58 deadbeef
Perform 1000 hex -> base58 -> hex conversions, comparing results stringwise:
mmgen/tests/bitcoin.py hextob58_pad_randloop 1000
Show available tests:
mmgen/tests/mnemonic.py
Generate a 12-word mnemonic from a random 128-bit seed:
mmgen/tests/mnemonic.py random128
or an 18-word mnemonic from a random 192-bit seed:
mmgen/tests/mnemonic.py random192
or a 24-word mnemonic from a random 256-bit seed:
mmgen/tests/mnemonic.py random256
Show statistics for the Electrum wordlist:
mmgen/tests/mnemonic.py electrum
Print the Electrum wordlist:
mmgen/tests/mnemonic.py electrum_print
Show statistics for the Tirosh wordlist:
mmgen/tests/mnemonic.py tirosh
Print the Tirosh wordlist:
mmgen/tests/mnemonic.py tirosh_print