catacomb/__init__.py (BaseRat): Make comparisons actually work.
[catacomb-python] / catacomb / __init__.py
index 7ea8d57..c0cb1ab 100644 (file)
@@ -46,7 +46,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.
@@ -320,7 +320,7 @@ class BaseRat (object):
     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)
+    return cmp(me._n*d, n*me._d)
   def __rcmp__(me, you):
     n, d = _split_rat(you)
     return cmp(n*me._d, me._n*d)
@@ -835,77 +835,92 @@ X448_BASE = MP(5).storel(56)
 
 Z128 = ByteString.zero(16)
 
-class _BoxyPub (object):
+class _BasePub (object):
   def __init__(me, pub, *args, **kw):
-    if len(pub) != me._PUBSZ: raise ValueError, 'bad public key'
-    super(_BoxyPub, me).__init__(*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):
+class _BasePriv (object):
   def __init__(me, priv, pub = None, *args, **kw):
-    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, *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.