algorithms.c (AEADAAD.copy): Propagate the hashed length to the copy.
[catacomb-python] / ec.c
diff --git a/ec.c b/ec.c
index dab6dfe..184dc9e 100644 (file)
--- a/ec.c
+++ b/ec.c
@@ -1,13 +1,11 @@
 /* -*-c-*-
  *
- * $Id$
- *
  * Elliptic curves
  *
  * (c) 2004 Straylight/Edgeware
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of the Python interface to Catacomb.
  *
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * Catacomb/Python is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with Catacomb/Python; if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -190,34 +188,31 @@ static PyObject *ecpt_pymul(PyObject *x, PyObject *y)
   if (ECPT_PYCHECK(x)) { PyObject *t; t = x; x = y; y = t; }
   if (!ECPT_PYCHECK(y) || (xx = tomp(x)) == 0) RETURN_NOTIMPL;
   ec_imul(ECPT_C(y), &zz, ECPT_P(y), xx);
+  MP_DROP(xx);
   return (ecpt_pywrap(ECPT_COBJ(y), &zz));
 }
 
 static long ecpt_pyhash(PyObject *me)
 {
-  long i;
+  uint32 h;
   ec p = EC_INIT;
 
-  EC_OUT(ECPT_C(me), &p, ECPT_P(me));
-  i = 0xe0fdd039; /* random perturbance */
-  if (p.x) i ^= mp_tolong(p.x);
-  if (p.y) i ^= mp_tolong(p.y);
-  if (i == -1) i = -2;
+  getecptout(&p, me);
+  if (EC_ATINF(&p)) h = 0x81d81a94;
+  else h = 0xe0fdd039 ^ (2*mphash(p.x)) ^ (3*mphash(p.y));
   EC_DESTROY(&p);
-  return (i);
+  return (h%LONG_MAX);
 }
 
 static PyObject *ecpt_pyrichcompare(PyObject *x, PyObject *y, int op)
 {
-  ec_curve *c;
-  PyObject *cobj;
   ec p = EC_INIT, q = EC_INIT;
   int b;
   PyObject *rc = 0;
 
-  if (ecbinop(x, y, &c, &cobj, &p, &q)) RETURN_NOTIMPL;
-  EC_OUT(c, &p, &p);
-  EC_OUT(c, &q, &q);
+  if (!ECPT_PYCHECK(y)) RETURN_NOTIMPL;
+  getecptout(&p, x);
+  getecptout(&q, y);
   switch (op) {
     case Py_EQ: b = EC_EQ(&p, &q); break;
     case Py_NE: b = !EC_EQ(&p, &q); break;
@@ -233,7 +228,8 @@ end:
 static PyObject *epmeth_oncurvep(PyObject *me, PyObject *arg)
 {
   if (!PyArg_ParseTuple(arg, ":oncurvep")) return (0);
-  return (getbool(!ec_check(ECPT_C(me), ECPT_P(me))));
+  return (getbool(EC_ATINF(ECPT_P(me)) ||
+                 !EC_CHECK(ECPT_C(me), ECPT_P(me))));
 }
 
 static PyObject *epmeth_dbl(PyObject *me, PyObject *arg)
@@ -256,7 +252,7 @@ static PyObject *epmeth_tobuf(PyObject *me, PyObject *arg)
   if (EC_ATINF(&p))
     n = 2;
   else
-    n = mp_octets(p.x) + mp_octets(p.y) + 4;
+    n = mp_octets(p.x) + mp_octets(p.y) + 6;
   rc = bytestring_pywrap(0, n);
   buf_init(&b, PyString_AS_STRING(rc), n);
   buf_putec(&b, &p);
@@ -287,6 +283,35 @@ static PyObject *epmeth_toraw(PyObject *me, PyObject *arg)
   return (rc);
 }
 
+static PyObject *epmeth_ec2osp(PyObject *me, PyObject *arg, PyObject *kw)
+{
+  buf b;
+  PyObject *rc;
+  char *p;
+  ec_curve *c = ECPT_C(me);
+  ec pp = EC_INIT;
+  unsigned f = EC_EXPLY;
+  int len;
+  static const char *const kwlist[] = { "flags", 0 };
+
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:ec2osp", KWLIST,
+                                  convuint, &f))
+    return (0);
+  len = c->f->noctets * 2 + 1;
+  rc = bytestring_pywrap(0, len);
+  p = PyString_AS_STRING(rc);
+  buf_init(&b, p, len);
+  EC_OUT(c, &pp, ECPT_P(me));
+  if (ec_ec2osp(c, f, &b, &pp)) {
+    Py_DECREF(rc); rc = 0;
+    VALERR("invalid flags");
+  }
+  EC_DESTROY(&pp);
+  _PyString_Resize(&rc, BLEN(&b));
+end:
+  return (rc);
+}
+
 static PyObject *epget_curve(PyObject *me, void *hunoz)
   { RETURN_OBJ(ECPT_COBJ(me)); }
 
