+/* 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);
+}