catacomb/pwsafe.py: Add missing `.errno' projection.
[catacomb-python] / catacomb / __init__.py
index 8038815..c810c42 100644 (file)
@@ -27,7 +27,8 @@ from __future__ import with_statement
 
 from binascii import hexlify as _hexify, unhexlify as _unhexify
 from contextlib import contextmanager as _ctxmgr
-import DLFCN as _dlfcn
+try: import DLFCN as _dlfcn
+except ImportError: _dlfcn = None
 import os as _os
 from struct import pack as _pack
 import sys as _sys
@@ -67,6 +68,15 @@ del _dlflags, _odlflags
 ## 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
+
 ## How to fix a name back into the right identifier.  Alas, the rules are not
 ## consistent.
 def _fixname(name):
@@ -75,7 +85,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.
@@ -89,19 +99,6 @@ def _init():
   for i in b:
     if i[0] != '_':
       d[i] = b[i];
-  for i in ['ByteString',
-            '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, gcaeads, gchashes, gcmacs, gcprps]:
     for c in i.itervalues():
       d[_fixname(c.name)] = c
@@ -217,15 +214,31 @@ _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))
-  def hashu16b(me, n): return me.hash(_pack('>H', n))
+  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))
+  def hashu16b(me, n):
+    me._check_range(n, 0xffff)
+    return me.hash(_pack('>H', n))
   hashu16 = hashu16b
-  def hashu32l(me, n): return me.hash(_pack('<L', n))
-  def hashu32b(me, n): return me.hash(_pack('>L', n))
+  def hashu32l(me, n):
+    me._check_range(n, 0xffffffff)
+    return me.hash(_pack('<L', n))
+  def hashu32b(me, n):
+    me._check_range(n, 0xffffffff)
+    return me.hash(_pack('>L', n))
   hashu32 = hashu32b
-  def hashu64l(me, n): return me.hash(_pack('<Q', n))
-  def hashu64b(me, n): return me.hash(_pack('>Q', n))
+  def hashu64l(me, n):
+    me._check_range(n, 0xffffffffffffffff)
+    return me.hash(_pack('<Q', n))
+  def hashu64b(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)
@@ -248,8 +261,8 @@ class _ShakeBase (_HashBase):
     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 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)
@@ -262,6 +275,8 @@ class _ShakeBase (_HashBase):
   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):
@@ -300,6 +315,8 @@ class KMAC (_ShakeBase):
   def xof(me):
     me.rightenc(0)
     return super(KMAC, me).xof()
+  @classmethod
+  def _bare_new(cls): return cls("")
 
 class KMAC128 (KMAC): _SHAKE = Shake128; _TAGSZ = 16
 class KMAC256 (KMAC): _SHAKE = Shake256; _TAGSZ = 32
@@ -353,15 +370,18 @@ 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)
+  __div__ = __truediv__
+  __rdiv__ = __rtruediv__
   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)
@@ -381,8 +401,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)
 
@@ -393,8 +415,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)
 
@@ -586,7 +610,7 @@ class _tmp:
   def pad(me, sz):
     if sz > me.max: raise ValueError, 'key too large'
     elif sz < me.min: return me.min
-    else: sz += me.mod; return sz - sz%me.mod
+    else: sz += me.mod - 1; return sz - sz%me.mod
 _augment(KeySZRange, _tmp)
 
 class _tmp:
@@ -978,14 +1002,9 @@ class Ed448Priv (_EdDSAPriv, Ed448Pub):
     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()])
   def _repr_pretty_(me, pp, cyclep):
@@ -993,36 +1012,7 @@ class _groupmap (object):
     if cyclep: pp.text('...')
     else: _pp_dict(pp, me.iteritems())
     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.