seed.py: move seedsplit related classes to seedsplit.py

This commit is contained in:
The MMGen Project 2022-01-15 14:00:05 +00:00
commit ff450b0ec5
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
12 changed files with 328 additions and 286 deletions

View file

@ -134,7 +134,7 @@ default wallet.
pnl = g.proj_name.lower() )
def seedsplit():
from .obj import SeedShareIdx,SeedShareCount,MasterShareIdx
from .seedsplit import SeedShareIdx,SeedShareCount,MasterShareIdx
return """
COMMAND NOTES:

View file

@ -22,8 +22,9 @@ mmgen/main_seedjoin: Regenerate an MMGen deterministic wallet from seed shares
"""
from .common import *
from .obj import MasterShareIdx,SeedSplitIDString,MMGenWalletLabel
from .seed import Seed,SeedShareMasterJoining
from .obj import MMGenWalletLabel
from .seed import Seed
from .seedsplit import SeedSplitIDString,MasterShareIdx,SeedShareMasterJoining
from .wallet import Wallet
opts_data = {

View file

@ -22,9 +22,10 @@ mmgen/main_wallet: Entry point for MMGen wallet-related scripts
import os
from .common import *
from .obj import MMGenWalletLabel
from .seedsplit import MasterShareIdx
from .wallet import Wallet,MMGenWallet
from .filename import find_file_in_dir
from .obj import MMGenWalletLabel,MasterShareIdx
usage = '[opts] [infile]'
nargs = 1
@ -148,7 +149,8 @@ if invoked_as == 'subgen':
from .obj import SubSeedIdx
ss_idx = SubSeedIdx(cmd_args.pop())
elif invoked_as == 'seedsplit':
from .obj import get_obj,SeedSplitSpecifier
from .obj import get_obj
from .seedsplit import SeedSplitSpecifier
master_share = MasterShareIdx(opt.master_share) if opt.master_share else None
if cmd_args:
sss = get_obj(SeedSplitSpecifier,s=cmd_args.pop(),silent=True)

View file

@ -65,7 +65,6 @@ def get_obj(objname,*args,**kwargs):
def is_mmgen_seed_id(s): return get_obj(SeedID, sid=s, silent=True,return_bool=True)
def is_mmgen_idx(s): return get_obj(AddrIdx, n=s, silent=True,return_bool=True)
def is_addrlist_id(s): return get_obj(AddrListID, sid=s, silent=True,return_bool=True)
def is_seed_split_specifier(s): return get_obj(SeedSplitSpecifier, s=s, silent=True,return_bool=True)
def is_mmgen_id(proto,s): return get_obj(MMGenID, proto=proto, id_str=s, silent=True,return_bool=True)
def is_coin_addr(proto,s): return get_obj(CoinAddr, proto=proto, addr=s, silent=True,return_bool=True)
@ -367,9 +366,6 @@ class MMGenListItem(MMGenObject):
return dict((k,v) for k,v in self.__dict__.items() if k in self.valid_attrs)
class MMGenIdx(Int): min_val = 1
class SeedShareIdx(MMGenIdx): max_val = 1024
class SeedShareCount(SeedShareIdx): min_val = 2
class MasterShareIdx(MMGenIdx): max_val = 1024
class AddrIdx(MMGenIdx): max_digits = 7
class AddrIdxList(list,InitErrors,MMGenObject):
@ -943,27 +939,6 @@ class MMGenPWIDString(MMGenLabel):
forbidden = list(' :/\\')
trunc_ok = False
class SeedSplitSpecifier(str,Hilite,InitErrors,MMGenObject):
color = 'red'
def __new__(cls,s):
if type(s) == cls:
return s
try:
arr = s.split(':')
assert len(arr) in (2,3), 'cannot be parsed'
a,b,c = arr if len(arr) == 3 else ['default'] + arr
me = str.__new__(cls,s)
me.id = SeedSplitIDString(a)
me.idx = SeedShareIdx(b)
me.count = SeedShareCount(c)
assert me.idx <= me.count, 'share index greater than share count'
return me
except Exception as e:
return cls.init_fail(e,s)
class SeedSplitIDString(MMGenPWIDString):
desc = 'seed split ID string'
class IPPort(str,Hilite,InitErrors,MMGenObject):
color = 'yellow'
width = 0

View file

@ -208,36 +208,14 @@ class Seed(SeedBase):
def subseed_by_seed_id(self,sid,last_idx=None,print_msg=False):
return self.subseeds.get_subseed_by_seed_id(sid,last_idx=last_idx,print_msg=print_msg)
def split(self,count,id_str=None,master_idx=None):
return SeedShareList(self,count,id_str,master_idx)
def split(self,*args,**kwargs):
from .seedsplit import SeedShareList
return SeedShareList(self,*args,**kwargs)
@staticmethod
def join_shares(seed_list,master_idx=None,id_str=None):
if not hasattr(seed_list,'__next__'): # seed_list can be iterator or iterable
seed_list = iter(seed_list)
class d(object):
byte_len,ret,count = None,0,0
def add_share(ss):
if d.byte_len:
assert ss.byte_len == d.byte_len, f'Seed length mismatch! {ss.byte_len} != {d.byte_len}'
else:
d.byte_len = ss.byte_len
d.ret ^= int(ss.data.hex(),16)
d.count += 1
if master_idx:
master_share = next(seed_list)
for ss in seed_list:
add_share(ss)
if master_idx:
add_share(SeedShareMasterJoining(master_idx,master_share,id_str,d.count+1).derived_seed)
SeedShareCount(d.count)
return Seed(seed_bin=d.ret.to_bytes(d.byte_len,'big'))
def join_shares(*args,**kwargs):
from .seedsplit import join_shares
return join_shares(*args,**kwargs)
class SubSeed(SeedBase):
@ -260,225 +238,3 @@ class SubSeed(SeedBase):
# field maximums: idx: 4294967295 (1000000), nonce: 65535 (1000), short: 255 (1)
scramble_key = idx.to_bytes(4,'big') + nonce.to_bytes(2,'big') + short.to_bytes(1,'big')
return scramble_seed(seed.data,scramble_key)[:16 if short else seed.byte_len]
class SeedShareList(SubSeedList):
have_short = False
split_type = 'N-of-N'
count = ImmutableAttr(SeedShareCount)
id_str = ImmutableAttr(SeedSplitIDString)
def __init__(self,parent_seed,count,id_str=None,master_idx=None,debug_last_share=False):
self.member_type = SeedShare
self.parent_seed = parent_seed
self.id_str = id_str or 'default'
self.count = count
def make_master_share():
for nonce in range(SeedShare.max_nonce+1):
ms = SeedShareMaster(self,master_idx,nonce)
if ms.sid == parent_seed.sid:
if g.debug_subseed:
msg(f'master_share seed ID collision with parent seed, incrementing nonce to {nonce+1}')
else:
return ms
raise SubSeedNonceRangeExceeded('nonce range exceeded')
def last_share_debug(last_share):
if not debug_last_share:
return False
sid_len = self.debug_last_share_sid_len
lsid = last_share.sid[:sid_len]
psid = parent_seed.sid[:sid_len]
ssids = [d[:sid_len] for d in self.data['long'].keys]
return (lsid in ssids or lsid == psid)
self.master_share = make_master_share() if master_idx else None
for nonce in range(SeedShare.max_nonce+1):
self.nonce_start = nonce
self.data = { 'long': IndexedDict(), 'short': IndexedDict() } # 'short' is required as a placeholder
if self.master_share:
self.data['long'][self.master_share.sid] = (1,self.master_share.nonce)
self._generate(count-1)
self.last_share = ls = SeedShareLast(self)
if last_share_debug(ls) or ls.sid in self.data['long'] or ls.sid == parent_seed.sid:
# collision: throw out entire split list and redo with new start nonce
if g.debug_subseed:
self._collision_debug_msg(ls.sid,count,nonce,'nonce_start',debug_last_share)
else:
self.data['long'][ls.sid] = (count,nonce)
break
else:
raise SubSeedNonceRangeExceeded('nonce range exceeded')
if g.debug_subseed:
A = parent_seed.data
B = self.join().data
assert A == B, f'Data mismatch!\noriginal seed: {A!r}\nrejoined seed: {B!r}'
def get_share_by_idx(self,idx,base_seed=False):
if idx < 1 or idx > self.count:
raise RangeError(f'{idx}: share index out of range')
elif idx == self.count:
return self.last_share
elif self.master_share and idx == 1:
return self.master_share if base_seed else self.master_share.derived_seed
else:
ss_idx = SubSeedIdx(str(idx) + 'L')
return self.get_subseed_by_ss_idx(ss_idx)
def get_share_by_seed_id(self,sid,base_seed=False):
if sid == self.data['long'].key(self.count-1):
return self.last_share
elif self.master_share and sid == self.data['long'].key(0):
return self.master_share if base_seed else self.master_share.derived_seed
else:
return self.get_subseed_by_seed_id(sid)
def join(self):
return Seed.join_shares(self.get_share_by_idx(i+1) for i in range(len(self)))
def format(self):
assert self.split_type == 'N-of-N'
fs1 = ' {}\n'
fs2 = '{i:>5}: {}\n'
mfs1,mfs2,midx,msid = ('','','','')
if self.master_share:
mfs1,mfs2 = (' with master share #{} ({})',' (master share #{})')
midx,msid = (self.master_share.idx,self.master_share.sid)
hdr = ' {} {} ({} bits)\n'.format('Seed:',self.parent_seed.sid.hl(),self.parent_seed.bitlen)
hdr += ' {} {c}-of-{c} (XOR){m}\n'.format('Split Type:',c=self.count,m=mfs1.format(midx,msid))
hdr += ' {} {}\n\n'.format('ID String:',self.id_str.hl())
hdr += fs1.format('Shares')
hdr += fs1.format('------')
sl = self.data['long'].keys
body1 = fs2.format(sl[0]+mfs2.format(midx),i=1)
body = (fs2.format(sl[n],i=n+1) for n in range(1,len(self)))
return hdr + body1 + ''.join(body)
class SeedShareBase(MMGenObject):
@property
def fn_stem(self):
pl = self.parent_list
msdata = f'_with_master{pl.master_share.idx}' if pl.master_share else ''
return '{}-{}-{}of{}{}[{}]'.format(
pl.parent_seed.sid,
pl.id_str,
self.idx,
pl.count,
msdata,
self.sid)
@property
def desc(self):
return self.get_desc()
def get_desc(self,ui=False):
pl = self.parent_list
mss = f', with master share #{pl.master_share.idx}' if pl.master_share else ''
if ui:
m = ( yellow("(share {} of {} of ")
+ pl.parent_seed.sid.hl()
+ yellow(', split id ')
+ pl.id_str.hl(encl="''")
+ yellow('{})') )
else:
m = "share {} of {} of " + pl.parent_seed.sid + ", split id '" + pl.id_str + "'{}"
return m.format(self.idx,pl.count,mss)
class SeedShare(SeedShareBase,SubSeed):
@staticmethod
def make_subseed_bin(parent_list,idx:int,nonce:int,length:str):
seed = parent_list.parent_seed
assert parent_list.have_short == False
assert length == 'long'
# field maximums: id_str: none (256 chars), count: 65535 (1024), idx: 65535 (1024), nonce: 65535 (1000)
scramble_key = (
f'{parent_list.split_type}:{parent_list.id_str}:'.encode() +
parent_list.count.to_bytes(2,'big') +
idx.to_bytes(2,'big') +
nonce.to_bytes(2,'big')
)
if parent_list.master_share:
scramble_key += (
b':master:' +
parent_list.master_share.idx.to_bytes(2,'big')
)
return scramble_seed(seed.data,scramble_key)[:seed.byte_len]
class SeedShareLast(SeedShareBase,SeedBase):
idx = ImmutableAttr(SeedShareIdx)
nonce = 0
def __init__(self,parent_list):
self.idx = parent_list.count
self.parent_list = parent_list
SeedBase.__init__(self,seed_bin=self.make_subseed_bin(parent_list))
@staticmethod
def make_subseed_bin(parent_list):
seed_list = (parent_list.get_share_by_idx(i+1) for i in range(len(parent_list)))
seed = parent_list.parent_seed
ret = int(seed.data.hex(),16)
for ss in seed_list:
ret ^= int(ss.data.hex(),16)
return ret.to_bytes(seed.byte_len,'big')
class SeedShareMaster(SeedBase,SeedShareBase):
idx = ImmutableAttr(MasterShareIdx)
nonce = ImmutableAttr(int,typeconv=False)
def __init__(self,parent_list,idx,nonce):
self.idx = idx
self.nonce = nonce
self.parent_list = parent_list
SeedBase.__init__(self,self.make_base_seed_bin())
self.derived_seed = SeedBase(self.make_derived_seed_bin(parent_list.id_str,parent_list.count))
@property
def fn_stem(self):
return '{}-MASTER{}[{}]'.format(
self.parent_list.parent_seed.sid,
self.idx,
self.sid )
def make_base_seed_bin(self):
seed = self.parent_list.parent_seed
# field maximums: idx: 65535 (1024)
scramble_key = b'master_share:' + self.idx.to_bytes(2,'big') + self.nonce.to_bytes(2,'big')
return scramble_seed(seed.data,scramble_key)[:seed.byte_len]
# Don't bother with avoiding seed ID collision here, as sid of derived seed is not used
# by user as an identifier
def make_derived_seed_bin(self,id_str,count):
# field maximums: id_str: none (256 chars), count: 65535 (1024)
scramble_key = id_str.encode() + b':' + count.to_bytes(2,'big')
return scramble_seed(self.data,scramble_key)[:self.byte_len]
def get_desc(self,ui=False):
psid = self.parent_list.parent_seed.sid
mss = f'master share #{self.idx} of '
return yellow('(' + mss) + psid.hl() + yellow(')') if ui else mss + psid
class SeedShareMasterJoining(SeedShareMaster):
id_str = ImmutableAttr(SeedSplitIDString)
count = ImmutableAttr(SeedShareCount)
def __init__(self,idx,base_seed,id_str,count):
SeedBase.__init__(self,seed_bin=base_seed.data)
self.id_str = id_str or 'default'
self.count = count
self.derived_seed = SeedBase(self.make_derived_seed_bin(self.id_str,self.count))

307
mmgen/seedsplit.py Executable file
View file

@ -0,0 +1,307 @@
#!/usr/bin/env python3
#
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
# Copyright (C)2013-2022 The MMGen Project <mmgen@tuta.io>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
seedsplit.py: Seed split classes and methods for the MMGen suite
"""
from .exception import RangeError
from .obj import MMGenPWIDString,MMGenIdx
from .seed import *
class SeedShareIdx(MMGenIdx):
max_val = 1024
class SeedShareCount(SeedShareIdx):
min_val = 2
class MasterShareIdx(MMGenIdx):
max_val = 1024
class SeedSplitSpecifier(str,Hilite,InitErrors,MMGenObject):
color = 'red'
def __new__(cls,s):
if type(s) == cls:
return s
try:
arr = s.split(':')
assert len(arr) in (2,3), 'cannot be parsed'
a,b,c = arr if len(arr) == 3 else ['default'] + arr
me = str.__new__(cls,s)
me.id = SeedSplitIDString(a)
me.idx = SeedShareIdx(b)
me.count = SeedShareCount(c)
assert me.idx <= me.count, 'share index greater than share count'
return me
except Exception as e:
return cls.init_fail(e,s)
def is_seed_split_specifier(s):
return get_obj( SeedSplitSpecifier, s=s, silent=True, return_bool=True )
class SeedSplitIDString(MMGenPWIDString):
desc = 'seed split ID string'
class SeedShareList(SubSeedList):
have_short = False
split_type = 'N-of-N'
count = ImmutableAttr(SeedShareCount)
id_str = ImmutableAttr(SeedSplitIDString)
def __init__(self,parent_seed,count,id_str=None,master_idx=None,debug_last_share=False):
self.member_type = SeedShare
self.parent_seed = parent_seed
self.id_str = id_str or 'default'
self.count = count
def make_master_share():
for nonce in range(SeedShare.max_nonce+1):
ms = SeedShareMaster(self,master_idx,nonce)
if ms.sid == parent_seed.sid:
if g.debug_subseed:
msg(f'master_share seed ID collision with parent seed, incrementing nonce to {nonce+1}')
else:
return ms
raise SubSeedNonceRangeExceeded('nonce range exceeded')
def last_share_debug(last_share):
if not debug_last_share:
return False
sid_len = self.debug_last_share_sid_len
lsid = last_share.sid[:sid_len]
psid = parent_seed.sid[:sid_len]
ssids = [d[:sid_len] for d in self.data['long'].keys]
return (lsid in ssids or lsid == psid)
self.master_share = make_master_share() if master_idx else None
for nonce in range(SeedShare.max_nonce+1):
self.nonce_start = nonce
self.data = { 'long': IndexedDict(), 'short': IndexedDict() } # 'short' is required as a placeholder
if self.master_share:
self.data['long'][self.master_share.sid] = (1,self.master_share.nonce)
self._generate(count-1)
self.last_share = ls = SeedShareLast(self)
if last_share_debug(ls) or ls.sid in self.data['long'] or ls.sid == parent_seed.sid:
# collision: throw out entire split list and redo with new start nonce
if g.debug_subseed:
self._collision_debug_msg(ls.sid,count,nonce,'nonce_start',debug_last_share)
else:
self.data['long'][ls.sid] = (count,nonce)
break
else:
raise SubSeedNonceRangeExceeded('nonce range exceeded')
if g.debug_subseed:
A = parent_seed.data
B = self.join().data
assert A == B, f'Data mismatch!\noriginal seed: {A!r}\nrejoined seed: {B!r}'
def get_share_by_idx(self,idx,base_seed=False):
if idx < 1 or idx > self.count:
raise RangeError(f'{idx}: share index out of range')
elif idx == self.count:
return self.last_share
elif self.master_share and idx == 1:
return self.master_share if base_seed else self.master_share.derived_seed
else:
ss_idx = SubSeedIdx(str(idx) + 'L')
return self.get_subseed_by_ss_idx(ss_idx)
def get_share_by_seed_id(self,sid,base_seed=False):
if sid == self.data['long'].key(self.count-1):
return self.last_share
elif self.master_share and sid == self.data['long'].key(0):
return self.master_share if base_seed else self.master_share.derived_seed
else:
return self.get_subseed_by_seed_id(sid)
def join(self):
return Seed.join_shares(self.get_share_by_idx(i+1) for i in range(len(self)))
def format(self):
assert self.split_type == 'N-of-N'
fs1 = ' {}\n'
fs2 = '{i:>5}: {}\n'
mfs1,mfs2,midx,msid = ('','','','')
if self.master_share:
mfs1,mfs2 = (' with master share #{} ({})',' (master share #{})')
midx,msid = (self.master_share.idx,self.master_share.sid)
hdr = ' {} {} ({} bits)\n'.format('Seed:',self.parent_seed.sid.hl(),self.parent_seed.bitlen)
hdr += ' {} {c}-of-{c} (XOR){m}\n'.format('Split Type:',c=self.count,m=mfs1.format(midx,msid))
hdr += ' {} {}\n\n'.format('ID String:',self.id_str.hl())
hdr += fs1.format('Shares')
hdr += fs1.format('------')
sl = self.data['long'].keys
body1 = fs2.format(sl[0]+mfs2.format(midx),i=1)
body = (fs2.format(sl[n],i=n+1) for n in range(1,len(self)))
return hdr + body1 + ''.join(body)
class SeedShareBase(MMGenObject):
@property
def fn_stem(self):
pl = self.parent_list
msdata = f'_with_master{pl.master_share.idx}' if pl.master_share else ''
return '{}-{}-{}of{}{}[{}]'.format(
pl.parent_seed.sid,
pl.id_str,
self.idx,
pl.count,
msdata,
self.sid)
@property
def desc(self):
return self.get_desc()
def get_desc(self,ui=False):
pl = self.parent_list
mss = f', with master share #{pl.master_share.idx}' if pl.master_share else ''
if ui:
m = ( yellow("(share {} of {} of ")
+ pl.parent_seed.sid.hl()
+ yellow(', split id ')
+ pl.id_str.hl(encl="''")
+ yellow('{})') )
else:
m = "share {} of {} of " + pl.parent_seed.sid + ", split id '" + pl.id_str + "'{}"
return m.format(self.idx,pl.count,mss)
class SeedShare(SeedShareBase,SubSeed):
@staticmethod
def make_subseed_bin(parent_list,idx:int,nonce:int,length:str):
seed = parent_list.parent_seed
assert parent_list.have_short == False
assert length == 'long'
# field maximums: id_str: none (256 chars), count: 65535 (1024), idx: 65535 (1024), nonce: 65535 (1000)
scramble_key = (
f'{parent_list.split_type}:{parent_list.id_str}:'.encode() +
parent_list.count.to_bytes(2,'big') +
idx.to_bytes(2,'big') +
nonce.to_bytes(2,'big')
)
if parent_list.master_share:
scramble_key += (
b':master:' +
parent_list.master_share.idx.to_bytes(2,'big')
)
return scramble_seed(seed.data,scramble_key)[:seed.byte_len]
class SeedShareLast(SeedShareBase,SeedBase):
idx = ImmutableAttr(SeedShareIdx)
nonce = 0
def __init__(self,parent_list):
self.idx = parent_list.count
self.parent_list = parent_list
SeedBase.__init__(self,seed_bin=self.make_subseed_bin(parent_list))
@staticmethod
def make_subseed_bin(parent_list):
seed_list = (parent_list.get_share_by_idx(i+1) for i in range(len(parent_list)))
seed = parent_list.parent_seed
ret = int(seed.data.hex(),16)
for ss in seed_list:
ret ^= int(ss.data.hex(),16)
return ret.to_bytes(seed.byte_len,'big')
class SeedShareMaster(SeedBase,SeedShareBase):
idx = ImmutableAttr(MasterShareIdx)
nonce = ImmutableAttr(int,typeconv=False)
def __init__(self,parent_list,idx,nonce):
self.idx = idx
self.nonce = nonce
self.parent_list = parent_list
SeedBase.__init__(self,self.make_base_seed_bin())
self.derived_seed = SeedBase(self.make_derived_seed_bin(parent_list.id_str,parent_list.count))
@property
def fn_stem(self):
return '{}-MASTER{}[{}]'.format(
self.parent_list.parent_seed.sid,
self.idx,
self.sid )
def make_base_seed_bin(self):
seed = self.parent_list.parent_seed
# field maximums: idx: 65535 (1024)
scramble_key = b'master_share:' + self.idx.to_bytes(2,'big') + self.nonce.to_bytes(2,'big')
return scramble_seed(seed.data,scramble_key)[:seed.byte_len]
# Don't bother with avoiding seed ID collision here, as sid of derived seed is not used
# by user as an identifier
def make_derived_seed_bin(self,id_str,count):
# field maximums: id_str: none (256 chars), count: 65535 (1024)
scramble_key = id_str.encode() + b':' + count.to_bytes(2,'big')
return scramble_seed(self.data,scramble_key)[:self.byte_len]
def get_desc(self,ui=False):
psid = self.parent_list.parent_seed.sid
mss = f'master share #{self.idx} of '
return yellow('(' + mss) + psid.hl() + yellow(')') if ui else mss + psid
class SeedShareMasterJoining(SeedShareMaster):
id_str = ImmutableAttr(SeedSplitIDString)
count = ImmutableAttr(SeedShareCount)
def __init__(self,idx,base_seed,id_str,count):
SeedBase.__init__(self,seed_bin=base_seed.data)
self.id_str = id_str or 'default'
self.count = count
self.derived_seed = SeedBase(self.make_derived_seed_bin(self.id_str,self.count))
def join_shares(seed_list,master_idx=None,id_str=None):
if not hasattr(seed_list,'__next__'): # seed_list can be iterator or iterable
seed_list = iter(seed_list)
class d(object):
byte_len,ret,count = None,0,0
def add_share(ss):
if d.byte_len:
assert ss.byte_len == d.byte_len, f'Seed length mismatch! {ss.byte_len} != {d.byte_len}'
else:
d.byte_len = ss.byte_len
d.ret ^= int(ss.data.hex(),16)
d.count += 1
if master_idx:
master_share = next(seed_list)
for ss in seed_list:
add_share(ss)
if master_idx:
add_share(SeedShareMasterJoining(master_idx,master_share,id_str,d.count+1).derived_seed)
SeedShareCount(d.count)
return Seed(seed_bin=d.ret.to_bytes(d.byte_len,'big'))

View file

@ -23,6 +23,7 @@ tool.py: Routines for the 'mmgen-tool' utility
from .protocol import hash160
from .common import *
from .crypto import *
from .seedsplit import MasterShareIdx
from .addr import *
NL = ('\n','\r\n')[g.platform=='win']

View file

@ -11,7 +11,7 @@ import os
from decimal import Decimal
from mmgen.obj import *
from mmgen.seed import *
from mmgen.seedsplit import *
from mmgen.protocol import *
from mmgen.addr import *
from mmgen.tx import *

View file

@ -32,7 +32,7 @@ os.environ['MMGEN_TEST_SUITE'] = '1'
from mmgen.common import *
from mmgen.obj import *
from mmgen.altcoins.eth.obj import *
from mmgen.seed import *
from mmgen.seedsplit import *
opts_data = {
'sets': [('super_silent', True, 'silent', True)],

View file

@ -8,7 +8,7 @@ test.objtest_py_d.ot_btc_mainnet: BTC mainnet test vectors for MMGen data object
"""
from mmgen.obj import *
from mmgen.seed import *
from mmgen.seedsplit import *
from .ot_common import *
from mmgen.protocol import init_proto

View file

@ -105,7 +105,7 @@ class TestSuiteSeedSplit(TestSuiteBase):
if not wf:
t.passphrase(dfl_wcls.desc,wpasswd)
if spec:
from mmgen.obj import SeedSplitSpecifier
from mmgen.seedsplit import SeedSplitSpecifier
sss = SeedSplitSpecifier(spec)
pat = rf'Processing .*\b{sss.idx}\b of \b{sss.count}\b of .* id .*{sss.id!r}'
else:

View file

@ -8,8 +8,8 @@ from mmgen.common import *
class unit_test(object):
def run_test(self,name,ut):
from mmgen.seed import Seed,SeedShareList
from mmgen.obj import SeedShareIdx
from mmgen.seed import Seed
from mmgen.seedsplit import SeedShareList,SeedShareIdx
g.debug_subseed = bool(opt.verbose)