mmgen-keygen: new viewkey-address file type

Generate using the --viewkeys option

Testing:

    $ test/unit_tests.py --verbose addrlist.viewkeyaddr
    $ test/tooltest2.py --fork --verbose --coin=xmr viewkeyaddrfile_chksum
    $ test/test.py -e ref_viewkeyaddrfile_gen_xmr ref_viewkeyaddrfile_chk_xmr
This commit is contained in:
The MMGen Project 2023-04-18 18:35:53 +00:00
commit dc685e9ced
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
10 changed files with 85 additions and 12 deletions

View file

@ -117,7 +117,8 @@ class AddrFile(MMGenObject):
if p.has_keys:
if self.cfg.b16:
out.append(fs.format( '', f'orig_hex: {e.sec.orig_bytes.hex()}', c ))
out.append(fs.format( '', f'{p.al_id.mmtype.wif_label}: {e.sec.wif}', c ))
if type(self) != ViewKeyAddrFile:
out.append(fs.format( '', f'{p.al_id.mmtype.wif_label}: {e.sec.wif}', c ))
for k in ('viewkey','wallet_passwd'):
v = getattr(e,k)
if v: out.append(fs.format( '', f'{k}: {v}', c ))
@ -149,9 +150,10 @@ class AddrFile(MMGenObject):
a = le(**{ 'proto': p.proto, 'idx':int(idx), p.main_attr:addr, 'comment':comment })
if p.has_keys: # order: wif,(orig_hex),viewkey,wallet_passwd
d = self.get_line(lines)
assert d[0] == p.al_id.mmtype.wif_label+':', iifs.format(d[0],p.al_id.mmtype.wif_label)
a.sec = PrivKey(proto=p.proto,wif=d[1])
if type(self) != ViewKeyAddrFile:
d = self.get_line(lines)
assert d[0] == p.al_id.mmtype.wif_label+':', iifs.format(d[0],p.al_id.mmtype.wif_label)
a.sec = PrivKey(proto=p.proto,wif=d[1])
for k,dtype,add_proto in (
('viewkey',ViewKey,True),
('wallet_passwd',WalletPassword,False) ):
@ -162,7 +164,7 @@ class AddrFile(MMGenObject):
ret.append(a)
if p.has_keys and p.ka_validity_chk != False:
if type(self) != ViewKeyAddrFile and p.has_keys and p.ka_validity_chk != False:
def verify_keys():
from .addrgen import KeyGenerator,AddrGenerator
@ -300,6 +302,10 @@ class KeyAddrFile(AddrFile):
desc = 'secret keys'
ext = 'akeys'
class ViewKeyAddrFile(KeyAddrFile):
desc = 'view keys'
ext = 'vkeys'
class KeyFile(KeyAddrFile):
ext = 'keys'
header = """

View file

@ -218,6 +218,10 @@ class AddrList(MMGenObject): # Address info for a single seed ID
if self.al_id == None:
return
if type(self) == ViewKeyAddrList:
if not 'viewkey' in self.al_id.mmtype.extra_attrs:
die(1,f'viewkeys not supported for address type {self.al_id.mmtype.desc!r}')
self.id_str = AddrListIDStr(self)
if type(self) == KeyList:
@ -242,8 +246,8 @@ class AddrList(MMGenObject): # Address info for a single seed ID
mmtype = self.al_id.mmtype
gen_wallet_passwd = type(self) == KeyAddrList and 'wallet_passwd' in mmtype.extra_attrs
gen_viewkey = type(self) == KeyAddrList and 'viewkey' in mmtype.extra_attrs
gen_wallet_passwd = type(self) in (KeyAddrList,ViewKeyAddrList) and 'wallet_passwd' in mmtype.extra_attrs
gen_viewkey = type(self) in (KeyAddrList,ViewKeyAddrList) and 'viewkey' in mmtype.extra_attrs
if self.gen_addrs:
from .addrgen import KeyGenerator,AddrGenerator
@ -281,7 +285,8 @@ class AddrList(MMGenObject): # Address info for a single seed ID
if gen_viewkey:
e.viewkey = ag.to_viewkey(data)
if gen_wallet_passwd:
e.wallet_passwd = self.gen_wallet_passwd(e.sec)
e.wallet_passwd = self.gen_wallet_passwd(
e.viewkey.encode() if type(self) == ViewKeyAddrList else e.sec )
elif self.gen_passwds:
e.passwd = self.gen_passwd(e.sec) # TODO - own type
@ -406,6 +411,11 @@ class KeyAddrList(AddrList):
has_keys = True
chksum_rec_f = lambda foo,e: (str(e.idx), e.addr, e.sec.wif)
class ViewKeyAddrList(KeyAddrList):
desc = 'viewkey-address'
gen_desc = 'viewkey/address pair'
chksum_rec_f = lambda foo,e: ( str(e.idx), e.addr )
class KeyList(KeyAddrList):
desc = 'key'
gen_desc = 'key'

View file

@ -79,6 +79,7 @@ opts_data = {
(default: {dmat})
-U, --subwallet= U Generate {what} for subwallet 'U' (see SUBWALLETS
below)
-V, --viewkeys Print viewkeys, omitting secret keys
-v, --verbose Produce more verbose output
-x, --b16 Print secret keys in hexadecimal too
""",
@ -156,6 +157,8 @@ ss_seed = ss.seed if cfg.subwallet is None else ss.seed.subseed(cfg.subwallet,pr
if cfg.no_addresses:
gen_clsname = 'KeyList'
elif cfg.viewkeys:
gen_clsname = 'ViewKeyAddrList'
al = getattr( mmgen.addrlist, gen_clsname )(
cfg = cfg,

View file

@ -137,6 +137,7 @@ mods = {
'file': (
'addrfile_chksum',
'keyaddrfile_chksum',
'viewkeyaddrfile_chksum',
'passwdfile_chksum',
'txview',
),

View file

@ -60,6 +60,11 @@ class tool_cmd(tool_cmd_base):
from ..addrlist import KeyAddrList
return self._file_chksum(mmgen_keyaddrfile,KeyAddrList)
def viewkeyaddrfile_chksum(self,mmgen_viewkeyaddrfile:str):
"compute checksum for MMGen key-address file"
from ..addrlist import ViewKeyAddrList
return self._file_chksum(mmgen_viewkeyaddrfile,ViewKeyAddrList)
def passwdfile_chksum(self,mmgen_passwdfile:str):
"compute checksum for MMGen password file"
from ..passwdlist import PasswordList

View file

@ -0,0 +1,21 @@
# MMGen viewkey-address file
#
# This file is editable.
# Everything following a hash symbol '#' is a comment and ignored by MMGen.
# A text label of 80 screen cells or less may be added to the right of each
# address, and it will be appended to the tracking wallet label upon import.
# The label may contain any printable ASCII symbol.
#
# Viewkey-address data checksum for 98831F3A-XMR-M[1-3]: 40C9 0E61 B743 229C
# Record this value to a secure location.
98831F3A XMR:MONERO {
1 41tmwZd2CdXEGtWqGY9fH9FVtQM8VxZASYPQ3VJQhFjtGWYzQFuidD21vJYTi2yy3tXRYXTNXBTaYVLav62rwUUpFFyicZU
viewkey: 3fa430d35eb44ae2ac91b302b794e6b789807ca0c19757042f581e5579314503
wallet_passwd: 4be230151aa51363af6123624ea20509
2 45Un3DKQfZ1XP9XWKVqMrzMugrxHLU8L47Jcxyu7dNnGKd7WWDTQ6QrBjCxoxQhnL13xdgKycywfijNuuTzbZBj7UHPjBMb
viewkey: 176fed837ea2d8ab98de50811a0869d0f2e6076fcacfa17707bfb2bca960190e
wallet_passwd: b19f506e52c8ffd7a3b1bc1c4fb4c1bb
3 47mWaHEPy26U4e2Xw1y3PhBuEBzMpPF1z7QzBVJ19pqe9nMmcztcHdkYs19YxrJnEWEkipSNroQxvJaoYfLX87Po39Btso4
viewkey: be75e20cf8ae8816bade5c05cb677929c67be310fcb509fd52630735229ac20d
wallet_passwd: 5e8e3b47a9aa28464dcc2a588e892d50
}

View file

@ -41,6 +41,8 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared):
'ref_segwitaddrfile':'98831F3A{}-S[1,31-33,500-501,1010-1011]{}.addrs',
'ref_bech32addrfile':'98831F3A{}-B[1,31-33,500-501,1010-1011]{}.addrs',
'ref_keyaddrfile': '98831F3A{}[1,31-33,500-501,1010-1011]{}.akeys.mmenc',
'ref_viewkeyaddrfile': '98831F3A-XMR-M[1-3].vkeys',
'ref_passwdfile_b32_24': '98831F3A-фубар@crypto.org-b32-24[1,4,1100].pws',
'ref_passwdfile_b32_12': '98831F3A-фубар@crypto.org-b32-12[1,4,1100].pws',
'ref_passwdfile_b58_10': '98831F3A-фубар@crypto.org-b58-10[1,4,1100].pws',

View file

@ -40,6 +40,7 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
'ref_keyaddrfile_chksum_zec': 'F05A 5A5C 0C8E 2617',
'ref_keyaddrfile_chksum_zec_z': '6B87 9B2D 0D8D 8D1E',
'ref_keyaddrfile_chksum_xmr': 'E0D7 9612 3D67 404A',
'ref_viewkeyaddrfile_chksum_xmr': '40C9 0E61 B743 229C',
'ref_keyaddrfile_chksum_dash': 'E83D 2C63 FEA2 4142',
'ref_keyaddrfile_chksum_eth': 'E400 70D9 0AE3 C7C2',
'ref_keyaddrfile_chksum_etc': 'EF49 967D BD6C FE45',
@ -61,6 +62,7 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
('ref_keyaddrfile_gen_zec', 'generate key-address file (ZEC-T)'),
('ref_keyaddrfile_gen_zec_z','generate key-address file (ZEC-Z)'),
('ref_keyaddrfile_gen_xmr', 'generate key-address file (XMR)'),
('ref_viewkeyaddrfile_gen_xmr','generate viewkey-address file (XMR)'),
('ref_addrfile_chk_eth', 'reference address file (ETH)'),
('ref_addrfile_chk_etc', 'reference address file (ETC)'),
@ -75,6 +77,7 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
('ref_keyaddrfile_chk_zec', 'reference key-address file (ZEC-T)'),
('ref_keyaddrfile_chk_zec_z','reference key-address file (ZEC-Z)'),
('ref_keyaddrfile_chk_xmr', 'reference key-address file (XMR)'),
('ref_viewkeyaddrfile_chk_xmr', 'reference viewkey-address file (XMR)'),
)
def ref_altcoin_tx_chk(self):
@ -173,6 +176,13 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
def ref_keyaddrfile_gen_xmr(self):
return self.ref_altcoin_addrgen(coin='XMR',mmtype='monero',gen_what='key')
def ref_viewkeyaddrfile_gen_xmr(self):
return self.ref_altcoin_addrgen(
coin = 'XMR',
mmtype = 'monero',
gen_what = 'viewkey',
add_args = ['--viewkeys'],
addr_idx_list = '1-3' )
def ref_addrfile_chk_eth(self):
return self.ref_addrfile_chk(ftype='addr',coin='ETH',subdir='ethereum',pfx='-ETH',
@ -222,3 +232,7 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
def ref_keyaddrfile_chk_xmr(self):
return self.ref_addrfile_chk(ftype='keyaddr',coin='XMR',subdir='monero',pfx='-XMR-M',
pat='XMR Mainnet.*Monero')
def ref_viewkeyaddrfile_chk_xmr(self):
return self.ref_addrfile_chk(ftype='viewkeyaddr',coin='XMR',subdir='monero',pfx='-XMR-M',
pat='XMR Mainnet.*Monero')

View file

@ -681,6 +681,11 @@ tests = {
( ['test/ref/ethereum_classic/98831F3A-ETC[1,31-33,500-501,1010-1011].addrs'],
'E97A D796 B495 E8BC'), ],
},
'viewkeyaddrfile_chksum': {
'xmr_mainnet': [
( ['test/ref/monero/98831F3A-XMR-M[1-3].vkeys'], '40C9 0E61 B743 229C' ),
],
},
'keyaddrfile_chksum': {
'btc_mainnet': [
( ['test/ref/98831F3A[1,31-33,500-501,1010-1011].akeys.mmenc'],

View file

@ -7,17 +7,17 @@ test.unit_tests_d.ut_addrlist: address list unit tests for the MMGen suite
from mmgen.common import *
from mmgen.seed import Seed
from mmgen.addr import MMGenAddrType
from mmgen.addrlist import AddrIdxList,AddrList,KeyList,KeyAddrList
from mmgen.addrlist import AddrIdxList,AddrList,KeyList,KeyAddrList,ViewKeyAddrList
from mmgen.passwdlist import PasswordList
from mmgen.protocol import init_proto
from ..include.common import cfg,qmsg,vmsg
def do_test(list_type,chksum,idx_spec=None,pw_id_str=None,add_kwargs=None):
def do_test(list_type,chksum,idx_spec=None,pw_id_str=None,add_kwargs=None,coin=None,addrtype=None):
qmsg(blue(f'Testing {list_type.__name__}'))
proto = init_proto( cfg, 'btc' )
proto = init_proto( cfg, coin or 'btc' )
seed = Seed(cfg,seed_bin=bytes.fromhex('feedbead'*8))
mmtype = MMGenAddrType(proto,'C')
mmtype = MMGenAddrType(proto, addrtype or 'C')
idxs = AddrIdxList(idx_spec or '1-3')
if cfg.verbose:
@ -93,6 +93,12 @@ class unit_tests:
def keyaddr(self,name,ut):
return do_test(KeyAddrList,'4A36 AA65 8C2B 7C35')
def keyaddr_xmr(self,name,ut):
return do_test(KeyAddrList,'AAA2 BA69 17FC 9A88',coin='XMR',addrtype='M')
def viewkeyaddr(self,name,ut):
return do_test(ViewKeyAddrList,'C122 2E58 DC28 D6AE',coin='XMR',addrtype='M')
def passwd(self,name,ut):
return do_test(PasswordList,'FF4A B716 4513 8F8F',pw_id_str='foo')