1097 lines
23 KiB
C
1097 lines
23 KiB
C
/* Copyright (c) 1998-2007 Apple Inc. All Rights Reserved. */
|
|
|
|
/*
|
|
|
|
giantIntegers.c - library for large-integer arithmetic.
|
|
|
|
Revision History
|
|
----------------
|
|
12/04/98 dmitch/R. Crandall
|
|
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 Doug Mitchell at Apple
|
|
Major rewrite of core arithmetic routines to make this module
|
|
independent of size of giantDigit.
|
|
Removed idivg() and radixdiv().
|
|
20 Jan 98 Doug Mitchell at Apple
|
|
Deleted FFT arithmetic; simplified mulg().
|
|
09 Jan 98 Doug Mitchell and Richard Crandall at Apple
|
|
gshiftright() optimization.
|
|
08 Jan 98 Doug Mitchell at Apple
|
|
newGiant() returns NULL on malloc failure
|
|
24 Dec 97 Doug Mitchell and Richard Crandall at Apple
|
|
New grammarSquare(); optimized modg_via_recip()
|
|
11 Jun 97 Doug Mitchell and Richard Crandall 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 Doug Mitchell at Apple
|
|
Changed size of giantstruct.n to 1 for Mac build
|
|
05 Feb 97 Doug Mitchell at Apple
|
|
newGiant() no longer modifies CurrentMaxShorts or giant stack
|
|
Added modg profiling
|
|
01 Feb 97 Doug Mitchell at NeXT
|
|
Added iszero() check in gcompg
|
|
17 Jan 97 Richard Crandall, Doug Mitchell at NeXT
|
|
Fixed negation bug in gmersennemod()
|
|
Fixed n[words-1] == 0 bug in extractbits()
|
|
Cleaned up lots of static declarations
|
|
19 Sep 96 Doug Mitchell at NeXT
|
|
Fixed --size underflow bug in normal_subg().
|
|
4 Sep 96 Doug Mitchell at NeXT
|
|
Fixed (b<n), (sign<0) case in gmersennemod() to allow for arbitrary n.
|
|
9 Aug 96 Doug Mitchell at NeXT
|
|
Fixed sign-extend bug in data_to_giant().
|
|
7 Aug 96 Doug Mitchell at NeXT
|
|
Changed precision in newtondivide().
|
|
Removed #ifdef UNUSED code.
|
|
24 Jul 96 Doug Mitchell at NeXT
|
|
Added scompg().
|
|
1991 Richard Crandall at NeXT
|
|
Created.
|
|
|
|
*/
|
|
|
|
#include <libGiants/giantTypes.h>
|
|
#include <libGiants/giantIntegers.h>
|
|
#include <libGiants/giantDebug.h>
|
|
#include <libGiants/giantPortCommon.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifndef GI_GIANT_LOG2_BITS_PER_DIGIT
|
|
#error Please define GI_GIANT_LOG2_BITS_PER_DIGIT
|
|
#endif
|
|
|
|
#if GIANTS_DEBUG
|
|
/*
|
|
* counter, acccumulates calls to (giantDigit x giantDigit) multiply.
|
|
*/
|
|
unsigned numGiantDigitMuls;
|
|
unsigned numMulgCommon;
|
|
unsigned numGSquareCommon;
|
|
#endif
|
|
|
|
/*
|
|
* Local (heap-allocated) giant support.
|
|
*/
|
|
|
|
#if !GI_INLINE_SMALL_FUNCS && !GI_MACRO_SMALL_FUNCTIONS
|
|
|
|
void initGiant(
|
|
giant g,
|
|
gi_uint16 capacity,
|
|
giantDigit *digits)
|
|
{
|
|
GI_CHECK_SP("initGiant");
|
|
g->sign = 0;
|
|
g->capacity = capacity;
|
|
g->n = digits;
|
|
}
|
|
|
|
/* call this after declaring a local lgiant and before using it */
|
|
void localGiantAlloc(lgiant *g)
|
|
{
|
|
initGiant(&g->g, GIANT_LITTLE_DIGITS, g->_n_);
|
|
|
|
}
|
|
|
|
/* ditto, for a bgiant */
|
|
extern void localBigGiantAlloc(bgiant *g)
|
|
{
|
|
initGiant(&g->g, GIANT_BIG_DIGITS, g->_n_);
|
|
}
|
|
|
|
/* ditto, for a bgiant */
|
|
void localTriGiantAlloc(tgiant *g)
|
|
{
|
|
initGiant(&g->g, GIANT_TRIPLE_DIGITS, g->_n_);
|
|
}
|
|
|
|
#endif /* !GI_INLINE_SMALL_FUNCS && !GI_MACRO_SMALL_FUNCTIONS */
|
|
|
|
gi_uint16 bitlen(giant n) {
|
|
gi_uint16 b = GIANT_BITS_PER_DIGIT;
|
|
giantDigit c = 1 << (GIANT_BITS_PER_DIGIT - 1);
|
|
giantDigit w;
|
|
|
|
GI_CHECK_SP("bitlen");
|
|
if (isZero(n)) {
|
|
return(0);
|
|
}
|
|
w = n->n[n->sign - 1];
|
|
GIASSERT (w != 0);
|
|
while((w&c) == 0) {
|
|
b--;
|
|
c >>= 1;
|
|
}
|
|
return(GIANT_BITS_PER_DIGIT * (n->sign - 1) + b);
|
|
}
|
|
|
|
giantDigit bitval(giant n, gi_uint16 pos)
|
|
{
|
|
gi_uint16 i = pos >> GI_GIANT_LOG2_BITS_PER_DIGIT;
|
|
giantDigit c = 1 << (pos & (GIANT_BITS_PER_DIGIT - 1));
|
|
|
|
GI_CHECK_SP("bitval");
|
|
return((n->n[i]) & c);
|
|
}
|
|
|
|
gi_uint16 giantNumBytes(giant n)
|
|
{
|
|
gi_uint16 bits = bitlen(n);
|
|
GI_CHECK_SP("giantNumBytes");
|
|
return (bits + 7) / 8;
|
|
}
|
|
|
|
/*
|
|
* Adjust sign for possible leading (m.s.) zero digits
|
|
*/
|
|
void gtrimSign(giant g)
|
|
{
|
|
int i = g->sign-1;
|
|
|
|
GI_CHECK_SP("gtrimSign");
|
|
if(g->sign == 0) {
|
|
return;
|
|
}
|
|
if(g->n[i] != 0) return;
|
|
for(--i; i>=0; i--) {
|
|
if(g->n[i] != 0) break;
|
|
}
|
|
g->sign = i+1;
|
|
}
|
|
|
|
#if !GI_INLINE_SMALL_FUNCS && !GI_MACRO_SMALL_FUNCTIONS
|
|
int isone(giant g) {
|
|
GI_CHECK_SP("isone");
|
|
return((g->sign == 1) && (g->n[0] == 1));
|
|
}
|
|
|
|
int isZero(giant thegiant) {
|
|
/* Returns TRUE if thegiant == 0. */
|
|
int count;
|
|
int length = thegiant->sign;
|
|
giantDigit *numpointer;
|
|
|
|
GI_CHECK_SP("isZero");
|
|
if (length) {
|
|
numpointer = thegiant->n;
|
|
|
|
for(count = 0; count<length; ++count,++numpointer) {
|
|
if (*numpointer != 0 ) {
|
|
return 0;
|
|
}
|
|
}
|
|
/* why wasn't this trimmed? */
|
|
GIASSERT(0);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#endif /* !GI_INLINE_SMALL_FUNCS && !GI_MACRO_SMALL_FUNCTIONS */
|
|
|
|
/* Returns the number of trailing zero bits in g. */
|
|
gi_uint16 numtrailzeros(
|
|
giant g)
|
|
{
|
|
gi_uint16 numDigits = g->sign, j, bcount=0;
|
|
giantDigit dig, c;
|
|
|
|
for (j=0;j<numDigits;j++) {
|
|
dig = g->n[j];
|
|
c = 1;
|
|
for (bcount=0;bcount<GIANT_BITS_PER_DIGIT; bcount++) {
|
|
if (c & dig) {
|
|
break;
|
|
}
|
|
c <<= 1;
|
|
}
|
|
if (bcount<GIANT_BITS_PER_DIGIT)
|
|
break;
|
|
}
|
|
return(bcount + GIANT_BITS_PER_DIGIT*j);
|
|
}
|
|
|
|
int gcompg(giant a, giant b)
|
|
/* returns -1,0,1 if a<b, a=b, a>b, respectively */
|
|
{
|
|
gi_uint16 sa = a->sign;
|
|
int j;
|
|
gi_uint16 sb = b->sign;
|
|
giantDigit va;
|
|
giantDigit vb;
|
|
|
|
if(isZero(a) && isZero(b)) return 0;
|
|
if(sa > sb) return(1);
|
|
if(sa < sb) return(-1);
|
|
|
|
for(j = sa-1; j >= 0; j--) {
|
|
va = a->n[j]; vb = b->n[j];
|
|
if (va > vb) return 1;
|
|
if (va < vb) return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* destgiant becomes equal to srcgiant */
|
|
void gtog(giant srcgiant, giant destgiant) {
|
|
|
|
unsigned numbytes;
|
|
|
|
GIASSERT(srcgiant != NULL);
|
|
GIASSERT(destgiant != NULL);
|
|
GIASSERT(srcgiant->sign <= destgiant->capacity);
|
|
|
|
GI_CHECK_SP("gtog");
|
|
numbytes = srcgiant->sign * GIANT_BYTES_PER_DIGIT;
|
|
Memcpy(destgiant->n, srcgiant->n, numbytes);
|
|
destgiant->sign = srcgiant->sign;
|
|
CHECK_GIANT_OFLOW(destgiant);
|
|
}
|
|
|
|
void int_to_giant(gi_uint32 i, giant g) {
|
|
/* The giant g becomes set to the integer value i. */
|
|
gi_size dex;
|
|
|
|
GI_CHECK_SP("int_to_giant");
|
|
g->sign = 0;
|
|
if (i == 0) {
|
|
g->n[0] = 0;
|
|
return;
|
|
}
|
|
|
|
if(sizeof(giantDigit) >= sizeof(i)) {
|
|
/* guaranteed trivial case */
|
|
g->n[0] = i;
|
|
g->sign = 1;
|
|
}
|
|
else {
|
|
/* one loop per digit */
|
|
gi_uint16 scnt = GIANT_BITS_PER_DIGIT;
|
|
|
|
for(dex=0; ; dex++) {
|
|
g->n[dex] = i & GIANT_DIGIT_MASK;
|
|
i >>= scnt;
|
|
g->sign++;
|
|
if(i == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The integer i becomes set to the giant value g. Returns GR_Overflow if
|
|
the giant is too big. */
|
|
GIReturn giant_to_int(giant g, gi_uint32 *i) {
|
|
gi_uint16 dex;
|
|
gi_uint32 value = 0;
|
|
|
|
GI_CHECK_SP("giant_to_int");
|
|
|
|
if (g->sign * GIANT_BYTES_PER_DIGIT > sizeof(*i))
|
|
return GR_Overflow;
|
|
|
|
for (dex = g->sign; dex-- > 0;) {
|
|
value <<= GIANT_BITS_PER_DIGIT;
|
|
value |= g->n[dex];
|
|
}
|
|
|
|
*i = value;
|
|
return GR_Success;
|
|
}
|
|
|
|
/*------------- Arithmetic --------------*/
|
|
|
|
/*
|
|
* Two implementations of these. Which one is faster depends highly on your
|
|
* implementation of giantPortCommon.h and your platform's giantDouble performance.
|
|
* If giantDouble arithmetic is fast then use GI_ADDG_INLINE. Otherwise try
|
|
* !GI_ADDG_INLINE, measure the two, and pick the best one.
|
|
*/
|
|
#if GI_ADDG_INLINE
|
|
|
|
void iaddg(giantDigit i, giant g) {
|
|
gi_size j;
|
|
giantDigit carry;
|
|
gi_size size = g->sign;
|
|
giantDouble tmp;
|
|
|
|
if (isZero(g)) {
|
|
int_to_giant(i,g);
|
|
}
|
|
else {
|
|
carry = i;
|
|
for(j=0; ((j<size) && (carry != 0)); j++) {
|
|
tmp = (giantDouble)(g->n[j]) + (giantDouble)carry;
|
|
carry = tmp >> GIANT_BITS_PER_DIGIT;
|
|
g->n[j] = tmp; // implicit truncate to giantDigit
|
|
}
|
|
if(carry) {
|
|
++g->sign;
|
|
CHECK_GIANT_OFLOW(g);
|
|
g->n[size] = carry;
|
|
}
|
|
}
|
|
}
|
|
|
|
void imulg(giantDigit a, giant g)
|
|
{
|
|
giantDigit carry = 0;
|
|
gi_size size = g->sign;
|
|
gi_size j;
|
|
giantDigit *digit = g->n;
|
|
giantDouble k;
|
|
|
|
GIASSERT((size == 0) || (g->n[size - 1] != 0)); // caller should trim!
|
|
GI_CHECK_SP("imulg");
|
|
|
|
for (j=0; j<size; ++j)
|
|
{
|
|
k = ((giantDouble)(*digit) * (giantDouble)a) + (giantDouble)carry;
|
|
carry = k >> GIANT_BITS_PER_DIGIT;
|
|
*digit = k; // implicit truncation
|
|
++digit;
|
|
}
|
|
if (carry)
|
|
{
|
|
*digit = carry;
|
|
g->sign = size+1;
|
|
return;
|
|
}
|
|
g->sign = size;
|
|
CHECK_GIANT_OFLOW(g);
|
|
}
|
|
|
|
void
|
|
normal_addg(
|
|
giant a,
|
|
giant b
|
|
)
|
|
{
|
|
giantDigit carry = 0;
|
|
gi_size asize = a->sign, bsize = b->sign;
|
|
gi_size j=0;
|
|
giantDigit *aptr = a->n, *bptr = b->n;
|
|
giantDouble k;
|
|
|
|
GI_CHECK_SP("normal_addg");
|
|
if (asize < bsize)
|
|
{
|
|
for (j=0; j<asize; j++)
|
|
{
|
|
k = (giantDouble)(*aptr++) + (giantDouble)(*bptr) + (giantDouble)carry;
|
|
carry = k >> GIANT_BITS_PER_DIGIT;
|
|
*bptr++ = k;
|
|
}
|
|
for (j=asize; j<bsize; j++)
|
|
{
|
|
k = (giantDouble)(*bptr) + (giantDouble)carry;
|
|
carry = k >> GIANT_BITS_PER_DIGIT;
|
|
*bptr++ = k;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (j=0; j<bsize; j++)
|
|
{
|
|
k = (giantDouble)(*aptr++) + (giantDouble)(*bptr) + (giantDouble)carry;
|
|
carry = k >> GIANT_BITS_PER_DIGIT;
|
|
*bptr++ = k;
|
|
}
|
|
for (j=bsize; j<asize; j++)
|
|
{
|
|
k = (giantDouble)(*aptr++) + (giantDouble)carry;
|
|
carry = k >> GIANT_BITS_PER_DIGIT;
|
|
*bptr++ = k;
|
|
}
|
|
}
|
|
if (carry)
|
|
{
|
|
*bptr = 1; ++j;
|
|
}
|
|
b->sign = j;
|
|
CHECK_GIANT_OFLOW(b);
|
|
}
|
|
|
|
#else /* !GI_ADDG_INLINE */
|
|
|
|
/*
|
|
* Use these versions if your giantPortCommon.h is faster than your platform's giantDouble
|
|
* arithmetic
|
|
*/
|
|
|
|
void iaddg(giantDigit i, giant g) {
|
|
gi_size j;
|
|
giantDigit carry;
|
|
gi_size size = g->sign;
|
|
|
|
if (isZero(g)) {
|
|
int_to_giant(i,g);
|
|
}
|
|
else {
|
|
carry = i;
|
|
giantDigit *n = g->n;
|
|
for(j=0; ((j<size) && (carry != 0)); j++) {
|
|
/* tmp = g->n[j] + carry;
|
|
carry = tmp >> GIANT_BITS_PER_DIGIT;
|
|
g->n[j] = tmp; -- implicit truncate to giantDigit */
|
|
giantDigit sum;
|
|
sum = giantAddDigits(*n, carry, &carry);
|
|
*n++ = sum;
|
|
}
|
|
if(carry) {
|
|
++g->sign;
|
|
CHECK_GIANT_OFLOW(g);
|
|
g->n[size] = carry;
|
|
}
|
|
}
|
|
}
|
|
|
|
void imulg(giantDigit a, giant g)
|
|
{
|
|
giantDigit carry = 0;
|
|
gi_size size = g->sign;
|
|
gi_size j;
|
|
giantDigit *digit = g->n;
|
|
|
|
GI_CHECK_SP("imulg");
|
|
for (j=0; j<size; ++j)
|
|
{
|
|
giantDigit lowProd;
|
|
giantDigit hiProd;
|
|
|
|
/* k := (*digit * a) + carry; */
|
|
giantMulDigits(*digit, a, &lowProd, &hiProd);
|
|
giantAddDouble(&lowProd, &hiProd, carry);
|
|
carry = hiProd;
|
|
*digit = lowProd;
|
|
++digit;
|
|
}
|
|
if (carry)
|
|
{
|
|
*digit = carry;
|
|
g->sign = size+1;
|
|
return;
|
|
}
|
|
g->sign = size;
|
|
}
|
|
|
|
void
|
|
normal_addg(
|
|
giant a,
|
|
giant b
|
|
)
|
|
{
|
|
giantDigit carry = 0;
|
|
gi_size asize = a->sign, bsize = b->sign;
|
|
gi_size j=0;
|
|
giantDigit *aptr = a->n, *bptr = b->n;
|
|
giantDigit sumHi;
|
|
bgiant tmpA;
|
|
|
|
GI_CHECK_SP("normal_addg");
|
|
if(a == b) {
|
|
/* this routine cannot handle an add in place - make a copy */
|
|
localBigGiantAlloc(&tmpA);
|
|
gtog(a, &tmpA.g);
|
|
aptr = tmpA.g.n;
|
|
}
|
|
|
|
if (asize < bsize)
|
|
{
|
|
for (j=0; j<asize; j++)
|
|
{
|
|
sumHi = 0;
|
|
if(carry) {
|
|
/* bring in previous carry */
|
|
giantAddDouble(bptr, &sumHi, carry);
|
|
}
|
|
/* now the addend, accumulating carry */
|
|
carry = sumHi;
|
|
giantAddDouble(bptr++, &carry, *aptr++);
|
|
}
|
|
for (j=asize; j<bsize; j++)
|
|
{
|
|
if(carry == 0) {
|
|
j = bsize;
|
|
break;
|
|
}
|
|
sumHi = 0;
|
|
giantAddDouble(bptr++, &sumHi, carry);
|
|
carry = sumHi;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (j=0; j<bsize; j++)
|
|
{
|
|
sumHi = 0;
|
|
if(carry) {
|
|
/* bring in previous carry */
|
|
giantAddDouble(bptr, &sumHi, carry);
|
|
}
|
|
/* now the addend, accumulating carry */
|
|
carry = sumHi;
|
|
giantAddDouble(bptr++, &carry, *aptr++);
|
|
|
|
}
|
|
for (j=bsize; j<asize; j++)
|
|
{
|
|
giantDigit sumLo = carry;
|
|
sumHi = 0;
|
|
giantAddDouble(&sumLo, &sumHi, *aptr++);
|
|
carry = sumHi;
|
|
*bptr++ = sumLo;
|
|
}
|
|
}
|
|
if (carry)
|
|
{
|
|
*bptr = 1; ++j;
|
|
}
|
|
b->sign = j;
|
|
CHECK_GIANT_OFLOW(b);
|
|
}
|
|
|
|
#endif /* GI_ADDG_INLINE */
|
|
|
|
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;
|
|
|
|
GI_CHECK_SP("normal_subg");
|
|
GIASSERT(gcompg(b, a) >= 0); /* else we'd come up with a negative result... */
|
|
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;
|
|
CHECK_GIANT_OFLOW(b);
|
|
}
|
|
|
|
/* return the number of leading zeroes in the m.s. digit */
|
|
static gi_uint16 gleadzeroes(giant g)
|
|
{
|
|
giantDigit dig = g->n[g->sign - 1];
|
|
gi_uint16 numZeroes = 0;
|
|
giantDigit mask = 1 << (GIANT_BITS_PER_DIGIT - 1);
|
|
|
|
GIASSERT(!isZero(g));
|
|
|
|
while((dig & mask) == 0) {
|
|
numZeroes++;
|
|
mask >>= 1;
|
|
if(mask == 0) {
|
|
/* all zeroes, shouldn't happen */
|
|
GIASSERT(0);
|
|
return GIANT_BITS_PER_DIGIT;
|
|
}
|
|
}
|
|
return numZeroes;
|
|
}
|
|
|
|
/*
|
|
* The new gshiftleft costs an extra 280 bytes of code space, but has no measurable
|
|
* increase in performance (on G4, gcc 3.3).
|
|
*/
|
|
#define NEW_SHIFTLEFT 0
|
|
|
|
#if NEW_SHIFTLEFT
|
|
|
|
|
|
void gshiftleft(gi_uint16 bits, giant g )
|
|
{
|
|
/* Number of full words/digits to leftshift */
|
|
gi_uint16 wordshift = bits >> GI_GIANT_LOG2_BITS_PER_DIGIT;
|
|
/* Number of bits to shift left */
|
|
gi_uint16 leftshift = bits & (GIANT_BITS_PER_DIGIT-1);
|
|
gi_uint16 rightshift = GIANT_BITS_PER_DIGIT - leftshift;
|
|
gi_uint16 olddigits = g->sign;
|
|
/* Leading 0's of high word */
|
|
gi_uint16 lead;
|
|
gi_uint16 newdigits;
|
|
gi_uint16 j = olddigits - 1;
|
|
giantDigit remainder;
|
|
gi_uint16 k;
|
|
|
|
if (!bits || !olddigits) {
|
|
return;
|
|
}
|
|
lead = gleadzeroes(g);
|
|
newdigits = ((bits + (GIANT_BITS_PER_DIGIT-lead) - 1) >> GI_GIANT_LOG2_BITS_PER_DIGIT) + olddigits;
|
|
k = newdigits;
|
|
|
|
if (!leftshift) {
|
|
/* Case 1: Whole word moves */
|
|
Memcpy(g->n + wordshift, g->n, olddigits * GIANT_BYTES_PER_DIGIT);
|
|
k = wordshift;
|
|
} else if (leftshift <= lead) {
|
|
/* Case 2: No bit-wrapping on the high end */
|
|
giantDigit next = g->n[j];
|
|
giantDigit load;
|
|
while( j > 0 ) {
|
|
load = next;
|
|
next = g->n[j-1];
|
|
remainder = next >> rightshift;
|
|
g->n[--k] = (load << leftshift) | remainder;
|
|
j--;
|
|
}
|
|
g->n[--k] = next << leftshift; // next == g->n[0]
|
|
} else {
|
|
/* Case 3: When we left-shift the high bits, they will spill over and use olddigits+wordshift+1 words */
|
|
giantDigit load = g->n[j];
|
|
remainder = 0;
|
|
while( j > 0 ) {
|
|
g->n[--k] = (load >> rightshift) | remainder;
|
|
remainder = load << leftshift;
|
|
load = g->n[--j];
|
|
}
|
|
g->n[--k] = (load >> rightshift) | remainder;
|
|
remainder = load << leftshift;
|
|
g->n[--k] = remainder;
|
|
}
|
|
Bzero(g->n, k * GIANT_BYTES_PER_DIGIT ); // Shift in 0's on the right
|
|
g->sign = newdigits;
|
|
CHECK_GIANT_OFLOW(g);
|
|
return;
|
|
}
|
|
|
|
#else /* OLD shiftleft */
|
|
|
|
void gshiftleft(gi_uint16 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 >> GI_GIANT_LOG2_BITS_PER_DIGIT);
|
|
int size = g->sign;
|
|
int j;
|
|
int k;
|
|
giantDigit carry;
|
|
giantDigit dat;
|
|
gi_uint16 lead;
|
|
gi_uint16 newdigits;
|
|
|
|
GI_CHECK_SP("gshiftleft");
|
|
if(!bits) return;
|
|
if(!size) return;
|
|
|
|
/* rem=0 means we're shifting strictly by digits, no bit shifts. */
|
|
if(rem == 0) {
|
|
gshiftwordsleft(digits-1, g);
|
|
return;
|
|
}
|
|
lead = gleadzeroes(g);
|
|
newdigits = ((bits + (GIANT_BITS_PER_DIGIT-lead) - 1) >>
|
|
GI_GIANT_LOG2_BITS_PER_DIGIT) + size;
|
|
|
|
/*
|
|
* due to hack of clearing g->n[k] below we can only shift such that
|
|
* the result is one digit less than the giant's capacity
|
|
*/
|
|
//GIASSERT((size+digits) <= (int)g->capacity);
|
|
k = size - 1 + digits; // (MSD of result + 1)
|
|
carry = 0;
|
|
|
|
/*
|
|
* 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];
|
|
if(k < newdigits) {
|
|
g->n[k--] = (dat >> crem) | carry;
|
|
}
|
|
else {
|
|
k--;
|
|
}
|
|
carry = (dat << rem);
|
|
}
|
|
do{
|
|
g->n[k--] = carry;
|
|
carry = 0;
|
|
} while(k>=0);
|
|
|
|
g->sign = newdigits;
|
|
CHECK_GIANT_OFLOW(g);
|
|
}
|
|
#endif /* NEW_SHIFTLEFT */
|
|
|
|
void gshiftright(gi_uint16 bits, giant g) {
|
|
/* shift g right bits bits. Equivalent to g = g/2^bits */
|
|
gi_size j;
|
|
gi_size size = g->sign;
|
|
giantDigit carry;
|
|
gi_size digits = bits >> GI_GIANT_LOG2_BITS_PER_DIGIT;
|
|
gi_size remain = bits & (GIANT_BITS_PER_DIGIT - 1);
|
|
gi_size cremain = GIANT_BITS_PER_DIGIT - remain;
|
|
|
|
GI_CHECK_SP("gshiftright");
|
|
if(bits==0) return;
|
|
if (digits >= size) {
|
|
g->sign = 0;
|
|
return;
|
|
}
|
|
|
|
size -= digits;
|
|
|
|
/* Begin OPT: 9 Jan 98 REC. */
|
|
if(remain == 0) {
|
|
g->sign = size;
|
|
/* FIXME we can do better than this with memmove or pointers... */
|
|
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;
|
|
}
|
|
g->sign = size;
|
|
CHECK_GIANT_OFLOW(g);
|
|
}
|
|
|
|
// Right-shift z by s giantDigits
|
|
void gshifltwordsright(
|
|
gi_uint16 digits,
|
|
giant g)
|
|
{
|
|
gi_size size = g->sign;
|
|
gi_size numBytes;
|
|
|
|
GI_CHECK_SP("gshifltwordsright");
|
|
if(digits == 0) {
|
|
return;
|
|
}
|
|
/* not necessary, we won't do anything if it's zero
|
|
if(isZero(g)) {
|
|
return;
|
|
}
|
|
*/
|
|
if (digits >= size) {
|
|
g->sign = 0;
|
|
return;
|
|
}
|
|
|
|
size -= digits;
|
|
g->sign = size;
|
|
numBytes = size * GIANT_BYTES_PER_DIGIT;
|
|
Memcpy(&g->n[0], &g->n[digits], numBytes);
|
|
}
|
|
|
|
/* shift left by s giantDigits */
|
|
void gshiftwordsleft(
|
|
gi_uint16 digits,
|
|
giant g)
|
|
{
|
|
gi_size dex;
|
|
giantDigit *src;
|
|
giantDigit *dst;
|
|
|
|
GI_CHECK_SP("gshiftwordsleft");
|
|
if(digits == 0) {
|
|
return;
|
|
}
|
|
|
|
/* start copying from m.s. digit */
|
|
src = &g->n[g->sign - 1];
|
|
dst = src + digits;
|
|
for(dex=0; dex<g->sign; dex++) {
|
|
*dst-- = *src--;
|
|
}
|
|
Bzero(g->n, digits * GIANT_BYTES_PER_DIGIT);
|
|
g->sign += digits;
|
|
CHECK_GIANT_OFLOW(g);
|
|
}
|
|
|
|
/* dest *= a * b */
|
|
void
|
|
mulg(
|
|
giant a,
|
|
giant b)
|
|
{
|
|
bgiant dest;
|
|
|
|
localBigGiantAlloc(&dest);
|
|
GI_CHECK_SP("mulg");
|
|
mulg_common(a, b, &dest.g);
|
|
gtog(&dest.g, b);
|
|
}
|
|
|
|
/* dest *= a * b */
|
|
void
|
|
mulg_common(
|
|
giant a,
|
|
giant b,
|
|
giant dest) /* typically a bgiant */
|
|
{
|
|
gi_size i,j;
|
|
giantDouble prod1;
|
|
giantDouble prod2;
|
|
giantDouble carry1=0;
|
|
giantDouble carry2=0;
|
|
gi_size asize = a->sign, bsize = b->sign;
|
|
giantDigit *aptr,*bptr,*destptr;
|
|
giantDigit curmul;
|
|
giantDigit prevmul;
|
|
giantDigit mult1;
|
|
giantDigit mult2;
|
|
giantDouble prevDigit;
|
|
giantDouble prodsum;
|
|
|
|
INCR_NUM_MULGS;
|
|
GIASSERT(dest->capacity >= (a->sign + b->sign));
|
|
GI_CHECK_SP("mulg_common");
|
|
|
|
if(isZero(a) || isZero(b)) {
|
|
dest->sign = 0;
|
|
return;
|
|
}
|
|
Bzero(dest->n, (asize+bsize) * GIANT_BYTES_PER_DIGIT);
|
|
|
|
bptr = b->n;
|
|
for (i=0; i<bsize-1; i += 2)
|
|
{
|
|
mult1 = *(bptr++);
|
|
mult2 = *(bptr++);
|
|
|
|
prevmul = 0;
|
|
carry1 = 0;
|
|
carry2 = 0;
|
|
aptr = &(a->n[0]);
|
|
destptr = &(dest->n[i]);
|
|
prevDigit = *destptr;
|
|
|
|
for (j=0; j<asize; ++j) {
|
|
//prod = *(aptr++) * mult + *destptr + carry;
|
|
curmul = (giantDouble)(*aptr++);
|
|
|
|
prevDigit += carry1 + carry2;
|
|
|
|
prod1 = (giantDouble)curmul*mult1;
|
|
prod2 = (giantDouble)prevmul*mult2;
|
|
|
|
INCR_DIGIT_MULS;
|
|
INCR_DIGIT_MULS;
|
|
|
|
carry1 = prod1 >> GIANT_BITS_PER_DIGIT;
|
|
carry2 = prod2 >> GIANT_BITS_PER_DIGIT;
|
|
|
|
prod1 &= GIANT_DIGIT_MASK;
|
|
prod2 &= GIANT_DIGIT_MASK;
|
|
|
|
prodsum = prod1 + prod2 + prevDigit;
|
|
carry1 += prodsum >> GIANT_BITS_PER_DIGIT;
|
|
prevDigit = *(destptr+1);
|
|
*(destptr++) = prodsum; // implicit truncate
|
|
prevmul = curmul;
|
|
}
|
|
|
|
prod1 = prevDigit + carry1;
|
|
prod1 += (giantDouble)prevmul*mult2;
|
|
prod1 += carry2;
|
|
carry1 = prod1 >> GIANT_BITS_PER_DIGIT;
|
|
*(destptr++) = prod1; // implicit truncate
|
|
*destptr = carry1;
|
|
}
|
|
|
|
if (i<bsize) {
|
|
mult1 = *(bptr++);
|
|
if (mult1) {
|
|
carry1 = 0;
|
|
aptr = &(a->n[0]);
|
|
destptr = &(dest->n[i]);
|
|
for (j=0; j<asize; ++j) {
|
|
//prod = *(aptr++) * mult + *destptr + carry;
|
|
prod1 = (giantDouble)(*aptr++);
|
|
prod1 *= mult1;
|
|
INCR_DIGIT_MULS;
|
|
prod1 += *destptr;
|
|
prod1 += carry1;
|
|
*(destptr++) = prod1; // implicit truncate
|
|
carry1 = prod1 >> GIANT_BITS_PER_DIGIT;
|
|
}
|
|
*destptr = carry1;
|
|
}
|
|
}
|
|
|
|
bsize += asize;
|
|
if (bsize && !carry1) {
|
|
--bsize;
|
|
}
|
|
dest->sign = bsize;
|
|
}
|
|
|
|
void
|
|
grammarSquare (
|
|
giant a)
|
|
{
|
|
bgiant dest;
|
|
|
|
localBigGiantAlloc(&dest);
|
|
GI_CHECK_SP("grammarSquare");
|
|
grammarSquare_common(a, &dest.g);
|
|
gtog(&dest.g, a);
|
|
}
|
|
|
|
void
|
|
grammarSquare_common (
|
|
giant a,
|
|
giant dest) /* typically a bgiant */
|
|
{
|
|
gi_size i,j;
|
|
giantDigit currentDigit;
|
|
giantDouble prod;
|
|
giantDouble carry=0;
|
|
gi_size asize = a->sign;
|
|
giantDigit *aptr,*bptr,*destptr;
|
|
giantDigit mult;
|
|
|
|
INCR_NUM_GSQUARE;
|
|
GI_CHECK_SP("grammarSquare_common");
|
|
if(asize == 0) {
|
|
/*
|
|
* the rest of this routine really is not equipped to handle this, hence
|
|
* this trivial special casse
|
|
*/
|
|
dest->sign = 0;
|
|
return;
|
|
}
|
|
destptr = dest->n;
|
|
|
|
aptr = a->n;
|
|
|
|
for (i=0; i<asize; ++i)
|
|
{
|
|
giantDouble prodx;
|
|
|
|
mult = *aptr++;
|
|
|
|
prodx = ((giantDouble)mult) * mult;
|
|
|
|
*destptr++ = prodx;
|
|
*destptr++ = prodx >> GIANT_BITS_PER_DIGIT;
|
|
}
|
|
|
|
bptr = a->n;
|
|
|
|
for (i=0; i<asize-1; ++i)
|
|
{
|
|
|
|
mult = *bptr++;
|
|
|
|
//if (mult)
|
|
if (1)
|
|
{
|
|
giantDouble carried;
|
|
giantDouble produced;
|
|
aptr = &(a->n[i+1]);
|
|
destptr = &(dest->n[2*i+1]);
|
|
carry = 0;
|
|
|
|
for (j=i+1; j<asize; ++j)
|
|
{
|
|
//prod = *(aptr++) * mult + *destptr + carry;
|
|
prod = (giantDouble)(*aptr++);
|
|
|
|
produced = prod * mult;
|
|
|
|
carried = (produced >> GIANT_BITS_PER_DIGIT) << 1;
|
|
produced = (produced & GIANT_DIGIT_MASK) << 1;
|
|
|
|
currentDigit = *destptr;
|
|
prod = currentDigit + carry;
|
|
prod += produced;
|
|
|
|
*(destptr++) = prod; // implicit truncate
|
|
carry = prod >> GIANT_BITS_PER_DIGIT;
|
|
|
|
carry += carried;
|
|
}
|
|
|
|
do {
|
|
currentDigit = *destptr;
|
|
|
|
carried = carry >> GIANT_BITS_PER_DIGIT;
|
|
|
|
prod = (carry & GIANT_DIGIT_MASK) + currentDigit;
|
|
|
|
*destptr++ = prod; // implicit truncate
|
|
|
|
carry = carried + (prod >> GIANT_BITS_PER_DIGIT);
|
|
} while (carry);
|
|
}
|
|
}
|
|
|
|
asize += asize;
|
|
|
|
currentDigit = dest->n[asize-1];
|
|
currentDigit += carry;
|
|
dest->n[asize-1] = currentDigit;
|
|
|
|
if (asize && !currentDigit)
|
|
--asize;
|
|
dest->sign = asize;
|
|
}
|
|
|
|
|
|
/*
|
|
* Clear all of a giant's data fields, for secure erasure of sensitive data.
|
|
*/
|
|
void clearGiant(giant g)
|
|
{
|
|
GI_CHECK_SP("clearGiant");
|
|
Bzero(g->n, g->capacity * GIANT_BYTES_PER_DIGIT);
|
|
g->sign = 0;
|
|
}
|
|
|