Much wider support for Catacomb in all its glory.
[catacomb-perl] / mp.xs
CommitLineData
660b443c 1# ---?---
2#
a1a90aaf 3# $Id$
660b443c 4#
5# Multiprecision interface
6#
7# (c) 2000 Straylight/Edgeware
8#
9
10#----- Licensing notice -----------------------------------------------------
11#
12# This file is part of the Perl interface to Catacomb.
13#
14# Catacomb/Perl is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License as published by
16# the Free Software Foundation; either version 2 of the License, or
17# (at your option) any later version.
18#
19# Catacomb/Perl is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22# GNU General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License
25# along with Catacomb/Perl; if not, write to the Free Software Foundation,
26# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27#
28
660b443c 29MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = mp_
30
31mp *
32new(me, sv = 0, radix = 0)
33 SV *me
34 SV *sv
35 int radix
36 CODE:
fcd15e0b 37 RETVAL = sv ? mp_fromsv(sv, "sv", radix, 1) : MP_ZERO;
660b443c 38 OUTPUT:
39 RETVAL
40
41mp *
a1a90aaf 42copy(x)
660b443c 43 mp *x
a1a90aaf 44 CODE:
45 RETVAL = MP_COPY(x);
46 OUTPUT:
47 RETVAL
660b443c 48
49mp *
50loadb(me, sv)
51 SV *me
52 SV *sv
53 PREINIT:
54 char *p;
55 STRLEN len;
56 CODE:
57 p = SvPV(sv, len);
58 RETVAL = mp_loadb(MP_NEW, p, len);
59 OUTPUT:
60 RETVAL
61
62mp *
63loadl(me, sv)
64 SV *me
65 SV *sv
66 PREINIT:
67 char *p;
68 STRLEN len;
69 CODE:
70 p = SvPV(sv, len);
71 RETVAL = mp_loadl(MP_NEW, p, len);
72 OUTPUT:
73 RETVAL
74
fcd15e0b 75mp *
76loadb2c(me, sv)
77 SV *me
78 SV *sv
79 PREINIT:
80 char *p;
81 STRLEN len;
82 CODE:
83 p = SvPV(sv, len);
84 RETVAL = mp_loadb2c(MP_NEW, p, len);
85 OUTPUT:
86 RETVAL
87
88mp *
89loadl2c(me, sv)
90 SV *me
91 SV *sv
92 PREINIT:
93 char *p;
94 STRLEN len;
95 CODE:
96 p = SvPV(sv, len);
97 RETVAL = mp_loadl2c(MP_NEW, p, len);
98 OUTPUT:
99 RETVAL
100
660b443c 101int
102metrics(m)
103 mp *m
104 INTERFACE_MACRO:
105 XSINTERFACE_FUNC
106 XSINTERFACE_FUNC_SETMP
107 INTERFACE:
fcd15e0b 108 octets bits octets2c
660b443c 109
110SV *
111storeb(m, i = -1)
112 mp *m
113 int i
114 PREINIT:
115 size_t sz;
116 CODE:
fcd15e0b 117 if (i >= 0)
118 sz = i;
119 else {
120 sz = mp_octets(m);
121 if (!sz)
122 sz = 1;
123 }
660b443c 124 RETVAL = NEWSV(0, sz ? sz : 1);
125 mp_storeb(m, SvPVX(RETVAL), sz);
126 SvCUR_set(RETVAL, sz);
127 SvPOK_on(RETVAL);
128 OUTPUT:
129 RETVAL
130
131SV *
132storel(m, i = -1)
133 mp *m
134 int i
135 PREINIT:
136 size_t sz;
137 CODE:
138 sz = (i < 0) ? mp_octets(m) : i;
139 RETVAL = NEWSV(0, sz ? sz : 1);
140 mp_storel(m, SvPVX(RETVAL), sz);
141 SvCUR_set(RETVAL, sz);
142 SvPOK_on(RETVAL);
143 OUTPUT:
144 RETVAL
145
146SV *
fcd15e0b 147storeb2c(m, i = -1)
148 mp *m
149 int i
150 PREINIT:
151 size_t sz;
152 CODE:
153 sz = (i < 0) ? mp_octets2c(m) : i;
154 RETVAL = NEWSV(0, sz ? sz : 1);
155 mp_storeb(m, SvPVX(RETVAL), sz);
156 SvCUR_set(RETVAL, sz);
157 SvPOK_on(RETVAL);
158 OUTPUT:
159 RETVAL
160
161SV *
162storel2c(m, i = -1)
163 mp *m
164 int i
165 PREINIT:
166 size_t sz;
167 CODE:
168 sz = (i < 0) ? mp_octets2c(m) : i;
169 RETVAL = NEWSV(0, sz ? sz : 1);
170 mp_storel(m, SvPVX(RETVAL), sz);
171 SvCUR_set(RETVAL, sz);
172 SvPOK_on(RETVAL);
173 OUTPUT:
174 RETVAL
175
176SV *
660b443c 177tostring(m, radix = 10)
178 mp *m
179 int radix
180 CODE:
181 RETVAL = NEWSV(0, 0);
182 mp_writesv(m, RETVAL, radix);
183 OUTPUT:
184 RETVAL
185
fcd15e0b 186void
187fromstring(me, s, radix = 10)
188 SV *me
189 SV *s
190 int radix
191 PREINIT:
192 mptext_stringctx ms;
193 STRLEN len;
194 mp *x;
195 PPCODE:
196 ms.buf = SvPV(s, len);
197 ms.lim = ms.buf + len;
198 x = mp_read(MP_NEW, radix, &mptext_stringops, &ms);
199 if (x) {
200 XPUSHs(RET_MP(x));
201 if (GIMME_V == G_ARRAY)
202 XPUSHs(sv_2mortal(newSVpvn(ms.buf, ms.lim - ms.buf)));
203 }
204
660b443c 205SV *
206toint(m)
207 mp *m
208 CODE:
209 RETVAL = newSViv(mp_toiv(m));
210 OUTPUT:
211 RETVAL
212
213SV *
214DESTROY(m)
215 mp *m
216 CODE:
217 mp_drop(m);
218 XSRETURN_UNDEF;
219
220mp *
221unop(a)
222 mp *a
223 C_ARGS:
224 MP_NEW, a
225 INTERFACE_MACRO:
226 XSINTERFACE_FUNC
227 XSINTERFACE_FUNC_SETMP
228 INTERFACE:
fcd15e0b 229 not not2c sqr sqrt
660b443c 230
231mp *
232neg(a)
233 mp *a
234 CODE:
a1a90aaf 235 MP_COPY(a);
660b443c 236 RETVAL = mp_split(a);
237 if (RETVAL->v < RETVAL->vl)
238 RETVAL->f ^= MP_NEG;
239 OUTPUT:
240 RETVAL
241
242mp *
243mp_factorial(me, x)
244 SV *me
245 IV x
246 C_ARGS:
247 x
248
249mp *
250binop(a, b)
251 mp *a
252 mp *b
253 C_ARGS:
254 MP_NEW, a, b
255 INTERFACE_MACRO:
256 XSINTERFACE_FUNC
257 XSINTERFACE_FUNC_SETMP
258 INTERFACE:
fcd15e0b 259 add sub mul and2c or2c nand2c nor2c xor2c and or nand nor xor exp
660b443c 260
261mp *
262shiftop(a, n)
263 mp *a
264 int n
265 C_ARGS:
266 MP_NEW, a, n
267 INTERFACE_MACRO:
268 XSINTERFACE_FUNC
269 XSINTERFACE_FUNC_SETMP
270 INTERFACE:
f9952aec 271 lsl lsr lsl2c lsr2c
272
273bool
274testbitop(a, n)
275 mp *a
276 unsigned long n
277 INTERFACE_MACRO:
278 XSINTERFACE_FUNC
279 XSINTERFACE_FUNC_SETMP
280 INTERFACE:
281 testbit testbit2c
282
283mp *
284flipbits(a, n)
285 mp *a
286 unsigned long n
287 C_ARGS:
288 MP_NEW, a, n
289 INTERFACE_MACRO:
290 XSINTERFACE_FUNC
291 XSINTERFACE_FUNC_SETMP
292 INTERFACE:
293 setbit clearbit setbit2c clearbit2c
660b443c 294
295int
296mp_cmp(a, b)
297 mp *a
298 mp *b
299
300int
301mp_eq(a, b)
302 mp *a
303 mp *b
304
305int
306jacobi(a, n)
307 mp *a
308 mp *n
309 CODE:
310 if (!MP_LEN(n) || !(n->v[0] & 1))
311 croak("n must be odd in Catacomb::MP::jacobi");
312 RETVAL = mp_jacobi(a, n);
313 OUTPUT:
314 RETVAL
315
316mp *
317mp_modsqrt(p, x)
318 mp *p
319 mp *x
fcd15e0b 320 INIT:
321 if (!MP_POSP(p) || !MP_ODDP(p))
322 croak("p is not positive and odd");
323 if (mp_jacobi(x, p) != 1)
324 croak("x not a quadratic residue mod p");
660b443c 325 C_ARGS:
326 MP_NEW, x, p
327
328void
329div(a, b)
330 mp *a
331 mp *b
332 PREINIT:
333 mp *q = MP_NEW, *r = MP_NEW;
334 PPCODE:
335 if (MP_EQ(b, MP_ZERO))
336 croak("Divide by zero in Catacomb::MP::div");
337 q = MP_NEW;
338 switch (GIMME_V) {
339 case G_ARRAY:
340 r = MP_NEW;
341 mp_div(&q, &r, a, b);
342 EXTEND(SP, 2);
343 PUSHs(RET_MP(q));
344 PUSHs(RET_MP(r));
345 break;
346 case G_VOID:
347 break;
348 default:
fcd15e0b 349 mp_div(&q, 0, a, b);
660b443c 350 EXTEND(SP, 1);
351 PUSHs(RET_MP(q));
352 break;
353 }
354
355void
356gcd(a, b)
357 mp *a
358 mp *b
359 PREINIT:
360 mp *g = MP_NEW, *x = MP_NEW, *y = MP_NEW;
361 PPCODE:
362 switch (GIMME_V) {
363 case G_ARRAY:
364 mp_gcd(&g, &x, &y, a, b);
365 EXTEND(SP, 3);
366 PUSHs(RET_MP(g));
367 PUSHs(RET_MP(x));
368 PUSHs(RET_MP(y));
369 break;
370 case G_VOID:
371 break;
372 default:
373 mp_gcd(&g, 0, 0, a, b);
374 EXTEND(SP, 1);
375 PUSHs(RET_MP(g));
376 break;
377 }
378
379void
380odd(m)
381 mp *m
382 PREINIT:
383 mp *t;
384 size_t s;
385 PPCODE:
386 t = mp_odd(MP_NEW, m, &s);
387 EXTEND(SP, 2);
660b443c 388 PUSHs(sv_2mortal(newSViv(s)));
fcd15e0b 389 PUSHs(RET_MP(t));
660b443c 390
fcd15e0b 391MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = pgen_
660b443c 392
fcd15e0b 393bool
394pgen_primep(x, r = &rand_global)
a1a90aaf 395 mp *x
fcd15e0b 396 grand *r
a1a90aaf 397
fcd15e0b 398MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = pfilt_
660b443c 399
fcd15e0b 400int
401pfilt_smallfactor(x)
660b443c 402 mp *x
660b443c 403
404MODULE = Catacomb PACKAGE = Catacomb::MP::Mont PREFIX = mpmont_
405
406MP_Mont *
407new(me, x)
408 SV *me
409 mp *x
410 CODE:
fcd15e0b 411 RETVAL = CREATE(MP_Mont);
412 if (mpmont_create(RETVAL, x)) {
413 DESTROY(RETVAL);
414 RETVAL = 0;
415 }
660b443c 416 OUTPUT:
417 RETVAL
418
419SV *
420DESTROY(mm)
421 MP_Mont *mm
422 CODE:
423 mpmont_destroy(mm);
424 DESTROY(mm);
425 XSRETURN_UNDEF;
426
427mp *
428mpmont_reduce(mm, x)
429 MP_Mont *mm
430 mp *x
431 C_ARGS:
432 mm, MP_NEW, x
433
434mp *
435mpmont_mul(mm, x, y)
436 MP_Mont *mm
437 mp *x
438 mp *y
439 C_ARGS:
440 mm, MP_NEW, x, y
441
442mp *
fcd15e0b 443in(mm, x)
444 MP_Mont *mm
445 mp *x
446 CODE:
447 RETVAL = MP_NEW;
448 mp_div(0, &RETVAL, x, mm->m);
449 RETVAL = mpmont_mul(mm, RETVAL, RETVAL, mm->r2);
450 OUTPUT:
451 RETVAL
452
453mp *
660b443c 454mpmont_expr(mm, g, x)
455 MP_Mont *mm
456 mp *g
457 mp *x
458 C_ARGS:
459 mm, MP_NEW, g, x
460
461mp *
462mpmont_exp(mm, g, x)
463 MP_Mont *mm
464 mp *g
465 mp *x
466 C_ARGS:
467 mm, MP_NEW, g, x
468
469mp *
470mpmont_mexpr(mm, ...)
471 MP_Mont *mm
472 PREINIT:
473 mp_expfactor *v;
474 size_t i, j, n;
475 CODE:
476 if (items < 3 || !(items & 1)) {
477 croak("Usage: Catacomb::MP::Mont::mexpr"
478 "(mm, g_0, x_0, g_1, x_1, ...");
479 }
480 n = (items - 1)/2;
481 v = xmalloc(n * sizeof(mp_expfactor));
482 for (i = 1, j = 0; i < items; i += 2, j++) {
fcd15e0b 483 v[j].base = mp_fromsv(ST(i), "g_i", 0, 0);
484 v[j].exp = mp_fromsv(ST(i + 1), "x_i", 0, 0);
660b443c 485 }
486 RETVAL = mpmont_mexpr(mm, MP_NEW, v, n);
487 xfree(v);
488 OUTPUT:
489 RETVAL
490
491mp *
492mpmont_mexp(mm, ...)
493 MP_Mont *mm
494 PREINIT:
495 mp_expfactor *v;
496 size_t i, j, n;
497 CODE:
498 if (items < 3 || !(items & 1)) {
499 croak("Usage: Catacomb::MP::Mont::mexp"
500 "(mm, g_0, x_0, g_1, x_1, ...");
501 }
502 n = (items - 1)/2;
503 v = xmalloc(n * sizeof(mp_expfactor));
504 for (i = 1, j = 0; i < items; i += 2, j++) {
fcd15e0b 505 v[j].base = mp_fromsv(ST(i), "g_%lu", 0, 0, (unsigned long)i);
506 v[j].exp = mp_fromsv(ST(i + 1), "x_%lu", 0, 0, (unsigned long)i);
660b443c 507 }
508 RETVAL = mpmont_mexp(mm, MP_NEW, v, n);
509 xfree(v);
510 OUTPUT:
511 RETVAL
512
513mp *
514r(mm)
515 MP_Mont *mm
516 CODE:
a1a90aaf 517 RETVAL = MP_COPY(mm->r);
660b443c 518 OUTPUT:
519 RETVAL
520
521mp *
522r2(mm)
523 MP_Mont *mm
524 CODE:
a1a90aaf 525 RETVAL = MP_COPY(mm->r2);
660b443c 526 OUTPUT:
527 RETVAL
528
529mp *
530m(mm)
531 MP_Mont *mm
532 CODE:
a1a90aaf 533 RETVAL = MP_COPY(mm->m);
660b443c 534 OUTPUT:
535 RETVAL
536
537MODULE = Catacomb PACKAGE = Catacomb::MP::Barrett PREFIX = mpbarrett_
538
539MP_Barrett *
540new(me, x)
541 SV *me
542 mp *x
543 CODE:
660b443c 544 RETVAL = CREATE(mpbarrett);
fcd15e0b 545 if (mpbarrett_create(RETVAL, x)) {
546 DESTROY(RETVAL);
547 RETVAL = 0;
548 }
660b443c 549 OUTPUT:
550 RETVAL
551
552SV *
553DESTROY(mb)
554 MP_Barrett *mb
555 CODE:
556 mpbarrett_destroy(mb);
557 DESTROY(mb);
558 XSRETURN_UNDEF;
559
560mp *
561mpbarrett_reduce(mb, x)
562 MP_Barrett *mb
563 mp *x
564 C_ARGS:
565 mb, MP_NEW, x
566
567mp *
568mpbarrett_exp(mb, g, x)
569 MP_Barrett *mb
570 mp *g
571 mp *x
572 C_ARGS:
573 mb, MP_NEW, g, x
574
575mp *
576m(mb)
577 MP_Barrett *mb
578 CODE:
a1a90aaf 579 RETVAL = MP_COPY(mb->m);
580 OUTPUT:
581 RETVAL
582
583MODULE = Catacomb PACKAGE = Catacomb::MP::Reduce PREFIX = mpreduce_
584
585MP_Reduce *
586new(me, x)
587 SV *me
588 mp *x
589 CODE:
fcd15e0b 590 RETVAL = CREATE(MP_Reduce);
591 if (mpreduce_create(RETVAL, x)) {
592 DESTROY(RETVAL);
593 RETVAL = 0;
594 }
a1a90aaf 595 OUTPUT:
596 RETVAL
597
598SV *
599DESTROY(r)
600 MP_Reduce *r
601 CODE:
602 mpreduce_destroy(r);
603 DESTROY(r);
604 XSRETURN_UNDEF;
605
606mp *
607reduce(r, x)
608 MP_Reduce *r
609 mp *x
610 CODE:
611 RETVAL = mpreduce_do(r, MP_NEW, x);
612 OUTPUT:
613 RETVAL
614
615mp *
616mpreduce_exp(r, x, y)
617 MP_Reduce *r
618 mp *x
619 mp *y
620 C_ARGS:
621 r, MP_NEW, x, y
622
623mp *
624m(r)
625 MP_Reduce *r
626 CODE:
627 RETVAL = MP_COPY(r->p);
660b443c 628 OUTPUT:
629 RETVAL
630
631MODULE = Catacomb PACKAGE = Catacomb::MP::CRT
632
633MP_CRT *
634new(me, ...)
635 SV *me
636 PREINIT:
637 mpcrt_mod *v;
638 size_t n, i;
639 CODE:
640 if (items < 1)
641 croak("Usage: Catacomb::MP::CRT::new(me, n_0, n_1, ...)");
642 n = items - 1;
643 v = xmalloc(n * sizeof(mpcrt_mod));
644 for (i = 0; i < n; i++) {
a1a90aaf 645 v[i].m = mp_copy(mp_fromsv(ST(i + 1), "n_%lu",
fcd15e0b 646 0, 0, (unsigned long)i));
647 v[i].n = v[i].ni = v[i].nni = 0;
660b443c 648 }
649 RETVAL = CREATE(MP_CRT);
650 mpcrt_create(RETVAL, v, n, 0);
651 OUTPUT:
652 RETVAL
653
fcd15e0b 654mp *
655product(mc)
656 MP_CRT *mc
657 CODE:
658 RETVAL = MP_COPY(mc->mb.m);
659 OUTPUT:
660 RETVAL
661
662void
663moduli(mc)
664 MP_CRT *mc
665 PREINIT:
666 size_t n, i;
667 PPCODE:
668 n = mc->k;
669 if (GIMME_V == G_SCALAR)
670 XPUSHs(sv_2mortal(newSViv(n)));
671 else for (i = 0; i < n; i++)
672 XPUSHs(RET_MP(MP_COPY(mc->v[i].m)));
673
660b443c 674SV *
675DESTROY(mc)
676 MP_CRT *mc
677 CODE:
678 mpcrt_destroy(mc);
679 xfree(mc->v);
680 DESTROY(mc);
681 XSRETURN_UNDEF;
682
683mp *
684solve(mc, ...)
685 MP_CRT *mc
686 PREINIT:
687 mp **v;
688 size_t n, i;
689 CODE:
690 n = mc->k;
691 if (items - 1 != n)
692 croak("Wrong number of residues for this CRT context");
fcd15e0b 693 v = xmalloc(n * sizeof(mp *));
694 for (i = 0; i < n; i++)
695 v[i] = mp_fromsv(ST(i + 1), "r_%lu", 0, 0, (unsigned long)i);
660b443c 696 RETVAL = mpcrt_solve(mc, MP_NEW, v);
697 xfree(v);
698 OUTPUT:
699 RETVAL
700
701#----- That's all, folks ----------------------------------------------------