From c7786369188038cf698f92fe78fc427b1aa98f47 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Mon, 28 Oct 2019 15:19:54 +0000 Subject: [PATCH] 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 --- mmgen/seed.py | 21 +++++++++++++++++++++ mmgen/util.py | 4 ++++ test/ref/1378FC64.b6d | 1 + test/ref/98831F3A.b6d | 1 + test/ref/FE3C6545.b6d | 2 ++ test/test_py_d/ts_ref_3seed.py | 7 +++++++ test/test_py_d/ts_wallet.py | 4 ++++ test/unit_tests_d/ut_baseconv.py | 26 ++++++++++++++++++++++++++ 8 files changed, 66 insertions(+) create mode 100644 test/ref/1378FC64.b6d create mode 100644 test/ref/98831F3A.b6d create mode 100644 test/ref/FE3C6545.b6d diff --git a/mmgen/seed.py b/mmgen/seed.py index 40615e69..aa9c42e1 100755 --- a/mmgen/seed.py +++ b/mmgen/seed.py @@ -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 diff --git a/mmgen/util.py b/mmgen/util.py index a1aee67b..27c8ac5e 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -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 diff --git a/test/ref/1378FC64.b6d b/test/ref/1378FC64.b6d new file mode 100644 index 00000000..8790d2d8 --- /dev/null +++ b/test/ref/1378FC64.b6d @@ -0,0 +1 @@ +135111311335561534526322511624324361264136623152556434641112356463412545532 diff --git a/test/ref/98831F3A.b6d b/test/ref/98831F3A.b6d new file mode 100644 index 00000000..8aa78601 --- /dev/null +++ b/test/ref/98831F3A.b6d @@ -0,0 +1 @@ +1253254513316235145146646115665463533224654453113624424263124136533542263452465156633216133232332365 diff --git a/test/ref/FE3C6545.b6d b/test/ref/FE3C6545.b6d new file mode 100644 index 00000000..47358461 --- /dev/null +++ b/test/ref/FE3C6545.b6d @@ -0,0 +1,2 @@ +15146 56446 53415 45431 55141 +32115 41325 16311 32553 43533 diff --git a/test/test_py_d/ts_ref_3seed.py b/test/test_py_d/ts_ref_3seed.py index 78053ee8..e06d4d31 100755 --- a/test/test_py_d/ts_ref_3seed.py +++ b/test/test_py_d/ts_ref_3seed.py @@ -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'] diff --git a/test/test_py_d/ts_wallet.py b/test/test_py_d/ts_wallet.py index 0ff4876b..99cab508 100755 --- a/test/test_py_d/ts_wallet.py +++ b/test/test_py_d/ts_wallet.py @@ -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') diff --git a/test/unit_tests_d/ut_baseconv.py b/test/unit_tests_d/ut_baseconv.py index c5d5efd0..f736a50d 100755 --- a/test/unit_tests_d/ut_baseconv.py +++ b/test/unit_tests_d/ut_baseconv.py @@ -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):