addr generation with secp256k1mod
This commit is contained in:
parent
843ded9929
commit
5676d7a3f9
20 changed files with 430 additions and 431 deletions
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 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.
|
||||
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.
|
||||
‘256’ is the seed length; ‘3’ is the scrypt hash preset. These values are
|
||||
configurable: type `mmgen-walletgen --help` for details.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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".
|
||||
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’.
|
||||
|
||||
Make a copy of the file:
|
||||
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 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 my.addrs
|
||||
$ mmgen-addrimport --batch my.addrs
|
||||
|
||||
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:
|
||||
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
|
||||
|
||||
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!
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
$ mmgen-txcreate -i
|
||||
$ mmgen-txcreate 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc,0.1 89ABCDEF:5
|
||||
|
||||
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:
|
||||
Note that 'mmgen-txcreate' accepts either MMGen IDs or Bitcoin addresses as
|
||||
arguments.
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
$ mmgen-txcreate 89ABCDEF:6,0.1 89ABCDEF:7,0.1 89ABCDEF:8
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Let’s go with the first of our two examples above.
|
||||
|
||||
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:
|
||||
|
||||
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
|
||||
|
||||
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):
|
||||
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:
|
||||
|
||||
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. 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.
|
||||
|
||||
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).
|
||||
|
||||
To refresh your memory, here are the three destination addresses in question:
|
||||
|
||||
$ cat my.addrs | grep -v Donations
|
||||
# My first MMGen addresses
|
||||
89ABCDEF {
|
||||
2 1AmkUxrfy5dMrfmeYwTxLxfIswUCcpeysc Storage 1
|
||||
3 1HgYCsfqYzIg7LVVfDTp7gYJocJEiDAy6N Storage 2
|
||||
4 14Tu3z1tiexXDonNsFIkvzqutE5E3pTK8s Storage 3
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
$ 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.
|
||||
|
||||
Note that the above transaction can be expressed much more concisely by
|
||||
replacing the Bitcoin addresses with their MMGen equivalents:
|
||||
|
||||
$ mmgen-txcreate 89ABCDEF:2,3.3 89ABCDEF:3,3.3 89ABCDEF:4
|
||||
|
||||
For this to work, the addresses must be imported into your tracking wallet,
|
||||
which they should be in any case.
|
||||
|
||||
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:
|
||||
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.
|
||||
|
||||
Transaction written to file 'FEDCBA[6.6].rawtx'
|
||||
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:
|
||||
|
||||
Note that the transaction has a unique ID, and the non-change spend amount of
|
||||
6.6 BTC is included in the filename.
|
||||
Transaction written to file 'FEDCBA[0.1].rawtx'
|
||||
|
||||
#### <a name=06>Create a keylist file (online computer):</a>
|
||||
Note that the transaction filename consists of a unique ID plus the spend
|
||||
amount.
|
||||
|
||||
To sign your transaction, you'll need the Bitcoin private key corresponding to
|
||||
its input address, '1F93Znz....'
|
||||
|
||||
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.
|
||||
|
||||
$ 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'
|
||||
Signed transaction written to file 'FEDCBA[0.1].sigtx'
|
||||
|
||||
The signed transaction is written to a new file whose name differs from the raw
|
||||
transaction file only by its '.sig' extension.
|
||||
|
||||
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, it’s advisable to 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, but using
|
||||
ordinary base conversion instead of Electrum's more complicated algorithm.
|
||||
ordinary base conversion instead of Electrum’s 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 you’d 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:
|
||||
Here’s 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, you’ll 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 computer’s 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, you’re 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, it’s 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 you’ve 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: it’s 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, won’t
|
||||
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 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:
|
||||
|
||||
$ 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
extmod/secp256k1mod.c
Executable file
35
extmod/secp256k1mod.c
Executable file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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': """
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
])
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
25
mmgen/tx.py
25
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'}
|
||||
|
|
|
|||
34
setup.py
34
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',
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue