chiark / gitweb /
ec.c, field.c, group.c: Allow exponents and scalars from prime fields.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 24 Nov 2019 00:41:52 +0000 (00:41 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 11 Apr 2020 11:49:31 +0000 (12:49 +0100)
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
field.c
group.c
t/t-ec.py

diff --git a/ec.c b/ec.c
index 86aa17fcf740c2b979f44a6d3a70bdf6e395dc37..9535240afe0d5aff62d1a437082fef9417b9a132 100644 (file)
--- 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 ba00d349e86259c100146d327e246d75f9fdfa5b..2e99efc26909352f69586b09076ac72ad5fe9124 100644 (file)
--- 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 8774290452fe2bf31a2862a784250aa9034c6e34..1e93ccc339e6fe496c1d33fd4dc826b1529d8ce2 100644 (file)
--- 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);
index 467ead5d4d0e6bffa643a87f3541ca7d8a2c1a0a..75dc2be5b518636eb3b0c01e1397101cd1868496 100644 (file)
--- 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)