chiark / gitweb /
Merge branch '1.1.x'
authorMark Wooding <mdw@distorted.org.uk>
Sun, 14 May 2017 03:28:02 +0000 (04:28 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 14 May 2017 03:28:02 +0000 (04:28 +0100)
* 1.1.x:
  Release 1.1.2.
  catacomb/__init__.py: Fix up cipher etc. names better.
  algorithms.c: Support the new 16-bit key-size descriptors.
  group.c: Track Catacomb group internals change.
  utils.c: Raise exceptions from `convTHING' with null arguments.
  Return `long' objects when `int' is requested but the value won't fit.
  bytestring.c: Check for cached hash more carefully.
  rand.c: Careful range checking on `block' and `mp'.
  *.c: Fix docstrings for methods.
  Further fixing to use `Py_ssize_t' in place of int.

Conflicts:
debian/control (already wanted later catacomb-dev)
group.c (no need for compatibility with older Catacombs)

17 files changed:
algorithms.c
algorithms.py
buffer.c
bytestring.c
catacomb-python.h
catacomb.c
catacomb/__init__.py
debian/control
ec.c
group.c
key.c
mp.c
pubkey.c
rand.c
setup.py
share.c
util.c

index 3a618d02a49308eea449b95e6708f83cd6006962..5703901fae129b68ea01e366884c6cbe94ff8e63 100644 (file)
@@ -473,7 +473,7 @@ static PyObject *gcipher_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   char *kwlist[] = { "k", 0 };
   char *k;
-  int sz;
+  Py_ssize_t sz;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
     goto end;
@@ -522,7 +522,7 @@ static PyObject *gccget_blksz(PyObject *me, void *hunoz)
 static PyObject *gcmeth_encrypt(PyObject *me, PyObject *arg)
 {
   char *p;
-  int sz;
+  Py_ssize_t sz;
   PyObject *rc = 0;
 
   if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &sz)) return (0);
@@ -548,7 +548,7 @@ static PyObject *gcmeth_enczero(PyObject *me, PyObject *arg)
 static PyObject *gcmeth_decrypt(PyObject *me, PyObject *arg)
 {
   char *p;
-  int sz;
+  Py_ssize_t sz;
   PyObject *rc = 0;
 
   if (!PyArg_ParseTuple(arg, "s#:decrypt", &p, &sz)) return (0);
@@ -574,9 +574,10 @@ static PyObject *gcmeth_deczero(PyObject *me, PyObject *arg)
 static PyObject *gcmeth_setiv(PyObject *me, PyObject *arg)
 {
   char *p;
-  int sz;
+  Py_ssize_t sz;
 
   if (!PyArg_ParseTuple(arg, "s#:setiv", &p, &sz)) goto end;
+  if (!GCIPHER_C(me)->ops->setiv) VALERR("`setiv' not supported");
   if (!GC_CLASS(GCIPHER_C(me))->blksz) VALERR("not a block cipher mode");
   if (sz != GC_CLASS(GCIPHER_C(me))->blksz) VALERR("bad IV length");
   GC_SETIV(GCIPHER_C(me), p);
@@ -588,6 +589,7 @@ end:
 static PyObject *gcmeth_bdry(PyObject *me, PyObject *arg)
 {
   if (!PyArg_ParseTuple(arg, ":bdry")) goto end;
+  if (!GCIPHER_C(me)->ops->bdry) VALERR("`bdry' not supported");
   if (!GC_CLASS(GCIPHER_C(me))->blksz) VALERR("not a block cipher mode");
   GC_BDRY(GCIPHER_C(me));
   RETURN_ME;
@@ -777,33 +779,12 @@ static PyObject *gchget_bufsz(PyObject *me, void *hunoz)
 static PyObject *ghmeth_hash(PyObject *me, PyObject *arg)
 {
   char *p;
-  int sz;
+  Py_ssize_t sz;
   if (!PyArg_ParseTuple(arg, "s#:hash", &p, &sz)) return (0);
   GH_HASH(GHASH_H(me), p, sz);
   RETURN_ME;
 }
 
-static PyObject *ghmeth_done(PyObject *me, PyObject *arg)
-{
-  ghash *g;
-  PyObject *rc;
-  if (!PyArg_ParseTuple(arg, ":done")) return (0);
-  g = GH_COPY(GHASH_H(me));
-  rc = bytestring_pywrap(0, g->ops->c->hashsz);
-  GH_DONE(g, PyString_AS_STRING(rc));
-  GH_DESTROY(g);
-  return (rc);
-}
-
-static PyGetSetDef gchash_pygetset[] = {
-#define GETSETNAME(op, name) gch##op##_##name
-  GET  (bufsz,                 "CH.bufsz -> hash buffer size, or zero")
-  GET  (hashsz,                "CH.blksz -> hash output size")
-  GET  (name,                  "CH.name -> name of this kind of hash")
-#undef GETSETNAME
-  { 0 }
-};
-
 #define GHMETH_HASHU_(n, W, w)                                         \
   static PyObject *ghmeth_hashu##w(PyObject *me, PyObject *arg)                \
   {                                                                    \
@@ -820,7 +801,7 @@ DOUINTCONV(GHMETH_HASHU_)
   static PyObject *ghmeth_hashbuf##w(PyObject *me, PyObject *arg)      \
   {                                                                    \
     char *p;                                                           \
-    int sz;                                                            \
+    Py_ssize_t sz;                                                     \
     if (!PyArg_ParseTuple(arg, "s#:hashbuf" #w, &p, &sz)) goto end;    \
     if (sz > MASK##n) TYERR("string too long");                                \
     GH_HASHBUF##W(GHASH_H(me), p, sz);                                 \
@@ -838,13 +819,36 @@ static PyObject *ghmeth_hashstrz(PyObject *me, PyObject *arg)
   RETURN_ME;
 }
 
+static PyObject *ghmeth_done(PyObject *me, PyObject *arg)
+{
+  ghash *g;
+  PyObject *rc;
+  if (!PyArg_ParseTuple(arg, ":done")) return (0);
+  g = GH_COPY(GHASH_H(me));
+  rc = bytestring_pywrap(0, g->ops->c->hashsz);
+  GH_DONE(g, PyString_AS_STRING(rc));
+  GH_DESTROY(g);
+  return (rc);
+}
+
+static PyGetSetDef gchash_pygetset[] = {
+#define GETSETNAME(op, name) gch##op##_##name
+  GET  (bufsz,                 "CH.bufsz -> hash buffer size, or zero")
+  GET  (hashsz,                "CH.hashsz -> hash output size")
+  GET  (name,                  "CH.name -> name of this kind of hash")
+#undef GETSETNAME
+  { 0 }
+};
+
 static PyMethodDef ghash_pymethods[] = {
 #define METHNAME(name) ghmeth_##name
   METH (hash,                  "H.hash(M)")
 #define METHU_(n, W, w) METH(hashu##w, "H.hashu" #w "(WORD)")
   DOUINTCONV(METHU_)
+#undef METHU_
 #define METHBUF_(n, W, w) METH(hashbuf##w, "H.hashbuf" #w "(BYTES)")
   DOUINTCONV(METHBUF_)
+#undef METHBUF_
   METH (hashstrz,              "H.hashstrz(STRING)")
   METH (done,                  "H.done() -> HASH")
 #undef METHNAME
@@ -959,7 +963,7 @@ static PyObject *gmac_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   char *kwlist[] = { "k", 0 };
   char *k;
-  int sz;
+  Py_ssize_t sz;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
     goto end;
@@ -1007,6 +1011,7 @@ PyObject *gmac_pywrap(PyObject *cobj, gmac *m, unsigned f)
   if (!cobj) cobj = gcmac_pywrap((/*unconst*/ gcmac *)GM_CLASS(m));
   else Py_INCREF(cobj);
   g = newtype((PyTypeObject *)cobj, 0, 0);
+  g->ty.ht_type.tp_basicsize = sizeof(ghash_pyobj);
   g->ty.ht_name = PyString_FromFormat("%s(keyed)", m->ops->c->name);
   g->ty.ht_type.tp_name = PyString_AS_STRING(g->ty.ht_name);
   g->ty.ht_type.tp_base = gmhash_pytype;
@@ -1193,6 +1198,394 @@ static PyTypeObject gmhash_pytype_skel = {
   0                                    /* @tp_is_gc@ */
 };
 
+/*----- Special snowflake for Poly1305 ------------------------------------*/
+
+PyTypeObject *poly1305cls_pytype, *poly1305key_pytype, *poly1305hash_pytype;
+
+typedef struct poly1305key_pyobj {
+  PyHeapTypeObject ty;
+  poly1305_key k;
+} poly1305key_pyobj;
+
+typedef struct poly1305hash_pyobj {
+  PyObject_HEAD
+  unsigned f;
+#define f_mask 1u
+  poly1305_ctx ctx;
+} poly1305hash_pyobj;
+
+#define P1305_F(o) (((poly1305hash_pyobj *)(o))->f)
+#define P1305_CTX(o) (&((poly1305hash_pyobj *)(o))->ctx)
+CONVFUNC(poly1305hash, poly1305_ctx *, P1305_CTX)
+
+static PyObject *poly1305hash_pynew(PyTypeObject *ty,
+                                   PyObject *arg, PyObject *kw)
+{
+  char *kwlist[] = { "mask", 0 };
+  poly1305key_pyobj *pk = (poly1305key_pyobj *)ty;
+  poly1305hash_pyobj *ph;
+  char *m = 0;
+  Py_ssize_t sz;
+
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#:new", kwlist, &m, &sz))
+    return (0);
+  if (m && sz != POLY1305_MASKSZ) VALERR("bad mask length");
+  ph = PyObject_NEW(poly1305hash_pyobj, ty);
+  ph->f = 0;
+  if (m) ph->f |= f_mask;
+  poly1305_macinit(&ph->ctx, &pk->k, m);
+  Py_INCREF(ty);
+  return ((PyObject *)ph);
+end:
+  return (0);
+}
+
+static PyObject *poly1305key_pynew(PyTypeObject *ty,
+                                  PyObject *arg, PyObject *kw)
+{
+  char *kwlist[] = { "k", 0 };
+  poly1305key_pyobj *pk;
+  char *k;
+  Py_ssize_t sz;
+
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
+    goto end;
+  if (keysz(sz, poly1305_keysz) != sz) VALERR("bad key length");
+
+  pk = newtype(ty, 0, 0);
+  pk->ty.ht_name = PyString_FromString("poly1305(keyed)");
+  pk->ty.ht_type.tp_basicsize = sizeof(poly1305hash_pyobj);
+  pk->ty.ht_type.tp_name = PyString_AS_STRING(pk->ty.ht_name);
+  pk->ty.ht_type.tp_base = poly1305hash_pytype;
+  Py_INCREF(poly1305key_pytype);
+  pk->ty.ht_type.tp_flags = (Py_TPFLAGS_DEFAULT |
+                            Py_TPFLAGS_BASETYPE |
+                            Py_TPFLAGS_HEAPTYPE);
+  pk->ty.ht_type.tp_alloc = PyType_GenericAlloc;
+  pk->ty.ht_type.tp_free = 0;
+  pk->ty.ht_type.tp_new = poly1305hash_pynew;
+  typeready(&pk->ty.ht_type);
+
+  poly1305_keyinit(&pk->k, k, sz);
+  return ((PyObject *)pk);
+
+end:
+  return (0);
+}
+
+static PyObject *poly1305clsget_name(PyObject *me, void *hunoz)
+  { return (PyString_FromString("poly1305")); }
+
+static PyObject *poly1305clsget_keysz(PyObject *me, void *hunoz)
+  { return (keysz_pywrap(poly1305_keysz)); }
+
+static PyObject *poly1305clsget_masksz(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(POLY1305_MASKSZ)); }
+
+static PyObject *poly1305clsget_tagsz(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(POLY1305_TAGSZ)); }
+
+static PyObject *polymeth_copy(PyObject *me, PyObject *arg)
+{
+  poly1305hash_pyobj *ph;
+  if (!PyArg_ParseTuple(arg, ":copy")) return (0);
+  ph = PyObject_NEW(poly1305hash_pyobj, me->ob_type);
+  poly1305_copy(&ph->ctx, P1305_CTX(me));
+  Py_INCREF(me->ob_type);
+  return ((PyObject *)ph);
+}
+
+static PyObject *polymeth_hash(PyObject *me, PyObject *arg)
+{
+  char *p;
+  Py_ssize_t sz;
+  if (!PyArg_ParseTuple(arg, "s#:hash", &p, &sz)) return (0);
+  poly1305_hash(P1305_CTX(me), p, sz);
+  RETURN_ME;
+}
+
+#define POLYMETH_HASHU_(n, W, w)                                       \
+  static PyObject *polymeth_hashu##w(PyObject *me, PyObject *arg)      \
+  {                                                                    \
+    uint##n x;                                                         \
+    octet b[SZ_##W];                                                   \
+    if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) goto end; \
+    STORE##W(b, x); poly1305_hash(P1305_CTX(me), b, sizeof(b));                \
+    RETURN_ME;                                                         \
+  end:                                                                 \
+    return (0);                                                                \
+  }
+DOUINTCONV(POLYMETH_HASHU_)
+
+#define POLYMETH_HASHBUF_(n, W, w)                                     \
+  static PyObject *polymeth_hashbuf##w(PyObject *me, PyObject *arg)    \
+  {                                                                    \
+    char *p;                                                           \
+    Py_ssize_t sz;                                                     \
+    octet b[SZ_##W];                                                   \
+    if (!PyArg_ParseTuple(arg, "s#:hashbuf" #w, &p, &sz)) goto end;    \
+    if (sz > MASK##n) TYERR("string too long");                                \
+    STORE##W(b, sz); poly1305_hash(P1305_CTX(me), b, sizeof(b));       \
+    poly1305_hash(P1305_CTX(me), p, sz);                               \
+    RETURN_ME;                                                         \
+  end:                                                                 \
+    return (0);                                                                \
+  }
+DOUINTCONV(POLYMETH_HASHBUF_)
+
+static PyObject *polymeth_hashstrz(PyObject *me, PyObject *arg)
+{
+  char *p;
+  if (!PyArg_ParseTuple(arg, "s:hashstrz", &p)) return (0);
+  poly1305_hash(P1305_CTX(me), p, strlen(p) + 1);
+  RETURN_ME;
+}
+
+static PyObject *polymeth_flush(PyObject *me, PyObject *arg)
+{
+  if (!PyArg_ParseTuple(arg, ":flush")) return (0);
+  poly1305_flush(P1305_CTX(me));
+  RETURN_ME;
+}
+
+static PyObject *polymeth_flushzero(PyObject *me, PyObject *arg)
+{
+  if (!PyArg_ParseTuple(arg, ":flushzero")) return (0);
+  poly1305_flushzero(P1305_CTX(me));
+  RETURN_ME;
+}
+
+static PyObject *polymeth_concat(PyObject *me, PyObject *arg)
+{
+  PyObject *pre, *suff;
+  if (!PyArg_ParseTuple(arg, "OO:concat", &pre, &suff)) return (0);
+  if (!PyObject_TypeCheck(pre, poly1305hash_pytype) ||
+      !PyObject_TypeCheck(suff, poly1305hash_pytype))
+    TYERR("wanted a poly1305hash");
+  if (me->ob_type != pre->ob_type || me->ob_type != suff->ob_type)
+    TYERR("key mismatch");
+  if (P1305_CTX(pre)->nbuf) VALERR("prefix is not block-aligned");
+  poly1305_concat(P1305_CTX(me), P1305_CTX(pre), P1305_CTX(suff));
+  RETURN_ME;
+end:
+  return (0);
+}
+
+static PyObject *polymeth_done(PyObject *me, PyObject *arg)
+{
+  PyObject *rc;
+  if (!PyArg_ParseTuple(arg, ":done")) return (0);
+  if (!(P1305_F(me) & f_mask)) VALERR("no mask");
+  rc = bytestring_pywrap(0, POLY1305_TAGSZ);
+  poly1305_done(P1305_CTX(me), PyString_AS_STRING(rc));
+  return (rc);
+end:
+  return (0);
+}
+
+static PyGetSetDef poly1305cls_pygetset[] = {
+#define GETSETNAME(op, name) poly1305cls##op##_##name
+  GET  (keysz,                 "PC.keysz -> acceptable key sizes")
+  GET  (masksz,                "PC.masksz -> mask size")
+  GET  (tagsz,                 "PC.tagsz -> MAC output size")
+  GET  (name,                  "PC.name -> name of this kind of MAC")
+#undef GETSETNAME
+  { 0 }
+};
+
+static PyMethodDef poly1305hash_pymethods[] = {
+#define METHNAME(name) polymeth_##name
+  METH  (copy,                 "P.copy() -> PP")
+  METH (hash,                  "P.hash(M)")
+#define METHU_(n, W, w) METH(hashu##w, "P.hashu" #w "(WORD)")
+  DOUINTCONV(METHU_)
+#undef METHU_
+#define METHBUF_(n, W, w) METH(hashbuf##w, "P.hashbuf" #w "(BYTES)")
+  DOUINTCONV(METHBUF_)
+#undef METHBUF_
+  METH (hashstrz,              "P.hashstrz(STRING)")
+  METH  (flush,                        "P.flush()")
+  METH  (flushzero,            "P.flushzero()")
+  METH  (concat,               "P.concat(PREFIX, SUFFIX)")
+  METH (done,                  "P.done() -> TAG")
+#undef METHNAME
+  { 0 }
+};
+
+static PyTypeObject poly1305cls_pytype_skel = {
+  PyObject_HEAD_INIT(0) 0,             /* Header */
+  "Poly1305Class",                     /* @tp_name@ */
+  sizeof(PyHeapTypeObject),            /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  0,                                   /* @tp_dealloc@ */
+  0,                                   /* @tp_print@ */
+  0,                                   /* @tp_getattr@ */
+  0,                                   /* @tp_setattr@ */
+  0,                                   /* @tp_compare@ */
+  0,                                   /* @tp_repr@ */
+  0,                                   /* @tp_as_number@ */
+  0,                                   /* @tp_as_sequence@ */
+  0,                                   /* @tp_as_mapping@ */
+  0,                                   /* @tp_hash@ */
+  0,                                   /* @tp_call@ */
+  0,                                   /* @tp_str@ */
+  0,                                   /* @tp_getattro@ */
+  0,                                   /* @tp_setattro@ */
+  0,                                   /* @tp_as_buffer@ */
+  Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
+    Py_TPFLAGS_BASETYPE,
+
+  /* @tp_doc@ */
+"Poly1305 metametaclass.  Best not to ask.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternext@ */
+  0,                                   /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  poly1305cls_pygetset,                        /* @tp_getset@ */
+  0,                                   /* @tp_base@ */
+  0,                                   /* @tp_dict@ */
+  0,                                   /* @tp_descr_get@ */
+  0,                                   /* @tp_descr_set@ */
+  0,                                   /* @tp_dictoffset@ */
+  0,                                   /* @tp_init@ */
+  PyType_GenericAlloc,                 /* @tp_alloc@ */
+  abstract_pynew,                      /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+static PyTypeObject poly1305key_pytype_skel = {
+  PyObject_HEAD_INIT(0) 0,             /* Header */
+  "poly1305",                          /* @tp_name@ */
+  sizeof(poly1305key_pyobj),           /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  0,                                   /* @tp_dealloc@ */
+  0,                                   /* @tp_print@ */
+  0,                                   /* @tp_getattr@ */
+  0,                                   /* @tp_setattr@ */
+  0,                                   /* @tp_compare@ */
+  0,                                   /* @tp_repr@ */
+  0,                                   /* @tp_as_number@ */
+  0,                                   /* @tp_as_sequence@ */
+  0,                                   /* @tp_as_mapping@ */
+  0,                                   /* @tp_hash@ */
+  0,                                   /* @tp_call@ */
+  0,                                   /* @tp_str@ */
+  0,                                   /* @tp_getattro@ */
+  0,                                   /* @tp_setattro@ */
+  0,                                   /* @tp_as_buffer@ */
+  Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
+    Py_TPFLAGS_BASETYPE,
+
+  /* @tp_doc@ */
+"Poly1305 key.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternext@ */
+  0,                                   /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  0,                                   /* @tp_getset@ */
+  0,                                   /* @tp_base@ */
+  0,                                   /* @tp_dict@ */
+  0,                                   /* @tp_descr_get@ */
+  0,                                   /* @tp_descr_set@ */
+  0,                                   /* @tp_dictoffset@ */
+  0,                                   /* @tp_init@ */
+  PyType_GenericAlloc,                 /* @tp_alloc@ */
+  poly1305key_pynew,                   /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+static PyTypeObject poly1305hash_pytype_skel = {
+  PyObject_HEAD_INIT(0) 0,             /* Header */
+  "Poly1305Hash",                      /* @tp_name@ */
+  sizeof(poly1305hash_pyobj),          /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  0,                                   /* @tp_dealloc@ */
+  0,                                   /* @tp_print@ */
+  0,                                   /* @tp_getattr@ */
+  0,                                   /* @tp_setattr@ */
+  0,                                   /* @tp_compare@ */
+  0,                                   /* @tp_repr@ */
+  0,                                   /* @tp_as_number@ */
+  0,                                   /* @tp_as_sequence@ */
+  0,                                   /* @tp_as_mapping@ */
+  0,                                   /* @tp_hash@ */
+  0,                                   /* @tp_call@ */
+  0,                                   /* @tp_str@ */
+  0,                                   /* @tp_getattro@ */
+  0,                                   /* @tp_setattro@ */
+  0,                                   /* @tp_as_buffer@ */
+  Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
+    Py_TPFLAGS_BASETYPE,
+
+  /* @tp_doc@ */
+"Poly1305 MAC context base class.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternext@ */
+  poly1305hash_pymethods,              /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  0,                                   /* @tp_getset@ */
+  0,                                   /* @tp_base@ */
+  0,                                   /* @tp_dict@ */
+  0,                                   /* @tp_descr_get@ */
+  0,                                   /* @tp_descr_set@ */
+  0,                                   /* @tp_dictoffset@ */
+  0,                                   /* @tp_init@ */
+  PyType_GenericAlloc,                 /* @tp_alloc@ */
+  abstract_pynew,                      /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+/*----- Special snowflake for HSalsa and HChaCha --------------------------*/
+
+#define DEF_HDANCE(DANCE, HDANCE, dance, hdance)                       \
+  static PyObject *meth_##hdance##_prf(PyObject *me, PyObject *arg)    \
+  {                                                                    \
+    dance##_ctx dance;                                                 \
+    char *k, *n;                                                       \
+    Py_ssize_t ksz, nsz;                                               \
+    PyObject *rc;                                                      \
+    if (!PyArg_ParseTuple(arg, "s#s#:" #hdance "_prf",                 \
+                         &k, &ksz, &n, &nsz))                          \
+      goto end;                                                                \
+    if (ksz != DANCE##_KEYSZ) VALERR("bad key length");                        \
+    if (nsz != HDANCE##_INSZ) VALERR("bad input length");              \
+    rc = bytestring_pywrap(0, HSALSA20_OUTSZ);                         \
+    dance##_init(&dance, k, ksz, 0);                                   \
+    hdance##_prf(&dance, n, PyString_AS_STRING(rc));                   \
+    return (rc);                                                       \
+  end:                                                                 \
+    return (0);                                                                \
+  }
+
+DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa20)
+DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa2012)
+DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa208)
+
+DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha20)
+DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha12)
+DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha8)
+
 /*----- Pseudorandom permutations -----------------------------------------*/
 
 static PyTypeObject *gcprp_pytype, *gprp_pytype;
@@ -1254,7 +1647,7 @@ static PyObject *gprp_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   char *kwlist[] = { "key", 0 };
   char *k;
-  int sz;
+  Py_ssize_t sz;
   const prpinfo *prp = GCPRP_PRP(ty);
   PyObject *me;
 
@@ -1300,7 +1693,7 @@ static PyObject *gcpget_blksz(PyObject *me, void *hunoz)
 static PyObject *gpmeth_encrypt(PyObject *me, PyObject *arg)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   PyObject *rc = 0;
 
   if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &n)) goto end;
@@ -1314,7 +1707,7 @@ end:
 static PyObject *gpmeth_decrypt(PyObject *me, PyObject *arg)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   PyObject *rc = 0;
 
   if (!PyArg_ParseTuple(arg, "s#:decrypt", &p, &n)) goto end;
@@ -1458,6 +1851,17 @@ toschnorr(N) -> M: convert work factor to Schnorr group order")
 toif(N) -> M: convert work factor to integer factorization problem size")
   METH (_KeySZ_toec,           "\
 toec(N) -> M: convert work factor to elliptic curve group order")
+  METH (_KeySZ_toec,           "\
+toec(N) -> M: convert work factor to elliptic curve group order")
+#define METH_HDANCE(hdance, HDance) METH(hdance##_prf, "\
+" #hdance "_prf(K, N) -> H: calculate " HDance " hash of N with K")
+  METH_HDANCE(hsalsa20, "HSalsa20")
+  METH_HDANCE(hsalsa2012, "HSalsa20/12")
+  METH_HDANCE(hsalsa208, "HSalsa20/8")
+  METH_HDANCE(hchacha20, "HChaCha20")
+  METH_HDANCE(hchacha12, "HChaCha12")
+  METH_HDANCE(hchacha8, "HChaCha8")
+#undef METH_DANCE
 #undef METHNAME
   { 0 }
 };
@@ -1475,6 +1879,9 @@ void algorithms_pyinit(void)
   INITTYPE(gcmac, type);
   INITTYPE(gmac, type);
   INITTYPE(gmhash, ghash);
+  INITTYPE(poly1305cls, type);
+  INITTYPE_META(poly1305key, type, poly1305cls);
+  INITTYPE(poly1305hash, root);
   INITTYPE(gcprp, type);
   INITTYPE(gprp, root);
   addmethods(methods);
@@ -1505,6 +1912,9 @@ void algorithms_pyinsert(PyObject *mod)
   INSERT("GMAC", gmac_pytype);
   INSERT("GMACHash", gmhash_pytype);
   INSERT("gcmacs", gcmacs());
+  INSERT("Poly1305Class", poly1305cls_pytype);
+  INSERT("poly1305", poly1305key_pytype);
+  INSERT("Poly1305Hash", poly1305hash_pytype);
   INSERT("GCPRP", gcprp_pytype);
   INSERT("GPRP", gprp_pytype);
   INSERT("gcprps", gcprps());
index 3ceb207b175fd4de8d7ab3c5c1401b5c790101a1..a2a468f46bf613fa8207079e0b6f63e19967e523 100644 (file)
@@ -30,8 +30,12 @@ streamciphers = '''
 rc4 seal
 '''.split()
 latindances = '''
-salsa20 salsa20/12 salsa20/8 xsalsa20 xsalsa20/12 xsalsa20/8
-chacha20 chacha12 chacha8 xchacha20 xchacha12 xchacha8
+salsa20 salsa20/12 salsa20/8
+salsa20-ietf salsa20/12-ietf salsa20/8-ietf
+xsalsa20 xsalsa20/12 xsalsa20/8
+chacha20 chacha12 chacha8
+chacha20-ietf chacha12-ietf chacha8-ietf
+xchacha20 xchacha12 xchacha8
 '''.split()
 streamciphers += map(lambda s: s.translate(None, '/'), latindances)
 hashes = '''
@@ -84,9 +88,10 @@ for i in latindances:
       break
   else:
     raise ValueError, 'failed to find root name for %s' % i
+  if i.endswith('-ietf'): root += '_ietf'
   print ('\t_("%(name)s", %(root)s_keysz, %(id)s_rand, ' +
-         'RNGF_NONCE, %(ROOT)s_NONCESZ) \\') % \
-      {'name': i, 'id': i.translate(None, '/'),
+         'RNGF_NONCE | RNGF_LATIN, %(ROOT)s_NONCESZ) \\') % \
+      {'name': i, 'id': i.translate(None, '/').replace('-', '_'),
        'root': root, 'ROOT': root.upper()}
 print '\t/* end */'
 print
index 65695162e814f3b13cc31e129f1a9853945b0521..43bf02de7647989b3d91b5fd48d47dc2d3b8ab5a 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -53,7 +53,7 @@ static PyObject *buferr;
 static PyObject *rbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   char *p, *q;
-  int n;
+  Py_ssize_t n;
   buf_pyobj *me = 0;
   static char *kwlist[] = { "data", 0 };
 
@@ -387,7 +387,7 @@ static PyObject *wbmeth_zero(PyObject *me, PyObject *arg)
 static PyObject *wbmeth_put(PyObject *me, PyObject *arg)
 {
   void *p;
-  int n;
+  Py_ssize_t n;
   if (!PyArg_ParseTuple(arg, "s#:put", &p, &n)) return (0);
   ensure(me, n);
   buf_put(BUF_B(me), p, n); assert(BOK(BUF_B(m)));
@@ -410,7 +410,7 @@ DOUINTCONV(WBMETH_PUTU_)
   static PyObject *wbmeth_putblk##w(PyObject *me, PyObject *arg)       \
   {                                                                    \
     char *p;                                                           \
-    int sz;                                                            \
+    Py_ssize_t sz;                                                     \
     if (!PyArg_ParseTuple(arg, "s#:putblk" #w, &p, &sz)) return (0);   \
     ensure(me, sz + SZ_##n);                                           \
     buf_putmem##w(BUF_B(me), p, sz); assert(BOK(BUF_B(me)));           \
index 4a7378da218e2315ec4d99b246750754c7217011..4abb260cabd6e72196d63be90b500ba50884af40 100644 (file)
@@ -54,13 +54,59 @@ static PyObject *bytestring_pynew(PyTypeObject *ty,
                                  PyObject *arg, PyObject *kw)
 {
   const char *p;
-  int n;
+  Py_ssize_t n;
   static char *kwlist[] = { "data", 0 };
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &n))
     return (0);
   return (dowrap(ty, p, n));
 }
 
+static PyObject *meth_ctstreq(PyObject *me, PyObject *args)
+{
+  char *p, *q;
+  Py_ssize_t psz, qsz;
+  if (!PyArg_ParseTuple(args, "s#s#:ctstreq", &p, &psz, &q, &qsz))
+    goto end;
+  if (psz == qsz && ct_memeq(p, q, psz)) RETURN_TRUE;
+  else RETURN_FALSE;
+end:
+  return (0);
+}
+
+static PyObject *bytestring_pyrichcompare(PyObject *me,
+                                         PyObject *you, int op)
+{
+  int b;
+  void *mystr, *yourstr;
+  Py_ssize_t mylen, yourlen, minlen;
+
+  if (!PyString_Check(me) || !PyString_Check(you)) RETURN_NOTIMPL;
+  mystr = PyString_AS_STRING(me); mylen = PyString_GET_SIZE(me);
+  yourstr = PyString_AS_STRING(you); yourlen = PyString_GET_SIZE(you);
+
+  switch (op) {
+    case Py_EQ:
+      b = mylen == yourlen && ct_memeq(mystr, yourstr, mylen);
+      break;
+    case Py_NE:
+      b = mylen != yourlen || !ct_memeq(mystr, yourstr, mylen);
+      break;
+    default:
+      minlen = mylen < yourlen ? mylen : yourlen;
+      b = memcmp(mystr, yourstr, minlen);
+      if (!b) b = mylen < yourlen ? -1 : mylen > yourlen ? +1 : 0;
+      switch (op) {
+       case Py_LT: b = b <  0; break;
+       case Py_LE: b = b <= 0; break;
+       case Py_GE: b = b >= 0; break;
+       case Py_GT: b = b >  0; break;
+       default: abort();
+      }
+  }
+  if (b) RETURN_TRUE;
+  else RETURN_FALSE;
+}
+
 #define BINOP(name, op)                                                        \
   static PyObject *bytestring_py##name(PyObject *x, PyObject *y) {     \
     const void *xv, *yv;                                               \
@@ -158,7 +204,7 @@ static PyTypeObject bytestring_pytype_skel = {
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
-  0,                                   /* @tp_richcompare@ */
+  bytestring_pyrichcompare,            /* @tp_richcompare@ */
   0,                                   /* @tp_weaklistoffset@ */
   0,                                   /* @tp_iter@ */
   0,                                   /* @tp_iternext@ */
@@ -179,10 +225,18 @@ static PyTypeObject bytestring_pytype_skel = {
 
 /*----- Initialization ----------------------------------------------------*/
 
+static PyMethodDef methods[] = {
+#define METHNAME(func) meth_##func
+  METH  (ctstreq,              "ctstreq(S, T) -> BOOL")
+#undef METHNAME
+  { 0 }
+};
+
 #define string_pytype &PyString_Type
 void bytestring_pyinit(void)
 {
   INITTYPE(bytestring, string);
+  addmethods(methods);
 }
 
 void bytestring_pyinsert(PyObject *mod)
index bed97d548c0e54f63acfcd7113c5efd8ee15c7f8..d7e254355dfb79fcd42dca3caaba556b9a883a85 100644 (file)
 
 /*----- Header files ------------------------------------------------------*/
 
+#define PY_SSIZE_T_CLEAN
+
 #include <Python.h>
 #include <longintrepr.h>
 #include <structmember.h>
 
-#undef ULLONG_MAX
-#undef ULONG_LONG_MAX
-
 #include <mLib/darray.h>
 #include <mLib/dstr.h>
 #include <mLib/macros.h>
@@ -47,6 +46,7 @@
 #include <mLib/unihash.h>
 
 #include <catacomb/buf.h>
+#include <catacomb/ct.h>
 
 #include <catacomb/grand.h>
 #include <catacomb/rand.h>
@@ -65,6 +65,7 @@
 #include <catacomb/gmac.h>
 #include <catacomb/md5.h>
 #include <catacomb/md5-hmac.h>
+#include <catacomb/poly1305.h>
 #include <catacomb/sha.h>
 #include <catacomb/sha-mgf.h>
 #include <catacomb/sha-hmac.h>
@@ -86,6 +87,9 @@
 #include <catacomb/ptab.h>
 #include <catacomb/bintab.h>
 #include <catacomb/dsa.h>
+#include <catacomb/x25519.h>
+#include <catacomb/x448.h>
+#include <catacomb/ed25519.h>
 
 #include <catacomb/gf.h>
 #include <catacomb/gfreduce.h>
 
 #define root_pytype 0
 #define type_pytype &PyType_Type
-#define INITTYPE(ty, base) do {                                                \
+#define INITTYPE_META(ty, base, meta) do {                             \
   ty##_pytype_skel.tp_base = base##_pytype;                            \
-  ty##_pytype = inittype(&ty##_pytype_skel);                           \
+  ty##_pytype = inittype(&ty##_pytype_skel, meta##_pytype);            \
 } while (0)
+#define INITTYPE(ty, base) INITTYPE_META(ty, base, type)
 
 #define INSERT(name, ob) do {                                          \
   PyObject *_o = (PyObject *)(ob);                                     \
@@ -238,16 +243,18 @@ extern int convulong(PyObject *, void *);
 DOUINTSZ(DECL_CONVU_)
 extern int convmpw(PyObject *, void *);
 extern int convuint(PyObject *, void *);
+extern int convk64(PyObject *, void *);
 extern int convszt(PyObject *, void *);
 extern int convbool(PyObject *, void *);
 extern PyObject *abstract_pynew(PyTypeObject *, PyObject *, PyObject *);
 extern PyObject *getbool(int);
 extern PyObject *getulong(unsigned long);
+extern PyObject *getk64(kludge64);
 extern void *newtype(PyTypeObject *, const PyTypeObject *, const char *);
 
 extern PyObject *mkexc(PyObject *, PyObject *, const char *, PyMethodDef *);
 extern void typeready(PyTypeObject *);
-extern PyTypeObject *inittype(PyTypeObject *);
+extern PyTypeObject *inittype(PyTypeObject *, PyTypeObject *);
 extern void addmethods(const PyMethodDef *);
 extern PyMethodDef *donemethods(void);
 
index 49d0f4001be6285b48b91ffc9e5bdaeebae9f17a..9c83c9dbe29877bd1b7654123f4362122ee9da36 100644 (file)
@@ -45,6 +45,9 @@ static const struct nameval consts[] = {
   C(KF_NONSECRET),
   C(KF_BURN), C(KF_OPT),
   C(EC_XONLY), C(EC_YBIT), C(EC_LSB), C(EC_CMPR), C(EC_EXPLY), C(EC_SORT),
+  C(X25519_KEYSZ), C(X25519_PUBSZ), C(X25519_OUTSZ),
+  C(X448_KEYSZ), C(X448_PUBSZ), C(X448_OUTSZ),
+  C(ED25519_KEYSZ), C(ED25519_PUBSZ), C(ED25519_SIGSZ),
 #define ENTRY(tag, val, str) C(KERR_##tag),
   KEY_ERRORS(ENTRY)
 #undef ENTRY
index f79b4d29b210c56129138a0c08607dff637d5bca..785838e67eb94830a2358670bcd86049ac0e889c 100644 (file)
@@ -96,6 +96,44 @@ def _checkend(r):
     raise SyntaxError, 'junk at end of string'
   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 '#<SECRET>'
+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('#<SECRET>')
+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, _clsname(obj) + open)
+def _pp_kv(pp, k, v, secretp = False):
+  ind = _pp_bgroup(pp, k + ' = ')
+  _pp_secret(pp, v, secretp)
+  pp.end_group(ind, '')
+def _pp_commas(pp, printfn, items):
+  firstp = True
+  for i in items:
+    if firstp: firstp = False
+    else: pp.text(','); pp.breakable()
+    printfn(i)
+def _pp_dict(pp, items):
+  def p((k, v)):
+    pp.begin_group(0)
+    pp.pretty(k)
+    pp.text(':')
+    pp.begin_group(2)
+    pp.breakable()
+    pp.pretty(v)
+    pp.end_group(2)
+    pp.end_group(0)
+  _pp_commas(pp, p, items)
+
 ###--------------------------------------------------------------------------
 ### Bytestrings.
 
@@ -108,8 +146,39 @@ class _tmp:
   def __repr__(me):
     return 'bytes(%r)' % hex(me)
 _augment(ByteString, _tmp)
+ByteString.__hash__ = str.__hash__
 bytes = ByteString.fromhex
 
+###--------------------------------------------------------------------------
+### Hashing.
+
+class _tmp:
+  def check(me, h):
+    hh = me.done()
+    return ctstreq(h, hh)
+_augment(GHash, _tmp)
+_augment(Poly1305Hash, _tmp)
+
+###--------------------------------------------------------------------------
+### 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)
+
+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:])
+
 ###--------------------------------------------------------------------------
 ### Multiprecision integers and binary polynomials.
 
@@ -132,7 +201,8 @@ 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):
     n, d = _split_rat(you)
@@ -177,6 +247,7 @@ class _tmp:
   def reduce(x): return MPReduce(x)
   def __div__(me, you): return IntRat(me, you)
   def __rdiv__(me, you): return IntRat(you, me)
+  _repr_pretty_ = _pp_str
 _augment(MP, _tmp)
 
 class _tmp:
@@ -188,6 +259,7 @@ class _tmp:
   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)
+  _repr_pretty_ = _pp_str
 _augment(GF, _tmp)
 
 class _tmp:
@@ -206,14 +278,24 @@ 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)
+    if cyclep: pp.text('...')
+    else: pp.pretty(me.p)
+    pp.end_group(ind, ')')
   def ec(me, a, b): return ECPrimeProjCurve(me, a, b)
 _augment(PrimeField, _tmp)
 
 class _tmp:
-  def __repr__(me): return '%s(%sL)' % (type(me).__name__, hex(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)
+    if cyclep: pp.text('...')
+    else: pp.text('%#x' % me.p)
+    pp.end_group(ind, ')')
 _augment(BinField, _tmp)
 
 class _tmp:
@@ -231,6 +313,7 @@ _augment(BinNormField, _tmp)
 class _tmp:
   def __str__(me): return str(me.value)
   def __repr__(me): return '%s(%s)' % (repr(me.field), repr(me.value))
+  _repr_pretty_ = _pp_str
 _augment(FE, _tmp)
 
 ###--------------------------------------------------------------------------
@@ -238,7 +321,16 @@ _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:
+      pp.text('...')
+    else:
+      pp.pretty(me.field); pp.text(','); pp.breakable()
+      pp.pretty(me.a); pp.text(','); pp.breakable()
+      pp.pretty(me.b)
+    pp.end_group(ind, ')')
   def frombuf(me, s):
     return ecpt.frombuf(me, s)
   def fromraw(me, s):
@@ -267,17 +359,37 @@ _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)
+  def _repr_pretty_(me, pp, cyclep):
+    if cyclep:
+      pp.text('...')
+    elif not me:
+      pp.text('inf')
+    else:
+      ind = _pp_bgroup(pp, '(')
+      pp.pretty(me.ix); pp.text(','); pp.breakable()
+      pp.pretty(me.iy)
+      pp.end_group(ind, ')')
 _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:
+      pp.text('...')
+    else:
+      _pp_kv(pp, 'curve', me.curve); pp.text(','); pp.breakable()
+      _pp_kv(pp, 'G', me.G); pp.text(','); pp.breakable()
+      _pp_kv(pp, 'r', me.r); pp.text(','); pp.breakable()
+      _pp_kv(pp, 'h', me.h)
+    pp.end_group(ind, ')')
   def __hash__(me):
     h = 0x9bedb8de
     h ^=   hash(me.curve)
@@ -294,21 +406,41 @@ class _tmp:
   def __str__(me):
     if not me: return 'inf'
     return '(%s, %s)' % (me.x, me.y)
+  def _repr_pretty_(me, pp, cyclep):
+    if cyclep:
+      pp.text('...')
+    elif not me:
+      pp.text('inf')
+    else:
+      ind = _pp_bgroup(pp, '(')
+      pp.pretty(me.x); pp.text(','); pp.breakable()
+      pp.pretty(me.y)
+      pp.end_group(ind, ')')
 _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:
+      pp.text('...')
+    else:
+      pp.pretty(me.default); pp.text(','); pp.breakable()
+      pp.pretty(me.min); pp.text(','); pp.breakable()
+      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 best(me, sz):
     if sz < me.min: raise ValueError, 'key too small'
@@ -317,7 +449,17 @@ 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:
+      pp.text('...')
+    else:
+      pp.pretty(me.default); pp.text(','); pp.breakable()
+      ind1 = _pp_bgroup(pp, '{')
+      _pp_commas(pp, pp.pretty, me.set)
+      pp.end_group(ind1, '}')
+    pp.end_group(ind, ')')
   def check(me, sz): return sz in me.set
   def best(me, sz):
     found = -1
@@ -327,13 +469,91 @@ class _tmp:
     return found
 _augment(KeySZSet, _tmp)
 
+###--------------------------------------------------------------------------
+### Key data objects.
+
+class _tmp:
+  def __repr__(me): return '%s(%r)' % (_clsname(me), me.name)
+_augment(KeyFile, _tmp)
+
+class _tmp:
+  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()]))
+  def _repr_pretty_(me, pp, cyclep):
+    ind = _pp_bgroup_tyname(pp, me)
+    if cyclep: pp.text('...')
+    else: _pp_dict(pp, me.iteritems())
+    pp.end_group(ind, ')')
+_augment(KeyAttributes, _tmp)
+
+class _tmp:
+  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_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 _guts(me): return me.ct
+_augment(KeyDataEncrypted, _tmp)
+
+class _tmp:
+  def _guts(me): return me.mp
+_augment(KeyDataMP, _tmp)
+
+class _tmp:
+  def _guts(me): return me.str
+_augment(KeyDataString, _tmp)
+
+class _tmp:
+  def _guts(me): return me.ecpt
+_augment(KeyDataECPt, _tmp)
+
+class _tmp:
+  def __repr__(me):
+    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('...')
+    else: _pp_dict(pp, me.iteritems())
+    pp.end_group(ind, ' })')
+_augment(KeyDataStructured, _tmp)
+
 ###--------------------------------------------------------------------------
 ### Abstract groups.
 
 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:
+      pp.text('...')
+    else:
+      _pp_kv(pp, 'p', me.p); pp.text(','); pp.breakable()
+      _pp_kv(pp, 'r', me.r); pp.text(','); pp.breakable()
+      _pp_kv(pp, 'g', me.g)
+    pp.end_group(ind, ')')
 _augment(FGInfo, _tmp)
 
 class _tmp:
@@ -346,7 +566,12 @@ _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('...')
+    else: pp.pretty(me.info)
+    pp.end_group(ind, ')')
 _augment(Group, _tmp)
 
 class _tmp:
@@ -357,6 +582,7 @@ class _tmp:
     h ^= 2*hash(info.r) & 0xffffffff
     h ^= 5*hash(info.g) & 0xffffffff
     return h
+  def _get_geval(me, x): return MP(x)
 _augment(PrimeGroup, _tmp)
 
 class _tmp:
@@ -367,15 +593,19 @@ class _tmp:
     h ^= 2*hash(info.r) & 0xffffffff
     h ^= 5*hash(info.g) & 0xffffffff
     return h
+  def _get_geval(me, x): return GF(x)
 _augment(BinGroup, _tmp)
 
 class _tmp:
   def __hash__(me): return 0x0ec23dab ^ hash(me.info)
+  def _get_geval(me, x): return x.toec()
 _augment(ECGroup, _tmp)
 
 class _tmp:
   def __repr__(me):
     return '%r(%r)' % (me.group, str(me))
+  def _repr_pretty_(me, pp, cyclep):
+    pp.pretty(type(me)._get_geval(me))
 _augment(GE, _tmp)
 
 ###--------------------------------------------------------------------------
@@ -434,13 +664,158 @@ 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)
 
+###--------------------------------------------------------------------------
+### DSA and related schemes.
+
+class _tmp:
+  def __repr__(me): return '%s(G = %r, p = %r)' % (_clsname(me), me.G, me.p)
+  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.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_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.end_group(ind, ')')
+_augment(DSAPriv, _tmp)
+_augment(KCDSAPriv, _tmp)
+
+###--------------------------------------------------------------------------
+### Bernstein's elliptic curve crypto and related schemes.
+
+X25519_BASE = \
+  bytes('0900000000000000000000000000000000000000000000000000000000000000')
+
+X448_BASE = \
+  bytes('05000000000000000000000000000000000000000000000000000000'
+        '00000000000000000000000000000000000000000000000000000000')
+
+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)
+    me.pub = pub
+  def __repr__(me): return '%s(pub = %r)' % (_clsname(me), 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)
+    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)
+    me.priv = priv
+  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, ')')
+
+class X25519Pub (_BoxyPub):
+  _PUBSZ = X25519_PUBSZ
+  _BASE = X25519_BASE
+
+class X25519Priv (_BoxyPriv, X25519Pub):
+  _KEYSZ = 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
+  _BASE = X448_BASE
+
+class X448Priv (_BoxyPriv, X448Pub):
+  _KEYSZ = 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))
+
 ###--------------------------------------------------------------------------
 ### Built-in named curves and prime groups.
 
@@ -448,9 +823,17 @@ class _groupmap (object):
   def __init__(me, map, nth):
     me.map = map
     me.nth = nth
-    me.i = [None] * (max(map.values()) + 1)
+    me._n = max(map.values()) + 1
+    me.i = me._n*[None]
   def __repr__(me):
-    return '{%s}' % ', '.join(['%r: %r' % (k, me[k]) for k in me])
+    return '{%s}' % ', '.join(['%r: %r' % kv for kv in me.iteritems()])
+  def _repr_pretty_(me, pp, cyclep):
+    ind = _pp_bgroup(pp, '{ ')
+    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):
index 444feba7e87eca68a2d944bbcfa2e1e65c84f92a..c9e5b41a1ef905849a466b997e8ac3c32edffa0c 100644 (file)
@@ -5,7 +5,7 @@ XS-Python-Version: >= 2.6, << 2.8
 Maintainer: Mark Wooding <mdw@distorted.org.uk>
 Build-Depends: debhelper (>= 9), pkg-config,
        python, python2.6-dev, python2.7-dev,
-       mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.2.5+14)
+       mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.3.0.1+3)
 Standards-Version: 3.8.0
 
 Package: python-catacomb
diff --git a/ec.c b/ec.c
index 63d97d8c26438db8e8d7e106823f7c769e745bc2..0489bc0f33e3b00d4a882b2be9772fdbaf8c0d17 100644 (file)
--- a/ec.c
+++ b/ec.c
@@ -835,7 +835,7 @@ static PyObject *ecmeth_mmul(PyObject *me, PyObject *arg)
 static PyObject *meth__ECPtCurve_fromraw(PyObject *me, PyObject *arg)
 {
   char *p;
-  int len;
+  Py_ssize_t len;
   buf b;
   PyObject *rc = 0;
   ec_curve *cc;
@@ -857,7 +857,7 @@ static PyObject *meth__ECPtCurve_os2ecp(PyObject *me,
                                        PyObject *arg, PyObject *kw)
 {
   char *p;
-  int len;
+  Py_ssize_t len;
   buf b;
   PyObject *rc = 0;
   ec_curve *cc;
@@ -881,7 +881,7 @@ static PyObject *meth__ECPt_frombuf(PyObject *me, PyObject *arg)
 {
   buf b;
   char *p;
-  int sz;
+  Py_ssize_t sz;
   PyObject *rc = 0;
   ec pp = EC_INIT;
 
diff --git a/group.c b/group.c
index ba59a8a749aecd366e3da0583cee7b60b2eb0793..cc8bbc1986608450df3132db8bb72b6a33c7aee0 100644 (file)
--- a/group.c
+++ b/group.c
@@ -184,7 +184,7 @@ static PyObject *meth__DHInfo_gendsa(PyObject *me,
   unsigned steps = 0;
   dsa_seed ds;
   char *k;
-  int ksz;
+  Py_ssize_t ksz;
   pgev evt = { 0 };
   char *kwlist[] =
     { "class", "pbits", "qbits", "seed", "event", "nsteps", 0 };
@@ -449,12 +449,6 @@ static PyTypeObject bindhinfo_pytype_skel = {
 PyTypeObject *ge_pytype, *group_pytype;
 PyTypeObject *primegroup_pytype, *bingroup_pytype, *ecgroup_pytype;
 
-#ifdef GROUP_GUTS_MPSTRUCT
-#  define GG_GEN(gg) ((gg)->gen.x)
-#else
-#  define GG_GEN(gg) ((gg)->gen)
-#endif
-
 group *group_copy(group *g)
 {
   if (strcmp(G_NAME(g), "prime") == 0) {
@@ -723,18 +717,34 @@ end:
 static PyObject *gemeth_toec(PyObject *me, PyObject *arg, PyObject *kw)
 {
   char *kwlist[] = { "curve", 0 };
-  PyTypeObject *cty = ecpt_pytype;
+  PyTypeObject *cty = 0;
+  PyObject *rc = 0;
+  group *g;
+  ec_curve *c;
   ec p = EC_INIT;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:toec", kwlist,
                                   &cty)) goto end;
-  if (!PyType_Check(cty) || !PyType_IsSubtype(cty, ecpt_pytype))
-    TYERR("want subtype of catacomb.ECPt");
-  if (G_TOEC(GE_G(me), &p, GE_X(me)))
+  g = GROUP_G(GE_GOBJ(me));
+  if (cty) {
+    if (!PyType_Check(cty) || !PyType_IsSubtype(cty, ecpt_pytype))
+      TYERR("want subtype of catacomb.ECPt");
+    Py_INCREF((PyObject *)cty);
+  } else if (strcmp(G_NAME(g), "ec") == 0) {
+    c = eccurve_copy(((gctx_ec *)g)->ei.c);
+    cty = (PyTypeObject *)eccurve_pywrap(0, c);
+  } else  {
+    cty = ecpt_pytype;
+    Py_INCREF((PyObject *)cty);
+  }
+  if (G_TOEC(GE_G(me), &p, GE_X(me))) {
+    Py_DECREF((PyObject *)cty);
     TYERR("can't convert to ec point");
-  return (ecpt_pywrapout(cty, &p));
+  }
+  rc = ecpt_pywrapout(cty, &p);
+  Py_DECREF((PyObject *)cty);
 end:
-  return (0);
+  return (rc);
 }
 
 static PyObject *gemeth_tobuf(PyObject *me, PyObject *arg)
@@ -821,7 +831,7 @@ static PyObject *meth__GE_frombuf(PyObject *me, PyObject *arg)
 {
   buf b;
   char *p;
-  int n;
+  Py_ssize_t n;
   group *g;
   ge *x = 0;
 
@@ -842,7 +852,7 @@ static PyObject *meth__GE_fromraw(PyObject *me, PyObject *arg)
 {
   buf b;
   char *p;
-  int n;
+  Py_ssize_t n;
   group *g;
   ge *x = 0;
 
@@ -863,7 +873,7 @@ static PyObject *meth__GE_fromstring(PyObject *me, PyObject *arg)
 {
   mptext_stringctx sc;
   char *p;
-  int n;
+  Py_ssize_t n;
   group *g;
   ge *x = 0;
 
@@ -876,7 +886,7 @@ static PyObject *meth__GE_fromstring(PyObject *me, PyObject *arg)
   if (G_READ(g, x, &mptext_stringops, &sc))
     VALERR("bad group element string");
   return (Py_BuildValue("(Ns#)", ge_pywrap(me, x),
-                       sc.buf, (int)(sc.lim - sc.buf)));
+                       sc.buf, (Py_ssize_t)(sc.lim - sc.buf)));
 end:
   if (x) G_DESTROY(g, x);
   return (0);
@@ -1128,7 +1138,7 @@ static PyObject *pgget_info(PyObject *me, void *hunoz)
   gctx_prime *gg = (gctx_prime *)GROUP_G(me);
   dp.p = MP_COPY(gg->mm.m);
   dp.q = MP_COPY(gg->g.r);
-  dp.g = mpmont_reduce(&gg->mm, MP_NEW, GG_GEN(gg));
+  dp.g = mpmont_reduce(&gg->mm, MP_NEW, gg->gen.x);
   return (fginfo_pywrap(&dp, dhinfo_pytype));
 }
 
@@ -1205,7 +1215,7 @@ static PyObject *bgget_info(PyObject *me, void *hunoz)
   gctx_bin *gg = (gctx_bin *)GROUP_G(me);
   dp.p = MP_COPY(gg->r.p);
   dp.q = MP_COPY(gg->g.r);
-  dp.g = MP_COPY(GG_GEN(gg));
+  dp.g = MP_COPY(gg->gen.x);
   return (fginfo_pywrap(&dp, bindhinfo_pytype));
 }
 
diff --git a/key.c b/key.c
index a3cd200b1189a4f9f05aec1e98b702468c898b67..8dec99cfa09e22415dfdbc47c0516a676eda24fd 100644 (file)
--- a/key.c
+++ b/key.c
@@ -414,7 +414,7 @@ end:
 static PyObject *kdmeth_lock(PyObject *me, PyObject *arg)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   PyObject *rc = 0;
   key_data *kd;
 
@@ -445,7 +445,7 @@ end:
 static PyObject *meth__KeyData_decode(PyObject *me, PyObject *arg)
 {
   const char *p;
-  int n;
+  Py_ssize_t n;
   key_data *kd;
   PyObject *rc = 0;
 
@@ -533,7 +533,7 @@ static PyObject *keydatabin_pynew(PyTypeObject *ty,
                                  PyObject *arg, PyObject *kw)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   unsigned f = 0;
   keydata_pyobj *me = 0;
   static char *kwlist[] = { "key", "flags", 0 };
@@ -610,7 +610,7 @@ static PyObject *keydataenc_pynew(PyTypeObject *ty,
                                  PyObject *arg, PyObject *kw)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   unsigned f = 0;
   keydata_pyobj *me = 0;
   static char *kwlist[] = { "key", "flags", 0 };
@@ -636,7 +636,7 @@ end:
 static PyObject *kdemeth_lock(PyObject *me, PyObject *arg)
 {
   char *hunoz;
-  int hukairz;
+  Py_ssize_t hukairz;
   if (!PyArg_ParseTuple(arg, "s#:lock", &hunoz, &hukairz)) goto end;
   KEYERR(KERR_WRONGTYPE);
 end:
@@ -662,7 +662,7 @@ end:
 static PyObject *kdemeth_unlock(PyObject *me, PyObject *arg)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   int err;
   PyObject *rc = 0;
   key_data *kd;
@@ -1969,7 +1969,7 @@ static PyObject *kfmeth_qtag(PyObject *me, PyObject *arg, PyObject *kw)
   }
   key_incref(*kd);
   rc = Py_BuildValue("(s#NN)",
-                    d.buf, d.len,
+                    d.buf, (Py_ssize_t)d.len,
                     key_pywrap(me, k),
                     keydata_pywrap(okd));
 end:
diff --git a/mp.c b/mp.c
index f5f43204a718256abc288f93db7c4aa7907e7804..79c6cf20c8952f6502f68395d28abeab2ebe0202 100644 (file)
--- a/mp.c
+++ b/mp.c
@@ -713,7 +713,7 @@ STOREOP(storeb2c, 2c)
   {                                                                    \
     buf b;                                                             \
     char *p;                                                           \
-    int sz;                                                            \
+    Py_ssize_t sz;                                                     \
     PyObject *rc = 0;                                                  \
     mp *x;                                                             \
                                                                        \
@@ -911,7 +911,7 @@ static PyObject *meth__MP_fromstring(PyObject *me,
 {
   int r = 0;
   char *p;
-  int len;
+  Py_ssize_t len;
   PyObject *z = 0;
   mp *zz;
   mptext_stringctx sc;
@@ -924,7 +924,8 @@ static PyObject *meth__MP_fromstring(PyObject *me,
   sc.buf = p; sc.lim = p + len;
   if ((zz = mp_read(MP_NEW, r, &mptext_stringops, &sc)) == 0)
     VALERR("bad integer");
-  z = Py_BuildValue("(Ns#)", mp_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf));
+  z = Py_BuildValue("(Ns#)", mp_pywrap(zz),
+                   sc.buf, (Py_ssize_t)(sc.lim - sc.buf));
 end:
   return (z);
 }
@@ -952,7 +953,7 @@ static PyObject *meth__MP_fibonacci(PyObject *me, PyObject *arg)
   static PyObject *meth__##py##_##name(PyObject *me, PyObject *arg)    \
   {                                                                    \
     char *p;                                                           \
-    int len;                                                           \
+    Py_ssize_t len;                                                    \
     if (!PyArg_ParseTuple(arg, "Os#:" #name, &me, &p, &len)) return (0); \
     return (pre##_pywrap(mp_##name(MP_NEW, p, len)));                  \
   }
@@ -2111,7 +2112,7 @@ static PyObject *meth__GF_fromstring(PyObject *me,
 {
   int r = 0;
   char *p;
-  int len;
+  Py_ssize_t len;
   PyObject *z = 0;
   mp *zz;
   mptext_stringctx sc;
@@ -2127,7 +2128,8 @@ static PyObject *meth__GF_fromstring(PyObject *me,
     if (zz) MP_DROP(zz);
     VALERR("bad binary polynomial");
   }
-  z = Py_BuildValue("(Ns#)", gf_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf));
+  z = Py_BuildValue("(Ns#)", gf_pywrap(zz),
+                   sc.buf, (Py_ssize_t)(sc.lim - sc.buf));
 end:
   return (z);
 }
index 4c4eb1dfbc40743ea7c342eea9dafde4a22c0a52..4067ae0ff10219ed5dbff4f24df93be1c4d41af7 100644 (file)
--- a/pubkey.c
+++ b/pubkey.c
@@ -54,26 +54,35 @@ static void dsa_pydealloc(PyObject *me)
 }
 
 static PyObject *dsa_setup(PyTypeObject *ty, PyObject *G, PyObject *u,
-                          PyObject *p, PyObject *rng, PyObject *hash)
+                          PyObject *p, PyObject *rng, PyObject *hash,
+                          void (*calcpub)(group *, ge *, mp *))
 {
   dsa_pyobj *g;
+  ge *pp;
 
   g = PyObject_New(dsa_pyobj, ty);
-  if (GROUP_G(G) != GE_G(p) && !group_samep(GROUP_G(G), GE_G(p)))
-    TYERR("public key not from group");
+  if (p) Py_INCREF(p);
   if (!u) {
     g->d.u = 0;
     u = Py_None;
   } else if ((g->d.u = getmp(u)) == 0)
     goto end;
+  if (!p) {
+    assert(g->d.u); assert(calcpub);
+    pp = G_CREATE(GROUP_G(G));
+    calcpub(GROUP_G(G), pp, g->d.u);
+    p = ge_pywrap(G, pp);
+  } else if (GROUP_G(G) != GE_G(p) && !group_samep(GROUP_G(G), GE_G(p)))
+    TYERR("public key not from group");
   g->d.g = GROUP_G(G);
   g->d.p = GE_X(p);
   g->d.r = GRAND_R(rng);
   g->d.h = GCHASH_CH(hash);
-  g->G = G; Py_INCREF(G); g->u = u; Py_INCREF(u); g->p = p; Py_INCREF(p);
+  g->G = G; Py_INCREF(G); g->u = u; Py_INCREF(u); g->p = p;
   g->rng = rng; Py_INCREF(rng); g->hash = hash; Py_INCREF(hash);
   return ((PyObject *)g);
 end:
+  if (p) Py_DECREF(p);
   FREEOBJ(g);
   return (0);
 }
@@ -81,17 +90,16 @@ end:
 static PyObject *dsapub_pynew(PyTypeObject *ty,
                              PyObject *arg, PyObject *kw)
 {
-  PyObject *G, *p, *u = 0, *rng = rand_pyobj, *hash = sha_pyobj;
+  PyObject *G, *p, *rng = rand_pyobj, *hash = sha_pyobj;
   PyObject *rc = 0;
-  char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 };
+  char *kwlist[] = { "G", "p", "hash", "rng", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|OO!O!:new", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!O!:new", kwlist,
                                   group_pytype, &G,
                                   ge_pytype, &p,
-                                  &u,
                                   gchash_pytype, &hash,
                                   grand_pytype, &rng) ||
-      (rc = dsa_setup(dsapub_pytype, G, u, p, rng, hash)) == 0)
+      (rc = dsa_setup(dsapub_pytype, G, 0, p, rng, hash, 0)) == 0)
     goto end;
 end:
   return (rc);
@@ -120,7 +128,7 @@ static PyObject *dsameth_sign(PyObject *me, PyObject *arg, PyObject *kw)
 {
   gdsa_sig s = GDSA_SIG_INIT;
   char *p;
-  int n;
+  Py_ssize_t n;
   mp *k = 0;
   PyObject *rc = 0;
   char *kwlist[] = { "msg", "k", 0 };
@@ -140,7 +148,7 @@ end:
 static PyObject *dsameth_verify(PyObject *me, PyObject *arg)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   gdsa_sig s = GDSA_SIG_INIT;
   PyObject *rc = 0;
 
@@ -156,20 +164,22 @@ end:
   return (rc);
 }
 
+static void dsa_calcpub(group *g, ge *p, mp *u) { G_EXP(g, p, g->g, u); }
+
 static PyObject *dsapriv_pynew(PyTypeObject *ty,
                               PyObject *arg, PyObject *kw)
 {
-  PyObject *G, *p, *u = Py_None, *rng = rand_pyobj, *hash = sha_pyobj;
+  PyObject *G, *p = 0, *u, *rng = rand_pyobj, *hash = sha_pyobj;
   PyObject *rc = 0;
-  char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 };
+  char *kwlist[] = { "G", "u", "p", "hash", "rng", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O|O!O!:new", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O|O!O!O!:new", kwlist,
                                   group_pytype, &G,
-                                  ge_pytype, &p,
                                   &u,
+                                  ge_pytype, &p,
                                   gchash_pytype, &hash,
                                   grand_pytype, &rng) ||
-      (rc = dsa_setup(dsapriv_pytype, G, u, p, rng, hash)) == 0)
+      (rc = dsa_setup(dsapriv_pytype, G, u, p, rng, hash, dsa_calcpub)) == 0)
     goto end;
 end:
   return (rc);
@@ -307,36 +317,43 @@ static PyTypeObject dsapriv_pytype_skel = {
 static PyObject *kcdsapub_pynew(PyTypeObject *ty,
                                PyObject *arg, PyObject *kw)
 {
-  PyObject *G, *p, *u = 0, *rng = rand_pyobj, *hash = has160_pyobj;
+  PyObject *G, *p, *rng = rand_pyobj, *hash = has160_pyobj;
   PyObject *rc = 0;
-  char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 };
+  char *kwlist[] = { "G", "p", "hash", "rng", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O|O!O!:new", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!O!:new", kwlist,
                                   group_pytype, &G,
                                   ge_pytype, &p,
-                                  &u,
                                   gchash_pytype, &hash,
                                   grand_pytype, &rng) ||
-      (rc = dsa_setup(kcdsapub_pytype, G, u, p, rng, hash)) == 0)
+      (rc = dsa_setup(kcdsapub_pytype, G, 0, p, rng, hash, 0)) == 0)
     goto end;
 end:
   return (rc);
 }
 
+static void kcdsa_calcpub(group *g, ge *p, mp *u)
+{
+  mp *uinv = mp_modinv(MP_NEW, u, g->r);
+  G_EXP(g, p, g->g, uinv);
+  mp_drop(uinv);
+}
+
 static PyObject *kcdsapriv_pynew(PyTypeObject *ty,
                                 PyObject *arg, PyObject *kw)
 {
-  PyObject *G, *p, *u = Py_None, *rng = rand_pyobj, *hash = has160_pyobj;
+  PyObject *G, *u, *p = 0, *rng = rand_pyobj, *hash = has160_pyobj;
   PyObject *rc = 0;
   char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|OO!O!:new", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O|O!O!O!:new", kwlist,
                                   group_pytype, &G,
-                                  ge_pytype, &p,
                                   &u,
+                                  ge_pytype, &p,
                                   gchash_pytype, &hash,
                                   grand_pytype, &rng) ||
-      (rc = dsa_setup(kcdsapriv_pytype, G, u, p, rng, hash)) == 0)
+      (rc = dsa_setup(kcdsapriv_pytype, G, u, p,
+                     rng, hash, kcdsa_calcpub)) == 0)
     goto end;
 end:
   return (rc);
@@ -365,7 +382,7 @@ static PyObject *kcdsameth_sign(PyObject *me, PyObject *arg, PyObject *kw)
 {
   gkcdsa_sig s = GKCDSA_SIG_INIT;
   char *p;
-  int n;
+  Py_ssize_t n;
   mp *k = 0;
   PyObject *r = 0, *rc = 0;
   char *kwlist[] = { "msg", "k", 0 };
@@ -388,7 +405,7 @@ end:
 static PyObject *kcdsameth_verify(PyObject *me, PyObject *arg)
 {
   char *p;
-  int n, rn;
+  Py_ssize_t n, rn;
   gkcdsa_sig s = GKCDSA_SIG_INIT;
   PyObject *rc = 0;
 
@@ -865,7 +882,7 @@ static PyObject *meth__p1crypt_encode(PyObject *me,
 {
   pkcs1 p1;
   char *m, *ep;
-  int msz, epsz;
+  Py_ssize_t msz, epsz;
   unsigned long nbits;
   PyObject *rc = 0;
   octet *b = 0;
@@ -894,7 +911,7 @@ static PyObject *meth__p1crypt_decode(PyObject *me,
 {
   pkcs1 p1;
   char *ep;
-  int epsz;
+  Py_ssize_t epsz;
   unsigned long nbits;
   int n;
   PyObject *rc = 0;
@@ -926,7 +943,7 @@ static PyObject *meth__p1sig_encode(PyObject *me,
 {
   pkcs1 p1;
   char *m, *ep;
-  int msz, epsz;
+  Py_ssize_t msz, epsz;
   unsigned long nbits;
   PyObject *rc = 0;
   octet *b = 0;
@@ -955,7 +972,7 @@ static PyObject *meth__p1sig_decode(PyObject *me,
 {
   pkcs1 p1;
   char *ep;
-  int epsz;
+  Py_ssize_t epsz;
   unsigned long nbits;
   int n;
   PyObject *hukairz;
@@ -988,7 +1005,7 @@ static PyObject *meth__oaep_encode(PyObject *me,
 {
   oaep o;
   char *m, *ep;
-  int msz, epsz;
+  Py_ssize_t msz, epsz;
   unsigned long nbits;
   PyObject *rc = 0;
   octet *b = 0;
@@ -1020,7 +1037,7 @@ static PyObject *meth__oaep_decode(PyObject *me,
 {
   oaep o;
   char *ep;
-  int epsz;
+  Py_ssize_t epsz;
   unsigned long nbits;
   int n;
   PyObject *rc = 0;
@@ -1055,7 +1072,7 @@ static PyObject *meth__pss_encode(PyObject *me,
 {
   pss p;
   char *m;
-  int msz;
+  Py_ssize_t msz;
   unsigned long nbits;
   PyObject *rc = 0;
   octet *b = 0;
@@ -1087,7 +1104,7 @@ static PyObject *meth__pss_decode(PyObject *me,
 {
   pss p;
   char *m;
-  int msz;
+  Py_ssize_t msz;
   unsigned long nbits;
   PyObject *rc = 0;
   octet *b = 0;
@@ -1118,6 +1135,91 @@ end:
   return (rc);
 }
 
+/*----- X25519 and related algorithms -------------------------------------*/
+
+static PyObject *meth_x25519(PyObject *me, PyObject *arg)
+{
+  const char *k, *p;
+  Py_ssize_t ksz, psz;
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, "s#s#:x25519", &k, &ksz, &p, &psz)) goto end;
+  if (ksz != X25519_KEYSZ) VALERR("bad key length");
+  if (psz != X25519_PUBSZ) VALERR("bad public length");
+  rc = bytestring_pywrap(0, X25519_OUTSZ);
+  x25519((octet *)PyString_AS_STRING(rc),
+        (const octet *)k, (const octet *)p);
+  return (rc);
+end:
+  return (0);
+}
+
+static PyObject *meth_x448(PyObject *me, PyObject *arg)
+{
+  const char *k, *p;
+  Py_ssize_t ksz, psz;
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, "s#s#:x448", &k, &ksz, &p, &psz)) goto end;
+  if (ksz != X448_KEYSZ) VALERR("bad key length");
+  if (psz != X448_PUBSZ) VALERR("bad public length");
+  rc = bytestring_pywrap(0, X448_OUTSZ);
+  x448((octet *)PyString_AS_STRING(rc),
+       (const octet *)k, (const octet *)p);
+  return (rc);
+end:
+  return (0);
+}
+
+/*----- Ed25519 -----------------------------------------------------------*/
+
+static PyObject *meth_ed25519_pubkey(PyObject *me, PyObject *arg)
+{
+  const char *k;
+  Py_ssize_t ksz;
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, "s#:ed25519_pubkey", &k, &ksz)) goto end;
+  rc = bytestring_pywrap(0, ED25519_PUBSZ);
+  ed25519_pubkey((octet *)PyString_AS_STRING(rc), k, ksz);
+  return (rc);
+end:
+  return (0);
+}
+
+static PyObject *meth_ed25519_sign(PyObject *me, PyObject *arg, PyObject *kw)
+{
+  const char *k, *p = 0, *m;
+  Py_ssize_t ksz, psz, msz;
+  PyObject *rc = 0;
+  octet pp[ED25519_PUBSZ];
+  char *kwlist[] = { "key", "msg", "pub", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|s#:ed25519_sign", kwlist,
+                                  &k, &ksz, &m, &msz, &p, &psz))
+    goto end;
+  if (p && psz != ED25519_PUBSZ) VALERR("bad public length");
+  if (!p) { p = (const char *)pp; ed25519_pubkey(pp, k, ksz); }
+  rc = bytestring_pywrap(0, ED25519_SIGSZ);
+  ed25519_sign((octet *)PyString_AS_STRING(rc), k, ksz,
+              (const octet *)p, m, msz);
+  return (rc);
+end:
+  return (0);
+}
+
+static PyObject *meth_ed25519_verify(PyObject *me, PyObject *arg)
+{
+  const char *p, *m, *s;
+  Py_ssize_t psz, msz, ssz;
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, "s#s#s#:ed25519_verify",
+                       &p, &psz, &m, &msz, &s, &ssz))
+    goto end;
+  if (psz != ED25519_PUBSZ) VALERR("bad public length");
+  if (ssz != ED25519_SIGSZ) VALERR("bad signature length");
+  rc = getbool(!ed25519_verify((const octet *)p, m, msz, (const octet *)s));
+  return (rc);
+end:
+  return (0);
+}
+
 /*----- Global stuff ------------------------------------------------------*/
 
 static PyMethodDef methods[] = {
@@ -1132,6 +1234,16 @@ static PyMethodDef methods[] = {
   KWMETH(_pss_decode,                  0)
   KWMETH(_RSAPriv_generate,            "\
 generate(NBITS, [event = pgen_nullev, rng = rand, nsteps = 0]) -> R")
+  METH  (x25519,                       "\
+x25519(KEY, PUBLIC) -> SHARED")
+  METH  (x448,                         "\
+x448(KEY, PUBLIC) -> SHARED")
+  METH  (ed25519_pubkey,               "\
+ed25519_pubkey(KEY) -> PUBLIC")
+  KWMETH(ed25519_sign,                 "\
+ed25519_sign(KEY, MSG, [PUBLIC]) -> SIG")
+  METH  (ed25519_verify,               "\
+ed25519_verify(PUBLIC, MSG, SIG) -> BOOL")
 #undef METHNAME
   { 0 }
 };
diff --git a/rand.c b/rand.c
index 4fcb15502b4a62554bd54f72f88816eff7f1c16a..f163efa0533014c28c034738e47206c8af476e88 100644 (file)
--- a/rand.c
+++ b/rand.c
@@ -173,7 +173,7 @@ end:
 static PyObject *grmeth_seedblock(PyObject *me, PyObject *arg)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   grand *r = GRAND_R(me);
   if (!PyArg_ParseTuple(arg, "s#:seedblock", &p, &n) ||
       checkop(r, GRAND_SEEDBLOCK, "seedblock"))
@@ -219,7 +219,7 @@ static PyObject *grmeth_mask(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
   char *p, *q;
-  int sz;
+  Py_ssize_t sz;
   PyObject *rc;
 
   if (!PyArg_ParseTuple(arg, "s#:mask", &p, &sz)) return (0);
@@ -452,7 +452,7 @@ static PyObject *trmeth_stretch(PyObject *me, PyObject *arg)
 static PyObject *trmeth_add(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
-  char *p; int n; unsigned goodbits;
+  char *p; Py_ssize_t n; unsigned goodbits;
   if (!PyArg_ParseTuple(arg, "s#O&:add", &p, &n, convuint, &goodbits))
     return (0);
   r->ops->misc(r, RAND_ADD, p, (size_t)n, goodbits);
@@ -462,7 +462,7 @@ static PyObject *trmeth_add(PyObject *me, PyObject *arg)
 static PyObject *trmeth_key(PyObject *me, PyObject *arg)
 {
   grand *r = GRAND_R(me);
-  char *p; int n;
+  char *p; Py_ssize_t n;
   if (!PyArg_ParseTuple(arg, "s#:key", &p, &n)) return (0);
   r->ops->misc(r, RAND_KEY, p, (size_t)n);
   RETURN_ME;
@@ -578,7 +578,7 @@ static PyTypeObject truerand_pytype_skel = {
 
 /*----- Generators from symmetric encryption algorithms -------------------*/
 
-static PyTypeObject *gccrand_pytype, *gcrand_pytype;
+static PyTypeObject *gccrand_pytype, *gcrand_pytype, *gclatinrand_pytype;
 
 typedef grand *gcrand_func(const void *, size_t sz);
 typedef grand *gcirand_func(const void *, size_t sz, uint32);
@@ -593,6 +593,7 @@ typedef struct gccrand_info {
 
 #define RNGF_INT 1u
 #define RNGF_NONCE 2u
+#define RNGF_LATIN 4u
 
 typedef struct gccrand_pyobj {
   PyHeapTypeObject ty;
@@ -616,7 +617,7 @@ static PyObject *gcrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   const gccrand_info *info = GCCRAND_INFO(ty);
   static char *kwlist[] = { "key", 0 };
   char *k;
-  int n;
+  Py_ssize_t n;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &n))
     goto end;
@@ -632,7 +633,7 @@ static PyObject *gcirand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   uint32 i = 0;
   static char *kwlist[] = { "key", "i", 0 };
   char *k;
-  int n;
+  Py_ssize_t n;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", kwlist,
                                   &k, &n, convu32, &i))
@@ -650,7 +651,7 @@ static PyObject *gcnrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   const gccrand_info *info = GCCRAND_INFO(ty);
   static char *kwlist[] = { "key", "nonce", 0 };
   char *k, *n;
-  int ksz, nsz;
+  Py_ssize_t ksz, nsz;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#:new", kwlist,
                                   &k, &ksz, &n, &nsz))
@@ -669,8 +670,9 @@ static PyObject *gccrand_pywrap(const gccrand_info *info)
   gccrand_pyobj *g = newtype(gccrand_pytype, 0, info->name);
   g->info = info;
   g->ty.ht_type.tp_basicsize = sizeof(grand_pyobj);
-  g->ty.ht_type.tp_base = gcrand_pytype;
-  Py_INCREF(gcrand_pytype);
+  g->ty.ht_type.tp_base =
+    (info->f & RNGF_LATIN) ? gclatinrand_pytype : gcrand_pytype;
+  Py_INCREF(g->ty.ht_type.tp_base);
   g->ty.ht_type.tp_flags = (Py_TPFLAGS_DEFAULT |
                            Py_TPFLAGS_BASETYPE |
                            Py_TPFLAGS_HEAPTYPE);
@@ -688,6 +690,28 @@ static PyObject *gccrget_name(PyObject *me, void *hunoz)
 static PyObject *gccrget_keysz(PyObject *me, void *hunoz)
   { return (keysz_pywrap(GCCRAND_INFO(me)->keysz)); }
 
+static PyObject *gclrmeth_tell(PyObject *me, PyObject *arg)
+{
+  grand *r = GRAND_R(me);
+  PyObject *rc = 0;
+  kludge64 off;
+
+  if (!PyArg_ParseTuple(arg, ":tell")) return (0);
+  r->ops->misc(r, SALSA20_TELLU64, &off);
+  rc = getk64(off);
+  return (rc);
+}
+
+static PyObject *gclrmeth_seek(PyObject *me, PyObject *arg)
+{
+  grand *r = GRAND_R(me);
+  kludge64 off;
+
+  if (!PyArg_ParseTuple(arg, "O&:seek", convk64, &off)) return (0);
+  r->ops->misc(r, SALSA20_SEEKU64, off);
+  RETURN_ME;
+}
+
 static PyGetSetDef gccrand_pygetset[] = {
 #define GETSETNAME(op, name) gccr##op##_##name
   GET  (keysz,                 "CR.keysz -> acceptable key sizes")
@@ -696,6 +720,14 @@ static PyGetSetDef gccrand_pygetset[] = {
   { 0 }
 };
 
+static PyMethodDef gclatinrand_pymethods[] = {
+#define METHNAME(name) gclrmeth_##name
+  METH (tell,          "R.tell() -> OFF")
+  METH (seek,          "R.seek(OFF)")
+#undef METHNAME
+  { 0 }
+};
+
 static PyTypeObject gccrand_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
   "GCCRand",                           /* @tp_name@ */
@@ -792,6 +824,54 @@ static PyTypeObject gcrand_pytype_skel = {
   0                                    /* @tp_is_gc@ */
 };
 
+static PyTypeObject gclatinrand_pytype_skel = {
+  PyObject_HEAD_INIT(0) 0,             /* Header */
+  "GCLatinRand",                       /* @tp_name@ */
+  sizeof(grand_pyobj),                 /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  grand_pydealloc,                     /* @tp_dealloc@ */
+  0,                                   /* @tp_print@ */
+  0,                                   /* @tp_getattr@ */
+  0,                                   /* @tp_setattr@ */
+  0,                                   /* @tp_compare@ */
+  0,                                   /* @tp_repr@ */
+  0,                                   /* @tp_as_number@ */
+  0,                                   /* @tp_as_sequence@ */
+  0,                                   /* @tp_as_mapping@ */
+  0,                                   /* @tp_hash@ */
+  0,                                   /* @tp_call@ */
+  0,                                   /* @tp_str@ */
+  0,                                   /* @tp_getattro@ */
+  0,                                   /* @tp_setattro@ */
+  0,                                   /* @tp_as_buffer@ */
+  Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
+    Py_TPFLAGS_BASETYPE,
+
+  /* @tp_doc@ */
+"Abstract base class for symmetric crypto-based generators.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternext@ */
+  gclatinrand_pymethods,               /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  0,                                   /* @tp_getset@ */
+  0,                                   /* @tp_base@ */
+  0,                                   /* @tp_dict@ */
+  0,                                   /* @tp_descr_get@ */
+  0,                                   /* @tp_descr_set@ */
+  0,                                   /* @tp_dictoffset@ */
+  0,                                   /* @tp_init@ */
+  PyType_GenericAlloc,                 /* @tp_alloc@ */
+  abstract_pynew,                      /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
 /*----- SSL and TLS generators --------------------------------------------*/
 
 static PyObject *sslprf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
@@ -1382,6 +1462,7 @@ void rand_pyinit(void)
   INITTYPE(tlsprf, grand);
   INITTYPE(gccrand, type);
   INITTYPE(gcrand, grand);
+  INITTYPE(gclatinrand, gcrand);
   rand_noisesrc(RAND_GLOBAL, &noise_source);
   rand_seed(RAND_GLOBAL, 160);
   addmethods(methods);
@@ -1404,6 +1485,7 @@ void rand_pyinsert(PyObject *mod)
   INSERT("BBSPriv", bbspriv_pytype);
   INSERT("GCCRand", gccrand_pytype);
   INSERT("GCRand", gcrand_pytype);
+  INSERT("GCLatinRand", gclatinrand_pytype);
   rand_pyobj = grand_pywrap(&rand_global, 0); Py_INCREF(rand_pyobj);
   gccrands_dict = gccrands(); Py_INCREF(gccrands_dict);
   INSERT("gccrands", gccrands_dict);
index 161e2afcfa56f31584feea6e7f10dee2c1e1bf2e..fe0ed538bf9389645be87fb2e89a64086ebdf969 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 import distutils.core as DC
 import mdwsetup as MS
 
-MS.pkg_config('catacomb', '2.2.0')
+MS.pkg_config('catacomb', '2.3.0.1+4')
 MS.pkg_config('mLib', '2.0.4')
 
 cat = DC.Extension('catacomb._base',
diff --git a/share.c b/share.c
index ad56d31f20a75817d372a728e481be00a4af0c9b..2caa718bb23290ec613a0f378ada8052964ffabe 100644 (file)
--- a/share.c
+++ b/share.c
@@ -113,7 +113,7 @@ static PyObject *gfsharesplit_pynew(PyTypeObject *ty,
                                    PyObject *arg, PyObject *kw)
 {
   char *p;
-  int n;
+  Py_ssize_t n;
   unsigned t;
   grand *r = &rand_global;
   gfshare_pyobj *s;
@@ -228,7 +228,7 @@ static PyObject *gfsmeth_add(PyObject *me, PyObject *arg)
 {
   unsigned i;
   char *p;
-  int n;
+  Py_ssize_t n;
   if (!PyArg_ParseTuple(arg, "O&s#:add", convuint, &i, &p, &n)) goto end;
   if (i > 254) VALERR("index must be < 255");
   if (n != GFSHARE_S(me)->sz) VALERR("bad share size");
diff --git a/util.c b/util.c
index 8fab0bf59979e43e26fecd868a6a20d2ac3553f1..d4b7fb060d189ffbea18e68cc1f4d572cb7ef391 100644 (file)
--- a/util.c
+++ b/util.c
@@ -42,6 +42,29 @@ PyObject *getulong(unsigned long w)
     return (PyLong_FromUnsignedLong(w));
 }
 
+static PyObject *i32 = 0;
+static int init_i32(void)
+  { if (!i32 && (i32 = PyInt_FromLong(32)) == 0) return (-1); return (0); }
+
+PyObject *getk64(kludge64 u)
+{
+  PyObject *i = 0, *j = 0, *t;
+  PyObject *rc = 0;
+
+  if (init_i32()) goto end;
+  if ((i = PyLong_FromUnsignedLong(HI64(u))) == 0) goto end;
+  if ((t = PyNumber_InPlaceLshift(i, i32)) == 0) goto end;
+  Py_DECREF(i); i = t;
+  if ((j = PyLong_FromUnsignedLong(LO64(u))) == 0) goto end;
+  if ((t = PyNumber_InPlaceOr(i, j)) == 0) goto end;
+  Py_DECREF(i); i = t;
+  if ((rc = PyNumber_Int(i)) == 0) goto end;
+end:
+  if (i) Py_DECREF(i);
+  if (j) Py_DECREF(j);
+  return (rc);
+}
+
 PyObject *getbool(int b)
 {
   if (b) RETURN_TRUE;
@@ -104,6 +127,28 @@ end:
   return (0);
 }
 
+int convk64(PyObject *o, void *pp)
+{
+  PyObject *i = 0, *t;
+  int rc = 0;
+  uint32 lo, hi;
+
+  if (init_i32()) goto end;
+  if ((i = PyNumber_Int(o)) == 0) goto end;
+  lo = PyInt_AsUnsignedLongMask(i);
+  if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end;
+  Py_DECREF(i); i = t;
+  hi = PyInt_AsUnsignedLongMask(i);
+  if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end;
+  Py_DECREF(i); i = t;
+  if (PyObject_IsTrue(i)) VALERR("out of range");
+  SET64(*(kludge64 *)pp, hi, lo);
+  rc = 1;
+end:
+  if (i) Py_DECREF(i);
+  return (rc);
+}
+
 int convmpw(PyObject *o, void *pp)
 {
   unsigned long u;
@@ -182,9 +227,9 @@ void typeready(PyTypeObject *ty)
   PyDict_SetItemString(ty->tp_dict, "__module__", modname);
 }
 
-PyTypeObject *inittype(PyTypeObject *tyskel)
+PyTypeObject *inittype(PyTypeObject *tyskel, PyTypeObject *meta)
 {
-  PyTypeObject *ty = newtype(&PyType_Type, tyskel, 0);
+  PyTypeObject *ty = newtype(meta, tyskel, 0);
   ty->tp_flags |= Py_TPFLAGS_HEAPTYPE;
   typeready(ty);
   return (ty);
@@ -230,8 +275,8 @@ PyMethodDef *donemethods(void)
 
 /*----- Exceptions --------------------------------------------------------*/
 
-PyObject * mkexc(PyObject *mod, PyObject *base,
-                const char *name, PyMethodDef *mm)
+PyObject *mkexc(PyObject *mod, PyObject *base,
+               const char *name, PyMethodDef *mm)
 {
   PyObject *nameobj = 0;
   PyObject *dict = 0;