Much wider support for Catacomb in all its glory.
[catacomb-perl] / mp.xs
diff --git a/mp.xs b/mp.xs
index 5d78908..9eb7fe2 100644 (file)
--- a/mp.xs
+++ b/mp.xs
@@ -34,8 +34,7 @@ new(me, sv = 0, radix = 0)
        SV *sv
        int radix
        CODE:
-       RETVAL = sv ? mp_fromsv(sv, "sv", 
-                               "Catacomb::MP", radix, 1) : MP_ZERO;
+       RETVAL = sv ? mp_fromsv(sv, "sv", radix, 1) : MP_ZERO;
        OUTPUT:
        RETVAL
 
@@ -73,6 +72,32 @@ loadl(me, sv)
        OUTPUT:
        RETVAL
 
+mp *
+loadb2c(me, sv)
+       SV *me
+       SV *sv
+       PREINIT:
+       char *p;
+       STRLEN len;
+       CODE:
+       p = SvPV(sv, len);
+       RETVAL = mp_loadb2c(MP_NEW, p, len);
+       OUTPUT:
+       RETVAL
+
+mp *
+loadl2c(me, sv)
+       SV *me
+       SV *sv
+       PREINIT:
+       char *p;
+       STRLEN len;
+       CODE:
+       p = SvPV(sv, len);
+       RETVAL = mp_loadl2c(MP_NEW, p, len);
+       OUTPUT:
+       RETVAL
+
 int
 metrics(m)
        mp *m
@@ -80,7 +105,7 @@ metrics(m)
        XSINTERFACE_FUNC
        XSINTERFACE_FUNC_SETMP
        INTERFACE:
-       octets bits
+       octets bits octets2c
 
 SV *
 storeb(m, i = -1)
@@ -89,7 +114,13 @@ storeb(m, i = -1)
        PREINIT:
        size_t sz;
        CODE:
-       sz = (i < 0) ? mp_octets(m) : i;
+       if (i >= 0)
+         sz = i;
+       else {
+         sz = mp_octets(m);
+         if (!sz) 
+           sz = 1;
+       }
        RETVAL = NEWSV(0, sz ? sz : 1);
        mp_storeb(m, SvPVX(RETVAL), sz);
        SvCUR_set(RETVAL, sz);
@@ -113,6 +144,36 @@ storel(m, i = -1)
        RETVAL
 
 SV *
+storeb2c(m, i = -1)
+       mp *m
+       int i
+       PREINIT:
+       size_t sz;
+       CODE:
+       sz = (i < 0) ? mp_octets2c(m) : i;
+       RETVAL = NEWSV(0, sz ? sz : 1);
+       mp_storeb(m, SvPVX(RETVAL), sz);
+       SvCUR_set(RETVAL, sz);
+       SvPOK_on(RETVAL);
+       OUTPUT:
+       RETVAL
+
+SV *
+storel2c(m, i = -1)
+       mp *m
+       int i
+       PREINIT:
+       size_t sz;
+       CODE:
+       sz = (i < 0) ? mp_octets2c(m) : i;
+       RETVAL = NEWSV(0, sz ? sz : 1);
+       mp_storel(m, SvPVX(RETVAL), sz);
+       SvCUR_set(RETVAL, sz);
+       SvPOK_on(RETVAL);
+       OUTPUT:
+       RETVAL
+
+SV *
 tostring(m, radix = 10)
        mp *m
        int radix
@@ -122,6 +183,25 @@ tostring(m, radix = 10)
        OUTPUT:
        RETVAL
 
+void
+fromstring(me, s, radix = 10)
+       SV *me
+       SV *s
+       int radix
+       PREINIT:
+       mptext_stringctx ms;
+       STRLEN len;
+       mp *x;
+       PPCODE:
+       ms.buf = SvPV(s, len);
+       ms.lim = ms.buf + len;
+       x = mp_read(MP_NEW, radix, &mptext_stringops, &ms);
+       if (x) {
+         XPUSHs(RET_MP(x));
+         if (GIMME_V == G_ARRAY)
+           XPUSHs(sv_2mortal(newSVpvn(ms.buf, ms.lim - ms.buf)));
+       }
+
 SV *
 toint(m)
        mp *m
@@ -146,7 +226,7 @@ unop(a)
        XSINTERFACE_FUNC
        XSINTERFACE_FUNC_SETMP
        INTERFACE:
-       not sqr sqrt
+       not not2c sqr sqrt
 
 mp *
 neg(a)
@@ -176,7 +256,7 @@ binop(a, b)
        XSINTERFACE_FUNC
        XSINTERFACE_FUNC_SETMP
        INTERFACE:
-       add sub mul and or xor
+       add sub mul and2c or2c nand2c nor2c xor2c and or nand nor xor exp
 
 mp *
 shiftop(a, n)
