Subwallets, Part 2: key/address generation using the parent wallet
See commit 7538a94 for Part 1
Examples:
# Create a bogus wallet in mnemonic format for testing purposes:
$ echo $(yes bee | head -n24) > bogus.mmwords
# Get the Seed ID of the wallet's 5th short (128-bit) subwallet:
$ mmgen-tool get_subseed 5S wallet=bogus.mmwords
30D66FF5
# Generate ten bech32 addresses from that subwallet:
$ mmgen-addrgen --type=bech32 --subwallet=5S bogus.mmwords 1-10
...
Addresses written to file '30D66FF5-B[1-10].addrs'
# Same as above, but generate secret keys too:
$ mmgen-keygen --type=bech32 --subwallet=5S bogus.mmwords 1-10
...
Secret keys written to file '30D66FF5-B[1-10].akeys'
This commit is contained in:
parent
ab8b5d053e
commit
d1b8aefde6
4 changed files with 48 additions and 14 deletions
|
|
@ -35,7 +35,7 @@ if sys.argv[0].split('-')[-1] == 'keygen':
|
|||
else:
|
||||
gen_what = 'addresses'
|
||||
gen_desc = 'addresses'
|
||||
opt_filter = 'hbcdeEiHOkKlpzPqrStv-'
|
||||
opt_filter = 'hbcdeEiHOkKlpzPqrStUv-'
|
||||
note_addrkey = ''
|
||||
note_secp256k1 = """
|
||||
If available, the secp256k1 library will be used for address generation.
|
||||
|
|
@ -78,6 +78,8 @@ opts_data = {
|
|||
-S, --stdout Print {what} to stdout
|
||||
-t, --type=t Choose address type. Options: see ADDRESS TYPES below
|
||||
(default: {dmat})
|
||||
-U, --subwallet= U Generate {what} for subwallet 'U' (see SUBWALLETS
|
||||
below)
|
||||
-v, --verbose Produce more verbose output
|
||||
-x, --b16 Print secret keys in hexadecimal too
|
||||
""",
|
||||
|
|
@ -96,9 +98,7 @@ ADDRESS TYPES:
|
|||
|
||||
NOTES FOR ALL GENERATOR COMMANDS
|
||||
|
||||
{n_pw}
|
||||
|
||||
{n_bw}
|
||||
{n_sw}{n_pw}{n_bw}
|
||||
|
||||
FMT CODES:
|
||||
|
||||
|
|
@ -118,7 +118,8 @@ FMT CODES:
|
|||
'notes': lambda s: s.format(
|
||||
n_secp=note_secp256k1,
|
||||
n_addrkey=note_addrkey,
|
||||
n_pw=help_notes('passwd'),
|
||||
n_sw=help_notes('subwallet')+'\n\n',
|
||||
n_pw=help_notes('passwd')+'\n\n',
|
||||
n_bw=help_notes('brainwallet'),
|
||||
n_fmt='\n '.join(SeedSource.format_fmt_codes().splitlines()),
|
||||
n_at='\n '.join(["'{}','{:<12} - {}".format(
|
||||
|
|
@ -145,8 +146,10 @@ do_license_msg()
|
|||
|
||||
ss = SeedSource(sf)
|
||||
|
||||
ss_seed = ss.seed if opt.subwallet is None else ss.seed.subseed(opt.subwallet,print_msg=True)
|
||||
|
||||
i = (gen_what=='addresses') or bool(opt.no_addresses)*2
|
||||
al = (KeyAddrList,AddrList,KeyList)[i](seed=ss.seed,addr_idxs=idxs,mmtype=addr_type)
|
||||
al = (KeyAddrList,AddrList,KeyList)[i](seed=ss_seed,addr_idxs=idxs,mmtype=addr_type)
|
||||
al.format()
|
||||
|
||||
if al.gen_addrs and opt.print_checksum:
|
||||
|
|
|
|||
|
|
@ -155,13 +155,7 @@ if invoked_as in ('conv','passchg','subgen'):
|
|||
gmsg('Processing output wallet')
|
||||
|
||||
if invoked_as == 'subgen':
|
||||
msg_r('{} {} of {}...'.format(
|
||||
green('Generating subseed'),
|
||||
ss_idx.hl(),
|
||||
ss_in.seed.sid.hl(),
|
||||
))
|
||||
msg('\b\b\b => {}'.format(ss_in.seed.subseed(ss_idx).sid.hl()))
|
||||
ss_out = SeedSource(seed=ss_in.seed.subseed(ss_idx).data)
|
||||
ss_out = SeedSource(seed=ss_in.seed.subseed(ss_idx,print_msg=True).data)
|
||||
else:
|
||||
ss_out = SeedSource(ss=ss_in,passchg=invoked_as=='passchg')
|
||||
|
||||
|
|
|
|||
|
|
@ -71,12 +71,20 @@ class Seed(SeedBase):
|
|||
self.subseeds = { 'long': OrderedDict(), 'short': OrderedDict() }
|
||||
SeedBase.__init__(self,seed_bin=seed_bin)
|
||||
|
||||
def subseed(self,ss_idx_in):
|
||||
def subseed(self,ss_idx_in,print_msg=False):
|
||||
ss_idx = SubSeedIdx(ss_idx_in)
|
||||
if print_msg:
|
||||
msg_r('{} {} of {}...'.format(
|
||||
green('Generating subseed'),
|
||||
ss_idx.hl(),
|
||||
self.sid.hl(),
|
||||
))
|
||||
if ss_idx.idx > len(self.subseeds['long']):
|
||||
self.gen_subseeds(ss_idx.idx)
|
||||
sid = list(self.subseeds[ss_idx.type].keys())[ss_idx.idx-1]
|
||||
idx,nonce = self.subseeds[ss_idx.type][sid]
|
||||
if print_msg:
|
||||
msg('\b\b\b => {}'.format(SeedID.hlc(sid)))
|
||||
assert idx == ss_idx.idx, "{} != {}: subseed list idx does not match subseed idx!".format(idx,ss_idx.idx)
|
||||
return SubSeed(self,idx,nonce,length=ss_idx.type)
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared):
|
|||
cmd_group = ( # TODO: move to tooltest2
|
||||
('ref_words_to_subwallet_chk1','subwallet generation from reference words file (long subseed)'),
|
||||
('ref_words_to_subwallet_chk2','subwallet generation from reference words file (short subseed)'),
|
||||
('ref_subwallet_addrgen1','subwallet address file generation (long subseed)'),
|
||||
('ref_subwallet_addrgen2','subwallet address file generation (short subseed)'),
|
||||
('ref_subwallet_keygen1','subwallet key-address file generation (long subseed)'),
|
||||
('ref_subwallet_keygen2','subwallet key-address file generation (short subseed)'),
|
||||
('ref_addrfile_chk', 'saved reference address file'),
|
||||
('ref_segwitaddrfile_chk','saved reference address file (segwit)'),
|
||||
('ref_bech32addrfile_chk','saved reference address file (bech32)'),
|
||||
|
|
@ -132,6 +136,31 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared):
|
|||
t.read()
|
||||
return t
|
||||
|
||||
def ref_subwallet_addrgen(self,ss_idx,target='addr'):
|
||||
wf = dfl_words_file
|
||||
args = ['-d',self.tr.trash_dir,'--subwallet='+ss_idx,wf,'1-10']
|
||||
t = self.spawn('mmgen-{}gen'.format(target),args)
|
||||
t.expect('Generating subseed {}'.format(ss_idx))
|
||||
chk_sid = self.chk_data['ref_subwallet_sid']['98831F3A:{}'.format(ss_idx)]
|
||||
assert chk_sid == t.expect_getend('Checksum for .* data ',regex=True)[:8]
|
||||
if target == 'key':
|
||||
t.expect('Encrypt key list? (y/N): ','n')
|
||||
fn = t.written_to_file(('Addresses','Secret keys')[target=='key'])
|
||||
assert chk_sid in fn,'incorrect filename: {} (does not contain {})'.format(fn,chk_sid)
|
||||
return t
|
||||
|
||||
def ref_subwallet_addrgen1(self):
|
||||
return self.ref_subwallet_addrgen('32L')
|
||||
|
||||
def ref_subwallet_addrgen2(self):
|
||||
return self.ref_subwallet_addrgen('1S')
|
||||
|
||||
def ref_subwallet_keygen1(self):
|
||||
return self.ref_subwallet_addrgen('32L',target='key')
|
||||
|
||||
def ref_subwallet_keygen2(self):
|
||||
return self.ref_subwallet_addrgen('1S',target='key')
|
||||
|
||||
def ref_addrfile_chk(self,ftype='addr',coin=None,subdir=None,pfx=None,mmtype=None,add_args=[]):
|
||||
af_key = 'ref_{}file'.format(ftype)
|
||||
af_fn = TestSuiteRef.sources[af_key].format(pfx or self.altcoin_pfx,'' if coin else self.tn_ext)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue