chiark / gitweb /
mp: Be more restrictive about implicit conversions.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 5 Apr 2006 11:20:57 +0000 (12:20 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 5 Apr 2006 11:20:57 +0000 (12:20 +0100)
Implicit conversions, e.g., for binary operators, used to be quite
promiscuous.  In particular, if P is a curve point and x is an MP, then
P * x was a point multiplication, but x * P converted P to an integer
(by discarding the y coordinate) and multiplied in integers.  This is
clearly insane.

The new code is pickier about converting things to MPs or GFs.  Explicit
conversions can still be given.  And there will still be great confusion
if you mix Catacomb types with other numeric types.  But things seem
more logical now, at least.

The actual implicit conversion rules are as follows:

  * An MP and any type with a `long' conversion /except/ for GF, FE,
    ECPt or GE may convert to MP.

  * A GF and any type with a `long' conversion /except/ for MP, FE, ECPt
    or GE may convert to GF.

  * Anything which can convert to `long' may convert to FE.  This will
    lead to confusion if you mix FEs and ECPts, but I think that's
    asking for trouble anyway.

  * There are no implicit conversions to ECPt or GE.  However, ECPt can
    be multiplied by anything with a `long' conversion.

I hope this is right.  If not, I'll fiddle some more.

mp.c

diff --git a/mp.c b/mp.c
index f31691e7567b6ab15fdfff981808f9ca809e8949..00b728d147d040ce0917e53e6e67a74ef6b66aa9 100644 (file)
--- a/mp.c
+++ b/mp.c
@@ -269,11 +269,44 @@ int convgf(PyObject *o, void *p)
   return (1);
 }
 
+static mp *implicitmp(PyObject *o)
+{
+  if (!o ||
+      GF_PYCHECK(o) ||
+      ECPT_PYCHECK(o) ||
+      FE_PYCHECK(o) ||
+      GE_PYCHECK(o))
+    return (0);
+  return (tomp(o));
+}
+
+static mp *implicitgf(PyObject *o)
+{
+  if (!o ||
+      MP_PYCHECK(o) ||
+      ECPT_PYCHECK(o) ||
+      FE_PYCHECK(o) ||
+      GE_PYCHECK(o))
+    return (0);
+  return (tomp(o));
+}
+
 static int mpbinop(PyObject *x, PyObject *y, mp **xx, mp **yy)
 {
-  if ((*xx = tomp(x)) == 0)
+  if ((*xx = implicitmp(x)) == 0)
+    return (-1);
+  if ((*yy = implicitmp(y)) == 0) {
+    MP_DROP(*xx);
+    return (-1);
+  }
+  return (0);
+}
+
+static int gfbinop(PyObject *x, PyObject *y, mp **xx, mp **yy)
+{
+  if ((*xx = implicitgf(x)) == 0)
     return (-1);
-  if ((*yy = tomp(y)) == 0) {
+  if ((*yy = implicitgf(y)) == 0) {
     MP_DROP(*xx);
     return (-1);
   }
@@ -286,7 +319,7 @@ static int mpbinop(PyObject *x, PyObject *y, mp **xx, mp **yy)
 #define BINOP(pre, name)                                               \
   static PyObject *pre##_py##name(PyObject *x, PyObject *y) {          \
     mp *xx, *yy, *zz;                                                  \
-    if (mpbinop(x, y, &xx, &yy)) RETURN_NOTIMPL;                       \
+    if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                    \
     zz = pre##_##name(MP_NEW, xx, yy);                                 \
     MP_DROP(xx); MP_DROP(yy);                                          \
     return (pre##_pywrap(zz));                                         \
@@ -330,7 +363,7 @@ static PyObject *mp_pyid(PyObject *x) { RETURN_OBJ(x); }
     mp *xx, *yy;                                                       \
     PyObject *z = 0;                                                   \
     long n;                                                            \
-    if (mpbinop(x, y, &xx, &yy)) RETURN_NOTIMPL;                       \
+    if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                    \
     if (mp_tolong_checked(yy, &n)) goto end;                           \
     if (n < 0)                                                         \
       z = pre##_pywrap(mp_##rname(MP_NEW, xx, -n));                    \
@@ -351,7 +384,7 @@ SHIFTOP(gf, lsr, lsl)
     mp *xx, *yy;                                                       \
     PyObject *z = 0;                                                   \
     INIT_##qq(q) INIT_##rr(r)                                          \
-    if (mpbinop(x, y, &xx, &yy)) RETURN_NOTIMPL;                       \
+    if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                    \
     if (MP_ZEROP(yy))                                                  \
       ZDIVERR("division by zero");                                     \
     pre##_div(ARG_##qq(q), ARG_##rr(r), xx, yy);                       \
@@ -396,7 +429,7 @@ static PyObject *mp_pyexp(PyObject *x, PyObject *y, PyObject *z)
   mp *r = 0;
   PyObject *rc = 0;
 
-  if ((xx = tomp(x)) == 0 || (yy = tomp(y)) == 0 ||
+  if ((xx = implicitmp(x)) == 0 || (yy = implicitmp(y)) == 0 ||
       (z && z != Py_None && (zz = tomp(z)) == 0)) {
     mp_drop(xx); mp_drop(yy); mp_drop(zz);
     RETURN_NOTIMPL;
@@ -876,7 +909,7 @@ Notes:\n\
 };
 
 static PyObject *meth__MP_fromstring(PyObject *me,
-                                   PyObject *arg, PyObject *kw)
+                                    PyObject *arg, PyObject *kw)
 {
   int r = 0;
   char *p;
@@ -1772,7 +1805,7 @@ static PyObject *gf_pyrichcompare(PyObject *x, PyObject *y, int op)
   int xl, yl;
   int b;
 
-  if (mpbinop(x, y, &xx, &yy)) RETURN_NOTIMPL;
+  if (gfbinop(x, y, &xx, &yy)) RETURN_NOTIMPL;
   switch (op) {
     case Py_EQ: b = MP_EQ(xx, yy); break;
     case Py_NE: b = !MP_EQ(xx, yy); break;