X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-python/blobdiff_plain/3dd40ab056aee7c852d26048537aa2a16121ce9d..98a1d50bd9c33b6cc9f281617400374e306378f7:/catacomb/__init__.py diff --git a/catacomb/__init__.py b/catacomb/__init__.py index eb19374..bd8aa57 100644 --- a/catacomb/__init__.py +++ b/catacomb/__init__.py @@ -23,16 +23,66 @@ ### along with Catacomb/Python; if not, write to the Free Software Foundation, ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import _base -import types as _types +from __future__ import with_statement + from binascii import hexlify as _hexify, unhexlify as _unhexify -from sys import argv as _argv +from contextlib import contextmanager as _ctxmgr +try: import DLFCN as _dlfcn +except ImportError: _dlfcn = None +import os as _os +from struct import pack as _pack +import sys as _sys +import types as _types + +###-------------------------------------------------------------------------- +### Import the main C extension module. + +try: + _dlflags = _odlflags = _sys.getdlopenflags() +except AttributeError: + _dlflags = _odlflags = -1 + +## Set the `deep binding' flag. Python has its own different MD5 +## implementation, and some distributions export `md5_init' and friends so +## they override our versions, which doesn't end well. Figure out how to +## turn this flag on so we don't have the problem. +if _dlflags >= 0: + try: _dlflags |= _dlfcn.RTLD_DEEPBIND + except AttributeError: + try: _dlflags |= _os.RTLD_DEEPBIND + except AttributeError: + if _os.uname()[0] == 'Linux': _dlflags |= 8 # magic knowledge + else: pass # can't do this. + _sys.setdlopenflags(_dlflags) + +import _base + +if _odlflags >= 0: + _sys.setdlopenflags(_odlflags) + +del _dlflags, _odlflags ###-------------------------------------------------------------------------- ### Basic stuff. -## For the benefit of the default keyreporter, we need the program na,e. -_base._ego(_argv[0]) +## For the benefit of the default keyreporter, we need the program name. +_base._ego(_sys.argv[0]) + +## Register our module. +_base._set_home_module(_sys.modules[__name__]) +def default_lostexchook(why, ty, val, tb): + """`catacomb.lostexchook(WHY, TY, VAL, TB)' reports lost exceptions.""" + _sys.stderr.write("\n\n!!! LOST EXCEPTION: %s\n" % why) + _sys.excepthook(ty, val, tb) + _sys.stderr.write("\n") +lostexchook = default_lostexchook + +## Text/binary conversions. +def _bin(s): return s + +## Iterating over dictionaries. +def _iteritems(dict): return dict.iteritems() +def _itervalues(dict): return dict.itervalues() ## How to fix a name back into the right identifier. Alas, the rules are not ## consistent. @@ -42,7 +92,7 @@ def _fixname(name): name = name.replace('-', '_') ## But slashes might become underscores or just vanish. - if name.startswith('salsa20'): name = name.translate(None, '/') + if name.startswith('salsa20'): name = name.replace('/', '') else: name = name.replace('/', '_') ## Done. @@ -56,22 +106,10 @@ def _init(): for i in b: if i[0] != '_': d[i] = b[i]; - for i in ['MP', 'GF', 'Field', - 'ECPt', 'ECPtCurve', 'ECCurve', 'ECInfo', - 'DHInfo', 'BinDHInfo', 'RSAPriv', 'BBSPriv', - 'PrimeFilter', 'RabinMiller', - 'Group', 'GE', - 'KeySZ', 'KeyData']: - c = d[i] - pre = '_' + i + '_' - plen = len(pre) - for j in b: - if j[:plen] == pre: - setattr(c, j[plen:], classmethod(b[j])) - for i in [gcciphers, gchashes, gcmacs, gcprps]: - for c in i.itervalues(): + for i in [gcciphers, gcaeads, gchashes, gcmacs, gcprps]: + for c in _itervalues(i): d[_fixname(c.name)] = c - for c in gccrands.itervalues(): + for c in _itervalues(gccrands): d[_fixname(c.name + 'rand')] = c _init() @@ -93,7 +131,7 @@ def _augment(c, cc): def _checkend(r): x, rest = r if rest != '': - raise SyntaxError, 'junk at end of string' + raise SyntaxError('junk at end of string') return x ## Some pretty-printing utilities. @@ -123,7 +161,8 @@ def _pp_commas(pp, printfn, items): else: pp.text(','); pp.breakable() printfn(i) def _pp_dict(pp, items): - def p((k, v)): + def p(kv): + k, v = kv pp.begin_group(0) pp.pretty(k) pp.text(':') @@ -141,15 +180,36 @@ class _tmp: def fromhex(x): return ByteString(_unhexify(x)) fromhex = staticmethod(fromhex) - def __hex__(me): - return _hexify(me) + def hex(me): return _hexify(me) + __hex__ = hex def __repr__(me): - return 'bytes(%r)' % hex(me) + return 'bytes(%r)' % me.hex() _augment(ByteString, _tmp) ByteString.__hash__ = str.__hash__ bytes = ByteString.fromhex ###-------------------------------------------------------------------------- +### Symmetric encryption. + +class _tmp: + def encrypt(me, n, m, tsz = None, h = ByteString.zero(0)): + if tsz is None: tsz = me.__class__.tagsz.default + e = me.enc(n, len(h), len(m), tsz) + if not len(h): a = None + else: a = e.aad().hash(h) + c0 = e.encrypt(m) + c1, t = e.done(aad = a) + return c0 + c1, t + def decrypt(me, n, c, t, h = ByteString.zero(0)): + d = me.dec(n, len(h), len(c), len(t)) + if not len(h): a = None + else: a = d.aad().hash(h) + m = d.decrypt(c) + m += d.done(t, aad = a) + return m +_augment(GAEKey, _tmp) + +###-------------------------------------------------------------------------- ### Hashing. class _tmp: @@ -159,25 +219,126 @@ class _tmp: _augment(GHash, _tmp) _augment(Poly1305Hash, _tmp) +class _HashBase (object): + ## The standard hash methods. Assume that `hash' is defined and returns + ## the receiver. + def _check_range(me, n, max): + if not (0 <= n <= max): raise OverflowError("out of range") + def hashu8(me, n): + me._check_range(n, 0xff) + return me.hash(_pack('B', n)) + def hashu16l(me, n): + me._check_range(n, 0xffff) + return me.hash(_pack('H', n)) + hashu16 = hashu16b + def hashu32l(me, n): + me._check_range(n, 0xffffffff) + return me.hash(_pack('L', n)) + hashu32 = hashu32b + def hashu64l(me, n): + me._check_range(n, 0xffffffffffffffff) + return me.hash(_pack('Q', n)) + hashu64 = hashu64b + def hashbuf8(me, s): return me.hashu8(len(s)).hash(s) + def hashbuf16l(me, s): return me.hashu16l(len(s)).hash(s) + def hashbuf16b(me, s): return me.hashu16b(len(s)).hash(s) + hashbuf16 = hashbuf16b + def hashbuf32l(me, s): return me.hashu32l(len(s)).hash(s) + def hashbuf32b(me, s): return me.hashu32b(len(s)).hash(s) + hashbuf32 = hashbuf32b + def hashbuf64l(me, s): return me.hashu64l(len(s)).hash(s) + def hashbuf64b(me, s): return me.hashu64b(len(s)).hash(s) + hashbuf64 = hashbuf64b + def hashstrz(me, s): return me.hash(s).hashu8(0) + +class _ShakeBase (_HashBase): + + ## Python gets really confused if I try to augment `__new__' on native + ## classes, so wrap and delegate. Sorry. + def __init__(me, perso = _bin(''), *args, **kw): + super(_ShakeBase, me).__init__(*args, **kw) + me._h = me._SHAKE(perso = perso, func = me._FUNC) + + ## Delegate methods... + def copy(me): new = me.__class__._bare_new(); new._copy(me); return new + def _copy(me, other): me._h = other._h.copy() + def hash(me, m): me._h.hash(m); return me + def xof(me): me._h.xof(); return me + def get(me, n): return me._h.get(n) + def mask(me, m): return me._h.mask(m) + def done(me, n): return me._h.done(n) + def check(me, h): return ctstreq(h, me.done(len(h))) + @property + def state(me): return me._h.state + @property + def buffered(me): return me._h.buffered + @property + def rate(me): return me._h.rate + @classmethod + def _bare_new(cls): return cls() + +class _tmp: + def check(me, h): + return ctstreq(h, me.done(len(h))) + def leftenc(me, n): + nn = MP(n).storeb() + return me.hashu8(len(nn)).hash(nn) + def rightenc(me, n): + nn = MP(n).storeb() + return me.hash(nn).hashu8(len(nn)) + def stringenc(me, str): + return me.leftenc(8*len(str)).hash(str) + def bytepad_before(me): + return me.leftenc(me.rate) + def bytepad_after(me): + if me.buffered: me.hash(me._Z[:me.rate - me.buffered]) + return me + @_ctxmgr + def bytepad(me): + me.bytepad_before() + yield me + me.bytepad_after() +_augment(Shake, _tmp) +_augment(_ShakeBase, _tmp) +Shake._Z = _ShakeBase._Z = ByteString.zero(200) + +class KMAC (_ShakeBase): + _FUNC = _bin('KMAC') + def __init__(me, k, *arg, **kw): + super(KMAC, me).__init__(*arg, **kw) + with me.bytepad(): me.stringenc(k) + def done(me, n = -1): + if n < 0: n = me._TAGSZ + me.rightenc(8*n) + return super(KMAC, me).done(n) + def xof(me): + me.rightenc(0) + return super(KMAC, me).xof() + @classmethod + def _bare_new(cls): return cls(_bin("")) + +class KMAC128 (KMAC): _SHAKE = Shake128; _TAGSZ = 16 +class KMAC256 (KMAC): _SHAKE = Shake256; _TAGSZ = 32 + ###-------------------------------------------------------------------------- ### NaCl `secretbox'. def secret_box(k, n, m): - E = xsalsa20(k).setiv(n) - r = E.enczero(poly1305.keysz.default) - s = E.enczero(poly1305.masksz) - y = E.encrypt(m) - t = poly1305(r)(s).hash(y).done() - return ByteString(t + y) + y, t = salsa20_naclbox(k).encrypt(n, m) + return t + y def secret_unbox(k, n, c): - E = xsalsa20(k).setiv(n) - r = E.enczero(poly1305.keysz.default) - s = E.enczero(poly1305.masksz) - y = c[poly1305.tagsz:] - if not poly1305(r)(s).hash(y).check(c[0:poly1305.tagsz]): - raise ValueError, 'decryption failed' - return E.decrypt(c[poly1305.tagsz:]) + tsz = poly1305.tagsz + return salsa20_naclbox(k).decrypt(n, c[tsz:], c[0:tsz]) ###-------------------------------------------------------------------------- ### Multiprecision integers and binary polynomials. @@ -217,18 +378,24 @@ class BaseRat (object): def __mul__(me, you): n, d = _split_rat(you) return type(me)(me._n*n, me._d*d) - def __div__(me, you): + __rmul__ = __mul__ + def __truediv__(me, you): n, d = _split_rat(you) return type(me)(me._n*d, me._d*n) - def __rdiv__(me, you): + def __rtruediv__(me, you): n, d = _split_rat(you) return type(me)(me._d*n, me._n*d) - def __cmp__(me, you): - n, d = _split_rat(you) - return type(me)(me._n*d, n*me._d) - def __rcmp__(me, you): + __div__ = __truediv__ + __rdiv__ = __rtruediv__ + def _order(me, you, op): n, d = _split_rat(you) - return cmp(n*me._d, me._n*d) + return op(me._n*d, n*me._d) + def __eq__(me, you): return me._order(you, lambda x, y: x == y) + def __ne__(me, you): return me._order(you, lambda x, y: x != y) + def __le__(me, you): return me._order(you, lambda x, y: x <= y) + def __lt__(me, you): return me._order(you, lambda x, y: x < y) + def __gt__(me, you): return me._order(you, lambda x, y: x > y) + def __ge__(me, you): return me._order(you, lambda x, y: x >= y) class IntRat (BaseRat): RING = MP @@ -245,8 +412,10 @@ class _tmp: def mont(x): return MPMont(x) def barrett(x): return MPBarrett(x) def reduce(x): return MPReduce(x) - def __div__(me, you): return IntRat(me, you) - def __rdiv__(me, you): return IntRat(you, me) + def __truediv__(me, you): return IntRat(me, you) + def __rtruediv__(me, you): return IntRat(you, me) + __div__ = __truediv__ + __rdiv__ = __rtruediv__ _repr_pretty_ = _pp_str _augment(MP, _tmp) @@ -257,8 +426,10 @@ class _tmp: def halftrace(x, y): return x.reduce().halftrace(y) def modsqrt(x, y): return x.reduce().sqrt(y) def quadsolve(x, y): return x.reduce().quadsolve(y) - def __div__(me, you): return GFRat(me, you) - def __rdiv__(me, you): return GFRat(you, me) + def __truediv__(me, you): return GFRat(me, you) + def __rtruediv__(me, you): return GFRat(you, me) + __div__ = __truediv__ + __rdiv__ = __rtruediv__ _repr_pretty_ = _pp_str _augment(GF, _tmp) @@ -425,6 +596,7 @@ class _tmp: def __repr__(me): return '%s(%d)' % (_clsname(me), me.default) def check(me, sz): return True def best(me, sz): return sz + def pad(me, sz): return sz _augment(KeySZAny, _tmp) class _tmp: @@ -441,11 +613,15 @@ class _tmp: pp.pretty(me.max); pp.text(','); pp.breakable() pp.pretty(me.mod) pp.end_group(ind, ')') - def check(me, sz): return me.min <= sz <= me.max and sz % me.mod == 0 + def check(me, sz): return me.min <= sz <= me.max and sz%me.mod == 0 def best(me, sz): - if sz < me.min: raise ValueError, 'key too small' + if sz < me.min: raise ValueError('key too small') elif sz > me.max: return me.max - else: return sz - (sz % me.mod) + else: return sz - sz%me.mod + def pad(me, sz): + if sz > me.max: raise ValueError('key too large') + elif sz < me.min: return me.min + else: sz += me.mod - 1; return sz - sz%me.mod _augment(KeySZRange, _tmp) class _tmp: @@ -465,7 +641,13 @@ class _tmp: found = -1 for i in me.set: if found < i <= sz: found = i - if found < 0: raise ValueError, 'key too small' + if found < 0: raise ValueError('key too small') + return found + def pad(me, sz): + found = -1 + for i in me.set: + if sz <= i and (found == -1 or i < found): found = i + if found < 0: raise ValueError('key too large') return found _augment(KeySZSet, _tmp) @@ -473,21 +655,34 @@ _augment(KeySZSet, _tmp) ### Key data objects. class _tmp: + def merge(me, file, report = None): + """KF.merge(FILE, [report = ])""" + name = file.name + lno = 1 + for line in file: + me.mergeline(name, lno, line, report) + lno += 1 + return me def __repr__(me): return '%s(%r)' % (_clsname(me), me.name) _augment(KeyFile, _tmp) class _tmp: + def extract(me, file, filter = ''): + """KEY.extract(FILE, [filter = ])""" + line = me.extractline(filter) + file.write(line) + return me def __repr__(me): return '%s(%r)' % (_clsname(me), me.fulltag) _augment(Key, _tmp) class _tmp: def __repr__(me): return '%s({%s})' % (_clsname(me), - ', '.join(['%r: %r' % kv for kv in me.iteritems()])) + ', '.join(['%r: %r' % kv for kv in _iteritems(me)()])) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: pp.text('...') - else: _pp_dict(pp, me.iteritems()) + else: _pp_dict(pp, _iteritems(me)) pp.end_group(ind, ')') _augment(KeyAttributes, _tmp) @@ -531,11 +726,11 @@ _augment(KeyDataECPt, _tmp) class _tmp: def __repr__(me): return '%s({%s})' % (_clsname(me), - ', '.join(['%r: %r' % kv for kv in me.iteritems()])) + ', '.join(['%r: %r' % kv for kv in _iteritems(me)])) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me, '({ ') if cyclep: pp.text('...') - else: _pp_dict(pp, me.iteritems()) + else: _pp_dict(pp, _iteritems(me)) pp.end_group(ind, ' })') _augment(KeyDataStructured, _tmp) @@ -612,7 +807,7 @@ _augment(GE, _tmp) ### RSA encoding techniques. class PKCS1Crypt (object): - def __init__(me, ep = '', rng = rand): + def __init__(me, ep = _bin(''), rng = rand): me.ep = ep me.rng = rng def encode(me, msg, nbits): @@ -621,7 +816,7 @@ class PKCS1Crypt (object): return _base._p1crypt_decode(ct, nbits, me.ep, me.rng) class PKCS1Sig (object): - def __init__(me, ep = '', rng = rand): + def __init__(me, ep = _bin(''), rng = rand): me.ep = ep me.rng = rng def encode(me, msg, nbits): @@ -630,7 +825,7 @@ class PKCS1Sig (object): return _base._p1sig_decode(msg, sig, nbits, me.ep, me.rng) class OAEP (object): - def __init__(me, mgf = sha_mgf, hash = sha, ep = '', rng = rand): + def __init__(me, mgf = sha_mgf, hash = sha, ep = _bin(''), rng = rand): me.mgf = mgf me.hash = hash me.ep = ep @@ -705,21 +900,23 @@ _augment(RSAPriv, _tmp) ### DSA and related schemes. class _tmp: - def __repr__(me): return '%s(G = %r, p = %r)' % (_clsname(me), me.G, me.p) + def __repr__(me): return '%s(G = %r, p = %r, hash = %r)' % \ + (_clsname(me), me.G, me.p, me.hash) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: pp.text('...') else: _pp_kv(pp, 'G', me.G); pp.text(','); pp.breakable() - _pp_kv(pp, 'p', me.p) + _pp_kv(pp, 'p', me.p); pp.text(','); pp.breakable() + _pp_kv(pp, 'hash', me.hash) pp.end_group(ind, ')') _augment(DSAPub, _tmp) _augment(KCDSAPub, _tmp) class _tmp: - def __repr__(me): return '%s(G = %r, u = %s, p = %r)' % \ - (_clsname(me), me.G, _repr_secret(me.u), me.p) + def __repr__(me): return '%s(G = %r, u = %s, p = %r, hash = %r)' % \ + (_clsname(me), me.G, _repr_secret(me.u), me.p, me.hash) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: @@ -727,7 +924,8 @@ class _tmp: else: _pp_kv(pp, 'G', me.G); pp.text(','); pp.breakable() _pp_kv(pp, 'u', me.u, True); pp.text(','); pp.breakable() - _pp_kv(pp, 'p', me.p) + _pp_kv(pp, 'p', me.p); pp.text(','); pp.breakable() + _pp_kv(pp, 'hash', me.hash) pp.end_group(ind, ')') _augment(DSAPriv, _tmp) _augment(KCDSAPriv, _tmp) @@ -735,133 +933,110 @@ _augment(KCDSAPriv, _tmp) ###-------------------------------------------------------------------------- ### Bernstein's elliptic curve crypto and related schemes. -X25519_BASE = \ - bytes('0900000000000000000000000000000000000000000000000000000000000000') +X25519_BASE = MP(9).storel(32) +X448_BASE = MP(5).storel(56) -X448_BASE = \ - bytes('05000000000000000000000000000000000000000000000000000000' - '00000000000000000000000000000000000000000000000000000000') +Z128 = ByteString.zero(16) -Z128 = bytes('00000000000000000000000000000000') - -class _BoxyPub (object): - def __init__(me, pub, *kw, **kwargs): - if len(pub) != me._PUBSZ: raise ValueError, 'bad public key' - super(_BoxyPub, me).__init__(*kw, **kwargs) +class _BasePub (object): + def __init__(me, pub, *args, **kw): + if not me._PUBSZ.check(len(pub)): raise ValueError('bad public key') + super(_BasePub, me).__init__(*args, **kw) me.pub = pub def __repr__(me): return '%s(pub = %r)' % (_clsname(me), me.pub) + def _pp(me, pp): _pp_kv(pp, 'pub', me.pub) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) - if cyclep: - pp.text('...') - else: - _pp_kv(pp, 'pub', me.pub) + if cyclep: pp.text('...') + else: me._pp(pp) pp.end_group(ind, ')') -class _BoxyPriv (_BoxyPub): - def __init__(me, priv, pub = None, *kw, **kwargs): - if len(priv) != me._KEYSZ: raise ValueError, 'bad private key' - if pub is None: pub = me._op(priv, me._BASE) - super(_BoxyPriv, me).__init__(pub = pub, *kw, **kwargs) +class _BasePriv (object): + def __init__(me, priv, pub = None, *args, **kw): + if not me._KEYSZ.check(len(priv)): raise ValueError('bad private key') + if pub is None: pub = me._pubkey(priv) + super(_BasePriv, me).__init__(pub = pub, *args, **kw) me.priv = priv + @classmethod + def generate(cls, rng = rand): + return cls(rng.block(cls._KEYSZ.default)) + def __repr__(me): + return '%s(priv = %d, pub = %r)' % \ + (_clsname(me), _repr_secret(me.priv), me.pub) + def _pp(me, pp): + _pp_kv(pp, 'priv', me.priv, secretp = True); pp.text(','); pp.breakable() + super(_BasePriv, me)._pp(pp) + +class _XDHPub (_BasePub): pass + +class _XDHPriv (_BasePriv): + def _pubkey(me, priv): return me._op(priv, me._BASE) def agree(me, you): return me._op(me.priv, you.pub) - def boxkey(me, recip): - return me._hashkey(me.agree(recip)) - def box(me, recip, n, m): - return secret_box(me.boxkey(recip), n, m) - def unbox(me, recip, n, c): - return secret_unbox(me.boxkey(recip), n, c) - def __repr__(me): return '%s(priv = %s, pub = %r)' % \ - (_clsname(me), _repr_secret(me.priv), me.pub) - def _repr_pretty_(me, pp, cyclep): - ind = _pp_bgroup_tyname(pp, me) - if cyclep: - pp.text('...') - else: - _pp_kv(pp, 'priv', me.priv, True); pp.text(','); pp.breakable() - _pp_kv(pp, 'pub', me.pub) - pp.end_group(ind, ')') + def boxkey(me, recip): return me._hashkey(me.agree(recip)) + def box(me, recip, n, m): return secret_box(me.boxkey(recip), n, m) + def unbox(me, recip, n, c): return secret_unbox(me.boxkey(recip), n, c) -class X25519Pub (_BoxyPub): - _PUBSZ = X25519_PUBSZ +class X25519Pub (_XDHPub): + _PUBSZ = KeySZSet(X25519_PUBSZ) _BASE = X25519_BASE -class X25519Priv (_BoxyPriv, X25519Pub): - _KEYSZ = X25519_KEYSZ +class X25519Priv (_XDHPriv, X25519Pub): + _KEYSZ = KeySZSet(X25519_KEYSZ) def _op(me, k, X): return x25519(k, X) def _hashkey(me, z): return hsalsa20_prf(z, Z128) -class X448Pub (_BoxyPub): - _PUBSZ = X448_PUBSZ +class X448Pub (_XDHPub): + _PUBSZ = KeySZSet(X448_PUBSZ) _BASE = X448_BASE -class X448Priv (_BoxyPriv, X448Pub): - _KEYSZ = X448_KEYSZ +class X448Priv (_XDHPriv, X448Pub): + _KEYSZ = KeySZSet(X448_KEYSZ) def _op(me, k, X): return x448(k, X) - ##def _hashkey(me, z): return ??? - -class Ed25519Pub (object): - def __init__(me, pub): - me.pub = pub - def verify(me, msg, sig): - return ed25519_verify(me.pub, msg, sig) - -class Ed25519Priv (Ed25519Pub): - def __init__(me, priv): - me.priv = priv - Ed25519Pub.__init__(me, ed25519_pubkey(priv)) - def sign(me, msg): - return ed25519_sign(me.priv, msg, pub = me.pub) - @classmethod - def generate(cls, rng = rand): - return cls(rng.block(ED25519_KEYSZ)) + def _hashkey(me, z): return Shake256().hash(z).done(salsa20.keysz.default) + +class _EdDSAPub (_BasePub): + def beginhash(me): return me._HASH() + def endhash(me, h): return h.done() + +class _EdDSAPriv (_BasePriv, _EdDSAPub): + pass + +class Ed25519Pub (_EdDSAPub): + _PUBSZ = KeySZSet(ED25519_PUBSZ) + _HASH = sha512 + def verify(me, msg, sig, **kw): + return ed25519_verify(me.pub, msg, sig, **kw) + +class Ed25519Priv (_EdDSAPriv, Ed25519Pub): + _KEYSZ = KeySZAny(ED25519_KEYSZ) + def _pubkey(me, priv): return ed25519_pubkey(priv) + def sign(me, msg, **kw): + return ed25519_sign(me.priv, msg, pub = me.pub, **kw) + +class Ed448Pub (_EdDSAPub): + _PUBSZ = KeySZSet(ED448_PUBSZ) + _HASH = shake256 + def verify(me, msg, sig, **kw): + return ed448_verify(me.pub, msg, sig, **kw) + +class Ed448Priv (_EdDSAPriv, Ed448Pub): + _KEYSZ = KeySZAny(ED448_KEYSZ) + def _pubkey(me, priv): return ed448_pubkey(priv) + def sign(me, msg, **kw): + return ed448_sign(me.priv, msg, pub = me.pub, **kw) ###-------------------------------------------------------------------------- -### Built-in named curves and prime groups. - -class _groupmap (object): - def __init__(me, map, nth): - me.map = map - me.nth = nth - me._n = max(map.values()) + 1 - me.i = me._n*[None] +### Built-in algorithm and group tables. + +class _tmp: def __repr__(me): - return '{%s}' % ', '.join(['%r: %r' % kv for kv in me.iteritems()]) + return '{%s}' % ', '.join(['%r: %r' % kv for kv in _iteritems(me)]) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup(pp, '{ ') if cyclep: pp.text('...') - else: _pp_dict(pp, me.iteritems()) + else: _pp_dict(pp, _iteritems(me)) pp.end_group(ind, ' }') - def __len__(me): - return me._n - def __contains__(me, k): - return k in me.map - def __getitem__(me, k): - i = me.map[k] - if me.i[i] is None: - me.i[i] = me.nth(i) - return me.i[i] - def __setitem__(me, k, v): - raise TypeError, "immutable object" - def __iter__(me): - return iter(me.map) - def iterkeys(me): - return iter(me.map) - def itervalues(me): - for k in me: - yield me[k] - def iteritems(me): - for k in me: - yield k, me[k] - def keys(me): - return [k for k in me] - def values(me): - return [me[k] for k in me] - def items(me): - return [(k, me[k]) for k in me] -eccurves = _groupmap(_base._eccurves, ECInfo._curven) -primegroups = _groupmap(_base._pgroups, DHInfo._groupn) -bingroups = _groupmap(_base._bingroups, BinDHInfo._groupn) +_augment(_base._MiscTable, _tmp) ###-------------------------------------------------------------------------- ### Prime number generation. @@ -971,7 +1146,7 @@ class SimulStepper (PrimeGenEventHandler): me.add = add def _stepfn(me, step): if step <= 0: - raise ValueError, 'step must be positive' + raise ValueError('step must be positive') if step <= MPW_MAX: return lambda f: f.step(step) j = PrimeFilter(step)