Browse Source

addr generation with secp256k1mod

philemon 8 years ago
parent
commit
5676d7a3f9

+ 2 - 5
doc/wiki/install-linux/Install-Bitcoind.md

@@ -18,10 +18,8 @@
 
 #### Download:
 
-> For the time being, Windows installers and Linux binary tarballs can be
-> obtained [here][00].  Once version 0.10 is released, get them from Bitcoin
-> Core's [main download page][01] instead.  Choose the 32-bit or 64-bit versions
-> appropriate for your respective computers.
+> Go to the Bitcoin Core [main download page][01].  Choose the 32-bit or 64-bit
+> versions appropriate for your respective computers.
 
 #### Install:
 
@@ -57,6 +55,5 @@
 > Note that in the absence of a blockchain the daemon starts very quickly and
 > uses practically no CPU once running.
 
-[00]: https://bitcoin.org/bin/0.10.0/test/
 [01]: https://bitcoin.org/en/download
 [bd]: https://bitcoin.org/bin/blockchain/

+ 10 - 1
doc/wiki/install-linux/Install-MMGen-on-Debian-or-Ubuntu-Linux.md

@@ -8,12 +8,21 @@ Install the Python Cryptography Toolkit:
 
 		$ sudo pip install pycrypto
 
+Install the secp256k1 library
+
+		$ git clone https://github.com/bitcoin-core/secp256k1.git
+		$ cd secp256k1
+		$ ./autogen.sh
+		$ ./configure
+		$ make
+		$ sudo make install
+
 Install MMGen:
 
 		$ git clone https://github.com/mmgen/mmgen.git
 		$ cd mmgen; sudo ./setup.py install
 
-Install vanitygen (optional but recommended):
+Install vanitygen (optional):
 
 		$ sudo apt-get install libpcre3-dev
 		$ git clone https://github.com/samr7/vanitygen.git

+ 2 - 5
doc/wiki/install-mswin/Install-Bitcoind.md

@@ -18,10 +18,8 @@
 
 #### Download:
 
-> For the time being, Windows installers and Linux binary tarballs can be
-> obtained [here][00].  Once version 0.10 is released, get them from Bitcoin
-> Core's [main download page][01] instead.  Choose the 32-bit or 64-bit versions
-> appropriate for your respective computers.
+> Go to the Bitcoin Core [main download page][01].  Choose the 32-bit or 64-bit
+> versions appropriate for your respective computers.
 
 #### Install:
 
@@ -57,6 +55,5 @@
 > Note that in the absence of a blockchain the daemon starts very quickly and
 > uses practically no CPU once running.
 
-[00]: https://bitcoin.org/bin/0.10.0/test/
 [01]: https://bitcoin.org/en/download
 [bd]: https://bitcoin.org/bin/blockchain/

+ 6 - 0
doc/wiki/install-mswin/Install-MMGen-on-Microsoft-Windows.md

@@ -1,3 +1,8 @@
+***Warning: the MMGen installation process on Windows is not for the faint of
+heart, and the user experience is less than optimal.  You're urged to use the
+prebuilt [MMGenLive][00] USB image instead.  It's now the preferred way for all
+non-Linux users to run MMGen.***
+
 Install MMGen on Windows by completing the following three steps:
 
 > 1. [Install MinGW and MSYS][01], if you haven't already;
@@ -12,3 +17,4 @@ Congratulations, your MMGen installation is now complete!  Now move on to
 [02]: Install-MMGen-and-Its-Dependencies-on-Microsoft-Windows
 [07]: Install-Bitcoind
 [08]: Getting-Started-with-MMGen
+[00]: https://github.com/mmgen/MMGenLive

+ 200 - 244
doc/wiki/using-mmgen/Getting-Started-with-MMGen.md

@@ -10,39 +10,56 @@
 
 #### <a href=#10>Additional Features</a>
 * <a href=#11>Using the mnemonic and seed features</a>
-* <a href=#12>Mnemonics and seeds additional information</a>
+* <a href=#12>Mnemonics and seeds: additional information</a>
 * <a href=#13>Incognito wallets</a>
 	* <a href=#13a>Hidden incognito wallets</a>
 
-IMPORTANT NOTE: The following primer presupposes you have MMGen installed
-on two computers, one offline and one online.  However, if you have an online
-computer and a few Bitcoin addresses with small balances, it's perfectly
-possible to practice the operations decribed below on a single machine.
+The following primer presupposes you have MMGen installed on two computers, one
+offline and one online.  However, if you have an online computer and a few
+Bitcoin addresses with small balances, it’s perfectly possible to perform the
+operations described below on a single online machine.
 
-If you're just looking to get your feet wet, wallet generation, wallet format
-conversions, address and key generation, and address import may all be practiced
-on an online or offline computer with no blockchain and no Bitcoin balance.
+For those who just want to experiment with MMGen: all wallet generation, wallet
+format conversion, address and key generation, and address import operations can
+be performed on either an online or offline computer with an empty blockchain
+and no Bitcoin balance.
+
+Note that all the filenames, seed IDs, Bitcoin addresses and so forth used in
+this primer are fake.  Substitute real ones in their place as you go.  The up
+arrow (for repeating commands) and tab key (or Ctrl-I) (for completing commands
+and filenames) will speed up your work at the command line greatly.
 
 ### <a name=01>Basic Operations</a>
 
 #### <a name=02>Generate a wallet (offline computer):</a>
 
-On your offline computer, generate a wallet with a random seed:
+On your offline computer, generate a wallet:
 
 		$ mmgen-walletgen
 		...
 		MMGen wallet written 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.
+‘89ABCDEF’ is the Seed ID; ‘76543210’ is the Key ID. These are randomly
+generated, so your IDs will of course be different than these.
+
+The Seed ID never changes and is used to identify all keys/addresses generated
+by this wallet.  You should make a note of it.  The Key ID changes whenever the
+wallet’s password or hash preset are changed and is less important.
+
+‘256’ is the seed length; ‘3’ is the scrypt hash preset.  These values are
+configurable: type `mmgen-walletgen --help` for details.
 
-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.
+Before moving any funds into your MMGen wallet, you should back it up in several
+places and preferably on several media such as paper, flash memory or a CD-ROM.
+You’re advised to use a passphrase with your wallet.  Otherwise, anyone who
+gains physical access to one of your backups can easily steal your coins.  Don’t
+forget your passphrase.  If you do, the coins in your MMGen wallet are gone
+forever.
 
-"256" is the seed length; "3" is the scrypt hash preset.  These values are
-configurable: type 'mmgen-walletgen --help' for details.
+Since the wallet is a small, humanly readable ASCII file, it can easily be
+printed out on paper.  It can also be exported to more compact forms, the seed
+file and mnemonic (discussed below).  These formats are short enough to be
+written out by hand or memorized.
 
 #### <a name=03>Generate addresses (offline computer):</a>
 
@@ -66,265 +83,202 @@ Now generate ten addresses with your just-created wallet:
 		  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.
+Note that the address range ‘1-10’ specified on the command line is included in
+the resulting filename.  MMGen addresses consist of the Seed ID followed by ‘:’
+and an index.  In this example, ‘89ABCDEF:1’ represents the Bitcoin address
+‘16bNmy...’, ‘89ABCDEF:2’ represents ‘1AmkUx...’ and so forth.
+
+To begin moving your Bitcoin holdings into your MMGen wallet, just spend into
+any of these addresses.  If you run out of addresses, generate more.  To
+generate a hundred addresses, for example, you’d specify an address range of ‘1-100’.
 
