From 3317491a2bc28732f805c8521777aafa52038793 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sun, 24 Nov 2019 00:41:52 +0000 Subject: [PATCH] ec.c, field.c, group.c: Allow exponents and scalars from prime fields. The idea is that the unit group of a finite field, and the point group of an elliptic curve, can usefully be viewed as modules over a suitable integer quotient ring; and, even more so, prime-order subgroups of these can be considered as one-dimensional vector spaces over prime-order fields. It's therefore helpful to allow elements of the appropriate field as exponents or scalar multipliers as appropriate. Unfortunately it's annoying to check whether we have the /right/ scalar field; we could check, but that does a lot of computation for little benefit. So allow any prime-field element in these positions. I don't (currently) allow a prime-field element as the exponent in `pow' applied to `MP' or `GF'; I'm open to representation on whether this is a good idea. They are permitted in the exponentiation functions attached to the various modular-reduction classes, because the exponent operand in those cases is subject to explicit conversion. --- ec.c | 6 +++++- field.c | 5 ++++- group.c | 5 ++++- t/t-ec.py | 3 ++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ec.c b/ec.c index b96f3f2..d4bd08d 100644 --- a/ec.c +++ b/ec.c @@ -186,7 +186,11 @@ static PyObject *ecpt_pymul(PyObject *x, PyObject *y) ec zz = EC_INIT; if (ECPT_PYCHECK(x)) { PyObject *t; t = x; x = y; y = t; } - if (!ECPT_PYCHECK(y) || (xx = implicitmp(x)) == 0) RETURN_NOTIMPL; + if (!ECPT_PYCHECK(y)) RETURN_NOTIMPL; + if (FE_PYCHECK(x) && FE_F(x)->ops->ty == FTY_PRIME) + xx = F_OUT(FE_F(x), MP_NEW, FE_X(x)); + else if ((xx = implicitmp(x)) == 0) + RETURN_NOTIMPL; ec_imul(ECPT_C(y), &zz, ECPT_P(y), xx); MP_DROP(xx); return (ecpt_pywrap(ECPT_COBJ(y), &zz)); diff --git a/field.c b/field.c index ba00d34..2e99efc 100644 --- a/field.c +++ b/field.c @@ -174,7 +174,10 @@ static PyObject *fe_pyexp(PyObject *x, PyObject *y, PyObject *z) field *ff; mp *xx, *yy; - if (z != Py_None || !FE_PYCHECK(x) || (yy = implicitmp(y)) == 0) + if (z != Py_None || !FE_PYCHECK(x)) RETURN_NOTIMPL; + if (FE_PYCHECK(y) && FE_F(y)->ops->ty == FTY_PRIME) + yy = F_OUT(FE_F(y), MP_NEW, FE_X(y)); + else if ((yy = implicitmp(y)) == 0) RETURN_NOTIMPL; ff = FE_F(x); xx = FE_X(x); MP_COPY(xx); if (MP_NEGP(yy) && F_ZEROP(ff, xx)) ZDIVERR("division by zero"); diff --git a/group.c b/group.c index 8774290..1e93ccc 100644 --- a/group.c +++ b/group.c @@ -589,7 +589,10 @@ static PyObject *ge_pyexp(PyObject *x, PyObject *n, PyObject *m) mp *nn; ge *z; - if (m != Py_None || !GE_PYCHECK(x) || (nn = implicitmp(n)) == 0) + if (m != Py_None || !GE_PYCHECK(x)) RETURN_NOTIMPL; + if (FE_PYCHECK(n) && FE_F(n)->ops->ty == FTY_PRIME) + nn = F_OUT(FE_F(n), MP_NEW, FE_X(n)); + else if ((nn = implicitmp(n)) == 0) RETURN_NOTIMPL; z = G_CREATE(GE_G(x)); G_EXP(GE_G(x), z, GE_X(x), nn); diff --git a/t/t-ec.py b/t/t-ec.py index 467ead5..75dc2be 100644 --- a/t/t-ec.py +++ b/t/t-ec.py @@ -180,7 +180,8 @@ class TestCurves (T.GenericTestMixin): me.assertRaises(TypeError, T.add, Q.point, R.point) me.assertRaises(TypeError, T.mul, kk(1), Q) me.assertEqual(Q - R, 11*P) - #me.assertEqual(P*l(17), Q) + me.assertEqual(l(17)*P, Q) + me.assertEqual(P*l(17), Q) ## Ordering. me.assertTrue(P == P) -- 2.11.0