@@ -388,9 +413,9 @@ static int ecptxl_3(ec_curve *c, ec *p,
 
   if (!x || !y || !z) TYERR("missing argument");
   if (!c) VALERR("internal form with no curve!");
-  if ((p->x == coord_in(c->f, x)) == 0 ||
-      (p->y == coord_in(c->f, y)) == 0 ||
-      (z != Py_None && (p->z = coord_in(c->f, z))) == 0)
+  if ((p->x = coord_in(c->f, x)) == 0 ||
+      (p->y = coord_in(c->f, y)) == 0 ||
+      (z != Py_None && (p->z = coord_in(c->f, z)) == 0))
     goto end;
   if (!p->z) p->z = MP_COPY(c->f->one); /* just in case */
   rc = 0;
@@ -428,19 +453,19 @@ static int ecptxl_1(ec_curve *c, ec *p, PyObject *x)
     getecptout(p, x);
     goto fix;
   } else if (PyString_Check(x)) {
-    if (PyObject_AsReadBuffer(x, &q, 0))
+    if (PyObject_AsReadBuffer(x, &q, &n))
       goto end;
     qd.p = q;
     qd.e = 0;
     if (!ec_ptparse(&qd, p))
-      SYNERR(qd.e);
+      VALERR(qd.e);
     goto fix;
   } else if (c && (xx = tomp(x)) != 0) {
     xx = F_IN(c->f, xx, xx);
     if (!EC_FIND(c, p, xx)) VALERR("not on the curve");
   } else if (PySequence_Check(x)) {
     t = x; x = 0;
-    n = PySequence_Size(t);
+    n = PySequence_Size(t); if (n < 0) goto end;
     if (n != 2 && (n != 3 || !c))
       TYERR("want sequence of two or three items");
     if ((x = PySequence_GetItem(t, 0)) == 0 ||
@@ -448,6 +473,7 @@ static int ecptxl_1(ec_curve *c, ec *p, PyObject *x)
        (n == 3 && (z = PySequence_GetItem(t, 2)) == 0))
       goto end;
     rc = (n == 2) ? ecptxl_2(c, p, x, y) : ecptxl_3(c, p, x, y, z);
+    goto end;
   } else
     TYERR("can't convert to curve point");
   goto ok;
@@ -476,14 +502,14 @@ static PyObject *ecptnc_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   PyObject *x = 0, *y = 0, *z = 0;
   ec p = EC_INIT;
-  char *kwlist[] = { "x", "y", 0 };
+  static const char *const kwlist[] = { "x", "y", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OO:new", kwlist, &x, &y) ||
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OO:new", KWLIST, &x, &y) ||
       ecptxl(0, &p, x, y, z))
     goto end;
   return (ecpt_pywrapout(ty, &p));
 end:
-  EC_DESTROY(&p);
+  mp_drop(p.x); mp_drop(p.y); mp_drop(p.z);
   return (0);
 }
 
@@ -494,8 +520,8 @@ static PyObject *ecpt_pyint(PyObject *me)
   PyObject *rc = 0;
   if (EC_ATINF(ECPT_P(me))) VALERR("point at infinity");
   getecptout(&p, me);
-  if (mp_tolong_checked(p.x, &l)) goto end;
-  rc = PyInt_FromLong(l);
+  if (!mp_tolong_checked(p.x, &l, 0)) rc = PyInt_FromLong(l);
+  else rc = mp_topylong(p.x);
 end:
   EC_DESTROY(&p);
   return (rc);
@@ -517,15 +543,15 @@ static PyObject *ecpt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   PyObject *x = 0, *y = 0, *z = 0;
   ec p = EC_INIT;
-  char *kwlist[] = { "x", "y", "z", 0 };
+  static const char *const kwlist[] = { "x", "y", "z", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OOO:new", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OOO:new", KWLIST,
                                   &x, &y, &z) ||
       ecptxl(ECCURVE_C(ty), &p, x, y, z))
     goto end;
   return (ecpt_pywrap((PyObject *)ty, &p));
 end:
-  EC_DESTROY(&p);
+  mp_drop(p.x); mp_drop(p.y); mp_drop(p.z);
   return (0);
 }
 
@@ -590,7 +616,7 @@ static PyNumberMethods ecpt_pynumber = {
 
 static PyTypeObject ecpt_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
-  "catacomb.ECPt",                     /* @tp_name@ */
+  "ECPt",                              /* @tp_name@ */
   sizeof(ecpt_pyobj),                  /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
 
@@ -614,7 +640,9 @@ static PyTypeObject ecpt_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-"Elliptic curve points, not associated with any curve.",
+"ECPt([X, [Y]]): elliptic curve points, not associated with any curve.\n\
+  X alone may be None, an existing point, a string 'X, Y', an\n\
+  x-coordinate, or a pair (X, Y); X and Y should be a coordinate pair.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -653,6 +681,7 @@ static PyGetSetDef ecpt_pygetset[] = {
 static PyMethodDef ecpt_pymethods[] = {
 #define METHNAME(func) epmeth_##func
   METH (toraw,         "X.toraw() -> BIN")
+  KWMETH(ec2osp,       "X.ec2osp([flags = EC_EXPLY]) -> BIN")
   METH (dbl,           "X.dbl() -> X + X")
   METH (oncurvep,      "X.oncurvep() -> BOOL")
 #undef METHNAME
@@ -704,7 +733,7 @@ static PyNumberMethods ecptcurve_pynumber = {
 
 static PyTypeObject ecptcurve_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
-  "catacomb.ECPtCurve",                        /* @tp_name@ */
+  "ECPtCurve",                         /* @tp_name@ */
   sizeof(ecpt_pyobj),                  /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
 
@@ -755,10 +784,14 @@ static PyTypeObject ecptcurve_pytype_skel = {
 
 static PyObject *eccurve_pyrichcompare(PyObject *x, PyObject *y, int op)
 {
-  int b = ec_samep(ECCURVE_C(x), ECCURVE_C(y));
+  int b;
+
+  assert(ECCURVE_PYCHECK(x));
+  if (!ECCURVE_PYCHECK(y)) RETURN_NOTIMPL;
+  b = ec_samep(ECCURVE_C(x), ECCURVE_C(y));
   switch (op) {
     case Py_EQ: break;
-    case Py_NE: b = !b;
+    case Py_NE: b = !b; break;
     default: TYERR("can't order elliptic curves");
   }
   return (getbool(b));
@@ -773,10 +806,10 @@ static int ecmmul_fill(void *pp, PyObject *me, PyObject *x, PyObject *m)
 {
   ec_mulfactor *f = pp;
 
+  EC_CREATE(&f->base);
   if (getecpt(ECCURVE_C(me), &f->base, x) ||
       (f->exp = getmp(m)) == 0)
     return (-1);
-  f->base = *ECPT_P(x);
   return (0);
 }
 
@@ -803,7 +836,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;
@@ -814,7 +847,31 @@ static PyObject *meth__ECPtCurve_fromraw(PyObject *me, PyObject *arg)
   buf_init(&b, p, len);
   cc = ECCURVE_C(me);
   if (ec_getraw(cc, &b, &pp))
-    SYNERR("bad point");
+    VALERR("bad point");
+  EC_IN(cc, &pp, &pp);
+  rc = Py_BuildValue("(NN)", ecpt_pywrap(me, &pp), bytestring_pywrapbuf(&b));
+end:
+  return (rc);
+}
+
+static PyObject *meth__ECPtCurve_os2ecp(PyObject *me,
+                                       PyObject *arg, PyObject *kw)
+{
+  char *p;
+  Py_ssize_t len;
+  buf b;
+  PyObject *rc = 0;
+  ec_curve *cc;
+  unsigned f = EC_XONLY | EC_LSB | EC_SORT | EC_EXPLY;
+  ec pp = EC_INIT;
+  static const char *const kwlist[] = { "class", "buf", "flags", 0 };
+
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|O&:os2ecp", KWLIST,
+                                  &me, &p, &len, convuint, &f))
+    return (0);
+  buf_init(&b, p, len);
+  cc = ECCURVE_C(me);
+  if (ec_os2ecp(cc, f, &b, &pp)) VALERR("bad point");
   EC_IN(cc, &pp, &pp);
   rc = Py_BuildValue("(NN)", ecpt_pywrap(me, &pp), bytestring_pywrapbuf(&b));
 end:
@@ -825,7 +882,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;
 
@@ -848,7 +905,7 @@ static PyObject *meth__ECPt_parse(PyObject *me, PyObject *arg)
   if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p)) goto end;
   qd.p = p;
   qd.e = 0;
-  if (!ec_ptparse(&qd, &pp)) SYNERR(qd.e);
+  if (!ec_ptparse(&qd, &pp)) VALERR(qd.e);
   rc = Py_BuildValue("(Ns)", ecpt_pywrapout(me, &pp), qd.p);
 end:
   return (rc);
@@ -885,11 +942,11 @@ end:
 
 static PyObject *ecmeth_rand(PyObject *me, PyObject *arg, PyObject *kw)
 {
-  char *kwlist[] = { "rng", 0 };
+  static const char *const kwlist[] = { "rng", 0 };
   grand *r = &rand_global;
   ec p = EC_INIT;
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", KWLIST,
                                   convgrand, &r))
     return (0);
   ec_rand(ECCURVE_C(me), &p, r);