@@ -188,7 +268,29 @@ shiftop(a, n)
        XSINTERFACE_FUNC
        XSINTERFACE_FUNC_SETMP
        INTERFACE:
-       lsl lsr
+       lsl lsr lsl2c lsr2c
+
+bool
+testbitop(a, n)
+       mp *a
+       unsigned long n
+       INTERFACE_MACRO:
+       XSINTERFACE_FUNC
+       XSINTERFACE_FUNC_SETMP
+       INTERFACE:
+       testbit testbit2c
+
+mp *
+flipbits(a, n)
+       mp *a
+       unsigned long n
+       C_ARGS:
+       MP_NEW, a, n
+       INTERFACE_MACRO:
+       XSINTERFACE_FUNC
+       XSINTERFACE_FUNC_SETMP
+       INTERFACE:
+       setbit clearbit setbit2c clearbit2c
 
 int
 mp_cmp(a, b)
@@ -215,6 +317,11 @@ mp *
 mp_modsqrt(p, x)
        mp *p
        mp *x
+       INIT:
+       if (!MP_POSP(p) || !MP_ODDP(p))
+         croak("p is not positive and odd");
+       if (mp_jacobi(x, p) != 1)
+         croak("x not a quadratic residue mod p");
        C_ARGS:
        MP_NEW, x, p
 
@@ -239,7 +346,7 @@ div(a, b)
          case G_VOID:
            break;
          default:
-           mp_div(&q, &r, a, b);
+           mp_div(&q, 0, a, b);
            EXTEND(SP, 1);
            PUSHs(RET_MP(q));
            break;
@@ -278,64 +385,21 @@ odd(m)
        PPCODE:
        t = mp_odd(MP_NEW, m, &s);
        EXTEND(SP, 2);
-       PUSHs(RET_MP(t));
        PUSHs(sv_2mortal(newSViv(s)));
+       PUSHs(RET_MP(t));
 
-int
-smallfactor(x)
-       mp *x
-       CODE:
-       RETVAL = pfilt_smallfactor(x);
-       OUTPUT:
-       RETVAL
-
-MP_Reduce *
-makereduce(x)
-       mp *x
-       CODE:
-       if (!MP_POSP(x))
-         croak("Argument to Catacomb::MP::makereduce must be positive");
-       RETVAL = CREATE(MP_Reduce);     
-       mpreduce_create(RETVAL, x);
-       OUTPUT:
-       RETVAL
+MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = pgen_
 
-MP_Mont *
-mont(x)
+bool
+pgen_primep(x, r = &rand_global)
        mp *x
-       CODE:
-       if (!MP_POSP(x))
-         croak("Argument to Catacomb::MP::mont must be positive");
-       if (!MP_ODDP(x))
-         croak("Argument to Catacomb::MP::mont must be odd");
-       RETVAL = CREATE(MP_Mont);       
-       mpmont_create(RETVAL, x);
-       OUTPUT:
-       RETVAL
+       grand *r
 
-MP_Barrett *
-barrett(x)
-       mp *x
-       CODE:
-       if (!MP_POSP(x))
-         croak("Argument to Catacomb::MP::barrett must be positive");
-       RETVAL = CREATE(mpbarrett);
-       mpbarrett_create(RETVAL, x);
-       OUTPUT:
-       RETVAL
+MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = pfilt_
 
-MP_Prime_Rabin *
-rabin(x)
+int
+pfilt_smallfactor(x)
        mp *x
-       CODE:
-       if (!MP_POSP(x))
-         croak("Argument to Catacomb::MP::rabin must be positive");
-       if (!MP_ODDP(x))
-         croak("Argument to Catacomb::MP::rabin must be odd");
-       RETVAL = CREATE(MP_Prime_Rabin);
-       rabin_create(RETVAL, x);
-       OUTPUT:
-       RETVAL
 
 MODULE = Catacomb PACKAGE = Catacomb::MP::Mont PREFIX = mpmont_
 
@@ -344,12 +408,11 @@ new(me, x)
        SV *me
        mp *x
        CODE:
-       if (!MP_POSP(x))
-         croak("Argument to Catacomb::MP::Mont::new must be positive");
-       if (!MP_ODDP(x))
-         croak("Argument to Catacomb::MP::Mont::new must be odd");
-       RETVAL = CREATE(MP_Mont);       
-       mpmont_create(RETVAL, x);
+       RETVAL = CREATE(MP_Mont);
+       if (mpmont_create(RETVAL, x)) {
+         DESTROY(RETVAL);
+         RETVAL = 0;
+       }
        OUTPUT:
        RETVAL
 
@@ -377,6 +440,17 @@ mpmont_mul(mm, x, y)
        mm, MP_NEW, x, y
 
 mp *
+in(mm, x)
+       MP_Mont *mm
+       mp *x
+       CODE:
+       RETVAL = MP_NEW;
+       mp_div(0, &RETVAL, x, mm->m);
+       RETVAL = mpmont_mul(mm, RETVAL, RETVAL, mm->r2);
+       OUTPUT:
+       RETVAL
+
+mp *
 mpmont_expr(mm, g, x)
        MP_Mont *mm
        mp *g
