]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_cryptkit/lib/giantIntegers.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_cryptkit / lib / giantIntegers.c
diff --git a/Security/libsecurity_cryptkit/lib/giantIntegers.c b/Security/libsecurity_cryptkit/lib/giantIntegers.c
new file mode 100644 (file)
index 0000000..e7872b5
--- /dev/null
@@ -0,0 +1,1744 @@
+/* Copyright (c) 1998,2011-2014 Apple Inc.  All Rights Reserved.
+ *
+ * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
+ * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
+ * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
+ * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
+ * INC.  ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
+ * EXPOSE YOU TO LIABILITY.
+ ***************************************************************************
+
+   giantIntegers.c - library for large-integer arithmetic.
+
+ Revision History
+ ----------------
+       Fixed a==b bug in addg(). 
+ 10/06/98              ap
+       Changed to compile with C++.
+ 13 Apr 98     Fixed shiftright(1) bug in modg_via_recip.
+ 09 Apr 98 at Apple
+       Major rewrite of core arithmetic routines to make this module
+               independent of size of giantDigit.
+       Removed idivg() and radixdiv().
+ 20 Jan 98 at Apple
+       Deleted FFT arithmetic; simplified mulg().
+ 09 Jan 98 at Apple
+       gshiftright() optimization.
+ 08 Jan 98 at Apple
+       newGiant() returns NULL on malloc failure
+ 24 Dec 97 at Apple
+       New grammarSquare(); optimized modg_via_recip()
+ 11 Jun 97 at Apple
+       Added modg_via_recip(), divg_via_recip(), make_recip()
+       Added new multiple giant stack mechanism
+       Fixed potential packing/alignment bug in copyGiant()
+       Added profiling for borrowGiant(), returnGiant()
+       Deleted obsolete ifdef'd code
+       Deleted newgiant()
+       All calls to borrowGiant() now specify required size (no more
+               borrowGiant(0) calls)
+ 08 May 97 at Apple
+       Changed size of giantstruct.n to 1 for Mac build
+ 05 Feb 97 at Apple
+       newGiant() no longer modifies CurrentMaxShorts or giant stack
+       Added modg profiling
+ 01 Feb 97 at NeXT
+       Added iszero() check in gcompg
+ 17 Jan 97 at NeXT
+       Fixed negation bug in gmersennemod()
+       Fixed n[words-1] == 0 bug in extractbits()
+       Cleaned up lots of static declarations
+ 19 Sep 96 at NeXT
+       Fixed --size underflow bug in normal_subg().
+  4 Sep 96 at NeXT
+       Fixed (b<n), (sign<0) case in gmersennemod() to allow for arbitrary n.
+  9 Aug 96 at NeXT
+       Fixed sign-extend bug in data_to_giant().
+  7 Aug 96 at NeXT
+       Changed precision in newtondivide().
+       Removed #ifdef UNUSED code.
+ 24 Jul 96 at NeXT
+       Added scompg().
+       Created.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "platform.h"
+#include "giantIntegers.h"
+#include "feeDebug.h"
+#include "ckconfig.h"
+#include "ellipticMeasure.h"
+#include "falloc.h"
+#include "giantPortCommon.h"
+
+#ifdef FEE_DEBUG
+#if (GIANT_LOG2_BITS_PER_DIGIT == 4)
+#warning Compiling with two-byte giantDigits
+#endif
+#endif
+
+#if 0
+#if    FEE_DEBUG
+char printbuf1[200];
+char printbuf2[200];
+char printbuf3[200];
+void printGiantBuf(giant x)
+{
+       int i;
+
+       sprintf(printbuf2, "sign=%d cap=%d n[]=", x->sign, x->capacity);
+       for(i=0; i<abs(x->sign); i++) {
+               sprintf(printbuf3 + 10*i, "%u:", x->n[i]);
+       }
+}
+
+char printbuf4[200];
+char printbuf5[200];
+void printGiantBuf2(giant x)
+{
+       int i;
+
+       sprintf(printbuf4, "sign=%d cap=%d n[]=", x->sign, x->capacity);
+       for(i=0; i<abs(x->sign); i++) {
+               sprintf(printbuf5 + 10*i, "%u:", x->n[i]);
+       }
+}
+#endif /* FEE_DEBUG */
+#endif /* 0 */
+
+/******** debugging flags *********/
+
+/*
+ * Flag use of unoptimized divg, modg, binvg
+ */
+//#define WARN_UNOPTIMIZE                      FEE_DEBUG
+#define WARN_UNOPTIMIZE                        0
+
+/*
+ * Log interesting giant stack events
+ */
+#define LOG_GIANT_STACK                        0
+
+/*
+ * Log allocation of giant larger than stack size
+ */
+#define LOG_GIANT_STACK_OVERFLOW       1
+
+/*
+ * Flag newGiant(0) and borrowGiant(0) calls
+ */
+#define WARN_ZERO_GIANT_SIZE           FEE_DEBUG
+
+/* temp mac-only giant initialization debug */
+#define GIANT_MAC_DEBUG                0
+#if    GIANT_MAC_DEBUG
+
+#include <string.h>
+#include <TextUtils.h>
+
+/* this one needs a writable string */
+static void logCom(unsigned char *str) {
+       c2pstr((char *)str);
+       DebugStr(str);
+}
+
+/* constant strings */
+void dblog0(const char *str)   {               
+       Str255  outStr;                         
+       strcpy((char *)outStr, str);    
+       logCom(outStr);                                 
+}
+
+#else  
+#define dblog0(s)
+
+#endif /* GIANT_MAC_DEBUG */
+
+#ifndef        min
+#define min(a,b) ((a)<(b)? (a) : (b))
+#endif // min
+#ifndef        max
+#define max(a,b) ((a)>(b)? (a) : (b))
+#endif // max
+
+#ifndef        TRUE
+#define TRUE           1
+#endif // TRUE
+#ifndef        FALSE
+#define FALSE          0
+#endif // FALSE
+
+static void absg(giant g);  /* g := |g|. */
+
+/************** globals *******************/
+
+
+/* ------ giant stack package ------ */
+
+/*
+ * The giant stack package is a local cache which allows us to avoid calls
+ * to malloc() for borrowGiant(). On a 90 Mhz Pentium, enabling the
+ * giant stack package shows about a 1.35 speedup factor over an identical
+ * CryptKit without the giant stacks enabled.
+ */
+
+#if    GIANTS_VIA_STACK
+
+#if    LOG_GIANT_STACK
+#define gstackDbg(x)           printf x
+#else  // LOG_GIANT_STACK
+#define gstackDbg(x)
+#endif // LOG_GIANT_STACK
+
+typedef struct {
+       unsigned        numDigits;      // capacity of giants in this stack
+       unsigned        numFree;        // number of free giants in stack
+       unsigned        totalGiants;    // total number in *stack
+       giant           *stack;
+} gstack;
+
+static gstack *gstacks = NULL;         // array of stacks
+static unsigned numGstacks = 0;                // # of elements in gstacks
+static int gstackInitd = 0;            // this module has been init'd
+
+#define INIT_NUM_GIANTS                16      /* initial # of giants / stack */
+#define MIN_GIANT_SIZE         4       /* numDigits for gstack[0]  */
+#define GIANT_SIZE_INCR                2       /* in << bits */
+
+/*
+ * Initialize giant stacks, with up to specified max giant size.
+ */
+void initGiantStacks(unsigned maxDigits)
+{
+       unsigned curSize = MIN_GIANT_SIZE;
+       unsigned sz;
+       unsigned i;
+
+       dblog0("initGiantStacks\n");
+       
+       if(gstackInitd) {
+               /*
+                * Shouldn't be called more than once...
+                */
+               printf("multiple initGiantStacks calls\n");
+               return;
+       }
+       gstackDbg(("initGiantStacks(%d)\n", maxDigits));
+
+       /*
+        * How many stacks?
+        */
+       numGstacks = 1;
+       while(curSize<=maxDigits) {
+               curSize <<= GIANT_SIZE_INCR;
+               numGstacks++;
+       }
+
+       sz = sizeof(gstack) * numGstacks;
+       gstacks = (gstack*) fmalloc(sz);
+       bzero(gstacks, sz);
+
+       curSize = MIN_GIANT_SIZE;
+       for(i=0; i<numGstacks; i++) {
+               gstacks[i].numDigits = curSize;
+               curSize <<= GIANT_SIZE_INCR;
+       }
+
+       gstackInitd = 1;
+}
+
+/* called at shut down - free resources */ 
+void freeGiantStacks(void)
+{
+       int i;
+       int j;
+       gstack *gs;
+       
+       if(!gstackInitd) {
+               return;
+       }
+       for(i=0; i<numGstacks; i++) {
+               gs = &gstacks[i];
+               for(j=0; j<gs->numFree; j++) {
+                       freeGiant(gs->stack[j]);
+                       gs->stack[j] = NULL;
+               }
+               /* and the stack itself - may be null if this was never used */
+               if(gs->stack != NULL) {
+                       ffree(gs->stack);
+                       gs->stack = NULL;
+               }
+       }
+       ffree(gstacks);
+       gstacks = NULL;
+       gstackInitd = 0;
+}
+
+#endif // GIANTS_VIA_STACK
+
+giant borrowGiant(unsigned numDigits)
+{
+       giant           result;
+
+       #if     GIANTS_VIA_STACK
+
+       unsigned        stackNum;
+       gstack          *gs = gstacks;
+
+       #if     WARN_ZERO_GIANT_SIZE
+       if(numDigits == 0) {
+               printf("borrowGiant(0)\n");
+               numDigits = gstacks[numGstacks-1].numDigits;
+       }
+       #endif  // WARN_ZERO_GIANT_SIZE
+
+       /*
+        * Find appropriate stack
+        */
+       if(numDigits <= MIN_GIANT_SIZE)
+               stackNum = 0;
+       else if (numDigits <= (MIN_GIANT_SIZE << GIANT_SIZE_INCR))
+               stackNum = 1;
+       else if (numDigits <= (MIN_GIANT_SIZE << (2 * GIANT_SIZE_INCR)))
+               stackNum = 2;
+       else if (numDigits <= (MIN_GIANT_SIZE << (3 * GIANT_SIZE_INCR)))
+               stackNum = 3;
+       else if (numDigits <= (MIN_GIANT_SIZE << (4 * GIANT_SIZE_INCR)))
+               stackNum = 4;
+       else
+               stackNum = numGstacks;
+
+       if(stackNum >= numGstacks) {
+               /*
+                * out of bounds; just malloc
+                */
+               #if     LOG_GIANT_STACK_OVERFLOW
+               gstackDbg(("giantFromStack overflow; numDigits %d\n",
+                       numDigits));
+               #endif  // LOG_GIANT_STACK_OVERFLOW
+               return newGiant(numDigits);
+       }
+       gs = &gstacks[stackNum];
+
+       #if     GIANT_MAC_DEBUG
+       if((gs->numFree != 0) && (gs->stack == NULL)) {
+               dblog0("borrowGiant: null stack!\n");
+       }
+       #endif
+       if(gs->numFree != 0) {
+               result = gs->stack[--gs->numFree];
+       }
+       else {
+               /*
+                * Stack empty; malloc
+                */
+               result = newGiant(gs->numDigits);
+       }
+
+       #else   /* GIANTS_VIA_STACK */
+
+       result = newGiant(numDigits);
+
+       #endif  /* GIANTS_VIA_STACK */
+
+       PROF_INCR(numBorrows);
+       return result;
+}
+
+void returnGiant(giant g)
+{
+
+       #if     GIANTS_VIA_STACK
+
+       unsigned        stackNum;
+       gstack          *gs;
+       unsigned        cap = g->capacity;
+
+
+       #if     FEE_DEBUG
+       if(!gstackInitd) {
+               CKRaise("returnGiant before stacks initialized!");
+       }
+       #endif  // FEE_DEBUG
+
+       #if     GIANT_MAC_DEBUG
+       if(g == NULL) {
+               dblog0("returnGiant: null g!\n");
+       }
+       #endif
+
+       /*
+        * Find appropriate stack. Note we expect exact match of
+        * capacity and stack's giant size.
+        */
+       /*
+        * Optimized unrolled loop. Just make sure there are enough cases
+        * to handle all of the stacks. Errors in this case will be flagged
+        * via LOG_GIANT_STACK_OVERFLOW.
+        */
+       switch(cap) {
+           case MIN_GIANT_SIZE:
+               stackNum = 0;
+               break;
+           case MIN_GIANT_SIZE << GIANT_SIZE_INCR:
+               stackNum = 1;
+               break;
+           case MIN_GIANT_SIZE << (2 * GIANT_SIZE_INCR):
+               stackNum = 2;
+               break;
+           case MIN_GIANT_SIZE << (3 * GIANT_SIZE_INCR):
+               stackNum = 3;
+               break;
+           case MIN_GIANT_SIZE << (4 * GIANT_SIZE_INCR):
+               stackNum = 4;
+               break;
+           default:
+               stackNum = numGstacks;
+               break;
+       }
+
+       if(stackNum >= numGstacks) {
+               /*
+                * out of bounds; just free
+                */
+               #if     LOG_GIANT_STACK_OVERFLOW
+               gstackDbg(("giantToStack overflow; numDigits %d\n", cap));
+               #endif  // LOG_GIANT_STACK_OVERFLOW
+               freeGiant(g);
+               return;
+       }
+       gs = &gstacks[stackNum];
+       if(gs->numFree == gs->totalGiants) {
+               if(gs->totalGiants == 0) {
+                       gstackDbg(("Initial alloc of gstack(%d)\n",
+                               gs->numDigits));
+                       gs->totalGiants = INIT_NUM_GIANTS;
+               }
+               else {
+                       gs->totalGiants *= 2;
+                       gstackDbg(("Bumping gstack(%d) to %d\n",
+                               gs->numDigits, gs->totalGiants));
+               }
+               gs->stack = (giantstruct**) frealloc(gs->stack, gs->totalGiants*sizeof(giant));
+       }
+       g->sign = 0;            // not sure this is important...
+       gs->stack[gs->numFree++] = g;
+
+       #if     GIANT_MAC_DEBUG
+       if((gs->numFree != 0) && (gs->stack == NULL)) {
+               dblog0("borrowGiant: null stack!\n");
+       }
+       #endif
+       
+       #else   /* GIANTS_VIA_STACK */
+
+       freeGiant(g);
+
+       #endif  /* GIANTS_VIA_STACK */
+}
+
+void freeGiant(giant x) {
+    ffree(x);
+}
+
+giant newGiant(unsigned numDigits) {
+    // giant sufficient for 2^numbits+16 sized ops
+    int size;
+    giant result;
+
+    #if        WARN_ZERO_GIANT_SIZE
+    if(numDigits == 0) {
+        printf("newGiant(0)\n");
+               #if     GIANTS_VIA_STACK
+        numDigits = gstacks[numGstacks-1].totalGiants;
+               #else
+               /* HACK */
+               numDigits = 20;
+               #endif
+    }
+    #endif     // WARN_ZERO_GIANT_SIZE
+
+    size = (numDigits-1) * GIANT_BYTES_PER_DIGIT + sizeof(giantstruct);
+    result = (giant)fmalloc(size);
+    if(result == NULL) {
+       return NULL;
+    }
+    result->sign = 0;
+    result->capacity = numDigits;
+    return result;
+}
+
+giant copyGiant(giant x)
+{
+       int bytes;
+
+       giant result = newGiant(x->capacity);
+
+       /*
+        * 13 Jun 1997
+        * NO! this assumes packed alignment
+        */
+       bytes = sizeof(giantstruct) +
+               ((x->capacity - 1) * GIANT_BYTES_PER_DIGIT);
+       bcopy(x, result, bytes);
+       return result;
+}
+
+/* ------ initialization and utility routines ------ */
+
+
+unsigned bitlen(giant n) {
+    unsigned   b = GIANT_BITS_PER_DIGIT;
+    giantDigit         c = 1 << (GIANT_BITS_PER_DIGIT - 1);
+    giantDigit         w;
+
+    if (isZero(n)) {
+       return(0);
+    }
+    w = n->n[abs(n->sign) - 1];
+    if (!w) {
+       CKRaise("bitlen - no bit set!");
+    }
+    while((w&c) == 0) {
+        b--;
+        c >>= 1;
+    }
+    return(GIANT_BITS_PER_DIGIT * (abs(n->sign)-1) + b);
+}
+
+int bitval(giant n, int pos) {
+    int i = abs(pos) >> GIANT_LOG2_BITS_PER_DIGIT;
+    giantDigit c = 1 << (pos & (GIANT_BITS_PER_DIGIT - 1));
+
+    return((n->n[i]) & c);
+}
+
+int gsign(giant g)
+/* returns the sign of g */
+{
+       if (isZero(g)) return(0);
+       if (g->sign > 0) return(1);
+       return(-1);
+}
+
+/*
+ * Adjust sign for possible leading (m.s.) zero digits
+ */
+void gtrimSign(giant g)
+{
+       int numDigits = abs(g->sign);
+       int i;
+
+       for(i=numDigits-1; i>=0; i--) {
+               if(g->n[i] == 0) {
+                       numDigits--;
+               }
+               else {
+                       break;
+               }
+       }
+       if(g->sign < 0) {
+               g->sign = -numDigits;
+       }
+       else {
+               g->sign = numDigits;
+       }
+}
+
+
+int isone(giant g) {
+    return((g->sign==1)&&(g->n[0]==1));
+}
+
+int isZero(giant thegiant) {
+/* Returns TRUE if thegiant == 0.  */
+    int count;
+    int length = abs(thegiant->sign);
+    giantDigit *numpointer;
+
+    if (length) {
+        numpointer = thegiant->n;
+
+        for(count = 0; count<length; ++count,++numpointer)
+            if (*numpointer != 0 ) return(FALSE);
+    }
+    return(TRUE);
+}
+
+int gcompg(giant a, giant b)
+/* returns -1,0,1 if a<b, a=b, a>b, respectively */
+{
+    int sa = a->sign;
+    int j;
+    int sb = b->sign;
+    giantDigit va;
+    giantDigit vb;
+    int sgn;
+
+    if(isZero(a) && isZero(b)) return 0;
+    if(sa > sb) return(1);
+    if(sa < sb) return(-1);
+    if(sa < 0) {
+       sa = -sa; /* Take absolute value of sa */
+       sgn = -1;
+    } else sgn = 1;
+    for(j = sa-1; j >= 0; j--) {
+        va = a->n[j]; vb = b->n[j];
+       if (va > vb) return(sgn);
+       if (va < vb) return(-sgn);
+    }
+    return(0);
+}
+
+/* destgiant becomes equal to srcgiant */
+void gtog(giant srcgiant, giant destgiant) {
+
+    int numbytes;
+
+    CKASSERT(srcgiant != NULL);
+    numbytes =  abs(srcgiant->sign) * GIANT_BYTES_PER_DIGIT;
+    if (destgiant->capacity < abs(srcgiant->sign))
+       CKRaise("gtog overflow!!");
+    memcpy((char *)destgiant->n, (char *)srcgiant->n, numbytes);
+    destgiant->sign = srcgiant->sign;
+}
+
+void int_to_giant(int i, giant g) {
+/* The giant g becomes set to the integer value i. */
+    int isneg = (i<0);
+    unsigned int j = abs(i);
+    unsigned dex;
+
+    g->sign = 0;
+    if (i==0) {
+       g->n[0] = 0;
+       return;
+    }
+
+    if(GIANT_BYTES_PER_DIGIT == sizeof(int)) {
+       g->n[0] = j;
+       g->sign = 1;
+    }
+    else {
+       /* one loop per digit */
+       unsigned scnt = GIANT_BITS_PER_DIGIT;   // fool compiler
+
+       for(dex=0; dex<sizeof(int); dex++) {
+           g->n[dex] = j & GIANT_DIGIT_MASK;
+           j >>= scnt;
+           g->sign++;
+           if(j == 0) {
+               break;
+           }
+       }
+    }
+    if (isneg) {
+       g->sign = -(g->sign);
+    }
+}
+
+/*------------- Arithmetic --------------*/
+
+void negg(giant g) {
+/* g becomes -g */
+    g->sign = -g->sign;
+}
+
+void iaddg(int i, giant g) {  /* positive g becomes g + (int)i */
+    int j;
+    giantDigit carry;
+    int size = abs(g->sign);
+
+    if (isZero(g)) {
+       int_to_giant(i,g);
+    }
+    else {
+       carry = i;
+       for(j=0; ((j<size) && (carry != 0)); j++) {
+            g->n[j] = giantAddDigits(g->n[j], carry, &carry);
+        }
+       if(carry) {
+           ++g->sign;
+           // realloc
+           if (g->sign > (int)g->capacity) CKRaise("iaddg overflow!");
+           g->n[size] = carry;
+       }
+    }
+}
+
+/*
+ * g *= (int n)
+ *
+ * FIXME - we can improve this...
+ */
+void imulg(unsigned n, giant g)
+{
+       giant tmp = borrowGiant(abs(g->sign) + sizeof(int));
+
+       int_to_giant(n, tmp);
+       mulg(tmp, g);
+       returnGiant(tmp);
+}
+
+static void normal_addg(giant a, giant b)
+/*  b := a + b, both a,b assumed non-negative.    */
+{
+    giantDigit carry1 = 0;
+    giantDigit carry2 = 0;
+    int asize = a->sign, bsize = b->sign;
+    giantDigit *an = a->n;
+    giantDigit *bn = b->n;
+    giantDigit tmp;
+    int j;
+    int comSize;
+    int maxSize;
+
+    if(asize < bsize) {
+        comSize = asize;
+       maxSize = bsize;
+    }
+    else {
+        comSize = bsize;
+       maxSize = asize;
+    }
+
+    /* first handle the common digits */
+    for(j=0; j<comSize; j++) {
+       /*
+        * first add the carry, then an[j] - either add could result
+        * in another carry
+        */
+       if(carry1 || carry2) {
+           tmp = giantAddDigits(bn[j], (giantDigit)1, &carry1);
+       }
+       else {
+           carry1 = 0;
+           tmp = bn[j];
+       }
+       bn[j] = giantAddDigits(tmp, an[j], &carry2);
+    }
+
+    if(asize < bsize) {
+
+       /* now propagate remaining carry beyond asize */
+       if(carry2) {
+           carry1 = 1;
+       }
+       if(carry1) {
+           for(; j<bsize; j++) {
+               bn[j] = giantAddDigits(bn[j], (giantDigit)1, &carry1);
+               if(carry1 == 0) {
+                   break;
+               }
+           }
+       }
+    } else {
+       /* now propagate remaining an[] and carry beyond bsize */
+       if(carry2) {
+           carry1 = 1;
+       }
+       for(; j<asize; j++) {
+           if(carry1) {
+               bn[j] = giantAddDigits(an[j], (giantDigit)1, &carry1);
+           }
+           else {
+               bn[j] = an[j];
+               carry1 = 0;
+           }
+       }
+    }
+    b->sign = maxSize;
+    if(carry1) {
+       // realloc?
+       bn[j] = 1;
+       b->sign++;
+       if (b->sign > (int)b->capacity) CKRaise("iaddg overflow!");
+    }
+
+}
+
+static void normal_subg(giant a, giant b)
+/* b := b - a; requires b, a non-negative and b >= a. */
+{
+    int j;
+    int size = b->sign;
+    giantDigit tmp;
+    giantDigit borrow1 = 0;
+    giantDigit borrow2 = 0;
+    giantDigit *an = a->n;
+    giantDigit *bn = b->n;
+
+    if(a->sign == 0) {
+       return;
+    }
+
+    for (j=0; j<a->sign; ++j) {
+       if(borrow1 || borrow2) {
+           tmp = giantSubDigits(bn[j], (giantDigit)1, &borrow1);
+       }
+       else {
+           tmp = bn[j];
+           borrow1 = 0;
+       }
+       bn[j] = giantSubDigits(tmp, an[j], &borrow2);
+    }
+    if(borrow1 || borrow2) {
+       /* propagate borrow thru remainder of bn[] */
+       borrow1 = 1;
+       for (j=a->sign; j<size; ++j) {
+           if(borrow1) {
+               bn[j] = giantSubDigits(bn[j], (giantDigit)1, &borrow1);
+           }
+           else {
+               break;
+           }
+       }
+    }
+
+    /* adjust sign for leading zero digits */
+    while((size-- > 0) && (b->n[size] == 0))
+       ;
+    b->sign = (b->n[size] == 0)? 0 : size+1;
+}
+
+static void reverse_subg(giant a, giant b)
+/* b := a - b; requires b, a non-negative and a >= b. */
+{
+    int j;
+    int size = a->sign;
+    giantDigit tmp;
+    giantDigit borrow1 = 0;
+    giantDigit borrow2 = 0;
+    giantDigit *an = a->n;
+    giantDigit *bn = b->n;
+
+    if(b->sign == 0) {
+       gtog(a, b);
+       return;
+    }
+    for (j=0; j<b->sign; ++j) {
+       if(borrow1 || borrow2) {
+           tmp = giantSubDigits(an[j], (giantDigit)1, &borrow1);
+       }
+       else {
+           tmp = an[j];
+           borrow1 = 0;
+       }
+       bn[j] = giantSubDigits(tmp, bn[j], &borrow2);
+    }
+    if(borrow1 || borrow2) {
+       /* propagate borrow thru remainder of bn[] */
+       borrow1 = 1;
+    }
+    for (j=b->sign; j<size; ++j) {
+       if(borrow1) {
+           bn[j] = giantSubDigits(an[j], (giantDigit)1, &borrow1);
+       }
+       else {
+           bn[j] = an[j];
+           borrow1 = 0;
+       }
+    }
+
+    b->sign = size; /* REC, 21 Apr 1996. */
+    while(!b->n[--size]);
+    b->sign = size+1;
+}
+
+
+void addg(giant a, giant b)
+/* b := b + a, any signs any result. */
+{   int asgn = a->sign, bsgn = b->sign;
+    if(asgn == 0) return;
+    if(bsgn == 0) {
+       gtog(a,b);
+       return;
+    }
+    if((asgn < 0) == (bsgn < 0)) {
+       if(bsgn > 0) {
+               normal_addg(a,b);
+               return;
+       }
+       negg(a); if(a != b) negg(b); normal_addg(a,b);  /* Fix REC 1 Dec 98. */
+       negg(a); if(a != b) negg(b); return;  /* Fix REC 1 Dec 98. */
+    }
+    if(bsgn > 0) {
+        negg(a);
+       if(gcompg(b,a) >= 0) {
+               normal_subg(a,b);
+               negg(a);
+               return;
+       }
+       reverse_subg(a,b);
+       negg(a);
+       negg(b);
+       return;
+    }
+    negg(b);
+    if(gcompg(b,a) < 0) {
+       reverse_subg(a,b);
+       return;
+    }
+    normal_subg(a,b);
+    negg(b);
+    return;
+}
+
+void subg(giant a, giant b)
+/* b := b - a, any signs, any result. */
+{
+  int asgn = a->sign, bsgn = b->sign;
+  if(asgn == 0) return;
+  if(bsgn == 0) {
+       gtog(a,b);
+       negg(b);
+       return;
+  }
+  if((asgn < 0) != (bsgn < 0)) {
+       if(bsgn > 0) {
+               negg(a);
+               normal_addg(a,b);
+               negg(a);
+               return;
+       }
+       negg(b);
+       normal_addg(a,b);
+       negg(b);
+       return;
+  }
+  if(bsgn > 0) {
+       if(gcompg(b,a) >= 0) {
+               normal_subg(a,b);
+               return;
+       }
+       reverse_subg(a,b);
+       negg(b);
+       return;
+  }
+  negg(a); negg(b);
+  if(gcompg(b,a) >= 0) {
+               normal_subg(a,b);
+               negg(a);
+               negg(b);
+               return;
+  }
+  reverse_subg(a,b);
+  negg(a);
+  return;
+}
+
+static void bdivg(giant v, giant u)
+/* u becomes greatest power of two not exceeding u/v. */
+{
+    int diff = bitlen(u) - bitlen(v);
+    giant scratch7;
+
+    if (diff<0) {
+        int_to_giant(0,u);
+        return;
+    }
+    scratch7 = borrowGiant(u->capacity);
+    gtog(v, scratch7);
+    gshiftleft(diff,scratch7);
+    if(gcompg(u,scratch7) < 0) diff--;
+    if(diff<0) {
+        int_to_giant(0,u);
+       returnGiant(scratch7);
+        return;
+    }
+    int_to_giant(1,u);
+    gshiftleft(diff,u);
+    returnGiant(scratch7);
+}
+
+int binvaux(giant p, giant x)
+/* Binary inverse method.
+   Returns zero if no inverse exists, in which case x becomes
+   GCD(x,p). */
+{
+    giant scratch7;
+    giant u0;
+    giant u1;
+    giant v0;
+    giant v1;
+    int result = 1;
+    int giantSize;
+    PROF_START;
+
+    if(isone(x)) return(result);
+    giantSize = 4 * abs(p->sign);
+    scratch7 = borrowGiant(giantSize);
+    u0 = borrowGiant(giantSize);
+    u1 = borrowGiant(giantSize);
+    v0 = borrowGiant(giantSize);
+    v1 = borrowGiant(giantSize);
+    int_to_giant(1, v0); gtog(x, v1);
+    int_to_giant(0,x); gtog(p, u1);
+    while(!isZero(v1)) {
+        gtog(u1, u0); bdivg(v1, u0);
+        gtog(x, scratch7);
+        gtog(v0, x);
+        mulg(u0, v0);
+        subg(v0,scratch7);
+        gtog(scratch7, v0);
+
+        gtog(u1, scratch7);
+        gtog(v1, u1);
+        mulg(u0, v1);
+        subg(v1,scratch7);
+        gtog(scratch7, v1);
+    }
+    if (!isone(u1)) {
+        gtog(u1,x);
+        if(x->sign<0) addg(p, x);
+        result = 0;
+        goto done;
+    }
+    if (x->sign<0) addg(p, x);
+  done:
+    returnGiant(scratch7);
+    returnGiant(u0);
+    returnGiant(u1);
+    returnGiant(v0);
+    returnGiant(v1);
+    PROF_END(binvauxTime);
+    return(result);
+}
+
+/*
+ * Superceded by binvg_cp()
+ */
+#if    0
+int binvg(giant p, giant x)
+{
+       modg(p, x);
+       return(binvaux(p,x));
+}
+#endif
+
+static void absg(giant g) {
+/* g becomes the absolute value of g */
+    if (g->sign < 0) g->sign = -g->sign;
+}
+
+void gshiftleft(int bits, giant g) {
+/* shift g left bits bits.  Equivalent to g = g*2^bits */
+    int        rem = bits & (GIANT_BITS_PER_DIGIT - 1);
+    int        crem = GIANT_BITS_PER_DIGIT - rem;
+    int        digits = 1 + (bits >> GIANT_LOG2_BITS_PER_DIGIT);
+    int        size = abs(g->sign);
+    int        j;
+    int        k;
+    int        sign = gsign(g);
+    giantDigit         carry;
+    giantDigit         dat;
+
+    #if                FEE_DEBUG
+    if(bits < 0) {
+        CKRaise("gshiftleft(-bits)\n");
+    }
+    #endif     /* FEE_DEBUG */
+
+    if(!bits) return;
+    if(!size) return;
+    if((size+digits) > (int)g->capacity) {
+        CKRaise("gshiftleft overflow");
+        return;
+    }
+    k = size - 1 + digits;     // (MSD of result + 1)
+    carry = 0;
+
+    /* bug fix for 32-bit giantDigits; this is also an optimization for
+     * other sizes. rem=0 means we're shifting strictly by digits, no
+     * bit shifts. */
+    if(rem == 0) {
+        g->n[k] = 0;           // XXX hack - for sign fixup
+       for(j=size-1; j>=0; j--) {
+           g->n[--k] = g->n[j];
+       }
+       do{
+           g->n[--k] = 0;
+       } while(k>0);
+    }
+    else {
+       /*
+        * normal unaligned case
+        * FIXME - this writes past g->n[size-1] the first time thru!
+        */
+       for(j=size-1; j>=0; j--) {
+           dat = g->n[j];
+           g->n[k--] = (dat >> crem) | carry;
+           carry = (dat << rem);
+       }
+       do{
+           g->n[k--] = carry;
+           carry = 0;
+       } while(k>=0);
+    }
+    k = size - 1 + digits;
+    if(g->n[k] == 0) --k;
+    g->sign = sign * (k+1);
+    if (abs(g->sign) > g->capacity) {
+       CKRaise("gshiftleft overflow");
+    }
+}
+
+void gshiftright(int bits, giant g) {
+/* shift g right bits bits.  Equivalent to g = g/2^bits */
+    int j;
+    int size=abs(g->sign);
+    giantDigit carry;
+    int digits = bits >> GIANT_LOG2_BITS_PER_DIGIT;
+    int remain = bits & (GIANT_BITS_PER_DIGIT - 1);
+    int cremain = GIANT_BITS_PER_DIGIT - remain;
+
+    #if                FEE_DEBUG
+    if(bits < 0) {
+        CKRaise("gshiftright(-bits)\n");
+    }
+    #endif     /* FEE_DEBUG */
+    if(bits==0) return;
+    if(isZero(g)) return;
+    if (digits >= size) {
+        g->sign = 0;
+        return;
+    }
+
+    size -= digits;
+
+/* Begin OPT: 9 Jan 98 REC. */
+    if(remain == 0) {
+        if(g->sign > 0) {
+           g->sign = size;
+       }
+       else {
+           g->sign = -size;
+       }
+        for(j=0; j < size; j++) {
+           g->n[j] = g->n[j+digits];
+       }
+        return;
+    }
+/* End OPT: 9 Jan 98 REC. */
+
+    for(j=0;j<size;++j) {
+        if (j==size-1) {
+           carry = 0;
+       }
+        else {
+           carry = (g->n[j+digits+1]) << cremain;
+       }
+        g->n[j] = ((g->n[j+digits]) >> remain ) | carry;
+    }
+    if (g->n[size-1] == 0) {
+       --size;
+    }
+    if(g->sign > 0) {
+       g->sign = size;
+    }
+    else {
+        g->sign = -size;
+    }
+    if (abs(g->sign) > g->capacity) {
+       CKRaise("gshiftright overflow");
+    }
+}
+
+
+void extractbits(unsigned n, giant src, giant dest) {
+/* dest becomes lowermost n bits of src.  Equivalent to dest = src % 2^n */
+    int digits = n >> GIANT_LOG2_BITS_PER_DIGIT;
+    int numbytes = digits * GIANT_BYTES_PER_DIGIT;
+    int bits = n & (GIANT_BITS_PER_DIGIT - 1);
+
+    if (n <= 0) {
+       return;
+    }
+    if (dest->capacity * 8 * GIANT_BYTES_PER_DIGIT < n) {
+       CKRaise("extractbits - not enough room");
+    }
+    if (digits >= abs(src->sign)) {
+       gtog(src,dest);
+    }
+    else {
+          memcpy((char *)(dest->n), (char *)(src->n), numbytes);
+          if (bits) {
+              dest->n[digits] = src->n[digits] & ((1<<bits)-1);
+              ++digits;
+          }
+         /* Next, fix by REC, 12 Jan 97. */
+          // while((dest->n[words-1] == 0) && (words > 0)) --words;
+          while((digits > 0) && (dest->n[digits-1] == 0)) {
+             --digits;
+         }
+          if(src->sign < 0) {
+             dest->sign = -digits;
+         }
+          else {
+             dest->sign = digits;
+         }
+    }
+    if (abs(dest->sign) > dest->capacity) {
+       CKRaise("extractbits overflow");
+    }
+}
+
+#define NEW_MERSENNE   0
+
+/*
+ * New gmersennemod, 24 Dec 1997. This runs significantly slower than the
+ * original.
+ */
+#if    NEW_MERSENNE
+
+void
+gmersennemod(
+       int     n,
+       giant   g
+)
+/* g := g (mod 2^n - 1) */
+{
+    int the_sign;
+    giant scratch3 = borrowGiant(g->capacity);
+    giant scratch4 = borrowGiant(1);
+
+    if ((the_sign = gsign(g)) < 0) absg(g);
+    while (bitlen(g) > n) {
+       gtog(g,scratch3);
+       gshiftright(n,scratch3);
+       addg(scratch3,g);
+       gshiftleft(n,scratch3);
+       subg(scratch3,g);
+    }
+    if(isZero(g)) goto out;
+    int_to_giant(1,scratch3);
+    gshiftleft(n,scratch3);
+    int_to_giant(1,scratch4);
+    subg(scratch4,scratch3);
+    if(gcompg(g,scratch3) >= 0) subg(scratch3,g);
+    if (the_sign < 0) {
+       g->sign = -g->sign;
+       addg(scratch3,g);
+    }
+out:
+    returnGiant(scratch3);
+    returnGiant(scratch4);
+}
+
+#else  /* NEW_MERSENNE */
+
+void gmersennemod(int n, giant g) {
+/*   g becomes g mod ((2^n)-1)
+     31 Jul 96 modified REC.
+     17 Jan 97 modified REC.
+*/
+    unsigned bits = n & (GIANT_BITS_PER_DIGIT - 1);
+    unsigned digits =  1 + ((n-1) >> GIANT_LOG2_BITS_PER_DIGIT);
+    int isPositive = (g->sign > 0);
+    int j;
+    int b;
+    int size;
+    int foundzero;
+    giantDigit mask = (bits == 0) ? GIANT_DIGIT_MASK : (giantDigit)((1<<bits)-1);
+    giant scratch1;
+
+    b = bitlen(g);
+    if(b < n) {
+        unsigned numDigits = (n + GIANT_BITS_PER_DIGIT - 1) >>
+               GIANT_LOG2_BITS_PER_DIGIT;
+       giantDigit lastWord = 0;
+       giantDigit bits = 1;
+
+        if(g->sign >= 0) return;
+
+       /*
+        * Cons up ((2**n)-1), add to g.
+        */
+       scratch1 = borrowGiant(numDigits + 1);
+       scratch1->sign = numDigits;
+       for(j=0; j<(int)(numDigits-1); j++) {
+               scratch1->n[j] = GIANT_DIGIT_MASK;
+       }
+
+       /*
+        * Last word has lower (n & (GIANT_BITS_PER_DIGIT-1)) bits set.
+        */
+       for(j=0; j < (int)(n & (GIANT_BITS_PER_DIGIT-1)); j++) {
+               lastWord |= bits;
+               bits <<= 1;
+       }
+       scratch1->n[numDigits-1] = lastWord;
+       addg(g, scratch1);   /* One version. */
+       gtog(scratch1, g);
+       returnGiant(scratch1);
+       return;
+    }
+    if(b == n) {
+        for(foundzero=0, j=0; j<b; j++) {
+            if(bitval(g, j)==0) {
+                foundzero = 1;
+                break;
+            }
+        }
+        if (!foundzero) {
+            int_to_giant(0, g);
+            return;
+        }
+    }
+
+    absg(g);
+    scratch1 = borrowGiant(g->capacity);
+    while ( ((unsigned)(g->sign) > digits) ||
+            ( ((unsigned)(g->sign)==digits) && (g->n[digits-1] > mask))) {
+        extractbits(n, g, scratch1);
+        gshiftright(n, g);
+        addg(scratch1, g);
+    }
+    size = g->sign;
+
+/* Commence new negation routine - REC 17 Jan 1997. */
+    if (!isPositive) { /* Mersenne negation is just bitwise complement. */
+        for(j = digits-1; j >= size; j--) {
+           g->n[j] = GIANT_DIGIT_MASK;
+       }
+        for(j = size-1; j >= 0; j--) {
+           g->n[j] = ~g->n[j];
+       }
+       g->n[digits-1] &= mask;
+       j = digits-1;
+        while((g->n[j] == 0) && (j > 0)) {
+           --j;
+       }
+        size = j+1;
+    }
+/* End new negation routine. */
+
+    g->sign = size;
+    if (abs(g->sign) > g->capacity) {
+       CKRaise("gmersennemod overflow");
+    }
+    if (size < (int)digits) {
+       goto bye;
+    }
+    if (g->n[size-1] != mask) {
+       goto bye;
+    }
+    mask = GIANT_DIGIT_MASK;
+    for(j=0; j<(size-1); j++) {
+       if (g->n[j] != mask) {
+           goto bye;
+       }
+    }
+    g->sign = 0;
+  bye:
+    returnGiant(scratch1);
+}
+
+#endif /* NEW_MERSENNE */
+
+void mulg(giant a, giant b) { /* b becomes a*b. */
+
+    int i;
+    int asize, bsize;
+    giantDigit *bptr = b->n;
+    giantDigit mult;
+    giant scratch1;
+    giantDigit carry;
+    giantDigit *scrPtr;
+
+
+    if (isZero(b)) {
+       return;
+    }
+    if (isZero(a)) {
+       gtog(a, b);
+       return;
+    }
+    if(a == b) {
+       grammarSquare(b);
+       return;
+    }
+
+    bsize = abs(b->sign);
+    asize = abs(a->sign);
+    scratch1 = borrowGiant((asize+bsize));
+    scrPtr = scratch1->n;
+
+    for(i=0; i<asize+bsize; ++i) {
+       scrPtr[i]=0;
+    }
+
+    for(i=0; i<bsize; ++i, scrPtr++) {
+       mult = bptr[i];
+       if (mult != 0) {
+           carry = VectorMultiply(mult,
+               a->n,
+               asize,
+               scrPtr);
+           /* handle MSD carry */
+           scrPtr[asize] += carry;
+       }
+    }
+    bsize+=asize;
+     if(scratch1->n[bsize - 1] == 0) {
+        --bsize;
+    }
+    scratch1->sign = gsign(a) * gsign(b) * bsize;
+    if (abs(scratch1->sign) > scratch1->capacity) {
+       CKRaise("GiantGrammarMul overflow");
+    }
+    gtog(scratch1,b);
+    returnGiant(scratch1);
+
+    #if                FEE_DEBUG
+    (void)bitlen(b); // Assertion....
+    #endif     /* FEE_DEBUG */
+    PROF_INCR(numMulg);                        // for normal profiling
+    INCR_MULGS;                                // for ellipticMeasure
+}
+
+void grammarSquare(giant a) {
+    /*
+     * For now, we're going to match the old implementation line for
+     * line by maintaining prod, carry, and temp as double precision
+     * giantDigits. There is probably a much better implementation....
+     */
+    giantDigit         prodLo;
+    giantDigit         prodHi;
+    giantDigit         carryLo = 0;
+    giantDigit         carryHi = 0;
+    giantDigit         tempLo;
+    giantDigit         tempHi;
+    unsigned int       cur_term;
+    unsigned           asize;
+    unsigned           max;
+    giantDigit         *ptr = a->n;
+    giantDigit         *ptr1;
+    giantDigit         *ptr2;
+    giant              scratch;
+
+    /* dmitch 11 Jan 1998 - special case for a == 0 */
+    if(a->sign == 0) {
+       goto end;
+    }
+    /* end a == 0 case */
+    asize = abs(a->sign);
+    max = asize * 2 - 1;
+    scratch = borrowGiant(2 * asize);
+    asize--;
+
+    /*
+     * temp = *ptr;
+     * temp *= temp;
+     * scratch->n[0] = temp;
+     * carry = temp >> 16;
+     */
+    giantMulDigits(*ptr, *ptr, &tempLo, &tempHi);
+    scratch->n[0] = tempLo;
+    carryLo = tempHi;
+    carryHi = 0;
+
+    for (cur_term = 1; cur_term < max; cur_term++) {
+       ptr1 = ptr2 = ptr;
+       if (cur_term <= asize) {
+           ptr2 += cur_term;
+       } else {
+           ptr1 += cur_term - asize;
+           ptr2 += asize;
+       }
+
+       /*
+        * prod = carry & 0xFFFF;
+        * carry >>= 16;
+        */
+       prodLo = carryLo;
+       prodHi = 0;
+       carryLo = carryHi;
+       carryHi = 0;
+       while(ptr1 < ptr2) {
+           /*
+            * temp = *ptr1++ * *ptr2--;
+            */
+           giantMulDigits(*ptr1++, *ptr2--, &tempLo, &tempHi);
+
+           /*
+            * prod += (temp << 1) & 0xFFFF;
+            */
+           giantAddDouble(&prodLo, &prodHi, (tempLo << 1));
+
+           /*
+            * carry += (temp >> 15);
+            * use bits from both product digits..
+            */
+           giantAddDouble(&carryLo, &carryHi,
+               (tempLo >> (GIANT_BITS_PER_DIGIT - 1)));
+           giantAddDouble(&carryLo, &carryHi, (tempHi << 1));
+
+           /* snag the msb from that last shift */
+           carryHi += (tempHi >> (GIANT_BITS_PER_DIGIT - 1));
+       }
+       if (ptr1 == ptr2) {
+           /*
+            * temp = *ptr1;
+            * temp *= temp;
+            */
+           giantMulDigits(*ptr1, *ptr1, &tempLo, &tempHi);
+
+           /*
+            * prod += temp & 0xFFFF;
+            */
+           giantAddDouble(&prodLo, &prodHi, tempLo);
+
+           /*
+            * carry += (temp >> 16);
+            */
+           giantAddDouble(&carryLo, &carryHi, tempHi);
+       }
+
+       /*
+        * carry += prod >> 16;
+        */
+       giantAddDouble(&carryLo, &carryHi, prodHi);
+
+       scratch->n[cur_term] = prodLo;
+    }
+    if (carryLo) {
+       scratch->n[cur_term] = carryLo;
+       scratch->sign = cur_term+1;
+    } else scratch->sign = cur_term;
+
+    gtog(scratch,a);
+    returnGiant(scratch);
+end:
+    PROF_INCR(numGsquare);
+}
+
+/*
+ * Clear all of a giant's data fields, for secure erasure of sensitive data.,
+ */
+void clearGiant(giant g)
+{
+    unsigned i;
+
+    for(i=0; i<g->capacity; i++) {
+       g->n[i] = 0;
+    }
+    g->sign = 0;
+}
+
+#if    ENGINE_127_BITS
+/*
+ * only used by engineNSA127.c, which is obsolete as of 16 Jan 1997
+ */
+int
+scompg(int n, giant g) {
+    if((g->sign == 1) && (g->n[0] == n)) return(1);
+    return(0);
+}
+
+#endif // ENGINE_127_BITS
+
+/*
+ */
+
+/*
+ * Calculate the reciprocal of a demonimator used in divg_via_recip() and
+ * modg_via_recip().
+ */
+void
+make_recip(giant d, giant r)
+/* r becomes the steady-state reciprocal
+   2^(2b)/d, where b = bit-length of d-1. */
+{
+       int b;
+       int giantSize = 4 * abs(d->sign);
+       giant tmp = borrowGiant(giantSize);
+       giant tmp2 = borrowGiant(giantSize);
+
+       if (isZero(d) || (d->sign < 0))
+       {
+               CKRaise("illegal argument to make_recip");
+       }
+       int_to_giant(1, r); subg(r, d); b = bitlen(d); addg(r, d);
+       gshiftleft(b, r); gtog(r, tmp2);
+       while(1) {
+               gtog(r, tmp);
+               gsquare(tmp);
+               gshiftright(b, tmp);
+               mulg(d, tmp);
+               gshiftright(b, tmp);
+               addg(r, r); subg(tmp, r);
+               if(gcompg(r, tmp2) <= 0) break;
+               gtog(r, tmp2);
+       }
+       int_to_giant(1, tmp);
+       gshiftleft(2*b, tmp);
+       gtog(r, tmp2); mulg(d, tmp2);
+       subg(tmp2, tmp);
+       int_to_giant(1, tmp2);
+       while(tmp->sign < 0) {
+               subg(tmp2, r);
+               addg(d, tmp);
+       }
+
+       returnGiant(tmp);
+       returnGiant(tmp2);
+       return;
+}
+
+/*
+ * Optimized divg, when reciprocal of denominator is known.
+ */
+void
+divg_via_recip(giant d, giant r, giant n)
+/* n := n/d, where r is the precalculated
+   steady-state reciprocal of d. */
+{
+       int s = 2*(bitlen(r)-1), sign = gsign(n);
+       int giantSize = (4 * abs(d->sign)) + abs(n->sign);
+       giant tmp = borrowGiant(giantSize);
+       giant tmp2 = borrowGiant(giantSize);
+
+       if (isZero(d) || (d->sign < 0))
+       {
+               CKRaise("illegal argument to divg_via_recip");
+       }
+       n->sign = abs(n->sign);
+       int_to_giant(0, tmp2);
+       while(1) {
+               gtog(n, tmp);
+               mulg(r, tmp);
+               gshiftright(s, tmp);
+               addg(tmp, tmp2);
+               mulg(d, tmp);
+               subg(tmp, n);
+               if(gcompg(n,d) >= 0) {
+                       subg(d,n);
+                       iaddg(1, tmp2);
+               }
+               if(gcompg(n,d) < 0) break;
+       }
+       gtog(tmp2, n);
+       n->sign *= sign;
+       returnGiant(tmp);
+       returnGiant(tmp2);
+       return;
+}
+
+/*
+ * Optimized modg, when reciprocal of denominator is known.
+ */
+
+/* New version, 24 Dec 1997. */
+
+void
+modg_via_recip(
+       giant   d,
+       giant   r,
+       giant   n
+)
+/* This is the fastest mod of the present collection.
+   n := n % d, where r is the precalculated
+   steady-state reciprocal of d. */
+
+{
+    int                s = (bitlen(r)-1), sign = n->sign;
+    int        giantSize = (4 * abs(d->sign)) + abs(n->sign);
+    giant      tmp, tmp2;
+
+    tmp = borrowGiant(giantSize);
+    tmp2 = borrowGiant(giantSize);
+    if (isZero(d) || (d->sign < 0))
+    {
+       CKRaise("illegal argument to modg_via_recip");
+    }
+    n->sign = abs(n->sign);
+    while (1)
+    {
+       gtog(n, tmp);
+       /* bug fix 13 Apr 1998 */
+       if(s == 0) {
+           gshiftleft(1, tmp);
+       }
+       else {
+           gshiftright(s-1, tmp);
+       }
+       /* end fix */
+       mulg(r, tmp);
+       gshiftright(s+1, tmp);
+       mulg(d, tmp);
+       subg(tmp, n);
+       if (gcompg(n,d) >= 0)
+               subg(d,n);
+       if (gcompg(n,d) < 0)
+               break;
+    }
+    if (sign >= 0)
+       goto done;
+    if (isZero(n))
+       goto done;
+    negg(n);
+    addg(d,n);
+done:
+    returnGiant(tmp);
+    returnGiant(tmp2);
+    return;
+}
+
+/*
+ * Unoptimized, inefficient general modg, when reciprocal of denominator
+ * is not known.
+ */
+void
+modg(
+       giant   d,
+       giant   n
+)
+{
+       /* n becomes n%d. n is arbitrary, but the denominator d must be
+        * positive! */
+
+       /*
+        * 4/9/2001: seeing overflow on this recip. Alloc per 
+        * d->capacity, not d->sign.
+        */
+       //giant recip = borrowGiant(2 * abs(d->sign));
+       giant recip = borrowGiant(2 * d->capacity);
+
+       #if     WARN_UNOPTIMIZE
+       dbgLog(("Warning: unoptimized modg!\n"));
+       #endif  // WARN_UNOPTIMIZE
+
+       make_recip(d, recip);
+       modg_via_recip(d, recip, n);
+       returnGiant(recip);
+}
+
+/*
+ * Unoptimized, inefficient general divg, when reciprocal of denominator
+ * is not known.
+ */
+void
+divg(
+       giant   d,
+       giant   n
+)
+{
+       /* n becomes n/d. n is arbitrary, but the denominator d must be
+        * positive!
+        */
+
+       giant recip = borrowGiant(2 * abs(d->sign));
+
+       #if     WARN_UNOPTIMIZE
+       dbgLog(("Warning: unoptimized divg!\n"));
+       #endif  // WARN_UNOPTIMIZE
+
+       make_recip(d, recip);
+       divg_via_recip(d, recip, n);
+       returnGiant(recip);
+}