@@ -903,17 +960,17 @@ static PyObject *eccurve_dopywrap(PyTypeObject *ty,
   eccurve_pyobj *cobj = newtype(ty, 0, c->ops->name);
   cobj->c = c;
   cobj->fobj = fobj;
-  cobj->ty.type.tp_basicsize = sizeof(ecpt_pyobj);
-  cobj->ty.type.tp_base = ecptcurve_pytype;
+  cobj->ty.ht_type.tp_basicsize = sizeof(ecpt_pyobj);
+  cobj->ty.ht_type.tp_base = ecptcurve_pytype;
   Py_INCREF(ecptcurve_pytype);
-  cobj->ty.type.tp_flags = (Py_TPFLAGS_DEFAULT |
-                           Py_TPFLAGS_BASETYPE |
-                           Py_TPFLAGS_CHECKTYPES |
-                           Py_TPFLAGS_HEAPTYPE);
-  cobj->ty.type.tp_alloc = PyType_GenericAlloc;
-  cobj->ty.type.tp_free = 0;
-  cobj->ty.type.tp_new = ecpt_pynew;
-  PyType_Ready(&cobj->ty.type);
+  cobj->ty.ht_type.tp_flags = (Py_TPFLAGS_DEFAULT |
+                              Py_TPFLAGS_BASETYPE |
+                              Py_TPFLAGS_CHECKTYPES |
+                              Py_TPFLAGS_HEAPTYPE);
+  cobj->ty.ht_type.tp_alloc = PyType_GenericAlloc;
+  cobj->ty.ht_type.tp_free = 0;
+  cobj->ty.ht_type.tp_new = ecpt_pynew;
+  typeready(&cobj->ty.ht_type);
   return ((PyObject *)cobj);
 }
 
@@ -945,10 +1002,10 @@ static PyObject *eccurve_pynew(PyTypeObject *ty,
 {
   PyObject *fobj;
   PyObject *cobj = 0;
-  char *kwlist[] = { "field", "a", "b", 0 };
+  static const char *const kwlist[] = { "field", "a", "b", 0 };
   mp *aa = 0, *bb = 0;
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&O&", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&O&", KWLIST,
                                   field_pytype, &fobj,
                                   convmp, &aa, convmp, &bb))
     goto end;
@@ -972,7 +1029,7 @@ static PyObject *meth__ECCurve_parse(PyObject *me, PyObject *arg)
   qd.p = p;
   qd.e = 0;
   if ((c = ec_curveparse(&qd)) == 0)
-    SYNERR(qd.e);
+    VALERR(qd.e);
   rc = eccurve_pywrap(0, c);
 end:
   return (rc);
@@ -984,7 +1041,7 @@ static PyObject *ecget_name(PyObject *me, void *hunoz)
 static PyObject *ecget_a(PyObject *me, void *hunoz)
   { return (fe_pywrap(ECCURVE_FOBJ(me), MP_COPY(ECCURVE_C(me)->a))); }
 
