Browse Source

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
The MMGen Project 5 years ago
parent
commit
c778636918

+ 21 - 0
mmgen/seed.py

@@ -1014,6 +1014,27 @@ class MMGenSeedFile(SeedSourceUnenc):
 
 
 		return True
 		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):
 class PlainHexSeedFile(SeedSourceUnenc):
 
 
 	stdin_ok = True
 	stdin_ok = True

+ 4 - 0
mmgen/util.py

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

+ 1 - 0
test/ref/1378FC64.b6d

@@ -0,0 +1 @@
+135111311335561534526322511624324361264136623152556434641112356463412545532

+ 1 - 0
test/ref/98831F3A.b6d

@@ -0,0 +1 @@
+1253254513316235145146646115665463533224654453113624424263124136533542263452465156633216133232332365

+ 2 - 0
test/ref/FE3C6545.b6d

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

+ 7 - 0
test/test_py_d/ts_ref_3seed.py

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

+ 4 - 0
test/test_py_d/ts_wallet.py

@@ -65,6 +65,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
 		('ref_seed_conv',      'conversion of saved seed file'),
 		('ref_seed_conv',      'conversion of saved seed file'),
 		('ref_hex_conv',       'conversion of saved MMGen hexadecimal seed file'),
 		('ref_hex_conv',       'conversion of saved MMGen hexadecimal seed file'),
 		('ref_plainhex_conv',  'conversion of saved plain 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_brain_conv',     'conversion of ref brainwallet'),
 		('ref_incog_conv',     'conversion of saved incog wallet'),
 		('ref_incog_conv',     'conversion of saved incog wallet'),
 		('ref_incox_conv',     'conversion of saved hex 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_bip39_conv_out',  'ref seed conversion to BIP39 mnemonic'),
 		('ref_hex_conv_out',    'ref seed conversion to MMGen hex seed'),
 		('ref_hex_conv_out',    'ref seed conversion to MMGen hex seed'),
 		('ref_plainhex_conv_out','ref seed conversion to plain 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_seed_conv_out',   'ref seed conversion to seed'),
 		('ref_incog_conv_out',  'ref seed conversion to incog data'),
 		('ref_incog_conv_out',  'ref seed conversion to incog data'),
 		('ref_incox_conv_out',  'ref seed conversion to hex 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_seed_conv(self):     return self.ref_mn_conv(ext='mmseed')
 	def ref_hex_conv(self):      return self.ref_mn_conv(ext='mmhex')
 	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_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):
 	def ref_brain_conv(self):
 		uopts = ['-i','b','-p','1','-l',str(self.seed_len)]
 		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_seed_conv_out(self):     return self.walletconv_out('seed')
 	def ref_hex_conv_out(self):      return self.walletconv_out('hexseed')
 	def ref_hex_conv_out(self):      return self.walletconv_out('hexseed')
 	def ref_plainhex_conv_out(self): return self.walletconv_out('hex')
 	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_incog_conv_out(self):    return self.walletconv_out('i')
 	def ref_incox_conv_out(self):    return self.walletconv_out('xi')
 	def ref_incox_conv_out(self):    return self.walletconv_out('xi')
 
 

+ 26 - 0
test/unit_tests_d/ut_baseconv.py

@@ -101,6 +101,32 @@ class unit_test(object):
 			(('ffffffff',None),'37777777777'),
 			(('ffffffff',None),'37777777777'),
 			(('ffffffff',20),'00000000037777777777'),
 			(('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):
 	def run_test(self,name,ut):