From 60a2627c3b6c0f96f188f85b9ed58f3ce1eeea44 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Sat, 11 Apr 2026 14:09:19 -0600 Subject: [PATCH 1/9] rename refactor SureMemoer to AuthMemoer. Move timer support to Memoer so that all Memoers can be sure based on gram provided or sent not class based. --- src/hio/core/memo/__init__.py | 2 +- src/hio/core/memo/memoing.py | 327 +++++++++++++++++++++++--------- src/hio/core/udp/peermemoing.py | 2 +- src/hio/help/helping.py | 8 +- tests/core/memo/test_memoing.py | 70 +++---- 5 files changed, 279 insertions(+), 130 deletions(-) diff --git a/src/hio/core/memo/__init__.py b/src/hio/core/memo/__init__.py index f5bef6fb..469af6f0 100644 --- a/src/hio/core/memo/__init__.py +++ b/src/hio/core/memo/__init__.py @@ -6,5 +6,5 @@ from .memoing import (Versionage, Sizage, MemoDex, GramDex, AuthDex, Keyage, openMemoer, Memoer, MemoerDoer, - openSM, SureMemoer, SureMemoerDoer) + openAM, AuthMemoer, AuthMemoerDoer) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index db9ab550..fd4729d8 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -336,8 +336,10 @@ def __iter__(self): -class Memoer(hioing.Mixin): - """Memoer mixin base class to adds memogram support to a transport class. +class Memoer(Tymee): + """Memoer base class subclass of Tymee that adds memogram support to a + transport class. + Memoer supports memos composed of asynchronous memograms. Provides common methods for subclasses. @@ -345,6 +347,9 @@ class Memoer(hioing.Mixin): A memogram supports the segmentation and desegmentation of memos to respect the underlying datagram size, buffer, and fragmentation behavior. + When indicated a memoer provides reliable delivery over unreliable + datagram transports using retry tymers and acknowldged services. + Layering a reliable transaction protocol for memos on top of a memogram transport enables reliable asynchronous messaging over unreliable datagram transport protocols. @@ -421,6 +426,7 @@ class Memoer(hioing.Mixin): MaxMemoSize (int): absolute max memo size MaxGramCount (int): absolute max gram count BufSize (int): used to set default buffer size for transport datagram buffers + Tymeout (float): default timeout for retry tymer(s) if any Stubbed Attributes:: @@ -479,6 +485,22 @@ class Memoer(hioing.Mixin): inbox (deque): holds final received complete memos for testing when not overridden in subclass to further process otherwise + tymeout (float): default timeout for retry tymer(s) if any + tymers (dict): keys are tid and values are Tymers for retry tymers for + each inflight tx + + Inherited Properties (Tymee):: + + tyme (float or None): relative cycle time of associated Tymist which is + provided by calling .tymth function wrapper closure which is obtained + from Tymist.tymen(). + None means not assigned yet. + tymth (Callable or None): function wrapper closure returned by + Tymist.tymen() method. When .tymth is called it returns associated + Tymist.tyme. Provides injected dependency on Tymist cycle tyme base. + None means not assigned yet. + + Properties:: code (bytes or None): gram code for gram header when rending for tx @@ -490,7 +512,7 @@ class Memoer(hioing.Mixin): Min gram body size is one. Gram size also limited by MaxGramSize and MaxGramCount relative to MaxMemoSize. - verific (bool): True means any rx grams must be signed. + authic (bool): True means any rx grams must be signed. False otherwise echoic (bool): True means use .echos in .send and .receive to mock the transport layer for testing and debugging. @@ -512,7 +534,7 @@ class Memoer(hioing.Mixin): _code (bytes or None): see size property _curt (bool): see curt property _size (int): see size property - _verific (bool): see verific property + _authic (bool): see authic property _echoic (bool): see echoic property _keep (dict): see keep property _oid (str or None): see oid property @@ -552,6 +574,7 @@ class Memoer(hioing.Mixin): MaxGramCount = 16777215 # (2**24-1) absolute max gram count MaxGramSize = 65535 # (2**16-1) absolute max gram size overridden in subclass BufSize = 65535 # (2**16-1) default buffersize + Tymeout = 0.0 # tymeout in seconds, tymeout of 0.0 means ignore tymeout @classmethod def _encodeOID(cls, raw, code='B'): @@ -889,6 +912,7 @@ def _decodeSGN(cls, qb64): def __init__(self, *, + tymeout=None, name=None, bc=None, bs=None, @@ -904,7 +928,7 @@ def __init__(self, *, code=MemoDex.MemoGram, curt=False, size=None, - verific=False, + authic=False, echoic=False, keep=None, oid=None, @@ -968,7 +992,7 @@ def __init__(self, *, Min gram body size is one. Gram size also limited by MaxGramSize and MaxGramCount relative to MaxMemoSize. - verific (bool): True means any rx grams must be signed. + authic (bool): True means any rx grams must be signed. False otherwise echoic (bool): True means use .echos in .send and .receive to mock the transport layer for testing and debugging. @@ -983,6 +1007,7 @@ def __init__(self, *, this is a lightweight mechanism that should be overridden in subclass for real world key management. oid (str or None): own oid defaults used to lookup keys to sign on tx + tymeout (float): default for retry tymer if any """ @@ -1004,9 +1029,13 @@ def __init__(self, *, self.code = code self.curt = curt self.size = size # property sets size given .code and constraints - self._verific = True if verific else False + self._authic = True if authic else False + + super().__init__(name=name, bc=bc, bs=bs, **kwa) - super(Memoer, self).__init__(name=name, bc=bc, bs=bs, **kwa) + self.tymeout = tymeout if tymeout is not None else self.Tymeout + self.tymers = {} + #Tymer(tymth=self.tymth, duration=self.tymeout) # retry tymer if not hasattr(self, "name"): # stub so mixin works in isolation. self.name = name if name is not None else "main" # mixed with subclass should provide this. @@ -1110,13 +1139,13 @@ def size(self, size): @property - def verific(self): - """Property getter for ._verific + def authic(self): + """Property getter for ._authic Returns: bool: True means any rx grams must be signed; False otherwise. """ - return self._verific + return self._authic @property def echoic(self): @@ -1186,6 +1215,25 @@ def close(self): self.opened = False + def wind(self, tymth): + """ + Inject new tymist.tymth as new ._tymth. Changes tymist.tyme base. + Updates winds .tymer .tymth + """ + super().wind(tymth) # wind Tymee superclass + for tid, tymer in self.tymers.items(): + tymer.wind(tymth) + + + def serviceTymers(self): + """Service all retry tymers + + Must be overriden in subclass. + This is a stub. + """ + pass + + def wiff(self, gram): """Determines encoding of gram bytes header when parsing grams. The encoding maybe either base2 or base64. @@ -1344,6 +1392,129 @@ def verify(self, oid, sig, ser): return True + def pickNew(self, gram): + """Strips header from gram bytearray leaving only gram body in gram and + returns (mid, gn, gc). Raises MemoerError if unrecognized or invalid + header this includes signature verification failure when signed. + + When signed the signature is computed on the domain qb64b or qb2 that + the packet is transmitted in. Note the packet itself is not concatenation + composable as per CESR only the header elements and sig are CESR 24 bit + aligned so there is no enmass conversion of concatenated memograms. + This is ok for a datagram segmentation that is decidedly not a stream. + + Returns: + result (tuple): tuple of form: + (mid: str, oid: str, gn: int, gc: int or None) where: + mid is fully qualified memoID, + oid is origin ID used to look up signature verification key, + gn is gram number, + gc is gram count. + When first gram (zeroth) returns (mid, oid, 0, gc). + When other gram returns (mid, oid, gn, None) + When code has empty oid then oid is None + Otherwise raises MemoerError error. + + When valid recognized header, strips header bytes from front of gram + leaving the gram body part bytearray. + + Parameters: + gram (bytearray): memo gram from which to parse and strip its header. + + + """ + curt = self.wiff(gram) # rx gram encoding True=B2 or False=B64 + if curt: # base2 binary encoding in triplets + if len(gram) < 4: # assumes len(code) must be 4 + raise hioing.MemoerError(f"Gram length={len(gram)} to short to " + f"hold code.") + code = helping.codeB2ToB64(gram, 4) # code is first 4 sextets + if self.authic and code not in self.Sodex: # must be signed + raise hioing.MemoerError(f"Unsigned gram {code =} when signed " + f"required.") + + hz, mz, xz, nz, zz, az, oz = self.Sizes[code] # hz mz xz nz zz az oz + pz = (3 - ((mz) % 3)) % 3 # net pad size for mid + cms = 3 * (hz + mz) // 4 # hz + mz are aligned on 24 bit boundary + oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 + nz = 3 * nz // 4 # encoding b2 means head part sizes smaller by 3/4 + zz = 3 * zz // 4 # encoding b2 means head part sizes smaller by 3/4 + xz = 3 * xz // 4 # encoding b2 means head part sizes smaller by 3/4 + az = 3 * az // 4 # encoding b2 means head part sizes smaller by 3/4 + + if len(gram) < (oz + 1): # not big enough for non-first gram + raise hioing.MemoerError(f"Not enough rx bytes for b2 gram" + f" < {oz + 1}.") + + mid = encodeB64(gram[:cms]) # convert to b64b with prefix code + oid = encodeB64(gram[cms:cms+xz]) # convert to b64b + neck = gram[cms+xz:cms+xz+nz] # bytearray to bytes short part of neck + gn = int.from_bytes(neck) # gram number convert to int + #neck = encodeB64(neck) # convert to b64b + #head = mid + oid + neck # bytes + if gn == 0: # first (zeroth) gram so long neck + if len(gram) < oz + nz + 1: + raise hioing.MemoerError(f"Not enough rx bytes for b2 " + f"gram < {oz + nz + 1}.") + lneck = bytes(gram[cms+xz+nz:cms+xz+2*nz]) # bytearray to bytes + gc = int.from_bytes(lneck) # gram count convert to int + lneck = encodeB64(lneck) # convert to b64b + sig = encodeB64(gram[-az if az else len(gram):]) # last ss bytes are signature + del gram[-az if az else len(gram):] # strip sig if any + sgram = bytes(gram[:]) # signed part make bytes copy to sign + del gram[:oz-az+nz] # strip off fore head leaving body in gram + #head += lneck + else: # non-zeroth gram so short neck + gc = None + sig = encodeB64(gram[-az if az else len(gram):]) + del gram[-az if az else len(gram):] # strip sig if any + sgram = bytes(gram[:]) # signed part make bytes copy to sign + del gram[:oz-az] # strip of fore head leaving body in gram + + else: # base64 text encoding in quadlets + if len(gram) < 2: # assumes len(code) must be 2 + raise hioing.MemoerError(f"Gram length={len(gram)} to short to " + f"hold code.") + code = gram[:2].decode() # assumes len(code) must be 2 + if self.authic and code not in self.Sodex: # must be signed + raise hioing.MemoerError(f"Unsigned gram {code =} when signed " + f"required.") + hz, mz, xz, nz, zz, az, oz = self.Sizes[code] # hz mz xz nz zz az oz + + if len(gram) < (oz + 1): # not big enough for non-first gram + raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" + f" < {oz + 1}.") + + mid = bytes(gram[:hz+mz]) # bytearray to bytes qb64b with prefix + oid = bytes(gram[hz+mz:hz+mz+xz]) #bytearry to bytes qb64b convert to qb64 + neck = bytes(gram[hz+mz+xz:hz+mz+xz+nz]) # qb64b short part of neck + gn = helping.b64ToInt(neck) + #head = mid + oid + neck # bytes + if gn == 0: # first (zeroth) gram so long neck + if len(gram) < oz + nz + 1: + raise hioing.MemoerError(f"Not enough rx bytes for b64 " + f"gram < {oz + nz + 1}.") + lneck = bytes(gram[hz+mz+xz+nz:hz+mz+xz+2*nz]) # bytearray to bytes copy + gc = helping.b64ToInt(lneck) # convert to int + sig = bytes(gram[-az if az else len(gram):]) # last az bytes signature + del gram[-az if az else len(gram):] # strip sig if any + sgram = bytes(gram[:]) # signed part make bytes copy to sign + del gram[:oz-az+nz] # strip of fore head leaving body in gram + #head += lneck # bytes + else: # non-zeroth gram short neck + gc = None + sig = bytes(gram[-az if az else len(gram):]) + del gram[-az if az else len(gram):] # strip sig if any + sgram = bytes(gram[:]) # signed part make bytes copy to sign + del gram[:oz-az] # strip of fore head leaving body in gram + + if sig: # signature not empty + #sgram = head + bytes(gram) # bytearray to bytes + self.verify(oid, sig, sgram) # raises MemoerVerifyError if invalid + + return (mid.decode(), oid.decode() if oid else None, gn, gc) + + def pick(self, gram): """Strips header from gram bytearray leaving only gram body in gram and returns (mid, gn, gc). Raises MemoerError if unrecognized or invalid @@ -1376,12 +1547,12 @@ def pick(self, gram): """ curt = self.wiff(gram) # rx gram encoding True=B2 or False=B64 - if curt: # base2 binary encoding + if curt: # base2 binary encoding in triplets if len(gram) < 2: # assumes len(code) must be 2 raise hioing.MemoerError(f"Gram length={len(gram)} to short to " f"hold code.") code = helping.codeB2ToB64(gram, 2) # assumes len(code) must be 2 - if self.verific and code not in self.Sodex: # must be signed + if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") @@ -1423,12 +1594,12 @@ def pick(self, gram): sgram = bytes(gram[:]) # signed part make bytes copy to sign del gram[:oz-az] # strip of fore head leaving body in gram - else: # base64 text encoding + else: # base64 text encoding in quadlets if len(gram) < 2: # assumes len(code) must be 2 raise hioing.MemoerError(f"Gram length={len(gram)} to short to " f"hold code.") code = gram[:2].decode() # assumes len(code) must be 2 - if self.verific and code not in self.Sodex: # must be signed + if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") hz, mz, xz, nz, zz, az, oz = self.Sizes[code] # hz mz xz nz zz az oz @@ -1467,6 +1638,7 @@ def pick(self, gram): return (mid.decode(), oid.decode() if oid else None, gn, gc) + def receive(self, *, echoic=False) -> (bytes, str or tuple or None): """Attempts to receive bytes from remote source. @@ -2067,6 +2239,7 @@ def serviceLocal(self): """Service the local Peer's receive and transmit queues """ self.serviceReceives() + self.serviceTymers() self.serviceTxGrams() @@ -2074,6 +2247,7 @@ def serviceAllOnce(self): """Service all Rx and Tx Once (non-greedy) """ self.serviceAllRxOnce() + self.serviceTymers() self.serviceAllTxOnce() @@ -2081,6 +2255,7 @@ def serviceAll(self): """Service all Rx and Tx (greedy) """ self.serviceAllRx() + self.serviceTymers() self.serviceAllTx() service = serviceAll # alias @@ -2121,7 +2296,11 @@ def openMemoer(cls=None, name="test", **kwa): class MemoerDoer(doing.Doer): - """Memoer Doer for reliable transports that do not require retry tymers. + """Memoer Doer for both reliable and unreliable transports. + Doer is a subclass of Tymee and is wound. + + Reliable do not require retry tymers + Unreliable require retry tymers for acknowldged services. See Doer for inherited attributes, properties, and methods. @@ -2137,10 +2316,18 @@ def __init__(self, peer, **kwa): Parameters: peer (Peer): is Memoer Subclass instance """ - super(MemoerDoer, self).__init__(**kwa) + super().__init__(**kwa) self.peer = peer + def wind(self, tymth): + """Inject new tymist.tymth as new ._tymth. Changes tymist.tyme base. + Updates winds .tymer .tymth + """ + super().wind(tymth) # wind this doer + self.peer.wind(tymth) # wind its peer + + def enter(self, *, temp=None): """Do 'enter' context actions. Override in subclass. Not a generator method. Set up resources. Comparable to context manager enter. @@ -2150,9 +2337,13 @@ def enter(self, *, temp=None): None means ignore parameter value. Use self.temp Inject temp or self.temp into file resources here if any + + Doist or DoDoer winds its doers on enter """ - # inject temp into file resources here if any - self.peer.reopen(temp=temp) + if self.tymth: # Doer tymth has been inited so wind .peer + self.peer.wind(self.tymth) # Doist or DoDoer winds its doers on enter + + self.peer.reopen(temp=temp) # inject temp into file resources here if any def recur(self, tyme): @@ -2166,10 +2357,9 @@ def exit(self): -class SureMemoer(Tymee, Memoer): - """SureMemoer mixin base class that supports reliable (sure) memo delivery - over unreliable datagram transports. These need retry tymers and acknowledged - delivery services. +class AuthMemoer(Memoer): + """AuthMemoer mixin base class that enforces authenticated memo delivery. + Subclass of Tymee and Memoer Inherited Class Attributes (Memoer):: @@ -2184,9 +2374,6 @@ class SureMemoer(Tymee, Memoer): MaxMemoSize (int): absolute max memo size MaxGramCount (int): absolute max gram count BufSize (int): used to set default buffer size for transport datagram buffers - - Class Attributes:: - Tymeout (float): default timeout for retry tymer(s) if any Inherited Stubbed Attributes (Memoer):: @@ -2242,9 +2429,6 @@ class SureMemoer(Tymee, Memoer): for (gram, dst) echos (deque): holding echo receive duples for testing. Each duple of form: (gram: bytes, dst: str). - - Attributes:: - tymeout (float): default timeout for retry tymer(s) if any tymers (dict): keys are tid and values are Tymers for retry tymers for each inflight tx @@ -2271,7 +2455,7 @@ class SureMemoer(Tymee, Memoer): Min gram body size is one. Gram size also limited by MaxGramSize and MaxGramCount relative to MaxMemoSize. - verific (bool): True means any rx grams must be signed. + authic (bool): True means any rx grams must be signed. False otherwise echoic (bool): True means use .echos in .send and .receive to mock the transport layer for testing and debugging. @@ -2289,67 +2473,25 @@ class SureMemoer(Tymee, Memoer): oid (str or None): own oid defaults used to lookup keys to sign on tx """ - Tymeout = 0.0 # tymeout in seconds, tymeout of 0.0 means ignore tymeout - def __init__(self, *, tymeout=None, code=MemoDex.AuthMemoGram, verific=True, **kwa): - """ - Initialization method for instance. - Inherited Parameters: - see superclass - Parameters: - tymeout (float): default for retry tymer if any + def __init__(self, *, code=MemoDex.AuthMemoGram, authic=True, **kwa): + """Initialization method for instance. - """ - super(SureMemoer, self).__init__(code=code, verific=verific, **kwa) - self.tymeout = tymeout if tymeout is not None else self.Tymeout - self.tymers = {} - #Tymer(tymth=self.tymth, duration=self.tymeout) # retry tymer - - - def wind(self, tymth): - """ - Inject new tymist.tymth as new ._tymth. Changes tymist.tyme base. - Updates winds .tymer .tymth - """ - super(SureMemoer, self).wind(tymth) # wind Tymee superclass - for tid, tymer in self.tymers.items(): - tymer.wind(tymth) - - def serviceTymers(self): - """Service all retry tymers - - Must be overriden in subclass. - This is a stub. - """ - pass - - - def serviceLocal(self): - """Service the local Peer's receive and transmit queues - """ - self.serviceReceives() - self.serviceTxGrams() + Force code to Auth type + Force authic to True + Inherited Parameters:: + see superclass - def serviceAllOnce(self): - """Service all Rx and Tx Once (non-greedy) """ - self.serviceAllRxOnce() - self.serviceTymers() - self.serviceAllTxOnce() + super().__init__(code=code, authic=authic, **kwa) - def serviceAll(self): - """Service all Rx and Tx (greedy) - """ - self.serviceAllRx() - self.serviceTymers() - self.serviceAllTx() @contextmanager -def openSM(cls=None, name="test", **kwa): +def openAM(cls=None, name="test", **kwa): """Wrapper to create and open SureMemoer instances When used in with statement block, calls .close() on exit of with block @@ -2359,17 +2501,17 @@ def openSM(cls=None, name="test", **kwa): Enables management of transport by name. Usage:: - with openSM() as peer: + with openAM() as peer: peer.receive() - with openSM(cls=SureMemoerSub) as peer: + with openAM(cls=SureMemoerSub) as peer: peer.receive() """ peer = None if cls is None: - cls = SureMemoer + cls = AuthMemoer try: peer = cls(name=name, **kwa) peer.reopen() @@ -2381,15 +2523,18 @@ def openSM(cls=None, name="test", **kwa): peer.close() -class SureMemoerDoer(doing.Doer): - """SureMemoerDoer Doer to provide reliable delivery over unreliable - datagram transports. This requires retry tymers and acknowldged services. +class AuthMemoerDoer(doing.Doer): + """AuthMemoerDoer Doer to ensure authenticated/signed memograms. + For both reliable and unreliable transports. + Reliable do not require retry tymers + Unreliable require retry tymers for acknowldged services. See Doer for inherited attributes, properties, and methods. + Doer is a subclass of Tymee and is wound. Attributes:: - .peer (SureMemoer) is underlying transport instance subclass of SureMemoer + .peer (AuthMemoer) is underlying transport instance subclass of AuthMemoer """ @@ -2399,20 +2544,18 @@ def __init__(self, peer, **kwa): Parameters: peer (SureMemoer): subclass instance """ - super(SureMemoerDoer, self).__init__(**kwa) + super().__init__(**kwa) self.peer = peer - def wind(self, tymth): """Inject new tymist.tymth as new ._tymth. Changes tymist.tyme base. Updates winds .tymer .tymth """ - super(SureMemoerDoer, self).wind(tymth) # wind this doer + super().wind(tymth) # wind this doer self.peer.wind(tymth) # wind its peer - def enter(self, *, temp=None): """Do 'enter' context actions. Override in subclass. Not a generator method. Set up resources. Comparable to context manager enter. @@ -2425,7 +2568,7 @@ def enter(self, *, temp=None): Doist or DoDoer winds its doers on enter """ - if self.tymth: + if self.tymth: # Doer tymth has been inited so wind .peer self.peer.wind(self.tymth) # Doist or DoDoer winds its doers on enter self.peer.reopen(temp=temp) # inject temp into file resources here if any diff --git a/src/hio/core/udp/peermemoing.py b/src/hio/core/udp/peermemoing.py index 7db41c50..97a6496b 100644 --- a/src/hio/core/udp/peermemoing.py +++ b/src/hio/core/udp/peermemoing.py @@ -89,7 +89,7 @@ class PeerMemoer(Peer, Memoer): code (bytes | None): gram code for gram header when rending for tx curt (bool): True means when rending for tx encode header in base2; False means when rending for tx encode header in base64 size (int): gram size when rending for tx. - verific (bool): True means any rx grams must be signed; False otherwise + authic (bool): True means any rx grams must be signed; False otherwise echoic (bool): True means use .echos in .send and .receive to mock transport. keep (dict): labels are oids and values are Keyage instances. oid (str|None): own oid defaults used to lookup keys to sign on tx diff --git a/src/hio/help/helping.py b/src/hio/help/helping.py index c563baf0..1f34e00a 100644 --- a/src/hio/help/helping.py +++ b/src/hio/help/helping.py @@ -549,11 +549,11 @@ def codeB64ToB2(s): def codeB2ToB64(b, l): - """Convert l sextets from base2 b to base64 str + """Converts first l sextets of base2 b bytes to base64 str and returns - Returns: + Returns:: code (str): conversion (encode) of l Base2 sextets from front of b - to Base64 chars. + to Base64 chars. One char for each of l sextets from front (left) of b. This is useful for encoding as code characters, sextets from the front of @@ -561,7 +561,7 @@ def codeB2ToB64(b, l): and l=4. Both require 3 bytes in b. Trailing pad bits are removed so returned sextets as characters are right aligned . - Parameters: + Parameters:: b (bytes | str): target from which to nab sextets l (int): number of sextets to convert from front of b """ diff --git a/tests/core/memo/test_memoing.py b/tests/core/memo/test_memoing.py index 3a0a40a5..2181ecf6 100644 --- a/tests/core/memo/test_memoing.py +++ b/tests/core/memo/test_memoing.py @@ -286,7 +286,7 @@ def test_memoer_sign_verify(): assert not peer.curt assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz xz nz zz az oz assert peer.size == peer.MaxGramSize - assert not peer.verific + assert not peer.authic assert not peer.echoic assert peer.keep == keep assert peer.oid == oid @@ -342,11 +342,15 @@ def test_memoer_basic(): assert not peer.curt assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz assert peer.size == peer.MaxGramSize - assert not peer.verific + assert not peer.authic assert not peer.echoic assert peer.keep == dict() assert peer.oid is None + assert peer.tymeout == 0.0 + assert peer.tymers == {} + + peer.reopen() assert peer.opened == True @@ -492,7 +496,7 @@ def test_memoer_small_gram_size(): assert not peer.curt assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz assert peer.size == 33 # can't be smaller than head + neck + 1 - assert not peer.verific + assert not peer.authic assert not peer.echoic assert peer.keep == dict() assert peer.oid is None @@ -667,7 +671,7 @@ def test_memoer_multiple(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert not peer.verific + assert not peer.authic assert not peer.echoic assert peer.keep == dict() assert peer.oid is None @@ -746,7 +750,7 @@ def test_memoer_multiple_echoic_service_tx_rx(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert not peer.verific + assert not peer.authic assert peer.echoic assert peer.keep == dict() assert peer.oid is None @@ -800,7 +804,7 @@ def test_memoer_multiple_echoic_service_all(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert not peer.verific + assert not peer.authic assert peer.echoic assert peer.keep == dict() assert peer.oid is None @@ -858,7 +862,7 @@ def test_memoer_basic_signed(): assert not peer.curt assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz xz nz zz az oz assert peer.size == peer.MaxGramSize - assert not peer.verific + assert not peer.authic assert not peer.echoic assert peer.keep == keep assert peer.oid == oid @@ -1055,7 +1059,7 @@ def test_memoer_multiple_signed(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert not peer.verific # force rx must be signed + assert not peer.authic # force rx must be signed assert not peer.echoic assert peer.keep == keep assert peer.oid == oid @@ -1182,7 +1186,7 @@ def test_memoer_multiple_signed(): def test_memoer_verific(): - """Test Memoer class with verific (signed required) + """Test Memoer class with authic (signed required) """ salt = b"ABCDEFGHIJKLMNOP" try: @@ -1193,7 +1197,7 @@ def test_memoer_verific(): oid = list(keep.keys())[0] assert oid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' - peer = memoing.Memoer(verific=True, keep=keep, oid=oid) + peer = memoing.Memoer(authic=True, keep=keep, oid=oid) assert peer.name == "main" assert peer.opened == False assert peer.bc is None @@ -1202,7 +1206,7 @@ def test_memoer_verific(): assert not peer.curt assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz assert peer.size == peer.MaxGramSize - assert peer.verific + assert peer.authic assert not peer.echoic assert peer.keep == keep assert peer.oid is oid @@ -1275,9 +1279,9 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): vidBeta = list(keep.keys())[1] assert vidBeta == 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' - # verific forces rx memos to be signed or dropped + # authic forces rx memos to be signed or dropped # to force signed tx then use Signed code - peer = memoing.Memoer(code=MemoDex.AuthMemoGram, size=170, verific=True, + peer = memoing.Memoer(code=MemoDex.AuthMemoGram, size=170, authic=True, echoic=True, keep=keep, oid=oid) assert peer.size == 170 assert peer.name == "main" @@ -1286,7 +1290,7 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.verific + assert peer.authic assert peer.echoic assert peer.keep == keep assert peer.oid == oid @@ -1374,6 +1378,8 @@ def test_open_memoer(): assert zeta.opened assert zeta.name == 'zeta' + assert zeta.tymeout == 0.0 + assert zeta.tymers == {} assert not zeta.opened @@ -1410,8 +1416,8 @@ def test_memoer_doer(): -def test_sure_memoer_basic(): - """Test SureMemoer class basic +def test_auth_memoer_basic(): + """Test AuthMemoer class basic """ try: keep = _setupKeep() # uses default salt @@ -1424,7 +1430,7 @@ def test_sure_memoer_basic(): oidBeta = list(keep.keys())[1] assert oidBeta == 'DJb1Z0pHx36MCOuIHWR4yPxfIiBxVzg6UCamv8fAN8gH' - peer = memoing.SureMemoer(echoic=True, keep=keep, oid=oid) + peer = memoing.AuthMemoer(echoic=True, keep=keep, oid=oid) assert peer.size == 65535 assert peer.name == "main" assert peer.opened == False @@ -1432,7 +1438,7 @@ def test_sure_memoer_basic(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.verific + assert peer.authic assert peer.echoic assert peer.keep == keep assert peer.oid == oid @@ -1566,7 +1572,7 @@ def test_open_sm(): except MemoerError as ex: return - with (memoing.openSM(name='zeta') as zeta): + with (memoing.openAM(name='zeta') as zeta): assert zeta.opened assert zeta.name == 'zeta' @@ -1579,8 +1585,8 @@ def test_open_sm(): """ End Test """ -def test_sure_memoer_multiple_echoic_service_all(): - """Test SureMemoer class with small gram size and multiple queued memos signed +def test_auth_memoer_multiple_echoic_service_all(): + """Test AuthMemoer class with small gram size and multiple queued memos signed using echos for transport """ try: @@ -1594,10 +1600,10 @@ def test_sure_memoer_multiple_echoic_service_all(): oidBeta = list(keep.keys())[1] assert oidBeta == 'DJb1Z0pHx36MCOuIHWR4yPxfIiBxVzg6UCamv8fAN8gH' - # verific forces rx memos to be signed or dropped - # to force signed tx then use Signed code + # authic forces rx memos to be authenticated/signed or dropped + # to force signed tx then use Auth type header code - with memoing.openSM(size=170, echoic=True, keep=keep, oid=oid) as peer: + with memoing.openAM(size=170, echoic=True, keep=keep, oid=oid) as peer: assert peer.size == 170 assert peer.name == "test" assert peer.opened == True @@ -1605,7 +1611,7 @@ def test_sure_memoer_multiple_echoic_service_all(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.verific + assert peer.authic assert peer.echoic assert peer.keep == keep assert peer.oid is oid @@ -1684,8 +1690,8 @@ def test_sure_memoer_multiple_echoic_service_all(): """ End Test """ -def test_sure_memoer_doer(): - """Test SureMemoerDoer class +def test_auth_memoer_doer(): + """Test AuthMemoerDoer class """ try: keep = _setupKeep() # uses default salt @@ -1702,9 +1708,9 @@ def test_sure_memoer_doer(): assert doist.limit == limit == 0.125 assert doist.doers == [] - peer = memoing.SureMemoer() + peer = memoing.AuthMemoer() - tmgdoer = memoing.SureMemoerDoer(peer=peer) + tmgdoer = memoing.AuthMemoerDoer(peer=peer) assert tmgdoer.peer == peer assert not tmgdoer.peer.opened assert tmgdoer.tock == 0.0 # ASAP @@ -1741,8 +1747,8 @@ def test_sure_memoer_doer(): test_memoer_multiple_signed_verific_echoic_service_all() test_open_memoer() test_memoer_doer() - test_sure_memoer_basic() + test_auth_memoer_basic() test_open_sm() - test_sure_memoer_multiple_echoic_service_all() - test_sure_memoer_doer() + test_auth_memoer_multiple_echoic_service_all() + test_auth_memoer_doer() From 65e113ca9cebff2466590811d95f1d5b98051c31 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Sat, 11 Apr 2026 14:22:07 -0600 Subject: [PATCH 2/9] more refactor cleanup --- src/hio/core/memo/memoing.py | 3 --- src/hio/core/udp/peermemoing.py | 36 +++++++++++++++++++++++---------- src/hio/core/uxd/peermemoing.py | 2 -- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index fd4729d8..7fca3dfd 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -484,13 +484,11 @@ class Memoer(Tymee): form: (gram: bytes, dst: str). inbox (deque): holds final received complete memos for testing when not overridden in subclass to further process otherwise - tymeout (float): default timeout for retry tymer(s) if any tymers (dict): keys are tid and values are Tymers for retry tymers for each inflight tx Inherited Properties (Tymee):: - tyme (float or None): relative cycle time of associated Tymist which is provided by calling .tymth function wrapper closure which is obtained from Tymist.tymen(). @@ -502,7 +500,6 @@ class Memoer(Tymee): Properties:: - code (bytes or None): gram code for gram header when rending for tx curt (bool): True means when rending for tx encode header in base2 False means when rending for tx encode header in base64 diff --git a/src/hio/core/udp/peermemoing.py b/src/hio/core/udp/peermemoing.py index 97a6496b..583b58c7 100644 --- a/src/hio/core/udp/peermemoing.py +++ b/src/hio/core/udp/peermemoing.py @@ -20,9 +20,7 @@ class PeerMemoer(Peer, Memoer): Inherited Class Attributes: - BufSize (int): used to set default buffer size for transport datagram buffers MaxGramSize (int): max gram bytes for this transport - Version (Versionage): default version namedtuple of form (major: int, minor: int) Codex (GramDex): dataclass ref to gram codex Codes (dict): maps codex names to codex values @@ -31,6 +29,8 @@ class PeerMemoer(Peer, Memoer): Sizes (dict): gram head part sizes Sizage instances keyed by gram codes MaxMemoSize (int): absolute max memo size MaxGramCount (int): absolute max gram count + BufSize (int): used to set default buffer size for transport datagram buffers + Tymeout (float): default timeout for retry tymer(s) if any Inherited Attributes: name (str): unique identifier of peer for management purposes @@ -79,9 +79,23 @@ class PeerMemoer(Peer, Memoer): for (gram, dst) echos (deque): holding echo receive duples for testing. Each duple of form: (gram: bytes, dst: str). + inbox (deque): holds final received complete memos for testing when not + overridden in subclass to further process otherwise + tymeout (float): default timeout for retry tymer(s) if any + tymers (dict): keys are tid and values are Tymers for retry tymers for + each inflight tx Inherited Properties: + tyme (float or None): relative cycle time of associated Tymist which is + provided by calling .tymth function wrapper closure which is obtained + from Tymist.tymen(). + None means not assigned yet. + tymth (Callable or None): function wrapper closure returned by + Tymist.tymen() method. When .tymth is called it returns associated + Tymist.tyme. Provides injected dependency on Tymist cycle tyme base. + None means not assigned yet. + host (str): element of .ha duple port (int): element of .ha duple path (tuple): .ha (host, port) alias to match .uxd @@ -94,15 +108,15 @@ class PeerMemoer(Peer, Memoer): keep (dict): labels are oids and values are Keyage instances. oid (str|None): own oid defaults used to lookup keys to sign on tx - Notes: - - size: first gram size = over head size + neck size + body size; - subsequent grams use over head size + body size; gram body size is at - least one and is limited by MaxGramSize and MaxGramCount relative to - MaxMemoSize. - - echoic: each entry in .echos is (gram: bytes, src: str); default echo - is (b'', None); when False it may be overridden by method parameter. - - keep: Keyage is namedtuple("Keyage", "sigkey verkey") with private - signing key sigkey and public verifying key verkey. + Notes:: + - size: first gram size = over head size + neck size + body size; + subsequent grams use over head size + body size; gram body size is at + least one and is limited by MaxGramSize and MaxGramCount relative to + MaxMemoSize. + - echoic: each entry in .echos is (gram: bytes, src: str); default echo + is (b'', None); when False it may be overridden by method parameter. + - keep: Keyage is namedtuple("Keyage", "sigkey verkey") with private + signing key sigkey and public verifying key verkey. """ diff --git a/src/hio/core/uxd/peermemoing.py b/src/hio/core/uxd/peermemoing.py index 2f768e22..1f8011cc 100644 --- a/src/hio/core/uxd/peermemoing.py +++ b/src/hio/core/uxd/peermemoing.py @@ -17,12 +17,10 @@ class PeerMemoer(Peer, Memoer): """Class for sending memograms over UXD transport Mixin base classes Peer and Memoer to attain memogram over uxd transport. - Inherited Class Attributes: See Peer Class See memoing.Memoer Class - Inherited Attributes: See Peer Class See Memoer Class From 19d19734235fea0e960a5379064c681253d89ea2 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Sun, 12 Apr 2026 10:24:18 -0600 Subject: [PATCH 3/9] refactor xz to vz for VID verifier id size --- src/hio/core/memo/memoing.py | 209 ++++++++++++++-------------- tests/core/memo/test_memoing.py | 54 +++---- tests/core/udp/test_peer_memoing.py | 6 +- tests/core/uxd/test_peer_memoing.py | 4 +- 4 files changed, 135 insertions(+), 138 deletions(-) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index 7fca3dfd..ae9fa327 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -94,7 +94,7 @@ HeadCode hc = b'__' HeadCodeSize hcs = 2 MemoIDSize mis = 22 - Gram OID xz =0 + Gram VID vz =0 GramNumSize gns = 4 GramCntSize gcs = 4 GramHeadSize ghs = 28 short @@ -107,7 +107,7 @@ HeadCode hc = b'_-' HeadCodeSize hcs = 2 MemoIDSize mis = 22 - Gram OID xz = 44 + Gram VID vz = 44 GramNumSize gns = 4 GramCntSize gcs = 4 GramHeadSize ghs = 28 + 44 = 72 short @@ -120,8 +120,8 @@ Sizes:: { - '__': Sizage(hz=2, mz=22, xz=0, nz=4, zz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, xz=44, nz=4, zz=0, az=88, oz=160), + '__': Sizage(hz=2, mz=22, vz=0, nz=4, zz=0, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, vz=44, nz=4, zz=0, az=88, oz=160), } Sizing: @@ -238,17 +238,18 @@ """Sizage: namedtuple for gram header part size entries in Memoer code tables hz is the serialization hard code part size int number of chars in hard code part mz is the mid (memo ID) part size int number of chars in the mid part -xz is the oid (origin ID) part size int number of chars in the oid part + nz is the gram num (neck) part size int number of chars for the gram number zz is the gram count part size int count of grams in memo. It only appears in the zeroth gram in a memo. +vz is the vid (verifier id, origin ID) part size int number of chars in the vid part az is the authenticator (signature) part size int number of chars in the auth part the authenticator part is discontinuously attached after the body part but its size is included in the overhead size computation for the body size oz is the overhead size int number of chars:: overhead is header with short neck and authenticator - oz = hz + mz + xz + nz + zz+ az + oz = hz + mz + + nz + vz + az zeroth overhead is header with long neck relative to short neck zoz = oz (short) + zz (note zz in zeroth gram = nz otherwise 0) @@ -258,7 +259,7 @@ The zeroth gram has a long neck consiting of two nz sized fields All other grams have a short neck consisting of 1 nz sized field """ -Sizage = namedtuple("Sizage", "hz mz xz nz zz az oz") +Sizage = namedtuple("Sizage", "hz mz vz nz zz az oz") @dataclass(frozen=True) @@ -498,7 +499,6 @@ class Memoer(Tymee): Tymist.tyme. Provides injected dependency on Tymist cycle tyme base. None means not assigned yet. - Properties:: code (bytes or None): gram code for gram header when rending for tx curt (bool): True means when rending for tx encode header in base2 @@ -541,20 +541,20 @@ class Memoer(Tymee): Codes = asdict(Codex) # map code name to code Names = {val : key for key, val in Codes.items()} # invert map code to code name Sodex = AuthDex # signed gram codex - # dict of gram header part sizes keyed by gram codes: hz mz xz nz zz az oz + # dict of gram header part sizes keyed by gram codes: hz mz vz nz zz az oz Sizes = { - '__': Sizage(hz=2, mz=22, xz=0, nz=4, zz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, xz=44, nz=4, zz=0, az=88, oz=160), - '1AAQ': Sizage(hz=4, mz=24, xz=0, nz=4, zz=4, az=0, oz=36), - '1AAR': Sizage(hz=4, mz=24, xz=0, nz=4, zz=0, az=0, oz=32), - '1AAS': Sizage(hz=4, mz=24, xz=44, nz=4, zz=4, az=88, oz=168), - '1AAT': Sizage(hz=4, mz=24, xz=44, nz=4, zz=0, az=88, oz=164), - '1AAU': Sizage(hz=4, mz=24, xz=0, nz=4, zz=4, az=0, oz=36), - '1AAV': Sizage(hz=4, mz=24, xz=0, nz=4, zz=0, az=0, oz=32), - '1AAW': Sizage(hz=4, mz=24, xz=44, nz=4, zz=4, az=88, oz=168), - '1AAX': Sizage(hz=4, mz=24, xz=44, nz=4, zz=0, az=88, oz=164), - '1AAY': Sizage(hz=4, mz=24, xz=0, nz=4, zz=0, az=0, oz=32), - '1AAZ': Sizage(hz=4, mz=24, xz=44, nz=4, zz=0, az=88, oz=164), + '__': Sizage(hz=2, mz=22, vz=0, nz=4, zz=0, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, vz=44, nz=4, zz=0, az=88, oz=160), + '1AAQ': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAR': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAS': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), + '1AAT': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=88, oz=120), + '1AAU': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAV': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAW': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), + '1AAX': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=88, oz=120), + '1AAY': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAZ': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), } Pairs = dict() # pair the zeroth code with the non-zeroth code of same type @@ -605,9 +605,9 @@ def _encodeOID(cls, raw, code='B'): qb64 = code + b64.decode() # fully qualified base64 oid with prefix code - _, _, xz, _, _, _, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz xz nz zz az oz - if len(qb64) != xz: - hioing.MemoerError(f"Invalid oid qb64 size={len(qb64) != {xz}}") + _, _, vz, _, _, _, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz zz az oz + if len(qb64) != vz: + hioing.MemoerError(f"Invalid oid qb64 size={len(qb64) != {vz}}") return qb64 # fully qualified base64 oid with prefix code @@ -855,7 +855,7 @@ def _encodeSGN(cls, raw, code='0B'): qb64 = code + b64.decode() # fully qualified base64 with prefixqb64de - _, _, _, _, _, az, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz xz nz zz az oz + _, _, _, _, _, az, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz zz az oz if len(qb64) != az: hioing.MemoerError(f"Invalid sig qb64 size={len(qb64) != {az}}") @@ -1125,7 +1125,7 @@ def size(self, size): size (int or None): gram size for rending memo """ - _, _, _, nz, _, _, oz = self.Sizes[self.code] # hz mz xz nz zz az oz + _, _, _, nz, _, _, oz = self.Sizes[self.code] # hz mz vz nz zz az oz size = size if size is not None else self.MaxGramSize if self.curt: # minimum header smaller when in base2 curt oz = 3 * oz // 4 @@ -1394,10 +1394,15 @@ def pickNew(self, gram): returns (mid, gn, gc). Raises MemoerError if unrecognized or invalid header this includes signature verification failure when signed. - When signed the signature is computed on the domain qb64b or qb2 that - the packet is transmitted in. Note the packet itself is not concatenation - composable as per CESR only the header elements and sig are CESR 24 bit - aligned so there is no enmass conversion of concatenated memograms. + When signed the signature is computed on the body of the gram as is when + gramified for transmission whether the body be in domain qb64b or qb2. + The body is assumed to always be in the raw domain ser when signed. + The header and signature parts are converted to raw from base2 or base64 + + Note the full packet itself is not concatenation composable (does not + align on 24 bit boundary) as per CESR. Only the header elements and sig + are CESR 24 bit aligned so there is no enmass conversion possible of + concatenated memograms. This is ok for a datagram segmentation that is decidedly not a stream. Returns: @@ -1422,91 +1427,83 @@ def pickNew(self, gram): """ curt = self.wiff(gram) # rx gram encoding True=B2 or False=B64 if curt: # base2 binary encoding in triplets - if len(gram) < 4: # assumes len(code) must be 4 + if len(gram) < 3: # assumes len(code) must be 3 triplets (4 sextexts) raise hioing.MemoerError(f"Gram length={len(gram)} to short to " f"hold code.") - code = helping.codeB2ToB64(gram, 4) # code is first 4 sextets + code = helping.codeB2ToB64(gram, 4) # code from first 4 sextets if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, xz, nz, zz, az, oz = self.Sizes[code] # hz mz xz nz zz az oz - pz = (3 - ((mz) % 3)) % 3 # net pad size for mid - cms = 3 * (hz + mz) // 4 # hz + mz are aligned on 24 bit boundary - oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 - nz = 3 * nz // 4 # encoding b2 means head part sizes smaller by 3/4 - zz = 3 * zz // 4 # encoding b2 means head part sizes smaller by 3/4 - xz = 3 * xz // 4 # encoding b2 means head part sizes smaller by 3/4 - az = 3 * az // 4 # encoding b2 means head part sizes smaller by 3/4 + hz, mz, vz, nz, zz, az, oz = self.Sizes[code] # hz mz vz nz zz az oz + # head encoced as b2 means bz head part sizes (bizes) are smaller by 3/4 + hz = 3 * hz // 4 + mz = 3 * mz // 4 + vz = 3 * vz // 4 + nz = 3 * nz // 4 + zz = 3 * zz // 4 + az = 3 * az // 4 + oz = 3 * oz // 4 - if len(gram) < (oz + 1): # not big enough for non-first gram + if len(gram) < oz : # not big enough for overhead raise hioing.MemoerError(f"Not enough rx bytes for b2 gram" - f" < {oz + 1}.") + f" < {oz}.") - mid = encodeB64(gram[:cms]) # convert to b64b with prefix code - oid = encodeB64(gram[cms:cms+xz]) # convert to b64b - neck = gram[cms+xz:cms+xz+nz] # bytearray to bytes short part of neck - gn = int.from_bytes(neck) # gram number convert to int - #neck = encodeB64(neck) # convert to b64b - #head = mid + oid + neck # bytes - if gn == 0: # first (zeroth) gram so long neck - if len(gram) < oz + nz + 1: - raise hioing.MemoerError(f"Not enough rx bytes for b2 " - f"gram < {oz + nz + 1}.") - lneck = bytes(gram[cms+xz+nz:cms+xz+2*nz]) # bytearray to bytes - gc = int.from_bytes(lneck) # gram count convert to int - lneck = encodeB64(lneck) # convert to b64b - sig = encodeB64(gram[-az if az else len(gram):]) # last ss bytes are signature - del gram[-az if az else len(gram):] # strip sig if any - sgram = bytes(gram[:]) # signed part make bytes copy to sign - del gram[:oz-az+nz] # strip off fore head leaving body in gram - #head += lneck - else: # non-zeroth gram so short neck + mid = encodeB64(gram[hz:hz+mz]) # convert to b64b + oid = encodeB64(gram[hz+mz:hz+mz+vz]) # convert to b64b + gnum = gram[hz+mz+vz:hz+mz+vz+nz] # bytearray to bytes gnum + gn = int.from_bytes(gnum) # gram number convert to int + + if zz: # first (zeroth) gram so long neck get gram count + if gn != 0: # zeroth gram must have gram num == 0 + raise hioing.MemoerError(f"Invalid zeroth gram, number" + f"not zero ={gn}") + + gcnt = bytes(gram[hz+mz+vz+nz:hz+mz+vz+nz+zz]) # bytearray to bytes + gc = int.from_bytes(gcnt) # gram count convert to int + else: gc = None - sig = encodeB64(gram[-az if az else len(gram):]) - del gram[-az if az else len(gram):] # strip sig if any - sgram = bytes(gram[:]) # signed part make bytes copy to sign - del gram[:oz-az] # strip of fore head leaving body in gram + + sig = encodeB64(gram[-az if az else len(gram):]) # last ss bytes are signature + del gram[-az if az else len(gram):] # strip sig if any + sgram = bytes(gram[:]) # signed raw part make bytes copy to sign + del gram[:oz-az] # strip off fore head leaving body in gram else: # base64 text encoding in quadlets - if len(gram) < 2: # assumes len(code) must be 2 + if len(gram) < 4: # assumes len(code) must be 4 raise hioing.MemoerError(f"Gram length={len(gram)} to short to " f"hold code.") - code = gram[:2].decode() # assumes len(code) must be 2 + code = gram[:4].decode() # assumes len(code) must be 2 if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, xz, nz, zz, az, oz = self.Sizes[code] # hz mz xz nz zz az oz + hz, mz, vz, nz, zz, az, oz = self.Sizes[code] # hz mz vz nz zz az oz - if len(gram) < (oz + 1): # not big enough for non-first gram + if len(gram) < (oz): # not big enough for overhead raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" - f" < {oz + 1}.") + f" < {oz}.") - mid = bytes(gram[:hz+mz]) # bytearray to bytes qb64b with prefix - oid = bytes(gram[hz+mz:hz+mz+xz]) #bytearry to bytes qb64b convert to qb64 - neck = bytes(gram[hz+mz+xz:hz+mz+xz+nz]) # qb64b short part of neck - gn = helping.b64ToInt(neck) - #head = mid + oid + neck # bytes - if gn == 0: # first (zeroth) gram so long neck - if len(gram) < oz + nz + 1: - raise hioing.MemoerError(f"Not enough rx bytes for b64 " - f"gram < {oz + nz + 1}.") - lneck = bytes(gram[hz+mz+xz+nz:hz+mz+xz+2*nz]) # bytearray to bytes copy - gc = helping.b64ToInt(lneck) # convert to int - sig = bytes(gram[-az if az else len(gram):]) # last az bytes signature - del gram[-az if az else len(gram):] # strip sig if any - sgram = bytes(gram[:]) # signed part make bytes copy to sign - del gram[:oz-az+nz] # strip of fore head leaving body in gram - #head += lneck # bytes - else: # non-zeroth gram short neck + mid = bytes(gram[hz:hz+mz]) # bytearray to bytes qb64b with prefix + oid = bytes(gram[hz+mz:hz+mz+vz]) #bytearry to bytes qb64b convert to qb64 + gnum = bytes(gram[hz+mz+vz:hz+mz+vz+nz]) # qb64b short part of neck + gn = helping.b64ToInt(gnum) + + if zz: # first (zeroth) gram so long neck get gram count + if gn != 0: # zeroth gram must have gram num == 0 + raise hioing.MemoerError(f"Invalid zeroth gram, number" + f"not zero ={gn}") + + gcnt = bytes(gram[hz+mz+vz+nz:hz+mz+vz+nz+zz]) # bytearray to bytes + gc = helping.b64ToInt(gcnt) # convert to int + else: gc = None - sig = bytes(gram[-az if az else len(gram):]) - del gram[-az if az else len(gram):] # strip sig if any - sgram = bytes(gram[:]) # signed part make bytes copy to sign - del gram[:oz-az] # strip of fore head leaving body in gram + + sig = bytes(gram[-az if az else len(gram):]) # last az bytes signature + del gram[-az if az else len(gram):] # strip sig if any + sgram = bytes(gram[:]) # signed raw part make bytes copy to sign + del gram[:oz-az] # strip of fore head leaving body in gram if sig: # signature not empty - #sgram = head + bytes(gram) # bytearray to bytes self.verify(oid, sig, sgram) # raises MemoerVerifyError if invalid return (mid.decode(), oid.decode() if oid else None, gn, gc) @@ -1553,13 +1550,13 @@ def pick(self, gram): raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, xz, nz, zz, az, oz = self.Sizes[code] # hz mz xz nz zz az oz + hz, mz, vz, nz, zz, az, oz = self.Sizes[code] # hz mz vz nz zz az oz pz = (3 - ((mz) % 3)) % 3 # net pad size for mid cms = 3 * (hz + mz) // 4 # hz + mz are aligned on 24 bit boundary oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 nz = 3 * nz // 4 # encoding b2 means head part sizes smaller by 3/4 zz = 3 * zz // 4 # encoding b2 means head part sizes smaller by 3/4 - xz = 3 * xz // 4 # encoding b2 means head part sizes smaller by 3/4 + vz = 3 * vz // 4 # encoding b2 means head part sizes smaller by 3/4 az = 3 * az // 4 # encoding b2 means head part sizes smaller by 3/4 if len(gram) < (oz + 1): # not big enough for non-first gram @@ -1567,8 +1564,8 @@ def pick(self, gram): f" < {oz + 1}.") mid = encodeB64(gram[:cms]) # convert to b64b with prefix code - oid = encodeB64(gram[cms:cms+xz]) # convert to b64b - neck = gram[cms+xz:cms+xz+nz] # bytearray to bytes short part of neck + oid = encodeB64(gram[cms:cms+vz]) # convert to b64b + neck = gram[cms+vz:cms+vz+nz] # bytearray to bytes short part of neck gn = int.from_bytes(neck) # gram number convert to int #neck = encodeB64(neck) # convert to b64b #head = mid + oid + neck # bytes @@ -1576,7 +1573,7 @@ def pick(self, gram): if len(gram) < oz + nz + 1: raise hioing.MemoerError(f"Not enough rx bytes for b2 " f"gram < {oz + nz + 1}.") - lneck = bytes(gram[cms+xz+nz:cms+xz+2*nz]) # bytearray to bytes + lneck = bytes(gram[cms+vz+nz:cms+vz+2*nz]) # bytearray to bytes gc = int.from_bytes(lneck) # gram count convert to int lneck = encodeB64(lneck) # convert to b64b sig = encodeB64(gram[-az if az else len(gram):]) # last ss bytes are signature @@ -1599,22 +1596,22 @@ def pick(self, gram): if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, xz, nz, zz, az, oz = self.Sizes[code] # hz mz xz nz zz az oz + hz, mz, vz, nz, zz, az, oz = self.Sizes[code] # hz mz vz nz zz az oz if len(gram) < (oz + 1): # not big enough for non-first gram raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" f" < {oz + 1}.") mid = bytes(gram[:hz+mz]) # bytearray to bytes qb64b with prefix - oid = bytes(gram[hz+mz:hz+mz+xz]) #bytearry to bytes qb64b convert to qb64 - neck = bytes(gram[hz+mz+xz:hz+mz+xz+nz]) # qb64b short part of neck + oid = bytes(gram[hz+mz:hz+mz+vz]) #bytearry to bytes qb64b convert to qb64 + neck = bytes(gram[hz+mz+vz:hz+mz+vz+nz]) # qb64b short part of neck gn = helping.b64ToInt(neck) #head = mid + oid + neck # bytes if gn == 0: # first (zeroth) gram so long neck if len(gram) < oz + nz + 1: raise hioing.MemoerError(f"Not enough rx bytes for b64 " f"gram < {oz + nz + 1}.") - lneck = bytes(gram[hz+mz+xz+nz:hz+mz+xz+2*nz]) # bytearray to bytes copy + lneck = bytes(gram[hz+mz+vz+nz:hz+mz+vz+2*nz]) # bytearray to bytes copy gc = helping.b64ToInt(lneck) # convert to int sig = bytes(gram[-az if az else len(gram):]) # last az bytes signature del gram[-az if az else len(gram):] # strip sig if any @@ -1957,12 +1954,12 @@ def rend(self, memo, oid=None): grams = [] memo = bytearray(memo.encode()) # convert and copy to bytearray # self.size is max gram size - hz, mz, xz, nz, zz, az, oz = self.Sizes[self.code] # hz mz xz n zz az oz + hz, mz, vz, nz, zz, az, oz = self.Sizes[self.code] # hz mz vz n zz az oz oid = oid if oid is not None else self.oid - if xz and (not oid or len(oid) != xz): - raise hioing.MemoerError(f"Missing or invalid {oid=} for {xz=}") + if vz and (not oid or len(oid) != vz): + raise hioing.MemoerError(f"Missing or invalid {oid=} for {vz=}") pz = (3 - ((mz) % 3)) % 3 # net pad size for mid # memo ID is 16 byte random UUID converted to 22 char Base64 right aligned @@ -1977,7 +1974,7 @@ def rend(self, memo, oid=None): oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 nz = 3 * nz // 4 # encoding b2 means head part sizes smaller by 3/4 zz = 3 * zz // 4 # encoding b2 means head part sizes smaller by 3/4 - xz = 3 * xz // 4 # encoding b2 means head part sizes smaller by 3/4 + vz = 3 * vz // 4 # encoding b2 means head part sizes smaller by 3/4 az = 3 * az // 4 # encoding b2 means head part sizes smaller by 3/4 mid = decodeB64(mid) @@ -2008,7 +2005,7 @@ def rend(self, memo, oid=None): else: num = helping.intToB64b(gn, l=nz) # num size must always be neck size - if xz: # need oid part, but can't mod here may need below to sign + if vz: # need oid part, but can't mod here may need below to sign if self.curt: oidp = decodeB64(oid.encode()) # oid part b2 else: diff --git a/tests/core/memo/test_memoing.py b/tests/core/memo/test_memoing.py index 2181ecf6..f48e7673 100644 --- a/tests/core/memo/test_memoing.py +++ b/tests/core/memo/test_memoing.py @@ -118,24 +118,24 @@ def test_memoer_class(): # Codes table with sizes of code (hard) and full primitive material assert Memoer.Sizes == \ { - '__': Sizage(hz=2, mz=22, xz=0, nz=4, zz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, xz=44, nz=4, zz=0, az=88, oz=160), - '1AAQ': Sizage(hz=4, mz=24, xz=0, nz=4, zz=4, az=0, oz=36), - '1AAR': Sizage(hz=4, mz=24, xz=0, nz=4, zz=0, az=0, oz=32), - '1AAS': Sizage(hz=4, mz=24, xz=44, nz=4, zz=4, az=88, oz=168), - '1AAT': Sizage(hz=4, mz=24, xz=44, nz=4, zz=0, az=88, oz=164), - '1AAU': Sizage(hz=4, mz=24, xz=0, nz=4, zz=4, az=0, oz=36), - '1AAV': Sizage(hz=4, mz=24, xz=0, nz=4, zz=0, az=0, oz=32), - '1AAW': Sizage(hz=4, mz=24, xz=44, nz=4, zz=4, az=88, oz=168), - '1AAX': Sizage(hz=4, mz=24, xz=44, nz=4, zz=0, az=88, oz=164), - '1AAY': Sizage(hz=4, mz=24, xz=0, nz=4, zz=0, az=0, oz=32), - '1AAZ': Sizage(hz=4, mz=24, xz=44, nz=4, zz=0, az=88, oz=164), + '__': Sizage(hz=2, mz=22, vz=0, nz=4, zz=0, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, vz=44, nz=4, zz=0, az=88, oz=160), + '1AAQ': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAR': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAS': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), + '1AAT': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=88, oz=120), + '1AAU': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAV': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAW': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), + '1AAX': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=88, oz=120), + '1AAY': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), + '1AAZ': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), } # verify Sizes and Codes for code, val in Memoer.Sizes.items(): hz = val.hz mz = val.mz - xz = val.xz + vz = val.vz nz = val.nz zz = val.zz az = val.az @@ -146,18 +146,18 @@ def test_memoer_class(): assert code[0] == '_' or code[0] == '1' assert code[1] in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890-_' assert oz > 0 - assert oz == hz + mz + xz + zz + az + nz + assert oz == hz + mz + vz + zz + az + nz assert mz # ms must not be empty pz = (3 - ((mz) % 3)) % 3 # net pad size for mid assert pz == (hz % 4) # combined code + mid size must lie on 24 bit boundary - assert not xz % 4 # oid size must be on 24 bit boundary + assert not vz % 4 # oid size must be on 24 bit boundary assert not az % 4 # sig size must be on 24 bit boundary assert nz and not nz % 4 # neck (num) size must be on 24 bit boundary assert not zz % 4 # when zeroth cnt size must be on 24 bit boundary assert zz == (nz if zz else 0) assert oz and not oz % 4 # overhead size must be on 24 bit boundary - if xz: - assert az # az must not be empty if xz not empty + if vz: + assert az # az must not be empty if vz not empty assert Memoer.Names == \ { @@ -197,8 +197,8 @@ def test_memoer_class(): raw, code = Memoer._decodeOID(oid) assert raw == verkey assert code == 'B' # nontrans AID - _, _, xz, _, _, _, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz xz nz zz az oz - assert len(oid) == 44 == xz + _, _, vz, _, _, _, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz zz az oz + assert len(oid) == 44 == vz qvk = Memoer._encodeQVK(raw=verkey) assert qvk == 'BG-R9L4kTXULe33Tqidn0c-W-x6xU4lIXCdhZQYrsih2' @@ -222,7 +222,7 @@ def test_memoer_class(): raw, code = Memoer._decodeSGN(sgntr) assert raw == signature assert code == '0B' - _, _, _, _, _, az, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz xz nz zz az oz + _, _, _, _, _, az, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz zz az oz assert len(sgntr) == 88 == az """Done Test""" @@ -284,7 +284,7 @@ def test_memoer_sign_verify(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz xz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz vz nz zz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -340,7 +340,7 @@ def test_memoer_basic(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -494,7 +494,7 @@ def test_memoer_small_gram_size(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz assert peer.size == 33 # can't be smaller than head + neck + 1 assert not peer.authic assert not peer.echoic @@ -860,7 +860,7 @@ def test_memoer_basic_signed(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz xz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz vz nz zz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -1204,7 +1204,7 @@ def test_memoer_verific(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz assert peer.size == peer.MaxGramSize assert peer.authic assert not peer.echoic @@ -1443,8 +1443,8 @@ def test_auth_memoer_basic(): assert peer.keep == keep assert peer.oid == oid - assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, xz=44, nz=4, zz=0, az=88, oz=160) - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz xz nz zz az oz + assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, vz=44, nz=4, zz=0, az=88, oz=160) + assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz vz nz zz az oz assert peer.size == peer.MaxGramSize assert peer.tymeout == 0.0 assert peer.tymers == {} diff --git a/tests/core/udp/test_peer_memoing.py b/tests/core/udp/test_peer_memoing.py index 85150436..14aaef31 100644 --- a/tests/core/udp/test_peer_memoing.py +++ b/tests/core/udp/test_peer_memoing.py @@ -25,7 +25,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz assert alpha.size == 1240 # default MaxGramSize for udp assert alpha.bc == 1024 assert not alpha.opened @@ -38,7 +38,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz assert alpha.size == size assert alpha.bc == 1024 assert not alpha.opened @@ -175,7 +175,7 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz assert alpha.size == size assert alpha.bc == 1024 diff --git a/tests/core/uxd/test_peer_memoing.py b/tests/core/uxd/test_peer_memoing.py index d715e223..4e8cd3e1 100644 --- a/tests/core/uxd/test_peer_memoing.py +++ b/tests/core/uxd/test_peer_memoing.py @@ -22,7 +22,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz assert alpha.size == 38 assert alpha.bc == 4 @@ -151,7 +151,7 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz xz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz assert alpha.size == 38 assert alpha.bc == 4 From c9d37e5436535a150a7789be270167247e817dff Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Sun, 12 Apr 2026 10:50:39 -0600 Subject: [PATCH 4/9] removed zz field in Sizes no longer needed with refactor --- src/hio/core/memo/memoing.py | 99 +++++++++++++---------------- tests/core/memo/test_memoing.py | 47 +++++++------- tests/core/udp/test_peer_memoing.py | 6 +- tests/core/uxd/test_peer_memoing.py | 4 +- 4 files changed, 71 insertions(+), 85 deletions(-) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index ae9fa327..f7dc439e 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -120,8 +120,8 @@ Sizes:: { - '__': Sizage(hz=2, mz=22, vz=0, nz=4, zz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, vz=44, nz=4, zz=0, az=88, oz=160), + '__': Sizage(hz=2, mz=22, vz=0, nz=4, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, vz=44, nz=4, az=88, oz=160), } Sizing: @@ -239,27 +239,27 @@ hz is the serialization hard code part size int number of chars in hard code part mz is the mid (memo ID) part size int number of chars in the mid part -nz is the gram num (neck) part size int number of chars for the gram number -zz is the gram count part size int count of grams in memo. It only appears in the - zeroth gram in a memo. +nz is the gram num (neck) part size int number of chars for the gram number for + non-zeroth grams and the gram count for zeroth grams (zeroth gram the gram + number must be 0 so don't need to include it) gram code indicates gram num 0 vz is the vid (verifier id, origin ID) part size int number of chars in the vid part az is the authenticator (signature) part size int number of chars in the auth part the authenticator part is discontinuously attached after the body part but its size is included in the overhead size computation for the body size -oz is the overhead size int number of chars:: +oz is the overhead size int number of chars oz = hz + mz + + nz + vz + az - overhead is header with short neck and authenticator - oz = hz + mz + + nz + vz + az + non-zero gram codes vz = 0 + non-auth gram codes az = 0 - zeroth overhead is header with long neck relative to short neck - zoz = oz (short) + zz (note zz in zeroth gram = nz otherwise 0) + for non-auth gram codes zeroth gram overhead is same as non-zeroth + for auth gram codes zeroth gram overhead is greater than non-zeroth by vz + auth zoz = auth noz + vz The gram num and gram count both have the same size i.e. the neck size. -The gram count only appears in the zeroth gram -The zeroth gram has a long neck consiting of two nz sized fields -All other grams have a short neck consisting of 1 nz sized field +The gram count only appears in the zeroth gram, +the gram num only appears in non-zeroth grams """ -Sizage = namedtuple("Sizage", "hz mz vz nz zz az oz") +Sizage = namedtuple("Sizage", "hz mz vz nz az oz") @dataclass(frozen=True) @@ -541,20 +541,20 @@ class Memoer(Tymee): Codes = asdict(Codex) # map code name to code Names = {val : key for key, val in Codes.items()} # invert map code to code name Sodex = AuthDex # signed gram codex - # dict of gram header part sizes keyed by gram codes: hz mz vz nz zz az oz + # dict of gram header part sizes keyed by gram codes: hz mz vz nz az oz Sizes = { - '__': Sizage(hz=2, mz=22, vz=0, nz=4, zz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, vz=44, nz=4, zz=0, az=88, oz=160), - '1AAQ': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAR': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAS': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), - '1AAT': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=88, oz=120), - '1AAU': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAV': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAW': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), - '1AAX': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=88, oz=120), - '1AAY': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAZ': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), + '__': Sizage(hz=2, mz=22, vz=0, nz=4, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, vz=44, nz=4, az=88, oz=160), + '1AAQ': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAR': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAS': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), + '1AAT': Sizage(hz=4, mz=24, vz=0, nz=4, az=88, oz=120), + '1AAU': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAV': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAW': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), + '1AAX': Sizage(hz=4, mz=24, vz=0, nz=4, az=88, oz=120), + '1AAY': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAZ': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), } Pairs = dict() # pair the zeroth code with the non-zeroth code of same type @@ -605,7 +605,7 @@ def _encodeOID(cls, raw, code='B'): qb64 = code + b64.decode() # fully qualified base64 oid with prefix code - _, _, vz, _, _, _, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz zz az oz + _, _, vz, _, _, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz az oz if len(qb64) != vz: hioing.MemoerError(f"Invalid oid qb64 size={len(qb64) != {vz}}") @@ -855,7 +855,7 @@ def _encodeSGN(cls, raw, code='0B'): qb64 = code + b64.decode() # fully qualified base64 with prefixqb64de - _, _, _, _, _, az, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz zz az oz + _, _, _, _, az, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz az oz if len(qb64) != az: hioing.MemoerError(f"Invalid sig qb64 size={len(qb64) != {az}}") @@ -1125,7 +1125,7 @@ def size(self, size): size (int or None): gram size for rending memo """ - _, _, _, nz, _, _, oz = self.Sizes[self.code] # hz mz vz nz zz az oz + _, _, _, nz, _, oz = self.Sizes[self.code] # hz mz vz nz az oz size = size if size is not None else self.MaxGramSize if self.curt: # minimum header smaller when in base2 curt oz = 3 * oz // 4 @@ -1435,13 +1435,12 @@ def pickNew(self, gram): raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, vz, nz, zz, az, oz = self.Sizes[code] # hz mz vz nz zz az oz + hz, mz, vz, nz, az, oz = self.Sizes[code] # hz mz vz nz az oz # head encoced as b2 means bz head part sizes (bizes) are smaller by 3/4 hz = 3 * hz // 4 mz = 3 * mz // 4 vz = 3 * vz // 4 nz = 3 * nz // 4 - zz = 3 * zz // 4 az = 3 * az // 4 oz = 3 * oz // 4 @@ -1452,17 +1451,13 @@ def pickNew(self, gram): mid = encodeB64(gram[hz:hz+mz]) # convert to b64b oid = encodeB64(gram[hz+mz:hz+mz+vz]) # convert to b64b gnum = gram[hz+mz+vz:hz+mz+vz+nz] # bytearray to bytes gnum - gn = int.from_bytes(gnum) # gram number convert to int + gn = int.from_bytes(gnum) # gram number/count convert to int - if zz: # first (zeroth) gram so long neck get gram count - if gn != 0: # zeroth gram must have gram num == 0 - raise hioing.MemoerError(f"Invalid zeroth gram, number" - f"not zero ={gn}") - - gcnt = bytes(gram[hz+mz+vz+nz:hz+mz+vz+nz+zz]) # bytearray to bytes - gc = int.from_bytes(gcnt) # gram count convert to int + if True: # first (zeroth) gram so long neck get gram count + gc = gn # zeroth so gcnt in neck where gnum + gn = 0 # zeroth so gnum must be zero else: - gc = None + gc = None # not provided in this gram sig = encodeB64(gram[-az if az else len(gram):]) # last ss bytes are signature del gram[-az if az else len(gram):] # strip sig if any @@ -1477,7 +1472,7 @@ def pickNew(self, gram): if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, vz, nz, zz, az, oz = self.Sizes[code] # hz mz vz nz zz az oz + hz, mz, vz, nz, az, oz = self.Sizes[code] # hz mz vz nz az oz if len(gram) < (oz): # not big enough for overhead raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" @@ -1488,15 +1483,11 @@ def pickNew(self, gram): gnum = bytes(gram[hz+mz+vz:hz+mz+vz+nz]) # qb64b short part of neck gn = helping.b64ToInt(gnum) - if zz: # first (zeroth) gram so long neck get gram count - if gn != 0: # zeroth gram must have gram num == 0 - raise hioing.MemoerError(f"Invalid zeroth gram, number" - f"not zero ={gn}") - - gcnt = bytes(gram[hz+mz+vz+nz:hz+mz+vz+nz+zz]) # bytearray to bytes - gc = helping.b64ToInt(gcnt) # convert to int + if True: # first (zeroth) gram so long neck get gram count + gc = gn # zeroth so gcnt in neck where gnum + gn = 0 # zeroth so gnum must be zer else: - gc = None + gc = None # not provided in this gram sig = bytes(gram[-az if az else len(gram):]) # last az bytes signature del gram[-az if az else len(gram):] # strip sig if any @@ -1550,12 +1541,11 @@ def pick(self, gram): raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, vz, nz, zz, az, oz = self.Sizes[code] # hz mz vz nz zz az oz + hz, mz, vz, nz, az, oz = self.Sizes[code] # hz mz vz nz az oz pz = (3 - ((mz) % 3)) % 3 # net pad size for mid cms = 3 * (hz + mz) // 4 # hz + mz are aligned on 24 bit boundary oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 nz = 3 * nz // 4 # encoding b2 means head part sizes smaller by 3/4 - zz = 3 * zz // 4 # encoding b2 means head part sizes smaller by 3/4 vz = 3 * vz // 4 # encoding b2 means head part sizes smaller by 3/4 az = 3 * az // 4 # encoding b2 means head part sizes smaller by 3/4 @@ -1596,7 +1586,7 @@ def pick(self, gram): if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, vz, nz, zz, az, oz = self.Sizes[code] # hz mz vz nz zz az oz + hz, mz, vz, nz, az, oz = self.Sizes[code] # hz mz vz nz az oz if len(gram) < (oz + 1): # not big enough for non-first gram raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" @@ -1954,7 +1944,7 @@ def rend(self, memo, oid=None): grams = [] memo = bytearray(memo.encode()) # convert and copy to bytearray # self.size is max gram size - hz, mz, vz, nz, zz, az, oz = self.Sizes[self.code] # hz mz vz n zz az oz + hz, mz, vz, nz, az, oz = self.Sizes[self.code] # hz mz vz nz az oz oid = oid if oid is not None else self.oid @@ -1973,7 +1963,6 @@ def rend(self, memo, oid=None): if self.curt: # rend header parts in base2 instead of base64 oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 nz = 3 * nz // 4 # encoding b2 means head part sizes smaller by 3/4 - zz = 3 * zz // 4 # encoding b2 means head part sizes smaller by 3/4 vz = 3 * vz // 4 # encoding b2 means head part sizes smaller by 3/4 az = 3 * az // 4 # encoding b2 means head part sizes smaller by 3/4 mid = decodeB64(mid) diff --git a/tests/core/memo/test_memoing.py b/tests/core/memo/test_memoing.py index f48e7673..3e9ac713 100644 --- a/tests/core/memo/test_memoing.py +++ b/tests/core/memo/test_memoing.py @@ -118,18 +118,18 @@ def test_memoer_class(): # Codes table with sizes of code (hard) and full primitive material assert Memoer.Sizes == \ { - '__': Sizage(hz=2, mz=22, vz=0, nz=4, zz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, vz=44, nz=4, zz=0, az=88, oz=160), - '1AAQ': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAR': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAS': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), - '1AAT': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=88, oz=120), - '1AAU': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAV': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAW': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), - '1AAX': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=88, oz=120), - '1AAY': Sizage(hz=4, mz=24, vz=0, nz=4, zz=0, az=0, oz=32), - '1AAZ': Sizage(hz=4, mz=24, vz=44, nz=4, zz=0, az=88, oz=164), + '__': Sizage(hz=2, mz=22, vz=0, nz=4, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, vz=44, nz=4, az=88, oz=160), + '1AAQ': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAR': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAS': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), + '1AAT': Sizage(hz=4, mz=24, vz=0, nz=4, az=88, oz=120), + '1AAU': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAV': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAW': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), + '1AAX': Sizage(hz=4, mz=24, vz=0, nz=4, az=88, oz=120), + '1AAY': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), + '1AAZ': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), } # verify Sizes and Codes for code, val in Memoer.Sizes.items(): @@ -137,7 +137,6 @@ def test_memoer_class(): mz = val.mz vz = val.vz nz = val.nz - zz = val.zz az = val.az oz = val.oz @@ -146,15 +145,13 @@ def test_memoer_class(): assert code[0] == '_' or code[0] == '1' assert code[1] in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890-_' assert oz > 0 - assert oz == hz + mz + vz + zz + az + nz + assert oz == hz + mz + vz + az + nz assert mz # ms must not be empty pz = (3 - ((mz) % 3)) % 3 # net pad size for mid assert pz == (hz % 4) # combined code + mid size must lie on 24 bit boundary assert not vz % 4 # oid size must be on 24 bit boundary assert not az % 4 # sig size must be on 24 bit boundary assert nz and not nz % 4 # neck (num) size must be on 24 bit boundary - assert not zz % 4 # when zeroth cnt size must be on 24 bit boundary - assert zz == (nz if zz else 0) assert oz and not oz % 4 # overhead size must be on 24 bit boundary if vz: assert az # az must not be empty if vz not empty @@ -197,7 +194,7 @@ def test_memoer_class(): raw, code = Memoer._decodeOID(oid) assert raw == verkey assert code == 'B' # nontrans AID - _, _, vz, _, _, _, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz zz az oz + _, _, vz, _, _, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz az oz assert len(oid) == 44 == vz qvk = Memoer._encodeQVK(raw=verkey) @@ -222,7 +219,7 @@ def test_memoer_class(): raw, code = Memoer._decodeSGN(sgntr) assert raw == signature assert code == '0B' - _, _, _, _, _, az, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz zz az oz + _, _, _, _, az, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz az oz assert len(sgntr) == 88 == az """Done Test""" @@ -284,7 +281,7 @@ def test_memoer_sign_verify(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz vz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 44, 4, 88, 160) # hz mz vz nz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -340,7 +337,7 @@ def test_memoer_basic(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -494,7 +491,7 @@ def test_memoer_small_gram_size(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz assert peer.size == 33 # can't be smaller than head + neck + 1 assert not peer.authic assert not peer.echoic @@ -860,7 +857,7 @@ def test_memoer_basic_signed(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz vz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 44, 4, 88, 160) # hz mz vz nz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -1204,7 +1201,7 @@ def test_memoer_verific(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz + assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz assert peer.size == peer.MaxGramSize assert peer.authic assert not peer.echoic @@ -1443,8 +1440,8 @@ def test_auth_memoer_basic(): assert peer.keep == keep assert peer.oid == oid - assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, vz=44, nz=4, zz=0, az=88, oz=160) - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 0, 88, 160) # hz mz vz nz zz az oz + assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, vz=44, nz=4, az=88, oz=160) + assert peer.Sizes[peer.code] == (2, 22, 44, 4, 88, 160) # hz mz vz nz az oz assert peer.size == peer.MaxGramSize assert peer.tymeout == 0.0 assert peer.tymers == {} diff --git a/tests/core/udp/test_peer_memoing.py b/tests/core/udp/test_peer_memoing.py index 14aaef31..ffe3f46b 100644 --- a/tests/core/udp/test_peer_memoing.py +++ b/tests/core/udp/test_peer_memoing.py @@ -25,7 +25,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz assert alpha.size == 1240 # default MaxGramSize for udp assert alpha.bc == 1024 assert not alpha.opened @@ -38,7 +38,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz assert alpha.size == size assert alpha.bc == 1024 assert not alpha.opened @@ -175,7 +175,7 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz assert alpha.size == size assert alpha.bc == 1024 diff --git a/tests/core/uxd/test_peer_memoing.py b/tests/core/uxd/test_peer_memoing.py index 4e8cd3e1..feab8204 100644 --- a/tests/core/uxd/test_peer_memoing.py +++ b/tests/core/uxd/test_peer_memoing.py @@ -22,7 +22,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz assert alpha.size == 38 assert alpha.bc == 4 @@ -151,7 +151,7 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 0, 28) # hz mz vz nz zz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz assert alpha.size == 38 assert alpha.bc == 4 From 0e8ec9156aaeddbb9c7f79e6f3e56403144187fd Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Sun, 12 Apr 2026 11:21:40 -0600 Subject: [PATCH 5/9] reordered nz and vz --- src/hio/core/memo/memoing.py | 62 ++++++++++++++--------------- tests/core/memo/test_memoing.py | 46 ++++++++++----------- tests/core/udp/test_peer_memoing.py | 6 +-- tests/core/uxd/test_peer_memoing.py | 4 +- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index f7dc439e..90ba9dd0 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -120,8 +120,8 @@ Sizes:: { - '__': Sizage(hz=2, mz=22, vz=0, nz=4, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, vz=44, nz=4, az=88, oz=160), + '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, nz=4, vz=44, az=88, oz=160), } Sizing: @@ -246,7 +246,7 @@ az is the authenticator (signature) part size int number of chars in the auth part the authenticator part is discontinuously attached after the body part but its size is included in the overhead size computation for the body size -oz is the overhead size int number of chars oz = hz + mz + + nz + vz + az +oz is the overhead size int number of chars oz = hz + mz + nz + vz + az non-zero gram codes vz = 0 non-auth gram codes az = 0 @@ -259,7 +259,7 @@ The gram count only appears in the zeroth gram, the gram num only appears in non-zeroth grams """ -Sizage = namedtuple("Sizage", "hz mz vz nz az oz") +Sizage = namedtuple("Sizage", "hz mz nz vz az oz") @dataclass(frozen=True) @@ -541,20 +541,20 @@ class Memoer(Tymee): Codes = asdict(Codex) # map code name to code Names = {val : key for key, val in Codes.items()} # invert map code to code name Sodex = AuthDex # signed gram codex - # dict of gram header part sizes keyed by gram codes: hz mz vz nz az oz + # dict of gram header part sizes keyed by gram codes: hz mz nz vz az oz Sizes = { - '__': Sizage(hz=2, mz=22, vz=0, nz=4, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, vz=44, nz=4, az=88, oz=160), - '1AAQ': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAR': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAS': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), - '1AAT': Sizage(hz=4, mz=24, vz=0, nz=4, az=88, oz=120), - '1AAU': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAV': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAW': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), - '1AAX': Sizage(hz=4, mz=24, vz=0, nz=4, az=88, oz=120), - '1AAY': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAZ': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), + '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, nz=4, vz=44,az=88, oz=160), + '1AAQ': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), + '1AAR': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), + '1AAS': Sizage(hz=4, mz=24, nz=4, vz=44,az=88, oz=164), + '1AAT': Sizage(hz=4, mz=24, nz=4, vz=0, az=88, oz=120), + '1AAU': Sizage(hz=4, mz=24, nz=4, vz=0,az=0, oz=32), + '1AAV': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), + '1AAW': Sizage(hz=4, mz=24, nz=4, vz=44, az=88, oz=164), + '1AAX': Sizage(hz=4, mz=24, nz=4, vz=0, az=88, oz=120), + '1AAY': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), + '1AAZ': Sizage(hz=4, mz=24, nz=4, vz=44, az=88, oz=164), } Pairs = dict() # pair the zeroth code with the non-zeroth code of same type @@ -605,7 +605,7 @@ def _encodeOID(cls, raw, code='B'): qb64 = code + b64.decode() # fully qualified base64 oid with prefix code - _, _, vz, _, _, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz az oz + _, _, _, vz, _, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az oz if len(qb64) != vz: hioing.MemoerError(f"Invalid oid qb64 size={len(qb64) != {vz}}") @@ -855,7 +855,7 @@ def _encodeSGN(cls, raw, code='0B'): qb64 = code + b64.decode() # fully qualified base64 with prefixqb64de - _, _, _, _, az, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz az oz + _, _, _, _, az, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az oz if len(qb64) != az: hioing.MemoerError(f"Invalid sig qb64 size={len(qb64) != {az}}") @@ -1125,7 +1125,7 @@ def size(self, size): size (int or None): gram size for rending memo """ - _, _, _, nz, _, oz = self.Sizes[self.code] # hz mz vz nz az oz + _, _, nz, _, _, oz = self.Sizes[self.code] # hz mz nz vz az oz size = size if size is not None else self.MaxGramSize if self.curt: # minimum header smaller when in base2 curt oz = 3 * oz // 4 @@ -1435,12 +1435,12 @@ def pickNew(self, gram): raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, vz, nz, az, oz = self.Sizes[code] # hz mz vz nz az oz + hz, mz, nz, vz, az, oz = self.Sizes[code] # hz mz nz vz az oz # head encoced as b2 means bz head part sizes (bizes) are smaller by 3/4 hz = 3 * hz // 4 mz = 3 * mz // 4 - vz = 3 * vz // 4 nz = 3 * nz // 4 + vz = 3 * vz // 4 az = 3 * az // 4 oz = 3 * oz // 4 @@ -1449,8 +1449,7 @@ def pickNew(self, gram): f" < {oz}.") mid = encodeB64(gram[hz:hz+mz]) # convert to b64b - oid = encodeB64(gram[hz+mz:hz+mz+vz]) # convert to b64b - gnum = gram[hz+mz+vz:hz+mz+vz+nz] # bytearray to bytes gnum + gnum = gram[hz+mz:hz+mz+nz] # bytearray to bytes gnum gn = int.from_bytes(gnum) # gram number/count convert to int if True: # first (zeroth) gram so long neck get gram count @@ -1459,6 +1458,7 @@ def pickNew(self, gram): else: gc = None # not provided in this gram + oid = encodeB64(gram[hz+mz+nz:hz+mz+nz+vz]) # convert to b64b sig = encodeB64(gram[-az if az else len(gram):]) # last ss bytes are signature del gram[-az if az else len(gram):] # strip sig if any sgram = bytes(gram[:]) # signed raw part make bytes copy to sign @@ -1472,23 +1472,23 @@ def pickNew(self, gram): if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, vz, nz, az, oz = self.Sizes[code] # hz mz vz nz az oz + hz, mz, nz, vz, az, oz = self.Sizes[code] # hz mz nz vz az oz if len(gram) < (oz): # not big enough for overhead raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" f" < {oz}.") mid = bytes(gram[hz:hz+mz]) # bytearray to bytes qb64b with prefix - oid = bytes(gram[hz+mz:hz+mz+vz]) #bytearry to bytes qb64b convert to qb64 - gnum = bytes(gram[hz+mz+vz:hz+mz+vz+nz]) # qb64b short part of neck - gn = helping.b64ToInt(gnum) + gnum = bytes(gram[hz+mz:hz+mz+nz]) # qb64b short part of neck + gn = helping.b64ToInt(gnum) if True: # first (zeroth) gram so long neck get gram count gc = gn # zeroth so gcnt in neck where gnum gn = 0 # zeroth so gnum must be zer else: gc = None # not provided in this gram + oid = bytes(gram[hz+mz+nz:hz+mz+nz+vz]) #bytearry to bytes qb64b convert to qb64 sig = bytes(gram[-az if az else len(gram):]) # last az bytes signature del gram[-az if az else len(gram):] # strip sig if any sgram = bytes(gram[:]) # signed raw part make bytes copy to sign @@ -1541,7 +1541,7 @@ def pick(self, gram): raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, vz, nz, az, oz = self.Sizes[code] # hz mz vz nz az oz + hz, mz, nz, vz, az, oz = self.Sizes[code] # hz mz nz vz az oz pz = (3 - ((mz) % 3)) % 3 # net pad size for mid cms = 3 * (hz + mz) // 4 # hz + mz are aligned on 24 bit boundary oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 @@ -1586,7 +1586,7 @@ def pick(self, gram): if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, vz, nz, az, oz = self.Sizes[code] # hz mz vz nz az oz + hz, mz, nz, vz, az, oz = self.Sizes[code] # hz mz nz vz az oz if len(gram) < (oz + 1): # not big enough for non-first gram raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" @@ -1944,7 +1944,7 @@ def rend(self, memo, oid=None): grams = [] memo = bytearray(memo.encode()) # convert and copy to bytearray # self.size is max gram size - hz, mz, vz, nz, az, oz = self.Sizes[self.code] # hz mz vz nz az oz + hz, mz, nz, vz, az, oz = self.Sizes[self.code] # hz mz nz vz az oz oid = oid if oid is not None else self.oid diff --git a/tests/core/memo/test_memoing.py b/tests/core/memo/test_memoing.py index 3e9ac713..416873e2 100644 --- a/tests/core/memo/test_memoing.py +++ b/tests/core/memo/test_memoing.py @@ -118,25 +118,25 @@ def test_memoer_class(): # Codes table with sizes of code (hard) and full primitive material assert Memoer.Sizes == \ { - '__': Sizage(hz=2, mz=22, vz=0, nz=4, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, vz=44, nz=4, az=88, oz=160), - '1AAQ': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAR': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAS': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), - '1AAT': Sizage(hz=4, mz=24, vz=0, nz=4, az=88, oz=120), - '1AAU': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAV': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAW': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), - '1AAX': Sizage(hz=4, mz=24, vz=0, nz=4, az=88, oz=120), - '1AAY': Sizage(hz=4, mz=24, vz=0, nz=4, az=0, oz=32), - '1AAZ': Sizage(hz=4, mz=24, vz=44, nz=4, az=88, oz=164), + '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0, oz=28), + '_-': Sizage(hz=2, mz=22, nz=4, vz=44,az=88, oz=160), + '1AAQ': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), + '1AAR': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), + '1AAS': Sizage(hz=4, mz=24, nz=4, vz=44,az=88, oz=164), + '1AAT': Sizage(hz=4, mz=24, nz=4, vz=0, az=88, oz=120), + '1AAU': Sizage(hz=4, mz=24, nz=4, vz=0,az=0, oz=32), + '1AAV': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), + '1AAW': Sizage(hz=4, mz=24, nz=4, vz=44, az=88, oz=164), + '1AAX': Sizage(hz=4, mz=24, nz=4, vz=0, az=88, oz=120), + '1AAY': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), + '1AAZ': Sizage(hz=4, mz=24, nz=4, vz=44, az=88, oz=164), } # verify Sizes and Codes for code, val in Memoer.Sizes.items(): hz = val.hz mz = val.mz - vz = val.vz nz = val.nz + vz = val.vz az = val.az oz = val.oz @@ -145,7 +145,7 @@ def test_memoer_class(): assert code[0] == '_' or code[0] == '1' assert code[1] in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890-_' assert oz > 0 - assert oz == hz + mz + vz + az + nz + assert oz == hz + mz + nz + vz + az assert mz # ms must not be empty pz = (3 - ((mz) % 3)) % 3 # net pad size for mid assert pz == (hz % 4) # combined code + mid size must lie on 24 bit boundary @@ -194,7 +194,7 @@ def test_memoer_class(): raw, code = Memoer._decodeOID(oid) assert raw == verkey assert code == 'B' # nontrans AID - _, _, vz, _, _, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz az oz + _, _, _, vz, _, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az oz assert len(oid) == 44 == vz qvk = Memoer._encodeQVK(raw=verkey) @@ -219,7 +219,7 @@ def test_memoer_class(): raw, code = Memoer._decodeSGN(sgntr) assert raw == signature assert code == '0B' - _, _, _, _, az, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz vz nz az oz + _, _, _, _, az, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az oz assert len(sgntr) == 88 == az """Done Test""" @@ -281,7 +281,7 @@ def test_memoer_sign_verify(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 88, 160) # hz mz vz nz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88, 160) # hz mz nz vz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -337,7 +337,7 @@ def test_memoer_basic(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -491,7 +491,7 @@ def test_memoer_small_gram_size(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz assert peer.size == 33 # can't be smaller than head + neck + 1 assert not peer.authic assert not peer.echoic @@ -857,7 +857,7 @@ def test_memoer_basic_signed(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 88, 160) # hz mz vz nz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88, 160) # hz mz nz vz az oz assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -1201,7 +1201,7 @@ def test_memoer_verific(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz assert peer.size == peer.MaxGramSize assert peer.authic assert not peer.echoic @@ -1440,8 +1440,8 @@ def test_auth_memoer_basic(): assert peer.keep == keep assert peer.oid == oid - assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, vz=44, nz=4, az=88, oz=160) - assert peer.Sizes[peer.code] == (2, 22, 44, 4, 88, 160) # hz mz vz nz az oz + assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, nz=4, vz=44, az=88, oz=160) + assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88, 160) # hz mz nz vz az oz assert peer.size == peer.MaxGramSize assert peer.tymeout == 0.0 assert peer.tymers == {} diff --git a/tests/core/udp/test_peer_memoing.py b/tests/core/udp/test_peer_memoing.py index ffe3f46b..3921de0c 100644 --- a/tests/core/udp/test_peer_memoing.py +++ b/tests/core/udp/test_peer_memoing.py @@ -25,7 +25,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz assert alpha.size == 1240 # default MaxGramSize for udp assert alpha.bc == 1024 assert not alpha.opened @@ -38,7 +38,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz assert alpha.size == size assert alpha.bc == 1024 assert not alpha.opened @@ -175,7 +175,7 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz assert alpha.size == size assert alpha.bc == 1024 diff --git a/tests/core/uxd/test_peer_memoing.py b/tests/core/uxd/test_peer_memoing.py index feab8204..b296e8af 100644 --- a/tests/core/uxd/test_peer_memoing.py +++ b/tests/core/uxd/test_peer_memoing.py @@ -22,7 +22,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz assert alpha.size == 38 assert alpha.bc == 4 @@ -151,7 +151,7 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 0, 4, 0, 28) # hz mz vz nz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz assert alpha.size == 38 assert alpha.bc == 4 From d474b945dfa06bb461f94f34a4d8eddf9a4c0fe6 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Sun, 12 Apr 2026 11:48:27 -0600 Subject: [PATCH 6/9] remove oz from Sizes just compute it from other sizes --- src/hio/core/memo/memoing.py | 93 ++++++++++++++++------------- tests/core/memo/test_memoing.py | 51 ++++++++-------- tests/core/udp/test_peer_memoing.py | 6 +- tests/core/uxd/test_peer_memoing.py | 4 +- 4 files changed, 84 insertions(+), 70 deletions(-) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index 90ba9dd0..7a7a6c48 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -120,8 +120,8 @@ Sizes:: { - '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, nz=4, vz=44, az=88, oz=160), + '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0), + '_-': Sizage(hz=2, mz=22, nz=4, vz=44, az=88), } Sizing: @@ -246,20 +246,22 @@ az is the authenticator (signature) part size int number of chars in the auth part the authenticator part is discontinuously attached after the body part but its size is included in the overhead size computation for the body size -oz is the overhead size int number of chars oz = hz + mz + nz + vz + az - non-zero gram codes vz = 0 - non-auth gram codes az = 0 +The total overhead size int number of chars is denoted oz +oz = hz + mz + nz + vz + az - for non-auth gram codes zeroth gram overhead is same as non-zeroth - for auth gram codes zeroth gram overhead is greater than non-zeroth by vz - auth zoz = auth noz + vz +non-zero gram codes vz = 0 +non-auth gram codes az = 0 + +for non-auth gram codes zeroth gram overhead is same as non-zeroth +for auth gram codes zeroth gram overhead is greater than non-zeroth by vz + auth zoz = auth noz + vz The gram num and gram count both have the same size i.e. the neck size. The gram count only appears in the zeroth gram, the gram num only appears in non-zeroth grams """ -Sizage = namedtuple("Sizage", "hz mz nz vz az oz") +Sizage = namedtuple("Sizage", "hz mz nz vz az") @dataclass(frozen=True) @@ -541,20 +543,20 @@ class Memoer(Tymee): Codes = asdict(Codex) # map code name to code Names = {val : key for key, val in Codes.items()} # invert map code to code name Sodex = AuthDex # signed gram codex - # dict of gram header part sizes keyed by gram codes: hz mz nz vz az oz + # dict of gram header part sizes keyed by gram codes: hz mz nz vz az Sizes = { - '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, nz=4, vz=44,az=88, oz=160), - '1AAQ': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), - '1AAR': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), - '1AAS': Sizage(hz=4, mz=24, nz=4, vz=44,az=88, oz=164), - '1AAT': Sizage(hz=4, mz=24, nz=4, vz=0, az=88, oz=120), - '1AAU': Sizage(hz=4, mz=24, nz=4, vz=0,az=0, oz=32), - '1AAV': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), - '1AAW': Sizage(hz=4, mz=24, nz=4, vz=44, az=88, oz=164), - '1AAX': Sizage(hz=4, mz=24, nz=4, vz=0, az=88, oz=120), - '1AAY': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), - '1AAZ': Sizage(hz=4, mz=24, nz=4, vz=44, az=88, oz=164), + '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0), + '_-': Sizage(hz=2, mz=22, nz=4, vz=44,az=88), + '1AAQ': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), + '1AAR': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), + '1AAS': Sizage(hz=4, mz=24, nz=4, vz=44,az=88), + '1AAT': Sizage(hz=4, mz=24, nz=4, vz=0, az=88), + '1AAU': Sizage(hz=4, mz=24, nz=4, vz=0,az=0), + '1AAV': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), + '1AAW': Sizage(hz=4, mz=24, nz=4, vz=44, az=88), + '1AAX': Sizage(hz=4, mz=24, nz=4, vz=0, az=88), + '1AAY': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), + '1AAZ': Sizage(hz=4, mz=24, nz=4, vz=44, az=88), } Pairs = dict() # pair the zeroth code with the non-zeroth code of same type @@ -605,7 +607,7 @@ def _encodeOID(cls, raw, code='B'): qb64 = code + b64.decode() # fully qualified base64 oid with prefix code - _, _, _, vz, _, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az oz + _, _, _, vz, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az if len(qb64) != vz: hioing.MemoerError(f"Invalid oid qb64 size={len(qb64) != {vz}}") @@ -855,7 +857,7 @@ def _encodeSGN(cls, raw, code='0B'): qb64 = code + b64.decode() # fully qualified base64 with prefixqb64de - _, _, _, _, az, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az oz + _, _, _, _, az = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az if len(qb64) != az: hioing.MemoerError(f"Invalid sig qb64 size={len(qb64) != {az}}") @@ -1125,7 +1127,8 @@ def size(self, size): size (int or None): gram size for rending memo """ - _, _, nz, _, _, oz = self.Sizes[self.code] # hz mz nz vz az oz + hz, mz, nz, vz, az = self.Sizes[self.code] # hz mz nz vz az + oz = hz + mz + nz + vz + az size = size if size is not None else self.MaxGramSize if self.curt: # minimum header smaller when in base2 curt oz = 3 * oz // 4 @@ -1435,14 +1438,15 @@ def pickNew(self, gram): raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, nz, vz, az, oz = self.Sizes[code] # hz mz nz vz az oz + hz, mz, nz, vz, az = self.Sizes[code] # hz mz nz vz az # head encoced as b2 means bz head part sizes (bizes) are smaller by 3/4 hz = 3 * hz // 4 mz = 3 * mz // 4 nz = 3 * nz // 4 vz = 3 * vz // 4 az = 3 * az // 4 - oz = 3 * oz // 4 + + oz = hz + mz + nz + vz + az if len(gram) < oz : # not big enough for overhead raise hioing.MemoerError(f"Not enough rx bytes for b2 gram" @@ -1472,7 +1476,8 @@ def pickNew(self, gram): if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, nz, vz, az, oz = self.Sizes[code] # hz mz nz vz az oz + hz, mz, nz, vz, az = self.Sizes[code] # hz mz nz vz az + oz = hz + mz + nz + vz + az if len(gram) < (oz): # not big enough for overhead raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" @@ -1541,13 +1546,16 @@ def pick(self, gram): raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, nz, vz, az, oz = self.Sizes[code] # hz mz nz vz az oz - pz = (3 - ((mz) % 3)) % 3 # net pad size for mid + hz, mz, nz, vz, az = self.Sizes[code] # hz mz nz vz az + # encoding b2 means head part sizes smaller by 3/4 + # pad = (3 - ((mz) % 3)) % 3 # net pad size cms = 3 * (hz + mz) // 4 # hz + mz are aligned on 24 bit boundary - oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 - nz = 3 * nz // 4 # encoding b2 means head part sizes smaller by 3/4 - vz = 3 * vz // 4 # encoding b2 means head part sizes smaller by 3/4 - az = 3 * az // 4 # encoding b2 means head part sizes smaller by 3/4 + mz = 3 * mz // 4 + nz = 3 * nz // 4 + vz = 3 * vz // 4 + az = 3 * az // 4 + + oz = hz + mz + nz + vz + az if len(gram) < (oz + 1): # not big enough for non-first gram raise hioing.MemoerError(f"Not enough rx bytes for b2 gram" @@ -1586,7 +1594,8 @@ def pick(self, gram): if self.authic and code not in self.Sodex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") - hz, mz, nz, vz, az, oz = self.Sizes[code] # hz mz nz vz az oz + hz, mz, nz, vz, az = self.Sizes[code] # hz mz nz vz az + oz = hz + mz + nz + vz + az if len(gram) < (oz + 1): # not big enough for non-first gram raise hioing.MemoerError(f"Not enough rx bytes for b64 gram" @@ -1944,7 +1953,8 @@ def rend(self, memo, oid=None): grams = [] memo = bytearray(memo.encode()) # convert and copy to bytearray # self.size is max gram size - hz, mz, nz, vz, az, oz = self.Sizes[self.code] # hz mz nz vz az oz + hz, mz, nz, vz, az = self.Sizes[self.code] # hz mz nz vz az + oz = hz + mz + nz + vz + az oid = oid if oid is not None else self.oid @@ -1961,10 +1971,13 @@ def rend(self, memo, oid=None): ml = len(memo) if self.curt: # rend header parts in base2 instead of base64 - oz = 3 * oz // 4 # encoding b2 means head part sizes smaller by 3/4 - nz = 3 * nz // 4 # encoding b2 means head part sizes smaller by 3/4 - vz = 3 * vz // 4 # encoding b2 means head part sizes smaller by 3/4 - az = 3 * az // 4 # encoding b2 means head part sizes smaller by 3/4 + # encoding b2 means head part sizes smaller by 3/4 + hz = 3 * hz // 4 + mz = 3 * mz // 4 + nz = 3 * nz // 4 + vz = 3 * vz // 4 + az = 3 * az // 4 + oz = 3 * oz // 4 mid = decodeB64(mid) bz = (self.size - oz) # max standard gram body size without neck diff --git a/tests/core/memo/test_memoing.py b/tests/core/memo/test_memoing.py index 416873e2..9c7d35eb 100644 --- a/tests/core/memo/test_memoing.py +++ b/tests/core/memo/test_memoing.py @@ -118,18 +118,18 @@ def test_memoer_class(): # Codes table with sizes of code (hard) and full primitive material assert Memoer.Sizes == \ { - '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0, oz=28), - '_-': Sizage(hz=2, mz=22, nz=4, vz=44,az=88, oz=160), - '1AAQ': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), - '1AAR': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), - '1AAS': Sizage(hz=4, mz=24, nz=4, vz=44,az=88, oz=164), - '1AAT': Sizage(hz=4, mz=24, nz=4, vz=0, az=88, oz=120), - '1AAU': Sizage(hz=4, mz=24, nz=4, vz=0,az=0, oz=32), - '1AAV': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), - '1AAW': Sizage(hz=4, mz=24, nz=4, vz=44, az=88, oz=164), - '1AAX': Sizage(hz=4, mz=24, nz=4, vz=0, az=88, oz=120), - '1AAY': Sizage(hz=4, mz=24, nz=4, vz=0, az=0, oz=32), - '1AAZ': Sizage(hz=4, mz=24, nz=4, vz=44, az=88, oz=164), + '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0), + '_-': Sizage(hz=2, mz=22, nz=4, vz=44,az=88), + '1AAQ': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), + '1AAR': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), + '1AAS': Sizage(hz=4, mz=24, nz=4, vz=44,az=88), + '1AAT': Sizage(hz=4, mz=24, nz=4, vz=0, az=88), + '1AAU': Sizage(hz=4, mz=24, nz=4, vz=0,az=0), + '1AAV': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), + '1AAW': Sizage(hz=4, mz=24, nz=4, vz=44, az=88), + '1AAX': Sizage(hz=4, mz=24, nz=4, vz=0, az=88), + '1AAY': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), + '1AAZ': Sizage(hz=4, mz=24, nz=4, vz=44, az=88), } # verify Sizes and Codes for code, val in Memoer.Sizes.items(): @@ -138,21 +138,22 @@ def test_memoer_class(): nz = val.nz vz = val.vz az = val.az - oz = val.oz + + oz = hz + mz + nz + vz + az + assert oz and not oz % 4 # overhead size nonzero and on 24 bit boundary assert len(code) == hz assert hz == 2 or hz == 4 assert code[0] == '_' or code[0] == '1' assert code[1] in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890-_' assert oz > 0 - assert oz == hz + mz + nz + vz + az - assert mz # ms must not be empty + assert mz # mid must not be empty pz = (3 - ((mz) % 3)) % 3 # net pad size for mid assert pz == (hz % 4) # combined code + mid size must lie on 24 bit boundary assert not vz % 4 # oid size must be on 24 bit boundary assert not az % 4 # sig size must be on 24 bit boundary assert nz and not nz % 4 # neck (num) size must be on 24 bit boundary - assert oz and not oz % 4 # overhead size must be on 24 bit boundary + if vz: assert az # az must not be empty if vz not empty @@ -194,7 +195,7 @@ def test_memoer_class(): raw, code = Memoer._decodeOID(oid) assert raw == verkey assert code == 'B' # nontrans AID - _, _, _, vz, _, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az oz + _, _, _, vz, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az assert len(oid) == 44 == vz qvk = Memoer._encodeQVK(raw=verkey) @@ -219,7 +220,7 @@ def test_memoer_class(): raw, code = Memoer._decodeSGN(sgntr) assert raw == signature assert code == '0B' - _, _, _, _, az, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az oz + _, _, _, _, az = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az assert len(sgntr) == 88 == az """Done Test""" @@ -281,7 +282,7 @@ def test_memoer_sign_verify(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88, 160) # hz mz nz vz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -337,7 +338,7 @@ def test_memoer_basic(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -491,7 +492,7 @@ def test_memoer_small_gram_size(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0) # hz mz nz vz az assert peer.size == 33 # can't be smaller than head + neck + 1 assert not peer.authic assert not peer.echoic @@ -857,7 +858,7 @@ def test_memoer_basic_signed(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88, 160) # hz mz nz vz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -1201,7 +1202,7 @@ def test_memoer_verific(): assert peer.bs == memoing.Memoer.BufSize == 65535 assert peer.code == memoing.MemoDex.MemoGram == '__' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz + assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert peer.authic assert not peer.echoic @@ -1440,8 +1441,8 @@ def test_auth_memoer_basic(): assert peer.keep == keep assert peer.oid == oid - assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, nz=4, vz=44, az=88, oz=160) - assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88, 160) # hz mz nz vz az oz + assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, nz=4, vz=44, az=88) + assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert peer.tymeout == 0.0 assert peer.tymers == {} diff --git a/tests/core/udp/test_peer_memoing.py b/tests/core/udp/test_peer_memoing.py index 3921de0c..b61ac830 100644 --- a/tests/core/udp/test_peer_memoing.py +++ b/tests/core/udp/test_peer_memoing.py @@ -25,7 +25,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az assert alpha.size == 1240 # default MaxGramSize for udp assert alpha.bc == 1024 assert not alpha.opened @@ -38,7 +38,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az assert alpha.size == size assert alpha.bc == 1024 assert not alpha.opened @@ -175,7 +175,7 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az assert alpha.size == size assert alpha.bc == 1024 diff --git a/tests/core/uxd/test_peer_memoing.py b/tests/core/uxd/test_peer_memoing.py index b296e8af..56909018 100644 --- a/tests/core/uxd/test_peer_memoing.py +++ b/tests/core/uxd/test_peer_memoing.py @@ -22,7 +22,7 @@ def test_memoer_peer_basic(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az assert alpha.size == 38 assert alpha.bc == 4 @@ -151,7 +151,7 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" assert alpha.code == MemoDex.MemoGram assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0, 28) # hz mz nz vz az oz + assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az assert alpha.size == 38 assert alpha.bc == 4 From 93fe3b4ccb17b9305cfeee3290f2e4492e266ae9 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Sun, 12 Apr 2026 12:12:08 -0600 Subject: [PATCH 7/9] added makeMID class method for Memoer --- src/hio/core/memo/memoing.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index 7a7a6c48..834d46c4 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -575,6 +575,28 @@ class Memoer(Tymee): BufSize = 65535 # (2**16-1) default buffersize Tymeout = 0.0 # tymeout in seconds, tymeout of 0.0 means ignore tymeout + @classmethod + def makeMID(cls, code='0A'): + """Make new random memo ID (MID) as 24 char CESR encoded qb64 UUID + + Returns:: + mid (str): 24 char qb64 CESR encoded qualified base64 from 128 bit UUID + CESR code '0A' labeled Salt_128 + + Parameters:: + code (str): CESR code for MID + """ + code = '0A' # Salt_128 + ps = (3 - (len(code) % 3)) % 3 # net pad size for code + uuid = uuid.uuid1().bytes # random UUID sorted in time order + if ps != (3 - (len(uuid) % 3)) % 3: # compare pad sizes + raise ValueError(f"Mismatch code and uuid pad sizes. " + f"Both not {ps=}") + # prepad convert strip midpad and then prefix code + mid = code.encode() + encodeB64(bytes([0] * ps) + uuid)[ps:] + return mid # fully qualified mid with prefixed code + + @classmethod def _encodeOID(cls, raw, code='B'): """Utility method for use with signed headers that encodes raw oid From 34ac2301d555ba605a2101d1d9c3505fa57784f2 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Sun, 12 Apr 2026 12:45:04 -0600 Subject: [PATCH 8/9] refactor oid origin id to verifier id --- src/hio/base/multidoing.py | 4 +- src/hio/core/memo/memoing.py | 273 ++++++++++++++++---------------- src/hio/core/udp/peermemoing.py | 18 +-- tests/core/memo/test_memoing.py | 198 +++++++++++------------ 4 files changed, 247 insertions(+), 246 deletions(-) diff --git a/src/hio/base/multidoing.py b/src/hio/base/multidoing.py index 3af3c1bf..572b7b3e 100644 --- a/src/hio/base/multidoing.py +++ b/src/hio/base/multidoing.py @@ -580,7 +580,7 @@ def serviceRxMemos(self): Override in subclass to handle result(s) and put them somewhere """ while self.rxms: - memo, src, oid = self._serviceOneRxMemo() + memo, src, vid = self._serviceOneRxMemo() self.logger.debug("Boss Peer RX: name=%s rx from src=%s memo=%s.", self.name, src, memo) @@ -818,7 +818,7 @@ def serviceRxMemos(self): Override in subclass to handle result(s) and put them somewhere """ while self.rxms: - memo, src, oid = self._serviceOneRxMemo() + memo, src, vid = self._serviceOneRxMemo() self.logger.debug("Hand Peer RX: name=%s rx from src=%s memo=%s.", self.name, src, memo) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index 834d46c4..b06ed392 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -39,7 +39,7 @@ Keyage = namedtuple("Keyage", "qvk qss") # example usage #keyage = Keyage(qvk="xyy", qss="abc", ) -#keep = dict("ABCXYZ"=keyage) # qualified oid as label, Keyage instance as value +#keep = dict("ABCXYZ"=keyage) # qualified vid as label, Keyage instance as value """Design Discusssion of Memo and Gram Sizing and Encoding: @@ -242,7 +242,7 @@ nz is the gram num (neck) part size int number of chars for the gram number for non-zeroth grams and the gram count for zeroth grams (zeroth gram the gram number must be 0 so don't need to include it) gram code indicates gram num 0 -vz is the vid (verifier id, origin ID) part size int number of chars in the vid part +vz is the vid (verifier id) part size int number of chars in the vid part az is the authenticator (signature) part size int number of chars in the auth part the authenticator part is discontinuously attached after the body part but its size is included in the overhead size computation for the body size @@ -401,7 +401,7 @@ class Memoer(Tymee): gram is put in bytearray for transport. Receive Flow:: - .receive -> (gram, src) -> grams parsed to .rxgs .counts .oids .sources -> + .receive -> (gram, src) -> grams parsed to .rxgs .counts .vids .sources -> signing key pair sigkey and verifier key -> .fuse -> memo .rxms deque @@ -462,20 +462,21 @@ class Memoer(Tymee): counts (dict): keyed by mid (memoID) that holds the gram count from the first gram for the memo. This enables lookup of the gram count when fusing its grams. - oids (dict[mid: (oid or None)]): keyed by mid that holds the origin ID str for - the memo indexed by its mid (memoID). This enables reattaching - the oid to memo when placing fused memo in rxms deque. - oid is only present when signed header otherwise oid is None + vids (dict[mid: (vid or None)]): keyed by mid that holds the vid verifier + ID str for the memo indexed by its mid (memoID). This enables + reattaching the vid to memo when placing fused memo in rxms deque. + vid is only present when signed header otherwise vid is None rxms (deque): holding rx (receive) memo tuples desegmented from rxgs grams each entry in deque is tuple of form: - (memo: str, src: str, oid: str) where: - memo is fused memo, src is source addr, oid is origin ID + (memo: str, src: str, vid: str) where: + memo is fused memo, src is source addr, vid is verifier ID txms (deque): holding tx (transmit) memo tuples to be segmented into txgs grams where each entry in deque is tuple of form - (memo: str, dst: str, oid: str or None) + (memo: str, dst: str, vid: str or None) memo is memo to be partitioned into gram dst is dst addr for grams - oid is origin id when gram is to be signed or None otherwise + vid is verifier id when gram is to be signed + (authenticated) or None otherwise txgs (deque): grams to transmit, each entry is duple of form: (gram: bytes, dst: str). txbs (tuple): current transmisstion duple of form: @@ -521,12 +522,12 @@ class Memoer(Tymee): Default echo is duple that indicates nothing to receive of form (b'', None). When False may be overridden by a method parameter. - keep (dict): labels are oids, values are Keyage instances + keep (dict): labels are vids, values are Keyage instances named tuple of signature key pair: sigkey = private signing key verkey = public verifying key Keyage = namedtuple("Keyage", "sigkey verkey") - oid (str or None): own oid defaults used to lookup keys to sign on tx + vid (str or None): own vid defaults used to lookup keys to sign on tx Hidden:: @@ -536,7 +537,7 @@ class Memoer(Tymee): _authic (bool): see authic property _echoic (bool): see echoic property _keep (dict): see keep property - _oid (str or None): see oid property + _oid (str or None): see vid property """ Version = Versionage(major=0, minor=0) # default version Codex = MemoDex @@ -598,51 +599,51 @@ def makeMID(cls, code='0A'): @classmethod - def _encodeOID(cls, raw, code='B'): - """Utility method for use with signed headers that encodes raw oid - (origin ID) as CESR compatible fully qualified B64 text domain str + def _encodeVID(cls, raw, code='B'): + """Utility method for use with signed headers that encodes raw vid + (verifier ID) as CESR compatible fully qualified B64 text domain str using CESR compatible text code - Parameters: - raw (bytes): oid to be encoded with code - code (str): code for type of raw oid CESR compatible + Parameters:: + raw (bytes): vid to be encoded with code + code (str): code for type of raw vid CESR compatible Ed25519N: str = 'B' # Ed25519 verkey non-transferable, basic derivation. Ed25519: str = 'D' # Ed25519 verkey basic derivation Blake3_256: str = 'E' # Blake3 256 bit digest derivation. - Returns: - qb64 (str): fully qualified base64 oid + Returns:: + qb64 (str): fully qualified base64 vid """ if code not in ('B', 'D', 'E'): - raise hioing.MemoerError(f"Invalid oid {code=}") + raise hioing.MemoerError(f"Invalid vid {code=}") rz = len(raw) # raw size if rz != 32: raise hioing.MemoerError(f"Invalid raw size {rz=} not 32") - pz = (3 - ((rz) % 3)) % 3 # net pad size for raw oid + pz = (3 - ((rz) % 3)) % 3 # net pad size for raw vid if len(code) != pz != 1: raise hioing.MemoerError(f"Invalid code size={len(code)} not equal" f" {pz=} not equal 1") b64 = encodeB64(bytes([0] * pz) + raw)[pz:] # prepad, convert, and prestrip - qb64 = code + b64.decode() # fully qualified base64 oid with prefix code + qb64 = code + b64.decode() # fully qualified base64 vid with prefix code _, _, _, vz, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az if len(qb64) != vz: - hioing.MemoerError(f"Invalid oid qb64 size={len(qb64) != {vz}}") + hioing.MemoerError(f"Invalid vid qb64 size={len(qb64) != {vz}}") - return qb64 # fully qualified base64 oid with prefix code + return qb64 # fully qualified base64 vid with prefix code @classmethod - def _decodeOID(cls, qb64): + def _decodeVID(cls, qb64): """Utility method for use with signed headers that decodes qualified - base64 oid to raw domain bytes from CESR compatible text code + base64 vid to raw domain bytes from CESR compatible text code - When oid code is 'B' nontransferable then don't look up in keep just get - the public key from the oid. This enables use cases for interacting without + When vid code is 'B' nontransferable then don't look up in keep just get + the public key from the vid. This enables use cases for interacting without having to preload keep with all nontrans OIDs. Allowed Codes: (CESR compatible) @@ -651,11 +652,11 @@ def _decodeOID(cls, qb64): Blake3_256: str = 'E' # Blake3 256 bit digest derivation. Parameters: - qb64 (str or bytes): qualified base64 oid to be decoded with code + qb64 (str or bytes): qualified base64 vid to be decoded with code Returns: tuple(raw, code) where: - raw (bytes): oid suitable for crypto operations + raw (bytes): vid suitable for crypto operations code (str): CESR compatible code from qb64 """ if hasattr(qb64, "decode"): # bytes @@ -664,11 +665,11 @@ def _decodeOID(cls, qb64): hz = 1 # only support qb64 length 44 code = qb64[:hz] if code not in ('B', 'D', 'E'): - raise hioing.MemoerError(f"Invalid oid {code=}") + raise hioing.MemoerError(f"Invalid vid {code=}") qz = len(qb64) # text size if qz != 44: - raise hioing.MemoerError(f"Invalid oid text size {qz=} not 44") + raise hioing.MemoerError(f"Invalid vid text size {qz=} not 44") hz = len(code) pz = hz % 4 # net pad size given hz @@ -684,7 +685,7 @@ def _decodeOID(cls, qb64): raise hioing.MemoerError(f"Nonzero midpad bytes=0x{pi:0{(pz)*2}x}.") if len(raw) != ((qz - hz) * 3 // 4): # exact lengths - raise hioing.MemoerError(f"Improperly qualified material = {oid}") + raise hioing.MemoerError(f"Improperly qualified material = {qb64}") return raw, code @@ -764,7 +765,7 @@ def _decodeQVK(cls, qb64): raise hioing.MemoerError(f"Nonzero midpad bytes=0x{pi:0{(pz)*2}x}.") if len(raw) != ((qz - hz) * 3 // 4): # exact lengths - raise hioing.MemoerError(f"Improperly qualified material = {qss}") + raise hioing.MemoerError(f"Improperly qualified material = {qb64}") return raw, code @@ -844,7 +845,7 @@ def _decodeQSS(cls, qb64): raise hioing.MemoerError(f"Nonzero midpad bytes=0x{pi:0{(pz)*2}x}.") if len(raw) != ((qz - hz) * 3 // 4): # exact lengths - raise hioing.MemoerError(f"Improperly qualified material = {qss}") + raise hioing.MemoerError(f"Improperly qualified material = {qb64}") return raw, code @@ -883,7 +884,7 @@ def _encodeSGN(cls, raw, code='0B'): if len(qb64) != az: hioing.MemoerError(f"Invalid sig qb64 size={len(qb64) != {az}}") - return qb64 # fully qualified base64 oid with prefix code + return qb64 # fully qualified base64 vid with prefix code @classmethod @@ -927,7 +928,7 @@ def _decodeSGN(cls, qb64): raise hioing.MemoerError(f"Nonzero midpad bytes=0x{pi:0{(pz)*2}x}.") if len(raw) != ((qz - hz) * 3 // 4): # exact lengths - raise hioing.MemoerError(f"Improperly qualified material = {sig}") + raise hioing.MemoerError(f"Improperly qualified material = {qb64}") return raw, code # qualified base64 sigseed @@ -941,7 +942,7 @@ def __init__(self, *, rxgs=None, sources=None, counts=None, - oids=None, + vids=None, rxms=None, txms=None, txgs=None, @@ -952,7 +953,7 @@ def __init__(self, *, authic=False, echoic=False, keep=None, - oid=None, + vid=None, **kwa ): """Setup instance @@ -982,21 +983,21 @@ def __init__(self, *, memo indexed by its mid (memoID). This enables lookup of the gram count for a given memo to know when it has received all its constituent grams in order to fuse back into the memo. - oids (dict[mid: (oid or None)]): keyed by mid that holds the origin ID + vids (dict[mid: (vid or None)]): keyed by mid that holds the verifier ID str for the memo indexed by its mid (memoID). - This enables reattaching the oid to memo when placing fused memo + This enables reattaching the vid to memo when placing fused memo in rxms deque. - oid is only present when signed header otherwise oid is None + vid is only present when signed header otherwise vid is None rxms (deque): holding rx (receive) memo tuples desegmented from rxgs grams each entry in deque is tuple of form: - (memo: str, src: str, oid: str) where: - memo is fused memo, src is source addr, oid is origin ID + (memo: str, src: str, vid: str) where: + memo is fused memo, src is source addr, vid is verifier ID txms (deque): holding tx (transmit) memo tuples to be segmented into txgs grams where each entry in deque is tuple of form - (memo: str, dst: str, oid: str or None) + (memo: str, dst: str, vid: str or None) memo is memo to be partitioned into gram dst is dst addr for grams - oid is origin id when gram is to be signed or None otherwise + vid is verifier id when gram is to be signed or None otherwise txgs (deque): grams to transmit, each entry is duple of form: (gram: bytes, dst: str). Grams include gram headers. txbs (tuple): current transmisstion duple of form: @@ -1023,11 +1024,11 @@ def __init__(self, *, Default echo is duple that indicates nothing to receive of form (b'', None). When False may be overridden by a method parameter. - keep (dict or None): labels are oids and values are Keyage instances - that provide current signature key pair for oid + keep (dict or None): labels are vids and values are Keyage instances + that provide current signature key pair for vid this is a lightweight mechanism that should be overridden in subclass for real world key management. - oid (str or None): own oid defaults used to lookup keys to sign on tx + vid (str or None): own vid defaults used to lookup keys to sign on tx tymeout (float): default for retry tymer if any """ @@ -1037,7 +1038,7 @@ def __init__(self, *, self.rxgs = rxgs if rxgs is not None else dict() self.sources = sources if sources is not None else dict() self.counts = counts if counts is not None else dict() - self.oids = oids if oids is not None else dict() + self.vids = vids if vids is not None else dict() self.rxms = rxms if rxms is not None else deque() self.txms = txms if txms is not None else deque() @@ -1075,7 +1076,7 @@ def __init__(self, *, self._echoic = True if echoic else False self._keep = keep if keep is not None else dict() - self.oid = oid if oid else None + self.vid = vid if vid else None @property def code(self): @@ -1187,28 +1188,28 @@ def keep(self): """Property getter for ._keep Returns: - dict: Mapping of oids to Keyage instances (sigkey, verkey). + dict: Mapping of vids to Keyage instances (sigkey, verkey). """ return self._keep @property - def oid(self): - """Property getter for ._oid + def vid(self): + """Property getter for ._vid Returns: - oid (str or None): oid used to sign on tx if any + vid (str or None): vid used to sign on tx if any """ - return self._oid + return self._vid - @oid.setter - def oid(self, oid): - """Property setter for ._oid + @vid.setter + def vid(self, vid): + """Property setter for ._vid Parameters: - oid (str or None): value to assign to own oid + vid (str or None): value to assign to own vid """ - self._oid = oid + self._vid = vid def open(self): @@ -1364,9 +1365,9 @@ def wiffNew(self, gram): raise hioing.MemoerError(f"Unexpected {sextet=} at gram head start.") - def verify(self, oid, sig, ser): + def verify(self, vid, sig, ser): """Verify signature sig on signed part of gram, ser, using current verkey - for oid. + for vid. Verify the signature on the header as per the serialized header format given by the header code as either qb2 or qb64. Do not convert @@ -1380,18 +1381,18 @@ def verify(self, oid, sig, ser): Raises MemoerVerifyError otherwise Parameters: - oid (bytes or str): qualified base64 qb64b of origin ID + vid (bytes or str): qualified base64 qb64b of verifier ID sig (bytes or str): qualified base64 qb64b signature ser (bytes or str): serialization to be signed """ - if hasattr(oid, "decode"): # bytes - oid = oid.decode() # make str + if hasattr(vid, "decode"): # bytes + vid = vid.decode() # make str - verkey, code = Memoer._decodeOID(oid) + verkey, code = Memoer._decodeVID(vid) if code not in ('B', ): # not non-trans so lookup in keep - if not (keyage := self.keep.get(oid)): - raise hioing.MemoerVerifyError(f"Missing keyage in keep for {oid=}") + if not (keyage := self.keep.get(vid)): + raise hioing.MemoerVerifyError(f"Missing keyage in keep for {vid=}") verkey, _ = Memoer._decodeQVK(keyage.qvk) # try: # may be correct size but not validly encoded @@ -1408,7 +1409,7 @@ def verify(self, oid, sig, ser): try: # _sign_verify_detached returns None if valid else raises ValueError pysodium.crypto_sign_verify_detached(rawsig, ser, verkey) except Exception as ex: - raise hioing.MemoerVerifyError(f"Signature verification failed from {oid=}" + raise hioing.MemoerVerifyError(f"Signature verification failed from {vid=}" f"for {sig=} on {ser=}") from ex return True @@ -1432,14 +1433,14 @@ def pickNew(self, gram): Returns: result (tuple): tuple of form: - (mid: str, oid: str, gn: int, gc: int or None) where: + (mid: str, vid: str, gn: int, gc: int or None) where: mid is fully qualified memoID, - oid is origin ID used to look up signature verification key, + vid is verifier ID used to look up signature verification key, gn is gram number, gc is gram count. - When first gram (zeroth) returns (mid, oid, 0, gc). - When other gram returns (mid, oid, gn, None) - When code has empty oid then oid is None + When first gram (zeroth) returns (mid, vid, 0, gc). + When other gram returns (mid, vid, gn, None) + When code has empty vid then vid is None Otherwise raises MemoerError error. When valid recognized header, strips header bytes from front of gram @@ -1484,7 +1485,7 @@ def pickNew(self, gram): else: gc = None # not provided in this gram - oid = encodeB64(gram[hz+mz+nz:hz+mz+nz+vz]) # convert to b64b + vid = encodeB64(gram[hz+mz+nz:hz+mz+nz+vz]) # convert to b64b sig = encodeB64(gram[-az if az else len(gram):]) # last ss bytes are signature del gram[-az if az else len(gram):] # strip sig if any sgram = bytes(gram[:]) # signed raw part make bytes copy to sign @@ -1515,16 +1516,16 @@ def pickNew(self, gram): else: gc = None # not provided in this gram - oid = bytes(gram[hz+mz+nz:hz+mz+nz+vz]) #bytearry to bytes qb64b convert to qb64 + vid = bytes(gram[hz+mz+nz:hz+mz+nz+vz]) #bytearry to bytes qb64b convert to qb64 sig = bytes(gram[-az if az else len(gram):]) # last az bytes signature del gram[-az if az else len(gram):] # strip sig if any sgram = bytes(gram[:]) # signed raw part make bytes copy to sign del gram[:oz-az] # strip of fore head leaving body in gram if sig: # signature not empty - self.verify(oid, sig, sgram) # raises MemoerVerifyError if invalid + self.verify(vid, sig, sgram) # raises MemoerVerifyError if invalid - return (mid.decode(), oid.decode() if oid else None, gn, gc) + return (mid.decode(), vid.decode() if vid else None, gn, gc) def pick(self, gram): @@ -1540,14 +1541,14 @@ def pick(self, gram): Returns: result (tuple): tuple of form: - (mid: str, oid: str, gn: int, gc: int or None) where: + (mid: str, vid: str, gn: int, gc: int or None) where: mid is fully qualified memoID, - oid is origin ID used to look up signature verification key, + vid is verifier ID used to look up signature verification key, gn is gram number, gc is gram count. - When first gram (zeroth) returns (mid, oid, 0, gc). - When other gram returns (mid, oid, gn, None) - When code has empty oid then oid is None + When first gram (zeroth) returns (mid, vid, 0, gc). + When other gram returns (mid, vid, gn, None) + When code has empty vid then vid is None Otherwise raises MemoerError error. When valid recognized header, strips header bytes from front of gram @@ -1584,11 +1585,11 @@ def pick(self, gram): f" < {oz + 1}.") mid = encodeB64(gram[:cms]) # convert to b64b with prefix code - oid = encodeB64(gram[cms:cms+vz]) # convert to b64b + vid = encodeB64(gram[cms:cms+vz]) # convert to b64b neck = gram[cms+vz:cms+vz+nz] # bytearray to bytes short part of neck gn = int.from_bytes(neck) # gram number convert to int #neck = encodeB64(neck) # convert to b64b - #head = mid + oid + neck # bytes + #head = mid + vid + neck # bytes if gn == 0: # first (zeroth) gram so long neck if len(gram) < oz + nz + 1: raise hioing.MemoerError(f"Not enough rx bytes for b2 " @@ -1624,10 +1625,10 @@ def pick(self, gram): f" < {oz + 1}.") mid = bytes(gram[:hz+mz]) # bytearray to bytes qb64b with prefix - oid = bytes(gram[hz+mz:hz+mz+vz]) #bytearry to bytes qb64b convert to qb64 + vid = bytes(gram[hz+mz:hz+mz+vz]) #bytearry to bytes qb64b convert to qb64 neck = bytes(gram[hz+mz+vz:hz+mz+vz+nz]) # qb64b short part of neck gn = helping.b64ToInt(neck) - #head = mid + oid + neck # bytes + #head = mid + vid + neck # bytes if gn == 0: # first (zeroth) gram so long neck if len(gram) < oz + nz + 1: raise hioing.MemoerError(f"Not enough rx bytes for b64 " @@ -1648,9 +1649,9 @@ def pick(self, gram): if sig: # signature not empty #sgram = head + bytes(gram) # bytearray to bytes - self.verify(oid, sig, sgram) # raises MemoerVerifyError if invalid + self.verify(vid, sig, sgram) # raises MemoerVerifyError if invalid - return (mid.decode(), oid.decode() if oid else None, gn, gc) + return (mid.decode(), vid.decode() if vid else None, gn, gc) @@ -1732,7 +1733,7 @@ def _serviceOneReceived(self, *, echoic=False): gram = bytearray(gram) # make copy bytearray so can strip off header try: - mid, oid, gn, gc = self.pick(gram) # parse and strip off head leaving body + mid, vid, gn, gc = self.pick(gram) # parse and strip off head leaving body except hioing.MemoerError as ex: # invalid gram so drop # may be bad signature when signed or unrecognized header format logger.error("Invalid Memoer gram from %s.\n %s.", src, ex) @@ -1749,8 +1750,8 @@ def _serviceOneReceived(self, *, echoic=False): if mid not in self.counts: # make idempotent first only no replay self.counts[mid] = gc # save gram count for mid - if mid not in self.oids: - self.oids[mid] = oid + if mid not in self.vids: + self.vids[mid] = vid # assumes unique mid across all possible sources. No replay by different # source only first source for a given mid is ever recognized @@ -1825,11 +1826,11 @@ def _serviceOnceRxGrams(self): continue memo = self.fuse(self.rxgs[mid], self.counts[mid]) if memo is not None: # allows for empty "" memo for some src - self.rxms.append((memo, self.sources[mid], self.oids[mid])) + self.rxms.append((memo, self.sources[mid], self.vids[mid])) del self.rxgs[mid] del self.counts[mid] del self.sources[mid] - del self.oids[mid] + del self.vids[mid] def serviceRxGramsOnce(self): @@ -1866,7 +1867,7 @@ def serviceRxMemosOnce(self): Override in subclass to handle result and put it somewhere """ try: - #memo, src, oid = self._serviceOneRxMemo() + #memo, src, vid = self._serviceOneRxMemo() self.inbox.append(self._serviceOneRxMemo()) except IndexError: pass @@ -1878,7 +1879,7 @@ def serviceRxMemos(self): Override in subclass to handle result(s) and put them somewhere """ while self.rxms: - #memo, src, oid = self._serviceOneRxMemo() + #memo, src, vid = self._serviceOneRxMemo() self.inbox.append(self._serviceOneRxMemo()) @@ -1898,19 +1899,19 @@ def serviceAllRx(self): self.serviceRxMemos() - def memoit(self, memo, dst, oid=None): - """Append (memo, dst, oid) tuple to .txms deque + def memoit(self, memo, dst, vid=None): + """Append (memo, dst, vid) tuple to .txms deque Parameters: memo (str): to be segmented and packed into gram(s) dst (str): address of remote destination of memo - oid (str or None): origin ID for verifying signature on grams + vid (str or None): verifier ID for verifying signature on grams """ - self.txms.append((memo, dst, oid)) + self.txms.append((memo, dst, vid)) - def sign(self, oid, ser): - """Sign serialization ser using private sigkey for origin ID oid and return + def sign(self, vid, ser): + """Sign serialization ser using private sigkey for verifier ID vid and return signature in serialized format defined by .curt Sign the serialized signed part of gram given by ser. Assumes that @@ -1926,18 +1927,18 @@ def sign(self, oid, ser): raises MemoerError if problem signing Parameters: - oid (bytes or str): qb64 or qb2 if .curt of oid of signer - assumes oid of correct length + vid (bytes or str): qb64 or qb2 if .curt of vid of signer + assumes vid of correct length ser (bytes or str): serialization to be signed (usually qb64 or qb64b) """ - if hasattr(oid, "decode"): # bytes - oid = oid.decode() # make str + if hasattr(vid, "decode"): # bytes + vid = vid.decode() # make str - if oid not in self.keep: - raise hioing.MemoerError("Invalid {oid=} for signing") + if vid not in self.keep: + raise hioing.MemoerError(f"Invalid {vid=} for signing") - qvk, qss = self.keep[oid] + qvk, qss = self.keep[vid] sigseed, code = self._decodeQSS(qss) # raises MemoerError if problem if code not in ('A'): raise hioing.MemoerError(f"Invalid sigseed algorithm type {code=}") @@ -1955,7 +1956,7 @@ def sign(self, oid, ser): return sig - def rend(self, memo, oid=None): + def rend(self, memo, vid=None): """Partition memo into packed grams with headers. Returns: @@ -1963,7 +1964,7 @@ def rend(self, memo, oid=None): Parameters: memo (str): to be partitioned into grams with headers - oid (str or None): origin ID when gram is to be signed, used to + vid (str or None): verifier ID when gram is to be signed, used to lookup sigkey to sign. None means not signable @@ -1978,10 +1979,10 @@ def rend(self, memo, oid=None): hz, mz, nz, vz, az = self.Sizes[self.code] # hz mz nz vz az oz = hz + mz + nz + vz + az - oid = oid if oid is not None else self.oid + vid = vid if vid is not None else self.vid - if vz and (not oid or len(oid) != vz): - raise hioing.MemoerError(f"Missing or invalid {oid=} for {vz=}") + if vz and (not vid or len(vid) != vz): + raise hioing.MemoerError(f"Missing or invalid {vid=} for {vz=}") pz = (3 - ((mz) % 3)) % 3 # net pad size for mid # memo ID is 16 byte random UUID converted to 22 char Base64 right aligned @@ -2029,11 +2030,11 @@ def rend(self, memo, oid=None): else: num = helping.intToB64b(gn, l=nz) # num size must always be neck size - if vz: # need oid part, but can't mod here may need below to sign + if vz: # need vid part, but can't mod here may need below to sign if self.curt: - oidp = decodeB64(oid.encode()) # oid part b2 + oidp = decodeB64(vid.encode()) # vid part b2 else: - oidp = oid.encode() # oid part b64 bytes + oidp = vid.encode() # vid part b64 bytes head = mid + oidp + num else: head = mid + num @@ -2046,7 +2047,7 @@ def rend(self, memo, oid=None): del memo[:bz] # del slice past end just deletes to end if az: # signed gram, .sign returns proper sig format when .curt - sig = self.sign(oid, gram) # raises MemoerError if invalid + sig = self.sign(vid, gram) # raises MemoerError if invalid gram = gram + sig grams.append(gram) @@ -2092,9 +2093,9 @@ def send(self, gram, dst, *, echoic=False) -> int: def _serviceOneTxMemo(self): - """Service one (memo, dst, oid) tuple from .txms deque where tuple is - of form (memo: str, dst: str, oid: str) where memo is the outgoing - memo, dst is the destination address, and oid is the origin ID used to + """Service one (memo, dst, vid) tuple from .txms deque where tuple is + of form (memo: str, dst: str, vid: str) where memo is the outgoing + memo, dst is the destination address, and vid is the verifier ID used to look up the sigkey to sign. Calls .rend method to process the partitioning and packing as @@ -2103,9 +2104,9 @@ def _serviceOneTxMemo(self): Appends (gram, dst) duple to .txgs deque. """ - memo, dst, oid = self.txms.popleft() # raises IndexError if empty deque + memo, dst, vid = self.txms.popleft() # raises IndexError if empty deque - for gram in self.rend(memo, oid): # partition memo into gram parts with head + for gram in self.rend(memo, vid): # partition memo into gram parts with head self.txgs.append((gram, dst)) # append duples (gram: bytes, dst: str) @@ -2424,20 +2425,20 @@ class AuthMemoer(Memoer): counts (dict): keyed by mid (memoID) that holds the gram count from the first gram for the memo. This enables lookup of the gram count when fusing its grams. - oids (dict[mid: (oid or None)]): keyed by mid that holds the origin ID str for + vids (dict[mid: (vid or None)]): keyed by mid that holds the verifier ID str for the memo indexed by its mid (memoID). This enables reattaching - the oid to memo when placing fused memo in rxms deque. - Vid is only present when signed header otherwise oid is None + the vid to memo when placing fused memo in rxms deque. + Vid is only present when signed header otherwise vid is None rxms (deque): holding rx (receive) memo tuples desegmented from rxgs grams each entry in deque is tuple of form: - (memo: str, src: str, oid: str) where: - memo is fused memo, src is source addr, oid is origin ID + (memo: str, src: str, vid: str) where: + memo is fused memo, src is source addr, vid is verifier ID txms (deque): holding tx (transmit) memo tuples to be segmented into txgs grams where each entry in deque is tuple of form - (memo: str, dst: str, oid: str or None) + (memo: str, dst: str, vid: str or None) memo is memo to be partitioned into gram dst is dst addr for grams - oid is origin id when gram is to be signed or None otherwise + vid is verifier id when gram is to be signed or None otherwise txgs (deque): grams to transmit, each entry is duple of form: (gram: bytes, dst: str). txbs (tuple): current transmisstion duple of form: @@ -2483,12 +2484,12 @@ class AuthMemoer(Memoer): Default echo is duple that indicates nothing to receive of form (b'', None) When False may be overridden by a method parameter - keep (dict): labels are oids, values are Keyage instances + keep (dict): labels are vids, values are Keyage instances named tuple of signature key pair: sigkey = private signing key verkey = public verifying key Keyage = namedtuple("Keyage", "sigkey verkey") - oid (str or None): own oid defaults used to lookup keys to sign on tx + vid (str or None): own vid defaults used to lookup keys to sign on tx """ diff --git a/src/hio/core/udp/peermemoing.py b/src/hio/core/udp/peermemoing.py index 583b58c7..e7317776 100644 --- a/src/hio/core/udp/peermemoing.py +++ b/src/hio/core/udp/peermemoing.py @@ -56,20 +56,20 @@ class PeerMemoer(Peer, Memoer): counts (dict): keyed by mid (memoID) that holds the gram count from the first gram for the memo. This enables lookup of the gram count when fusing its grams. - oids (dict[mid: (oid | None)]): keyed by mid that holds the origin ID str for + vids (dict[mid: (vid | None)]): keyed by mid that holds the verifier ID str for the memo indexed by its mid (memoID). This enables reattaching - the oid to memo when placing fused memo in rxms deque. - Vid is only present when signed header otherwise oid is None + the vid to memo when placing fused memo in rxms deque. + Vid is only present when signed header otherwise vid is None rxms (deque): holding rx (receive) memo tuples desegmented from rxgs grams each entry in deque is tuple of form: - (memo: str, src: str, oid: str) where: - memo is fused memo, src is source addr, oid is origin ID + (memo: str, src: str, vid: str) where: + memo is fused memo, src is source addr, vid is verifier ID txms (deque): holding tx (transmit) memo tuples to be segmented into txgs grams where each entry in deque is tuple of form - (memo: str, dst: str, oid: str | None) + (memo: str, dst: str, vid: str | None) memo is memo to be partitioned into gram dst is dst addr for grams - oid is verification id when gram is to be signed or None otherwise + vid is verification id when gram is to be signed or None otherwise txgs (deque): grams to transmit, each entry is duple of form: (gram: bytes, dst: str). txbs (tuple): current transmisstion duple of form: @@ -105,8 +105,8 @@ class PeerMemoer(Peer, Memoer): size (int): gram size when rending for tx. authic (bool): True means any rx grams must be signed; False otherwise echoic (bool): True means use .echos in .send and .receive to mock transport. - keep (dict): labels are oids and values are Keyage instances. - oid (str|None): own oid defaults used to lookup keys to sign on tx + keep (dict): labels are vids and values are Keyage instances. + vid (str|None): own vid defaults used to lookup keys to sign on tx Notes:: - size: first gram size = over head size + neck size + body size; diff --git a/tests/core/memo/test_memoing.py b/tests/core/memo/test_memoing.py index 9c7d35eb..d7e5d4f0 100644 --- a/tests/core/memo/test_memoing.py +++ b/tests/core/memo/test_memoing.py @@ -24,10 +24,10 @@ def _setupKeep(salt=None): """Setup Keep for signed memos Parameters: - salt(str|bytes): salt used to generate key pairs and oids for keep + salt(str|bytes): salt used to generate key pairs and vids for keep Returns: - keep (dict): labels are oids, values are keyage instances + keep (dict): labels are vids, values are keyage instances Ed25519_Seed: str = 'A' # Ed25519 256 bit random seed for private key @@ -41,7 +41,7 @@ def _setupKeep(salt=None): keep = {} - # non transferable verkey as oid + # non transferable verkey as vid sigseed = pysodium.crypto_pwhash(outlen=32, passwd="0", salt=salt, @@ -51,13 +51,13 @@ def _setupKeep(salt=None): # creates signing/verification key pair from seed verkey, sigkey = pysodium.crypto_sign_seed_keypair(sigseed) # raw - oid = Memoer._encodeOID(raw=verkey, code='B') # make fully qualified + vid = Memoer._encodeVID(raw=verkey, code='B') # make fully qualified qvk = Memoer._encodeQVK(raw=verkey) # make fully qualified qss = Memoer._encodeQSS(raw=sigseed) # make fully qualified keyage = Keyage(qvk=qvk, qss=qss) # raw - keep[oid] = keyage + keep[vid] = keyage - # transferable verkey as oid + # transferable verkey as vid sigseed = pysodium.crypto_pwhash(outlen=32, passwd="1", salt=salt, @@ -67,13 +67,13 @@ def _setupKeep(salt=None): # creates signing/verification key pair from seed verkey, sigkey = pysodium.crypto_sign_seed_keypair(sigseed) # raw - oid = Memoer._encodeOID(raw=verkey, code='D') # make fully qualified + vid = Memoer._encodeVID(raw=verkey, code='D') # make fully qualified qvk = Memoer._encodeQVK(raw=verkey) # make fully qualified qss = Memoer._encodeQSS(raw=sigseed) # make fully qualified keyage = Keyage(qvk=qvk, qss=qss) # raw - keep[oid] = keyage + keep[vid] = keyage - # digest of verkey as oid + # digest of verkey as vid sigseed = pysodium.crypto_pwhash(outlen=32, passwd="2", salt=salt, @@ -84,11 +84,11 @@ def _setupKeep(salt=None): verkey, sigkey = pysodium.crypto_sign_seed_keypair(sigseed) # raw dig = digest = blake3.blake3(verkey).digest() - oid = Memoer._encodeOID(raw=dig, code='E') + vid = Memoer._encodeVID(raw=dig, code='E') qvk = Memoer._encodeQVK(raw=verkey) # make fully qualified qss = Memoer._encodeQSS(raw=sigseed) # make fully qualified keyage = Keyage(qvk=qvk, qss=qss) # raw - keep[oid] = keyage + keep[vid] = keyage return keep @@ -150,7 +150,7 @@ def test_memoer_class(): assert mz # mid must not be empty pz = (3 - ((mz) % 3)) % 3 # net pad size for mid assert pz == (hz % 4) # combined code + mid size must lie on 24 bit boundary - assert not vz % 4 # oid size must be on 24 bit boundary + assert not vz % 4 # vid size must be on 24 bit boundary assert not az % 4 # sig size must be on 24 bit boundary assert nz and not nz % 4 # neck (num) size must be on 24 bit boundary @@ -190,17 +190,17 @@ def test_memoer_class(): assert Memoer.BufSize == (2**16-1) # default buffersize verkey = (b"o\x91\xf4\xbe$Mu\x0b{}\xd3\xaa'g\xd1\xcf\x96\xfb\x1e\xb1S\x89H\\'ae\x06+\xb2(v") - oid = Memoer._encodeOID(raw=verkey) - assert oid == 'BG-R9L4kTXULe33Tqidn0c-W-x6xU4lIXCdhZQYrsih2' - raw, code = Memoer._decodeOID(oid) + vid = Memoer._encodeVID(raw=verkey) + assert vid == 'BG-R9L4kTXULe33Tqidn0c-W-x6xU4lIXCdhZQYrsih2' + raw, code = Memoer._decodeVID(vid) assert raw == verkey assert code == 'B' # nontrans AID _, _, _, vz, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az - assert len(oid) == 44 == vz + assert len(vid) == 44 == vz qvk = Memoer._encodeQVK(raw=verkey) assert qvk == 'BG-R9L4kTXULe33Tqidn0c-W-x6xU4lIXCdhZQYrsih2' - raw, code = Memoer._decodeQVK(oid) + raw, code = Memoer._decodeQVK(vid) assert raw == verkey assert code == 'B' assert len(qvk) == 44 @@ -272,10 +272,10 @@ def test_memoer_sign_verify(): except MemoerError as ex: return - oid = list(keep.keys())[0] - assert oid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' + vid = list(keep.keys())[0] + assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' - peer = memoing.Memoer(code=MemoDex.AuthMemoGram, keep=keep, oid=oid) + peer = memoing.Memoer(code=MemoDex.AuthMemoGram, keep=keep, vid=vid) assert peer.name == "main" assert peer.opened == False assert peer.bc is None @@ -287,42 +287,42 @@ def test_memoer_sign_verify(): assert not peer.authic assert not peer.echoic assert peer.keep == keep - assert peer.oid == oid + assert peer.vid == vid memo = "Hello There" - oid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .oid - assert oid in peer.keep + vid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .vid + assert vid in peer.keep mid = '_-ALBI68S1ZIxqwFOSWFF1L2' lneck = 'AAAC' # gram count 2 # create signed portion of gram long neck neck = 'AAAA' # gram number 0 - head = mid + oid + neck + lneck + head = mid + vid + neck + lneck sgram = (head + "Hello There").encode() #sign - sgntr = peer.sign(oid, sgram) + sgntr = peer.sign(vid, sgram) #verify - assert peer.verify(oid, sgntr, sgram) + assert peer.verify(vid, sgntr, sgram) # test invalid bad gram bgram = (head + "Hello Where").encode() with pytest.raises(MemoerVerifyError): - peer.verify(oid, sgntr, bgram) + peer.verify(vid, sgntr, bgram) # create signed portion of gram short neck neck = 'AAAB' # gram number 1 - head = mid + oid + neck + head = mid + vid + neck sgram = (head + "Hello There").encode() #sign - sgntr = peer.sign(oid, sgram) + sgntr = peer.sign(vid, sgram) #verify - assert peer.verify(oid, sgntr, sgram) + assert peer.verify(vid, sgntr, sgram) # test invalid bad gram bgram = (head + "Hello Where").encode() with pytest.raises(MemoerVerifyError): - peer.verify(oid, sgntr, bgram) + peer.verify(vid, sgntr, bgram) """Done""" @@ -343,7 +343,7 @@ def test_memoer_basic(): assert not peer.authic assert not peer.echoic assert peer.keep == dict() - assert peer.oid is None + assert peer.vid is None assert peer.tymeout == 0.0 assert peer.tymers == {} @@ -497,7 +497,7 @@ def test_memoer_small_gram_size(): assert not peer.authic assert not peer.echoic assert peer.keep == dict() - assert peer.oid is None + assert peer.vid is None peer = memoing.Memoer(size=38) assert peer.size == 38 @@ -672,7 +672,7 @@ def test_memoer_multiple(): assert not peer.authic assert not peer.echoic assert peer.keep == dict() - assert peer.oid is None + assert peer.vid is None peer.reopen() assert peer.opened == True @@ -751,7 +751,7 @@ def test_memoer_multiple_echoic_service_tx_rx(): assert not peer.authic assert peer.echoic assert peer.keep == dict() - assert peer.oid is None + assert peer.vid is None peer.reopen() assert peer.opened == True @@ -805,7 +805,7 @@ def test_memoer_multiple_echoic_service_all(): assert not peer.authic assert peer.echoic assert peer.keep == dict() - assert peer.oid is None + assert peer.vid is None peer.reopen() assert peer.opened == True @@ -848,10 +848,10 @@ def test_memoer_basic_signed(): except MemoerError as ex: return - oid = list(keep.keys())[0] - assert oid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' + vid = list(keep.keys())[0] + assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' - peer = memoing.Memoer(code=MemoDex.AuthMemoGram, keep=keep, oid=oid) + peer = memoing.Memoer(code=MemoDex.AuthMemoGram, keep=keep, vid=vid) assert peer.name == "main" assert peer.opened == False assert peer.bc is None @@ -863,7 +863,7 @@ def test_memoer_basic_signed(): assert not peer.authic assert not peer.echoic assert peer.keep == keep - assert peer.oid == oid + assert peer.vid == vid peer.reopen() assert peer.opened == True @@ -877,9 +877,9 @@ def test_memoer_basic_signed(): memo = "Hello There" dst = "beta" - oid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .oid - peer.memoit(memo, dst, oid) - assert peer.txms[0] == ('Hello There', 'beta', oid) + vid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .vid + peer.memoit(memo, dst, vid) + assert peer.txms[0] == ('Hello There', 'beta', vid) peer.serviceTxMemos() assert not peer.txms g, d = peer.txgs[0] @@ -902,7 +902,7 @@ def test_memoer_basic_signed(): # test with invalid signature sig = ('A' * 88) - gram = (mid + oid + 'AAAA' + 'AAAB' + "Hello There" + sig).encode() + gram = (mid + vid + 'AAAA' + 'AAAB' + "Hello There" + sig).encode() echo = (gram, "beta") peer.echos.append(echo) peer.serviceReceives(echoic=True) @@ -911,9 +911,9 @@ def test_memoer_basic_signed(): # test with valid signature # create signed portion of gram - sgram = (mid + oid + 'AAAA' + 'AAAB' + "Hello There").encode() - qvk, qss = peer.keep[oid] - sig = peer.sign(oid, sgram) + sgram = (mid + vid + 'AAAA' + 'AAAB' + "Hello There").encode() + qvk, qss = peer.keep[vid] + sig = peer.sign(vid, sgram) gram = sgram + sig echo = (gram, "beta") peer.echos.append(echo) @@ -925,16 +925,16 @@ def test_memoer_basic_signed(): assert not peer.rxgs assert not peer.counts assert not peer.sources - assert peer.rxms[0] == ('Hello There', 'beta', oid) + assert peer.rxms[0] == ('Hello There', 'beta', vid) peer.serviceRxMemos() assert not peer.rxms # send and receive via echo memo = "See ya later!" dst = "beta" - oid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .oid - peer.memoit(memo, dst, oid) - assert peer.txms[0] == ('See ya later!', 'beta', oid) + vid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .vid + peer.memoit(memo, dst, vid) + assert peer.txms[0] == ('See ya later!', 'beta', vid) peer.serviceTxMemos() assert not peer.txms g, d = peer.txgs[0] @@ -963,7 +963,7 @@ def test_memoer_basic_signed(): assert not peer.counts assert not peer.sources peer.rxms[0] - assert peer.rxms[0] == ('See ya later!', 'beta', oid) + assert peer.rxms[0] == ('See ya later!', 'beta', vid) peer.serviceRxMemos() assert not peer.rxms @@ -971,9 +971,9 @@ def test_memoer_basic_signed(): peer.curt = True # set to binary base2 memo = "Hello There" dst = "beta" - oid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .oid - peer.memoit(memo, dst, oid) - assert peer.txms[0] == ('Hello There', 'beta', oid) + vid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .vid + peer.memoit(memo, dst, vid) + assert peer.txms[0] == ('Hello There', 'beta', vid) peer.serviceTxMemos() assert not peer.txms g, d = peer.txgs[0] @@ -995,16 +995,16 @@ def test_memoer_basic_signed(): mid = '_-ALBI68S1ZIxqwFOSWFF1L2' # signed header # test with valid signature - oid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .oid - head = mid + oid + 'AAAA' + 'AAAB' + vid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .vid + head = mid + vid + 'AAAA' + 'AAAB' assert len(head) == 76 head = decodeB64(head.encode()) # qb2 version of head assert len(head) == 57 sgram = head + memo.encode() # sign the qb2 version assert len(sgram) == 68 assert peer.curt - qvk, qss = peer.keep[oid] - tail = peer.sign(oid, sgram) # returns sig in qb2 becaue .curt + qvk, qss = peer.keep[vid] + tail = peer.sign(vid, sgram) # returns sig in qb2 becaue .curt assert len(tail) == 66 gram = head + memo.encode() + tail # qb2 version @@ -1020,13 +1020,13 @@ def test_memoer_basic_signed(): assert not peer.rxgs assert not peer.counts assert not peer.sources - assert peer.rxms[0] == ('Hello There', 'beta', oid) + assert peer.rxms[0] == ('Hello There', 'beta', vid) peer.serviceRxMemos() assert not peer.rxms - assert peer.inbox[0] == ('Hello There', 'beta', oid) - assert peer.inbox[1] == ('See ya later!', 'beta', oid) - assert peer.inbox[2] == ('Hello There', 'beta', oid) + assert peer.inbox[0] == ('Hello There', 'beta', vid) + assert peer.inbox[1] == ('See ya later!', 'beta', vid) + assert peer.inbox[2] == ('Hello There', 'beta', vid) peer.inbox = deque() # clear it @@ -1043,13 +1043,13 @@ def test_memoer_multiple_signed(): except MemoerError as ex: return - oid = list(keep.keys())[0] - assert oid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' + vid = list(keep.keys())[0] + assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' oidBeta = list(keep.keys())[1] assert oidBeta == 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' - peer = memoing.Memoer(code=MemoDex.AuthMemoGram, size=170, keep=keep, oid=oid) + peer = memoing.Memoer(code=MemoDex.AuthMemoGram, size=170, keep=keep, vid=vid) assert peer.size == 170 assert peer.name == "main" assert peer.opened == False @@ -1060,7 +1060,7 @@ def test_memoer_multiple_signed(): assert not peer.authic # force rx must be signed assert not peer.echoic assert peer.keep == keep - assert peer.oid == oid + assert peer.vid == vid peer.reopen() assert peer.opened == True @@ -1109,7 +1109,7 @@ def test_memoer_multiple_signed(): assert not peer.counts assert not peer.sources assert len(peer.rxms) == 2 - assert peer.rxms[0] == ('Hello there.', 'alpha', oid) + assert peer.rxms[0] == ('Hello there.', 'alpha', vid) assert peer.rxms[1] == ('How ya doing?', 'beta', oidBeta) peer.serviceRxMemos() assert not peer.rxms @@ -1164,16 +1164,16 @@ def test_memoer_multiple_signed(): assert not peer.counts assert not peer.sources assert len(peer.rxms) == 2 - assert peer.rxms[0] == ('Hello there.', 'alpha', oid) + assert peer.rxms[0] == ('Hello there.', 'alpha', vid) assert peer.rxms[1] == ('How ya doing?', 'beta', oidBeta) peer.serviceRxMemos() assert not peer.rxms assert peer.inbox == deque( [ - ('Hello there.', 'alpha', oid), + ('Hello there.', 'alpha', vid), ('How ya doing?', 'beta', oidBeta), - ('Hello there.', 'alpha', oid), + ('Hello there.', 'alpha', vid), ('How ya doing?', 'beta', oidBeta) ]) @@ -1192,10 +1192,10 @@ def test_memoer_verific(): except MemoerError as ex: return - oid = list(keep.keys())[0] - assert oid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' + vid = list(keep.keys())[0] + assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' - peer = memoing.Memoer(authic=True, keep=keep, oid=oid) + peer = memoing.Memoer(authic=True, keep=keep, vid=vid) assert peer.name == "main" assert peer.opened == False assert peer.bc is None @@ -1207,7 +1207,7 @@ def test_memoer_verific(): assert peer.authic assert not peer.echoic assert peer.keep == keep - assert peer.oid is oid + assert peer.vid is vid peer.reopen() assert peer.opened == True @@ -1230,11 +1230,11 @@ def test_memoer_verific(): assert not peer.sources assert not peer.rxms mid = '_-ALBI68S1ZIxqwFOSWFF1L2' # signed code - oid = list(keep.keys())[1] + vid = list(keep.keys())[1] sig = ('A' * 88) - sgram = (mid + oid + 'AAAA' + 'AAAB' + "Hello There").encode() - qvk, qss = peer.keep[oid] - sig = peer.sign(oid, sgram) + sgram = (mid + vid + 'AAAA' + 'AAAB' + "Hello There").encode() + qvk, qss = peer.keep[vid] + sig = peer.sign(vid, sgram) gram = sgram + sig echo = (gram, "beta") peer.echos.append(echo) @@ -1247,13 +1247,13 @@ def test_memoer_verific(): assert not peer.rxgs assert not peer.counts assert not peer.sources - assert peer.rxms[0] == ('Hello There', 'beta', oid) + assert peer.rxms[0] == ('Hello There', 'beta', vid) peer.serviceRxMemos() assert not peer.rxms assert peer.inbox == deque( [ - ('Hello There', 'beta', oid) + ('Hello There', 'beta', vid) ]) peer.close() @@ -1271,8 +1271,8 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): except MemoerError as ex: return - oid = list(keep.keys())[0] - assert oid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' + vid = list(keep.keys())[0] + assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' vidBeta = list(keep.keys())[1] assert vidBeta == 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' @@ -1280,7 +1280,7 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): # authic forces rx memos to be signed or dropped # to force signed tx then use Signed code peer = memoing.Memoer(code=MemoDex.AuthMemoGram, size=170, authic=True, - echoic=True, keep=keep, oid=oid) + echoic=True, keep=keep, vid=vid) assert peer.size == 170 assert peer.name == "main" assert peer.opened == False @@ -1291,7 +1291,7 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): assert peer.authic assert peer.echoic assert peer.keep == keep - assert peer.oid == oid + assert peer.vid == vid peer.reopen() assert peer.opened == True @@ -1321,7 +1321,7 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): assert peer.inbox == deque( [ - ('Hello there.', 'alpha', oid), + ('Hello there.', 'alpha', vid), ('How ya doing?', 'beta', vidBeta) ]) @@ -1356,9 +1356,9 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): assert peer.inbox == deque( [ - ('Hello there.', 'alpha', oid), + ('Hello there.', 'alpha', vid), ('How ya doing?', 'beta', vidBeta), - ('Hello there.', 'alpha', oid), + ('Hello there.', 'alpha', vid), ('How ya doing?', 'beta', vidBeta), ]) @@ -1422,13 +1422,13 @@ def test_auth_memoer_basic(): except MemoerError as ex: return - oid = list(keep.keys())[0] - assert oid == 'BG-R9L4kTXULe33Tqidn0c-W-x6xU4lIXCdhZQYrsih2' + vid = list(keep.keys())[0] + assert vid == 'BG-R9L4kTXULe33Tqidn0c-W-x6xU4lIXCdhZQYrsih2' oidBeta = list(keep.keys())[1] assert oidBeta == 'DJb1Z0pHx36MCOuIHWR4yPxfIiBxVzg6UCamv8fAN8gH' - peer = memoing.AuthMemoer(echoic=True, keep=keep, oid=oid) + peer = memoing.AuthMemoer(echoic=True, keep=keep, vid=vid) assert peer.size == 65535 assert peer.name == "main" assert peer.opened == False @@ -1439,7 +1439,7 @@ def test_auth_memoer_basic(): assert peer.authic assert peer.echoic assert peer.keep == keep - assert peer.oid == oid + assert peer.vid == vid assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, nz=4, vz=44, az=88) assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88) # hz mz nz vz az @@ -1592,8 +1592,8 @@ def test_auth_memoer_multiple_echoic_service_all(): except MemoerError as ex: return - oid = list(keep.keys())[0] - assert oid == 'BG-R9L4kTXULe33Tqidn0c-W-x6xU4lIXCdhZQYrsih2' + vid = list(keep.keys())[0] + assert vid == 'BG-R9L4kTXULe33Tqidn0c-W-x6xU4lIXCdhZQYrsih2' oidBeta = list(keep.keys())[1] assert oidBeta == 'DJb1Z0pHx36MCOuIHWR4yPxfIiBxVzg6UCamv8fAN8gH' @@ -1601,7 +1601,7 @@ def test_auth_memoer_multiple_echoic_service_all(): # authic forces rx memos to be authenticated/signed or dropped # to force signed tx then use Auth type header code - with memoing.openAM(size=170, echoic=True, keep=keep, oid=oid) as peer: + with memoing.openAM(size=170, echoic=True, keep=keep, vid=vid) as peer: assert peer.size == 170 assert peer.name == "test" assert peer.opened == True @@ -1612,7 +1612,7 @@ def test_auth_memoer_multiple_echoic_service_all(): assert peer.authic assert peer.echoic assert peer.keep == keep - assert peer.oid is oid + assert peer.vid is vid # send and receive multiple via echo peer.memoit("Hello there.", "alpha") @@ -1640,7 +1640,7 @@ def test_auth_memoer_multiple_echoic_service_all(): assert peer.inbox == deque( [ - ('Hello there.', 'alpha', oid), + ('Hello there.', 'alpha', vid), ('How ya doing?', 'beta', oidBeta) ]) @@ -1676,9 +1676,9 @@ def test_auth_memoer_multiple_echoic_service_all(): assert peer.inbox == deque( [ - ('Hello there.', 'alpha', oid), + ('Hello there.', 'alpha', vid), ('How ya doing?', 'beta', oidBeta), - ('Hello there.', 'alpha', oid), + ('Hello there.', 'alpha', vid), ('How ya doing?', 'beta', oidBeta), ]) From 61129a5cb9a455164fbc998c48fb4b1e458606ae Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Mon, 13 Apr 2026 21:03:51 -0600 Subject: [PATCH 9/9] finished refactor Memoer to used CESR codes for header parts --- src/hio/core/memo/__init__.py | 3 +- src/hio/core/memo/memoing.py | 275 ++++++++++++++------------ tests/core/memo/test_memoing.py | 296 ++++++++++++++++------------ tests/core/udp/test_peer_memoing.py | 46 ++--- tests/core/uxd/test_peer_memoing.py | 42 ++-- 5 files changed, 368 insertions(+), 294 deletions(-) diff --git a/src/hio/core/memo/__init__.py b/src/hio/core/memo/__init__.py index 469af6f0..d02a45c1 100644 --- a/src/hio/core/memo/__init__.py +++ b/src/hio/core/memo/__init__.py @@ -4,7 +4,8 @@ """ -from .memoing import (Versionage, Sizage, MemoDex, GramDex, AuthDex, Keyage, +from .memoing import (Versionage, Sizage, Keyage, + MemoDex, ZeroDex, GramDex, AuthDex, AckDex, openMemoer, Memoer, MemoerDoer, openAM, AuthMemoer, AuthMemoerDoer) diff --git a/src/hio/core/memo/memoing.py b/src/hio/core/memo/memoing.py index b06ed392..0c4fcda4 100644 --- a/src/hio/core/memo/memoing.py +++ b/src/hio/core/memo/memoing.py @@ -263,15 +263,12 @@ """ Sizage = namedtuple("Sizage", "hz mz nz vz az") - @dataclass(frozen=True) class MemoGramCodex: """MemoGramCodex is codex of all varieties of MemoGram Hard Codes. Only provide defined codes. Undefined are left out so that inclusion(exclusion) via 'in' operator works. """ - MemoGram: str = '__' # memogram code - AuthMemoGram: str = '_-' # authenticated memogram code (signed) GramZero: str = '1AAQ' # zeroth gram code Gram: str = '1AAR' # non-zeroth gram code GramAuthZero: str = '1AAS' # zeroth authenticated gram code (signed) @@ -288,13 +285,33 @@ def __iter__(self): MemoDex = MemoGramCodex() # Make instance + +@dataclass(frozen=True) +class ZeroGramCodex: + """GramCodex is codex of all Zero Gram Hard Codes. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + GramZero: str = '1AAQ' # zeroth gram code + GramAuthZero: str = '1AAS' # zeroth authenticated gram code (signed) + GramSureZero: str = '1AAU' # zeroth reliable gram code (acked) + GramSureAuthZero: str = '1AAW' # zeroth reliable authenticated gram code (acked & signed) + + def __iter__(self): + return iter(astuple(self)) + +ZeroDex = ZeroGramCodex() # Make instance + @dataclass(frozen=True) class GramCodex: - """GramCodex is codex of all Gram Hard Codes. + """GramCodex is codex of all Non-Zero Gram Hard Codes. Only provide defined codes. Undefined are left out so that inclusion(exclusion) via 'in' operator works. """ - MemoGram: str = '__' # memogram code + Gram: str = '1AAR' # non-zeroth gram code + GramAuth: str = '1AAT' # non-zeroth authenticated gram code (signed) + GramSure: str = '1AAV' # non-zeroth reliable gram code (acked) + GramSureAuth: str = '1AAX' # non-zeroth reliable authenticated gram code (acked & signed) def __iter__(self): return iter(astuple(self)) @@ -308,7 +325,6 @@ class AuthGramCodex: Only provide defined codes. Undefined are left out so that inclusion(exclusion) via 'in' operator works. """ - AuthMemoGram: str = '_-' # authenticated memogram code (signed) GramAuthZero: str = '1AAS' # zeroth authenticated gram code (signed) GramAuth: str = '1AAT' # non-zeroth authenticated gram code (signed) GramSureAuthZero: str = '1AAW' # zeroth reliable authenticated gram code (acked & signed) @@ -321,22 +337,19 @@ def __iter__(self): AuthDex = AuthGramCodex() # Make instance +@dataclass(frozen=True) +class AckCodex: + """AckCodex is codex of all Ack Hard Codes. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + Ack: str = '1AAY' # ack code to enable reliable grams + AckAuth: str = '1AAZ' # authenticated ack code to enable reliable grams (signed) -#@dataclass(frozen=True) -#class AckGramCodex: - #"""AckGramCodex is codex of all AckGram (acknowledge) Codes. - #Only provide defined codes. - #Undefined are left out so that inclusion(exclusion) via 'in' operator works. - #""" - #AckGram: str = '_9' # acknowledge gram code - #AuthAckGram: str = '_8' # authenticated acknowledge gram code (signed) - - #def __iter__(self): - #return iter(astuple(self)) - -#AckDex = AckGramCodex() # Make instance - + def __iter__(self): + return iter(astuple(self)) +AckDex = AckCodex() # Make instance class Memoer(Tymee): @@ -543,11 +556,11 @@ class Memoer(Tymee): Codex = MemoDex Codes = asdict(Codex) # map code name to code Names = {val : key for key, val in Codes.items()} # invert map code to code name - Sodex = AuthDex # signed gram codex + Zedex = ZeroDex # only zeroth gram codes for rending + Audex = AuthDex # signed gram codex + # dict of gram header part sizes keyed by gram codes: hz mz nz vz az Sizes = { - '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0), - '_-': Sizage(hz=2, mz=22, nz=4, vz=44,az=88), '1AAQ': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), '1AAR': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), '1AAS': Sizage(hz=4, mz=24, nz=4, vz=44,az=88), @@ -566,7 +579,6 @@ class Memoer(Tymee): Pairs[MemoDex.GramSureZero] = MemoDex.GramSure Pairs[MemoDex.GramSureAuthZero] = MemoDex.GramSureAuth - # Base2 Binary index representation of Text Base64 Char Codes #Bodes = ({helping.codeB64ToB2(c): c for n, c in Codes.items()}) # big enough to hold a CESR big frame with code @@ -582,19 +594,18 @@ def makeMID(cls, code='0A'): Returns:: mid (str): 24 char qb64 CESR encoded qualified base64 from 128 bit UUID - CESR code '0A' labeled Salt_128 + default CESR code '0A' labeled Salt_128 Parameters:: code (str): CESR code for MID """ - code = '0A' # Salt_128 - ps = (3 - (len(code) % 3)) % 3 # net pad size for code - uuid = uuid.uuid1().bytes # random UUID sorted in time order - if ps != (3 - (len(uuid) % 3)) % 3: # compare pad sizes - raise ValueError(f"Mismatch code and uuid pad sizes. " - f"Both not {ps=}") + raw = uuid.uuid1().bytes # random UUID sorted in time order + ps = (3 - (len(raw) % 3)) % 3 # net pad size for raw + if ps != len(code) % 4: # compare pad for raw and code + raise ValueError(f"Mismatch length code with raw uuid pad size, " + f" {len(code)} != {ps}") # prepad convert strip midpad and then prefix code - mid = code.encode() + encodeB64(bytes([0] * ps) + uuid)[ps:] + mid = code + encodeB64(bytes([0] * ps) + raw)[ps:].decode() return mid # fully qualified mid with prefixed code @@ -630,7 +641,7 @@ def _encodeVID(cls, raw, code='B'): qb64 = code + b64.decode() # fully qualified base64 vid with prefix code - _, _, _, vz, _ = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az + _, _, _, vz, _ = cls.Sizes[MemoDex.GramAuthZero] # hz mz nz vz az if len(qb64) != vz: hioing.MemoerError(f"Invalid vid qb64 size={len(qb64) != {vz}}") @@ -880,7 +891,7 @@ def _encodeSGN(cls, raw, code='0B'): qb64 = code + b64.decode() # fully qualified base64 with prefixqb64de - _, _, _, _, az = cls.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az + _, _, _, _, az = cls.Sizes[MemoDex.GramAuthZero] # hz mz nz vz az if len(qb64) != az: hioing.MemoerError(f"Invalid sig qb64 size={len(qb64) != {az}}") @@ -947,7 +958,7 @@ def __init__(self, *, txms=None, txgs=None, txbs=None, - code=MemoDex.MemoGram, + code=MemoDex.GramZero, curt=False, size=None, authic=False, @@ -1082,7 +1093,7 @@ def __init__(self, *, def code(self): """Property getter for ._code - Returns: + Returns:: code (str): two char base64 gram code """ return self._code @@ -1092,10 +1103,10 @@ def code(self): def code(self, code): """Property setter for ._code - Parameters: + Parameters:: code (str): two char base64 gram code """ - if code not in self.Codex: + if code not in self.Zedex: # code for rending must be a zero gram raise hioing.MemoerError(f"Invalid {code=}.") self._code = code @@ -1107,7 +1118,7 @@ def code(self, code): def curt(self): """Property getter for ._curt - Returns: + Returns:: curt (bool): True means when rending for tx encode header in base2 False means when rending for tx encode header in base64 """ @@ -1129,12 +1140,12 @@ def curt(self, curt): @property def size(self): - """Property getter for ._size + """Property getter for ._size, maximum gram size when rending for tx Returns: size (int): gram size when rending for tx. - First gram size = head size + neck size + body size. - Other gram size = head size + body size. + Zeroth gram size = zeroth overhead + body. + Non-Zeroth gram size = non-zeroth overhead + body. Min gram body size is one. Gram size also limited by MaxGramSize and MaxGramCount relative to MaxMemoSize. @@ -1144,21 +1155,24 @@ def size(self): @size.setter def size(self, size): - """Property setter for ._size + """Property setter for ._size of maximum gram size when rending for tx Parameters: size (int or None): gram size for rending memo """ + size = size if size is not None else self.MaxGramSize + hz, mz, nz, vz, az = self.Sizes[self.code] # hz mz nz vz az oz = hz + mz + nz + vz + az - size = size if size is not None else self.MaxGramSize if self.curt: # minimum header smaller when in base2 curt oz = 3 * oz // 4 - nz = 3 * nz // 4 - - # mininum size must be big enough for first gram header and 1 body byte - self._size = max(min(size, self.MaxGramSize), oz + nz + 1) + # min size is big enough for zeroth gram overhead plus 1 body byte + size = max(size, oz + 1) + if size > self.MaxGramSize: + hioing.MemoerError(f"Invalid {size=} exceeds " + f"MaxGramSize={self.MaxGramSize}") + self._size = size @property @@ -1257,7 +1271,7 @@ def serviceTymers(self): pass - def wiff(self, gram): + def wiffOld(self, gram): """Determines encoding of gram bytes header when parsing grams. The encoding maybe either base2 or base64. @@ -1304,7 +1318,7 @@ def wiff(self, gram): raise hioing.MemoerError(f"Unexpected {sextet=} at gram head start.") - def wiffNew(self, gram): + def wiff(self, gram): """Determines encoding of gram bytes header when parsing grams. The encoding maybe either base2 or base64. @@ -1415,7 +1429,7 @@ def verify(self, vid, sig, ser): return True - def pickNew(self, gram): + def pick(self, gram): """Strips header from gram bytearray leaving only gram body in gram and returns (mid, gn, gc). Raises MemoerError if unrecognized or invalid header this includes signature verification failure when signed. @@ -1457,7 +1471,7 @@ def pickNew(self, gram): raise hioing.MemoerError(f"Gram length={len(gram)} to short to " f"hold code.") code = helping.codeB2ToB64(gram, 4) # code from first 4 sextets - if self.authic and code not in self.Sodex: # must be signed + if self.authic and code not in self.Audex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") @@ -1478,14 +1492,21 @@ def pickNew(self, gram): mid = encodeB64(gram[hz:hz+mz]) # convert to b64b gnum = gram[hz+mz:hz+mz+nz] # bytearray to bytes gnum gn = int.from_bytes(gnum) # gram number/count convert to int - - if True: # first (zeroth) gram so long neck get gram count + vid = encodeB64(gram[hz+mz+nz:hz+mz+nz+vz]) # convert to b64b + if code in ZeroDex: # first (zeroth) gram so get gram count gc = gn # zeroth so gcnt in neck where gnum gn = 0 # zeroth so gnum must be zero - else: + elif code in GramDex: gc = None # not provided in this gram + if not vid: + vid = self.vids.get(mid.decode()) # if not then get from .vids + vid = vid.encode() if vid is not None else b"" + elif code in AckDex: + pass + else: + raise hioing.MemoerError(f"Invalid {code=}") + - vid = encodeB64(gram[hz+mz+nz:hz+mz+nz+vz]) # convert to b64b sig = encodeB64(gram[-az if az else len(gram):]) # last ss bytes are signature del gram[-az if az else len(gram):] # strip sig if any sgram = bytes(gram[:]) # signed raw part make bytes copy to sign @@ -1496,7 +1517,7 @@ def pickNew(self, gram): raise hioing.MemoerError(f"Gram length={len(gram)} to short to " f"hold code.") code = gram[:4].decode() # assumes len(code) must be 2 - if self.authic and code not in self.Sodex: # must be signed + if self.authic and code not in self.Audex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") hz, mz, nz, vz, az = self.Sizes[code] # hz mz nz vz az @@ -1510,25 +1531,32 @@ def pickNew(self, gram): gnum = bytes(gram[hz+mz:hz+mz+nz]) # qb64b short part of neck gn = helping.b64ToInt(gnum) - if True: # first (zeroth) gram so long neck get gram count + vid = bytes(gram[hz+mz+nz:hz+mz+nz+vz]) #bytearry to bytes qb64b convert to qb64 + if code in ZeroDex: # first (zeroth) gram so get gram count gc = gn # zeroth so gcnt in neck where gnum - gn = 0 # zeroth so gnum must be zer + gn = 0 # zeroth so gnum must be zero + elif code in GramDex: + gc = None # not provided in this gram + if not vid: + vid = self.vids.get(mid.decode()) # if not then get from .vids + vid = vid.encode() if vid is not None else b"" + elif code in AckDex: + pass else: - gc = None # not provided in this gram + raise hioing.MemoerError(f"Invalid {code=}") - vid = bytes(gram[hz+mz+nz:hz+mz+nz+vz]) #bytearry to bytes qb64b convert to qb64 sig = bytes(gram[-az if az else len(gram):]) # last az bytes signature del gram[-az if az else len(gram):] # strip sig if any sgram = bytes(gram[:]) # signed raw part make bytes copy to sign del gram[:oz-az] # strip of fore head leaving body in gram - if sig: # signature not empty + if sig: # signature not empty when Auth code sig is never empty self.verify(vid, sig, sgram) # raises MemoerVerifyError if invalid return (mid.decode(), vid.decode() if vid else None, gn, gc) - def pick(self, gram): + def pickOld(self, gram): """Strips header from gram bytearray leaving only gram body in gram and returns (mid, gn, gc). Raises MemoerError if unrecognized or invalid header this includes signature verification failure when signed. @@ -1565,7 +1593,7 @@ def pick(self, gram): raise hioing.MemoerError(f"Gram length={len(gram)} to short to " f"hold code.") code = helping.codeB2ToB64(gram, 2) # assumes len(code) must be 2 - if self.authic and code not in self.Sodex: # must be signed + if self.authic and code not in self.Audex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") @@ -1614,7 +1642,7 @@ def pick(self, gram): raise hioing.MemoerError(f"Gram length={len(gram)} to short to " f"hold code.") code = gram[:2].decode() # assumes len(code) must be 2 - if self.authic and code not in self.Sodex: # must be signed + if self.authic and code not in self.Audex: # must be signed raise hioing.MemoerError(f"Unsigned gram {code =} when signed " f"required.") hz, mz, nz, vz, az = self.Sizes[code] # hz mz nz vz az @@ -1975,83 +2003,84 @@ def rend(self, memo, vid=None): """ grams = [] memo = bytearray(memo.encode()) # convert and copy to bytearray - # self.size is max gram size - hz, mz, nz, vz, az = self.Sizes[self.code] # hz mz nz vz az - oz = hz + mz + nz + vz + az + + zcode = self.code # zeroth gram code + zhz, zmz, znz, zvz, zaz = self.Sizes[zcode] # hz mz nz vz az + zoz = zhz + zmz + znz + zvz + zaz # overhead on zeroth gram + + ncode = self.Pairs[zcode] # non-zeroth gram code + nhz, nmz, nnz, nvz, naz = self.Sizes[ncode] # hz mz nz vz az + noz = nhz + nmz + nnz + nvz + naz # overhead on non-zeroth grams vid = vid if vid is not None else self.vid + if zvz and (not vid or len(vid) != zvz): + raise hioing.MemoerError(f"Missing or invalid {vid=} for {zvz=}") - if vz and (not vid or len(vid) != vz): - raise hioing.MemoerError(f"Missing or invalid {vid=} for {vz=}") + mid = self.makeMID() + if len(mid) != zmz: + raise hioing.MemoerError(f"Invalid {mid=} for {zmz=}") - pz = (3 - ((mz) % 3)) % 3 # net pad size for mid - # memo ID is 16 byte random UUID converted to 22 char Base64 right aligned - mid = encodeB64(bytes([0] * pz) + uuid.uuid1().bytes)[pz:] #pzrepad, convert, and prestrip - if hz != pz or hz != len(self.code): - raise hioing.MemoerError(f"Invalid code size {hz=} for {pz=} or " - f"code={self.code}") - mid = self.code.encode() + mid # fully qualified mid with prefix code - ml = len(memo) + zcodeb = zcode.encode() # make bytes + ncodeb = ncode.encode() # make bytes + vidb = vid.encode() if vid else b'' # convert to bytes + midb = mid.encode() # convert to bytes if self.curt: # rend header parts in base2 instead of base64 # encoding b2 means head part sizes smaller by 3/4 - hz = 3 * hz // 4 - mz = 3 * mz // 4 - nz = 3 * nz // 4 - vz = 3 * vz // 4 - az = 3 * az // 4 - oz = 3 * oz // 4 - mid = decodeB64(mid) - - bz = (self.size - oz) # max standard gram body size without neck - # compute gram count based on overhead note added neck overhead in first gram - # first gram is special its header is longer by ns than the other grams - # which means its payload body is shorter by ns than the other gram bodies - # so take ml and subtract first payload size = ml - (bs-ns) to get the - # portion of memo carried by other grams. Divide this by bs rounded up - # (ceil) to get cnt of other grams and add 1 for the first gram to get - # total gram cnt. - # gc = ceil((ml-(bs-ns))/bs + 1) = ceil((ml-bs+ns)/bs + 1) - gc = math.ceil((ml-bz+nz)/bz+1) # includes added neck ns overhead - mms = min(self.MaxMemoSize, (bz * self.MaxGramCount) - nz) # max memo payload - + zhz = 3 * zhz // 4 + zmz = 3 * zmz // 4 + znz = 3 * znz // 4 + zvz = 3 * zvz // 4 + zaz = 3 * zaz // 4 + zoz = 3 * zoz // 4 + zcodeb = decodeB64(zcodeb) # convert to base2 bytes + ncodeb = decodeB64(ncodeb) # convert to base2 bytes + midb = decodeB64(midb) # convert to base2 bytes + vidb = decodeB64(vidb) # convert to base2 bytes + + # self.size is min-max gram size computed on zeroth gram + zbz = (self.size - zoz) # max zeroth gram body size >=1 + nbz = (self.size - noz) # max non-zeroth gram body size >=1 + ml = len(memo) + gc = math.ceil((ml+nbz-zbz)/nbz) + mms = min(self.MaxMemoSize, (nbz*(self.MaxGramCount-1) + zbz)) # max memo payload if ml > mms: - raise hioing.MemoerError(f"Memo length={ml} exceeds max={mms}.") + raise hioing.MemoerError(f"Memo length={ml} exceeds max={mms}") if self.curt: - neck = gc.to_bytes(nz) + gcnt = gc.to_bytes(znz) # gcnt as b2 bytes else: - neck = helping.intToB64b(gc, l=nz) + gcnt = helping.intToB64b(gc, l=znz) # gcnt as b64 bytes gn = 0 while memo: - if self.curt: - num = gn.to_bytes(nz) # num size must always be neck size - else: - num = helping.intToB64b(gn, l=nz) # num size must always be neck size - - if vz: # need vid part, but can't mod here may need below to sign - if self.curt: - oidp = decodeB64(vid.encode()) # vid part b2 - else: - oidp = vid.encode() # vid part b64 bytes - head = mid + oidp + num - else: - head = mid + num if gn == 0: - gram = head + neck + memo[:bz-nz] # copy slice past end just copies to end - del memo[:bz-nz] # del slice past end just deletes to end + head = zcodeb + midb + gcnt + if zvz: + head += vidb + gram = head + memo[:zbz] # copy slice past end just copies to end + del memo[:zbz] # del slice past end just deletes to end + if zaz: # signed gram, .sign returns proper sig format when .curt + sig = self.sign(vid, gram) # raises MemoerError if invalid + gram = gram + sig + else: - gram = head + memo[:bz] # copy slice past end just copies to end - del memo[:bz] # del slice past end just deletes to end + if self.curt: + gnum = gn.to_bytes(znz) # gnum as b2 bytes + else: + gnum = helping.intToB64b(gn, l=znz) # gnum as b64 bytes - if az: # signed gram, .sign returns proper sig format when .curt - sig = self.sign(vid, gram) # raises MemoerError if invalid - gram = gram + sig + head = ncodeb + midb + gnum + if nvz: + head += vidb + gram = head + memo[:nbz] # copy slice past end just copies to end + del memo[:nbz] # del slice past end just deletes to end + if naz: # signed gram, .sign returns proper sig format when .curt + sig = self.sign(vid, gram) # raises MemoerError if invalid + gram = gram + sig grams.append(gram) - gn += 1 return grams @@ -2494,7 +2523,7 @@ class AuthMemoer(Memoer): """ - def __init__(self, *, code=MemoDex.AuthMemoGram, authic=True, **kwa): + def __init__(self, *, code=MemoDex.GramAuthZero, authic=True, **kwa): """Initialization method for instance. Force code to Auth type diff --git a/tests/core/memo/test_memoing.py b/tests/core/memo/test_memoing.py index d7e5d4f0..d5e5223a 100644 --- a/tests/core/memo/test_memoing.py +++ b/tests/core/memo/test_memoing.py @@ -16,8 +16,10 @@ from hio.help import helping from hio.base import doing, tyming from hio.core.memo import memoing -from hio.core.memo import (Versionage, Sizage, Keyage, MemoDex, GramDex, AuthDex, - Memoer, ) +from hio.core.memo import (Versionage, Sizage, Keyage, + MemoDex, ZeroDex, GramDex, AuthDex, AckDex, + Memoer, AuthMemoer, openMemoer, openAM, + MemoerDoer, AuthMemoerDoer) def _setupKeep(salt=None): @@ -101,8 +103,6 @@ def test_memoer_class(): assert Memoer.Codes == \ { - 'MemoGram': '__', - 'AuthMemoGram': '_-', 'GramZero': '1AAQ', 'Gram': '1AAR', 'GramAuthZero': '1AAS', @@ -118,8 +118,6 @@ def test_memoer_class(): # Codes table with sizes of code (hard) and full primitive material assert Memoer.Sizes == \ { - '__': Sizage(hz=2, mz=22, nz=4, vz=0, az=0), - '_-': Sizage(hz=2, mz=22, nz=4, vz=44,az=88), '1AAQ': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), '1AAR': Sizage(hz=4, mz=24, nz=4, vz=0, az=0), '1AAS': Sizage(hz=4, mz=24, nz=4, vz=44,az=88), @@ -159,8 +157,6 @@ def test_memoer_class(): assert Memoer.Names == \ { - '__': 'MemoGram', - '_-': 'AuthMemoGram', '1AAQ': 'GramZero', '1AAR': 'Gram', '1AAS': 'GramAuthZero', @@ -173,8 +169,21 @@ def test_memoer_class(): '1AAZ': 'AckAuth', } + assert Memoer.Zedex == ZeroDex + assert Memoer.Audex == AuthDex - assert Memoer.Sodex == AuthDex + for zero, nonzero in Memoer.Pairs.items(): + assert zero in ZeroDex + assert nonzero in GramDex + + zdex = list(ZeroDex) # astuple + gdex = list(GramDex) # astuple + keys = list(Memoer.Pairs.keys()) + vals = list(Memoer.Pairs.values()) + for i, zero in enumerate(zdex): + assert zdex[i] == keys[i] == zero + for i, gram in enumerate(gdex): + assert gdex[i] == vals[i] == gram assert Memoer.Pairs[MemoDex.GramZero] == MemoDex.Gram assert Memoer.Pairs[MemoDex.GramAuthZero] == MemoDex.GramAuth @@ -195,7 +204,7 @@ def test_memoer_class(): raw, code = Memoer._decodeVID(vid) assert raw == verkey assert code == 'B' # nontrans AID - _, _, _, vz, _ = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az + _, _, _, vz, _ = Memoer.Sizes[MemoDex.GramAuthZero] # hz mz nz vz az assert len(vid) == 44 == vz qvk = Memoer._encodeQVK(raw=verkey) @@ -220,7 +229,7 @@ def test_memoer_class(): raw, code = Memoer._decodeSGN(sgntr) assert raw == signature assert code == '0B' - _, _, _, _, az = Memoer.Sizes[MemoDex.AuthMemoGram] # hz mz nz vz az + _, _, _, _, az = Memoer.Sizes[MemoDex.GramAuthZero] # hz mz nz vz az assert len(sgntr) == 88 == az """Done Test""" @@ -272,53 +281,51 @@ def test_memoer_sign_verify(): except MemoerError as ex: return + mid = Memoer.makeMID() # test class method + assert len(mid) == 24 + assert mid[:2] == '0A' + + # default vid vid = list(keep.keys())[0] assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' + code = MemoDex.GramAuthZero - peer = memoing.Memoer(code=MemoDex.AuthMemoGram, keep=keep, vid=vid) + peer = Memoer(code=code, keep=keep, vid=vid) assert peer.name == "main" assert peer.opened == False assert peer.bc is None - assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' + assert peer.bs == Memoer.BufSize == 65535 + assert peer.code == MemoDex.GramAuthZero == '1AAS' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88) # hz mz nz vz az + assert peer.Sizes[peer.code] == (4, 24, 4, 44, 88) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic assert peer.keep == keep assert peer.vid == vid - memo = "Hello There" - + # manually generate memogram + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + gcnt = 'AAAB' # gram count 1 + # serder vid vid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .vid assert vid in peer.keep - mid = '_-ALBI68S1ZIxqwFOSWFF1L2' - lneck = 'AAAC' # gram count 2 + head = code + mid + gcnt + vid + assert head == '1AAS0AD5s502N14R8bWw8qyvRW-SAAABDGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' - # create signed portion of gram long neck - neck = 'AAAA' # gram number 0 - head = mid + vid + neck + lneck - sgram = (head + "Hello There").encode() - #sign - sgntr = peer.sign(vid, sgram) - #verify - assert peer.verify(vid, sgntr, sgram) + memo = "Hello There" # body - # test invalid bad gram - bgram = (head + "Hello Where").encode() - with pytest.raises(MemoerVerifyError): - peer.verify(vid, sgntr, bgram) - - # create signed portion of gram short neck - neck = 'AAAB' # gram number 1 - head = mid + vid + neck - sgram = (head + "Hello There").encode() + sgram = (head + memo).encode() #sign sgntr = peer.sign(vid, sgram) #verify assert peer.verify(vid, sgntr, sgram) + gram = head + memo + sgntr.decode() + assert gram == ('1AAS0AD5s502N14R8bWw8qyvRW-SAAABDGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' + 'Hello There' + '0BBvO2SHplT7vjLMvcKU5s11d4lt_KVg0zbzZDiaRZ9jQhEZhPxqSo71DQSnk5YTpZphbooVW14sea2UL2DT_aMB') + # test invalid bad gram bgram = (head + "Hello Where").encode() with pytest.raises(MemoerVerifyError): @@ -331,14 +338,14 @@ def test_memoer_sign_verify(): def test_memoer_basic(): """Test Memoer class basic """ - peer = memoing.Memoer() + peer = Memoer() assert peer.name == "main" assert peer.opened == False assert peer.bc is None - assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.MemoGram == '__' + assert peer.bs == Memoer.BufSize == 65535 + assert peer.code == MemoDex.GramZero == '1AAQ' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0) # hz mz nz vz az + assert peer.Sizes[peer.code] == (4, 24, 4, 0, 0) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -348,7 +355,6 @@ def test_memoer_basic(): assert peer.tymeout == 0.0 assert peer.tymers == {} - peer.reopen() assert peer.opened == True @@ -377,8 +383,10 @@ def test_memoer_basic(): assert not peer.counts assert not peer.sources assert not peer.rxms - mid = '__ALBI68S1ZIxqwFOSWFF1L2' - gram = (mid + 'AAAA' + 'AAAB' + "Hello There").encode() + + code = '1AAQ' + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + gram = (code + mid + 'AAAB' + "Hello There").encode() echo = (gram, "beta") peer.echos.append(echo) peer.serviceReceives(echoic=True) @@ -454,9 +462,11 @@ def test_memoer_basic(): assert not peer.counts assert not peer.sources assert not peer.rxms - mid = '__ALBI68S1ZIxqwFOSWFF1L2' - headneck = decodeB64((mid + 'AAAA' + 'AAAB').encode()) - gram = headneck + b"Hello There" + + code = '1AAQ' + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + head = decodeB64((code + mid + 'AAAB').encode()) # base 2 + gram = head + b"Hello There" assert peer.wiff(gram) # base2 echo = (gram, "beta") peer.echos.append(echo) @@ -490,10 +500,10 @@ def test_memoer_small_gram_size(): assert peer.opened == False assert peer.bc is None assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.MemoGram == '__' + assert peer.code == memoing.MemoDex.GramZero == '1AAQ' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0) # hz mz nz vz az - assert peer.size == 33 # can't be smaller than head + neck + 1 + assert peer.Sizes[peer.code] == (4, 24, 4, 0, 0) # hz mz nz vz az + assert peer.size == 33 # overhead + 1 is minimum size assert not peer.authic assert not peer.echoic assert peer.keep == dict() @@ -528,13 +538,19 @@ def test_memoer_small_gram_size(): assert not peer.counts assert not peer.sources assert not peer.rxms - b'__DFymLrtlZG6bp0HhlUsR6uAAAAAAACHello ' - b'__DFymLrtlZG6bp0HhlUsR6uAAABThere' - mid = '__DFymLrtlZG6bp0HhlUsR6u' - gram = (mid + 'AAAA' + 'AAAC' + "Hello ").encode() + + + code = '1AAQ' + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + gcnt = 'AAAC' # 2 + gram = (code + mid + gcnt + "Hello ").encode() + assert len(gram) == peer.size == 38 echo = (gram, "beta") peer.echos.append(echo) - gram = (mid + 'AAAB' + "There").encode() + + code = '1AAR' + gnum = 'AAAB' # 1 + gram = (code + mid + gnum + "There").encode() echo = (gram, "beta") peer.echos.append(echo) peer.serviceReceives(echoic=True) @@ -561,7 +577,7 @@ def test_memoer_small_gram_size(): assert peer.txms[0] == ('See ya later!', 'beta', None) peer.serviceTxMemos() assert not peer.txms - assert len(peer.txgs) == 2 + assert len(peer.txgs) == 3 for m, d in peer.txgs: assert not peer.wiff(m) # base64 assert d == dst == 'beta' @@ -574,14 +590,16 @@ def test_memoer_small_gram_size(): assert not peer.rxms assert not peer.counts assert not peer.sources + peer.serviceReceives(echoic=True) assert not peer.echos mid = list(peer.rxgs.keys())[0] - assert len(peer.rxgs[mid]) == 2 - assert peer.counts[mid] == 2 + assert len(peer.rxgs[mid]) == 3 + assert peer.counts[mid] == 3 assert peer.sources[mid] == 'beta' assert peer.rxgs[mid][0] == bytearray(b'See ya') - assert peer.rxgs[mid][1] == bytearray(b' later!') + assert peer.rxgs[mid][1] == bytearray(b' later') + assert peer.rxgs[mid][2] == bytearray(b'!') assert not peer.echos peer.serviceRxGrams() assert not peer.rxgs @@ -605,7 +623,7 @@ def test_memoer_small_gram_size(): assert peer.txms[0] == ('See ya later alligator!', 'beta', None) peer.serviceTxMemos() assert not peer.txms - assert len(peer.txgs) == 2 + assert len(peer.txgs) == 3 for m, d in peer.txgs: assert peer.wiff(m) # base2 assert d == dst == 'beta' @@ -619,16 +637,21 @@ def test_memoer_small_gram_size(): assert not peer.rxms assert not peer.echos - b'__DFymLrtlZG6bp0HhlUsR6uAAAAAAACHello ' - b'__DFymLrtlZG6bp0HhlUsR6uAAABThere' - mid = '__DFymLrtlZG6bp0HhlUsR6u' - headneck = decodeB64((mid + 'AAAA' + 'AAAC').encode()) - gram = headneck + b"See ya later a" - assert peer.wiff(gram) # base2 + code = '1AAQ' + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + gcnt = 'AAAC' # 2 + head = decodeB64((code + mid + gcnt).encode()) # base 2 + gram = head + b"See ya later a" + assert len(gram) == peer.size == 38 + assert peer.wiff(gram) # base2 echo = (gram, "beta") peer.echos.append(echo) - head = decodeB64((mid + 'AAAB').encode()) + + code = '1AAR' + gnum = 'AAAB' # 1 + head = decodeB64((code + mid + gnum).encode()) gram = head + b"lligator!" + assert len(gram) == 33 assert peer.wiff(gram) # base2 echo = (gram, "beta") peer.echos.append(echo) @@ -661,13 +684,13 @@ def test_memoer_small_gram_size(): def test_memoer_multiple(): """Test Memoer class with small gram size and multiple queued memos """ - peer = memoing.Memoer(size=38) + peer = Memoer(size=38) assert peer.size == 38 assert peer.name == "main" assert peer.opened == False assert peer.bc is None - assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.MemoGram == '__' + assert peer.bs == Memoer.BufSize == 65535 + assert peer.code == MemoDex.GramZero == '1AAQ' assert not peer.curt assert not peer.authic assert not peer.echoic @@ -683,14 +706,14 @@ def test_memoer_multiple(): assert len(peer.txms) == 2 peer.serviceTxMemos() assert not peer.txms - assert len(peer.txgs) == 4 + assert len(peer.txgs) == 5 for m, d in peer.txgs: assert not peer.wiff(m) # base64 assert d in ("alpha", "beta") peer.serviceTxGrams(echoic=True) assert not peer.txgs assert peer.txbs == (b'', None) - assert len(peer.echos) == 4 + assert len(peer.echos) == 5 assert not peer.rxgs assert not peer.rxms assert not peer.counts @@ -711,10 +734,11 @@ def test_memoer_multiple(): mid = list(peer.rxgs.keys())[1] assert peer.sources[mid] == 'beta' - assert peer.counts[mid] == 2 - assert len(peer.rxgs[mid]) == 2 + assert peer.counts[mid] == 3 + assert len(peer.rxgs[mid]) == 3 assert peer.rxgs[mid][0] == bytearray(b'How ya') - assert peer.rxgs[mid][1] == bytearray(b' doing?') + assert peer.rxgs[mid][1] == bytearray(b' doing') + assert peer.rxgs[mid][2] == bytearray(b'?') peer.serviceRxGrams() assert not peer.rxgs @@ -746,7 +770,7 @@ def test_memoer_multiple_echoic_service_tx_rx(): assert peer.opened == False assert peer.bc is None assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.MemoGram == '__' + assert peer.code == memoing.MemoDex.GramZero == '1AAQ' assert not peer.curt assert not peer.authic assert peer.echoic @@ -765,7 +789,7 @@ def test_memoer_multiple_echoic_service_tx_rx(): assert not peer.txms assert not peer.txgs assert peer.txbs == (b'', None) - assert len(peer.echos) == 4 + assert len(peer.echos) == 5 assert not peer.rxgs assert not peer.rxms @@ -800,7 +824,7 @@ def test_memoer_multiple_echoic_service_all(): assert peer.opened == False assert peer.bc is None assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.MemoGram == '__' + assert peer.code == memoing.MemoDex.GramZero == '1AAQ' assert not peer.curt assert not peer.authic assert peer.echoic @@ -820,7 +844,7 @@ def test_memoer_multiple_echoic_service_all(): assert not peer.txms assert not peer.txgs assert peer.txbs == (b'', None) - assert len(peer.echos) == 4 # Rx not serviced yet after Tx serviced + assert len(peer.echos) == 5 # Rx not serviced yet after Tx serviced peer.serviceAll() # services Rx first then Tx so have to serviceAll twice assert not peer.echos @@ -851,14 +875,14 @@ def test_memoer_basic_signed(): vid = list(keep.keys())[0] assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' - peer = memoing.Memoer(code=MemoDex.AuthMemoGram, keep=keep, vid=vid) + peer = Memoer(code=MemoDex.GramAuthZero, keep=keep, vid=vid) assert peer.name == "main" assert peer.opened == False assert peer.bc is None assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' + assert peer.code == memoing.MemoDex.GramAuthZero == '1AAS' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88) # hz mz nz vz az + assert peer.Sizes[peer.code] == (4, 24, 4, 44, 88) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert not peer.authic assert not peer.echoic @@ -886,7 +910,7 @@ def test_memoer_basic_signed(): assert not peer.wiff(g) # base64 assert g.find(memo.encode()) != -1 assert len(g) == 160 + 4 + len(memo) - assert g[:2].decode() == MemoDex.AuthMemoGram + assert g[:4].decode() == MemoDex.GramAuthZero assert d == dst == 'beta' peer.serviceTxGrams() assert not peer.txgs @@ -898,11 +922,17 @@ def test_memoer_basic_signed(): assert not peer.rxms # Test with signed header - mid = '_-ALBI68S1ZIxqwFOSWFF1L2' # signed header + code = '1AAS' + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + gcnt = 'AAAB' # 1 + head = (code + mid + gcnt + vid).encode() + sgram = head + b"Hello There" + assert len(sgram) == 87 + assert not peer.wiff(sgram) # base64 # test with invalid signature - sig = ('A' * 88) - gram = (mid + vid + 'AAAA' + 'AAAB' + "Hello There" + sig).encode() + sig = (b'A' * 88) + gram = sgram + sig echo = (gram, "beta") peer.echos.append(echo) peer.serviceReceives(echoic=True) @@ -911,7 +941,6 @@ def test_memoer_basic_signed(): # test with valid signature # create signed portion of gram - sgram = (mid + vid + 'AAAA' + 'AAAB' + "Hello There").encode() qvk, qss = peer.keep[vid] sig = peer.sign(vid, sgram) gram = sgram + sig @@ -941,7 +970,7 @@ def test_memoer_basic_signed(): assert not peer.wiff(g) # base64 assert g.find(memo.encode()) != -1 assert len(g) == 160 + 4 + len(memo) - assert g[:2].decode() == MemoDex.AuthMemoGram + assert g[:4].decode() == MemoDex.GramAuthZero assert d == dst == 'beta' peer.serviceTxGrams(echoic=True) assert not peer.txgs @@ -977,10 +1006,10 @@ def test_memoer_basic_signed(): peer.serviceTxMemos() assert not peer.txms g, d = peer.txgs[0] - assert peer.wiff(g) # base64 + assert peer.wiff(g) # base2 assert g.find(memo.encode()) != -1 assert len(g) == 3 * (160 + 4) // 4 + len(memo) - assert helping.codeB2ToB64(g, 2) == MemoDex.AuthMemoGram + assert helping.codeB2ToB64(g, 4) == MemoDex.GramAuthZero assert d == dst == 'beta' peer.serviceTxGrams() assert not peer.txgs @@ -992,13 +1021,15 @@ def test_memoer_basic_signed(): assert not peer.rxms # test with signed header - mid = '_-ALBI68S1ZIxqwFOSWFF1L2' # signed header - + code = '1AAS' + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + gcnt = 'AAAB' # 1 # test with valid signature vid = 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' # not default .vid - head = mid + vid + 'AAAA' + 'AAAB' + head = (code + mid + gcnt + vid).encode() + assert len(head) == 76 - head = decodeB64(head.encode()) # qb2 version of head + head = decodeB64(head) # qb2 version of head assert len(head) == 57 sgram = head + memo.encode() # sign the qb2 version assert len(sgram) == 68 @@ -1046,16 +1077,16 @@ def test_memoer_multiple_signed(): vid = list(keep.keys())[0] assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' - oidBeta = list(keep.keys())[1] - assert oidBeta == 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' + vidBeta = list(keep.keys())[1] + assert vidBeta == 'DGORBFFJe5Zj4T1FQHpRFSe41hQuq8HULAMWyc9C07ni' - peer = memoing.Memoer(code=MemoDex.AuthMemoGram, size=170, keep=keep, vid=vid) + peer = Memoer(code=MemoDex.GramAuthZero, size=170, keep=keep, vid=vid) assert peer.size == 170 assert peer.name == "main" assert peer.opened == False assert peer.bc is None assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' + assert peer.code == memoing.MemoDex.GramAuthZero == '1AAS' assert not peer.curt assert not peer.authic # force rx must be signed assert not peer.echoic @@ -1065,9 +1096,9 @@ def test_memoer_multiple_signed(): peer.reopen() assert peer.opened == True - # send and receive multiple via echo not signed + # send and receive multiple via echo signed peer.memoit("Hello there.", "alpha") # use default for vidAlpha - peer.memoit("How ya doing?", "beta", oidBeta) + peer.memoit("How ya doing?", "beta", vidBeta) assert len(peer.txms) == 2 peer.serviceTxMemos() assert not peer.txms @@ -1110,7 +1141,7 @@ def test_memoer_multiple_signed(): assert not peer.sources assert len(peer.rxms) == 2 assert peer.rxms[0] == ('Hello there.', 'alpha', vid) - assert peer.rxms[1] == ('How ya doing?', 'beta', oidBeta) + assert peer.rxms[1] == ('How ya doing?', 'beta', vidBeta) peer.serviceRxMemos() assert not peer.rxms @@ -1122,7 +1153,7 @@ def test_memoer_multiple_signed(): # send and receive multiple via echo in base2 .curt = True mode peer.memoit("Hello there.", "alpha") # use default for vidAlpha - peer.memoit("How ya doing?", "beta", oidBeta) + peer.memoit("How ya doing?", "beta", vidBeta) assert len(peer.txms) == 2 peer.serviceTxMemos() assert not peer.txms @@ -1165,16 +1196,16 @@ def test_memoer_multiple_signed(): assert not peer.sources assert len(peer.rxms) == 2 assert peer.rxms[0] == ('Hello there.', 'alpha', vid) - assert peer.rxms[1] == ('How ya doing?', 'beta', oidBeta) + assert peer.rxms[1] == ('How ya doing?', 'beta', vidBeta) peer.serviceRxMemos() assert not peer.rxms assert peer.inbox == deque( [ ('Hello there.', 'alpha', vid), - ('How ya doing?', 'beta', oidBeta), + ('How ya doing?', 'beta', vidBeta), ('Hello there.', 'alpha', vid), - ('How ya doing?', 'beta', oidBeta) + ('How ya doing?', 'beta', vidBeta) ]) @@ -1183,7 +1214,7 @@ def test_memoer_multiple_signed(): """ End Test """ -def test_memoer_verific(): +def test_memoer_authic(): """Test Memoer class with authic (signed required) """ salt = b"ABCDEFGHIJKLMNOP" @@ -1195,14 +1226,14 @@ def test_memoer_verific(): vid = list(keep.keys())[0] assert vid == 'BJZTHNWXscuT-SPokPzSeBkShpHj6g8bQrP0Rh7IJNUp' - peer = memoing.Memoer(authic=True, keep=keep, vid=vid) + peer = Memoer(authic=True, keep=keep, vid=vid) # only recieves not send signed assert peer.name == "main" assert peer.opened == False assert peer.bc is None assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.MemoGram == '__' + assert peer.code == memoing.MemoDex.GramZero == '1AAQ' assert not peer.curt - assert peer.Sizes[peer.code] == (2, 22, 4, 0, 0) # hz mz nz vz az + assert peer.Sizes[peer.code] == (4, 24, 4, 0, 0) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert peer.authic assert not peer.echoic @@ -1216,12 +1247,18 @@ def test_memoer_verific(): assert not peer.counts assert not peer.sources assert not peer.rxms - mid = '__ALBI68S1ZIxqwFOSWFF1L2' # not signed code - gram = (mid + 'AAAA' + 'AAAB' + "Hello There").encode() + + # send non-signed memo to authic memoer + code = '1AAQ' + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + gcnt = 'AAAB' # 1 + head = (code + mid + gcnt).encode() + + gram = head + "Hello There".encode() echo = (gram, "beta") peer.echos.append(echo) peer.serviceReceives(echoic=True) - assert not peer.rxgs # dropped gram + assert not peer.rxgs # dropped gram because not signed assert not peer.echos assert not peer.rxms @@ -1229,10 +1266,13 @@ def test_memoer_verific(): assert not peer.counts assert not peer.sources assert not peer.rxms - mid = '_-ALBI68S1ZIxqwFOSWFF1L2' # signed code + + code = '1AAS' # signed gram + mid = '0AD5s502N14R8bWw8qyvRW-S' # hard code here for test + gcnt = 'AAAB' # 1 vid = list(keep.keys())[1] - sig = ('A' * 88) - sgram = (mid + vid + 'AAAA' + 'AAAB' + "Hello There").encode() + head = (code + mid + gcnt + vid).encode() + sgram = head + "Hello There".encode() qvk, qss = peer.keep[vid] sig = peer.sign(vid, sgram) gram = sgram + sig @@ -1279,14 +1319,14 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): # authic forces rx memos to be signed or dropped # to force signed tx then use Signed code - peer = memoing.Memoer(code=MemoDex.AuthMemoGram, size=170, authic=True, + peer = Memoer(code=MemoDex.GramAuthZero, size=170, authic=True, echoic=True, keep=keep, vid=vid) assert peer.size == 170 assert peer.name == "main" assert peer.opened == False assert peer.bc is None assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' + assert peer.code == memoing.MemoDex.GramAuthZero == '1AAS' assert not peer.curt assert peer.authic assert peer.echoic @@ -1372,7 +1412,7 @@ def test_memoer_multiple_signed_verific_echoic_service_all(): def test_open_memoer(): """Test contextmanager decorator openMemoer """ - with (memoing.openMemoer(name='zeta') as zeta): + with (openMemoer(name='zeta') as zeta): assert zeta.opened assert zeta.name == 'zeta' @@ -1398,7 +1438,7 @@ def test_memoer_doer(): assert doist.limit == limit == 0.125 assert doist.doers == [] - peer = memoing.Memoer() + peer = Memoer() mgdoer = memoing.MemoerDoer(peer=peer) assert mgdoer.peer == peer @@ -1428,21 +1468,21 @@ def test_auth_memoer_basic(): oidBeta = list(keep.keys())[1] assert oidBeta == 'DJb1Z0pHx36MCOuIHWR4yPxfIiBxVzg6UCamv8fAN8gH' - peer = memoing.AuthMemoer(echoic=True, keep=keep, vid=vid) + peer = AuthMemoer(echoic=True, keep=keep, vid=vid) assert peer.size == 65535 assert peer.name == "main" assert peer.opened == False assert peer.bc is None assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' + assert peer.code == memoing.MemoDex.GramAuthZero == '1AAS' assert not peer.curt assert peer.authic assert peer.echoic assert peer.keep == keep assert peer.vid == vid - assert peer.Sizes[peer.code] == Sizage(hz=2, mz=22, nz=4, vz=44, az=88) - assert peer.Sizes[peer.code] == (2, 22, 4, 44, 88) # hz mz nz vz az + assert peer.Sizes[peer.code] == Sizage(hz=4, mz=24, nz=4, vz=44, az=88) + assert peer.Sizes[peer.code] == (4, 24, 4, 44, 88) # hz mz nz vz az assert peer.size == peer.MaxGramSize assert peer.tymeout == 0.0 assert peer.tymers == {} @@ -1570,7 +1610,7 @@ def test_open_sm(): except MemoerError as ex: return - with (memoing.openAM(name='zeta') as zeta): + with (openAM(name='zeta') as zeta): assert zeta.opened assert zeta.name == 'zeta' @@ -1606,8 +1646,8 @@ def test_auth_memoer_multiple_echoic_service_all(): assert peer.name == "test" assert peer.opened == True assert peer.bc is None - assert peer.bs == memoing.Memoer.BufSize == 65535 - assert peer.code == memoing.MemoDex.AuthMemoGram == '_-' + assert peer.bs == Memoer.BufSize == 65535 + assert peer.code == MemoDex.GramAuthZero == '1AAS' assert not peer.curt assert peer.authic assert peer.echoic @@ -1706,9 +1746,9 @@ def test_auth_memoer_doer(): assert doist.limit == limit == 0.125 assert doist.doers == [] - peer = memoing.AuthMemoer() + peer = AuthMemoer() - tmgdoer = memoing.AuthMemoerDoer(peer=peer) + tmgdoer = AuthMemoerDoer(peer=peer) assert tmgdoer.peer == peer assert not tmgdoer.peer.opened assert tmgdoer.tock == 0.0 # ASAP @@ -1741,7 +1781,7 @@ def test_auth_memoer_doer(): test_memoer_multiple_echoic_service_all() test_memoer_basic_signed() test_memoer_multiple_signed() - test_memoer_verific() + test_memoer_authic() test_memoer_multiple_signed_verific_echoic_service_all() test_open_memoer() test_memoer_doer() diff --git a/tests/core/udp/test_peer_memoing.py b/tests/core/udp/test_peer_memoing.py index b61ac830..d9e180b7 100644 --- a/tests/core/udp/test_peer_memoing.py +++ b/tests/core/udp/test_peer_memoing.py @@ -23,9 +23,9 @@ def test_memoer_peer_basic(): alpha = peermemoing.PeerMemoer(name="alpha", temp=True) assert alpha.name == "alpha" - assert alpha.code == MemoDex.MemoGram + assert alpha.code == MemoDex.GramZero assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az + assert alpha.Sizes[alpha.code] == (4, 24, 4, 0, 0) # hz mz nz vz az assert alpha.size == 1240 # default MaxGramSize for udp assert alpha.bc == 1024 assert not alpha.opened @@ -36,9 +36,9 @@ def test_memoer_peer_basic(): size = 38 # force gram size to be smaller than default so forces segmentation alpha = peermemoing.PeerMemoer(name="alpha", temp=True, size=size, port=alphaPort) assert alpha.name == "alpha" - assert alpha.code == MemoDex.MemoGram + assert alpha.code == MemoDex.GramZero assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az + assert alpha.Sizes[alpha.code] == (4, 24, 4, 0, 0) # hz mz nz vz az assert alpha.size == size assert alpha.bc == 1024 assert not alpha.opened @@ -61,7 +61,7 @@ def test_memoer_peer_basic(): assert len(alpha.txms) == 2 alpha.serviceTxMemos() assert not alpha.txms - assert len(alpha.txgs) == 4 + assert len(alpha.txgs) == 5 for m, d in alpha.txgs: assert not alpha.wiff(m) # base64 assert d == beta.path @@ -92,10 +92,11 @@ def test_memoer_peer_basic(): mid = list(beta.rxgs.keys())[1] assert beta.sources[mid] == alpha.path - assert beta.counts[mid] == 2 - assert len(beta.rxgs[mid]) == 2 + assert beta.counts[mid] == 3 + assert len(beta.rxgs[mid]) == 3 assert beta.rxgs[mid][0] == bytearray(b'How ya') - assert beta.rxgs[mid][1] == bytearray(b' doing?') + assert beta.rxgs[mid][1] == bytearray(b' doing') + assert beta.rxgs[mid][2] == bytearray(b'?') beta.serviceRxGrams() assert not beta.rxgs @@ -133,13 +134,13 @@ def test_memoer_peer_basic(): mid = list(alpha.rxgs.keys())[0] assert alpha.sources[mid] == beta.path - assert alpha.counts[mid] == 4 - assert len(alpha.rxgs[mid]) == 4 + assert alpha.counts[mid] == 5 + assert len(alpha.rxgs[mid]) == 5 mid = list(alpha.rxgs.keys())[1] assert alpha.sources[mid] == beta.path - assert alpha.counts[mid] == 3 - assert len(alpha.rxgs[mid]) == 3 + assert alpha.counts[mid] == 4 + assert len(alpha.rxgs[mid]) == 4 alpha.serviceRxGrams() assert not alpha.rxgs @@ -173,9 +174,9 @@ def test_memoer_peer_open(): assert alpha.name == "alpha" - assert alpha.code == MemoDex.MemoGram + assert alpha.code == MemoDex.GramZero assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az + assert alpha.Sizes[alpha.code] == (4, 24, 4, 0, 0) # hz mz nz vz az assert alpha.size == size assert alpha.bc == 1024 @@ -192,7 +193,7 @@ def test_memoer_peer_open(): assert len(alpha.txms) == 2 alpha.serviceTxMemos() assert not alpha.txms - assert len(alpha.txgs) == 4 + assert len(alpha.txgs) == 5 for m, d in alpha.txgs: assert not alpha.wiff(m) # base64 assert d == beta.path @@ -222,10 +223,11 @@ def test_memoer_peer_open(): mid = list(beta.rxgs.keys())[1] assert beta.sources[mid] == alpha.path - assert beta.counts[mid] == 2 - assert len(beta.rxgs[mid]) == 2 + assert beta.counts[mid] == 3 + assert len(beta.rxgs[mid]) == 3 assert beta.rxgs[mid][0] == bytearray(b'How ya') - assert beta.rxgs[mid][1] == bytearray(b' doing?') + assert beta.rxgs[mid][1] == bytearray(b' doing') + assert beta.rxgs[mid][2] == bytearray(b'?') beta.serviceRxGrams() assert not beta.rxgs @@ -262,13 +264,13 @@ def test_memoer_peer_open(): mid = list(alpha.rxgs.keys())[0] assert alpha.sources[mid] == beta.path - assert alpha.counts[mid] == 4 - assert len(alpha.rxgs[mid]) == 4 + assert alpha.counts[mid] == 5 + assert len(alpha.rxgs[mid]) == 5 mid = list(alpha.rxgs.keys())[1] assert alpha.sources[mid] == beta.path - assert alpha.counts[mid] == 3 - assert len(alpha.rxgs[mid]) == 3 + assert alpha.counts[mid] == 4 + assert len(alpha.rxgs[mid]) == 4 alpha.serviceRxGrams() assert not alpha.rxgs diff --git a/tests/core/uxd/test_peer_memoing.py b/tests/core/uxd/test_peer_memoing.py index 56909018..6e464ac7 100644 --- a/tests/core/uxd/test_peer_memoing.py +++ b/tests/core/uxd/test_peer_memoing.py @@ -20,9 +20,9 @@ def test_memoer_peer_basic(): return alpha = peermemoing.PeerMemoer(name="alpha", temp=True, size=38) assert alpha.name == "alpha" - assert alpha.code == MemoDex.MemoGram + assert alpha.code == MemoDex.GramZero assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az + assert alpha.Sizes[alpha.code] == (4, 24, 4, 0, 0) # hz mz nz vz az assert alpha.size == 38 assert alpha.bc == 4 @@ -43,7 +43,7 @@ def test_memoer_peer_basic(): assert len(alpha.txms) == 2 alpha.serviceTxMemos() assert not alpha.txms - assert len(alpha.txgs) == 4 + assert len(alpha.txgs) == 5 for m, d in alpha.txgs: assert not alpha.wiff(m) # base64 assert d == beta.path @@ -71,10 +71,11 @@ def test_memoer_peer_basic(): mid = list(beta.rxgs.keys())[1] assert beta.sources[mid] == alpha.path - assert beta.counts[mid] == 2 - assert len(beta.rxgs[mid]) == 2 + assert beta.counts[mid] == 3 + assert len(beta.rxgs[mid]) == 3 assert beta.rxgs[mid][0] == bytearray(b'How ya') - assert beta.rxgs[mid][1] == bytearray(b' doing?') + assert beta.rxgs[mid][1] == bytearray(b' doing') + assert beta.rxgs[mid][2] == bytearray(b'?') beta.serviceRxGrams() assert not beta.rxgs @@ -109,13 +110,13 @@ def test_memoer_peer_basic(): mid = list(alpha.rxgs.keys())[0] assert alpha.sources[mid] == beta.path - assert alpha.counts[mid] == 4 - assert len(alpha.rxgs[mid]) == 4 + assert alpha.counts[mid] == 5 + assert len(alpha.rxgs[mid]) == 5 mid = list(alpha.rxgs.keys())[1] assert alpha.sources[mid] == beta.path - assert alpha.counts[mid] == 3 - assert len(alpha.rxgs[mid]) == 3 + assert alpha.counts[mid] == 4 + assert len(alpha.rxgs[mid]) == 4 alpha.serviceRxGrams() assert not alpha.rxgs @@ -149,9 +150,9 @@ def test_memoer_peer_open(): with (peermemoing.openPM(name='alpha', size=38) as alpha, peermemoing.openPM(name='beta', size=38) as beta): assert alpha.name == "alpha" - assert alpha.code == MemoDex.MemoGram + assert alpha.code == MemoDex.GramZero assert not alpha.curt - assert alpha.Sizes[alpha.code] == (2, 22, 4, 0, 0) # hz mz nz vz az + assert alpha.Sizes[alpha.code] == (4, 24, 4, 0, 0) # hz mz nz vz az assert alpha.size == 38 assert alpha.bc == 4 @@ -168,7 +169,7 @@ def test_memoer_peer_open(): assert len(alpha.txms) == 2 alpha.serviceTxMemos() assert not alpha.txms - assert len(alpha.txgs) == 4 + assert len(alpha.txgs) == 5 for m, d in alpha.txgs: assert not alpha.wiff(m) # base64 assert d == beta.path @@ -196,10 +197,11 @@ def test_memoer_peer_open(): mid = list(beta.rxgs.keys())[1] assert beta.sources[mid] == alpha.path - assert beta.counts[mid] == 2 - assert len(beta.rxgs[mid]) == 2 + assert beta.counts[mid] == 3 + assert len(beta.rxgs[mid]) == 3 assert beta.rxgs[mid][0] == bytearray(b'How ya') - assert beta.rxgs[mid][1] == bytearray(b' doing?') + assert beta.rxgs[mid][1] == bytearray(b' doing') + assert beta.rxgs[mid][2] == bytearray(b'?') beta.serviceRxGrams() assert not beta.rxgs @@ -234,13 +236,13 @@ def test_memoer_peer_open(): mid = list(alpha.rxgs.keys())[0] assert alpha.sources[mid] == beta.path - assert alpha.counts[mid] == 4 - assert len(alpha.rxgs[mid]) == 4 + assert alpha.counts[mid] == 5 + assert len(alpha.rxgs[mid]) == 5 mid = list(alpha.rxgs.keys())[1] assert alpha.sources[mid] == beta.path - assert alpha.counts[mid] == 3 - assert len(alpha.rxgs[mid]) == 3 + assert alpha.counts[mid] == 4 + assert len(alpha.rxgs[mid]) == 4 alpha.serviceRxGrams() assert not alpha.rxgs