123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- #!/usr/bin/env python
- #
- # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
- # Copyright (C) 2013 by 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/>.
- """
- addr.py: Address generation/display routines for mmgen suite
- """
- import sys
- from hashlib import sha256, sha512
- from binascii import hexlify, unhexlify
- from mmgen.bitcoin import numtowif
- from mmgen.config import *
- def test_for_keyconv():
- """
- Test for the presence of 'keyconv' utility on system
- """
- keyconv_exec = "keyconv"
- from subprocess import Popen, PIPE
- try:
- p = Popen([keyconv_exec, '-h'], stdout=PIPE, stderr=PIPE)
- except:
- sys.stderr.write("""
- Executable '%s' unavailable. Falling back on (slow) internal ECDSA library.
- Please install '%s' from the %s package on your system for much faster
- address generation.
- """ % (keyconv_exec, keyconv_exec, "vanitygen"))
- return False
- else:
- return True
- def generate_addrs(seed, addrnums, opts):
- """
- generate_addresses(start, end, seed, opts) => None
- Generate a Bitcoin address or addresses end based on a seed, optionally
- outputting secret keys
- The 'keyconv' utility will be used for address generation if installed.
- Otherwise an internal function is used
- Supported options:
- print_secret, no_addresses, no_keyconv, gen_what
- Addresses are returned in a list of dictionaries with the following keys:
- num, sec, wif, addr
- """
- if not 'no_addresses' in opts:
- if 'no_keyconv' in opts or test_for_keyconv() == False:
- sys.stderr.write("Using (slow) internal ECDSA library for address generation\n")
- from mmgen.bitcoin import privnum2addr
- keyconv = ""
- else:
- from subprocess import Popen, PIPE
- keyconv = "keyconv"
- a,t_addrs,i,out = sorted(addrnums),len(addrnums),0,[]
- while a:
- seed = sha512(seed).digest(); i += 1 # round /i/
- if i < a[0]: continue
- a.pop(0)
- sys.stderr.write("\rGenerating %s %s (%s of %s)" %
- (opts['gen_what'], i, t_addrs-len(a), t_addrs))
- # Secret key is double sha256 of seed hash round /i/
- sec = sha256(sha256(seed).digest()).hexdigest()
- wif = numtowif(int(sec,16))
- el = { 'num': i }
- if not 'print_addresses_only' in opts:
- el['sec'] = sec
- el['wif'] = wif
- if not 'no_addresses' in opts:
- if keyconv:
- p = Popen([keyconv, wif], stdout=PIPE)
- addr = dict([j.split() for j in \
- p.stdout.readlines()])['Address:']
- else:
- addr = privnum2addr(int(sec,16))
- el['addr'] = addr
- out.append(el)
- sys.stderr.write("\rGenerated %s %s%s\n"%(t_addrs,opts['gen_what']," "*15))
- return out
- def format_addr_data(addrlist, seed_chksum, opts):
- """
- print_addresses(addrs, opts) => None
- Print out the addresses and/or keys generated by generate_addresses()
- By default, prints addresses only
- Output can be customized with the following command line options:
- print_secret
- no_addresses
- b16
- """
- start = addrlist[0]['num']
- end = addrlist[-1]['num']
- wif_msg = ""
- if ('b16' in opts and 'print_secret' in opts) \
- or 'no_addresses' in opts:
- wif_msg = " (wif)"
- fa = "%s%%-%ss %%-%ss %%s" % (
- " "*2, len(str(end)) + (0 if 'no_addresses' in opts else 1),
- (5 if 'print_secret' in opts else 1) + len(wif_msg)
- )
- header = """
- # MMGen address file
- #
- # This file is editable.
- # Everything following a hash symbol '#' is ignored.
- # A label may be added to the right of each address, and it will be
- # appended to the bitcoind wallet label upon import (max. {} characters,
- # allowed characters: A-Za-z0-9, plus '{}').
- """.format(max_wallet_addr_label_len,
- "', '".join(wallet_addr_label_symbols)).strip()
- data = [header + "\n"]
- data.append("%s {" % seed_chksum.upper())
- for el in addrlist:
- col1 = el['num']
- if 'no_addresses' in opts:
- if 'b16' in opts:
- data.append(fa % (col1, " (hex):", el['sec']))
- col1 = ""
- data.append(fa % (col1, " (wif):", el['wif']))
- if 'b16' in opts: data.append("")
- elif 'print_secret' in opts:
- if 'b16' in opts:
- data.append(fa % (col1, "sec (hex):", el['sec']))
- col1 = ""
- data.append(fa % (col1, "sec"+wif_msg+":", el['wif']))
- data.append(fa % ("", "addr:", el['addr']))
- data.append("")
- else:
- data.append(fa % (col1, "", el['addr']))
- if not data[-1]: data.pop()
- data.append("}")
- return "\n".join(data) + "\n"
- def write_addr_data_to_file(seed, data, addr_list, opts):
- if 'print_addresses_only' in opts: ext = "addrs"
- elif 'no_addresses' in opts: ext = "keys"
- else: ext = "akeys"
- if 'b16' in opts: ext = ext.replace("keys","xkeys")
- beg = addr_list[0]
- end = addr_list[-1]
- sep = "-" if (end - beg == len(addr_list) - 1) else ".."
- from mmgen.utils import write_to_file, make_chksum_8, msg
- addr_range = beg if beg == end else "%s%s%s" % (beg,sep,end)
- outfile = "{}[{}].{}".format(make_chksum_8(seed),addr_range,ext)
- if 'outdir' in opts:
- outfile = "%s/%s" % (opts['outdir'], outfile)
- write_to_file(outfile,data)
- dtype = "Address" if 'print_addresses_only' in opts else "Key"
- msg("%s data saved to file '%s'" % (dtype,outfile))
|