[seed]: export seed to hexadecimal (mmhex) format

This commit is contained in:
philemon 2016-12-15 20:53:29 +03:00
commit 02256664fb
Signed by untrusted user who does not match committer: mmgen
GPG key ID: 62DBE9E5212F05BE
8 changed files with 122 additions and 33 deletions

View file

@ -165,8 +165,8 @@ Get the [zip archive][10] of the latest stable version from GitHub, unpack and i
$ python setup.py build --compiler=mingw32
$ sudo ./setup.py install
If you wish, you may run the MMGen test suite to make sure your installation's
working:
After first installing and starting the [Bitcoin daemon][77], you may then run
the MMGen test suite to make sure your installation's working:
$ test/test.py -s
@ -184,3 +184,4 @@ working:
[31]: https://sourceforge.net/projects/mingw/files/MinGW/Extension/autoconf/autoconf2.5/autoconf2.5-2.68-1/autoconf2.5-2.68-1-mingw32-bin.tar.lzma
[32]: https://sourceforge.net/projects/mingw/files/MinGW/Extension/automake/automake1.11/automake1.11-1.11.1-1/automake1.11-1.11.1-1-mingw32-bin.tar.lzma
[33]: https://sourceforge.net/projects/mingw/files/MinGW/Extension/libtool/libtool-2.4-1/libtool-2.4-1-mingw32-bin.tar.lzma
[77]: Install-Bitcoind

View file

@ -9,8 +9,8 @@
* <a href='#a_st'>Send a transaction</a>
#### <a href='#a_af'>Additional Features</a>
* <a href='#a_ms'>Using the mnemonic and seed features</a>
* <a href='#a_ai'>Mnemonics and seeds: additional information</a>
* <a href='#a_ms'>Using the mnemonic, seed and hexseed formats</a>
* <a href='#a_ai'>Mnemonics, seeds and hexseeds: additional information</a>
* <a href='#a_ic'>Incognito wallets</a>
* <a href='#a_hi'>Hidden incognito wallets</a>
@ -308,7 +308,7 @@ by invoking the desired command with the `-h` or `--help` switch.
### <a name='a_af'>Additional Features</a>
#### <a name='a_ms'>Using the mnemonic and seed features:</a>
#### <a name='a_ms'>Using the mnemonic, seed and hexseed formats:</a>
Continuing our example above, generate a mnemonic from the default wallet:
@ -387,10 +387,25 @@ Or you can do the same thing with 'mmgen-tool':
$ mmgen-tool str2id6 'XnyC NfPH piuW dQ2d nM47 VU'
0fe02f
#### <a name='a_ai'>Mnemonics and seeds: additional information</a>
Beginning with version 0.9.0, export to and generation from hexadecimal
(hexseed) format is also supported. Hexseed files are identical to seed files
but encoded in hexadecimal rather than base 58. They bear the extension
'.mmhex':
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:
$ cat FE3C6545.mmhex
afc3fe 456d 7f5f 1c4b fe3b c916 b875 60ae 6a3e
You can easily check that a hexseed is correct by generating its Seed ID with
standard command-line tools:
$ echo 456d 7f5f 1c4b fe3b c916 b875 60ae 6a3e | tr -d ' ' | xxd -r -p | sha256sum -b | xxd -r -p | sha256sum -b | cut -c 1-8
fe3c6545
#### <a name='a_ai'>Mnemonics, seeds and hexseeds: additional information</a>
MMGen commands that take mnemonic, seed or hexseed data may receive the data
from a prompt instead of a file. Just omit the file name and specify the input
format:
$ mmgen-walletconv -i words
...

View file

