Browse Source

SubSeed: add 'nonce_start' attr; minor changes and fixes

MMGen 5 years ago
parent
commit
35d037a4da
3 changed files with 35 additions and 29 deletions
  1. 2 2
      mmgen/obj.py
  2. 32 27
      mmgen/seed.py
  3. 1 0
      test/test_py_d/ts_regtest.py

+ 2 - 2
mmgen/obj.py

@@ -586,8 +586,8 @@ class SeedID(str,Hilite,InitErrors):
 		cls.arg_chk(on_fail)
 		try:
 			if seed:
-				from mmgen.seed import Seed,SubSeed
-				assert type(seed) in (Seed,SubSeed),'not a Seed or SubSeed instance'
+				from mmgen.seed import SeedBase
+				assert issubclass(type(seed),SeedBase),'not a subclass of SeedBase'
 				from mmgen.util import make_chksum_8
 				return str.__new__(cls,make_chksum_8(seed.data))
 			elif sid:

+ 32 - 27
mmgen/seed.py

@@ -66,6 +66,7 @@ class SeedBase(MMGenObject):
 
 class SubSeedList(MMGenObject):
 	have_short = True
+	nonce_start = 0
 
 	def __init__(self,parent_seed):
 		self.member_type = SubSeed
@@ -75,11 +76,6 @@ class SubSeedList(MMGenObject):
 	def __len__(self):
 		return len(self.data['long'])
 
-	def get_params_by_ss_idx(self,ss_idx):
-		sid = self.data[ss_idx.type].key(ss_idx.idx-1)
-		idx,nonce = self.data[ss_idx.type][sid]
-		return (sid,idx,nonce)
-
 	def get_subseed_by_ss_idx(self,ss_idx_in,print_msg=False):
 		ss_idx = SubSeedIdx(ss_idx_in)
 		if print_msg:
@@ -92,21 +88,27 @@ class SubSeedList(MMGenObject):
 		if ss_idx.idx > len(self):
 			self._generate(ss_idx.idx)
 
-		sid,idx,nonce = self.get_params_by_ss_idx(ss_idx)
+		sid = self.data[ss_idx.type].key(ss_idx.idx-1)
+		idx,nonce = self.data[ss_idx.type][sid]
+		if idx != ss_idx.idx:
+			m = "{} != {}: self.data[{t!r}].key(i) does not match self.data[{t!r}][i]!"
+			die(3,m.format(idx,ss_idx.idx,t=ss_idx.type))
 
 		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 self.member_type(self,idx,nonce,length=ss_idx.type)
 
-	def get_existing_subseed_by_seed_id(self,sid):
-		for k in ('long','short') if self.have_short else ('long',):
-			if sid in self.data[k]:
-				idx,nonce = self.data[k][sid]
-				return self.member_type(self,idx,nonce,length=k)
+		seed = self.member_type(self,idx,nonce,length=ss_idx.type)
+		assert seed.sid == sid,'{} != {}: Seed ID mismatch!'.format(seed.sid,sid)
+		return seed
 
 	def get_subseed_by_seed_id(self,sid,last_idx=None,print_msg=False):
 
