From: Mark Wooding Date: Wed, 5 Apr 2006 11:20:57 +0000 (+0100) Subject: mp: Be more restrictive about implicit conversions. X-Git-Tag: 1.0.1~18 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/catacomb-python/commitdiff_plain/bf8910bde6a430a64868ef70319f94e94114c82c?ds=sidebyside mp: Be more restrictive about implicit conversions. 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. --- diff --git a/mp.c b/mp.c index f31691e..00b728d 100644 --- 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;