-static PyObject *ecget_b(PyObject *me, void *hunoz) 
+static PyObject *ecget_b(PyObject *me, void *hunoz)
   { return (fe_pywrap(ECCURVE_FOBJ(me), MP_COPY(ECCURVE_C(me)->b))); }
 
 static PyObject *ecget_field(PyObject *me, void *hunoz)
@@ -1002,21 +1059,21 @@ static PyGetSetDef eccurve_pygetset[] = {
   GET  (inf,           "E.inf -> point at infinity of this curve")
 #undef GETSETNAME
   { 0 }
-};  
+};
 
 static PyMethodDef eccurve_pymethods[] = {
 #define METHNAME(name) ecmeth_##name
   METH (mmul,          "\
 E.mmul([(P0, N0), (P1, N1), ...]) = N0 P0 + N1 P1 + ...")
   METH (find,          "E.find(X) -> P")
-  KWMETH(rand,         "E.rand(rng = rand) ->P")
+  KWMETH(rand,         "E.rand([rng = rand]) -> P")
 #undef METHNAME
   { 0 }
 };
 
 static PyTypeObject eccurve_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
-  "catacomb.ECCurve",                  /* @tp_name@ */
+  "ECCurve",                           /* @tp_name@ */
   sizeof(eccurve_pyobj),               /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
 
@@ -1039,7 +1096,7 @@ static PyTypeObject eccurve_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "An elliptic curve.  Abstract class.",
+"An elliptic curve.  Abstract class.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -1070,7 +1127,7 @@ static PyObject *ecprimecurve_pynew(PyTypeObject *ty,
 
 static PyTypeObject ecprimecurve_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
-  "catacomb.ECPrimeCurve",             /* @tp_name@ */
+  "ECPrimeCurve",                      /* @tp_name@ */
   sizeof(eccurve_pyobj),               /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
 
@@ -1093,7 +1150,8 @@ static PyTypeObject ecprimecurve_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "An elliptic curve over a prime field.  Use ecprimeprojcurve.",
+"ECPrimeCurve(FIELD, A, B): an elliptic curve over a prime field.\n\
+  Use ECPrimeProjCurve instead.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -1124,7 +1182,7 @@ static PyObject *ecprimeprojcurve_pynew(PyTypeObject *ty,
 
 static PyTypeObject ecprimeprojcurve_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
-  "catacomb.ECPrimeProjCurve",         /* @tp_name@ */
+  "ECPrimeProjCurve",                  /* @tp_name@ */
   sizeof(eccurve_pyobj),               /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
 
@@ -1147,7 +1205,8 @@ static PyTypeObject ecprimeprojcurve_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "An elliptic curve over a prime field, using projective coordinates.",
+"ECPrimeProjCurve(FIELD, A, B): an elliptic curve over a prime field\n\
+  using projective coordinates.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -1178,7 +1237,7 @@ static PyObject *ecbincurve_pynew(PyTypeObject *ty,
 
 static PyTypeObject ecbincurve_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
-  "catacomb.ECBinCurve",               /* @tp_name@ */
+  "ECBinCurve",                                /* @tp_name@ */
   sizeof(eccurve_pyobj),               /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
 
@@ -1201,7 +1260,8 @@ static PyTypeObject ecbincurve_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "An elliptic curve over a binary field.  Use ecbinprojcurve.",
+"ECBinCurve(FIELD, A, B): an elliptic curve over a binary field.\n\
+  Use ECBinProjCurve instead.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -1232,7 +1292,7 @@ static PyObject *ecbinprojcurve_pynew(PyTypeObject *ty,
 
 static PyTypeObject ecbinprojcurve_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
-  "catacomb.ECBinProjCurve",           /* @tp_name@ */
+  "ECBinProjCurve",                    /* @tp_name@ */
   sizeof(eccurve_pyobj),               /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
 
@@ -1255,7 +1315,8 @@ static PyTypeObject ecbinprojcurve_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "An elliptic curve over a binary field, using projective coordinates.",
+"ECBinProjCurve(FIELD, A, B): an elliptic curve over a binary field,\n\
+  using projective coordinates.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -1316,10 +1377,10 @@ static PyObject *ecinfo_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
   ec_info ei = { 0 };
   PyObject *e, *g;