+		def get_existing_subseed_by_seed_id(sid):
+			for k in ('long','short') if self.have_short else ('long',):
+				if sid in self.data[k]:
+					idx,nonce = self.data[k][sid]
+					return self.member_type(self,idx,nonce,length=k)
+
 		def do_msg(subseed):
 			if print_msg:
 				qmsg('{} {} ({}:{})'.format(
@@ -119,7 +121,7 @@ class SubSeedList(MMGenObject):
 		if last_idx == None:
 			last_idx = g.subseeds
 
-		subseed = self.get_existing_subseed_by_seed_id(sid)
+		subseed = get_existing_subseed_by_seed_id(sid)
 		if subseed:
 			do_msg(subseed)
 			return subseed
@@ -129,11 +131,20 @@ class SubSeedList(MMGenObject):
 
 		self._generate(last_idx,last_sid=sid)
 
-		subseed = self.get_existing_subseed_by_seed_id(sid)
+		subseed = get_existing_subseed_by_seed_id(sid)
 		if subseed:
 			do_msg(subseed)
 			return subseed
 
+	def _collision_debug_msg(self,sid,idx,nonce,nonce_desc='nonce'):
+		slen = 'short' if sid in self.data['short'] else 'long'
+		m1 = 'add_subseed(idx={},{}):'.format(idx,slen)
+		if sid == self.parent_seed.sid:
+			m2 = 'collision with parent Seed ID {},'.format(sid)
+		else:
+			m2 = 'collision with ID {} (idx={},{}),'.format(sid,self.data[slen][sid][0],slen)
+		msg('{:30} {:46} incrementing {} to {}'.format(m1,m2,nonce_desc,nonce+1))
+
 	def _generate(self,last_idx=None,last_sid=None):
 
 		if last_idx == None:
@@ -148,19 +159,13 @@ class SubSeedList(MMGenObject):
 			last_sid = SeedID(sid=last_sid)
 
 		def add_subseed(idx,length):
-			for nonce in range(self.member_type.max_nonce): # use nonce to handle Seed ID collisions
+			for nonce in range(self.nonce_start,self.member_type.max_nonce): # use nonce to handle SeedID collisions
 				sid = make_chksum_8(self.member_type.make_subseed_bin(self,idx,nonce,length))
 				if not (sid in self.data['long'] or sid in self.data['short'] or sid == self.parent_seed.sid):
 					self.data[length][sid] = (idx,nonce)
 					return last_sid == sid
 				elif g.debug_subseed: # should get ≈450 collisions for first 1,000,000 subseeds
-					k = ('long','short')[sid in self.data['short']]
-					m1 = 'add_subseed(idx={},{}):'.format(idx,length)
-					if sid == self.parent_seed.sid:
-						m2 = 'collision with parent Seed ID {},'.format(sid)
-					else:
-						m2 = 'collision with ID {} (idx={},{}),'.format(sid,self.data[k][sid][0],k)
-					msg('{:30} {:46} incrementing nonce to {}'.format(m1,m2,nonce+1))
+					self._collision_debug_msg(sid,idx,nonce)
 			else: # must exit here, as this could leave self.data in inconsistent state
 				raise SubSeedNonceRangeExceeded('add_subseed(): nonce range exceeded')
 
@@ -213,13 +218,13 @@ class SubSeed(SeedBase):
 		self.idx = idx
 		self.nonce = nonce
 		self.ss_idx = SubSeedIdx(str(idx) + { 'long': 'L', 'short': 'S' }[length])
-		SeedBase.__init__(self,seed_bin=SubSeed.make_subseed_bin(parent_list,idx,nonce,length))
+		SeedBase.__init__(self,seed_bin=type(self).make_subseed_bin(parent_list,idx,nonce,length))
 
 	@staticmethod
 	def make_subseed_bin(parent_list,idx:int,nonce:int,length:str):
 		seed = parent_list.parent_seed
 		short = { 'short': True, 'long': False }[length]
-		# field maximums: idx: 4294967295, nonce: 65535, short (bool): 255
+		# field maximums: idx: 4294967295 (1000000), nonce: 65535 (1000), short: 255 (1)
 		scramble_key  = idx.to_bytes(4,'big',signed=False) + \
 						nonce.to_bytes(2,'big',signed=False) + \
 						short.to_bytes(1,'big',signed=False)
@@ -438,11 +443,11 @@ an empty passphrase, just hit ENTER twice.
 		while True:
 			ret = my_raw_input(p)
 			if ret:
-				if ret in g.hash_presets.keys():
+				if ret in g.hash_presets:
 					self.ssdata.hash_preset = ret
 					return ret
 				else:
-					msg('Invalid input.  Valid choices are {}'.format(', '.join(sorted(g.hash_presets.keys()))))
+					msg('Invalid input.  Valid choices are {}'.format(', '.join(g.hash_presets)))
 			else:
 				self.ssdata.hash_preset = hp
 				return hp

+ 1 - 0
test/test_py_d/ts_regtest.py

@@ -275,6 +275,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 		fn = get_file_with_ext(self._user_dir(user),'mmdat')
 		t = self.spawn('mmgen-tool',['get_subseed',subseed_idx,'wallet='+fn],no_msg=True)
 		t.passphrase('MMGen wallet',rt_pw)
+		t.expect('Hashing passphrase...done')
 		sid = t.read().strip()[:8]
 		self.usr_subsids[user][subseed_idx] = sid
 		return sid