source: git/ntl/src/g_lip_impl.h @ 09da99

spielwiese
Last change on this file since 09da99 was 09da99, checked in by Hans Schönemann <hannes@…>, 20 years ago
*hannes: NTL- 5.3.1 git-svn-id: file:///usr/local/Singular/svn/trunk@6910 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 95.2 KB
Line 
1
2/*
3 * This is a "wrapper" layer that builds on top of the "mpn" layer of gmp.
4 * This layer provides much of the same functionality of the "mpz"
5 * layer of gmp, but the interface it provides is much more like
6 * the interface provided by lip.
7 *
8 * This layer was written under the following assumptions about gmp:
9 *  1) mp_limb_t is an unsigned integral type
10 *  2) sizeof(mp_limb_t) == sizeof(long) or sizeof(mp_limb_t) == 2*sizeof(long)
11 *  3) the number of bits of an mp_limb_t is equal to that of a long,
12 *     or twice that of a long
13 *  4) the number of bits of a gmp radix is equal to the number of bits
14 *     of an mp_limb_t
15 *
16 * Except for assumption (1), these assumptions are verified in the
17 * installation script, and they should be universally satisfied in practice,
18 * except when gmp is built using the proposed, new "nail" fetaure
19 * (in which some bits of an mp_limb_t are unused).
20 * The code here will not work properly with the "nail" feature;
21 * however, I have (attempted to) identify all such problem spots,
22 * and any other places where assumptions (2-4) are made,
23 * with a comment labeled "DIRT".
24 */
25
26
27
28#include <NTL/lip.h>
29
30#include <NTL/ctools.h>
31
32
33#include <stdlib.h>
34#include <stdio.h>
35#include <math.h>
36
37
38#include <gmp.h>
39
40typedef mp_limb_t *_ntl_limb_t_ptr;
41
42int _ntl_gmp_hack = 0;
43
44#if (__GNU_MP_VERSION < 3)
45
46#error "You have to use GNP version >= 3.1"
47
48#endif
49
50#if ((__GNU_MP_VERSION == 3) && (__GNU_MP_VERSION_MINOR < 1))
51
52#error "You have to use GNP version >= 3.1"
53
54#endif
55
56
57
58/* v 3.1 is supposed  mpn_tdiv_qr defined, but it doesn't.
59   Here's a workaround */
60
61#if ((__GNU_MP_VERSION == 3) && (__GNU_MP_VERSION_MINOR == 1) && (__GNU_MP_VERSION_PATCHLEVEL == 0))
62
63#define mpn_tdiv_qr __MPN(tdiv_qr)
64
65
66#ifdef __cplusplus
67extern "C" 
68#endif
69void mpn_tdiv_qr(mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, 
70                 mp_srcptr, mp_size_t);
71
72#endif
73
74
75#if (defined(NTL_CXX_ONLY) && !defined(__cplusplus))
76#error "CXX_ONLY flag set...must use C++ compiler"
77#endif
78
79
80union gbigint_header {
81
82   long info[2];
83   mp_limb_t alignment;
84
85};
86
87/* A bigint is represented as two long's, ALLOC and SIZE, followed by a
88 * vector DATA of mp_limb_t's. 
89 *
90 * ALLOC is of the form
91 *    (alloc << 2) | continue_flag | frozen_flag
92 * where
93 *    - alloc is the number of allocated mp_limb_t's,
94 *    - continue flag is either 2 or 0,
95 *    - frozen_flag is either 1 or 0.
96 * If frozen_flag is set, then the space for this bigint is *not*
97 * managed by the _ntl_gsetlength and _ntl_gfree routines,
98 * but are instead managed by the vec_ZZ_p and ZZVec routines.
99 * The continue_flag is only set when the frozen_flag is set.
100 *
101 * SIZE is the number of mp_limb_t's actually
102 * used by the bigint, with the sign of SIZE having
103 * the sign of the bigint.
104 * Note that the zero bigint is represented as SIZE=0.
105 *
106 * Bigint's are accessed through a handle, which is pointer to void.
107 * A null handle logically represents the bigint zero.
108 * This is done so that the interface presented to higher level
109 * routines is essentially the same as that of NTL's traditional
110 * long integer package.
111 *
112 * The components ALLOC, SIZE, and DATA are all accessed through
113 * macros using pointer casts.  While all of may seem a bit dirty,
114 * it should be quite portable: objects are never referenced
115 * through pointers of different types, and no alignmement
116 * problems should arise.
117 *
118 * Actually, mp_limb_t is usually the type unsigned long.
119 * However, on some 64-bit platforms, the type long is only 32 bits,
120 * and gmp makes mp_limb_t unsigned long long in this case.
121 * This is fairly rare, as the industry standard for Unix is to
122 * have 64-bit longs on 64-bit machines.
123 */ 
124
125#if 1
126
127#define ALLOC(p) (((long *) (p))[0])
128#define SIZE(p) (((long *) (p))[1])
129#define DATA(p) ((mp_limb_t *) (((long *) (p)) + 2))
130
131#define STORAGE(len) ((long)(2*sizeof(long) + (len)*sizeof(mp_limb_t)))
132
133/* DIRT: STORAGE computes the number of bytes to allocate for a bigint
134 * of maximal SIZE len.  This should be computed so that one
135 * can store several such bigints in a contiguous array
136 * of memory without breaking any alignment requirements.
137 * Currently, it is assumed (and explicitly checked in the NTL installation
138 * script) that sizeof(mp_limb_t) is either sizeof(long) or
139 * 2*sizeof(long), and therfore, nothing special needs to
140 * be done to enfoce alignment requirements.  If this assumption
141 * should change, then the storage layout for bigints must be
142 * re-designed.   
143 */
144
145#define MustAlloc(c, len)  (!(c) || (ALLOC(c) >> 2) < (len))
146
147
148
149#define GET_SIZE_NEG(sz, neg, p)  \
150do  \
151{   \
152   long _s;   \
153   _s = SIZE(p);   \
154   if (_s < 0) {  \
155      sz = -_s;  \
156      neg = 1;  \
157   }  \
158   else {  \
159      sz = _s;  \
160      neg = 0;  \
161   }  \
162}  \
163while (0)
164
165#define STRIP(sz, p)  \
166do  \
167{  \
168   long _i;  \
169   _i = sz - 1;  \
170   while (_i >= 0 && p[_i] == 0) _i--;  \
171   sz = _i + 1;  \
172}  \
173while (0)
174
175#define ZEROP(p) (!p || !SIZE(p))
176
177#define ONEP(p) (p && SIZE(p) == 1 && DATA(p)[0] == 1)
178
179#define SWAP_BIGINT(a, b)  \
180do  \
181{  \
182   _ntl_gbigint _t;  \
183   _t = a;  \
184   a = b;  \
185   b = _t;  \
186}  \
187while (0)
188
189#define SWAP_LONG(a, b)  \
190do  \
191{  \
192   long _t;  \
193   _t = a;  \
194   a = b;  \
195   b = _t;  \
196}  \
197while (0)
198
199#define SWAP_LIMB_PTR(a, b)  \
200do  \
201{  \
202   _ntl_limb_t_ptr _t;  \
203   _t = a;  \
204   a = b;  \
205   b = _t;  \
206}  \
207while (0)
208
209#define COUNT_BITS(cnt, a)  \
210do  \
211{  \
212   long _i = 0;  \
213   mp_limb_t _a = (a);  \
214  \
215   while (_a>=256)  \
216      _i += 8, _a >>= 8;  \
217   if (_a >=16)  \
218      _i += 4, _a >>= 4;  \
219   if (_a >= 4)  \
220      _i += 2, _a >>= 2;  \
221   if (_a >= 2)  \
222      _i += 2;  \
223   else if (_a >= 1)  \
224      _i++;  \
225  \
226   cnt = _i;  \
227}  \
228while (0)
229
230#else
231
232/* These are C++ inline functions that are equivalent to the above
233 * macros.  They are mainly intended as a debugging aid.
234 */
235
236
237inline long& ALLOC(_ntl_gbigint p) 
238   { return (((long *) p)[0]); }
239
240inline long& SIZE(_ntl_gbigint p) 
241   { return (((long *) p)[1]); }
242
243inline mp_limb_t * DATA(_ntl_gbigint p) 
244   { return ((mp_limb_t *) (((long *) (p)) + 2)); }
245
246inline long STORAGE(long len)
247   { return ((long)(2*sizeof(long) + (len)*sizeof(mp_limb_t))); }
248
249inline long MustAlloc(_ntl_gbigint c, long len) 
250   { return (!(c) || (ALLOC(c) >> 2) < (len)); }
251
252
253inline void GET_SIZE_NEG(long& sz, long& neg, _ntl_gbigint p)
254{ 
255   long s; 
256   s = SIZE(p); 
257   if (s < 0) {
258      sz = -s;
259      neg = 1;
260   }
261   else {
262      sz = s;
263      neg = 0;
264   }
265}
266
267inline void STRIP(long& sz, mp_limb_t *p)
268{
269   long i;
270   i = sz - 1;
271   while (i >= 0 && p[i] == 0) i--;
272   sz = i + 1;
273}
274
275inline long ZEROP(_ntl_gbigint p)
276{
277   return !p || !SIZE(p);
278}
279
280inline long ONEP(_ntl_gbigint p)
281{
282   return p && SIZE(p) == 1 && DATA(p)[0] == 1;
283}
284
285inline void SWAP_BIGINT(_ntl_gbigint& a, _ntl_gbigint& b)
286{
287   _ntl_gbigint t;
288   t = a;
289   a = b;
290   b = t;
291}
292
293inline void SWAP_LONG(long& a, long& b)
294{
295   long t;
296   t = a;
297   a = b;
298   b = t;
299}
300
301inline void SWAP_LIMB_PTR(_ntl_limb_t_ptr& a, _ntl_limb_t_ptr& b)
302{
303   _ntl_limb_t_ptr t;
304   t = a;
305   a = b;
306   b = t;
307}
308
309
310inline void COUNT_BITS(long& cnt, mp_limb_t a)
311{
312   long i = 0;
313
314   while (a>=256)
315      i += 8, a >>= 8;
316   if (a >=16)
317      i += 4, a >>= 4;
318   if (a >= 4)
319      i += 2, a >>= 2;
320   if (a >= 2)
321      i += 2;
322   else if (a >= 1)
323      i++;
324
325   cnt = i;
326}
327
328#endif
329
330#define STORAGE_OVF(len) NTL_OVERFLOW(len, sizeof(mp_limb_t), 2*sizeof(long))
331
332
333
334static 
335void ghalt(char *c)
336{
337   fprintf(stderr,"fatal error:\n   %s\nexit...\n",c);
338   fflush(stderr);
339   abort();
340}
341
342
343#define MIN_SETL        (4)
344   /* _ntl_gsetlength allocates a multiple of MIN_SETL digits */
345
346
347
348void _ntl_gsetlength(_ntl_gbigint *v, long len)
349{
350   _ntl_gbigint x = *v;
351
352   if (len < 0)
353      ghalt("negative size allocation in _ntl_zgetlength");
354
355   if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0))
356      ghalt("size too big in _ntl_gsetlength");
357
358#ifdef NTL_SMALL_MP_SIZE_T
359   /* this makes sure that numbers don't get too big for GMP */
360   if (len >= (1L << (NTL_BITS_PER_INT-4)))
361      ghalt("size too big for GMP");
362#endif
363
364
365   if (x) {
366      long oldlen = ALLOC(x);
367      long fixed = oldlen & 1;
368      oldlen = oldlen >> 2;
369
370      if (fixed) {
371         if (len > oldlen) 
372            ghalt("internal error: can't grow this _ntl_gbigint");
373         else
374            return;
375      }
376
377      if (len <= oldlen) return;
378
379      len++;  /* always allocate at least one more than requested */
380
381      oldlen = (long) (oldlen * 1.2); /* always increase by at least 20% */
382      if (len < oldlen)
383         len = oldlen;
384
385      /* round up to multiple of MIN_SETL */
386      len = ((len+(MIN_SETL-1))/MIN_SETL)*MIN_SETL; 
387
388      /* test len again */
389      if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0))
390         ghalt("size too big in _ntl_gsetlength");
391
392      if (STORAGE_OVF(len))
393         ghalt("reallocation failed in _ntl_gsetlength");
394
395      ALLOC(x) = len << 2;
396      if (!(x = (_ntl_gbigint)NTL_REALLOC((void *) x, 1, STORAGE(len), 0))) {
397         ghalt("reallocation failed in _ntl_gsetlength");
398      }
399   }
400   else {
401      len++;
402      len = ((len+(MIN_SETL-1))/MIN_SETL)*MIN_SETL;
403
404      /* test len again */
405      if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0))
406         ghalt("size too big in _ntl_gsetlength");
407
408      if (STORAGE_OVF(len))
409         ghalt("reallocation failed in _ntl_gsetlength");
410
411      if (!(x = (_ntl_gbigint)NTL_MALLOC(1, STORAGE(len), 0))) {
412         ghalt("allocation failed in _ntl_gsetlength");
413      }
414      ALLOC(x) = len << 2;
415      SIZE(x) = 0;
416   }
417
418   *v = x;
419}
420
421void _ntl_gfree(_ntl_gbigint *xx)
422{
423   _ntl_gbigint x = *xx;
424
425   if (!x)
426      return;
427
428   if (ALLOC(x) & 1)
429      ghalt("Internal error: can't free this _ntl_gbigint");
430
431   free((void*) x);
432   *xx = 0;
433   return;
434}
435
436void
437_ntl_gswap(_ntl_gbigint *a, _ntl_gbigint *b)
438{
439   _ntl_gbigint c;
440
441   if ((*a && (ALLOC(*a) & 1)) || (*b && (ALLOC(*b) & 1))) {
442      static _ntl_gbigint t = 0; 
443      _ntl_gcopy(*a, &t);
444      _ntl_gcopy(*b, a);
445      _ntl_gcopy(t, b);
446      return;
447   }
448
449   c = *a;
450   *a = *b;
451   *b = c;
452}
453
454
455void _ntl_gcopy(_ntl_gbigint a, _ntl_gbigint *bb)
456{
457   _ntl_gbigint b;
458   long sa, abs_sa, i;
459   mp_limb_t *adata, *bdata;
460
461   b = *bb;
462
463   if (!a || (sa = SIZE(a)) == 0) {
464      if (b) SIZE(b) = 0;
465   }
466   else {
467      if (a != b) {
468         if (sa >= 0)
469            abs_sa = sa;
470         else
471            abs_sa = -sa;
472
473         if (MustAlloc(b, abs_sa)) {
474            _ntl_gsetlength(&b, abs_sa);
475            *bb = b;
476         }
477
478         adata = DATA(a);
479         bdata = DATA(b);
480
481         for (i = 0; i < abs_sa; i++)
482            bdata[i] = adata[i];
483
484         SIZE(b) = sa;
485      }
486   }
487}
488
489
490void _ntl_gzero(_ntl_gbigint *aa) 
491{
492   _ntl_gbigint a = *aa;
493
494   if (a) SIZE(a) = 0;
495}
496
497void _ntl_gone(_ntl_gbigint *aa)
498{
499   _ntl_gbigint a = *aa;
500   if (!a) {
501      _ntl_gsetlength(&a, 1);
502      *aa = a;
503   }
504
505   SIZE(a) = 1;
506   DATA(a)[0] = 1;
507}
508
509long _ntl_giszero(_ntl_gbigint a)
510{
511   return ZEROP(a);
512}
513
514long _ntl_godd(_ntl_gbigint a)
515{
516   if (ZEROP(a)) 
517      return 0;
518   else
519      return DATA(a)[0]&1;
520}
521
522long _ntl_gbit(_ntl_gbigint a, long p)
523{
524   long bl;
525   long sa;
526   mp_limb_t wh;
527
528   if (p < 0 || !a) return 0;
529
530   bl = p/NTL_ZZ_NBITS;
531   wh = ((mp_limb_t) 1) << (p - NTL_ZZ_NBITS*bl);
532
533   sa = SIZE(a);
534   if (sa < 0) sa = -sa;
535
536   if (sa <= bl) return 0;
537   if (DATA(a)[bl] & wh) return 1;
538   return 0;
539}
540
541void _ntl_glowbits(_ntl_gbigint a, long b, _ntl_gbigint *cc)
542{
543   _ntl_gbigint c;
544
545   long bl;
546   long wh;
547   long sa;
548   long i;
549   mp_limb_t *adata, *cdata;
550
551   if (ZEROP(a) || (b<=0)) {
552      _ntl_gzero(cc);
553      return;
554   }
555
556   bl = b/NTL_ZZ_NBITS;
557   wh = b - NTL_ZZ_NBITS*bl;
558   if (wh != 0) 
559      bl++;
560   else
561      wh = NTL_ZZ_NBITS;
562
563   sa = SIZE(a);
564   if (sa < 0) sa = -sa;
565
566   if (sa < bl) {
567      _ntl_gcopy(a,cc);
568      _ntl_gabs(cc);
569      return;
570   }
571
572   c = *cc;
573
574   /* a won't move if c aliases a */
575   _ntl_gsetlength(&c, bl);
576   *cc = c;
577
578   adata = DATA(a);
579   cdata = DATA(c);
580
581   for (i = 0; i < bl-1; i++)
582      cdata[i] = adata[i];
583
584   if (wh == NTL_ZZ_NBITS)
585      cdata[bl-1] = adata[bl-1];
586   else
587      cdata[bl-1] = adata[bl-1] & ((((mp_limb_t) 1) << wh) - ((mp_limb_t) 1));
588
589   STRIP(bl, cdata);
590   SIZE(c) = bl; 
591}
592
593long _ntl_gslowbits(_ntl_gbigint a, long p)
594{
595   static _ntl_gbigint x = 0;
596
597   if (p > NTL_BITS_PER_LONG)
598      p = NTL_BITS_PER_LONG;
599
600   _ntl_glowbits(a, p, &x);
601
602   return _ntl_gtoint(x);
603}
604
605long _ntl_gsetbit(_ntl_gbigint *a, long b)
606{
607   long bl;
608   long sa, aneg;
609   long i;
610   mp_limb_t wh, *adata, tmp;
611
612   if (b<0) ghalt("_ntl_gsetbit: negative index");
613
614   if (ZEROP(*a)) {
615      _ntl_gintoz(1, a);
616      _ntl_glshift(*a, b, a);
617      return 0;
618   }
619
620   bl = (b/NTL_ZZ_NBITS);
621   wh = ((mp_limb_t) 1) << (b - NTL_ZZ_NBITS*bl);
622
623   GET_SIZE_NEG(sa, aneg, *a);
624
625   if (sa > bl) {
626      adata = DATA(*a);
627      tmp = adata[bl] & wh;
628      adata[bl] |= wh;
629      if (tmp) return 1;
630      return 0;
631   } 
632   else {
633      _ntl_gsetlength(a, bl+1);
634      adata = DATA(*a);
635      for (i = sa; i < bl; i++)
636         adata[i] = 0;
637      adata[bl] = wh;
638
639      sa = bl+1;
640      if (aneg) sa = -sa;
641      SIZE(*a) = sa;
642      return 0;
643   }
644}
645
646long _ntl_gswitchbit(_ntl_gbigint *a, long b)
647{
648   long bl;
649   long sa, aneg;
650   long i;
651   mp_limb_t wh, *adata, tmp;
652
653   if (b<0) ghalt("_ntl_gswitchbit: negative index");
654
655
656   if (ZEROP(*a)) {
657      _ntl_gintoz(1, a);
658      _ntl_glshift(*a, b, a);
659      return 0;
660   }
661
662   bl = (b/NTL_ZZ_NBITS);
663   wh = ((mp_limb_t) 1) << (b - NTL_ZZ_NBITS*bl);
664
665   GET_SIZE_NEG(sa, aneg, *a);
666
667   if (sa > bl) {
668      adata = DATA(*a);
669      tmp = adata[bl] & wh;
670      adata[bl] ^= wh;
671
672      if (bl == sa-1) {
673         STRIP(sa, adata);
674         if (aneg) sa = -sa;
675         SIZE(*a) = sa;
676      }
677
678      if (tmp) return 1;
679      return 0;
680   } 
681   else {
682      _ntl_gsetlength(a, bl+1);
683      adata = DATA(*a);
684      for (i = sa; i < bl; i++)
685         adata[i] = 0;
686      adata[bl] = wh;
687
688      sa = bl+1;
689      if (aneg) sa = -sa;
690      SIZE(*a) = sa;
691      return 0;
692   }
693}
694
695long
696_ntl_gweights(
697        long aa
698        )
699{
700        unsigned long a;
701        long res = 0;
702        if (aa < 0) 
703                a = -((unsigned long) aa);
704        else
705                a = aa;
706   
707        while (a) {
708                if (a & 1) res ++;
709                a >>= 1;
710        }
711        return (res);
712}
713
714static long
715gweights_mp_limb(
716        mp_limb_t a
717        )
718{
719        long res = 0;
720   
721        while (a) {
722                if (a & 1) res ++;
723                a >>= 1;
724        }
725        return (res);
726}
727
728long
729_ntl_gweight(
730        _ntl_gbigint a
731        )
732{
733        long i;
734        long sa;
735        mp_limb_t *adata;
736        long res;
737
738        if (!a) return (0);
739
740        sa = SIZE(a);
741        if (sa < 0) sa = -sa;
742        adata = DATA(a);
743
744        res = 0;
745        for (i = 0; i < sa; i++)
746                res += gweights_mp_limb(adata[i]);
747
748        return (res);
749}
750
751long 
752_ntl_g2logs(
753        long aa
754        )
755{
756        long i = 0;
757        unsigned long a;
758
759        if (aa < 0)
760                a = - ((unsigned long) aa);
761        else
762                a = aa;
763
764        while (a>=256)
765                i += 8, a >>= 8;
766        if (a >=16)
767                i += 4, a >>= 4;
768        if (a >= 4)
769                i += 2, a >>= 2;
770        if (a >= 2)
771                i += 2;
772        else if (a >= 1)
773                i++;
774        return (i);
775}
776
777long _ntl_g2log(_ntl_gbigint a)
778{
779   long la;
780   long t;
781
782   if (!a) return 0;
783   la = SIZE(a);
784   if (la == 0) return 0;
785   if (la < 0) la = -la;
786   COUNT_BITS(t, DATA(a)[la-1]);
787   return NTL_ZZ_NBITS*(la - 1) + t;
788}
789
790
791
792long _ntl_gmakeodd(_ntl_gbigint *nn)
793{
794   _ntl_gbigint n = *nn;
795   long shift;
796   mp_limb_t *ndata;
797   mp_limb_t i;
798
799   if (ZEROP(n))
800      return (0);
801
802   shift = 0;
803   ndata = DATA(n);
804
805   while (ndata[shift] == 0)
806      shift++;
807
808   i = ndata[shift];
809
810   shift = NTL_ZZ_NBITS * shift;
811
812   while ((i & 1) == 0) {
813      shift++;
814      i >>= 1;
815   }
816   _ntl_grshift(n, shift, &n);
817   return shift;
818}
819
820
821long _ntl_gnumtwos(_ntl_gbigint n)
822{
823   long shift;
824   mp_limb_t *ndata;
825   mp_limb_t i;
826
827   if (ZEROP(n))
828      return (0);
829
830   shift = 0;
831   ndata = DATA(n);
832
833   while (ndata[shift] == 0)
834      shift++;
835
836   i = ndata[shift];
837
838   shift = NTL_ZZ_NBITS * shift;
839
840   while ((i & 1) == 0) {
841      shift++;
842      i >>= 1;
843   }
844
845   return shift;
846}
847
848
849void _ntl_gand(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc)
850{
851   _ntl_gbigint c;
852   long sa;
853   long sb;
854   long sm;
855   long i;
856   long a_alias, b_alias;
857   mp_limb_t *adata, *bdata, *cdata;
858
859   if (ZEROP(a) || ZEROP(b)) {
860      _ntl_gzero(cc);
861      return;
862   }
863
864   c = *cc;
865   a_alias = (a == c);
866   b_alias = (b == c);
867
868   sa = SIZE(a);
869   if (sa < 0) sa = -sa;
870
871   sb = SIZE(b);
872   if (sb < 0) sb = -sb;
873
874   sm = (sa > sb ? sb : sa);
875
876   _ntl_gsetlength(&c, sm);
877   if (a_alias) a = c;
878   if (b_alias) b = c;
879   *cc = c;
880
881   adata = DATA(a);
882   bdata = DATA(b);
883   cdata = DATA(c);
884
885   for (i = 0; i < sm; i++)
886      cdata[i] = adata[i] & bdata[i];
887
888   STRIP(sm, cdata);
889   SIZE(c) = sm;
890}
891
892
893void _ntl_gxor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc)
894{
895   _ntl_gbigint c;
896   long sa;
897   long sb;
898   long sm;
899   long la;
900   long i;
901   long a_alias, b_alias;
902   mp_limb_t *adata, *bdata, *cdata;
903
904   if (ZEROP(a)) {
905      _ntl_gcopy(b,cc);
906      _ntl_gabs(cc);
907      return;
908   }
909
910   if (ZEROP(b)) {
911      _ntl_gcopy(a,cc);
912      _ntl_gabs(cc);
913      return;
914   }
915
916   c = *cc;
917   a_alias = (a == c);
918   b_alias = (b == c);
919
920   sa = SIZE(a);
921   if (sa < 0) sa = -sa;
922
923   sb = SIZE(b);
924   if (sb < 0) sb = -sb;
925
926   if (sa > sb) {
927      la = sa;
928      sm = sb;
929   } 
930   else {
931      la = sb;
932      sm = sa;
933   }
934
935   _ntl_gsetlength(&c, la);
936   if (a_alias) a = c;
937   if (b_alias) b = c;
938   *cc = c;
939
940   adata = DATA(a);
941   bdata = DATA(b);
942   cdata = DATA(c);
943
944   for (i = 0; i < sm; i ++)
945      cdata[i] = adata[i] ^ bdata[i];
946
947   if (sa > sb)
948      for (;i < la; i++) cdata[i] = adata[i];
949   else
950      for (;i < la; i++) cdata[i] = bdata[i];
951
952   STRIP(la, cdata);
953   SIZE(c) = la;
954}
955
956
957void _ntl_gor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc)
958{
959   _ntl_gbigint c;
960   long sa;
961   long sb;
962   long sm;
963   long la;
964   long i;
965   long a_alias, b_alias;
966   mp_limb_t *adata, *bdata, *cdata;
967
968   if (ZEROP(a)) {
969      _ntl_gcopy(b,cc);
970      _ntl_gabs(cc);
971      return;
972   }
973
974   if (ZEROP(b)) {
975      _ntl_gcopy(a,cc);
976      _ntl_gabs(cc);
977      return;
978   }
979
980   c = *cc;
981   a_alias = (a == c);
982   b_alias = (b == c);
983
984   sa = SIZE(a);
985   if (sa < 0) sa = -sa;
986
987   sb = SIZE(b);
988   if (sb < 0) sb = -sb;
989
990   if (sa > sb) {
991      la = sa;
992      sm = sb;
993   } 
994   else {
995      la = sb;
996      sm = sa;
997   }
998
999   _ntl_gsetlength(&c, la);
1000   if (a_alias) a = c;
1001   if (b_alias) b = c;
1002   *cc = c;
1003
1004   adata = DATA(a);
1005   bdata = DATA(b);
1006   cdata = DATA(c);
1007
1008   for (i = 0; i < sm; i ++)
1009      cdata[i] = adata[i] | bdata[i];
1010
1011   if (sa > sb)
1012      for (;i < la; i++) cdata[i] = adata[i];
1013   else
1014      for (;i < la; i++) cdata[i] = bdata[i];
1015
1016   STRIP(la, cdata);
1017   SIZE(c) = la;
1018}
1019
1020
1021void _ntl_gnegate(_ntl_gbigint *aa)
1022{
1023   _ntl_gbigint a = *aa;
1024   if (a) SIZE(a) = -SIZE(a);
1025}
1026
1027
1028/*
1029 * DIRT: this implementation of _ntl_gintoz relies crucially
1030 * on the assumption that the number of bits per limb_t is at least
1031 * equal to the number of bits per long.
1032 */
1033
1034void _ntl_gintoz(long d, _ntl_gbigint *aa)
1035{
1036   _ntl_gbigint a = *aa;
1037
1038   if (d == 0) {
1039      if (a) SIZE(a) = 0;
1040   }
1041   else if (d > 0) {
1042      if (!a) {
1043         _ntl_gsetlength(&a, 1);
1044         *aa = a;
1045      }
1046   
1047      SIZE(a) = 1;
1048      DATA(a)[0] = d;
1049   }
1050   else {
1051      if (!a) {
1052         _ntl_gsetlength(&a, 1);
1053         *aa = a;
1054      }
1055   
1056      SIZE(a) = -1;
1057      DATA(a)[0] = -((mp_limb_t) d); /* careful! */
1058   }
1059}
1060
1061
1062/*
1063 * DIRT: this implementation of _ntl_guintoz relies crucially
1064 * on the assumption that the number of bits per limb_t is at least
1065 * equal to the number of bits per long.
1066 */
1067
1068void _ntl_guintoz(unsigned long d, _ntl_gbigint *aa)
1069{
1070   _ntl_gbigint a = *aa;
1071
1072   if (d == 0) {
1073      if (a) SIZE(a) = 0;
1074   }
1075   else {
1076      if (!a) {
1077         _ntl_gsetlength(&a, 1);
1078         *aa = a;
1079      }
1080   
1081      SIZE(a) = 1;
1082      DATA(a)[0] = d;
1083   }
1084}
1085
1086
1087long _ntl_gtoint(_ntl_gbigint a)
1088{
1089   unsigned long res = _ntl_gtouint(a);
1090   return NTL_ULONG_TO_LONG(res);
1091}
1092
1093/*
1094 * DIRT: this implementation of _ntl_gtouint relies crucially
1095 * on the assumption that the number of bits per limb_t is at least
1096 * equal to the number of bits per long.
1097 */
1098
1099unsigned long _ntl_gtouint(_ntl_gbigint a)
1100{
1101   if (ZEROP(a)) 
1102      return 0;
1103
1104   if (SIZE(a) > 0) 
1105      return DATA(a)[0];
1106
1107   return -DATA(a)[0];
1108}
1109
1110
1111long _ntl_gcompare(_ntl_gbigint a, _ntl_gbigint b)
1112{
1113   long sa, sb, cmp;
1114   mp_limb_t *adata, *bdata;
1115
1116   if (!a) 
1117      sa = 0;
1118   else
1119      sa = SIZE(a);
1120
1121   if (!b) 
1122      sb = 0;
1123   else
1124      sb = SIZE(b);
1125
1126   if (sa != sb) {
1127      if (sa > sb)
1128         return 1;
1129      else
1130         return -1;
1131   }
1132
1133   if (sa == 0)
1134      return 0;
1135
1136   adata = DATA(a);
1137   bdata = DATA(b);
1138
1139   if (sa > 0) {
1140      cmp = mpn_cmp(adata, bdata, sa);
1141
1142      if (cmp > 0)
1143         return 1;
1144      else if (cmp < 0) 
1145         return -1;
1146      else
1147         return 0;
1148   }
1149   else {
1150      cmp = mpn_cmp(adata, bdata, -sa);
1151
1152      if (cmp > 0)
1153         return -1;
1154      else if (cmp < 0) 
1155         return 1;
1156      else
1157         return 0;
1158   }
1159}
1160
1161
1162long _ntl_gsign(_ntl_gbigint a)
1163{
1164   long sa;
1165
1166   if (!a) return 0;
1167
1168   sa = SIZE(a);
1169   if (sa > 0) return 1;
1170   if (sa == 0) return 0;
1171   return -1;
1172}
1173
1174void _ntl_gabs(_ntl_gbigint *pa)
1175{
1176   _ntl_gbigint a = *pa;
1177
1178   if (!a) return;
1179   if (SIZE(a) < 0) SIZE(a) = -SIZE(a);
1180}
1181
1182long _ntl_gscompare(_ntl_gbigint a, long b)
1183{
1184   if (b == 0) {
1185      long sa;
1186      if (!a) return 0;
1187      sa = SIZE(a);
1188      if (sa > 0) return 1;
1189      if (sa == 0) return 0;
1190      return -1;
1191   }
1192   else {
1193      static _ntl_gbigint B = 0;
1194      _ntl_gintoz(b, &B);
1195      return _ntl_gcompare(a, B);
1196   }
1197}
1198
1199
1200void _ntl_glshift(_ntl_gbigint n, long k, _ntl_gbigint *rres)
1201{
1202   _ntl_gbigint res;
1203   mp_limb_t *ndata, *resdata, *resdata1;
1204   long limb_cnt, i, sn, nneg, sres;
1205   long n_alias;
1206
1207   if (ZEROP(n)) {
1208      _ntl_gzero(rres);
1209      return;
1210   }
1211
1212   res = *rres;
1213   n_alias = (n == res);
1214
1215   if (!k) {
1216      if (!n_alias)
1217         _ntl_gcopy(n, rres);
1218      return;
1219   }
1220
1221   if (k < 0) {
1222      if (k < -NTL_MAX_LONG) 
1223         _ntl_gzero(rres);
1224      else
1225         _ntl_grshift(n, -k, rres);
1226      return;
1227   }
1228
1229   GET_SIZE_NEG(sn, nneg, n);
1230
1231   limb_cnt = k/NTL_ZZ_NBITS;
1232   sres = sn + limb_cnt + 1; 
1233
1234   if (MustAlloc(res, sres)) {
1235      _ntl_gsetlength(&res, sres);
1236      if (n_alias) n = res;
1237      *rres = res;
1238   }
1239
1240   ndata = DATA(n);
1241   resdata = DATA(res);
1242   resdata1 = resdata + limb_cnt;
1243   k %= NTL_ZZ_NBITS;
1244   sres--;
1245
1246   if (k != 0) {
1247      mp_limb_t t = mpn_lshift(resdata1, ndata, sn, k);
1248      if (t != 0) {
1249         resdata[sres] = t;
1250         sres++;
1251      }
1252   }
1253   else {
1254      for (i = sn-1; i >= 0; i--)
1255         resdata1[i] = ndata[i];
1256   }
1257
1258   for (i = 0; i < limb_cnt; i++)
1259      resdata[i] = 0;
1260
1261   if (nneg) sres = -sres;
1262   SIZE(res) = sres;
1263}
1264
1265void _ntl_grshift(_ntl_gbigint n, long k, _ntl_gbigint *rres)
1266{
1267   _ntl_gbigint res;
1268   mp_limb_t *ndata, *resdata, *ndata1;
1269   long limb_cnt, i, sn, nneg, sres;
1270
1271   if (ZEROP(n)) {
1272      _ntl_gzero(rres);
1273      return;
1274   }
1275
1276   if (!k) {
1277      if (n != *rres)
1278         _ntl_gcopy(n, rres);
1279      return;
1280   }
1281
1282   if (k < 0) {
1283      if (k < -NTL_MAX_LONG) ghalt("overflow in _ntl_glshift");
1284      _ntl_glshift(n, -k, rres);
1285      return;
1286   }
1287
1288   GET_SIZE_NEG(sn, nneg, n);
1289
1290   limb_cnt = k/NTL_ZZ_NBITS;
1291
1292   sres = sn - limb_cnt;
1293
1294   if (sres <= 0) {
1295      _ntl_gzero(rres);
1296      return;
1297   }
1298
1299   res = *rres;
1300   if (MustAlloc(res, sres)) {
1301      /* n won't move if res aliases n */
1302      _ntl_gsetlength(&res, sres);
1303      *rres = res;
1304   }
1305
1306   ndata = DATA(n);
1307   resdata = DATA(res);
1308   ndata1 = ndata + limb_cnt;
1309   k %= NTL_ZZ_NBITS;
1310
1311   if (k != 0) {
1312      mpn_rshift(resdata, ndata1, sres, k);
1313      if (resdata[sres-1] == 0)
1314         sres--;
1315   }
1316   else {
1317      for (i = 0; i < sres; i++)
1318         resdata[i] = ndata1[i];
1319   }
1320
1321   if (nneg) sres = -sres;
1322   SIZE(res) = sres;
1323}
1324   
1325   
1326
1327void
1328_ntl_gadd(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc)
1329{
1330   long sa, aneg, sb, bneg, sc, cmp;
1331   mp_limb_t *adata, *bdata, *cdata, carry;
1332   _ntl_gbigint c;
1333   long a_alias, b_alias;
1334
1335   if (ZEROP(a)) {
1336      _ntl_gcopy(b, cc);
1337      return;
1338   }
1339
1340   if (ZEROP(b)) {
1341      _ntl_gcopy(a, cc);
1342      return;
1343   }
1344
1345   GET_SIZE_NEG(sa, aneg, a);
1346   GET_SIZE_NEG(sb, bneg, b);
1347
1348   if (sa < sb) {
1349      SWAP_BIGINT(a, b);
1350      SWAP_LONG(sa, sb);
1351      SWAP_LONG(aneg, bneg);
1352   }
1353
1354   /* sa >= sb */
1355
1356   c = *cc;
1357   a_alias = (a == c);
1358   b_alias = (b == c);
1359
1360   if (aneg == bneg) {
1361      /* same sign => addition */
1362
1363      sc = sa + 1;
1364      if (MustAlloc(c, sc)) {
1365         _ntl_gsetlength(&c, sc);
1366         if (a_alias) a = c; 
1367         if (b_alias) b = c;
1368         *cc = c;
1369      }
1370
1371      adata = DATA(a);
1372      bdata = DATA(b);
1373      cdata = DATA(c);
1374
1375      carry = mpn_add(cdata, adata, sa, bdata, sb);
1376      if (carry) 
1377         cdata[sc-1] = carry;
1378      else
1379         sc--;
1380
1381      if (aneg) sc = -sc;
1382      SIZE(c) = sc;
1383   }
1384   else {
1385      /* opposite sign => subtraction */
1386
1387      sc = sa;
1388      if (MustAlloc(c, sc)) {
1389         _ntl_gsetlength(&c, sc);
1390         if (a_alias) a = c; 
1391         if (b_alias) b = c;
1392         *cc = c;
1393      }
1394
1395      adata = DATA(a);
1396      bdata = DATA(b);
1397      cdata = DATA(c);
1398
1399      if (sa > sb) 
1400         cmp = 1;
1401      else
1402         cmp = mpn_cmp(adata, bdata, sa);
1403
1404      if (cmp == 0) {
1405         SIZE(c) = 0;
1406      }
1407      else {
1408         if (cmp < 0) cmp = 0;
1409         if (cmp > 0) cmp = 1;
1410         /* abs(a) != abs(b) && (abs(a) > abs(b) <=> cmp) */
1411
1412         if (cmp)
1413            mpn_sub(cdata, adata, sa, bdata, sb);
1414         else
1415            mpn_sub(cdata, bdata, sb, adata, sa); /* sa == sb */
1416
1417         STRIP(sc, cdata);
1418         if (aneg == cmp) sc = -sc;
1419         SIZE(c) = sc;
1420      }
1421   }
1422}
1423
1424void
1425_ntl_gsadd(_ntl_gbigint a, long b, _ntl_gbigint *cc)
1426{
1427   static _ntl_gbigint B = 0;
1428   _ntl_gintoz(b, &B);
1429   _ntl_gadd(a, B, cc);
1430}
1431
1432void
1433_ntl_gsub(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc)
1434{
1435   long sa, aneg, sb, bneg, sc, cmp, rev;
1436   mp_limb_t *adata, *bdata, *cdata, carry;
1437   _ntl_gbigint c;
1438   long a_alias, b_alias;
1439
1440   if (ZEROP(a)) {
1441      _ntl_gcopy(b, cc);
1442      c = *cc;
1443      if (c) SIZE(c) = -SIZE(c); 
1444      return;
1445   }
1446
1447   if (ZEROP(b)) {
1448      _ntl_gcopy(a, cc);
1449      return;
1450   }
1451
1452   GET_SIZE_NEG(sa, aneg, a);
1453   GET_SIZE_NEG(sb, bneg, b);
1454
1455   if (sa < sb) {
1456      SWAP_BIGINT(a, b);
1457      SWAP_LONG(sa, sb);
1458      SWAP_LONG(aneg, bneg);
1459      rev = 1;
1460   }
1461   else 
1462      rev = 0;
1463
1464   /* sa >= sb */
1465
1466   c = *cc;
1467   a_alias = (a == c);
1468   b_alias = (b == c);
1469
1470   if (aneg != bneg) {
1471      /* opposite sign => addition */
1472
1473      sc = sa + 1;
1474      if (MustAlloc(c, sc)) {
1475         _ntl_gsetlength(&c, sc);
1476         if (a_alias) a = c; 
1477         if (b_alias) b = c;
1478         *cc = c;
1479      }
1480
1481      adata = DATA(a);
1482      bdata = DATA(b);
1483      cdata = DATA(c);
1484
1485      carry = mpn_add(cdata, adata, sa, bdata, sb);
1486      if (carry) 
1487         cdata[sc-1] = carry;
1488      else
1489         sc--;
1490
1491      if (aneg ^ rev) sc = -sc;
1492      SIZE(c) = sc;
1493   }
1494   else {
1495      /* same sign => subtraction */
1496
1497      sc = sa;
1498      if (MustAlloc(c, sc)) {
1499         _ntl_gsetlength(&c, sc);
1500         if (a_alias) a = c; 
1501         if (b_alias) b = c;
1502         *cc = c;
1503      }
1504
1505      adata = DATA(a);
1506      bdata = DATA(b);
1507      cdata = DATA(c);
1508
1509      if (sa > sb) 
1510         cmp = 1;
1511      else
1512         cmp = mpn_cmp(adata, bdata, sa);
1513
1514      if (cmp == 0) {
1515         SIZE(c) = 0;
1516      }
1517      else {
1518         if (cmp < 0) cmp = 0;
1519         if (cmp > 0) cmp = 1;
1520         /* abs(a) != abs(b) && (abs(a) > abs(b) <=> cmp) */
1521
1522         if (cmp)
1523            mpn_sub(cdata, adata, sa, bdata, sb);
1524         else
1525            mpn_sub(cdata, bdata, sb, adata, sa); /* sa == sb */
1526
1527         STRIP(sc, cdata);
1528         if ((aneg == cmp) ^ rev) sc = -sc;
1529         SIZE(c) = sc;
1530      }
1531   }
1532}
1533
1534void
1535_ntl_gsubpos(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc)
1536{
1537   long sa, sb, sc;
1538   mp_limb_t *adata, *bdata, *cdata;
1539   _ntl_gbigint c;
1540   long a_alias, b_alias;
1541
1542   if (ZEROP(a)) {
1543      _ntl_gzero(cc);
1544      return;
1545   }
1546
1547   if (ZEROP(b)) {
1548      _ntl_gcopy(a, cc);
1549      return;
1550   }
1551
1552   sa = SIZE(a);
1553   sb = SIZE(b);
1554
1555   c = *cc;
1556   a_alias = (a == c);
1557   b_alias = (b == c);
1558
1559   sc = sa;
1560   if (MustAlloc(c, sc)) {
1561      _ntl_gsetlength(&c, sc);
1562      if (a_alias) a = c; 
1563      if (b_alias) b = c;
1564      *cc = c;
1565   }
1566
1567   adata = DATA(a);
1568   bdata = DATA(b);
1569   cdata = DATA(c);
1570
1571   mpn_sub(cdata, adata, sa, bdata, sb);
1572
1573   STRIP(sc, cdata);
1574   SIZE(c) = sc;
1575}
1576
1577void _ntl_gmul(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc)
1578{
1579   static _ntl_gbigint mem = 0;
1580
1581   long sa, aneg, sb, bneg, alias, sc;
1582   mp_limb_t *adata, *bdata, *cdata, msl;
1583   _ntl_gbigint c;
1584
1585   if (ZEROP(a) || ZEROP(b)) {
1586      _ntl_gzero(cc);
1587      return;
1588   }
1589
1590   GET_SIZE_NEG(sa, aneg, a);
1591   GET_SIZE_NEG(sb, bneg, b);
1592
1593   if (a == *cc || b == *cc) {
1594      c = mem;
1595      alias = 1;
1596   }
1597   else {
1598      c = *cc;
1599      alias = 0;
1600   }
1601
1602   sc = sa + sb;
1603   if (MustAlloc(c, sc))
1604      _ntl_gsetlength(&c, sc);
1605
1606   if (alias)
1607      mem = c;
1608   else
1609      *cc = c;
1610
1611   adata = DATA(a);
1612   bdata = DATA(b);
1613   cdata = DATA(c);
1614
1615   if (sa >= sb)
1616      msl = mpn_mul(cdata, adata, sa, bdata, sb);
1617   else
1618      msl = mpn_mul(cdata, bdata, sb, adata, sa);
1619
1620   if (!msl) sc--;
1621   if (aneg != bneg) sc = -sc;
1622   SIZE(c) = sc;
1623
1624   if (alias) _ntl_gcopy(mem, cc);
1625}
1626
1627void _ntl_gsq(_ntl_gbigint a, _ntl_gbigint *cc)
1628{
1629   _ntl_gmul(a, a, cc);
1630   /* this is good enough...eventually, mpn_sqr_n will be called */
1631}
1632
1633
1634/*
1635 * DIRT: this implementation of _ntl_gsmul relies crucially
1636 * on the assumption that the number of bits per limb_t is at least
1637 * equal to the number of bits per long.
1638 */
1639
1640void
1641_ntl_gsmul(_ntl_gbigint a, long d, _ntl_gbigint *bb)
1642{
1643   long sa, sb;
1644   long anegative, bnegative;
1645   _ntl_gbigint b;
1646   mp_limb_t *adata, *bdata;
1647   mp_limb_t dd, carry;
1648   long a_alias;
1649
1650   if (ZEROP(a) || !d) {
1651      _ntl_gzero(bb);
1652      return;
1653   }
1654
1655   GET_SIZE_NEG(sa, anegative, a);
1656
1657   if (d < 0) {
1658      dd = - ((mp_limb_t) d); /* careful ! */
1659      bnegative = 1-anegative;
1660   }
1661   else {
1662      dd = (mp_limb_t) d;
1663      bnegative = anegative;
1664   }
1665
1666   sb = sa + 1;
1667
1668   b = *bb;
1669   a_alias = (a == b);
1670
1671   if (MustAlloc(b, sb)) {
1672      _ntl_gsetlength(&b, sb);
1673      if (a_alias) a = b;
1674      *bb = b;
1675   }
1676
1677   adata = DATA(a);
1678   bdata = DATA(b);
1679
1680   if (dd == 2) 
1681      carry = mpn_lshift(bdata, adata, sa, 1);
1682   else
1683      carry = mpn_mul_1(bdata, adata, sa, dd);
1684
1685   if (carry) 
1686      bdata[sa] = carry;
1687   else
1688      sb--;
1689
1690   if (bnegative) sb = -sb;
1691   SIZE(b) = sb;
1692}
1693
1694/*
1695 * DIRT: this implementation of _ntl_gsdiv relies crucially
1696 * on the assumption that the number of bits per limb_t is at least
1697 * equal to the number of bits per long.
1698 */
1699
1700long _ntl_gsdiv(_ntl_gbigint a, long d, _ntl_gbigint *bb)
1701{
1702   long sa, aneg, sb, dneg;
1703   _ntl_gbigint b;
1704   mp_limb_t dd, *adata, *bdata;
1705   long r;
1706
1707   if (!d) {
1708      ghalt("division by zero in _ntl_gsdiv");
1709   }
1710
1711   if (ZEROP(a)) {
1712      _ntl_gzero(bb);
1713      return (0);
1714   }
1715
1716   GET_SIZE_NEG(sa, aneg, a);
1717
1718   if (d < 0) {
1719      dd = - ((mp_limb_t) d); /* careful ! */
1720      dneg = 1;
1721   }
1722   else {
1723      dd = (mp_limb_t) d;
1724      dneg = 0;
1725   }
1726
1727   sb = sa;
1728   b = *bb;
1729   if (MustAlloc(b, sb)) {
1730      /* if b aliases a, then b won't move */
1731      _ntl_gsetlength(&b, sb);
1732      *bb = b;
1733   }
1734
1735   adata = DATA(a);
1736   bdata = DATA(b);
1737
1738   if (dd == 2) 
1739      r = mpn_rshift(bdata, adata, sa, 1) >> (NTL_ZZ_NBITS - 1);
1740   else
1741      r = mpn_divmod_1(bdata, adata, sa, dd);
1742
1743   if (bdata[sb-1] == 0)
1744      sb--;
1745
1746   SIZE(b) = sb;
1747
1748   if (aneg || dneg) {
1749      if (aneg != dneg) {
1750         if (!r) {
1751            SIZE(b) = -SIZE(b);
1752         }
1753         else {
1754            _ntl_gsadd(b, 1, &b);
1755            SIZE(b) = -SIZE(b);
1756            if (dneg)
1757               r = r + d;
1758            else
1759               r = d - r;
1760            *bb = b;
1761         }
1762      }
1763      else
1764         r = -r;
1765   }
1766
1767   return r;
1768}
1769
1770/*
1771 * DIRT: this implementation of _ntl_gsmod relies crucially
1772 * on the assumption that the number of bits per limb_t is at least
1773 * equal to the number of bits per long.
1774 */
1775
1776long _ntl_gsmod(_ntl_gbigint a, long d)
1777{
1778   long sa, aneg, dneg;
1779   mp_limb_t dd, *adata;
1780   long r;
1781
1782   if (!d) {
1783      ghalt("division by zero in _ntl_gsmod");
1784   }
1785
1786   if (ZEROP(a)) {
1787      return (0);
1788   }
1789
1790   GET_SIZE_NEG(sa, aneg, a);
1791
1792   if (d < 0) {
1793      dd = - ((mp_limb_t) d); /* careful ! */
1794      dneg = 1;
1795   }
1796   else {
1797      dd = (mp_limb_t) d;
1798      dneg = 0;
1799   }
1800
1801   adata = DATA(a);
1802
1803   if (dd == 2) 
1804      r = adata[0] & 1;
1805   else
1806      r = mpn_mod_1(adata, sa, dd);
1807
1808   if (aneg || dneg) {
1809      if (aneg != dneg) {
1810         if (r) {
1811            if (dneg)
1812               r = r + d;
1813            else
1814               r = d - r;
1815         }
1816      }
1817      else
1818         r = -r;
1819   }
1820
1821   return r;
1822}
1823
1824
1825void _ntl_gdiv(_ntl_gbigint a, _ntl_gbigint d, 
1826               _ntl_gbigint *bb, _ntl_gbigint *rr)
1827{
1828   static _ntl_gbigint b = 0, rmem = 0;
1829
1830   _ntl_gbigint r;
1831
1832   long sa, aneg, sb, sd, dneg, sr, in_place;
1833   mp_limb_t *adata, *ddata, *bdata, *rdata;
1834
1835   if (ZEROP(d)) {
1836      ghalt("division by zero in _ntl_gdiv");
1837   }
1838
1839   if (ZEROP(a)) {
1840      if (bb) _ntl_gzero(bb);
1841      if (rr) _ntl_gzero(rr);
1842      return;
1843   }
1844
1845   GET_SIZE_NEG(sa, aneg, a);
1846   GET_SIZE_NEG(sd, dneg, d);
1847
1848   if (!aneg && !dneg && rr && *rr != a && *rr != d) {
1849      in_place = 1;
1850      r = *rr;
1851   }
1852   else {
1853      in_place = 0;
1854      r = rmem;
1855   }
1856
1857   if (sa < sd) {
1858      _ntl_gzero(&b);
1859      _ntl_gcopy(a, &r);
1860      if (aneg) SIZE(r) = -SIZE(r);
1861      goto done;
1862   }
1863
1864   sb = sa-sd+1;
1865   if (MustAlloc(b, sb))
1866      _ntl_gsetlength(&b, sb);
1867
1868   sr = sd;
1869   if (MustAlloc(r, sr))
1870      _ntl_gsetlength(&r, sr);
1871
1872   adata = DATA(a);
1873   ddata = DATA(d);
1874   bdata = DATA(b);
1875   rdata = DATA(r);
1876
1877   mpn_tdiv_qr(bdata, rdata, 0, adata, sa, ddata, sd);
1878
1879   if (bdata[sb-1] == 0)
1880      sb--;
1881   SIZE(b) = sb;
1882
1883   STRIP(sr, rdata);
1884   SIZE(r) = sr;
1885
1886done:
1887
1888   if (aneg || dneg) {
1889      if (aneg != dneg) {
1890         if (ZEROP(r)) {
1891            SIZE(b) = -SIZE(b);
1892         }
1893         else {
1894            if (bb) {
1895               _ntl_gsadd(b, 1, &b);
1896               SIZE(b) = -SIZE(b);
1897            }
1898            if (rr) {
1899               if (dneg)
1900                  _ntl_gadd(r, d, &r);
1901               else
1902                  _ntl_gsub(d, r, &r);
1903            }
1904         }
1905      }
1906      else
1907         SIZE(r) = -SIZE(r);
1908   }
1909
1910   if (bb) _ntl_gcopy(b, bb);
1911
1912   if (in_place)
1913      *rr = r;
1914   else {
1915      if (rr) _ntl_gcopy(r, rr);
1916      rmem = r;
1917   }
1918}
1919
1920
1921/* a simplified mod operation:  assumes a >= 0, d > 0 are non-negative,
1922 * that space for the result has already been allocated,
1923 * and that inputs do not alias output. */
1924
1925static
1926void gmod_simple(_ntl_gbigint a, _ntl_gbigint d, _ntl_gbigint *rr)
1927{
1928   static _ntl_gbigint b = 0;
1929
1930   long sa, sb, sd, sr;
1931   mp_limb_t *adata, *ddata, *bdata, *rdata;
1932   _ntl_gbigint r;
1933
1934   if (ZEROP(a)) {
1935      _ntl_gzero(rr);
1936      return;
1937   }
1938
1939   sa = SIZE(a);
1940   sd = SIZE(d);
1941
1942   if (sa < sd) {
1943      _ntl_gcopy(a, rr);
1944      return;
1945   }
1946
1947   sb = sa-sd+1;
1948   if (MustAlloc(b, sb))
1949      _ntl_gsetlength(&b, sb);
1950
1951   sr = sd;
1952   r = *rr;
1953
1954   adata = DATA(a);
1955   ddata = DATA(d);
1956   bdata = DATA(b);
1957   rdata = DATA(r);
1958
1959   mpn_tdiv_qr(bdata, rdata, 0, adata, sa, ddata, sd);
1960
1961   STRIP(sr, rdata);
1962   SIZE(r) = sr;
1963}
1964
1965
1966void _ntl_gmod(_ntl_gbigint a, _ntl_gbigint d, _ntl_gbigint *rr)
1967{
1968   _ntl_gdiv(a, d, 0, rr);
1969}
1970
1971void _ntl_gquickmod(_ntl_gbigint *rr, _ntl_gbigint d)
1972{
1973   _ntl_gdiv(*rr, d, 0, rr);
1974}
1975
1976void _ntl_gsqrt(_ntl_gbigint n, _ntl_gbigint *rr)
1977{
1978   static _ntl_gbigint r = 0;
1979
1980   long sn, sr;
1981   mp_limb_t *ndata, *rdata;
1982
1983   if (ZEROP(n)) {
1984      _ntl_gzero(rr);
1985      return;
1986   }
1987
1988   sn = SIZE(n);
1989   if (sn < 0) ghalt("negative argument to _ntl_sqrt");
1990
1991   sr = (sn+1)/2;
1992   _ntl_gsetlength(&r, sr);
1993
1994   ndata = DATA(n);
1995   rdata = DATA(r);
1996
1997   mpn_sqrtrem(rdata, 0, ndata, sn);
1998
1999   STRIP(sr, rdata);
2000   SIZE(r) = sr;
2001
2002   _ntl_gcopy(r, rr);
2003}
2004
2005/*
2006 * DIRT: this implementation of _ntl_gsqrts relies crucially
2007 * on the assumption that the number of bits per limb_t is at least
2008 * equal to the number of bits per long.
2009 */
2010
2011long _ntl_gsqrts(long n)
2012{
2013   mp_limb_t ndata, rdata;
2014
2015   if (n == 0) {
2016      return 0;
2017   }
2018
2019   if (n < 0) ghalt("negative argument to _ntl_sqrts");
2020
2021   ndata = n;
2022
2023   mpn_sqrtrem(&rdata, 0, &ndata, 1);
2024
2025   return rdata;
2026}
2027
2028
2029void _ntl_ggcd(_ntl_gbigint m1, _ntl_gbigint m2, _ntl_gbigint *r)
2030{
2031   static _ntl_gbigint s1 = 0, s2 = 0, res = 0;
2032
2033   long k1, k2, k_min, l1, l2, ss1, ss2, sres;
2034
2035   _ntl_gcopy(m1, &s1);
2036   _ntl_gabs(&s1);
2037
2038   _ntl_gcopy(m2, &s2);
2039   _ntl_gabs(&s2);
2040
2041   if (ZEROP(s1)) {
2042      _ntl_gcopy(s2, r);
2043      return;
2044   }
2045
2046   if (ZEROP(s2)) {
2047      _ntl_gcopy(s1, r);
2048      return;
2049   }
2050
2051   k1 = _ntl_gmakeodd(&s1);
2052   k2 = _ntl_gmakeodd(&s2);
2053
2054   if (k1 <= k2)
2055      k_min = k1;
2056   else
2057      k_min = k2;
2058
2059   l1 = _ntl_g2log(s1);
2060   l2 = _ntl_g2log(s2);
2061
2062   ss1 = SIZE(s1);
2063   ss2 = SIZE(s2);
2064
2065   if (ss1 >= ss2)
2066      sres = ss1;
2067   else
2068      sres = ss2;
2069
2070   /* set to max: gmp documentation is unclear on this point */
2071
2072   _ntl_gsetlength(&res, sres);
2073   
2074   if (l1 >= l2)
2075      SIZE(res) = mpn_gcd(DATA(res), DATA(s1), ss1, DATA(s2), ss2);
2076   else
2077      SIZE(res) = mpn_gcd(DATA(res), DATA(s2), ss2, DATA(s1), ss1);
2078
2079   _ntl_glshift(res, k_min, &res);
2080
2081   _ntl_gcopy(res, r);
2082}
2083
2084static long 
2085gxxeucl(
2086   _ntl_gbigint ain,
2087   _ntl_gbigint nin,
2088   _ntl_gbigint *invv,
2089   _ntl_gbigint *uu
2090   )
2091{
2092   static _ntl_gbigint a = 0;
2093   static _ntl_gbigint n = 0;
2094   static _ntl_gbigint q = 0;
2095   static _ntl_gbigint w = 0;
2096   static _ntl_gbigint x = 0;
2097   static _ntl_gbigint y = 0;
2098   static _ntl_gbigint z = 0;
2099   _ntl_gbigint inv = *invv;
2100   _ntl_gbigint u = *uu;
2101   long diff;
2102   long ilo;
2103   long sa;
2104   long sn;
2105   long temp;
2106   long e;
2107   long fast;
2108   long parity;
2109   long gotthem;
2110   mp_limb_t *p;
2111   long try11;
2112   long try12;
2113   long try21;
2114   long try22;
2115   long got11;
2116   long got12;
2117   long got21;
2118   long got22;
2119   double hi;
2120   double lo;
2121   double dt;
2122   double fhi, fhi1;
2123   double flo, flo1;
2124   double num;
2125   double den;
2126   double dirt;
2127
2128   _ntl_gsetlength(&a, (e = (SIZE(ain) > SIZE(nin) ? SIZE(ain) : SIZE(nin))));
2129   _ntl_gsetlength(&n, e);
2130   _ntl_gsetlength(&q, e);
2131   _ntl_gsetlength(&w, e);
2132   _ntl_gsetlength(&x, e);
2133   _ntl_gsetlength(&y, e);
2134   _ntl_gsetlength(&z, e);
2135   _ntl_gsetlength(&inv, e);
2136   *invv = inv;
2137   _ntl_gsetlength(&u, e);
2138   *uu = u;
2139
2140   fhi1 = 1.0 + ((double) 32.0)/NTL_FDOUBLE_PRECISION;
2141   flo1 = 1.0 - ((double) 32.0)/NTL_FDOUBLE_PRECISION;
2142
2143   fhi = 1.0 + ((double) 8.0)/NTL_FDOUBLE_PRECISION;
2144   flo = 1.0 - ((double) 8.0)/NTL_FDOUBLE_PRECISION;
2145
2146   _ntl_gcopy(ain, &a);
2147   _ntl_gcopy(nin, &n);
2148
2149   _ntl_gone(&inv);
2150   _ntl_gzero(&w);
2151
2152   while (SIZE(n) > 0)
2153   {
2154      gotthem = 0;
2155      sa = SIZE(a);
2156      sn = SIZE(n);
2157      diff = sa - sn;
2158      if (!diff || diff == 1)
2159      {
2160         sa = SIZE(a);
2161         p = DATA(a) + (sa-1);
2162         num = (double) (*p) * NTL_ZZ_FRADIX;
2163         if (sa > 1)
2164            num += (*(--p));
2165         num *= NTL_ZZ_FRADIX;
2166         if (sa > 2)
2167            num += (*(p - 1));
2168
2169         sn = SIZE(n);
2170         p = DATA(n) + (sn-1);
2171         den = (double) (*p) * NTL_ZZ_FRADIX;
2172         if (sn > 1)
2173            den += (*(--p));
2174         den *= NTL_ZZ_FRADIX;
2175         if (sn > 2)
2176            den += (*(p - 1));
2177
2178         hi = fhi1 * (num + 1.0) / den;
2179         lo = flo1 * num / (den + 1.0);
2180         if (diff > 0)
2181         {
2182            hi *= NTL_ZZ_FRADIX;
2183            lo *= NTL_ZZ_FRADIX;
2184         }
2185         try11 = 1;
2186         try12 = 0;
2187         try21 = 0;
2188         try22 = 1;
2189         parity = 1;
2190         fast = 1; 
2191         while (fast > 0)
2192         {
2193            parity = 1 - parity;
2194            if (hi >= NTL_SP_BOUND)
2195               fast = 0;
2196            else
2197            {
2198               ilo = (long)lo;
2199               dirt = hi - ilo;
2200               if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi)
2201                  fast = 0;
2202               else
2203               {
2204                  dt = lo-ilo;
2205                  lo = flo / dirt;
2206                  if (dt > 1.0/NTL_FDOUBLE_PRECISION)
2207                     hi = fhi / dt;
2208                  else
2209                     hi = NTL_SP_BOUND;
2210                  temp = try11;
2211                  try11 = try21;
2212                  if ((NTL_WSP_BOUND - temp) / ilo < try21)
2213                     fast = 0;
2214                  else
2215                     try21 = temp + ilo * try21;
2216                  temp = try12;
2217                  try12 = try22;
2218                  if ((NTL_WSP_BOUND - temp) / ilo < try22)
2219                     fast = 0;
2220                  else
2221                     try22 = temp + ilo * try22;
2222                  if ((fast > 0) && (parity > 0))
2223                  {
2224                     gotthem = 1;
2225                     got11 = try11;
2226                     got12 = try12;
2227                     got21 = try21;
2228                     got22 = try22;
2229                  }
2230               }
2231            }
2232         }
2233      }
2234      if (gotthem)
2235      {
2236         _ntl_gsmul(inv, got11, &x);
2237         _ntl_gsmul(w, got12, &y);
2238         _ntl_gsmul(inv, got21, &z);
2239         _ntl_gsmul(w, got22, &w);
2240         _ntl_gadd(x, y, &inv);
2241         _ntl_gadd(z, w, &w);
2242         _ntl_gsmul(a, got11, &x);
2243         _ntl_gsmul(n, got12, &y);
2244         _ntl_gsmul(a, got21, &z);
2245         _ntl_gsmul(n, got22, &n);
2246         _ntl_gsub(x, y, &a);
2247         _ntl_gsub(n, z, &n);
2248      }
2249      else
2250      {
2251         _ntl_gdiv(a, n, &q, &a);
2252         _ntl_gmul(q, w, &x);
2253         _ntl_gadd(inv, x, &inv);
2254         if (!ZEROP(a))
2255         {
2256            _ntl_gdiv(n, a, &q, &n);
2257            _ntl_gmul(q, inv, &x);
2258            _ntl_gadd(w, x, &w);
2259         }
2260         else
2261         {
2262            _ntl_gcopy(n, &a);
2263            _ntl_gzero(&n);
2264            _ntl_gcopy(w, &inv);
2265            _ntl_gnegate(&inv);
2266         }
2267      }
2268   }
2269
2270   if (_ntl_gscompare(a, 1) == 0)
2271      e = 0;
2272   else 
2273      e = 1;
2274
2275   _ntl_gcopy(a, &u);
2276
2277   *invv = inv;
2278   *uu = u;
2279
2280   return (e);
2281}
2282
2283#if 0
2284void
2285_ntl_gexteucl(
2286        _ntl_gbigint aa,
2287        _ntl_gbigint *xa,
2288        _ntl_gbigint bb,
2289        _ntl_gbigint *xb,
2290        _ntl_gbigint *d
2291        )
2292{
2293   static _ntl_gbigint modcon = 0;
2294   static _ntl_gbigint a=0, b=0;
2295   long anegative = 0;
2296   long bnegative = 0;
2297
2298   _ntl_gcopy(aa, &a);
2299   _ntl_gcopy(bb, &b);
2300
2301   if (a && SIZE(a) < 0) {
2302      anegative = 1;
2303      SIZE(a) = -SIZE(a);
2304   }
2305   else
2306      anegative = 0;
2307
2308   if (b && SIZE(b) < 0) {
2309      bnegative = 1;
2310      SIZE(b) = -SIZE(b);
2311   }
2312   else
2313      bnegative = 0;
2314
2315
2316   if (ZEROP(b))
2317   {
2318      _ntl_gone(xa);
2319      _ntl_gzero(xb);
2320      _ntl_gcopy(a, d);
2321      goto done;
2322   }
2323
2324   if (ZEROP(a))
2325   {
2326      _ntl_gzero(xa);
2327      _ntl_gone(xb);
2328      _ntl_gcopy(b, d);
2329      goto done;
2330   }
2331
2332   gxxeucl(a, b, xa, d);
2333   _ntl_gmul(a, *xa, xb);
2334   _ntl_gsub(*d, *xb, xb);
2335   _ntl_gdiv(*xb, b, xb, &modcon);
2336
2337   if (!ZEROP(modcon))
2338   {
2339      ghalt("non-zero remainder in _ntl_gexteucl   BUG");
2340   }
2341
2342
2343done:
2344   if (anegative)
2345   {
2346      _ntl_gnegate(xa);
2347   }
2348   if (bnegative)
2349   {
2350      _ntl_gnegate(xb);
2351   }
2352}
2353#endif
2354
2355void
2356_ntl_gexteucl(
2357        _ntl_gbigint ain,
2358        _ntl_gbigint *xap,
2359        _ntl_gbigint bin,
2360        _ntl_gbigint *xbp,
2361        _ntl_gbigint *dp
2362        )
2363{
2364   if (ZEROP(bin)) {
2365      long asign = _ntl_gsign(ain);
2366
2367      _ntl_gcopy(ain, dp);
2368      _ntl_gabs(dp);
2369      _ntl_gintoz( (asign >= 0 ? 1 : -1), xap);
2370      _ntl_gzero(xbp);
2371   }
2372   else if (ZEROP(ain)) {
2373      long bsign = _ntl_gsign(bin);
2374
2375      _ntl_gcopy(bin, dp);
2376      _ntl_gabs(dp);
2377      _ntl_gzero(xap);
2378      _ntl_gintoz(bsign, xbp); 
2379   }
2380   else {
2381      static _ntl_gbigint a = 0, b = 0, xa = 0, xb = 0, d = 0, tmp = 0;
2382
2383      long sa, aneg, sb, bneg, rev;
2384      mp_limb_t *adata, *bdata, *ddata, *xadata;
2385      mp_size_t sxa, sd;
2386
2387      GET_SIZE_NEG(sa, aneg, ain);
2388      GET_SIZE_NEG(sb, bneg, bin);
2389
2390      _ntl_gsetlength(&a, sa+1); /* +1 because mpn_gcdext may need it */
2391      _ntl_gcopy(ain, &a);
2392
2393      _ntl_gsetlength(&b, sb+1); /* +1 because mpn_gcdext may need it */
2394      _ntl_gcopy(bin, &b);
2395
2396
2397      adata = DATA(a);
2398      bdata = DATA(b);
2399
2400      if (sa < sb || (sa == sb && mpn_cmp(adata, bdata, sa) < 0)) {
2401         SWAP_BIGINT(ain, bin);
2402         SWAP_LONG(sa, sb);
2403         SWAP_LONG(aneg, bneg);
2404         SWAP_LIMB_PTR(adata, bdata);
2405         rev = 1;
2406      }
2407      else 
2408         rev = 0;
2409
2410      _ntl_gsetlength(&d, sa+1); /* +1 because mpn_gcdext may need it...
2411                                    documentation is unclear, but this is
2412                                    what is done in mpz_gcdext */
2413      _ntl_gsetlength(&xa, sa+1); /* ditto */
2414
2415      ddata = DATA(d);
2416      xadata = DATA(xa);
2417
2418      sd = mpn_gcdext(ddata, xadata, &sxa, adata, sa, bdata, sb);
2419
2420      SIZE(d) = sd;
2421      SIZE(xa) = sxa;
2422
2423      if (aneg) _ntl_gnegate(&xa);
2424
2425      _ntl_gmul(ain, xa, &tmp);
2426      _ntl_gsub(d, tmp, &tmp);
2427      _ntl_gdiv(tmp, bin, &xb, &tmp);
2428
2429      if (!ZEROP(tmp)) ghalt("internal bug in _ntl_gexteucl");
2430
2431      if (rev) SWAP_BIGINT(xa, xb);
2432
2433      _ntl_gcopy(xa, xap);
2434      _ntl_gcopy(xb, xbp);
2435      _ntl_gcopy(d, dp); 
2436   }
2437}
2438
2439
2440long _ntl_ginv(_ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint *invv)
2441{
2442   static _ntl_gbigint u = 0;
2443   static _ntl_gbigint d = 0;
2444   static _ntl_gbigint a = 0;
2445   static _ntl_gbigint n = 0;
2446
2447   long sz; 
2448   long sd;
2449   mp_size_t su;
2450
2451   if (_ntl_gscompare(nin, 1) <= 0) {
2452      ghalt("InvMod: second input <= 1");
2453   }
2454
2455   if (_ntl_gsign(ain) < 0) {
2456      ghalt("InvMod: first input negative");
2457   }
2458
2459   if (_ntl_gcompare(ain, nin) >= 0) {
2460      ghalt("InvMod: first input too big");
2461   }
2462
2463   sz = SIZE(nin) + 2;
2464
2465   if (MustAlloc(a, sz))
2466      _ntl_gsetlength(&a, sz);
2467
2468
2469   if (MustAlloc(n, sz))
2470       _ntl_gsetlength(&n, sz);
2471
2472
2473   if (MustAlloc(d, sz))
2474       _ntl_gsetlength(&d, sz);
2475
2476   if (MustAlloc(u, sz))
2477       _ntl_gsetlength(&u, sz);
2478
2479   _ntl_gadd(ain, nin, &a);
2480   _ntl_gcopy(nin, &n);
2481
2482   /* We apply mpn_gcdext to (a, n) = (ain+nin, nin), because that function
2483    * only computes the co-factor of the larger input. This way, we avoid
2484    * a multiplication and a division.
2485    */
2486
2487   sd = mpn_gcdext(DATA(d), DATA(u), &su, DATA(a), SIZE(a), DATA(n), SIZE(n));
2488
2489   SIZE(d) = sd;
2490   SIZE(u) = su;
2491
2492   if (ONEP(d)) {
2493
2494      /*
2495       * We make sure that u is in range 0..n-1, just in case
2496       * GMP is sloppy.
2497       */
2498
2499      while (_ntl_gsign(u) < 0) _ntl_gadd(u, nin, &u);
2500      while (_ntl_gcompare(u, nin) >= 0) _ntl_gsub(u, nin, &u);
2501
2502      _ntl_gcopy(u, invv);
2503      return 0;
2504   }
2505   else {
2506      _ntl_gcopy(d, invv);
2507      return 1;
2508   }
2509}
2510
2511
2512void
2513_ntl_ginvmod(
2514        _ntl_gbigint a,
2515        _ntl_gbigint n,
2516        _ntl_gbigint *c
2517        )
2518{
2519        if (_ntl_ginv(a, n, c))
2520                ghalt("undefined inverse in _ntl_ginvmod");
2521}
2522
2523
2524void
2525_ntl_gaddmod(
2526        _ntl_gbigint a,
2527        _ntl_gbigint b,
2528        _ntl_gbigint n,
2529        _ntl_gbigint *c
2530        )
2531{
2532        if (*c != n) {
2533                _ntl_gadd(a, b, c);
2534                if (_ntl_gcompare(*c, n) >= 0)
2535                        _ntl_gsubpos(*c, n, c);
2536        }
2537        else {
2538                static _ntl_gbigint mem = 0;
2539
2540                _ntl_gadd(a, b, &mem);
2541                if (_ntl_gcompare(mem, n) >= 0)
2542                        _ntl_gsubpos(mem, n, c);
2543                else
2544                        _ntl_gcopy(mem, c);
2545        }
2546}
2547
2548
2549void
2550_ntl_gsubmod(
2551        _ntl_gbigint a,
2552        _ntl_gbigint b,
2553        _ntl_gbigint n,
2554        _ntl_gbigint *c
2555        )
2556{
2557        static _ntl_gbigint mem = 0;
2558        long cmp;
2559
2560        if ((cmp=_ntl_gcompare(a, b)) < 0) {
2561                _ntl_gadd(n, a, &mem);
2562                _ntl_gsubpos(mem, b, c);
2563        } else if (!cmp) 
2564                _ntl_gzero(c);
2565        else 
2566                _ntl_gsubpos(a, b, c);
2567}
2568
2569void
2570_ntl_gsmulmod(
2571        _ntl_gbigint a,
2572        long d,
2573        _ntl_gbigint n,
2574        _ntl_gbigint *c
2575        )
2576{
2577        static _ntl_gbigint mem = 0;
2578
2579        _ntl_gsmul(a, d, &mem);
2580        _ntl_gmod(mem, n, c);
2581}
2582
2583
2584
2585void
2586_ntl_gmulmod(
2587        _ntl_gbigint a,
2588        _ntl_gbigint b,
2589        _ntl_gbigint n,
2590        _ntl_gbigint *c
2591        )
2592{
2593        static _ntl_gbigint mem = 0;
2594
2595        _ntl_gmul(a, b, &mem);
2596        _ntl_gmod(mem, n, c);
2597}
2598
2599void
2600_ntl_gsqmod(
2601        _ntl_gbigint a,
2602        _ntl_gbigint n,
2603        _ntl_gbigint *c
2604        )
2605{
2606        _ntl_gmulmod(a, a, n, c);
2607}
2608
2609
2610double _ntl_gdoub_aux(_ntl_gbigint n)
2611{
2612   double res;
2613   mp_limb_t *ndata;
2614   long i, sn, nneg;
2615
2616   if (!n)
2617      return ((double) 0);
2618
2619   GET_SIZE_NEG(sn, nneg, n);
2620
2621   ndata = DATA(n);
2622
2623   res = 0;
2624   for (i = sn-1; i >= 0; i--)
2625      res = res * NTL_ZZ_FRADIX + ((double) ndata[i]);
2626
2627   if (nneg) res = -res;
2628
2629   return res;
2630}
2631
2632long _ntl_ground_correction(_ntl_gbigint a, long k, long residual)
2633{
2634   long direction;
2635   long p;
2636   long sgn;
2637   long bl;
2638   mp_limb_t wh;
2639   long i;
2640   mp_limb_t *adata;
2641
2642   if (SIZE(a) > 0)
2643      sgn = 1;
2644   else
2645      sgn = -1;
2646
2647   adata = DATA(a);
2648
2649   p = k - 1;
2650   bl = (p/NTL_ZZ_NBITS);
2651   wh = ((mp_limb_t) 1) << (p - NTL_ZZ_NBITS*bl);
2652
2653   if (adata[bl] & wh) {
2654      /* bit is 1...we have to see if lower bits are all 0
2655         in order to implement "round to even" */
2656
2657      if (adata[bl] & (wh - ((mp_limb_t) 1))) 
2658         direction = 1;
2659      else {
2660         i = bl - 1;
2661         while (i >= 0 && adata[i] == 0) i--;
2662         if (i >= 0)
2663            direction = 1;
2664         else
2665            direction = 0;
2666      }
2667
2668      /* use residual to break ties */
2669
2670      if (direction == 0 && residual != 0) {
2671         if (residual == sgn)
2672            direction = 1;
2673         else 
2674            direction = -1;
2675      }
2676
2677      if (direction == 0) {
2678         /* round to even */
2679
2680         wh = wh << 1;
2681
2682         /*
2683          * DIRT: if GMP has non-empty "nails", this won't work.
2684          */
2685
2686         if (wh == 0) {
2687            wh = 1;
2688            bl++;
2689         }
2690
2691         if (adata[bl] & wh)
2692            direction = 1;
2693         else
2694            direction = -1;
2695      }
2696   }
2697   else
2698      direction = -1;
2699
2700   if (direction == 1)
2701      return sgn;
2702
2703   return 0;
2704}
2705
2706
2707
2708
2709double _ntl_gdoub(_ntl_gbigint n)
2710{
2711   static _ntl_gbigint tmp = 0;
2712
2713   long s;
2714   long shamt;
2715   long correction;
2716   double x;
2717
2718   s = _ntl_g2log(n);
2719   shamt = s - NTL_DOUBLE_PRECISION;
2720
2721   if (shamt <= 0)
2722      return _ntl_gdoub_aux(n);
2723
2724   _ntl_grshift(n, shamt, &tmp);
2725
2726   correction = _ntl_ground_correction(n, shamt, 0);
2727
2728   if (correction) _ntl_gsadd(tmp, correction, &tmp);
2729
2730   x = _ntl_gdoub_aux(tmp);
2731
2732   x = _ntl_ldexp(x, shamt);
2733
2734   return x;
2735}
2736
2737
2738double _ntl_glog(_ntl_gbigint n)
2739{
2740   static _ntl_gbigint tmp = 0;
2741
2742   static double log_2;
2743   static long init = 0;
2744
2745   long s;
2746   long shamt;
2747   long correction;
2748   double x;
2749
2750   if (!init) {
2751      log_2 = log(2.0);
2752      init = 1;
2753   }
2754
2755   if (_ntl_gsign(n) <= 0)
2756      ghalt("log argument <= 0");
2757
2758   s = _ntl_g2log(n);
2759   shamt = s - NTL_DOUBLE_PRECISION;
2760
2761   if (shamt <= 0)
2762      return log(_ntl_gdoub_aux(n));
2763
2764   _ntl_grshift(n, shamt, &tmp);
2765
2766   correction = _ntl_ground_correction(n, shamt, 0);
2767
2768   if (correction) _ntl_gsadd(tmp, correction, &tmp);
2769
2770   x = _ntl_gdoub_aux(tmp);
2771
2772   return log(x) + shamt*log_2;
2773}
2774
2775
2776
2777
2778
2779/* To implement _ntl_gdoubtoz, I've implemented essentially the
2780 * same algorithm as in LIP, processing in blocks of
2781 * NTL_SP_NBITS bits, rather than NTL_ZZ_NBITS.
2782 * This is conversion is rather delicate, and I don't want to
2783 * make any new assumptions about the underlying arithmetic.
2784 * This implementation should be quite portable. */
2785
2786void _ntl_gdoubtoz(double a, _ntl_gbigint *xx)
2787{
2788   static _ntl_gbigint x = 0;
2789
2790   long neg, i, t, sz;
2791
2792   a = floor(a);
2793
2794   if (!_ntl_IsFinite(&a))
2795      ghalt("_ntl_gdoubtoz: attempt to convert non-finite value");
2796
2797   if (a < 0) {
2798      a = -a;
2799      neg = 1;
2800   }
2801   else
2802      neg = 0;
2803
2804   if (a == 0) {
2805      _ntl_gzero(xx);
2806      return;
2807   }
2808
2809   sz = 0;
2810   while (a >= 1) {
2811      a = a*(1.0/NTL_SP_FBOUND);
2812      sz++;
2813   }
2814
2815   i = 0;
2816   _ntl_gzero(&x);
2817
2818   while (a != 0) {
2819      i++;
2820      a = a*NTL_SP_FBOUND;
2821      t = (long) a;
2822      a = a - t;
2823
2824      if (i == 1) {
2825         _ntl_gintoz(t, &x);
2826      }
2827      else {
2828         _ntl_glshift(x, NTL_SP_NBITS, &x);
2829         _ntl_gsadd(x, t, &x);
2830      }
2831   }
2832
2833   if (i > sz) ghalt("bug in _ntl_gdoubtoz");
2834
2835   _ntl_glshift(x, (sz-i)*NTL_SP_NBITS, xx);
2836   if (neg) _ntl_gnegate(xx);
2837}
2838
2839
2840
2841/* I've adapted LIP's extended euclidean algorithm to
2842 * do rational reconstruction.  -- VJS.
2843 */
2844
2845
2846long 
2847_ntl_gxxratrecon(
2848   _ntl_gbigint ain,
2849   _ntl_gbigint nin,
2850   _ntl_gbigint num_bound,
2851   _ntl_gbigint den_bound,
2852   _ntl_gbigint *num_out,
2853   _ntl_gbigint *den_out
2854   )
2855{
2856   static _ntl_gbigint a = 0;
2857   static _ntl_gbigint n = 0;
2858   static _ntl_gbigint q = 0;
2859   static _ntl_gbigint w = 0;
2860   static _ntl_gbigint x = 0;
2861   static _ntl_gbigint y = 0;
2862   static _ntl_gbigint z = 0;
2863   static _ntl_gbigint inv = 0;
2864   static _ntl_gbigint u = 0;
2865   static _ntl_gbigint a_bak = 0;
2866   static _ntl_gbigint n_bak = 0;
2867   static _ntl_gbigint inv_bak = 0;
2868   static _ntl_gbigint w_bak = 0;
2869
2870   mp_limb_t *p;
2871
2872   long diff;
2873   long ilo;
2874   long sa;
2875   long sn;
2876   long snum;
2877   long sden;
2878   long e;
2879   long fast;
2880   long temp;
2881   long parity;
2882   long gotthem;
2883   long try11;
2884   long try12;
2885   long try21;
2886   long try22;
2887   long got11;
2888   long got12;
2889   long got21;
2890   long got22;
2891
2892   double hi;
2893   double lo;
2894   double dt;
2895   double fhi, fhi1;
2896   double flo, flo1;
2897   double num;
2898   double den;
2899   double dirt;
2900
2901   if (_ntl_gsign(num_bound) < 0)
2902      ghalt("rational reconstruction: bad numerator bound");
2903
2904   if (!num_bound)
2905      snum = 0;
2906   else
2907      snum = SIZE(num_bound);
2908
2909   if (_ntl_gsign(den_bound) <= 0)
2910      ghalt("rational reconstruction: bad denominator bound");
2911
2912   sden = SIZE(den_bound);
2913
2914   if (_ntl_gsign(nin) <= 0)
2915      ghalt("rational reconstruction: bad modulus");
2916
2917   if (_ntl_gsign(ain) < 0 || _ntl_gcompare(ain, nin) >= 0)
2918      ghalt("rational reconstruction: bad residue");
2919
2920     
2921   e = SIZE(nin);
2922
2923   _ntl_gsetlength(&a, e);
2924   _ntl_gsetlength(&n, e);
2925   _ntl_gsetlength(&q, e);
2926   _ntl_gsetlength(&w, e);
2927   _ntl_gsetlength(&x, e);
2928   _ntl_gsetlength(&y, e);
2929   _ntl_gsetlength(&z, e);
2930   _ntl_gsetlength(&inv, e);
2931   _ntl_gsetlength(&u, e);
2932   _ntl_gsetlength(&a_bak, e);
2933   _ntl_gsetlength(&n_bak, e);
2934   _ntl_gsetlength(&inv_bak, e);
2935   _ntl_gsetlength(&w_bak, e);
2936
2937   fhi1 = 1.0 + ((double) 32.0)/NTL_FDOUBLE_PRECISION;
2938   flo1 = 1.0 - ((double) 32.0)/NTL_FDOUBLE_PRECISION;
2939
2940   fhi = 1.0 + ((double) 8.0)/NTL_FDOUBLE_PRECISION;
2941   flo = 1.0 - ((double) 8.0)/NTL_FDOUBLE_PRECISION;
2942
2943   _ntl_gcopy(ain, &a);
2944   _ntl_gcopy(nin, &n);
2945
2946   _ntl_gone(&inv);
2947   _ntl_gzero(&w);
2948
2949   while (1)
2950   {
2951      if (SIZE(w) >= sden && _ntl_gcompare(w, den_bound) > 0) break;
2952      if (SIZE(n) <= snum && _ntl_gcompare(n, num_bound) <= 0) break;
2953
2954      _ntl_gcopy(a, &a_bak);
2955      _ntl_gcopy(n, &n_bak);
2956      _ntl_gcopy(w, &w_bak);
2957      _ntl_gcopy(inv, &inv_bak);
2958
2959      gotthem = 0;
2960      sa = SIZE(a);
2961      sn = SIZE(n);
2962      diff = sa - sn;
2963      if (!diff || diff == 1)
2964      {
2965         sa = SIZE(a);
2966         p = DATA(a) + (sa-1);
2967         num = (double) (*p) * NTL_ZZ_FRADIX;
2968         if (sa > 1)
2969            num += (*(--p));
2970         num *= NTL_ZZ_FRADIX;
2971         if (sa > 2)
2972            num += (*(p - 1));
2973
2974         sn = SIZE(n);
2975         p = DATA(n) + (sn-1);
2976         den = (double) (*p) * NTL_ZZ_FRADIX;
2977         if (sn > 1)
2978            den += (*(--p));
2979         den *= NTL_ZZ_FRADIX;
2980         if (sn > 2)
2981            den += (*(p - 1));
2982
2983         hi = fhi1 * (num + 1.0) / den;
2984         lo = flo1 * num / (den + 1.0);
2985         if (diff > 0)
2986         {
2987            hi *= NTL_ZZ_FRADIX;
2988            lo *= NTL_ZZ_FRADIX;
2989         }
2990
2991         try11 = 1;
2992         try12 = 0;
2993         try21 = 0;
2994         try22 = 1;
2995         parity = 1;
2996         fast = 1; 
2997         while (fast > 0)
2998         {
2999            parity = 1 - parity;
3000            if (hi >= NTL_SP_BOUND)
3001               fast = 0;
3002            else
3003            {
3004               ilo = (long)lo;
3005               dirt = hi - ilo;
3006               if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi)
3007                  fast = 0;
3008               else
3009               {
3010                  dt = lo-ilo;
3011                  lo = flo / dirt;
3012                  if (dt > 1.0/NTL_FDOUBLE_PRECISION)
3013                     hi = fhi / dt;
3014                  else
3015                     hi = NTL_SP_BOUND;
3016                  temp = try11;
3017                  try11 = try21;
3018                  if ((NTL_WSP_BOUND - temp) / ilo < try21)
3019                     fast = 0;
3020                  else
3021                     try21 = temp + ilo * try21;
3022                  temp = try12;
3023                  try12 = try22;
3024                  if ((NTL_WSP_BOUND - temp) / ilo < try22)
3025                     fast = 0;
3026                  else
3027                     try22 = temp + ilo * try22;
3028                  if ((fast > 0) && (parity > 0))
3029                  {
3030                     gotthem = 1;
3031                     got11 = try11;
3032                     got12 = try12;
3033                     got21 = try21;
3034                     got22 = try22;
3035                  }
3036               }
3037            }
3038         }
3039      }
3040      if (gotthem)
3041      {
3042         _ntl_gsmul(inv, got11, &x);
3043         _ntl_gsmul(w, got12, &y);
3044         _ntl_gsmul(inv, got21, &z);
3045         _ntl_gsmul(w, got22, &w);
3046         _ntl_gadd(x, y, &inv);
3047         _ntl_gadd(z, w, &w);
3048         _ntl_gsmul(a, got11, &x);
3049         _ntl_gsmul(n, got12, &y);
3050         _ntl_gsmul(a, got21, &z);
3051         _ntl_gsmul(n, got22, &n);
3052         _ntl_gsub(x, y, &a);
3053         _ntl_gsub(n, z, &n);
3054      }
3055      else
3056      {
3057         _ntl_gdiv(a, n, &q, &a);
3058         _ntl_gmul(q, w, &x);
3059         _ntl_gadd(inv, x, &inv);
3060         if (!ZEROP(a))
3061         {
3062            _ntl_gdiv(n, a, &q, &n);
3063            _ntl_gmul(q, inv, &x);
3064            _ntl_gadd(w, x, &w);
3065         }
3066         else
3067         {
3068            break;
3069         }
3070      }
3071   }
3072
3073   _ntl_gcopy(a_bak, &a);
3074   _ntl_gcopy(n_bak, &n);
3075   _ntl_gcopy(w_bak, &w);
3076   _ntl_gcopy(inv_bak, &inv);
3077
3078   _ntl_gnegate(&w);
3079
3080   while (1)
3081   {
3082      sa = SIZE(w);
3083      if (sa < 0) SIZE(w) = -sa;
3084      if (SIZE(w) >= sden && _ntl_gcompare(w, den_bound) > 0) return 0;
3085      SIZE(w) = sa;
3086
3087      if (SIZE(n) <= snum && _ntl_gcompare(n, num_bound) <= 0) break;
3088     
3089      fast = 0;
3090      sa = SIZE(a);
3091      sn = SIZE(n);
3092      diff = sa - sn;
3093      if (!diff || diff == 1)
3094      {
3095         sa = SIZE(a);
3096         p = DATA(a) + (sa-1);
3097         num = (double) (*p) * NTL_ZZ_FRADIX;
3098         if (sa > 1)
3099            num += (*(--p));
3100         num *= NTL_ZZ_FRADIX;
3101         if (sa > 2)
3102            num += (*(p - 1));
3103
3104         sn = SIZE(n);
3105         p = DATA(n) + (sn-1);
3106         den = (double) (*p) * NTL_ZZ_FRADIX;
3107         if (sn > 1)
3108            den += (*(--p));
3109         den *= NTL_ZZ_FRADIX;
3110         if (sn > 2)
3111            den += (*(p - 1));
3112
3113         hi = fhi1 * (num + 1.0) / den;
3114         lo = flo1 * num / (den + 1.0);
3115         if (diff > 0)
3116         {
3117            hi *= NTL_ZZ_FRADIX;
3118            lo *= NTL_ZZ_FRADIX;
3119         }
3120
3121         if (hi < NTL_SP_BOUND)
3122         {
3123            ilo = (long)lo;
3124            if (ilo == (long)hi)
3125               fast = 1;
3126         }
3127      }
3128
3129      if (fast) 
3130      {
3131         if (ilo != 0) {
3132            if (ilo == 1) {
3133               _ntl_gsub(inv, w, &inv);
3134               _ntl_gsubpos(a, n, &a);
3135            }
3136            else {
3137               _ntl_gsmul(w, ilo, &x);
3138               _ntl_gsub(inv, x, &inv);
3139               _ntl_gsmul(n, ilo, &x);
3140               _ntl_gsubpos(a, x, &a);
3141            }
3142         }
3143      }
3144      else {
3145         _ntl_gdiv(a, n, &q, &a);
3146         _ntl_gmul(q, w, &x);
3147         _ntl_gsub(inv, x, &inv);
3148      }
3149
3150      _ntl_gswap(&a, &n);
3151      _ntl_gswap(&inv, &w);
3152   }
3153
3154   if (_ntl_gsign(w) < 0) {
3155      _ntl_gnegate(&w);
3156      _ntl_gnegate(&n);
3157   }
3158
3159   _ntl_gcopy(n, num_out);
3160   _ntl_gcopy(w, den_out);
3161
3162   return 1;
3163}
3164
3165
3166void
3167_ntl_gexp(
3168        _ntl_gbigint a,
3169        long e,
3170        _ntl_gbigint *bb
3171        )
3172{
3173        long k;
3174        long len_a;
3175        static _ntl_gbigint res = 0;
3176
3177        if (!e)
3178        {
3179                _ntl_gone(bb);
3180                return;
3181        }
3182
3183        if (e < 0)
3184                ghalt("negative exponent in _ntl_gexp");
3185
3186        if (_ntl_giszero(a))
3187        {
3188                _ntl_gzero(bb);
3189                return;
3190        }
3191
3192        len_a = _ntl_g2log(a);
3193        if (len_a > (NTL_MAX_LONG-(NTL_ZZ_NBITS-1))/e)
3194                ghalt("overflow in _ntl_gexp");
3195
3196        _ntl_gsetlength(&res, (len_a*e+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS);
3197
3198        _ntl_gcopy(a, &res);
3199        k = 1;
3200        while ((k << 1) <= e)
3201                k <<= 1;
3202        while (k >>= 1) {
3203                _ntl_gsq(res, &res);
3204                if (e & k)
3205                        _ntl_gmul(a, res, &res);
3206        }
3207
3208        _ntl_gcopy(res, bb);
3209}
3210
3211void
3212_ntl_gexps(
3213        long a,
3214        long e,
3215        _ntl_gbigint *bb
3216        )
3217{
3218        long k;
3219        long len_a;
3220        static _ntl_gbigint res = 0;
3221
3222        if (!e)
3223        {
3224                _ntl_gone(bb);
3225                return;
3226        }
3227
3228        if (e < 0)
3229                ghalt("negative exponent in _ntl_zexps");
3230
3231        if (!a)
3232        {
3233                _ntl_gzero(bb);
3234                return;
3235        }
3236
3237        len_a = _ntl_g2logs(a);
3238        if (len_a > (NTL_MAX_LONG-(NTL_ZZ_NBITS-1))/e)
3239                ghalt("overflow in _ntl_gexps");
3240
3241        _ntl_gsetlength(&res, (len_a*e+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS);
3242
3243        _ntl_gintoz(a, &res);
3244        k = 1;
3245        while ((k << 1) <= e)
3246                k <<= 1;
3247        while (k >>= 1) {
3248                _ntl_gsq(res, &res);
3249                if (e & k)
3250                        _ntl_gsmul(res, a, &res);
3251        }
3252
3253        _ntl_gcopy(res, bb);
3254}
3255
3256
3257static
3258long OptWinSize(long n)
3259/* finds k that minimizes n/(k+1) + 2^{k-1} */
3260
3261{
3262   long k;
3263   double v, v_new;
3264
3265
3266   v = n/2.0 + 1.0;
3267   k = 1;
3268
3269   for (;;) {
3270      v_new = n/((double)(k+2)) + ((double)(1L << k));
3271      if (v_new >= v) break;
3272      v = v_new;
3273      k++;
3274   }
3275
3276   return k;
3277}
3278
3279
3280
3281/* DIRT: will not work with non-empty "nails" */
3282
3283static
3284mp_limb_t neg_inv_mod_limb(mp_limb_t m0)
3285{
3286   mp_limb_t x; 
3287   long k;
3288
3289   x = 1; 
3290   k = 1; 
3291   while (k < NTL_ZZ_NBITS) {
3292      x += x * (1 - x * m0);
3293      k <<= 1;
3294   }
3295
3296
3297   return - x;
3298}
3299
3300
3301/* Montgomery reduction:
3302 * This computes res = T/b^m mod N, where b = 2^{NTL_ZZ_NBITS}.
3303 * It is assumed that N has n limbs, and that T has at most n + m limbs.
3304 * Also, inv should be set to -N^{-1} mod b.
3305 * Finally, it is assumed that T has space allocated for n + m limbs,
3306 * and that res has space allocated for n limbs. 
3307 * Note: res should not overlap any inputs, and T is destroyed.
3308 * Note: res will have at most n limbs, but may not be fully reduced
3309 * mod N.  In general, we will have res < T/b^m + N.
3310 */
3311
3312/* DIRT: this routine may not work with non-empty "nails" */
3313
3314static
3315void redc(_ntl_gbigint T, _ntl_gbigint N, long m, mp_limb_t inv, 
3316          _ntl_gbigint res) 
3317{
3318   long n, sT, i;
3319   mp_limb_t *Ndata, *Tdata, *resdata, q, d, t, c;
3320
3321   n = SIZE(N);
3322   Ndata = DATA(N);
3323   sT = SIZE(T);
3324   Tdata = DATA(T);
3325   resdata = DATA(res);
3326
3327   for (i = sT; i < m+n; i++)
3328      Tdata[i] = 0;
3329
3330   c = 0;
3331   for (i = 0; i < m; i++) {
3332      q = Tdata[i]*inv;
3333      d = mpn_addmul_1(Tdata+i, Ndata, n, q);
3334      t = Tdata[i+n] + d;
3335      Tdata[i+n] = t + c;
3336      if (t < d || (c == 1 && t + c  == 0)) 
3337         c = 1;
3338      else
3339         c = 0;
3340   }
3341
3342   if (c) {
3343      mpn_sub_n(resdata, Tdata + m, Ndata, n);
3344   }
3345   else {
3346      for (i = 0; i < n; i++)
3347         resdata[i] = Tdata[m + i];
3348   }
3349
3350   i = n;
3351   STRIP(i, resdata);
3352
3353   SIZE(res) = i;
3354   SIZE(T) = 0;
3355}
3356
3357
3358
3359#define REDC_CROSS (32)
3360
3361void _ntl_gpowermod(_ntl_gbigint g, _ntl_gbigint e, _ntl_gbigint F,
3362                    _ntl_gbigint *h)
3363
3364/* h = g^e mod f using "sliding window" algorithm
3365
3366   remark: the notation (h, g, e, F) is strange, because I
3367   copied the code from BB.c.
3368*/
3369
3370{
3371   _ntl_gbigint res, gg, *v, t;
3372   long n, i, k, val, cnt, m;
3373   long use_redc, sF;
3374   mp_limb_t inv;
3375
3376   if (_ntl_gsign(g) < 0 || _ntl_gcompare(g, F) >= 0 || 
3377       _ntl_gscompare(F, 1) <= 0) 
3378      ghalt("PowerMod: bad args");
3379
3380   if (_ntl_gscompare(e, 0) == 0) {
3381      _ntl_gone(h);
3382      return;
3383   }
3384
3385   if (_ntl_gscompare(e, 1) == 0) {
3386      _ntl_gcopy(g, h);
3387      return;
3388   }
3389
3390   if (_ntl_gscompare(e, -1) == 0) {
3391      _ntl_ginvmod(g, F, h);
3392      return;
3393   }
3394
3395   if (_ntl_gscompare(e, 2) == 0) {
3396      _ntl_gsqmod(g, F, h);
3397      return;
3398   }
3399
3400   if (_ntl_gscompare(e, -2) == 0) {
3401      res = 0;
3402      _ntl_gsqmod(g, F, &res);
3403      _ntl_ginvmod(res, F, h);
3404      _ntl_gfree(&res);
3405      return;
3406   }
3407
3408   n = _ntl_g2log(e);
3409
3410   sF = SIZE(F);
3411
3412   res = 0;
3413   _ntl_gsetlength(&res, sF*2);
3414
3415   t = 0;
3416   _ntl_gsetlength(&t, sF*2);
3417
3418   use_redc = (DATA(F)[0] & 1) && sF < REDC_CROSS;
3419
3420   gg = 0;
3421
3422   if (use_redc) {
3423      _ntl_glshift(g, sF*NTL_ZZ_NBITS, &res);
3424      _ntl_gmod(res, F, &gg);
3425
3426      inv = neg_inv_mod_limb(DATA(F)[0]);
3427   }
3428   else
3429      _ntl_gcopy(g, &gg);
3430
3431
3432   if (_ntl_gscompare(g, 2) == 0) {
3433      /* plain square-and-multiply algorithm, optimized for g == 2 */
3434
3435      _ntl_gbigint F1 = 0;
3436
3437      if (use_redc) {
3438         long shamt;
3439
3440         COUNT_BITS(shamt, DATA(F)[sF-1]);
3441         shamt = NTL_ZZ_NBITS - shamt;
3442         _ntl_glshift(F, shamt, &F1);
3443      }
3444
3445      _ntl_gcopy(gg, &res);
3446
3447      for (i = n - 2; i >= 0; i--) {
3448         _ntl_gsq(res, &t);
3449         if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res);
3450
3451         if (_ntl_gbit(e, i)) {
3452            _ntl_gadd(res, res, &res);
3453
3454            if (use_redc) {
3455               while (SIZE(res) > sF) {
3456                  _ntl_gsubpos(res, F1, &res);
3457               }
3458            }
3459            else {
3460               if (_ntl_gcompare(res, F) >= 0)
3461                  _ntl_gsubpos(res, F, &res);
3462            }
3463         }
3464      }
3465
3466
3467      if (use_redc) {
3468         _ntl_gcopy(res, &t);
3469         redc(t, F, sF, inv, res);
3470         if (_ntl_gcompare(res, F) >= 0) {
3471            _ntl_gsub(res, F, &res);
3472         }
3473      }
3474
3475      if (_ntl_gsign(e) < 0) _ntl_ginvmod(res, F, &res);
3476
3477      _ntl_gcopy(res, h);
3478      _ntl_gfree(&res);
3479      _ntl_gfree(&gg);
3480      _ntl_gfree(&t);
3481      _ntl_gfree(&F1);
3482      return;
3483   }
3484
3485
3486   if (n < 16) { 
3487      /* plain square-and-multiply algorithm */
3488
3489      _ntl_gcopy(gg, &res);
3490
3491      for (i = n - 2; i >= 0; i--) {
3492         _ntl_gsq(res, &t);
3493         if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res);
3494
3495         if (_ntl_gbit(e, i)) {
3496            _ntl_gmul(res, gg, &t);
3497            if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res);
3498         }
3499      }
3500
3501
3502      if (use_redc) {
3503         _ntl_gcopy(res, &t);
3504         redc(t, F, sF, inv, res);
3505         if (_ntl_gcompare(res, F) >= 0) {
3506            _ntl_gsub(res, F, &res);
3507         }
3508      }
3509
3510      if (_ntl_gsign(e) < 0) _ntl_ginvmod(res, F, &res);
3511
3512      _ntl_gcopy(res, h);
3513      _ntl_gfree(&res);
3514      _ntl_gfree(&gg);
3515      _ntl_gfree(&t);
3516      return;
3517   }
3518
3519   k = OptWinSize(n);
3520
3521   if (k > 5) k = 5;
3522
3523   v = (_ntl_gbigint *) NTL_MALLOC((1L << (k-1)), sizeof(_ntl_gbigint), 0);
3524   if (!v) ghalt("out of memory");
3525   for (i = 0; i < (1L << (k-1)); i++) {
3526      v[i] = 0; 
3527      _ntl_gsetlength(&v[i], sF);
3528   }
3529
3530   _ntl_gcopy(gg, &v[0]);
3531 
3532   if (k > 1) {
3533      _ntl_gsq(gg, &t);
3534      if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res);
3535
3536      for (i = 1; i < (1L << (k-1)); i++) {
3537         _ntl_gmul(v[i-1], res, &t);
3538         if (use_redc) redc(t, F, sF, inv, v[i]); else _ntl_gmod(t, F, &v[i]);
3539      }
3540   }
3541
3542   _ntl_gcopy(gg, &res);
3543
3544   val = 0;
3545   for (i = n-2; i >= 0; i--) {
3546      val = (val << 1) | _ntl_gbit(e, i); 
3547      if (val == 0) {
3548         _ntl_gsq(res, &t);
3549         if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res);
3550      }
3551      else if (val >= (1L << (k-1)) || i == 0) {
3552         cnt = 0;
3553         while ((val & 1) == 0) {
3554            val = val >> 1;
3555            cnt++;
3556         }
3557
3558         m = val;
3559         while (m > 0) {
3560            _ntl_gsq(res, &t);
3561            if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res);
3562            m = m >> 1;
3563         }
3564
3565         _ntl_gmul(res, v[val >> 1], &t);
3566         if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res);
3567
3568         while (cnt > 0) {
3569            _ntl_gsq(res, &t);
3570            if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res);
3571            cnt--;
3572         }
3573
3574         val = 0;
3575      }
3576   }
3577
3578   if (use_redc) {
3579      _ntl_gcopy(res, &t);
3580      redc(t, F, sF, inv, res);
3581      if (_ntl_gcompare(res, F) >= 0) {
3582         _ntl_gsub(res, F, &res);
3583      }
3584   }
3585
3586   if (_ntl_gsign(e) < 0) _ntl_ginvmod(res, F, &res);
3587
3588   _ntl_gcopy(res, h);
3589
3590   _ntl_gfree(&res);
3591   _ntl_gfree(&gg);
3592   _ntl_gfree(&t);
3593   for (i = 0; i < (1L << (k-1)); i++)
3594      _ntl_gfree(&v[i]);
3595   free(v);
3596}
3597
3598long _ntl_gsize(_ntl_gbigint rep)
3599{
3600   if (!rep)
3601      return 0;
3602   else if (SIZE(rep) < 0)
3603      return -SIZE(rep);
3604   else
3605      return SIZE(rep);
3606}
3607
3608long _ntl_gisone(_ntl_gbigint rep)
3609{
3610   return rep != 0 && SIZE(rep) == 1 && DATA(rep)[0] == 1;
3611}
3612
3613long _ntl_gsptest(_ntl_gbigint rep)
3614{
3615   return !rep || SIZE(rep) == 0 ||
3616          ((SIZE(rep) == 1 || SIZE(rep) == -1) && 
3617           DATA(rep)[0] < ((mp_limb_t) NTL_SP_BOUND));
3618}
3619
3620long _ntl_gwsptest(_ntl_gbigint rep)
3621{
3622   return !rep || SIZE(rep) == 0 ||
3623          ((SIZE(rep) == 1 || SIZE(rep) == -1) && 
3624           DATA(rep)[0] < ((mp_limb_t) NTL_WSP_BOUND));
3625}
3626
3627
3628
3629long _ntl_gcrtinrange(_ntl_gbigint g, _ntl_gbigint a)
3630{
3631   long sa, sg, i; 
3632   mp_limb_t carry, u, v;
3633   mp_limb_t *adata, *gdata;
3634
3635   if (!a || SIZE(a) <= 0) return 0;
3636
3637   sa = SIZE(a);
3638
3639   if (!g) return 1;
3640
3641   sg = SIZE(g);
3642
3643   if (sg == 0) return 1;
3644
3645   if (sg < 0) sg = -sg;
3646
3647   if (sa-sg > 1) return 1;
3648
3649   if (sa-sg < 0) return 0;
3650
3651   adata = DATA(a);
3652   gdata = DATA(g);
3653
3654   carry=0;
3655
3656   if (sa-sg == 1) {
3657      if (adata[sa-1] > ((mp_limb_t) 1)) return 1;
3658      carry = 1;
3659   }
3660
3661   i = sg-1;
3662   u = 0;
3663   v = 0;
3664   while (i >= 0 && u == v) {
3665      u = (carry << (NTL_ZZ_NBITS-1)) + (adata[i] >> 1);
3666      v = gdata[i];
3667      carry = (adata[i] & 1);
3668      i--;
3669   }
3670
3671   if (u == v) {
3672      if (carry) return 1;
3673      return (SIZE(g) > 0);
3674   }
3675   else
3676      return (u > v);
3677}
3678
3679
3680
3681/* DIRT: this routine will not work with non-empty "nails" */
3682
3683void _ntl_gfrombytes(_ntl_gbigint *x, const unsigned char *p, long n)
3684{
3685   long BytesPerLimb;
3686   long lw, r, i, j;
3687   mp_limb_t *xp, t;
3688
3689   if (n <= 0) {
3690      x = 0;
3691      return;
3692   }
3693
3694   BytesPerLimb = NTL_ZZ_NBITS/8;
3695
3696
3697   lw = n/BytesPerLimb;
3698   r = n - lw*BytesPerLimb;
3699
3700   if (r != 0) 
3701      lw++;
3702   else
3703      r = BytesPerLimb;
3704
3705   _ntl_gsetlength(x, lw); 
3706   xp = DATA(*x);
3707
3708   for (i = 0; i < lw-1; i++) {
3709      t = 0;
3710      for (j = 0; j < BytesPerLimb; j++) {
3711         t >>= 8;
3712         t += (((mp_limb_t)(*p)) & ((mp_limb_t) 255)) << ((BytesPerLimb-1)*8);
3713         p++;
3714      }
3715      xp[i] = t;
3716   }
3717
3718   t = 0;
3719   for (j = 0; j < r; j++) {
3720      t >>= 8;
3721      t += (((mp_limb_t)(*p)) & ((mp_limb_t) 255)) << ((BytesPerLimb-1)*8);
3722      p++;
3723   }
3724
3725   t >>= (BytesPerLimb-r)*8;
3726   xp[lw-1] = t;
3727
3728   STRIP(lw, xp);
3729   SIZE(*x) = lw; 
3730}
3731
3732
3733
3734/* DIRT: this routine will not work with non-empty "nails" */
3735
3736void _ntl_gbytesfromz(unsigned char *p, _ntl_gbigint a, long n)
3737{
3738   long BytesPerLimb;
3739   long lbits, lbytes, min_bytes, min_words, r;
3740   long i, j;
3741   mp_limb_t *ap, t;
3742
3743   if (n < 0) n = 0;
3744
3745   BytesPerLimb = NTL_ZZ_NBITS/8;
3746
3747   lbits = _ntl_g2log(a);
3748   lbytes = (lbits+7)/8;
3749
3750   min_bytes = (lbytes < n) ? lbytes : n;
3751
3752   min_words = min_bytes/BytesPerLimb;
3753
3754   r = min_bytes - min_words*BytesPerLimb;
3755   if (r != 0)
3756      min_words++;
3757   else
3758      r = BytesPerLimb;
3759
3760   if (a)
3761      ap = DATA(a);
3762   else
3763      ap = 0;
3764
3765
3766   for (i = 0; i < min_words-1; i++) {
3767      t = ap[i];
3768      for (j = 0; j < BytesPerLimb; j++) {
3769         *p = t & ((mp_limb_t) 255);
3770         t >>= 8;
3771         p++;
3772      }
3773   }
3774
3775   if (min_words > 0) {
3776      t = ap[min_words-1];
3777      for (j = 0; j < r; j++) {
3778         *p = t & ((mp_limb_t) 255);
3779         t >>= 8;
3780         p++;
3781      }
3782   }
3783
3784   for (j = min_bytes; j < n; j++) {
3785      *p = 0;
3786      p++;
3787   }
3788}
3789
3790
3791
3792
3793long _ntl_gblock_construct_alloc(_ntl_gbigint *x, long d, long n)
3794{
3795   long d1, sz, AllocAmt, m, j, alloc;
3796   char *p;
3797   _ntl_gbigint t;
3798
3799
3800   /* check n value */
3801
3802   if (n <= 0)
3803      ghalt("block construct: n must be positive");
3804
3805
3806
3807   /* check d value */
3808
3809   if (d <= 0)
3810      ghalt("block construct: d must be positive");
3811
3812   if (NTL_OVERFLOW(d, NTL_ZZ_NBITS, NTL_ZZ_NBITS))
3813      ghalt("block construct: d too large");
3814
3815#ifdef NTL_SMALL_MP_SIZE_T
3816   /* this makes sure that numbers don't get too big for GMP */
3817   if (d >= (1L << (NTL_BITS_PER_INT-4)))
3818      ghalt("size too big for GMP");
3819#endif
3820
3821   d1 = d + 1;
3822
3823   if (STORAGE_OVF(d1))
3824      ghalt("block construct: d too large");
3825
3826
3827
3828   sz = STORAGE(d1);
3829
3830   AllocAmt = NTL_MAX_ALLOC_BLOCK/sz;
3831   if (AllocAmt == 0) AllocAmt = 1;
3832
3833   if (AllocAmt < n)
3834      m = AllocAmt;
3835   else
3836      m = n;
3837
3838   p = (char *) NTL_MALLOC(m, sz, 0);
3839   if (!p) ghalt("out of memory in _ntl_gblock_construct");
3840
3841   *x = (_ntl_gbigint) p;
3842
3843   for (j = 0; j < m; j++) {
3844      t = (_ntl_gbigint) p;
3845      alloc = (d1 << 2) | 1;
3846      if (j < m-1) alloc |= 2;
3847      ALLOC(t) = alloc;
3848      SIZE(t) = 0;
3849      p += sz;
3850   }
3851
3852   return m;
3853}
3854
3855
3856void _ntl_gblock_construct_set(_ntl_gbigint x, _ntl_gbigint *y, long i)
3857{
3858   long d1, sz;
3859
3860
3861   d1 = ALLOC(x) >> 2;
3862   sz = STORAGE(d1);
3863
3864   *y = (_ntl_gbigint) (((char *) x) + i*sz);
3865}
3866
3867
3868long _ntl_gblock_destroy(_ntl_gbigint x)
3869{
3870   long d1, sz, alloc, m;
3871   char *p;
3872   _ntl_gbigint t;
3873
3874   
3875   d1 = ALLOC(x) >> 2;
3876   sz = STORAGE(d1);
3877
3878   p = (char *) x;
3879
3880   m = 1;
3881
3882   for (;;) {
3883      t = (_ntl_gbigint) p;
3884      alloc = ALLOC(t);
3885      if ((alloc & 1) == 0) 
3886         ghalt("corrupted memory detected in _ntl_gblock_destroy");
3887      if ((alloc & 2) == 0) break;
3888      m++;
3889      p += sz;
3890   }
3891
3892   free(x);
3893   return m;
3894}
3895
3896
3897long _ntl_gblock_storage(long d)
3898{
3899   long d1, sz; 
3900
3901   d1 = d + 1;
3902   sz = STORAGE(d1) + sizeof(_ntl_gbigint);
3903
3904   return sz;
3905}
3906
3907
3908/*
3909 * This is a completely portable MulMod routine.
3910 */
3911
3912#define SP_MUL_MOD(r, a, b, n)  \
3913{  \
3914   long l__a = (a);  \
3915   long l__b = (b);  \
3916   long l__n = (n);  \
3917   long l__q;  \
3918   unsigned long l__res;  \
3919  \
3920   l__q  = (long) ((((double) l__a) * ((double) l__b)) / ((double) l__n));  \
3921   l__res = ((unsigned long) l__a)*((unsigned long) l__b) - \
3922            ((unsigned long) l__q)*((unsigned long) l__n);  \
3923   if (l__res >> (NTL_BITS_PER_LONG-1))  \
3924      l__res += l__n;  \
3925   else if (((long) l__res) >= l__n)  \
3926      l__res -= l__n;  \
3927  \
3928   r = (long) l__res;  \
3929}
3930
3931
3932
3933
3934#if (NTL_ARITH_RIGHT_SHIFT && defined(NTL_AVOID_BRANCHING) && !defined(NTL_CLEAN_INT))
3935
3936#define SP_MUL_MOD2(res, a, b, n, bninv) \
3937do {  \
3938   long _a = (a);  \
3939   long _b = (b);  \
3940   long _n = (n);  \
3941   double _bninv = (bninv);  \
3942   long _q, _res;  \
3943  \
3944   _q  = (long) (((double) _a) * _bninv);  \
3945   _res = _a*_b - _q*_n;  \
3946  \
3947   _res += (_res >> (NTL_BITS_PER_LONG-1)) & _n;  \
3948   _res -= _n;  \
3949   _res += (_res >> (NTL_BITS_PER_LONG-1)) & _n;  \
3950  \
3951   res = _res;  \
3952} while (0) 
3953
3954#else
3955
3956/*
3957 * This is a completely portable MulMod routine.
3958 */
3959
3960#define SP_MUL_MOD2(res, a, b, n, bninv) \
3961do { \
3962   long _a = (a); \
3963   long _b = (b); \
3964   long _n = (n); \
3965   double _bninv = (bninv); \
3966   long _q;  \
3967   unsigned long _res; \
3968 \
3969   _q  = (long) (((double) _a) * _bninv); \
3970   _res = ((unsigned long) _a)*((unsigned long) _b)  - \
3971          ((unsigned long) _q)*((unsigned long) _n); \
3972 \
3973   if (_res >> (NTL_BITS_PER_LONG-1))  \
3974      _res += _n;  \
3975   else if (((long) _res) >= _n)  \
3976      _res -= _n;  \
3977 \
3978   res = (long) _res; \
3979} while (0)
3980
3981#endif
3982
3983
3984static
3985long SpecialPower(long e, long p)
3986{
3987   long a;
3988   long x, y;
3989
3990   a = (long) ((((mp_limb_t) 1) << (NTL_ZZ_NBITS-2)) % ((mp_limb_t) p));
3991   SP_MUL_MOD(a, a, 2, p);
3992   SP_MUL_MOD(a, a, 2, p);
3993
3994   x = 1;
3995   y = a;
3996   while (e) {
3997      if (e & 1) SP_MUL_MOD(x, x, y, p);
3998      SP_MUL_MOD(y, y, y, p);
3999      e = e >> 1;
4000   }
4001
4002   return x;
4003}
4004
4005
4006static
4007void sp_ext_eucl(long *dd, long *ss, long *tt, long a, long b)
4008{
4009   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
4010
4011   long aneg = 0, bneg = 0;
4012
4013   if (a < 0) {
4014      if (a < -NTL_MAX_LONG) ghalt("integer overflow");
4015      a = -a;
4016      aneg = 1;
4017   }
4018
4019   if (b < 0) {
4020      if (b < -NTL_MAX_LONG) ghalt("integer overflow");
4021      b = -b;
4022      bneg = 1;
4023   }
4024
4025   u1=1; v1=0;
4026   u2=0; v2=1;
4027   u = a; v = b;
4028
4029   while (v != 0) {
4030      q = u / v;
4031      r = u % v;
4032      u = v;
4033      v = r;
4034      u0 = u2;
4035      v0 = v2;
4036      u2 =  u1 - q*u2;
4037      v2 = v1- q*v2;
4038      u1 = u0;
4039      v1 = v0;
4040   }
4041
4042   if (aneg)
4043      u1 = -u1;
4044
4045   if (bneg)
4046      v1 = -v1;
4047
4048   *dd = u;
4049   *ss = u1;
4050   *tt = v1;
4051}
4052
4053static
4054long sp_inv_mod(long a, long n)
4055{
4056   long d, s, t;
4057
4058   sp_ext_eucl(&d, &s, &t, a, n);
4059   if (d != 1) ghalt("inverse undefined");
4060   if (s < 0)
4061      return s + n;
4062   else
4063      return s;
4064}
4065
4066/* ------ HERE ------ */
4067
4068
4069
4070struct crt_body_gmp {
4071   _ntl_gbigint *v;
4072   long sbuf;
4073   long n;
4074   _ntl_gbigint buf;
4075};
4076
4077struct crt_body_gmp1 {
4078   long n;
4079   long levels;
4080   long *primes;
4081   long *inv_vec;
4082   long *val_vec;
4083   long *index_vec;
4084   _ntl_gbigint *prod_vec;
4085   _ntl_gbigint *rem_vec;
4086   _ntl_gbigint *coeff_vec;
4087   _ntl_gbigint temps[2];
4088   _ntl_gbigint modulus;
4089};
4090
4091
4092struct crt_body {
4093   long strategy;
4094
4095   union {
4096      struct crt_body_gmp G;
4097      struct crt_body_gmp1 G1;
4098   } U;
4099};
4100
4101
4102
4103
4104void _ntl_gcrt_struct_init(void **crt_struct, long n, _ntl_gbigint p,
4105                          const long *primes)
4106{
4107   struct crt_body *c;
4108
4109   c = (struct crt_body *) NTL_MALLOC(1, sizeof(struct crt_body), 0);
4110   if (!c) ghalt("out of memory");
4111
4112   if (n >= 600) {
4113      struct crt_body_gmp1 *C = &c->U.G1;
4114      long *q;
4115      long i, j;
4116      long levels, vec_len;
4117      long *val_vec, *inv_vec;
4118      long *index_vec;
4119      _ntl_gbigint *prod_vec, *rem_vec, *coeff_vec;
4120      _ntl_gbigint *temps;
4121
4122      C->modulus = 0;
4123      _ntl_gcopy(p, &C->modulus);
4124
4125      temps = &C->temps[0];
4126
4127      temps[0] = 0;
4128      temps[1] = 0;
4129   
4130      q = (long *) NTL_MALLOC(n, sizeof(long), 0);
4131      if (!q) ghalt("out of memory");
4132
4133      val_vec = (long *) NTL_MALLOC(n, sizeof(long), 0);
4134      if (!val_vec) ghalt("out of memory");
4135
4136      inv_vec = (long *) NTL_MALLOC(n, sizeof(long), 0);
4137      if (!inv_vec) ghalt("out of memory");
4138
4139      for (i = 0; i < n; i++)
4140         q[i] = primes[i];
4141
4142      levels = 0;
4143      while ((n >> levels) >= 16) levels++;
4144
4145      vec_len = (1L << levels) - 1;
4146
4147      index_vec = (long *) NTL_MALLOC((vec_len+1), sizeof(long), 0);
4148      if (!index_vec) ghalt("out of memory");
4149
4150      prod_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0);
4151      if (!prod_vec) ghalt("out of memory");
4152
4153      rem_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0);
4154      if (!rem_vec) ghalt("out of memory");
4155
4156      coeff_vec = (_ntl_gbigint *) NTL_MALLOC(n, sizeof(_ntl_gbigint), 0);
4157      if (!coeff_vec) ghalt("out of memory");
4158
4159      for (i = 0; i < vec_len; i++)
4160         prod_vec[i] = 0;
4161
4162      for (i = 0; i < vec_len; i++)
4163         rem_vec[i] = 0;
4164
4165      for (i = 0; i < n; i++)
4166         coeff_vec[i] = 0;
4167
4168      index_vec[0] = 0;
4169      index_vec[1] = n;
4170
4171      for (i = 0; i <= levels-2; i++) {
4172         long start = (1L << i) - 1;
4173         long finish = (1L << (i+1)) - 2;
4174         for (j = finish; j >= start; j--) {
4175            index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2;
4176            index_vec[2*j+1] = index_vec[j];
4177         }
4178         index_vec[2*finish+3] = n;
4179      }
4180
4181      for (i = (1L << (levels-1)) - 1; i < vec_len; i++) {
4182         /* multiply primes index_vec[i]..index_vec[i+1]-1 into
4183          * prod_vec[i]
4184          */
4185
4186         _ntl_gone(&prod_vec[i]);
4187         for (j = index_vec[i]; j < index_vec[i+1]; j++)
4188            _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]);
4189      }
4190
4191      for (i = (1L << (levels-1)) - 1; i < vec_len; i++) {
4192         for (j = index_vec[i]; j < index_vec[i+1]; j++)
4193            _ntl_gsdiv(prod_vec[i], q[j], &coeff_vec[j]);
4194      }
4195
4196      for (i = (1L << (levels-1)) - 2; i >= 0; i--)
4197         _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]);
4198
4199
4200      /* the following is asymptotically the bottleneck...but it
4201       * it probably doesn't matter. */
4202
4203      for (i = 0; i < n; i++) {
4204         long tt;
4205         _ntl_gsdiv(prod_vec[0], q[i], &temps[0]);
4206         tt = mpn_mod_1(DATA(temps[0]), SIZE(temps[0]), q[i]);
4207         inv_vec[i] = sp_inv_mod(tt, q[i]);
4208      }
4209
4210      c->strategy = 2;
4211      C->n = n;
4212      C->primes = q;
4213      C->val_vec = val_vec;
4214      C->inv_vec = inv_vec;
4215      C->levels = levels;
4216      C->index_vec = index_vec;
4217      C->prod_vec = prod_vec;
4218      C->rem_vec = rem_vec;
4219      C->coeff_vec = coeff_vec;
4220
4221      *crt_struct = (void *) c;
4222      return;
4223   }
4224
4225   {
4226      struct crt_body_gmp *C = &c->U.G;
4227      long i;
4228      c->strategy = 1;
4229
4230      C->n = n;
4231      C->v = (_ntl_gbigint *) NTL_MALLOC(n, sizeof(_ntl_gbigint), 0);
4232      if (!C->v) ghalt("out of memory");
4233
4234      for (i = 0; i < n; i++)
4235         C->v[i] = 0;
4236
4237      C->sbuf = SIZE(p)+2;
4238
4239      C->buf = 0;
4240      _ntl_gsetlength(&C->buf, C->sbuf);
4241
4242      *crt_struct = (void *) c;
4243      return;
4244   }
4245}
4246
4247void _ntl_gcrt_struct_insert(void *crt_struct, long i, _ntl_gbigint m)
4248{
4249   struct crt_body *c = (struct crt_body *) crt_struct;
4250
4251   switch (c->strategy) {
4252   case 1: {
4253      _ntl_gcopy(m, &c->U.G.v[i]);
4254      break;
4255   }
4256
4257   default:
4258      ghalt("_ntl_gcrt_struct_insert: inconsistent strategy");
4259
4260   } /* end switch */
4261}
4262
4263
4264void _ntl_gcrt_struct_free(void *crt_struct)
4265{
4266   struct crt_body *c = (struct crt_body *) crt_struct;
4267
4268   switch (c->strategy) {
4269   case 1: {
4270      struct crt_body_gmp *C = &c->U.G;
4271      long i, n;
4272
4273      n = C->n;
4274
4275      for (i = 0; i < n; i++)
4276         _ntl_gfree(&C->v[i]);
4277
4278      _ntl_gfree(&C->buf);
4279
4280      free(C->v);
4281
4282      free(c);
4283      break;
4284   }
4285
4286   case 2: { 
4287      struct crt_body_gmp1 *C = &c->U.G1;
4288      long n = C->n;
4289      long levels = C->levels;
4290      long *primes = C->primes;
4291      long *inv_vec = C->inv_vec;
4292      long *val_vec = C->val_vec;
4293      long *index_vec = C->index_vec;
4294      _ntl_gbigint *prod_vec = C->prod_vec;
4295      _ntl_gbigint *rem_vec = C->rem_vec;
4296      _ntl_gbigint *coeff_vec = C->coeff_vec;
4297      _ntl_gbigint *temps = C->temps;
4298      _ntl_gbigint modulus = C->modulus;
4299      long vec_len = (1L << levels) - 1;
4300
4301      long i;
4302
4303      for (i = 0; i < vec_len; i++)
4304         _ntl_gfree(&prod_vec[i]);
4305
4306      for (i = 0; i < vec_len; i++)
4307         _ntl_gfree(&rem_vec[i]);
4308
4309      for (i = 0; i < n; i++)
4310         _ntl_gfree(&coeff_vec[i]);
4311
4312      _ntl_gfree(&temps[0]);
4313      _ntl_gfree(&temps[1]);
4314
4315      _ntl_gfree(&modulus);
4316
4317      free(primes);
4318      free(inv_vec);
4319      free(val_vec);
4320      free(index_vec);
4321      free(prod_vec);
4322      free(rem_vec);
4323      free(coeff_vec);
4324
4325      free(c);
4326      break;
4327   }
4328
4329   default:
4330
4331      ghalt("_ntl_gcrt_struct_free: inconsistent strategy");
4332
4333   } /* end case */
4334}
4335
4336static
4337void gadd_mul_many(_ntl_gbigint *res, _ntl_gbigint *a, long *b, 
4338                      long n, long sz)
4339
4340{
4341   mp_limb_t *xx, *yy; 
4342   long i, sx;
4343   long sy;
4344   mp_limb_t carry;
4345
4346   sx = sz + 2;
4347   if (MustAlloc(*res, sx))
4348      _ntl_gsetlength(res, sx);
4349
4350   xx = DATA(*res);
4351
4352   for (i = 0; i < sx; i++)
4353      xx[i] = 0;
4354
4355   for (i = 0; i < n; i++) {
4356      if (!a[i]) continue;
4357
4358      yy = DATA(a[i]);
4359      sy = SIZE(a[i]); 
4360
4361      if (!sy || !b[i]) continue;
4362
4363      carry = mpn_addmul_1(xx, yy, sy, b[i]);
4364      yy = xx + sy;
4365      *yy += carry;
4366
4367      if (*yy < carry) { /* unsigned comparison! */
4368         do {
4369            yy++;
4370            *yy += 1;
4371         } while (*yy == 0);
4372      }
4373   }
4374
4375   while (sx > 0 && xx[sx-1] == 0) sx--;
4376   SIZE(*res) = sx;
4377}
4378
4379void _ntl_gcrt_struct_eval(void *crt_struct, _ntl_gbigint *x, const long *b)
4380{
4381   struct crt_body *c = (struct crt_body *) crt_struct;
4382
4383   switch (c->strategy) {
4384
4385   case 1: {
4386      struct crt_body_gmp *C = &c->U.G;
4387
4388      mp_limb_t *xx, *yy; 
4389      _ntl_gbigint *a;
4390      long i, sx, n;
4391      long sy;
4392      mp_limb_t carry;
4393   
4394      n = C->n;
4395      sx = C->sbuf;
4396   
4397      xx = DATA(C->buf);
4398
4399      for (i = 0; i < sx; i++)
4400         xx[i] = 0;
4401   
4402      a = C->v;
4403   
4404      for (i = 0; i < n; i++) {
4405         if (!a[i]) continue;
4406
4407         yy = DATA(a[i]);
4408         sy = SIZE(a[i]); 
4409   
4410         if (!sy || !b[i]) continue;
4411   
4412         carry = mpn_addmul_1(xx, yy, sy, b[i]);
4413         yy = xx + sy;
4414         *yy += carry;
4415
4416         if (*yy < carry) { /* unsigned comparison! */
4417            do {
4418               yy++;
4419               *yy += 1;
4420            } while (*yy == 0);
4421         }
4422      }
4423   
4424      while (sx > 0 && xx[sx-1] == 0) sx--;
4425      SIZE(C->buf) = sx;
4426      _ntl_gcopy(C->buf, x);
4427      break;
4428   }
4429
4430   case 2: {
4431      struct crt_body_gmp1 *C = &c->U.G1;
4432
4433      long n = C->n;
4434      long levels = C->levels;
4435      long *primes = C->primes;
4436      long *inv_vec = C->inv_vec;
4437      long *val_vec = C->val_vec;
4438      long *index_vec = C->index_vec;
4439      _ntl_gbigint *prod_vec = C->prod_vec;
4440      _ntl_gbigint *rem_vec = C->rem_vec;
4441      _ntl_gbigint *coeff_vec = C->coeff_vec;
4442      _ntl_gbigint *temps = C->temps;
4443      long vec_len = (1L << levels) - 1;
4444
4445      long i, j;
4446
4447      for (i = 0; i < n; i++) {
4448         SP_MUL_MOD(val_vec[i], b[i], inv_vec[i], primes[i]);
4449      }
4450
4451      for (i = (1L << (levels-1)) - 1; i < vec_len; i++) {
4452         long j1 = index_vec[i];
4453         long j2 = index_vec[i+1];
4454         gadd_mul_many(&rem_vec[i], &coeff_vec[j1], &val_vec[j1], j2-j1, 
4455                          SIZE(prod_vec[i]));
4456      }
4457
4458      for (i = (1L << (levels-1)) - 2; i >= 0; i--) {
4459         _ntl_gmul(prod_vec[2*i+1], rem_vec[2*i+2], &temps[0]);
4460         _ntl_gmul(rem_vec[2*i+1], prod_vec[2*i+2], &temps[1]);
4461         _ntl_gadd(temps[0], temps[1], &rem_vec[i]);
4462      }
4463
4464      /* temps[0] = rem_vec[0] mod prod_vec[0] (least absolute residue) */
4465      _ntl_gmod(rem_vec[0], prod_vec[0], &temps[0]);
4466      _ntl_gsub(temps[0], prod_vec[0], &temps[1]);
4467      _ntl_gnegate(&temps[1]);
4468      if (_ntl_gcompare(temps[0], temps[1]) > 0) {
4469         _ntl_gnegate(&temps[1]);
4470         _ntl_gcopy(temps[1], &temps[0]);
4471      }
4472
4473      _ntl_gmod(temps[0], C->modulus, &temps[1]);
4474      _ntl_gcopy(temps[1], x);
4475
4476      break;
4477   }
4478
4479   default:
4480
4481      ghalt("_crt_gstruct_eval: inconsistent strategy");
4482
4483   } /* end case */
4484
4485}
4486
4487
4488long _ntl_gcrt_struct_special(void *crt_struct)
4489{
4490   struct crt_body *c = (struct crt_body *) crt_struct;
4491   return (c->strategy == 2);
4492}
4493
4494
4495struct rem_body_lip {
4496   long n;
4497   long *primes;
4498};
4499
4500struct rem_body_gmp {
4501   long n;
4502   long levels;
4503   long *primes;
4504   long *index_vec;
4505   _ntl_gbigint *prod_vec;
4506   _ntl_gbigint *rem_vec;
4507};
4508
4509
4510struct rem_body_gmp1 {
4511   long n;
4512   long levels;
4513   long *primes;
4514   long *index_vec;
4515   long *len_vec;
4516   mp_limb_t *inv_vec;
4517   long *corr_vec;
4518   double *corraux_vec;
4519   _ntl_gbigint *prod_vec;
4520   _ntl_gbigint *rem_vec;
4521};
4522
4523
4524struct rem_body {
4525   long strategy;
4526
4527   union {
4528      struct rem_body_lip L;
4529      struct rem_body_gmp G;
4530      struct rem_body_gmp1 G1;
4531   } U;
4532};
4533
4534
4535
4536
4537void _ntl_grem_struct_init(void **rem_struct, long n, _ntl_gbigint modulus,
4538                          const long *p)
4539{
4540   struct rem_body *r;
4541
4542   r = (struct rem_body *) NTL_MALLOC(1, sizeof(struct rem_body), 0);
4543   if (!r) ghalt("out of memory");
4544
4545   if (n >= 32 && n <= 256) {
4546      struct rem_body_gmp1 *R = &r->U.G1;
4547
4548      long *q;
4549      long i, j;
4550      long levels, vec_len;
4551      long *index_vec;
4552      long *len_vec, *corr_vec;
4553      double *corraux_vec;
4554      mp_limb_t *inv_vec;
4555      _ntl_gbigint *prod_vec, *rem_vec;
4556   
4557      q = (long *) NTL_MALLOC(n, sizeof(long), 0);
4558      if (!q) ghalt("out of memory");
4559   
4560      for (i = 0; i < n; i++)
4561         q[i] = p[i];
4562
4563      levels = 0;
4564      while ((n >> levels) >= 4) levels++;
4565
4566      vec_len = (1L << levels) - 1;
4567
4568      index_vec = (long *) NTL_MALLOC((vec_len+1), sizeof(long), 0);
4569      if (!index_vec) ghalt("out of memory");
4570
4571      len_vec = (long *) NTL_MALLOC(vec_len, sizeof(long), 0);
4572      if (!len_vec) ghalt("out of memory");
4573
4574      inv_vec = (mp_limb_t *) NTL_MALLOC(vec_len, sizeof(mp_limb_t), 0);
4575      if (!inv_vec) ghalt("out of memory");
4576
4577      corr_vec = (long *) NTL_MALLOC(n, sizeof(long), 0);
4578      if (!corr_vec) ghalt("out of memory");
4579
4580      corraux_vec = (double *) NTL_MALLOC(n, sizeof(double), 0);
4581      if (!corraux_vec) ghalt("out of memory");
4582
4583      prod_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0);
4584      if (!prod_vec) ghalt("out of memory");
4585
4586      rem_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0);
4587      if (!rem_vec) ghalt("out of memory");
4588
4589      for (i = 0; i < vec_len; i++)
4590         prod_vec[i] = 0;
4591
4592      for (i = 0; i < vec_len; i++)
4593         rem_vec[i] = 0;
4594
4595      index_vec[0] = 0;
4596      index_vec[1] = n;
4597
4598      for (i = 0; i <= levels-2; i++) {
4599         long start = (1L << i) - 1;
4600         long finish = (1L << (i+1)) - 2;
4601         for (j = finish; j >= start; j--) {
4602            index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2;
4603            index_vec[2*j+1] = index_vec[j];
4604         }
4605         index_vec[2*finish+3] = n;
4606      }
4607
4608      for (i = (1L << (levels-1)) - 1; i < vec_len; i++) {
4609         /* multiply primes index_vec[i]..index_vec[i+1]-1 into
4610          * prod_vec[i]
4611          */
4612
4613         _ntl_gone(&prod_vec[i]);
4614         for (j = index_vec[i]; j < index_vec[i+1]; j++)
4615            _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]); 
4616      }
4617
4618      for (i = (1L << (levels-1)) - 2; i >= 3; i--)
4619         _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]);
4620
4621     
4622      for (i = 3; i < vec_len; i++)
4623         len_vec[i] = _ntl_gsize(prod_vec[i]);
4624
4625      /* Set len_vec[1] = len_vec[2] =
4626       *    max(_ntl_gsize(modulus), len_vec[3..6]).
4627       * This is a bit paranoid, but it makes the code
4628       * more robust. */
4629
4630      j = _ntl_gsize(modulus);
4631      for (i = 3; i <= 6; i++)
4632         if (len_vec[i] > j) j = len_vec[i];
4633
4634      len_vec[1] = len_vec[2] = j;
4635
4636      for (i = 3; i < vec_len; i++)
4637         inv_vec[i] = neg_inv_mod_limb(DATA(prod_vec[i])[0]);
4638
4639
4640      for (i = (1L << (levels-1)) - 1; i < vec_len; i++) {
4641         for (j = index_vec[i]; j < index_vec[i+1]; j++) {
4642            corr_vec[j] = SpecialPower(len_vec[1] - len_vec[i], q[j]);
4643            corraux_vec[j] = ((double) corr_vec[j])/((double) q[j]);
4644         }
4645      }
4646
4647
4648      /* allocate length in advance to streamline eval code */
4649
4650      _ntl_gsetlength(&rem_vec[0], len_vec[1]); /* a special temp */
4651
4652      for (i = 1; i < vec_len; i++)
4653         _ntl_gsetlength(&rem_vec[i], len_vec[i]);
4654
4655
4656
4657
4658      r->strategy = 2;
4659      R->n = n;
4660      R->primes = q;
4661      R->levels = levels;
4662      R->index_vec = index_vec;
4663      R->len_vec = len_vec;
4664      R->inv_vec = inv_vec;
4665      R->corr_vec = corr_vec;
4666      R->corraux_vec = corraux_vec;
4667      R->prod_vec = prod_vec;
4668      R->rem_vec = rem_vec;
4669
4670      *rem_struct = (void *) r;
4671   }
4672   else if (n >= 32) {
4673      struct rem_body_gmp *R = &r->U.G;
4674
4675      long *q;
4676      long i, j;
4677      long levels, vec_len;
4678      long *index_vec;
4679      _ntl_gbigint *prod_vec, *rem_vec;
4680   
4681      q = (long *) NTL_MALLOC(n, sizeof(long), 0);
4682      if (!q) ghalt("out of memory");
4683   
4684      for (i = 0; i < n; i++)
4685         q[i] = p[i];
4686
4687      levels = 0;
4688      while ((n >> levels) >= 4) levels++;
4689
4690      vec_len = (1L << levels) - 1;
4691
4692      index_vec = (long *) NTL_MALLOC((vec_len+1), sizeof(long), 0);
4693      if (!index_vec) ghalt("out of memory");
4694
4695      prod_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0);
4696      if (!prod_vec) ghalt("out of memory");
4697
4698      rem_vec = (_ntl_gbigint *) NTL_MALLOC(vec_len, sizeof(_ntl_gbigint), 0);
4699      if (!rem_vec) ghalt("out of memory");
4700
4701      for (i = 0; i < vec_len; i++)
4702         prod_vec[i] = 0;
4703
4704      for (i = 0; i < vec_len; i++)
4705         rem_vec[i] = 0;
4706
4707      index_vec[0] = 0;
4708      index_vec[1] = n;
4709
4710      for (i = 0; i <= levels-2; i++) {
4711         long start = (1L << i) - 1;
4712         long finish = (1L << (i+1)) - 2;
4713         for (j = finish; j >= start; j--) {
4714            index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2;
4715            index_vec[2*j+1] = index_vec[j];
4716         }
4717         index_vec[2*finish+3] = n;
4718      }
4719
4720      for (i = (1L << (levels-1)) - 1; i < vec_len; i++) {
4721         /* multiply primes index_vec[i]..index_vec[i+1]-1 into
4722          * prod_vec[i]
4723          */
4724
4725         _ntl_gone(&prod_vec[i]);
4726         for (j = index_vec[i]; j < index_vec[i+1]; j++)
4727            _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]); 
4728      }
4729
4730      for (i = (1L << (levels-1)) - 2; i >= 3; i--)
4731         _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]);
4732
4733
4734      /* allocate length in advance to streamline eval code */
4735
4736      _ntl_gsetlength(&rem_vec[1], _ntl_gsize(modulus));
4737      _ntl_gsetlength(&rem_vec[2], _ntl_gsize(modulus));
4738
4739      for (i = 1; i < (1L << (levels-1)) - 1; i++) {
4740         _ntl_gsetlength(&rem_vec[2*i+1], _ntl_gsize(prod_vec[2*i+1]));
4741         _ntl_gsetlength(&rem_vec[2*i+2], _ntl_gsize(prod_vec[2*i+2]));
4742      }
4743
4744      r->strategy = 1;
4745      R->n = n;
4746      R->primes = q;
4747      R->levels = levels;
4748      R->index_vec = index_vec;
4749      R->prod_vec = prod_vec;
4750      R->rem_vec = rem_vec;
4751
4752      *rem_struct = (void *) r;
4753   }
4754   else
4755   {
4756      struct rem_body_lip *R = &r->U.L;
4757
4758      long *q;
4759      long i;
4760
4761      r->strategy = 0;
4762      R->n = n;
4763      q = (long *) NTL_MALLOC(n, sizeof(long), 0);
4764      if (!q) ghalt("out of memory");
4765      R->primes = q;
4766 
4767      for (i = 0; i < n; i++)
4768         q[i] = p[i];
4769 
4770      *rem_struct = (void *) r;
4771   }
4772
4773}
4774
4775
4776
4777void _ntl_grem_struct_free(void *rem_struct)
4778{
4779   struct rem_body *r = (struct rem_body *) rem_struct;
4780
4781   switch (r->strategy) {
4782
4783   case 0: {
4784      free(r->U.L.primes);
4785      free(r);
4786      break;
4787   }
4788
4789   case 1: {
4790      struct rem_body_gmp *R = &r->U.G;
4791
4792      long levels = R->levels;
4793      long vec_len = (1L << levels) - 1;
4794      long i;
4795
4796      for (i = 0; i < vec_len; i++)
4797         _ntl_gfree(&R->prod_vec[i]);
4798
4799      for (i = 0; i < vec_len; i++)
4800         _ntl_gfree(&R->rem_vec[i]);
4801
4802      free(R->primes);
4803      free(R->index_vec);
4804      free(R->prod_vec);
4805      free(R->rem_vec);
4806      free(r);
4807      break;
4808   }
4809
4810   case 2: {
4811      struct rem_body_gmp1 *R = &r->U.G1;
4812
4813      long levels = R->levels;
4814      long vec_len = (1L << levels) - 1;
4815      long i;
4816
4817      for (i = 0; i < vec_len; i++)
4818         _ntl_gfree(&R->prod_vec[i]);
4819
4820      for (i = 0; i < vec_len; i++)
4821         _ntl_gfree(&R->rem_vec[i]);
4822
4823      free(R->primes);
4824      free(R->index_vec);
4825      free(R->len_vec);
4826      free(R->corr_vec);
4827      free(R->inv_vec);
4828      free(R->corraux_vec);
4829      free(R->prod_vec);
4830      free(R->rem_vec);
4831      free(r);
4832      break;
4833   }
4834
4835
4836   default:
4837      ghalt("_ntl_grem_struct_free: inconsistent strategy");
4838
4839   } /* end switch */
4840}
4841
4842
4843
4844
4845void _ntl_grem_struct_eval(void *rem_struct, long *x, _ntl_gbigint a)
4846{
4847   struct rem_body *r = (struct rem_body *) rem_struct;
4848
4849   switch (r->strategy) {
4850
4851   case 0: {
4852      struct rem_body_lip *R = &r->U.L;
4853      long n = R->n;
4854      long *q = R->primes;
4855
4856      long j;
4857      mp_limb_t *adata;
4858      long sa;
4859
4860      if (!a) 
4861         sa = 0;
4862      else
4863         sa = SIZE(a);
4864
4865      if (sa == 0) {
4866         for (j = 0; j < n; j++)
4867            x[j] = 0;
4868
4869         break;
4870      }
4871
4872      adata = DATA(a);
4873
4874      for (j = 0; j < n; j++)
4875         x[j] = mpn_mod_1(adata, sa, q[j]);
4876
4877      break;
4878   }
4879
4880   case 1: {
4881      struct rem_body_gmp *R = &r->U.G;
4882
4883      long n = R->n;
4884      long levels = R->levels;
4885      long *q = R->primes;
4886      long *index_vec = R->index_vec;
4887      _ntl_gbigint *prod_vec = R->prod_vec;
4888      _ntl_gbigint *rem_vec = R->rem_vec;
4889      long vec_len = (1L << levels) - 1;
4890
4891      long i, j;
4892
4893      if (ZEROP(a)) {
4894         for (j = 0; j < n; j++)
4895            x[j] = 0;
4896
4897         break;
4898      }
4899
4900      _ntl_gcopy(a, &rem_vec[1]);
4901      _ntl_gcopy(a, &rem_vec[2]);
4902
4903      for (i = 1; i < (1L << (levels-1)) - 1; i++) {
4904         gmod_simple(rem_vec[i], prod_vec[2*i+1], &rem_vec[2*i+1]);
4905         gmod_simple(rem_vec[i], prod_vec[2*i+2], &rem_vec[2*i+2]);
4906      }
4907
4908      for (i = (1L << (levels-1)) - 1; i < vec_len; i++) {
4909         long lo = index_vec[i];
4910         long hi = index_vec[i+1];
4911         mp_limb_t *s1p = DATA(rem_vec[i]);
4912         long s1size = SIZE(rem_vec[i]);
4913         if (s1size == 0) {
4914            for (j = lo; j <hi; j++)
4915               x[j] = 0;
4916         }
4917         else {
4918            for (j = lo; j < hi; j++)
4919               x[j] = mpn_mod_1(s1p, s1size, q[j]);
4920         }
4921      }
4922
4923      break;
4924   }
4925
4926   case 2: {
4927      struct rem_body_gmp1 *R = &r->U.G1;
4928
4929      long n = R->n;
4930      long levels = R->levels;
4931      long *q = R->primes;
4932      long *index_vec = R->index_vec;
4933      long *len_vec = R->len_vec;
4934      long *corr_vec = R->corr_vec;
4935      double *corraux_vec = R->corraux_vec;
4936      mp_limb_t *inv_vec = R->inv_vec;
4937      _ntl_gbigint *prod_vec = R->prod_vec;
4938      _ntl_gbigint *rem_vec = R->rem_vec;
4939      long vec_len = (1L << levels) - 1;
4940
4941      long i, j;
4942
4943      if (ZEROP(a)) {
4944         for (j = 0; j < n; j++)
4945            x[j] = 0;
4946
4947         break;
4948      }
4949
4950      _ntl_gcopy(a, &rem_vec[1]);
4951      _ntl_gcopy(a, &rem_vec[2]);
4952
4953      for (i = 1; i < (1L << (levels-1)) - 1; i++) {
4954         _ntl_gcopy(rem_vec[i], &rem_vec[0]);
4955         redc(rem_vec[0], prod_vec[2*i+1], len_vec[i]-len_vec[2*i+1],
4956              inv_vec[2*i+1], rem_vec[2*i+1]);
4957         redc(rem_vec[i], prod_vec[2*i+2], len_vec[i]-len_vec[2*i+2],
4958              inv_vec[2*i+2], rem_vec[2*i+2]);
4959      }
4960
4961      for (i = (1L << (levels-1)) - 1; i < vec_len; i++) {
4962         long lo = index_vec[i];
4963         long hi = index_vec[i+1];
4964         mp_limb_t *s1p = DATA(rem_vec[i]);
4965         long s1size = SIZE(rem_vec[i]);
4966         if (s1size == 0) {
4967            for (j = lo; j <hi; j++)
4968               x[j] = 0;
4969         }
4970         else {
4971            for (j = lo; j < hi; j++) {
4972               long t = mpn_mod_1(s1p, s1size, q[j]);
4973               SP_MUL_MOD2(x[j], t, corr_vec[j], q[j], corraux_vec[j]);
4974            }
4975         }
4976      }
4977
4978      break;
4979   }
4980
4981   default:
4982      ghalt("_ntl_grem_struct_eval: inconsistent strategy");
4983
4984
4985   } /* end switch */
4986
4987
4988}
4989
4990
Note: See TracBrowser for help on using the repository browser.