[seed]: export seed to hexadecimal (mmhex) format
This commit is contained in:
parent
c7fcf448d9
commit
02256664fb
8 changed files with 122 additions and 33 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
...
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
1
test/ref/1378FC64.mmhex
Normal file
|
|
@ -0,0 +1 @@
|
|||
8a0088 456d 7f5f 1c4b fe3b c916 b875 60ae 6a3e 20da 3969 1cf5 3ded
|
||||
1
test/ref/98831F3A.mmhex
Normal file
1
test/ref/98831F3A.mmhex
Normal 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
1
test/ref/FE3C6545.mmhex
Normal file
|
|
@ -0,0 +1 @@
|
|||
afc3fe 456d 7f5f 1c4b fe3b c916 b875 60ae 6a3e
|
||||
38
test/test.py
38
test/test.py
|
|
@ -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',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue