tool.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #!/usr/bin/env python
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. tool.py: Routines and data for the mmgen-tool utility
  20. """
  21. import sys
  22. import mmgen.bitcoin as bitcoin
  23. from mmgen.util import *
  24. commands = {
  25. # "keyconv_compare": ['wif [str]'],
  26. # "keyconv_compare_randloop": ['iterations [int]'],
  27. # "hextob58_pad": ['hexnum [str]],
  28. # "b58tohex_pad": ['b58num [str]'],
  29. # "hextob58_pad_randloop": ['iterations [int]'],
  30. # "test_wiftohex": ['wif [str]'],
  31. # "hextosha256": ['hexnum [str]'],
  32. # "hextowiftopubkey": ['hexnum [str]'],
  33. # "pubhextoaddr": ['hexnum [str]'],
  34. # "hextowif_comp": ['hexnum [str]'],
  35. # "wiftohex_comp": ['wif [str]'],
  36. # "privhextoaddr_comp": ['hexnum [str]'],
  37. # "wiftoaddr_comp": ['wif [str]'],
  38. "strtob58": ['<string> [str]'],
  39. "hextob58": ['<hex number> [str]'],
  40. "b58tohex": ['<b58 number> [str]'],
  41. "b58randenc": [],
  42. "randwif": ['compressed [bool=False]'],
  43. "randpair": ['compressed [bool=False]'],
  44. "wif2addr": ['<wif> [str]', 'compressed [bool=False]'],
  45. "hexdump": ['<infile> [str]', 'cols [int=8]', 'line_nums [bool=True]'],
  46. "unhexdump": ['<infile> [str]'],
  47. "mn_rand128": ['wordlist [str="electrum"]'],
  48. "mn_rand192": ['wordlist [str="electrum"]'],
  49. "mn_rand256": ['wordlist [str="electrum"]'],
  50. "mn_stats": ['wordlist [str="electrum"]'],
  51. "mn_printlist": ['wordlist [str="electrum"]']
  52. }
  53. command_help = """
  54. General operations:
  55. hexdump - encode binary data in formatted hexadecimal form
  56. unhexdump - decode formatted hexadecimal data
  57. Bitcoin operations:
  58. strtob58 - convert a string to base 58
  59. hextob58 - convert a hexadecimal number to base 58
  60. b58tohex - convert a base 58 number to hexadecimal
  61. b58randenc - generate a random 32-byte number and convert it to base 58
  62. randwif - generate a random private key in WIF format
  63. randpair - generate a random private key/address pair
  64. wif2addr - generate a Bitcoin address from a key in WIF format
  65. Mnemonic operations (choose "electrum" (default), "tirosh" or "all" wordlists):
  66. mn_rand128 - generate random 128-bit mnemonic
  67. mn_rand192 - generate random 192-bit mnemonic
  68. mn_rand256 - generate random 256-bit mnemonic
  69. mn_stats - show stats for mnemonic wordlist
  70. mn_printlist - print mnemonic wordlist
  71. IMPORTANT NOTE: Though MMGen mnemonics use the Electrum wordlist, they're
  72. computed using a different algorithm and are NOT Electrum-compatible!
  73. """
  74. def tool_usage(prog_name, command):
  75. print "USAGE: '%s %s%s'" % (prog_name, command,
  76. (" "+" ".join(commands[command]) if commands[command] else ""))
  77. def process_args(prog_name, command, uargs):
  78. cargs = commands[command]
  79. cargs_req = [[i.split(" [")[0],i.split(" [")[1][:-1]]
  80. for i in cargs if "=" not in i]
  81. cargs_nam = dict([[
  82. i.split(" [")[0],
  83. [i.split(" [")[1].split("=")[0], i.split(" [")[1].split("=")[1][:-1]]
  84. ] for i in cargs if "=" in i])
  85. uargs_req = [i for i in uargs if "=" not in i]
  86. uargs_nam = dict([i.split("=") for i in uargs if "=" in i])
  87. # print cargs_req; print cargs_nam; print uargs_req; print uargs_nam; sys.exit()
  88. n = len(cargs_req)
  89. if len(uargs_req) != n:
  90. print "ERROR: %s argument%s required" % (n, " is" if n==1 else "s are")
  91. tool_usage(prog_name, command)
  92. sys.exit(1)
  93. for a in uargs_nam.keys():
  94. if a not in cargs_nam.keys():
  95. print "'%s' invalid named argument" % a
  96. sys.exit(1)
  97. def test_type(arg_type,arg,name=""):
  98. try:
  99. t = type(eval(arg))
  100. assert(t == eval(arg_type))
  101. except:
  102. print "'%s': Invalid argument for argument %s ('%s' required)" % \
  103. (arg, name, arg_type)
  104. sys.exit(1)
  105. return True
  106. ret = []
  107. for i in range(len(cargs_req)):
  108. arg,arg_type = uargs_req[i], cargs_req[i][1]
  109. if arg == "true" or arg == "false": arg = arg.capitalize()
  110. if arg_type == "str":
  111. ret.append('"%s"' % (arg))
  112. elif test_type(arg_type, arg, "#"+str(i+1)):
  113. ret.append('%s' % (arg))
  114. for k in uargs_nam.keys():
  115. arg,arg_type = uargs_nam[k], cargs_nam[k][0]
  116. if arg == "true" or arg == "false": arg = arg.capitalize()
  117. if arg_type == "str":
  118. ret.append('%s="%s"' % (k, arg))
  119. elif test_type(arg_type, arg, "'"+k+"'"):
  120. ret.append('%s=%s' % (k, arg))
  121. return ret
  122. # Individual commands
  123. def print_convert_results(indata,enc,dec,no_recode=False):
  124. vmsg("Input: [%s]" % indata)
  125. vmsg_r("Encoded data: ["); msg_r(enc); vmsg_r("]"); msg("")
  126. if not no_recode:
  127. vmsg("Recoded data: [%s]" % dec)
  128. if indata != dec:
  129. msg("WARNING! Recoded number doesn't match input stringwise!")
  130. def hexdump(infile, cols=8, line_nums=True):
  131. data = get_data_from_file(infile)
  132. o = pretty_hexdump(data, 2, cols, line_nums)
  133. print o
  134. def unhexdump(infile):
  135. data = get_data_from_file(infile)
  136. o = decode_pretty_hexdump(data)
  137. sys.stdout.write(o)
  138. def strtob58(s):
  139. enc = bitcoin.b58encode(s)
  140. dec = bitcoin.b58decode(enc)
  141. print_convert_results(s,enc,dec)
  142. def hextob58(s,f_enc=bitcoin.b58encode, f_dec=bitcoin.b58decode):
  143. enc = f_enc(unhexlify(s))
  144. dec = hexlify(f_dec(enc))
  145. print_convert_results(s,enc,dec)
  146. def b58tohex(s,f_enc=bitcoin.b58decode, f_dec=bitcoin.b58encode):
  147. tmp = f_enc(s)
  148. if tmp == False: sys.exit(1)
  149. enc = hexlify(tmp)
  150. dec = f_dec(unhexlify(enc))
  151. print_convert_results(s,enc,dec)
  152. def get_random(length):
  153. from Crypto import Random
  154. return Random.new().read(length)
  155. def b58randenc():
  156. r = get_random(32)
  157. enc = bitcoin.b58encode(r)
  158. dec = bitcoin.b58decode(enc)
  159. print_convert_results(hexlify(r),enc,hexlify(dec))
  160. def randwif(compressed=False):
  161. r_hex = hexlify(get_random(32))
  162. enc = bitcoin.hextowif(r_hex,compressed)
  163. print_convert_results(r_hex,enc,"",no_recode=True)
  164. def randpair(compressed=False):
  165. r_hex = hexlify(get_random(32))
  166. wif = bitcoin.hextowif(r_hex,compressed)
  167. addr = bitcoin.privnum2addr(int(r_hex,16),compressed)
  168. vmsg("Key (hex): %s" % r_hex)
  169. vmsg_r("Key (WIF): "); msg(wif)
  170. vmsg_r("Addr: "); msg(addr)
  171. def wif2addr(s_in,compressed=False):
  172. s_enc = bitcoin.wiftohex(s_in,compressed)
  173. if s_enc == False:
  174. msg("Invalid address")
  175. sys.exit(1)
  176. addr = bitcoin.privnum2addr(int(s_enc,16),compressed)
  177. vmsg_r("Addr: "); msg(addr)
  178. from mmgen.mnemonic import *
  179. from mmgen.mn_electrum import electrum_words as el
  180. from mmgen.mn_tirosh import tirosh_words as tl
  181. wordlists = sorted(wl_checksums.keys())
  182. def get_wordlist(wordlist):
  183. wordlist = wordlist.lower()
  184. if wordlist not in wordlists:
  185. msg('"%s": invalid wordlist. Valid choices: %s' %
  186. (wordlist,'"'+'" "'.join(wordlists)+'"'))
  187. sys.exit(1)
  188. return el if wordlist == "electrum" else tl
  189. def do_random_mn(nbytes,wordlist):
  190. r = get_random(nbytes)
  191. wlists = wordlists if wordlist == "all" else [wordlist]
  192. for wl in wlists:
  193. l = get_wordlist(wl)
  194. if wl == wlists[0]: vmsg("Seed: %s" % hexlify(r))
  195. mn = get_mnemonic_from_seed(r,l.strip().split("\n"),
  196. wordlist,print_info=False)
  197. vmsg("%s wordlist mnemonic:" % (wl.capitalize()))
  198. print " ".join(mn)
  199. def mn_rand128(wordlist="electrum"): do_random_mn(16,wordlist)
  200. def mn_rand192(wordlist="electrum"): do_random_mn(24,wordlist)
  201. def mn_rand256(wordlist="electrum"): do_random_mn(32,wordlist)
  202. def mn_stats(wordlist="electrum"):
  203. l = get_wordlist(wordlist)
  204. check_wordlist(l,wordlist)
  205. def mn_printlist(wordlist="electrum"):
  206. l = get_wordlist(wordlist)
  207. print "%s" % l.strip()