@ -223,6 +223,9 @@ class SeedSourceUnenc(SeedSource):
def _decrypt_retry(self): pass
def _encrypt(self): pass
def _filename(self):
return '%s[%s].%s' % (self.seed.sid,self.seed.length,self.ext)
class SeedSourceEnc(SeedSource):
_msg = {
@ -470,9 +473,6 @@ class Mnemonic (SeedSourceUnenc):
return True
def _filename(self):
return '%s[%s].%s' % (self.seed.sid,self.seed.length,self.ext)
class SeedFile (SeedSourceUnenc):
stdin_ok = True
@ -509,8 +509,7 @@ class SeedFile (SeedSourceUnenc):
vmsg_r('Validating %s checksum...' % desc)
if not compare_chksums(
a,'checksum',make_chksum_6(b),'base 58 data'):
if not compare_chksums(a,'file',make_chksum_6(b),'computed',verbose=True):
return False
ret = b58decode_pad(b)
@ -527,8 +526,53 @@ class SeedFile (SeedSourceUnenc):
return True
def _filename(self):
return '%s[%s].%s' % (self.seed.sid,self.seed.length,self.ext)
class HexSeedFile (SeedSourceUnenc):
stdin_ok = True
fmt_codes = 'seedhex','hexseed','hex','mmhex'
desc = 'hexadecimal seed data'
ext = 'mmhex'
def _format(self):
h = self.seed.hexdata
self.ssdata.chksum = make_chksum_6(h)
self.ssdata.hexseed = h
self.fmt_data = '%s %s\n' % (self.ssdata.chksum, split_into_cols(4,h))
def _deformat(self):
desc = self.desc
d = self.fmt_data.split()
try:
d[1]
chk,hstr = d[0],''.join(d[1:])
except:
msg("'%s': invalid %s" % (self.fmt_data.strip(),desc))
return False
if not len(hstr)*4 in g.seed_lens:
msg('Invalid data length (%s) in %s' % (len(hstr),desc))
return False
if not is_chksum_6(chk):
msg("'%s': invalid checksum format in %s" % (chk, desc))
return False
if not is_hexstring(hstr):
msg("'%s': not a hexadecimal string, in %s" % (hstr, desc))
return False
vmsg_r('Validating %s checksum...' % desc)
if not compare_chksums(chk,'file',make_chksum_6(hstr),'computed',verbose=True):
return False
self.seed = Seed(unhexlify(hstr))
self.ssdata.chksum = chk
self.ssdata.hexseed = hstr
check_usr_seed_len(self.seed.length)
return True
class Wallet (SeedSourceEnc):
@ -614,7 +658,7 @@ class Wallet (SeedSourceEnc):
chk = make_chksum_6(' '.join(lines[1:]))
if not compare_chksums(lines[0],'master',chk,'computed',
hdr='For wallet master checksum'):
hdr='For wallet master checksum',verbose=True):
return False
return True
@ -658,7 +702,7 @@ class Wallet (SeedSourceEnc):
return False
if not compare_chksums(chk,key,
make_chksum_6(b58_val),'computed checksum'):
make_chksum_6(b58_val),'computed checksum',verbose=True):
return False
val = b58decode_pad(b58_val)

View file

@ -117,14 +117,14 @@ def qmsg_r(s,alt=False):
if opt.quiet:
if alt != False: sys.stderr.write(alt)
else: sys.stderr.write(s)
def vmsg(s):
if opt.verbose: sys.stderr.write(s + '\n')
def vmsg_r(s):
if opt.verbose: sys.stderr.write(s)
def Vmsg(s):
if opt.verbose: sys.stdout.write(s + '\n')
def Vmsg_r(s):
if opt.verbose: sys.stdout.write(s)
def vmsg(s,force=False):
if opt.verbose or force: sys.stderr.write(s + '\n')
def vmsg_r(s,force=False):
if opt.verbose or force: sys.stderr.write(s)
def Vmsg(s,force=False):
if opt.verbose or force: sys.stdout.write(s + '\n')
def Vmsg_r(s,force=False):
if opt.verbose or force: sys.stdout.write(s)
def dmsg(s):
if opt.debug: sys.stdout.write(s + '\n')
@ -295,7 +295,7 @@ def get_hash_params(hash_preset):
else: # Shouldn't be here
die(3,"%s: invalid 'hash_preset' value" % hash_preset)
def compare_chksums(chk1, desc1, chk2, desc2, hdr='', die_on_fail=False):
def compare_chksums(chk1,desc1,chk2,desc2,hdr='',die_on_fail=False,verbose=False):
if not chk1 == chk2:
m = "%s ERROR: %s checksum (%s) doesn't match %s checksum (%s)"\
@ -303,7 +303,7 @@ def compare_chksums(chk1, desc1, chk2, desc2, hdr='', die_on_fail=False):
if die_on_fail:
die(3,m)
else:
vmsg(m)
vmsg(m,force=verbose)
return False
vmsg('%s checksum OK (%s)' % (capfirst(desc1),chk1))

