mp.c: Check that CRT moduli are actually positive.
[catacomb-python] / mp.c
diff --git a/mp.c b/mp.c
index e4f5980..77f7c3c 100644 (file)
--- a/mp.c
+++ b/mp.c
@@ -795,7 +795,7 @@ static PyGetSetDef mp_pygetset[] = {
 
 static PyMethodDef mp_pymethods[] = {
 #define METHNAME(func) mpmeth_##func
-  METH (jacobi,        "X.jacobi(Y) -> Jacobi symbol (Y/X) (NB inversion!)")
+  METH (jacobi,        "X.jacobi(Y) -> Jacobi symbol (Y|X) (NB inversion!)")
   METH (setbit,        "X.setbit(N) -> X with bit N set")
   METH (clearbit,      "X.clearbit(N) -> X with bit N clear")
   METH (testbit,       "X.testbit(N) -> true/false if bit N set/clear in X")
@@ -809,14 +809,14 @@ static PyMethodDef mp_pymethods[] = {
   METH (modsqrt,       "X.modsqrt(Y) -> square root of Y mod X, if X prime")
   METH (leastcongruent,
         "X.leastcongruent(B, M) -> smallest Z >= B with Z == X (mod M)")
-  KWMETH(primep,       "X.primep(rng = rand) -> true/false if X is prime")
-  KWMETH(tostring,     "X.tostring(radix = 10) -> STR")
-  KWMETH(storel,       "X.storel(len = -1) -> little-endian bytes")
-  KWMETH(storeb,       "X.storeb(len = -1) -> big-endian bytes")
+  KWMETH(primep,       "X.primep([rng = rand]) -> true/false if X is prime")
+  KWMETH(tostring,     "X.tostring([radix = 10]) -> STR")
+  KWMETH(storel,       "X.storel([len = -1]) -> little-endian bytes")
+  KWMETH(storeb,       "X.storeb([len = -1]) -> big-endian bytes")
   KWMETH(storel2c,
-        "X.storel2c(len = -1) -> little-endian bytes, two's complement")
+        "X.storel2c([len = -1]) -> little-endian bytes, two's complement")
   KWMETH(storeb2c,
-        "X.storeb2c(len = -1) -> big-endian bytes, two's complement")
+        "X.storeb2c([len = -1]) -> big-endian bytes, two's complement")
   METH (tobuf,         "X.tobuf() -> buffer format")
 #undef METHNAME
   { 0 }
@@ -892,11 +892,15 @@ static PyTypeObject mp_pytype_skel = {
 
   /* @tp_doc@ */
 "Multiprecision integers, similar to `long' but more efficient and\n\
-versatile.  Support all the standard arithmetic operations.\n\
+versatile.  Support all the standard arithmetic operations, with\n\
+implicit conversions from `PrimeFilter', and other objects which\n\
+convert to `long'.\n\
 \n\
-Constructor mp(X, radix = R) attempts to convert X to an `mp'.  If\n\
+Constructor MP(X, [radix = R]) attempts to convert X to an `MP'.  If\n\
 X is a string, it's read in radix-R form, or we look for a prefix\n\
-if R = 0.  Other acceptable things are ints and longs.\n\
+if R = 0.  Other acceptable things are field elements, elliptic curve\n\
+points, group elements, Python `int' and `long' objects, and anything\n\
+with an integer conversion.\n\
 \n\
 Notes:\n\
 \n\
@@ -1733,6 +1737,7 @@ static PyObject *mpcrt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   for (i = 0; i < n; i++) {
     if ((x = PySequence_GetItem(q, i)) == 0) goto end;
     xx = getmp(x); Py_DECREF(x); if (!xx) goto end;
+    if (MP_CMP(xx, <=, MP_ZERO)) VALERR("moduli must be positive");
     v[i].m = xx; v[i].n = 0; v[i].ni = 0; v[i].nni = 0;
   }
   c = (mpcrt_pyobj *)ty->tp_alloc(ty, 0);
@@ -1999,13 +2004,13 @@ static PyMethodDef gf_pymethods[] = {
   METH (irreduciblep,  "X.irreduciblep() -> true/false")
 #undef METHNAME
 #define METHNAME(func) mpmeth_##func
-  KWMETH(tostring,     "X.tostring(radix = 10) -> STR")
-  KWMETH(storel,       "X.storel(len = -1) -> little-endian bytes")
-  KWMETH(storeb,       "X.storeb(len = -1) -> big-endian bytes")
+  KWMETH(tostring,     "X.tostring([radix = 10]) -> STR")
+  KWMETH(storel,       "X.storel([len = -1]) -> little-endian bytes")
+  KWMETH(storeb,       "X.storeb([len = -1]) -> big-endian bytes")
   KWMETH(storel2c,
-        "X.storel2c(len = -1) -> little-endian bytes, two's complement")
+        "X.storel2c([len = -1]) -> little-endian bytes, two's complement")
   KWMETH(storeb2c,
-        "X.storeb2c(len = -1) -> big-endian bytes, two's complement")
+        "X.storeb2c([len = -1]) -> big-endian bytes, two's complement")
   METH (tobuf,         "X.tobuf() -> buffer format")
 #undef METHNAME
   { 0 }
@@ -2083,9 +2088,11 @@ static PyTypeObject gf_pytype_skel = {
 "Binary polynomials.  Support almost all the standard arithmetic\n\
 operations.\n\
 \n\
-Constructor gf(X, radix = R) attempts to convert X to a `gf'.  If\n\
+Constructor GF(X, [radix = R]) attempts to convert X to a `GF'.  If\n\
 X is a string, it's read in radix-R form, or we look for a prefix\n\
-if R = 0.  Other acceptable things are ints and longs.\n\
+if R = 0.  Other acceptable things are field elements, elliptic curve\n\
+points, group elements, Python `int' and `long' objects, and anything\n\
+with an integer conversion.\n\
 \n\
 The name is hopelessly wrong from a technical point of view, but\n\
 but it's much easier to type than `p2' or `c2' or whatever.\n\
@@ -2466,13 +2473,13 @@ and normal basis representations.",
 static PyMethodDef methods[] = {
 #define METHNAME(func) meth_##func
   KWMETH(_MP_fromstring,       "\
-fromstring(STR, radix = 0) -> (X, REST)\n\
+fromstring(STR, [radix = 0]) -> (X, REST)\n\
 \n\
 Parse STR as a large integer, according to radix.  If radix is zero,\n\
 read a prefix from STR to decide radix: allow `0' for octal, `0x' for hex\n\
 or `R_' for other radix R.")
   KWMETH(_GF_fromstring,       "\
-fromstring(STR, radix = 0) -> (X, REST)\n\
+fromstring(STR, [radix = 0]) -> (X, REST)\n\
 \n\
 Parse STR as a binary polynomial, according to radix.  If radix is zero,\n\
 read a prefix from STR to decide radix: allow `0' for octal, `0x' for hex\n\