Much wider support for Catacomb in all its glory.
[catacomb-perl] / mp.xs
diff --git a/mp.xs b/mp.xs
index e405339..9eb7fe2 100644 (file)
--- a/mp.xs
+++ b/mp.xs
@@ -1,6 +1,6 @@
 # ---?---
 #
-# $Id: mp.xs,v 1.1 2004/04/02 18:04:01 mdw Exp $
+# $Id$
 #
 # Multiprecision interface
 #
 # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #
 
-#----- Revision history -----------------------------------------------------
-#
-# $Log: mp.xs,v $
-# Revision 1.1  2004/04/02 18:04:01  mdw
-# Initial checkin.
-#
-
 MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = mp_
 
 mp *
@@ -46,8 +39,12 @@ new(me, sv = 0, radix = 0)
        RETVAL
 
 mp *
-mp_copy(x)
+copy(x)
        mp *x
+       CODE:
+       RETVAL = MP_COPY(x);
+       OUTPUT:
+       RETVAL
 
 mp *
 loadb(me, sv)
@@ -75,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
@@ -82,7 +105,7 @@ metrics(m)
        XSINTERFACE_FUNC
        XSINTERFACE_FUNC_SETMP
        INTERFACE:
-       octets bits
+       octets bits octets2c
 
 SV *
 storeb(m, i = -1)
@@ -91,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);
@@ -115,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
@@ -124,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
@@ -148,13 +226,13 @@ unop(a)
        XSINTERFACE_FUNC
        XSINTERFACE_FUNC_SETMP
        INTERFACE:
-       not sqr sqrt
+       not not2c sqr sqrt
 
 mp *
 neg(a)
        mp *a
        CODE:
-       mp_copy(a);
+       MP_COPY(a);
        RETVAL = mp_split(a);
        if (RETVAL->v < RETVAL->vl)
          RETVAL->f ^= MP_NEG;
@@ -178,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)
@@ -190,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)
@@ -217,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
 
@@ -241,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;
@@ -280,53 +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
+MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = pgen_
 
-MP_Mont *
-mont(x)
+bool
+pgen_primep(x, r = &rand_global)
        mp *x
-       CODE:
-       if (x->f & MP_NEG)
-         croak("Argument to Catacomb::MP::mont must be positive");
-       if (x->v == x->vl || !(x->v[0] & 1u))
-         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 (x->f & MP_NEG)
-         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 (x->f & MP_NEG)
-         croak("Argument to Catacomb::MP::rabin must be positive");
-       if (x->v == x->vl || !(x->v[0] & 1u))
-         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_
 
@@ -335,12 +408,11 @@ new(me, x)
        SV *me
        mp *x
        CODE:
-       if (x->f & MP_NEG)
-         croak("Argument to Catacomb::MP::Mont::new must be positive");
-       if (x->v == x->vl || !(x->v[0] & 1u))
-         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
 
@@ -368,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
@@ -431,7 +514,7 @@ mp *
 r(mm)
        MP_Mont *mm
        CODE:
-       RETVAL = mp_copy(mm->r);
+       RETVAL = MP_COPY(mm->r);
        OUTPUT:
        RETVAL
 
@@ -439,7 +522,7 @@ mp *
 r2(mm)
        MP_Mont *mm
        CODE:
-       RETVAL = mp_copy(mm->r2);
+       RETVAL = MP_COPY(mm->r2);
        OUTPUT:
        RETVAL
 
@@ -447,7 +530,7 @@ mp *
 m(mm)
        MP_Mont *mm
        CODE:
-       RETVAL = mp_copy(mm->m);
+       RETVAL = MP_COPY(mm->m);
        OUTPUT:
        RETVAL
 
@@ -458,10 +541,11 @@ new(me, x)
        SV *me
        mp *x
        CODE:
-       if (x->f & MP_NEG)
-         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
 
@@ -492,7 +576,55 @@ mp *
 m(mb)
        MP_Barrett *mb
        CODE:
-       RETVAL = mp_copy(mb->m);
+       RETVAL = MP_COPY(mb->m);
+       OUTPUT:
+       RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::MP::Reduce PREFIX = mpreduce_
+
+MP_Reduce *
+new(me, x)
+       SV *me
+       mp *x
+       CODE:
+       RETVAL = CREATE(MP_Reduce);     
+       if (mpreduce_create(RETVAL, x)) {
+         DESTROY(RETVAL);
+         RETVAL = 0;
+       }
+       OUTPUT:
+       RETVAL
+
+SV *
+DESTROY(r)
+       MP_Reduce *r
+       CODE:
+       mpreduce_destroy(r);
+       DESTROY(r);
+       XSRETURN_UNDEF;
+
+mp *
+reduce(r, x)
+       MP_Reduce *r
+       mp *x
+       CODE:
+       RETVAL = mpreduce_do(r, MP_NEW, x);
+       OUTPUT:
+       RETVAL
+
+mp *
+mpreduce_exp(r, x, y)
+       MP_Reduce *r
+       mp *x
+       mp *y
+       C_ARGS:
+       r, MP_NEW, x, y
+
+mp *
+m(r)
+       MP_Reduce *r
+       CODE:
+       RETVAL = MP_COPY(r->p);
        OUTPUT:
        RETVAL
 
@@ -510,14 +642,35 @@ new(me, ...)
        n = items - 1;
        v = xmalloc(n * sizeof(mpcrt_mod));
        for (i = 0; i < n; i++) {
-         v[i].m = mp_copy(mp_fromsv(ST(i + 1), "n_%lu", 0, 0, 
-                          (unsigned long)i));
+         v[i].m = mp_copy(mp_fromsv(ST(i + 1), "n_%lu", 
+                          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
@@ -537,6 +690,7 @@ solve(mc, ...)
        n = mc->k;
        if (items - 1 != n)
          croak("Wrong number of residues for this CRT context");
+       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);