1
test/ref/1378FC64.mmhex Normal file
View file

@ -0,0 +1 @@
8a0088 456d 7f5f 1c4b fe3b c916 b875 60ae 6a3e 20da 3969 1cf5 3ded

1
test/ref/98831F3A.mmhex Normal file
View file

@ -0,0 +1 @@
091c8f 456d 7f5f 1c4b fe3b c916 b875 60ae 6a3e 20da 3969 1cf5 3ded 010e 90a5 6e04 8e62

1
test/ref/FE3C6545.mmhex Normal file
View file

@ -0,0 +1 @@
afc3fe 456d 7f5f 1c4b fe3b c916 b875 60ae 6a3e

View file

@ -203,6 +203,7 @@ cfgs = {
'sigtx': 'txsign',
'mmwords': 'export_mnemonic',
'mmseed': 'export_seed',
'mmhex': 'export_hex',
'mmincog': 'export_incog',
'mmincox': 'export_incog_hex',
hincog_fn: 'export_incog_hidden',
@ -407,12 +408,14 @@ cmd_group['main'] = OrderedDict([
# txdo must go after txsign
['txdo', (1,'online transaction', [[['sigtx','mmdat'],1]])],
['export_hex', (1,'seed export to hexadecimal format', [[['mmdat'],1]])],
['export_seed', (1,'seed export to mmseed format', [[['mmdat'],1]])],
['export_mnemonic', (1,'seed export to mmwords format', [[['mmdat'],1]])],
['export_incog', (1,'seed export to mmincog format', [[['mmdat'],1]])],
['export_incog_hex',(1,'seed export to mmincog hex format', [[['mmdat'],1]])],
['export_incog_hidden',(1,'seed export to hidden mmincog format', [[['mmdat'],1]])],
['addrgen_hex', (1,'address generation from mmhex file', [[['mmhex','addrs'],1]])],
['addrgen_seed', (1,'address generation from mmseed file', [[['mmseed','addrs'],1]])],
['addrgen_mnemonic',(1,'address generation from mmwords file',[[['mmwords','addrs'],1]])],
['addrgen_incog', (1,'address generation from mmincog file',[[['mmincog','addrs'],1]])],
@ -456,6 +459,7 @@ cmd_group['ref'] = (
# reading
('ref_wallet_chk', ([],'saved reference wallet')),
('ref_seed_chk', ([],'saved seed file')),
('ref_hex_chk', ([],'saved mmhex file')),
('ref_mn_chk', ([],'saved mnemonic file')),
('ref_hincog_chk', ([],'saved hidden incog reference wallet')),
('ref_brain_chk', ([],'saved brainwallet')),
@ -481,6 +485,7 @@ cmd_group['conv_in'] = ( # reading
('ref_wallet_conv', 'conversion of saved reference wallet'),
('ref_mn_conv', 'conversion of saved mnemonic'),
('ref_seed_conv', 'conversion of saved seed file'),
('ref_hex_conv', 'conversion of saved hexadecimal seed file'),
('ref_brain_conv', 'conversion of ref brainwallet'),
('ref_incog_conv', 'conversion of saved incog wallet'),
('ref_incox_conv', 'conversion of saved hex incog wallet'),
@ -491,6 +496,7 @@ cmd_group['conv_in'] = ( # reading
cmd_group['conv_out'] = ( # writing
('ref_wallet_conv_out', 'ref seed conversion to wallet'),
('ref_mn_conv_out', 'ref seed conversion to mnemonic'),
('ref_hex_conv_out', 'ref seed conversion to hex seed'),
('ref_seed_conv_out', 'ref seed conversion to seed'),
('ref_incog_conv_out', 'ref seed conversion to incog data'),
('ref_incox_conv_out', 'ref seed conversion to hex incog data'),
@ -1547,6 +1553,9 @@ class MMGenTestSuite(object):
end_silence()
ok()
def export_hex(self,name,wf,desc='hexadecimal seed data',out_fmt='hex',pf=None):
self.export_seed(name,wf,desc=desc,out_fmt=out_fmt,pf=pf)
def export_seed_dfl_wallet(self,name,pf,desc='seed data',out_fmt='seed'):
self.export_seed(name,wf=None,desc=desc,out_fmt=out_fmt,pf=pf)
@ -1582,6 +1591,9 @@ class MMGenTestSuite(object):
# t.no_overwrite()
ok()
def addrgen_hex(self,name,wf,foo,desc='hexadecimal seed data',in_fmt='hex'):
self.addrgen_seed(name,wf,foo,desc=desc,in_fmt=in_fmt)
def addrgen_mnemonic(self,name,wf,foo):
self.addrgen_seed(name,wf,foo,desc='mnemonic data',in_fmt='words')
@ -1795,6 +1807,9 @@ class MMGenTestSuite(object):
def ref_seed_conv(self,name):
self.ref_mn_conv(name,ext='mmseed',desc='Seed data')
def ref_hex_conv(self,name):
self.ref_mn_conv(name,ext='mmhex',desc='Hexadecimal seed data')
def ref_brain_conv(self,name):
uopts = ['-i','b','-p','1','-l',str(cfg['seed_len'])]
self.walletconv_in(name,None,'brainwallet',uopts,oo=True)
@ -1825,6 +1840,9 @@ class MMGenTestSuite(object):
def ref_seed_conv_out(self,name):
self.walletconv_out(name,'seed data','seed')
def ref_hex_conv_out(self,name):
self.walletconv_out(name,'hexadecimal seed data','hexseed')
def ref_incog_conv_out(self,name):
self.walletconv_out(name,'incognito data',out_fmt='i',pw=True)
@ -1851,16 +1869,21 @@ class MMGenTestSuite(object):
pf = None
self.walletchk(name,wf,pf=pf,pw=True,sid=cfg['seed_id'])
from mmgen.seed import SeedFile
def ref_seed_chk(self,name,ext=SeedFile.ext):
wf = os.path.join(ref_dir,'%s.%s' % (cfg['seed_id'],ext))
def ref_ss_chk(self,name,ss=None):
wf = os.path.join(ref_dir,'%s.%s' % (cfg['seed_id'],ss.ext))
self.walletchk(name,wf,pf=None,desc=ss.desc,sid=cfg['seed_id'])
def ref_seed_chk(self,name):
from mmgen.seed import SeedFile
desc = ('mnemonic data','seed data')[ext==SeedFile.ext]
self.walletchk(name,wf,pf=None,desc=desc,sid=cfg['seed_id'])
self.ref_ss_chk(name,ss=SeedFile)
def ref_hex_chk(self,name):
from mmgen.seed import HexSeedFile
self.ref_ss_chk(name,ss=HexSeedFile)
def ref_mn_chk(self,name):
from mmgen.seed import Mnemonic
self.ref_seed_chk(name,ext=Mnemonic.ext)
self.ref_ss_chk(name,ss=Mnemonic)
def ref_brain_chk(self,name,bw_file=ref_bw_file):
wf = os.path.join(ref_dir,bw_file)
@ -2060,6 +2083,7 @@ class MMGenTestSuite(object):
'ref_wallet_conv',
'ref_mn_conv',
'ref_seed_conv',
'ref_hex_conv',
'ref_brain_conv',
'ref_incog_conv',
'ref_incox_conv',
@ -2068,6 +2092,7 @@ class MMGenTestSuite(object):
'ref_wallet_conv_out',
'ref_mn_conv_out',
'ref_seed_conv_out',
'ref_hex_conv_out',
'ref_incog_conv_out',
'ref_incox_conv_out',
'ref_hincog_conv_out',
@ -2075,6 +2100,7 @@ class MMGenTestSuite(object):
'refwalletgen',
'refaddrgen',
'ref_seed_chk',
'ref_hex_chk',
'ref_mn_chk',
'ref_brain_chk',
'ref_hincog_chk',