-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".
+Let’s say you’ve decided to spend some BTC into the first four addresses above.
+Before doing so, you must import these addresses into the tracking wallet on
+your online machine so their balances will be visible.  For convenience
+of reference, provide the addresses with labels.  We’ll use the labels
+‘Donations’, ‘Storage 1’, ‘Storage 2’ and ‘Storage 3’.
 
-Make a copy of the file:
+Make a copy of the address file
 
 		$ cp '89ABCDEF[1-10].addrs' my.addrs
 
-and edit the copy using your favorite text editor to look like this:
+and edit it using the text editor of your choice,
+
+		$ nano my.addrs
+
+adding labels to the addresses you’ve chosen to spend to:
 
-		$ cat my.addrs
 		# My first MMGen addresses
 		89ABCDEF {
 		  1    16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE  Donations
 		  2    1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc  Storage 1
 		  3    1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N  Storage 2
 		  4    14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s  Storage 3
+		  5    1PeI55vtp2bX2uKDkAAR2c6ekHNYe4Hcq7
+		  6    1FEqfEsSILwXPfMvVvVuUovzTaaST62Mnf
+		  7    1LTTzuhMqPLwQ4IGCwwugny6ZMtUQJSJ1
+		  8    1F9495H8EJLb54wirgZkVgI47SP7M2RQWv
+		  9    1JbrCyt7BdxRE9GX1N7GiEct8UnIjPmpYd
+		  10   1H7vVTk4ejUbQXw45I6g5qvPBSe9bsjDqh
 		}
 
-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.
+Any line beginning with ‘#’ is a comment.  Comments may be placed at the ends
+of lines as well.
 
-Copy this file onto a USB stick and transfer it to your online computer.
+Save the file, copy it onto a USB stick and transfer it to your online computer.
 
 #### <a name=04>Import addresses (online computer):</a>
 
 On your online computer, go to your bitcoind data directory and move any
-existing 'wallet.dat' file out of harm's way.  Start bitcoind and let it
-generate a new 'wallet.dat', which you'll use as your **tracking wallet**.
-Import your four addresses into the new tracking wallet with the command:
+existing 'wallet.dat' file out of harm’s way.  Start bitcoind and let it
+generate a new 'wallet.dat', which you’ll use as your tracking wallet.
+Import your ten addresses into the new tracking wallet with the command:
+
+		$ mmgen-addrimport --batch my.addrs
+
+These addresses will now be tracked: any BTC transferred to them will show up in
+your listing of address balances.  Balances can be viewed using `mmgen-tool
+listaddresses` (the `showempty` option requests the inclusion of addresses with
+empty balances, and `showbtcaddrs` causes Bitcoin addresses to be displayed
+also).
+
+		$ mmgen-tool listaddresses showempty=1 showbtcaddrs=1
+		MMGenID     ADDRESS                             COMMENT    BALANCE
+		89ABCDEF:1  16bNmyYISiptuvJG3X7MPwiiS4HYvD7ksE  Donations    0
+		89ABCDEF:2  1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc  Storage 1    0
+		89ABCDEF:3  1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N  Storage 2    0
+		89ABCDEF:4  14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s  Storage 3    0
+		89ABCDEF:5  1PeI55vtp2bX2uKDkAAR2c6ekHNYe4Hcq7               0
+		...
+		TOTAL: 0 BTC
 
-		$ mmgen-addrimport my.addrs
+Note that it’s also possible to [track ordinary Bitcoin addresses with your
+tracking wallet][1].  This is not recommended, however, as you must save their
+corresponding keys in a key list in order to spend them.  Avoiding the use of
+keys is precisely the reason MMGen was created!
 
-These addresses will now be tracked by bitcoind.  Any BTC transferred to them
-will show up in your listing of address balances.  Balances can be viewed with
-the 'mmgen-tool' utility:
+Now that your addresses are being tracked, you may go ahead and send some BTC to
+them.  If you send 0.1, 0.2, 0.3 and 0.4 BTC respectively, for example, your
+address listing will look something like this after the transactions have been
+confirmed:
 
 		$ mmgen-tool listaddresses
-		No addresses with balances!
-
-The 'showempty' option shows all tracked addresses, even ones with no balances,
-so the four imported addresses should now show up on the listing:
-
-		$ mmgen-tool listaddresses showempty=1
-		ADDRESS        COMMENT                            BALANCE
-		89ABCDEF:1     Donations                          0
-		89ABCDEF:2     Storage 1                          0
-		89ABCDEF:3     Storage 2                          0
-		89ABCDEF:4     Storage 3                          0
-
-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 --rescan -l my_existing_addrs_with_balances
-
-NOTE: The '--rescan' option forces a rescan of the entire block chain, which is
-required for all addresses with existing balances.  Since the rescanning process
-is very slow, you'll save yourself a great deal of time by always importing
-new addresses BEFORE spending into them.
-
-Continue in this fashion until you've imported all addresses with balances into
-your tracking wallet.
+		MMGenID     COMMENT    BALANCE
+		89ABCDEF:1  Donations    0.1
+		89ABCDEF:2  Storage 1    0.2
+		89ABCDEF:3  Storage 2    0.3
+		89ABCDEF:4  Storage 3    0.4
+		TOTAL: 1 BTC
 
 #### <a name=05>Create a transaction (online computer):</a>
 
-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.  Note that 'mmgen-tool
-listaddresses' shows only MMGen address balances; to view **all** balances,
-including your non-MMGen ones, use the 'mmgen-txcreate' command:
-
-		$ mmgen-txcreate -i
-
-A list of all 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 optionally be viewed in a pager or printed to file.  For a wallet
-with ten unspent outputs, the display might 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 that you have some BTC under MMGen’s control, you’re ready to create a
+transaction.  Note that transactions are harmless until they’re signed and
+broadcast to the network, so feel free to experiment and create transactions
+with different combinations of inputs and outputs.
 
-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.
+To send 0.1 BTC to the a third-party address 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc,
+for example, and send the change back to yourself at address 89ABCDEF:5, you’d
+issue the following command:
 
-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.  You're advised to use a passphrase on your wallet.  Otherwise, anyone
-who gains physical access to one of your backups can easily steal your coins.
+		$ mmgen-txcreate 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc,0.1 89ABCDEF:5
 
-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 your
-address with the largest balance, 10 BTC, address 1F93Znz..., into three roughly
-equal parts and send them to the addresses labeled "Storage 1", "Storage 2" and
-"Storage 3" (89ABCDEF:2, 89ABCDEF:3 and 89ABCDEF:4).
+Note that 'mmgen-txcreate' accepts either MMGen IDs or Bitcoin addresses as
+arguments.
 
-To refresh your memory, here are the three destination addresses in question:
+To send 0.1 BTC to each of your addresses 89ABCDEF:6 and 89ABCDEF:7 and return the
+change to 89ABCDEF:8, you’d do this:
 
-		$ cat my.addrs | grep -v Donations
-		# My first MMGen addresses
-		89ABCDEF {
-		  2    1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc  Storage 1
-		  3    1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N  Storage 2
-		  4    14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s  Storage 3
-		}
+		$ mmgen-txcreate 89ABCDEF:6,0.1 89ABCDEF:7,0.1 89ABCDEF:8
 
