mnemonic.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #!/usr/bin/env python
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2014 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. mnemonic.py: Mnemomic routines for the MMGen suite
  20. """
  21. wl_checksums = {
  22. "electrum": '5ca31424',
  23. "tirosh": '1a5faeff'
  24. }
  25. # These are the only base-1626 specific configs:
  26. mn_base = 1626
  27. def mn_fill(mn): return len(mn) * 8 / 3
  28. def mn_len(hexnum): return len(hexnum) * 3 / 8
  29. import sys
  30. from mmgen.util import msg,make_chksum_8
  31. import mmgen.config as g
  32. # These universal base-conversion routines work for any base
  33. def baseNtohex(base,words,wordlist,fill=0):
  34. deconv = \
  35. [wordlist.index(words[::-1][i])*(base**i) for i in range(len(words))]
  36. return hex(sum(deconv))[2:].rstrip('L').zfill(fill)
  37. def hextobaseN(base,hexnum,wordlist,mn_len):
  38. num = int(hexnum,16)
  39. return [wordlist[num / (base**i) % base] for i in range(mn_len)][::-1]
  40. def get_seed_from_mnemonic(mn,wl):
  41. if len(mn) not in g.mnemonic_lens:
  42. msg("Bad mnemonic (%i words). Allowed numbers of words: %s" %
  43. (len(mn),", ".join([str(i) for i in g.mnemonic_lens])))
  44. return False
  45. for n,w in enumerate(mn,1):
  46. if w not in wl:
  47. msg("Bad mnemonic: word number %s is not in the wordlist" % n)
  48. return False
  49. from binascii import unhexlify
  50. seed = unhexlify(baseNtohex(mn_base,mn,wl,mn_fill(mn)))
  51. msg("Valid mnemomic for seed ID %s" % make_chksum_8(seed))
  52. return seed
  53. def get_mnemonic_from_seed(seed, wl, label, print_info=False):
  54. from binascii import hexlify
  55. if print_info:
  56. msg("Wordlist: %s" % label.capitalize())
  57. msg("Seed length: %s bits" % (len(seed) * 8))
  58. msg("Seed: %s" % hexlify(seed))
  59. hseed = hexlify(seed)
  60. mn = hextobaseN(mn_base,hseed,wl,mn_len(hseed))
  61. if print_info:
  62. msg("mnemonic (%s words):\n%s" % (len(mn), " ".join(mn)))
  63. if int(baseNtohex(mn_base,mn,wl,mn_fill(mn)),16) != int(hexlify(seed),16):
  64. msg("ERROR: seed recomputed from wordlist not the same as original seed!")
  65. msg("Recomputed seed %s" % baseNtohex(mn_base,mn,wl,mn_fill(mn)))
  66. sys.exit(3)
  67. return mn
  68. def check_wordlist(wl_str,label):
  69. wl = wl_str.strip().split("\n")
  70. print "Wordlist: %s" % label.capitalize()
  71. from hashlib import sha256
  72. print "Length: %i words" % len(wl)
  73. new_chksum = sha256(" ".join(wl)).hexdigest()[:8]
  74. if new_chksum != wl_checksums[label]:
  75. print "ERROR: Checksum mismatch. Computed: %s, Saved: %s" % \
  76. (new_chksum,wl_checksums[label])
  77. sys.exit(3)
  78. print "Checksum: %s (matches)" % new_chksum
  79. if (sorted(wl) == wl):
  80. print "List is sorted"
  81. else:
  82. print "ERROR: List is not sorted!"
  83. sys.exit(3)