X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/catacomb-python/blobdiff_plain/d7012c2b527e1a079c78ec4c383083ac4f0eb850..1b3b79da95ab3a541fb613c82d6e2e8b5136e4ae:/catacomb/__init__.py diff --git a/catacomb/__init__.py b/catacomb/__init__.py index 28b4f85..1a2b5f4 100644 --- a/catacomb/__init__.py +++ b/catacomb/__init__.py @@ -23,10 +23,14 @@ ### along with Catacomb/Python; if not, write to the Free Software Foundation, ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +from __future__ import with_statement + import _base import types as _types from binascii import hexlify as _hexify, unhexlify as _unhexify +from contextlib import contextmanager as _ctxmgr from sys import argv as _argv +from struct import pack as _pack ###-------------------------------------------------------------------------- ### Basic stuff. @@ -34,6 +38,20 @@ from sys import argv as _argv ## For the benefit of the default keyreporter, we need the program na,e. _base._ego(_argv[0]) +## How to fix a name back into the right identifier. Alas, the rules are not +## consistent. +def _fixname(name): + + ## Hyphens consistently become underscores. + name = name.replace('-', '_') + + ## But slashes might become underscores or just vanish. + if name.startswith('salsa20'): name = name.translate(None, '/') + else: name = name.replace('/', '_') + + ## Done. + return name + ## Initialize the module. Drag in the static methods of the various ## classes; create names for the various known crypto algorithms. def _init(): @@ -42,7 +60,8 @@ def _init(): for i in b: if i[0] != '_': d[i] = b[i]; - for i in ['MP', 'GF', 'Field', + for i in ['ByteString', + 'MP', 'GF', 'Field', 'ECPt', 'ECPtCurve', 'ECCurve', 'ECInfo', 'DHInfo', 'BinDHInfo', 'RSAPriv', 'BBSPriv', 'PrimeFilter', 'RabinMiller', @@ -56,9 +75,9 @@ def _init(): setattr(c, j[plen:], classmethod(b[j])) for i in [gcciphers, gchashes, gcmacs, gcprps]: for c in i.itervalues(): - d[c.name.replace('-', '_').translate(None, '/')] = c + d[_fixname(c.name)] = c for c in gccrands.itervalues(): - d[c.name.replace('-', '_').translate(None, '/') + 'rand'] = c + d[_fixname(c.name + 'rand')] = c _init() ## A handy function for our work: add the methods of a named class to an @@ -83,16 +102,24 @@ def _checkend(r): return x ## Some pretty-printing utilities. +PRINT_SECRETS = False +def _clsname(me): return type(me).__name__ +def _repr_secret(thing, secretp = True): + if not secretp or PRINT_SECRETS: return repr(thing) + else: return '#' def _pp_str(me, pp, cyclep): pp.text(cyclep and '...' or str(me)) +def _pp_secret(pp, thing, secretp = True): + if not secretp or PRINT_SECRETS: pp.pretty(thing) + else: pp.text('#') def _pp_bgroup(pp, text): ind = len(text) pp.begin_group(ind, text) return ind def _pp_bgroup_tyname(pp, obj, open = '('): - return _pp_bgroup(pp, type(obj).__name__ + open) -def _pp_kv(pp, k, v): + return _pp_bgroup(pp, _clsname(obj) + open) +def _pp_kv(pp, k, v, secretp = False): ind = _pp_bgroup(pp, k + ' = ') - pp.pretty(v) + _pp_secret(pp, v, secretp) pp.end_group(ind, '') def _pp_commas(pp, printfn, items): firstp = True @@ -137,6 +164,96 @@ 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 hashu8(me, n): return me.hash(_pack('B', n)) + def hashu16l(me, n): return me.hash(_pack('H', n)) + hashu16 = hashu16b + def hashu32l(me, n): return me.hash(_pack('L', n)) + hashu32 = hashu32b + def hashu64l(me, n): 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 = '', *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__(); new._copy(me) + def _copy(me, other): me._h = other._h + 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 + +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(200*'\0') + +class KMAC (_ShakeBase): + _FUNC = '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() + +class KMAC128 (KMAC): _SHAKE = Shake128; _TAGSZ = 16 +class KMAC256 (KMAC): _SHAKE = Shake256; _TAGSZ = 32 + ###-------------------------------------------------------------------------- ### NaCl `secretbox'. @@ -179,7 +296,7 @@ class BaseRat (object): @property def denom(me): return me._d def __str__(me): return '%s/%s' % (me._n, me._d) - def __repr__(me): return '%s(%s, %s)' % (type(me).__name__, me._n, me._d) + def __repr__(me): return '%s(%s, %s)' % (_clsname(me), me._n, me._d) _repr_pretty_ = _pp_str def __add__(me, you): @@ -256,7 +373,7 @@ class _tmp: _augment(Field, _tmp) class _tmp: - def __repr__(me): return '%s(%sL)' % (type(me).__name__, me.p) + def __repr__(me): return '%s(%sL)' % (_clsname(me), me.p) def __hash__(me): return 0x114401de ^ hash(me.p) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) @@ -267,7 +384,7 @@ class _tmp: _augment(PrimeField, _tmp) class _tmp: - def __repr__(me): return '%s(%#xL)' % (type(me).__name__, me.p) + def __repr__(me): return '%s(%#xL)' % (_clsname(me), me.p) def ec(me, a, b): return ECBinProjCurve(me, a, b) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) @@ -299,7 +416,7 @@ _augment(FE, _tmp) class _tmp: def __repr__(me): - return '%s(%r, %s, %s)' % (type(me).__name__, me.field, me.a, me.b) + return '%s(%r, %s, %s)' % (_clsname(me), me.field, me.a, me.b) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: @@ -337,8 +454,8 @@ _augment(ECBinCurve, _tmp) class _tmp: def __repr__(me): - if not me: return 'ECPt()' - return 'ECPt(%s, %s)' % (me.ix, me.iy) + if not me: return '%s()' % _clsname(me) + return '%s(%s, %s)' % (_clsname(me), me.ix, me.iy) def __str__(me): if not me: return 'inf' return '(%s, %s)' % (me.ix, me.iy) @@ -356,8 +473,8 @@ _augment(ECPt, _tmp) class _tmp: def __repr__(me): - return 'ECInfo(curve = %r, G = %r, r = %s, h = %s)' % \ - (me.curve, me.G, me.r, me.h) + return '%s(curve = %r, G = %r, r = %s, h = %s)' % \ + (_clsname(me), me.curve, me.G, me.r, me.h) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: @@ -400,15 +517,15 @@ _augment(ECPtCurve, _tmp) ### Key sizes. class _tmp: - def __repr__(me): return 'KeySZAny(%d)' % me.default + def __repr__(me): return '%s(%d)' % (_clsname(me), me.default) def check(me, sz): return True def best(me, sz): return sz _augment(KeySZAny, _tmp) class _tmp: def __repr__(me): - return 'KeySZRange(%d, %d, %d, %d)' % \ - (me.default, me.min, me.max, me.mod) + return '%s(%d, %d, %d, %d)' % \ + (_clsname(me), me.default, me.min, me.max, me.mod) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: @@ -427,7 +544,7 @@ class _tmp: _augment(KeySZRange, _tmp) class _tmp: - def __repr__(me): return 'KeySZSet(%d, %s)' % (me.default, me.set) + def __repr__(me): return '%s(%d, %s)' % (_clsname(me), me.default, me.set) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: @@ -451,17 +568,17 @@ _augment(KeySZSet, _tmp) ### Key data objects. class _tmp: - def __repr__(me): return 'KeyFile(%r)' % me.name + def __repr__(me): return '%s(%r)' % (_clsname(me), me.name) _augment(KeyFile, _tmp) class _tmp: - def __repr__(me): return 'Key(%r)' % me.fulltag + def __repr__(me): return '%s(%r)' % (_clsname(me), me.fulltag) _augment(Key, _tmp) class _tmp: def __repr__(me): - return 'KeyAttributes({%s})' % \ - ', '.join(['%r: %r' % kv for kv in me.iteritems()]) + return '%s({%s})' % (_clsname(me), + ', '.join(['%r: %r' % kv for kv in me.iteritems()])) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: pp.text('...') @@ -470,74 +587,46 @@ class _tmp: _augment(KeyAttributes, _tmp) class _tmp: - def __repr__(me): return 'KeyDataBinary(%r, %r)' % \ - (me.bin, me.writeflags(me.flags)) + def __repr__(me): + return '%s(%s, %r)' % (_clsname(me), + _repr_secret(me._guts(), + not (me.flags & KF_NONSECRET)), + me.writeflags(me.flags)) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: pp.text('...') else: - pp.pretty(me.bin); pp.text(','); pp.breakable() + _pp_secret(pp, me._guts(), not (me.flags & KF_NONSECRET)) + pp.text(','); pp.breakable() pp.pretty(me.writeflags(me.flags)) pp.end_group(ind, ')') +_augment(KeyData, _tmp) + +class _tmp: + def _guts(me): return me.bin _augment(KeyDataBinary, _tmp) class _tmp: - def __repr__(me): return 'KeyDataEncrypted(%r, %r)' % \ - (me.ct, me.writeflags(me.flags)) - def _repr_pretty_(me, pp, cyclep): - ind = _pp_bgroup_tyname(pp, me) - if cyclep: - pp.text('...') - else: - pp.pretty(me.ct); pp.text(','); pp.breakable() - pp.pretty(me.writeflags(me.flags)) - pp.end_group(ind, ')') + def _guts(me): return me.ct _augment(KeyDataEncrypted, _tmp) class _tmp: - def __repr__(me): return 'KeyDataMP(%r, %r)' % \ - (me.mp, me.writeflags(me.flags)) - def _repr_pretty_(me, pp, cyclep): - ind = _pp_bgroup_tyname(pp, me) - if cyclep: - pp.text('...') - else: - pp.pretty(me.mp); pp.text(','); pp.breakable() - pp.pretty(me.writeflags(me.flags)) - pp.end_group(ind, ')') + def _guts(me): return me.mp _augment(KeyDataMP, _tmp) class _tmp: - def __repr__(me): return 'KeyDataString(%r)' % \ - (me.str, me.writeflags(me.flags)) - def _repr_pretty_(me, pp, cyclep): - ind = _pp_bgroup_tyname(pp, me) - if cyclep: - pp.text('...') - else: - pp.pretty(me.str); pp.text(','); pp.breakable() - pp.pretty(me.writeflags(me.flags)) - pp.end_group(ind, ')') + def _guts(me): return me.str _augment(KeyDataString, _tmp) class _tmp: - def __repr__(me): return 'KeyDataECPt(%r)' % \ - (me.ecpt, me.writeflags(me.flags)) - def _repr_pretty_(me, pp, cyclep): - ind = _pp_bgroup_tyname(pp, me) - if cyclep: - pp.text('...') - else: - pp.pretty(me.ecpt); pp.text(','); pp.breakable() - pp.pretty(me.writeflags(me.flags)) - pp.end_group(ind, ')') + def _guts(me): return me.ecpt _augment(KeyDataECPt, _tmp) class _tmp: def __repr__(me): - return 'KeyDataStructured({%s})' % \ - ', '.join(['%r: %r' % kv for kv in me.iteritems()]) + return '%s({%s})' % (_clsname(me), + ', '.join(['%r: %r' % kv for kv in me.iteritems()])) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me, '({ ') if cyclep: pp.text('...') @@ -550,8 +639,7 @@ _augment(KeyDataStructured, _tmp) class _tmp: def __repr__(me): - return '%s(p = %s, r = %s, g = %s)' % \ - (type(me).__name__, me.p, me.r, me.g) + return '%s(p = %s, r = %s, g = %s)' % (_clsname(me), me.p, me.r, me.g) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: @@ -573,7 +661,7 @@ _augment(BinDHInfo, _tmp) class _tmp: def __repr__(me): - return '%s(%r)' % (type(me).__name__, me.info) + return '%s(%r)' % (_clsname(me), me.info) def _repr_pretty_(me, pp, cyclep): ind = _pp_bgroup_tyname(pp, me) if cyclep: pp.text('...') @@ -671,78 +759,171 @@ class _tmp: return x is None or x == msg except ValueError: return False + def __repr__(me): + return '%s(n = %r, e = %r)' % (_clsname(me), me.n, me.e) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'n', me.n); pp.text(','); pp.breakable() + _pp_kv(pp, 'e', me.e) + pp.end_group(ind, ')') _augment(RSAPub, _tmp) class _tmp: def decrypt(me, ct, enc): return enc.decode(me.privop(ct), me.n.nbits) def sign(me, msg, enc): return me.privop(enc.encode(msg, me.n.nbits)) + def __repr__(me): + return '%s(n = %r, e = %r, d = %s, ' \ + 'p = %s, q = %s, dp = %s, dq = %s, q_inv = %s)' % \ + (_clsname(me), me.n, me.e, + _repr_secret(me.d), _repr_secret(me.p), _repr_secret(me.q), + _repr_secret(me.dp), _repr_secret(me.dq), _repr_secret(me.q_inv)) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'n', me.n); pp.text(','); pp.breakable() + _pp_kv(pp, 'e', me.e); pp.text(','); pp.breakable() + _pp_kv(pp, 'd', me.d, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'p', me.p, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'q', me.q, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'dp', me.dp, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'dq', me.dq, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'q_inv', me.q_inv, secretp = True) + pp.end_group(ind, ')') _augment(RSAPriv, _tmp) ###-------------------------------------------------------------------------- -### Bernstein's elliptic curve crypto and related schemes. +### DSA and related schemes. + +class _tmp: + 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.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, 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: + pp.text('...') + 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.text(','); pp.breakable() + _pp_kv(pp, 'hash', me.hash) + pp.end_group(ind, ')') +_augment(DSAPriv, _tmp) +_augment(KCDSAPriv, _tmp) -X25519_BASE = \ - bytes('0900000000000000000000000000000000000000000000000000000000000000') +###-------------------------------------------------------------------------- +### Bernstein's elliptic curve crypto and related schemes. -X448_BASE = \ - bytes('05000000000000000000000000000000000000000000000000000000' - '00000000000000000000000000000000000000000000000000000000') +X25519_BASE = MP(9).storel(32) +X448_BASE = MP(5).storel(56) -Z128 = bytes('00000000000000000000000000000000') +Z128 = ByteString.zero(16) -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: 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)) - -class X25519Pub (_BoxyPub): - _PUBSZ = X25519_PUBSZ + 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 (_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.