-The following command does just this, sending 6.6 BTC of the transaction's 10
-BTC input to the first two addresses and the remainder to the third address,
-for which no amount has been specified:
+As you can see, each send address is followed by a comma and the amount.  The
+address with no amount is the change address.  All addresses belonging to your
+seed in the above examples are already imported and tracked, so you’re OK.  If
+you wanted to send to 89ABCDEF:11 instead, you'd have to import it first.
 
-		$ mmgen-txcreate 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc,3.3 1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N,3.3 14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s
 
-The address with no amount is the **change address**; MMGen will calculate
-the amount sent to it automatically by subtracting the sum of the outputs
-plus transaction fee, if any, from the inputs.  In our example, 3.39995 BTC (10
-BTC - (3.3 + 3.3 BTC) - .00005 BTC default transaction fee) will go to this
-address.
+Let’s go with the first of our two examples above.
 
-Note that the above transaction can be expressed much more concisely by
-replacing the Bitcoin addresses with their MMGen equivalents:
+Upon invocation, the 'mmgen-txcreate' command shows you a list of your
+unspent outputs 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.  In our example, the display
+will look something like this:
 
-		$ mmgen-txcreate 89ABCDEF:2,3.3 89ABCDEF:3,3.3 89ABCDEF:4
+		UNSPENT OUTPUTS (sort order: Age)  Total BTC: 1
+		 Num  TX id  Vout    Address                               Amt(BTC) Age(d)
+		 1)   e9742b16... 5  1L3kxmi.. 89ABCDEF:1    Donations       0.1    1
+		 2)   fa84d709... 6  1N4dSGj.. 89ABCDEF:2    Storage 1       0.2    1
+		 3)   8dde8ef5... 6  1M1fVDc.. 89ABCDEF:3    Storage 1       0.3    1
+		 4)   c76874c7... 0  1E8MFoC.. 89ABCDEF:4    Storage 3       0.4    1
 
-For this to work, the addresses must be imported into your tracking wallet,
-which they should be in any case.
+		Sort options: [t]xid, [a]mount, a[d]dress, [A]ge, [r]everse, [M]mgen addr
+		Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
+		'q'=quit view, 'p'=print to file, 'v'=pager view, 'w'=wide view, 'l'=add label:
 
-After hitting ENTER you'll be presented with the same UNSPENT OUTPUTS display as
-with the '-i' option above.  In our example, note that the output with 10 BTC
-which you wish to spend, 1F93Znz..., is listed as number '1'.  Remember this.
-After quitting the menu with 'q' you'll see the following prompt:
+After quitting the menu with 'q', you’ll see the following prompt:
 
 		Enter a range or space-separated list of outputs to spend:
 
-Type your remembered '1' here and hit ENTER.  After several more prompts and
-confirmations, your transaction will be saved:
-
-		Transaction written to file 'FEDCBA[6.6].rawtx'
-
-Note that the transaction has a unique ID, and the non-change spend amount of
-6.6 BTC is included in the filename.
+Here you must choose outputs of sufficient value to cover the send amount of 0.1
+BTC, plus the transaction fee.  By the way, MMGen calculates fees automatically
+using bitcoind’s 'estimatefee' RPC call, which makes things very convenient.  If
+you want to increase the fee a bit for speedier confirmation, use the
+`--tx-fee-adj` option.  Type `mmgen-txcreate --help` for details.
 
-#### <a name=06>Create a keylist file (online computer):</a>
+Output #2 is worth 0.2 BTC, which is sufficient, so let’s choose it.  After
+several more prompts and confirmations, your transaction will be saved:
 
-To sign your transaction, you'll need the Bitcoin private key corresponding to
-its input address, '1F93Znz....'
+		Transaction written to file 'FEDCBA[0.1].rawtx'
 
-If the key in question is in a bitcoind wallet ('wallet.dat'), you'll want to
-extract the key (along with all the other keys in the wallet) to a keylist
-file.  This is done using the 'bitcoin-cli dumpwallet' command with bitcoind
-running.
+Note that the transaction filename consists of a unique ID plus the spend
+amount.
 
-		$ bitcoin-cli dumpwallet my_secret.keys
-
-This will write the keylist file 'my_secret.keys' (or whatever filename you've
-chosen) to your home directory (or maybe to your Bitcoin data directory, results
-may vary).  If you want it written to another location, provide an absolute
-path.
-
-Note that the keylist file lists your private keys in *unencrypted* form, even
-if your 'wallet.dat' was encrypted.  Therefore, it should be backed up to a safe
-location—to a USB stick, say, or to your offline computer.  After you've backed
-it up, securely delete all copies of it on your online computer.
-
-You'll use this keylist file to sign all transactions that spend from addresses
-in your bitcoind wallet.
-
-If the key/address pair in question came from another source, you may create
-your own file 'my_secret.keys' (or whatever) in a plain text editor and just
-list the key in this file.  In the case of multiple keys, just list them all,
-one key per line.  In our example, the file will have one line containing a
-single private key corresponding to the address '1F93Znz....'
+As you can see, MMGen gives you complete control over your transaction inputs
+and change addresses.  This feature will be appreciated by privacy-conscious users.
 
 #### <a name=06>Sign a transaction (offline computer):</a>
 
-Now transfer the the raw transaction file and just-created keylist file to your
-offline computer and run:
+Now transfer the the raw transaction file to your offline computer and sign it
+using your wallet:
 
-		$ mmgen-txsign -k my_secret.keys FEDCBA[6.6].rawtx
+		$ mmgen-txsign FEDCBA[0.1].rawtx 89ABCDEF-76543210[256,3].mmdat
 		...
-		Signed transaction written to file 'FEDCBA[6.6].sigtx'
-
-The signed transaction is written to a new file whose name differs from the raw
-transaction file only by its '.sig' extension.
+		Signed transaction written to file 'FEDCBA[0.1].sigtx'
 
-NOTE: once you've migrated your funds to MMGen, the keylist file will no longer be
-needed.  Instead, you'll sign transactions by listing an MMGen seed source
-(wallet, mnemonic or seed file) on the command line after the transaction, and
-the required keys will be generated on the fly, as in the following example:
-
-		$ mmgen-txsign ABCDE[1].rawtx my_mmgen_wallet.mmdat
-
-NOTE: transactions may contain a mixture of MMGen and non-MMGen inputs, as well
-as inputs with more than one MMGen Seed ID.  Just list a seed source for each
-MMGen input on the command line after the transaction, as in this example:
-
-		$ mmgen-txsign -k my_secret.keys my_tx.raw a.mmdat b.mmwords c.mmseed
+Note that the signed transaction file bears the extension '.sigtx'.
 
 #### <a name=07>Send a transaction (online computer):</a>
 
-Now you're ready for the final step: broadcasting the transaction to the
-network.  Copy the just-created signed transaction file to your online computer,
-start bitcoind and issue the command:
+Now you’re ready for the final step: broadcasting the transaction to the
+network.  Copy the signed transaction file to your online computer, start
+bitcoind if necessary, and issue the command:
 
-		$ mmgen-txsend FEDCBA[6.6].sigtx
+		$ mmgen-txsend FEDCBA[0.1].sigtx
 
-Like all MMGen commands, 'mmgen-txsend' is interactive, so you'll be prompted
+Like all MMGen commands, 'mmgen-txsend' is interactive, so you’ll be prompted
 before the transaction is actually sent.
 
-Once the transaction is broadcast to the network, you can view your three new
-MMGen addresses and their balances:
+Once the transaction is broadcast to the network and confirmed, your address
+listing should look something like this:
 