@@ -406,8 +480,8 @@ mpmont_mexpr(mm, ...)
        n = (items - 1)/2;
        v = xmalloc(n * sizeof(mp_expfactor));
        for (i = 1, j = 0; i < items; i += 2, j++) {
-         v[j].base = mp_fromsv(ST(i), "g_i", "Catacomb::MP", 0, 0);
-         v[j].exp = mp_fromsv(ST(i + 1), "x_i", "Catacomb::MP", 0, 0);
+         v[j].base = mp_fromsv(ST(i), "g_i", 0, 0);
+         v[j].exp = mp_fromsv(ST(i + 1), "x_i", 0, 0);
        }
        RETVAL = mpmont_mexpr(mm, MP_NEW, v, n);
        xfree(v);
@@ -428,10 +502,8 @@ mpmont_mexp(mm, ...)
        n = (items - 1)/2;
        v = xmalloc(n * sizeof(mp_expfactor));
        for (i = 1, j = 0; i < items; i += 2, j++) {
-         v[j].base = mp_fromsv(ST(i), "g_%lu",
-                               "Catacomb::MP", 0, 0, (unsigned long)i);
-         v[j].exp = mp_fromsv(ST(i + 1), "x_%lu",
-                              "Catacomb::MP", 0, 0, (unsigned long)i);
+         v[j].base = mp_fromsv(ST(i), "g_%lu", 0, 0, (unsigned long)i);
+         v[j].exp = mp_fromsv(ST(i + 1), "x_%lu", 0, 0, (unsigned long)i);
        }
        RETVAL = mpmont_mexp(mm, MP_NEW, v, n);
        xfree(v);
@@ -469,10 +541,11 @@ new(me, x)
        SV *me
        mp *x
        CODE:
-       if (!MP_POSP(x))
-         croak("Argument to Catacomb::MP::Barrett::new must be positive");
        RETVAL = CREATE(mpbarrett);
-       mpbarrett_create(RETVAL, x);
+       if (mpbarrett_create(RETVAL, x)) {
+         DESTROY(RETVAL);
+         RETVAL = 0;
+       }
        OUTPUT:
        RETVAL
 
@@ -514,10 +587,11 @@ new(me, x)
        SV *me
        mp *x
        CODE:
-       if (!MP_POSP(x))
-         croak("Argument to Catacomb::MP::Reduce::new must be positive");
-       RETVAL = CREATE(mpreduce);
-       mpreduce_create(RETVAL, x);
+       RETVAL = CREATE(MP_Reduce);     
+       if (mpreduce_create(RETVAL, x)) {
+         DESTROY(RETVAL);
+         RETVAL = 0;
+       }
        OUTPUT:
        RETVAL
 
@@ -569,14 +643,34 @@ new(me, ...)
        v = xmalloc(n * sizeof(mpcrt_mod));
        for (i = 0; i < n; i++) {
          v[i].m = mp_copy(mp_fromsv(ST(i + 1), "n_%lu", 
-                          "Catacomb::MP", 0, 0, 
-                          (unsigned long)i));
+                          0, 0, (unsigned long)i));
+         v[i].n = v[i].ni = v[i].nni = 0;
        }
        RETVAL = CREATE(MP_CRT);
        mpcrt_create(RETVAL, v, n, 0);
        OUTPUT:
        RETVAL
 
+mp *
+product(mc)
+       MP_CRT *mc
+       CODE:
+       RETVAL = MP_COPY(mc->mb.m);
+       OUTPUT:
+       RETVAL
+
+void
+moduli(mc)
+       MP_CRT *mc
+       PREINIT:
+       size_t n, i;
+       PPCODE:
+       n = mc->k;
+       if (GIMME_V == G_SCALAR)
+         XPUSHs(sv_2mortal(newSViv(n)));
+       else for (i = 0; i < n; i++)
+         XPUSHs(RET_MP(MP_COPY(mc->v[i].m)));
+
 SV *
 DESTROY(mc)
        MP_CRT *mc
@@ -596,10 +690,9 @@ solve(mc, ...)
        n = mc->k;
        if (items - 1 != n)
          croak("Wrong number of residues for this CRT context");
-       for (i = 0; i < n; i++) {
-         v[i] = mp_fromsv(ST(i + 1), "r_%lu", "Catacomb::MP", 
-                          0, 0, (unsigned long)i);
-       }
+       v = xmalloc(n * sizeof(mp *));
+       for (i = 0; i < n; i++)
+         v[i] = mp_fromsv(ST(i + 1), "r_%lu", 0, 0, (unsigned long)i);
        RETVAL = mpcrt_solve(mc, MP_NEW, v);
        xfree(v);
        OUTPUT: