New die roll (base6d) wallet format

- Permits the creation of wallets by repeated rolls of a die: 50 rolls for
  128-bit, 75 for 192-bit, and 100 for 256-bit seeds.  The base6d format
  uses the digits from one to six, so that user doesn't have to subtract
  one from each roll.

Testing:

  $ test/unit_tests.py baseconv
  $ test/test.py ref3 conv

Example:

  NOTE: when creating a real wallet, the following steps must be performed in a
  secure offline environment, and preferably with the use of a text editor and
  a file written in volatile memory (e.g. /dev/shm), rather than the `echo`
  command.  A more private and user-friendly data input method will be provided
  in a forthcoming patch.

  Sample 128-bit data obtained by rolling a die 50 times and entering each roll
  on the keyboard as a digit:

      15146 56446 53415 45431 55141 32115 41325 16311 32553 43533

  Here spaces have been added for greater readability.  Newlines are also
  permitted.

  Save the data in a file with the extension .b6d:

      $ echo 15146 56446 53415 45431 55141 32115 41325 16311 32553 43533 > myseed.b6d

  Convert to MMGen's default wallet format:

      $ mmgen-walletconv -o wallet myseed.b6d

  Convert the wallet back to base6d:

      $ mmgen-walletconv -o dieroll FE3C6545*.mmdat
      Base6d die roll seed data written to file 'FE3C6545[128].b6d'

      $ cat 'FE3C6545[128].b6d'
      15146 56446 53415 45431 55141
      32115 41325 16311 32553 43533
This commit is contained in:
The MMGen Project 2019-10-28 15:19:54 +00:00
commit c778636918
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
8 changed files with 66 additions and 0 deletions

View file

@ -1014,6 +1014,27 @@ class MMGenSeedFile(SeedSourceUnenc):
return True
class DieRollSeedFile(SeedSourceUnenc):
stdin_ok = True
fmt_codes = 'b6d','die','dieroll',
desc = 'base6d die roll seed data'
ext = 'b6d'
def _format(self):
d = baseconv.frombytes(self.seed.data,'b6d',pad='seed',tostr=True) + '\n'
self.fmt_data = block_format(d,gw=5,cols=5)
def _deformat(self):
d = self.fmt_data.translate(dict((ord(ws),None) for ws in '\t\n '))
seed_bytes = baseconv.tobytes(d,'b6d',pad='seed')
self.seed = Seed(seed_bytes)
self.ssdata.hexseed = seed_bytes.hex()
check_usr_seed_len(self.seed.bitlen)
return True
class PlainHexSeedFile(SeedSourceUnenc):
stdin_ok = True

View file

@ -287,6 +287,7 @@ class baseconv(object):
'b16': ('hexadecimal string', 'base16 (hexadecimal) string data'),
'b10': ('base10 string', 'base10 (decimal) string data'),
'b8': ('base8 string', 'base8 (octal) string data'),
'b6d': ('base6d (die roll)', 'base6 data using the digits from one to six'),
'mmgen': ('MMGen native mnemonic',
'MMGen native mnemonic seed phrase data created using old Electrum wordlist and simple base conversion'),
}
@ -296,6 +297,7 @@ class baseconv(object):
'b16': tuple('0123456789abcdef'),
'b10': tuple('0123456789'),
'b8': tuple('01234567'),
'b6d': tuple('123456'),
}
mn_base = 1626 # tirosh list is 1633 words long!
mn_ids = ('mmgen','tirosh')
@ -306,9 +308,11 @@ class baseconv(object):
}
seed_pad_lens = {
'b58': { 16:22, 24:33, 32:44 },
'b6d': { 16:50, 24:75, 32:100 },
}
seed_pad_lens_rev = {
'b58': { 22:16, 33:24, 44:32 },
'b6d': { 50:16, 75:24, 100:32 },
}
@classmethod

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

@ -0,0 +1 @@
135111311335561534526322511624324361264136623152556434641112356463412545532

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

@ -0,0 +1 @@
1253254513316235145146646115665463533224654453113624424263124136533542263452465156633216133232332365

2
test/ref/FE3C6545.b6d Normal file
View file

@ -0,0 +1,2 @@
15146 56446 53415 45431 55141
32115 41325 16311 32553 43533

View file

@ -48,6 +48,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
('ref_seed_chk', ([],'saved seed file')),
('ref_hex_chk', ([],'saved mmhex file')),
('ref_plainhex_chk',([],'saved hex file')),
('ref_dieroll_chk', ([],'saved dieroll (b6d) file')),
('ref_mn_chk', ([],'saved native MMGen mnemonic file')),
('ref_bip39_chk', ([],'saved BIP39 mnemonic file')),
('ref_hincog_chk', ([],'saved hidden incog reference wallet')),
@ -60,6 +61,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
('ref_walletconv_seed', ([],'wallet filename (seed)')),
('ref_walletconv_hexseed', ([],'wallet filename (hex seed)')),
('ref_walletconv_plainhexseed',([],'wallet filename (plain hex seed)')),
('ref_walletconv_dieroll', ([],'wallet filename (dieroll (b6d) seed)')),
('ref_walletconv_incog', ([],'wallet filename (incog)')),
('ref_walletconv_xincog', ([],'wallet filename (hex incog)')),
)
@ -94,6 +96,10 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
from mmgen.seed import PlainHexSeedFile
return self.ref_ss_chk(ss=PlainHexSeedFile)
def ref_dieroll_chk(self):
from mmgen.seed import DieRollSeedFile
return self.ref_ss_chk(ss=DieRollSeedFile)
def ref_mn_chk(self):
from mmgen.seed import MMGenMnemonic
return self.ref_ss_chk(ss=MMGenMnemonic)
@ -170,6 +176,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
def ref_walletconv_seed(self): return self.ref_walletconv(ofmt='mmseed')
def ref_walletconv_hexseed(self): return self.ref_walletconv(ofmt='mmhex')
def ref_walletconv_plainhexseed(self): return self.ref_walletconv(ofmt='hex')
def ref_walletconv_dieroll(self): return self.ref_walletconv(ofmt='dieroll')
def ref_walletconv_incog(self,ofmt='incog',ext='mmincog'):
args = ['-r0','-p1']

View file

@ -65,6 +65,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
('ref_seed_conv', 'conversion of saved seed file'),
('ref_hex_conv', 'conversion of saved MMGen hexadecimal seed file'),
('ref_plainhex_conv', 'conversion of saved plain hexadecimal seed file'),
('ref_dieroll_conv', 'conversion of saved dieroll (b6d) 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'),
@ -76,6 +77,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
('ref_bip39_conv_out', 'ref seed conversion to BIP39 mnemonic'),
('ref_hex_conv_out', 'ref seed conversion to MMGen hex seed'),
('ref_plainhex_conv_out','ref seed conversion to plain hex seed'),
('ref_dieroll_conv_out','ref seed conversion to dieroll (b6d) 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'),
@ -101,6 +103,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
def ref_seed_conv(self): return self.ref_mn_conv(ext='mmseed')
def ref_hex_conv(self): return self.ref_mn_conv(ext='mmhex')
def ref_plainhex_conv(self): return self.ref_mn_conv(ext='hex')
def ref_dieroll_conv(self): return self.ref_mn_conv(ext='b6d')
def ref_brain_conv(self):
uopts = ['-i','b','-p','1','-l',str(self.seed_len)]
@ -129,6 +132,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
def ref_seed_conv_out(self): return self.walletconv_out('seed')
def ref_hex_conv_out(self): return self.walletconv_out('hexseed')
def ref_plainhex_conv_out(self): return self.walletconv_out('hex')
def ref_dieroll_conv_out(self): return self.walletconv_out('dieroll')
def ref_incog_conv_out(self): return self.walletconv_out('i')
def ref_incox_conv_out(self): return self.walletconv_out('xi')

View file

@ -101,6 +101,32 @@ class unit_test(object):
(('ffffffff',None),'37777777777'),
(('ffffffff',20),'00000000037777777777'),
),
'b6d': (
(('00',None),'1'),
(('00',1),'1'),
(('00',2),'11'),
(('01',None),'2'),
(('01',1),'2'),
(('01',2),'12'),
(('0f',None),'34'),
(('0f',1),'34'),
(('0f',2),'34'),
(('010f',None),'2242'),
(('010f',20),'11111111111111112242'),
(('deadbeef',None),'2525524636426'),
(('deadbeef',20),'11111112525524636426'),
(('00000000',None),'1'),
(('00000000',20),'11111111111111111111'),
(('ffffffff',None),'2661215126614'),
(('ffffffff',20),'11111112661215126614'),
(('ff'*16,'seed'),'34164464641266661652465154654653354436664555521414'),
(('ff'*24,'seed'),'246111411433323364222465566552324652566121541623426135163525451613554313654'),
(('ff'*32,'seed'),'2132521653312613134145131423465414636252114131225324246311141642456513416322412146151432142242565134'),
(('00'*16,'seed'),'1'*50),
(('00'*24,'seed'),'1'*75),
(('00'*32,'seed'),'1'*100),
),
}
def run_test(self,name,ut):