-		$ mmgen-tool listaddresses minconf=0
-		ADDRESS        COMMENT                            BALANCE
-		89ABCDEF:2     Storage 1                          3.3
-		89ABCDEF:3     Storage 2                          3.3
-		89ABCDEF:4     Storage 3                          3.39995
+		$ mmgen-tool listaddresses minconf=1
+		MMGenID     COMMENT    BALANCE
+		89ABCDEF:1  Donations    0.1
+		89ABCDEF:3  Storage 2    0.3
+		89ABCDEF:4  Storage 3    0.4
+		89ABCDEF:5  Storage 1    0.0999
+		TOTAL: 0.8999 BTC
 
-Your total MMGen balance will also now be visible:
+Since you’ve sent 0.1 BTC to a third party, your balance has declined by 0.1 BTC
+plus the tx fee of 0.0001 BTC.  To verify that your transaction’s received its
+second, third and so on confirmations, increase `minconf` accordingly.
 
-		$ mmgen-tool getbalance minconf=0
-		Wallet        Unconfirmed      <0 confirms      >=0 confirms
-		89ABCDEF:     0 BTC            0 BTC            9.99995 BTC
-		TOTAL:        0 BTC            0 BTC            9.99995 BTC
+Congratulations!  You’ve now mastered the basics of MMGen!
 
-To verify that your transaction's received its first, second, third, and so on,
-confirmation, increase the 'minconf' value to 1, 2, 3 and so forth.
-
-Congratulations!  You've performed your first MMGen transaction and placed your
-first funds under MMGen control.
+Some of MMGen’s more advanced features are discussed below.  Others are
+documented in the help screens of the individual MMGen commands: display these
+by invoking the desired command with the `-h` or `--help` switch.
 
 ### <a name=10>Additional Features</a>
 
@@ -342,17 +296,17 @@ Continuing our example above, generate a mnemonic from the wallet:
 		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 these seed lengths using the '-l'
+words.  You may generate a wallet with 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, it's advisable to stick to the default 256-bit seed length
-if you're not planning to use the mnemonic feature.
+foreseeable future, its advisable to stick to the default 256-bit seed length
+if youre not planning to use the mnemonic feature.
 
 NOTE: MMGen mnemonics are generated from the Electrum wordlist, but using
-ordinary base conversion instead of Electrum's more complicated algorithm.
+ordinary base conversion instead of Electrums more complicated algorithm.
 
-The mnemonic file may be used any place you'd use a MMGen wallet with the same
+The mnemonic file may be used any place youd use a MMGen wallet with the same
 Seed ID.  You can generate ten addresses with it just as you did with the
 wallet, for example:
 
@@ -385,7 +339,7 @@ And they can also be used to regenerate a wallet:
 		...
 		MMGen wallet written to file '89ABCDEF-23456701[256,3].mmdat'
 
-Here's a sample seed file for a 256-bit wallet:
+Heres a sample seed file for a 256-bit wallet:
 
 		$ cat 8B7392ED.mmseed
 		f4c84b C5ZT wWpT Jsoi wRVw 2dm9 Aftd WLb8 FggQ eC8h Szjd da9L
@@ -407,7 +361,7 @@ Or you can do the same thing with 'mmgen-tool':
 		$ mmgen-tool str2id6 'XnyC NfPH piuW dQ2d nM47 VU'
 		0fe02f
 
-#### <a name=12>Mnemonics and seeds — additional information:</a>
+#### <a name=12>Mnemonics and seeds: additional information</a>
 
 MMGen commands that take mnemonic and seed data may receive the data from a
 prompt instead of a file.  Just omit the file name and specify the input format:
@@ -416,16 +370,16 @@ prompt instead of a file.  Just omit the file name and specify the input format:
 		...
 		Enter mnemonic data: <type or paste your mnemonic here>
 
-With the '-S' option, MMGen commands may be requested to print wallet data to
+With the `-S` option, MMGen commands may be requested to print wallet data to
 screen instead of a file.  To safeguard against over-the-shoulder, Van Eck
-phreaking and other side-channel attacks, you'll be prompted before this
+phreaking and other side-channel attacks, youll be prompted before this
 sensitive data is actually displayed.  MMGen never prints unencrypted private
 data to screen by default.
 
 The output of any MMGen command may be written to a directory of your choice
-using the '-d' option.  For example, on a Linux system you can use
-'-d /dev/shm' to write keys and seeds to volatile memory instead of disk,
-ensuring that no trace of this sensitive data remains once your computer's been
+using the `-d` option.  For example, on a Linux system you can use
+`-d /dev/shm` to write keys and seeds to volatile memory instead of disk,
+ensuring that no trace of this sensitive data remains once your computers been
 powered down.
 
 #### <a name=13><a name=incog>Incognito wallets</a>
@@ -434,7 +388,7 @@ An incognito format wallet is indistinguishable from random data, allowing you
 to hide your wallet at an offset within a random-data-filled file or partition.
 Barring any inside knowledge, a potential attacker has no way of knowing where
 the wallet is hidden, or whether the file or partition contains anything of
-interest at all for that matter.
+interest at all, for that matter.
 
 An incognito wallet with a reasonably secure password could even be hidden on
 unencrypted cloud storage.  Hiding your wallet at some offset in a 1 GB file
@@ -443,7 +397,7 @@ again that any potential attacker even knows or suspects you have an MMGen
 wallet hidden there.
 
 If you plan to store your incognito wallet in an insecure location such as cloud
-storage, you're advised to use a strong scrypt (hash) preset and a strong
+storage, youre advised to use a strong scrypt (hash) preset and a strong
 password.  These can be changed using the 'mmgen-passchg' utility:
 
 		$ mmgen-passchg -p 5 89ABCDEF-01234567[256,3].mmdat
@@ -457,8 +411,8 @@ password.  These can be changed using the 'mmgen-passchg' utility:
 		MMGen wallet written to file '89ABCDEF-87654321[256,5].mmdat'
 
 The scrypt preset is the numeral in the wallet filename following the seed
-length.  As you can see, it's now changed to '5'.  Now export your new toughened
-wallet to incognito format, using the '-k' option to leave the passphrase
+length.  As you can see, its now changed to '5'.  Now export your new toughened
+wallet to incognito format, using the `-k` option to leave the passphrase
 unchanged:
 
 		$ mmgen-walletconv -k -o incog 89ABCDEF-87654321[256,5].mmdat
@@ -470,7 +424,7 @@ unchanged:
 		Incognito data written to file '89ABCDEF-87654321-ECA86420[256,5].mmincog'
 
 Incog wallets have a special identifier, the Incog ID, which can be used to
-locate the wallet data if you've forgotten where you hid it (see the example
+locate the wallet data if youve forgotten where you hid it (see the example
 below).  Naturally, an attacker could use this ID to find the data too, so it
 should be kept secret.
 
@@ -486,13 +440,13 @@ Incog wallets can also be output to hexadecimal format:
 		3706 c5ce 56e0 7590 e677 6c6e 750a d057
 		b43a 21f9 82c7 6bd1 fe96 bad9 2d54 c4c0
 
-Note that the Incog ID is different here: it's generated from an init vector,
+Note that the Incog ID is different here: its generated from an init vector,
 which is a different random number each time, making the incog data as a whole
 different as well.  This allows you to store your incog data in multiple
-public locations without having repeated "random" wallet data give you away.
+public locations without having repeated ‘random’ wallet data give you away.
 