-  char *kwlist[] = { "curve", "G", "r", "h", 0 };
+  static const char *const kwlist[] = { "curve", "G", "r", "h", 0 };
   ecinfo_pyobj *rc = 0;
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O&O&:new", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O&O&:new", KWLIST,
                                   eccurve_pytype, &e, ecpt_pytype, &g,
                                   convmp, &ei.r, convmp, &ei.h))
     goto end;
@@ -1327,7 +1388,7 @@ static PyObject *ecinfo_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
     TYERR("point not from this curve");
   ei.c = ECCURVE_C(e);
   EC_CREATE(&ei.g);
-  EC_COPY(&ei.g, ECPT_P(g));
+  EC_OUT(ei.c, &ei.g, ECPT_P(g));
   rc = (ecinfo_pyobj *)ty->tp_alloc(ty, 0);
   rc->ei = ei;
   rc->cobj = e;
@@ -1352,7 +1413,7 @@ static PyObject *meth__ECInfo_parse(PyObject *me, PyObject *arg)
   qd.p = p;
   qd.e = 0;
   if (ec_infoparse(&qd, &ei))
-    SYNERR(qd.e);
+    VALERR(qd.e);
   rc = Py_BuildValue("(Ns)", ecinfo_pywrap(&ei), qd.p);
 end:
   return (rc);
@@ -1387,11 +1448,11 @@ end:
 
 static PyObject *eimeth_check(PyObject *me, PyObject *arg, PyObject *kw)
 {
-  char *kwlist[] = { "rng", 0 };
+  static const char *const kwlist[] = { "rng", 0 };
   grand *r = &rand_global;
   const char *p;
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:check", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:check", KWLIST,
                                   convgrand, &r))
     goto end;
   if ((p = ec_checkinfo(ECINFO_EI(me), r)) != 0)
@@ -1430,14 +1491,14 @@ static PyGetSetDef ecinfo_pygetset[] = {
 
 static PyMethodDef ecinfo_pymethods[] = {
 #define METHNAME(name) eimeth_##name
-  KWMETH(check,                "I.check() -> None")
+  KWMETH(check,                "I.check([rng = rand]) -> None")
 #undef METHNAME
   { 0 }
 };
 
 static PyTypeObject ecinfo_pytype_skel = {
   PyObject_HEAD_INIT(0) 0,             /* Header */
-  "catacomb.ECInfo",                   /* @tp_name@ */
+  "ECInfo",                            /* @tp_name@ */
   sizeof(ecinfo_pyobj),                        /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
 
@@ -1460,7 +1521,7 @@ static PyTypeObject ecinfo_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "Elliptic curve domain parameters.",
+"ECInfo(CURVE, G, R, H): elliptic curve domain parameters.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -1487,12 +1548,13 @@ static PyTypeObject ecinfo_pytype_skel = {
 
 static PyMethodDef methods[] = {
 #define METHNAME(func) meth_##func
-  METH (_ECPt_frombuf,         "frombuf(E, STR) -> (P, REST)")
-  METH (_ECPtCurve_fromraw,    "fromraw(E, STR) -> (P, REST)")
-  METH (_ECPt_parse,           "parse(E, STR) -> (P, REST)")
-  METH (_ECCurve_parse,        "parse(STR) -> (E, REST)")
-  METH (_ECInfo_parse,         "parse(STR) -> (I, REST)")
-  METH (_ECInfo__curven,       "_curven(N) -> I")
+  METH (_ECPt_frombuf,         "frombuf(E, STR) -> (P, REST)")
+  METH (_ECPtCurve_fromraw,    "fromraw(E, STR) -> (P, REST)")
+  KWMETH(_ECPtCurve_os2ecp,    "os2ecp(E, STR, [flags = ...]) -> (P, REST)")
+  METH (_ECPt_parse,           "parse(E, STR) -> (P, REST)")
+  METH (_ECCurve_parse,        "parse(STR) -> (E, REST)")
+  METH (_ECInfo_parse,         "parse(STR) -> (I, REST)")
+  METH (_ECInfo__curven,       "_curven(N) -> I")
 #undef METHNAME
   { 0 }
 };
@@ -1528,7 +1590,7 @@ static PyObject *namedcurves(void)
     }
     c = PyInt_FromLong(i);
   found:
-    PyDict_SetItemString(d, (/*unconst*/ char *)ectab[i].name, c);
+    PyDict_SetItemString(d, (/*unconst*/ char *)p, c);
     Py_DECREF(c);
   }
   ncurves = i;