-Indistinguishable from any random hex dump, this data is ideally suited for a
-paper wallet that could potentially fall into the wrong hands.
+This data is ideally suited for a paper wallet that could potentially fall into
+the wrong hands.
 
 Your incognito wallet (whether hex or binary) can be used just like any other
 MMGen wallet, mnemonic or seed file to generate addresses and sign transactions:
@@ -508,9 +462,9 @@ MMGen wallet, mnemonic or seed file to generate addresses and sign transactions:
 
 ##### <a name=13a><a name=incog>Hidden incognito wallets</a>
 
-With the '-o hincog' option, incognito wallet data can be created and hidden at
+With the `-o hincog` option, incognito wallet data can be created and hidden at
 a specified offset in a file or partition in a single convenient operation, with
-the random file being created automatically if required.  Here's how you'd
+the random file being created automatically if necessary.  Here’s how you’d
 create a 1GB file 'random.dat' and hide a wallet in it at offset 123456789:
 
 		$ mmgen-walletconv -k -o hincog -J random.dat,123456789 89ABCDEF-87654321[256,5].mmdat
@@ -522,22 +476,22 @@ create a 1GB file 'random.dat' and hide a wallet in it at offset 123456789:
 		...
 		Data written to file 'random.dat' at offset 123456789
 
-Your "random" file can now be uploaded to a cloud storage service, for example,
+Your ‘random’ file can now be uploaded to a cloud storage service, for example,
 or some other, preferably non-public, location on the Net (in a real-life
-situation you will choose a less obvious offset than '123456789' though, won't
+situation you will choose a less obvious offset than '123456789' though, wont
 you?).
 
-Now let's say at some point in the future you download this file to recover
-your wallet and realize you've forgotten the offset where the data is hidden.
-If you've saved your Incog ID, you're in luck:
+Now lets say at some point in the future you download this file to recover
+your wallet and realize youve forgotten the offset where the data is hidden.
+If you’ve saved your Incog ID, you’re in luck:
 
 		$ mmgen-tool find_incog_data random.dat ED1F2ACB
 		...
 		Incog data for ID ED1F2ACB found at offset 123456789
 
 The search process can be slow, so patience is required.  In addition, on
-large files 'false positives' are a distinct possibility, in which case you'll
-need to use the 'keep_searching=1' parameter to keep going until you find the
+large files ‘false positives’ are a distinct possibility, in which case you’ll
+need to use the `keep_searching=1` parameter to keep going until you find the
 real offset.
 
 Hidden incog wallets are nearly as convenient to use as ordinary ones.
@@ -550,3 +504,5 @@ Transaction signing uses the same syntax:
 		$ mmgen-txsign -H random.dat,123456789 ABCDEF[0.1].rawtx
 		...
 		Signed transaction written to file 'ABCDEF[0.1].sigtx'
+
+[1]: https://github.com/mmgen/mmgen/wiki/Tracking-and-spending-ordinary-Bitcoin-addresses

+ 35 - 0
extmod/secp256k1mod.c

@@ -0,0 +1,35 @@
+#include <Python.h>
+#include <secp256k1.h>
+
+static PyObject * priv2pub(PyObject *self, PyObject *args) {
+    const unsigned char * privkey;
+    const int klen;
+    const int compressed;
+    if (!PyArg_ParseTuple(args, "t#I", &privkey, &klen, &compressed))
+        return NULL;
+    if (klen != 32) return NULL;
+    secp256k1_pubkey pubkey;
+    size_t pubkeyclen = compressed == 1 ? 33: 65;
+    unsigned char pubkeyc[pubkeyclen];
+	static secp256k1_context *ctx = NULL;
+	if (ctx == NULL) {
+	/*	puts ("Initializing context"); */
+		ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+	}
+    if (secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) != 1) return NULL;
+    if (secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey,
+			compressed == 1 ? SECP256K1_EC_COMPRESSED: SECP256K1_EC_UNCOMPRESSED) != 1)
+				return NULL;
+    return Py_BuildValue("s#", pubkeyc,pubkeyclen);
+}
+
+static PyMethodDef secp256k1Methods[] = {
+    {"priv2pub", priv2pub, METH_VARARGS, "Generate pubkey from privkey using libsecp256k1"},
+    {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+PyMODINIT_FUNC initsecp256k1(void) {
+    PyObject *m;
+    m = Py_InitModule("secp256k1", secp256k1Methods);
+    if (m == NULL) return;
+}

+ 0 - 41
mmgen/__init__.py

@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-#
-# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C)2013-2016 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 = Multi-Mode GENerator, a Bitcoin cold storage/tracking solution for
-        the command line
-"""
-__all__ = [
-	'rpc',
-	'addr.py',
-	'bitcoin.py',
-	'config.py',
-	'license.py',
-	'mn_electrum.py',
-	'mnemonic.py',
-	'mn_tirosh.py',
-	'Opts.py',
-	'tx.py',
-	'util.py',
-	'walletgen.py'
-]
-
-__version__ = '.6.0'     # See also below and setup.py
-
-# New software should look at this instead of at __version__ above.
-version_info = (0, 6, 0)    # See also above and setup.py

+ 68 - 20
mmgen/addr.py

@@ -22,29 +22,87 @@ addr.py:  Address generation/display routines for the MMGen suite
 
 from hashlib import sha256, sha512
 from mmgen.common import *
-from mmgen.bitcoin import numtowif
+from mmgen.bitcoin import privnum2addr,hex2wif,wif2hex
 from mmgen.obj import *
 from mmgen.tx import *
 from mmgen.tw import *
 
 pnm = g.proj_name
 
-def test_for_keyconv(silent=False):
+def _test_for_keyconv(silent=False):
 	no_keyconv_errmsg = """
-Executable '{kconv}' unavailable. Falling back on (slow) internal ECDSA library.
-Please install '{kconv}' from the {vgen} package on your system for much
-faster address generation.
+Executable '{kconv}' unavailable.  Please install '{kconv}' from the {vgen}
+package on your system or specify the secp256k1 library.
 """.format(kconv=g.keyconv_exec, vgen='vanitygen')
-
 	from subprocess import check_output,STDOUT
 	try:
 		check_output([g.keyconv_exec, '-G'],stderr=STDOUT)
 	except:
-		if not silent: msg(no_keyconv_errmsg)
+		if not silent: msg(no_keyconv_errmsg.strip())
 		return False
+	return True
 
+def _test_for_secp256k1(silent=False):
+	no_secp256k1_errmsg = """
+secp256k1 library unavailable.  Will use '{kconv}', or failing that, the (slow)
+internal ECDSA library for address generation.
+""".format(kconv=g.keyconv_exec)
+	try:
+		from mmgen.secp256k1 import priv2pub
+		assert priv2pub(os.urandom(32),1)
+	except:
+		if not silent: msg(no_secp256k1_errmsg.strip())
+		return False
 	return True
 
+def _wif2addr_python(wif):
+	privhex = wif2hex(wif)
+	if not privhex: return False
+	return privnum2addr(int(privhex,16),wif[0] != '5')
+
+def _wif2addr_keyconv(wif):
+	if wif[0] == '5':
+		from subprocess import check_output
+		return check_output(['keyconv', wif]).split()[1]
+	else:
+		return _wif2addr_python(wif)
+
+def _wif2addr_secp256k1(wif):
+	return _privhex2addr_secp256k1(wif2hex(wif),wif[0] != '5')
+
+def _privhex2addr_python(privhex,compressed=False):
+	return privnum2addr(int(privhex,16),compressed)
+
+def _privhex2addr_keyconv(privhex,compressed=False):
+	if compressed:
+		return privnum2addr(int(privhex,16),compressed)
+	else:
+		from subprocess import check_output
+		return check_output(['keyconv', hex2wif(privhex,compressed=False)]).split()[1]
+
+def _privhex2addr_secp256k1(privhex,compressed=False):
+	from mmgen.secp256k1 import priv2pub
+	from mmgen.bitcoin import hexaddr2addr,pubhex2hexaddr
+	from binascii import hexlify,unhexlify
+	pubkey = priv2pub(unhexlify(privhex),int(compressed))
+	return hexaddr2addr(pubhex2hexaddr(hexlify(pubkey)))
+
+def _keygen_selector():
+	if opt.key_generator == 3 and _test_for_secp256k1():
+		return 2
+	elif opt.key_generator in (2,3) and _test_for_keyconv():
+		return 1
+	else:
+		msg('Using (slow) internal ECDSA library for address generation')
+		return 0
+
+def get_wif2addr_f():
+	return (_wif2addr_python,_wif2addr_keyconv,_wif2addr_secp256k1)[_keygen_selector()]
+
+def get_privhex2addr_f(selector=None):
+	sel = selector-1 if selector else _keygen_selector()
+	return (_privhex2addr_python,_privhex2addr_keyconv,_privhex2addr_secp256k1)[sel]
+
 class AddrListEntry(MMGenListItem):
 	attrs = 'idx','addr','label','wif','sec'
 	label = MMGenListItemAttr('label','MMGenAddrLabel')
@@ -166,13 +224,7 @@ Removed %s duplicate wif key%s from keylist (also in {pnm} key-address file
 		seed = seed.get_data()
 
 		if self.gen_addrs:
-			if opt.no_keyconv or test_for_keyconv() == False:
-				msg('Using (slow) internal ECDSA library for address generation')
-				from mmgen.bitcoin import privnum2addr
-				keyconv = False
-			else:
-				from subprocess import check_output
-				keyconv = 'keyconv'
+			privhex2addr_f = get_privhex2addr_f()
 
 		t_addrs,num,pos,out = len(addrnums),0,0,[]
 
@@ -190,16 +242,12 @@ Removed %s duplicate wif key%s from keylist (also in {pnm} key-address file
 
 			# Secret key is double sha256 of seed hash round /num/
 			sec = sha256(sha256(seed).digest()).hexdigest()
-			wif = numtowif(int(sec,16))
 
 			if self.gen_addrs:
-				if keyconv:
-					e.addr = check_output([keyconv, wif]).split()[1]
-				else:
-					e.addr = privnum2addr(int(sec,16))
+				e.addr = privhex2addr_f(sec,compressed=False)
 
 			if self.gen_keys:
-				e.wif = wif
+				e.wif = hex2wif(sec,compressed=False)
 				if opt.b16: e.sec = sec
 
 			out.append(e)

+ 9 - 17
mmgen/bitcoin.py

@@ -34,14 +34,13 @@ _b = 0x0000000000000000000000000000000000000000000000000000000000000007L
 _a = 0x0000000000000000000000000000000000000000000000000000000000000000L
 _Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L
 _Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L
-curve_secp256k1 = ecdsa.ellipticcurve.CurveFp( _p, _a, _b )
-generator_secp256k1 = ecdsa.ellipticcurve.Point( curve_secp256k1, _Gx, _Gy, _r )
-oid_secp256k1 = (1,3,132,0,10)
-secp256k1 = ecdsa.curves.Curve('secp256k1', curve_secp256k1, generator_secp256k1, oid_secp256k1)
+_curve_secp256k1 = ecdsa.ellipticcurve.CurveFp(_p,_a,_b)
+_generator_secp256k1 = ecdsa.ellipticcurve.Point(_curve_secp256k1,_Gx,_Gy,_r)
+_oid_secp256k1 = (1,3,132,0,10)
+_secp256k1 = ecdsa.curves.Curve('secp256k1',_curve_secp256k1,_generator_secp256k1,_oid_secp256k1)
 
 b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
 
-#
 # From en.bitcoin.it:
 #   The Base58 encoding used is home made, and has some differences.
 #   Especially, leading zeroes are kept as single zeroes when conversion
@@ -51,7 +50,6 @@ b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
 #
 # The 'zero address':
 # 1111111111111111111114oLvT2 (use step2 = ('0' * 40) to generate)
-#
 
 def pubhex2hexaddr(pubhex):
 	step1 = sha256(unhexlify(pubhex)).digest()
@@ -100,13 +98,6 @@ def _b58tonum(b58num):
 		if not i in b58a: return False
 	return sum([b58a.index(n) * (58**i) for i,n in enumerate(list(b58num[::-1]))])
 
-def numtowif(numpriv):
-	step1 = '80' + '{:064x}'.format(numpriv)
-	step2 = sha256(unhexlify(step1)).digest()
-	step3 = sha256(step2).hexdigest()
-	key = step1 + step3[:8]
-	return _numtob58(int(key,16))
-
 # The following are MMGen internal (non-Bitcoin) b58 functions
 
 # Drop-in replacements for b64encode() and b64decode():
@@ -153,9 +144,10 @@ def b58decode_pad(s):
 
 # Compressed address support:
 
-def wiftohex(wifpriv,compressed=False):
+def wif2hex(wif):
+	compressed = wif[0] != '5'
 	idx = (66,68)[bool(compressed)]
-	num = _b58tonum(wifpriv)
+	num = _b58tonum(wif)
 	if num == False: return False
 	key = '{:x}'.format(num)
 	if compressed and key[66:68] != '01': return False
@@ -163,7 +155,7 @@ def wiftohex(wifpriv,compressed=False):
 	round2 = sha256(round1).hexdigest()
 	return key[2:66] if (key[:2] == '80' and key[idx:] == round2[:8]) else False
 
-def hextowif(hexpriv,compressed=False):
+def hex2wif(hexpriv,compressed=False):
 	step1 = '80' + hexpriv + ('','01')[bool(compressed)]
 	step2 = sha256(unhexlify(step1)).digest()
 	step3 = sha256(step2).hexdigest()
@@ -171,7 +163,7 @@ def hextowif(hexpriv,compressed=False):
 	return _numtob58(int(key,16))
 
 def privnum2pubhex(numpriv,compressed=False):
-	pko = ecdsa.SigningKey.from_secret_exponent(numpriv,secp256k1)
+	pko = ecdsa.SigningKey.from_secret_exponent(numpriv,_secp256k1)
 	pubkey = hexlify(pko.get_verifying_key().to_string())
 	if compressed:
 		p = ('03','02')[pubkey[-1] in '02468ace']

+ 5 - 2
mmgen/globalvars.py

@@ -51,7 +51,7 @@ prog_name = os.path.basename(sys.argv[0])
 author    = 'Philemon'
 email     = '<mmgen-py@yandex.com>'
 Cdates    = '2013-2016'
-version   = '0.8.5'
+version   = '0.8.6rc1'
 
 required_opts = [
 	'quiet','verbose','debug','outdir','echo_passphrase','passwd_file',
@@ -68,7 +68,7 @@ incompatible_opts = (
 min_screen_width = 80
 
 # Global value sets user opt
-dfl_vars = 'seed_len','hash_preset','usr_randchars','debug','tx_confs','tx_fee_adj','tx_fee'
+dfl_vars = 'seed_len','hash_preset','usr_randchars','debug','tx_confs','tx_fee_adj','tx_fee','key_generator'
 
 keyconv_exec = 'keyconv'
 
@@ -87,6 +87,9 @@ salt_len       = 16
 aesctr_iv_len  = 16
 hincog_chk_len = 8
 
+key_generators = 'python-ecdsa','keyconv','secp256k1'
+key_generator = 3 # secp256k1 is default
+
 hash_presets = {
 #   Scrypt params:
 #   ID    N   p  r

+ 4 - 2
mmgen/main_addrgen.py

@@ -55,8 +55,8 @@ opts_data = {
 -H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
                       'f' at offset 'o' (comma-separated).
 -O, --old-incog-fmt   Specify old-format incognito input.
--K, --no-keyconv      Force use of internal libraries for address genera-
-                      tion, even if 'keyconv' is available.
+-K, --key-generator=m Use method 'm' for public key generation.
+                      Options: {kgs} (default: {kg})
 -l, --seed-len=    l  Specify wallet seed length of 'l' bits.  This option
                       is required only for brainwallet and incognito inputs
                       with non-standard (< {g.seed_len}-bit) seed lengths.
@@ -71,6 +71,8 @@ opts_data = {
 """.format(
 	seed_lens=', '.join([str(i) for i in g.seed_lens]),
 	pnm=g.proj_name,
+	kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
+	kg=g.key_generator,
 	what=gen_what,g=g
 ),
 	'notes': """

+ 0 - 1
mmgen/main_tool.py

@@ -45,7 +45,6 @@ Type '{} help <command> for help on a particular command
 
 cmd_args = opts.init(opts_data,
 	add_opts=[
-		'no_keyconv',
 		'hidden_incog_input_params',
 		'in_fmt'
 		])

+ 6 - 3
mmgen/main_txsign.py

@@ -50,8 +50,8 @@ opts_data = {
                       for password hashing (default: '{g.hash_preset}').
 -z, --show-hash-presets Show information on available hash presets.
 -k, --keys-from-file=f Provide additional keys for non-{pnm} addresses
--K, --no-keyconv      Force use of internal libraries for address gener-
-                      ation, even if 'keyconv' is available.
+-K, --key-generator=m Use method 'm' for public key generation.
+                      Options: {kgs} (default: {kg})
 -M, --mmgen-keys-from-file=f Provide keys for {pnm} addresses in a key-
                       address file (output of '{pnl}-keygen'). Permits
                       online signing without an {pnm} seed source.
@@ -64,7 +64,10 @@ opts_data = {
 -I, --info            Display information about the transaction and exit.
 -t, --terse-info      Like '--info', but produce more concise output.
 -v, --verbose         Produce more verbose output
-""".format(g=g,pnm=pnm,pnl=pnm.lower()),
+""".format(
+		g=g,pnm=pnm,pnl=pnm.lower(),
+		kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
+		kg=g.key_generator),
 	'notes': """
 
 Transactions with either {pnm} or non-{pnm} input addresses may be signed.

+ 3 - 0
mmgen/opts.py

@@ -294,6 +294,9 @@ def check_opts(usr_opts):       # Returns false if any check fails
 			if not opt_is_int(val,desc): return False
 			if not opt_compares(val,'>=',g.min_urandchars,desc): return False
 			if not opt_compares(val,'<=',g.max_urandchars,desc): return False
+		elif key == 'key_generator':
+			if not opt_compares(val,'<=',len(g.key_generators),desc): return False
+			if not opt_compares(val,'>',0,desc): return False
 		else:
 			if g.debug: Msg("check_opts(): No test for opt '%s'" % key)
 

+ 0 - 28
mmgen/share/__init__.py

@@ -1,28 +0,0 @@
-#!/usr/bin/env python
-#
-# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013-2016 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 = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-"""
-__all__ = [
-	'Opts.py',
-]
-
-__version__ = '0.7.7'     # See also below and setup.py
-
-# New software should look at this instead of at __version__ above.
-version_info = (0, 7, 7)    # See also above and setup.py

+ 6 - 6
mmgen/tool.py

@@ -288,20 +288,20 @@ def randhex(nbytes='32'):
 
 def randwif(compressed=False):
 	r_hex = ba.hexlify(get_random(32))
-	enc = bitcoin.hextowif(r_hex,compressed)
-	dec = bitcoin.wiftohex(enc,compressed)
+	enc = bitcoin.hex2wif(r_hex,compressed)
+	dec = bitcoin.wif2hex(enc)
 	print_convert_results(r_hex,enc,dec,'hex')
 
 def randpair(compressed=False):
 	r_hex = ba.hexlify(get_random(32))
-	wif = bitcoin.hextowif(r_hex,compressed)
+	wif = bitcoin.hex2wif(r_hex,compressed)
 	addr = bitcoin.privnum2addr(int(r_hex,16),compressed)
 	Vmsg('Key (hex):  %s' % r_hex)
 	Vmsg_r('Key (WIF):  '); Msg(wif)
 	Vmsg_r('Addr:       '); Msg(addr)
 
 def wif2addr(wif,compressed=False):
-	s_enc = bitcoin.wiftohex(wif,compressed)
+	s_enc = bitcoin.wif2hex(wif)
 	if s_enc == False:
 		die(1,'Invalid address')
 	addr = bitcoin.privnum2addr(int(s_enc,16),compressed)
@@ -515,10 +515,10 @@ def privhex2addr(privkeyhex,compressed=False):
 	Msg(bitcoin.privnum2addr(int(privkeyhex,16),compressed))
 
 def wif2hex(wif,compressed=False):
-	Msg(bitcoin.wiftohex(wif,compressed))
+	Msg(bitcoin.wif2hex(wif))
 
 def hex2wif(hexpriv,compressed=False):
-	Msg(bitcoin.hextowif(hexpriv,compressed))
+	Msg(bitcoin.hex2wif(hexpriv,compressed))
 
 def encrypt(infile,outfile='',hash_preset=''):
 	data = get_data_from_file(infile,'data for encryption',binary=True)

+ 2 - 23
mmgen/tx.py

@@ -38,29 +38,8 @@ def is_b58_str(s):
 
 def is_wif(s):
 	if s == '': return False
-	compressed = not s[0] == '5'
-	from mmgen.bitcoin import wiftohex
-	return wiftohex(s,compressed) is not False
-
-def _wiftoaddr(s):
-	if s == '': return False
-	compressed = not s[0] == '5'
-	from mmgen.bitcoin import wiftohex,privnum2addr
-	hex_key = wiftohex(s,compressed)
-	if not hex_key: return False
-	return privnum2addr(int(hex_key,16),compressed)
-
-def _wiftoaddr_keyconv(wif):
-	if wif[0] == '5':
-		from subprocess import check_output
-		return check_output(['keyconv', wif]).split()[1]
-	else:
-		return _wiftoaddr(wif)
-
-def get_wif2addr_f():
-	if opt.no_keyconv: return _wiftoaddr
-	from mmgen.addr import test_for_keyconv
-	return (_wiftoaddr,_wiftoaddr_keyconv)[bool(test_for_keyconv())]
+	from mmgen.bitcoin import wif2hex
+	return bool(wif2hex(s))
 
 class MMGenTxInputOldFmt(MMGenListItem):  # for converting old tx files only
 	tr = {'amount':'amt', 'address':'addr', 'confirmations':'confs','comment':'label'}

+ 30 - 4
setup.py

@@ -16,18 +16,44 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from distutils.core import setup
+from distutils.core import setup,Extension
+from distutils.command.build_ext import build_ext
+import os
+from shutil import copy2
+
+# install extension module in repository after building
+class my_build_ext(build_ext):
+	def build_extension(self,ext):
+		build_ext.build_extension(self,ext)
+		ext_src = self.get_ext_fullpath(ext.name)
+		ext_dest = self.get_ext_filename(ext.name)
+		try: os.unlink(ext_dest)
+		except: pass
+		os.chmod(ext_src,0755)
+		print 'copying %s to %s' % (ext_src,ext_dest)
+		copy2(ext_src,ext_dest)
+
+module1 = Extension(
+	name         = 'mmgen.secp256k1',
+	sources      = ['extmod/secp256k1mod.c'],
+	libraries    = ['secp256k1'],
+	library_dirs = ['/usr/local/lib'],
+	runtime_library_dirs = ['/usr/local/lib'],
+	include_dirs = ['/usr/local/include'],
+	)
 
 setup(
 		name         = 'mmgen',
-		description  = 'A complete Bitcoin cold-storage solution for the command line',
-		version      = '0.8.5',
+		description  = 'A complete Bitcoin offline/online wallet solution for the command line',
+		version      = '0.8.6rc1',
 		author       = 'Philemon',
 		author_email = 'mmgen-py@yandex.com',
 		url          = 'https://github.com/mmgen/mmgen',
 		license      = 'GNU GPL v3',
-		platforms    = 'Linux, MS Windows',
+		platforms    = 'Linux, MS Windows, Raspberry PI',
 		keywords     = 'Bitcoin, wallet, cold storage, offline storage, open-source, command-line, Python, Bitcoin Core, bitcoind, hd, deterministic, hierarchical, secure, anonymous',
+		cmdclass     = { 'build_ext': my_build_ext },
+		ext_modules = [module1],
 		py_modules = [
 			'mmgen.__init__',
 			'mmgen.addr',

+ 40 - 27
test/gentest.py

@@ -29,14 +29,14 @@ from binascii import hexlify
 
 # Import these _after_ local path's been added to sys.path
 from mmgen.common import *
-from mmgen.bitcoin import hextowif,privnum2addr
+from mmgen.bitcoin import hex2wif,privnum2addr
 
 start_mscolor()
 
 rounds = 100
 opts_data = {
-	'desc': "Test addresses generated by {} against output of 'keyconv'".format(g.proj_name),
-	'usage':'[options] [rounds]',
+	'desc': "Test address generation using various methods",
+	'usage':'[options] a:b [rounds]',
 	'options': """
 -h, --help         Print this help message
 -s, --system       Test scripts and modules installed on system rather than
@@ -44,51 +44,64 @@ opts_data = {
 -v, --verbose      Produce more verbose output
 """,
 	'notes': """
+{pnm} can generate addresses from secret keys using one of three methods,
+as specified by the user:
 
-'keyconv' is the address generation utility from the well-known vanitygen
-package.  If it's installed on your system, {pnm} will use it by default to
-generate Bitcoin addresses.  Otherwise, it falls back on its own internal
-routines, which use the Python ecdsa library.
+    1) with the native Python ecdsa library (very slow)
+    2) with the 'keyconv' utility from the 'vanitygen' package (the default)
+    3) using bitcoincore.org's secp256k1 library (very fast, experimental)
 
-rounds is {} by default.
-""".format(rounds,pnm=g.proj_name)
+This test suite compares the output of these different methods against each
+other over set of randomly generated secret keys ({snum} by default).
+
+EXAMPLE:
+  gentest.py 2:3 1000
+  (compare output of 'keyconv' with secp256k1 library, 1000 rounds)
+""".format(pnm=g.proj_name,snum=rounds)
 }
 cmd_args = opts.init(opts_data,add_opts=['exact_output'])
 
-if len(cmd_args) == 1:
+if not 1 <= len(cmd_args) <= 2: opts.usage()
+
+if len(cmd_args) == 2:
 	try:
-		rounds = int(cmd_args[0])
+		rounds = int(cmd_args[1])
 		assert rounds > 0
 	except:
 		die(1,"'rounds' must be a positive integer")
 
-elif len(cmd_args) > 1:
-	opts.usage(opts_data)
+try:
+	a,b = cmd_args[0].split(':')
+	a,b = int(a),int(b)
+	for i in a,b: assert 1 <= i <= len(g.key_generators)
+	assert a != b
+except:
+	die(1,"%s: incorrect 'a:b' specifier" % cmd_args[0])
 
 if opt.system: sys.path.pop(0)
 
-from mmgen.addr import test_for_keyconv
-if not test_for_keyconv(silent=True):
-	die(1,"To run this test, you must install 'keyconv' from the vanitygen package.")
-
-m = "Comparing {}'s internally generated addresses against output of 'keyconv'"
-msg(green(m.format(g.proj_name)))
-
-from subprocess import check_output
+m = "Comparing address generators '{}' and '{}'"
+msg(green(m.format(g.key_generators[a-1],g.key_generators[b-1])))
+from mmgen.addr import get_privhex2addr_f
+gen_a = get_privhex2addr_f(selector=a)
+gen_b = get_privhex2addr_f(selector=b)
+compressed = False
 for i in range(1,rounds+1):
 	msg_r('\rRound %s/%s ' % (i,rounds))
 	sec = hexlify(os.urandom(32))
-	wif = hextowif(sec)
-	a = privnum2addr(int(sec,16))
-	vmsg('\nkey:  %s\naddr: %s\n' % (wif,a))
-	b = check_output(['keyconv', wif]).split()[1]
-	if a != b:
+	wif = hex2wif(sec,compressed=compressed)
+	a_addr = gen_a(sec,compressed)
+	b_addr = gen_b(sec,compressed)
+	vmsg('\nkey:  %s\naddr: %s\n' % (wif,a_addr))
+	if a_addr != b_addr:
 		msg_r(red('\nERROR: Addresses do not match!'))
 		die(3,"""
   sec key: {}
   WIF key: {}
   {pnm}:   {}
   keyconv: {}
-""".format(sec,wif,a,b,pnm=g.proj_name).rstrip())
+""".format(sec,wif,a_addr,b_addr,pnm=g.proj_name).rstrip())
+	if a != 2 and b != 2:
+		compressed = not compressed
 
 msg(green(('\n','')[bool(opt.verbose)] + 'OK'))

+ 2 - 2
test/test.py

@@ -854,11 +854,11 @@ def create_fake_unspent_data(adata,unspent_data_file,tx_data,non_mmgen_input='')
 				out.append(create_fake_unspent_entry(btcaddr,sid,idx,lbl))
 
 	if non_mmgen_input:
-		from mmgen.bitcoin import privnum2addr,hextowif
+		from mmgen.bitcoin import privnum2addr,hex2wif
 		privnum = getrandnum(32)
 		btcaddr = privnum2addr(privnum,compressed=True)
 		of = os.path.join(cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn)
-		write_data_to_file(of, hextowif('{:064x}'.format(privnum),
+		write_data_to_file(of, hex2wif('{:064x}'.format(privnum),
 					compressed=True)+'\n','compressed bitcoin key',silent=True)
 
 		out.append(create_fake_unspent_entry(btcaddr,non_mmgen='Non-MMGen address'))