1995-11-06 02:34:19 -08:00
|
|
|
|
/* Copyright Digital Equipment Corporation & INRIA 1988, 1989 */
|
|
|
|
|
/* Last modified_on Thu Feb 20 18:18:12 GMT+1:00 1992 by shand */
|
|
|
|
|
/* modified_on Tue Jan 15 19:32:53 GMT+1:00 1991 by herve */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* KerN.c: the kernel written in C */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Description of types and constants.
|
|
|
|
|
*
|
|
|
|
|
* Several conventions are used in the commentary:
|
|
|
|
|
* A "BigNum" is the name for an infinite-precision number.
|
|
|
|
|
* Capital letters (e.g., "N") are used to refer to the value of BigNums.
|
|
|
|
|
* The word "digit" refers to a single BigNum digit.
|
|
|
|
|
* The notation "Size(N)" refers to the number of digits in N,
|
|
|
|
|
* which is typically passed to the subroutine as "nl".
|
|
|
|
|
* The notation "Length(N)" refers to the number of digits in N,
|
|
|
|
|
* not including any leading zeros.
|
|
|
|
|
* The word "Base" is used for the number 2 ** BN_DIGIT_SIZE, where
|
|
|
|
|
* BN_DIGIT_SIZE is the number of bits in a single BigNum digit.
|
|
|
|
|
* The expression "BBase(N)" is used for Base ** NumDigits(N).
|
|
|
|
|
* The term "leading zeros" refers to any zeros before the most
|
|
|
|
|
* significant digit of a number.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* In the code, we have:
|
|
|
|
|
*
|
|
|
|
|
* "nn" is a pointer to a big number,
|
|
|
|
|
* "nl" is the number of digits from nn,
|
|
|
|
|
* "d" is a digit.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
#define BNNMACROS_OFF
|
|
|
|
|
#include "BigNum.h"
|
|
|
|
|
#define NOMEM
|
|
|
|
|
|
|
|
|
|
/*** copyright ***/
|
|
|
|
|
|
|
|
|
|
static char copyright[]="@(#)KerN.c: copyright Digital Equipment Corporation & INRIA 1988, 1989\n";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******* non arithmetic access to digits ********/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
void BnnSetToZero (BigNum nn, BigNumLength nl)
|
|
|
|
|
#else
|
|
|
|
|
void BnnSetToZero (nn, nl)
|
|
|
|
|
BigNum nn; BigNumLength nl;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Sets all the specified digits of the BigNum to 0
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
BigNum nnlim;
|
|
|
|
|
if (nl <= 0)
|
|
|
|
|
return;
|
|
|
|
|
nnlim = nn+nl-1;
|
|
|
|
|
do *nn = 0; while(nn++ < nnlim);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
void BnnAssign (BigNum mm, BigNum nn, BigNumLength nl)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
void BnnAssign ( mm, nn, nl)
|
|
|
|
|
BigNum mm; BigNum nn; BigNumLength nl;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copies N => M
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
BigNum nnlim;
|
|
|
|
|
if (nl <= 0)
|
|
|
|
|
return;
|
|
|
|
|
nnlim = nn+nl;
|
|
|
|
|
#ifdef MSDOS
|
|
|
|
|
if (realaddr(mm) < realaddr(nn) || realaddr(mm) > realaddr(nnlim))
|
|
|
|
|
#else
|
|
|
|
|
if ((mm < nn) || ( mm > nnlim))
|
|
|
|
|
#endif
|
|
|
|
|
do *mm++ = *nn++; while(nn < nnlim);
|
|
|
|
|
else
|
|
|
|
|
#ifdef MSDOS
|
|
|
|
|
if (realaddr(mm) > realaddr(nn))
|
|
|
|
|
#else
|
|
|
|
|
if (mm > nn)
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
mm += nl;
|
|
|
|
|
do *--mm = *--nnlim; while(nn < nnlim);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
void BnnSetDigit (BigNum nn, BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
void BnnSetDigit ( nn, d)
|
|
|
|
|
BigNum nn; BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Sets a single digit of N to the passed value
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
*nn = d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumDigit BnnGetDigit (BigNum nn)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumDigit BnnGetDigit ( nn)
|
|
|
|
|
BigNum nn;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns the single digit pointed by N
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
return (*nn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumLength BnnNumDigits (BigNum nn, BigNumLength nl)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumLength BnnNumDigits ( nn, nl)
|
|
|
|
|
BigNum nn; BigNumLength nl;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns the number of digits of N, not counting leading zeros
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
nn += nl;
|
|
|
|
|
|
|
|
|
|
while (nl != 0 && *--nn == 0)
|
|
|
|
|
nl--;
|
|
|
|
|
|
|
|
|
|
return (nl == 0 ? 1 : nl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumDigit BnnNumLeadingZeroBitsInDigit (BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumDigit BnnNumLeadingZeroBitsInDigit ( d)
|
|
|
|
|
BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns the number of leading zero bits in a digit
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
register int p = 0;
|
|
|
|
|
if (BN_DIGIT_SIZE == 16 || BN_DIGIT_SIZE == 32 || BN_DIGIT_SIZE == 64)
|
|
|
|
|
{
|
|
|
|
|
register BigNumDigit mask = (~(BigNumDigit)0) << (BN_DIGIT_SIZE/2);
|
|
|
|
|
register BigNumLength maskl = BN_DIGIT_SIZE/2;
|
|
|
|
|
|
|
|
|
|
if (d == 0)
|
|
|
|
|
return (BN_DIGIT_SIZE);
|
|
|
|
|
while (maskl)
|
|
|
|
|
{
|
|
|
|
|
if ((d & mask) == 0)
|
|
|
|
|
{
|
|
|
|
|
p += maskl;
|
|
|
|
|
d <<= maskl;
|
|
|
|
|
}
|
|
|
|
|
maskl >>= 1;
|
|
|
|
|
mask <<= maskl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
register BigNumDigit mask = ((BigNumDigit)1) << (BN_DIGIT_SIZE-1);
|
|
|
|
|
|
|
|
|
|
while ((d & mask) == 0)
|
|
|
|
|
{
|
|
|
|
|
p++;
|
|
|
|
|
mask >>= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
/************** Predicates on one digit ***************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
Boolean BnnDoesDigitFitInWord (BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
Boolean BnnDoesDigitFitInWord ( d)
|
|
|
|
|
BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns TRUE iff the digit can be represented in just BN_WORD_SIZE bits
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
/* The C compiler must evaluate the predicate at compile time */
|
|
|
|
|
if (BN_DIGIT_SIZE > BN_WORD_SIZE)
|
|
|
|
|
return (d >= ((BigNumDigit)1) << BN_WORD_SIZE ? FALSE : TRUE);
|
|
|
|
|
else
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
Boolean BnnIsDigitZero (BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
Boolean BnnIsDigitZero ( d)
|
|
|
|
|
BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/* Returns TRUE iff digit = 0 */
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
return (d == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
Boolean BnnIsDigitNormalized (BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
Boolean BnnIsDigitNormalized ( d)
|
|
|
|
|
BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns TRUE iff Base/2 <= digit < Base
|
|
|
|
|
* i.e., if digit's leading bit is 1
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
return (d & (((BigNumDigit)1) << (BN_DIGIT_SIZE - 1)) ? TRUE : FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
Boolean BnnIsDigitOdd (BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
Boolean BnnIsDigitOdd ( d)
|
|
|
|
|
BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns TRUE iff digit is odd
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
return (d & 1 ? TRUE : FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumCmp BnnCompareDigits (BigNumDigit d1, BigNumDigit d2)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumCmp BnnCompareDigits ( d1, d2)
|
|
|
|
|
BigNumDigit d1; BigNumDigit d2;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns BN_GREATER if digit1 > digit2
|
|
|
|
|
* BN_EQUAL if digit1 = digit2
|
|
|
|
|
* BN_LESS if digit1 < digit2
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
return (d1 > d2 ? BN_GT : (d1 == d2 ? BN_EQ : BN_LT));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************** Logical operations ********************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
void BnnComplement (BigNum nn, BigNumLength nl)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
void BnnComplement ( nn, nl)
|
|
|
|
|
BigNum nn; BigNumLength nl;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Performs the computation BBase(N) - N - 1 => N
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
BigNum nnlim;
|
|
|
|
|
|
|
|
|
|
if (nl <= 0)
|
|
|
|
|
return;
|
|
|
|
|
nnlim = nn+nl;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
nn++;
|
|
|
|
|
nn[-1] = ~nn[-1];
|
|
|
|
|
}
|
|
|
|
|
while (nn < nnlim);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
void BnnAndDigits (BigNum n, BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
void BnnAndDigits ( n, d)
|
|
|
|
|
BigNum n; BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns the logical computation n[0] AND d in n[0]
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
*n &= d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
void BnnOrDigits (BigNum n, BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
void BnnOrDigits ( n, d)
|
|
|
|
|
BigNum n; BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns the logical computation n[0] OR d2 in n[0].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
*n |= d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
void BnnXorDigits (BigNum n, BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
void BnnXorDigits ( n, d)
|
|
|
|
|
BigNum n; BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns the logical computation n[0] XOR d in n[0].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
*n ^= d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
/****************** Shift operations *******************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumDigit BnnShiftLeft (BigNum mm, BigNumLength ml, int nbits)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumDigit BnnShiftLeft ( mm, ml, nbits)
|
|
|
|
|
BigNum mm; BigNumLength ml; int nbits;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Shifts M left by "nbits", filling with 0s.
|
|
|
|
|
* Returns the leftmost "nbits" of M in a digit.
|
|
|
|
|
* Assumes 0 <= nbits < BN_DIGIT_SIZE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
register BigNumDigit res = 0, save;
|
|
|
|
|
int rnbits;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nbits != 0)
|
|
|
|
|
{
|
|
|
|
|
rnbits = BN_DIGIT_SIZE - nbits;
|
|
|
|
|
|
|
|
|
|
while (ml-- > 0)
|
|
|
|
|
{
|
|
|
|
|
save = *mm;
|
|
|
|
|
*mm++ = (save << nbits) | res;
|
|
|
|
|
res = save >> rnbits;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumDigit BnnShiftRight (BigNum mm, BigNumLength ml, int nbits)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumDigit BnnShiftRight ( mm, ml, nbits)
|
|
|
|
|
BigNum mm; BigNumLength ml; int nbits;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Shifts M right by "nbits", filling with 0s.
|
|
|
|
|
* Returns the rightmost "nbits" of M in a digit.
|
|
|
|
|
* Assumes 0 <= nbits < BN_DIGIT_SIZE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
register BigNumDigit res = 0, save;
|
|
|
|
|
int lnbits;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nbits != 0)
|
|
|
|
|
{
|
|
|
|
|
mm += ml;
|
|
|
|
|
lnbits = BN_DIGIT_SIZE - nbits;
|
|
|
|
|
|
|
|
|
|
while (ml-- > 0)
|
|
|
|
|
{
|
|
|
|
|
save = *(--mm);
|
|
|
|
|
*mm = (save >> nbits) | res;
|
|
|
|
|
res = save << lnbits;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************* Additions **************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumCarry BnnAddCarry (BigNum nn, BigNumLength nl, BigNumCarry carryin)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumCarry BnnAddCarry ( nn, nl, carryin)
|
|
|
|
|
BigNum nn; BigNumLength nl; BigNumCarry carryin;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Performs the sum N + CarryIn => N.
|
|
|
|
|
* Returns the CarryOut.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
if (carryin == 0)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
if (nl == 0)
|
|
|
|
|
return (1);
|
|
|
|
|
|
|
|
|
|
while (nl > 0 && !(++(*nn++)))
|
|
|
|
|
nl--;
|
|
|
|
|
|
|
|
|
|
return (nl > 0 ? 0 : 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumCarry BnnAdd (BigNum mm, BigNumLength ml, BigNum nn, BigNumLength nl, BigNumCarry carryin)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumCarry BnnAdd ( mm, ml, nn, nl, carryin)
|
|
|
|
|
BigNum mm; BigNumLength ml; BigNum nn; BigNumLength nl; BigNumCarry carryin;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Performs the sum M + N + CarryIn => M.
|
|
|
|
|
* Returns the CarryOut.
|
|
|
|
|
* Assumes Size(M) >= Size(N).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
register BigNumProduct c = carryin;
|
1997-06-13 08:54:18 -07:00
|
|
|
|
register BigNumProduct save;
|
1995-11-06 02:34:19 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ml -= nl;
|
|
|
|
|
|
1997-06-13 08:54:18 -07:00
|
|
|
|
while (nl > 0)
|
|
|
|
|
{
|
|
|
|
|
save = *mm;
|
|
|
|
|
c += save;
|
|
|
|
|
if (c < save)
|
|
|
|
|
{
|
|
|
|
|
*(mm++) = *(nn++);
|
|
|
|
|
c = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
save = *(nn++);
|
|
|
|
|
c += save;
|
|
|
|
|
*(mm++) = c;
|
|
|
|
|
c = (c < save) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
nl--;
|
1995-11-06 02:34:19 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (BnnAddCarry (mm, ml, (BigNumCarry) c));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
/****************** Subtraction *************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumCarry BnnSubtractBorrow (BigNum nn, BigNumLength nl, BigNumCarry carryin)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumCarry BnnSubtractBorrow ( nn, nl, carryin)
|
|
|
|
|
BigNum nn; BigNumLength nl; BigNumCarry carryin;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Performs the difference N + CarryIn - 1 => N.
|
|
|
|
|
* Returns the CarryOut.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
if (carryin == 1)
|
|
|
|
|
return (1);
|
|
|
|
|
if (nl == 0)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
while (nl > 0 && !((*nn++)--))
|
|
|
|
|
nl--;
|
|
|
|
|
|
|
|
|
|
return (nl > 0 ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumCarry BnnSubtract (BigNum mm, BigNumLength ml, BigNum nn, BigNumLength nl, BigNumCarry carryin)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumCarry BnnSubtract ( mm, ml, nn, nl, carryin)
|
|
|
|
|
BigNum mm; BigNumLength ml; BigNum nn; BigNumLength nl; BigNumCarry carryin;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Performs the difference M - N + CarryIn - 1 => M.
|
|
|
|
|
* Returns the CarryOut.
|
|
|
|
|
* Assumes Size(M) >= Size(N).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
register BigNumProduct c = carryin;
|
|
|
|
|
register BigNumDigit invn;
|
1997-06-13 08:54:18 -07:00
|
|
|
|
register BigNumProduct save;
|
1995-11-06 02:34:19 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ml -= nl;
|
|
|
|
|
|
1997-06-13 08:54:18 -07:00
|
|
|
|
while (nl > 0)
|
|
|
|
|
{
|
|
|
|
|
save = *mm;
|
|
|
|
|
invn = *(nn++) ^ -1;
|
|
|
|
|
c += save;
|
|
|
|
|
|
|
|
|
|
if (c < save)
|
|
|
|
|
{
|
|
|
|
|
*(mm++) = invn;
|
|
|
|
|
c = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c += invn;
|
|
|
|
|
*(mm++) = c;
|
|
|
|
|
c = (c < invn) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
nl--;
|
1995-11-06 02:34:19 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (BnnSubtractBorrow (mm, ml, (BigNumCarry) c)); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/* */
|
|
|
|
|
|
|
|
|
|
/***************** Multiplication ************************/
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumCarry BnnMultiplyDigit (BigNum pp, BigNumLength pl, BigNum mm, BigNumLength ml, BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumCarry BnnMultiplyDigit ( pp, pl, mm, ml, d)
|
|
|
|
|
BigNum pp; BigNumLength pl; BigNum mm; BigNumLength ml; BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Performs the product:
|
|
|
|
|
* Q = P + M * d
|
|
|
|
|
* BB = BBase(P)
|
|
|
|
|
* Q mod BB => P
|
|
|
|
|
* Q div BB => CarryOut
|
|
|
|
|
* Returns the CarryOut.
|
|
|
|
|
* Assumes Size(P) >= Size(M) + 1.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
register BigNumProduct c = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (d == 0)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
if (d == 1)
|
|
|
|
|
return (BnnAdd (pp, pl, mm, ml, (BigNumCarry) 0));
|
|
|
|
|
|
|
|
|
|
pl -= ml;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
/* help for stupid compilers--may actually be counter
|
|
|
|
|
productive on pipelined machines with decent register allocation!! */
|
|
|
|
|
#define m_digit X0
|
|
|
|
|
#define X3 Lm
|
|
|
|
|
#define X1 Hm
|
|
|
|
|
register BigNumDigit Lm, Hm, Ld, Hd, X0, X2 /*, X1, X3 */;
|
|
|
|
|
|
|
|
|
|
Ld = d & ((((BigNumDigit)1) << (BN_DIGIT_SIZE / 2)) -1);
|
|
|
|
|
Hd = d >> (BN_DIGIT_SIZE / 2);
|
|
|
|
|
while (ml != 0)
|
|
|
|
|
{
|
|
|
|
|
ml--;
|
|
|
|
|
m_digit = *mm++;
|
|
|
|
|
Lm = m_digit & ((((BigNumDigit)1) << (BN_DIGIT_SIZE / 2)) -1);
|
|
|
|
|
Hm = m_digit >> (BN_DIGIT_SIZE / 2);
|
|
|
|
|
X0 = Ld * Lm;
|
|
|
|
|
X2 = Hd * Lm;
|
|
|
|
|
X3 = Hd * Hm;
|
|
|
|
|
X1 = Ld * Hm;
|
|
|
|
|
|
|
|
|
|
if ((c += X0) < X0) X3++;
|
|
|
|
|
if ((X1 += X2) < X2) X3 += (((BigNumDigit)1)<<(BN_DIGIT_SIZE / 2));
|
|
|
|
|
X3 += (X1 >> (BN_DIGIT_SIZE / 2));
|
|
|
|
|
X1 <<= (BN_DIGIT_SIZE / 2);
|
|
|
|
|
if ((c += X1) < X1) X3++;
|
|
|
|
|
if ((*pp += c) < c) X3++;
|
|
|
|
|
pp++;
|
|
|
|
|
|
|
|
|
|
c = X3;
|
|
|
|
|
#undef m_digit
|
|
|
|
|
#undef X1
|
|
|
|
|
#undef X3
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
X0 = *pp;
|
|
|
|
|
c += X0;
|
|
|
|
|
*(pp++) = c;
|
|
|
|
|
|
|
|
|
|
if (c >= X0)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
pl--;
|
|
|
|
|
while (pl != 0 && !(++(*pp++)))
|
|
|
|
|
pl--;
|
|
|
|
|
|
|
|
|
|
return (pl != 0 ? 0 : 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef mips
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumCarry BnnMultiply2Digit (BigNum pp, BigNumLength pl, BigNum mm, BigNumLength ml, BigNumDigit d0, BigNumDigit d1)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumCarry BnnMultiply2Digit ( pp, pl, mm, ml, d0, d1)
|
|
|
|
|
BigNum pp; BigNumLength pl; BigNum mm; BigNumLength ml; BigNumDigit d0; BigNumDigit d1;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Provided for compatibility with mips assembler implementation.
|
|
|
|
|
* Performs the product:
|
|
|
|
|
* Q = P + M * d0_d1
|
|
|
|
|
* BB = BBase(P)
|
|
|
|
|
* Q mod BB => P
|
|
|
|
|
* Q div BB => CarryOut
|
|
|
|
|
* Returns the CarryOut.
|
|
|
|
|
* Assumes Size(P) >= Size(M) + 1.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
return
|
|
|
|
|
BnnMultiplyDigit (pp, pl, mm, ml, d0)
|
|
|
|
|
+ BnnMultiplyDigit (pp+1, pl-1, mm, ml, d1);
|
|
|
|
|
}
|
|
|
|
|
#endif /* mips */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
/**/
|
|
|
|
|
|
|
|
|
|
/********************** Division *************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* xh:xl -= yh:yl */
|
|
|
|
|
#define SUB(xh,xl,yh,yl) if (yl > xl) {xl -= yl; xh -= yh + 1;}\
|
|
|
|
|
else {xl -= yl; xh -= yh;}
|
|
|
|
|
|
|
|
|
|
#define LOW(x) (x & ((((BigNumDigit)1) << (BN_DIGIT_SIZE / 2)) -1))
|
|
|
|
|
#define HIGH(x) (x >> (BN_DIGIT_SIZE / 2))
|
|
|
|
|
#define L2H(x) (x << (BN_DIGIT_SIZE / 2))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _NO_PROTO
|
|
|
|
|
BigNumDigit BnnDivideDigit (BigNum qq, BigNum nn, BigNumLength nl, BigNumDigit d)
|
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
|
BigNumDigit BnnDivideDigit ( qq, nn, nl, d)
|
|
|
|
|
BigNum qq; BigNum nn; BigNumLength nl; BigNumDigit d;
|
|
|
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
|
|
|
|
/* Performs the quotient: N div d => Q
|
|
|
|
|
* Returns R = N mod d
|
|
|
|
|
* Assumes leading digit of N < d, and d > 0.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
int k;
|
|
|
|
|
BigNumLength orig_nl;
|
|
|
|
|
BigNumDigit rh; /* Two halves of current remainder */
|
|
|
|
|
BigNumDigit rl; /* Correspond to quad above */
|
|
|
|
|
register BigNumDigit qa; /* Current appr. to quotient */
|
|
|
|
|
register BigNumDigit ph, pl; /* product of c and qa */
|
|
|
|
|
BigNumDigit ch, cl, prev_qq;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Normalize divisor */
|
|
|
|
|
k = BnnNumLeadingZeroBitsInDigit (d);
|
|
|
|
|
if (k != 0)
|
|
|
|
|
{
|
|
|
|
|
prev_qq = qq[-1];
|
|
|
|
|
orig_nl = nl;
|
|
|
|
|
d <<= k;
|
|
|
|
|
BnnShiftLeft (nn, nl, k);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nn += nl;
|
|
|
|
|
nl--;
|
|
|
|
|
qq += nl;
|
|
|
|
|
|
|
|
|
|
ch = HIGH (d);
|
|
|
|
|
cl = LOW (d);
|
|
|
|
|
|
|
|
|
|
rl = *(--nn);
|
|
|
|
|
|
|
|
|
|
while (nl != 0)
|
|
|
|
|
{
|
|
|
|
|
nl--;
|
|
|
|
|
rh = rl;
|
|
|
|
|
rl = *(--nn);
|
|
|
|
|
qa = rh / ch; /* appr. quotient */
|
|
|
|
|
|
|
|
|
|
/* Compute ph, pl */
|
|
|
|
|
pl = cl * qa;
|
|
|
|
|
ph = ch * qa;
|
|
|
|
|
ph += HIGH (pl);
|
|
|
|
|
pl = L2H (pl);
|
|
|
|
|
|
|
|
|
|
/* While ph:pl > rh:rl, decrement qa, adjust qh:ql */
|
|
|
|
|
while (ph > rh || ph == rh && pl > rl)
|
|
|
|
|
{
|
|
|
|
|
qa--;
|
|
|
|
|
SUB (ph, pl, ch, L2H (cl));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUB (rh, rl, ph, pl);
|
|
|
|
|
|
|
|
|
|
/* Top half of quotient is correct; save it */
|
|
|
|
|
*(--qq) = L2H (qa);
|
|
|
|
|
qa = (L2H (rh) | HIGH (rl)) / ch;
|
|
|
|
|
|
|
|
|
|
/* Approx low half of q */
|
|
|
|
|
/* Compute ph, pl, again */
|
|
|
|
|
pl = cl * qa;
|
|
|
|
|
ph = ch * qa;
|
|
|
|
|
ph += HIGH (pl);
|
|
|
|
|
pl = LOW (pl) | L2H (LOW (ph));
|
|
|
|
|
ph = HIGH (ph);
|
|
|
|
|
|
|
|
|
|
/* While ph:pl > rh:rl, decrement qa, adjust qh:ql */
|
|
|
|
|
while (ph > rh || ph == rh && pl > rl)
|
|
|
|
|
{
|
|
|
|
|
qa--;
|
|
|
|
|
SUB (ph, pl, 0, d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Subtract ph:pl from rh:rl; we know rh will be 0 */
|
|
|
|
|
rl -= pl;
|
|
|
|
|
*qq |= qa;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Denormalize dividend */
|
|
|
|
|
if (k != 0) {
|
|
|
|
|
if((qq > nn) && (qq < &nn[orig_nl])) {
|
|
|
|
|
/* Overlap between qq and nn. Care of *qq! */
|
|
|
|
|
orig_nl = (qq - nn);
|
|
|
|
|
BnnShiftRight (nn, orig_nl, k);
|
|
|
|
|
nn[orig_nl - 1] = prev_qq;
|
|
|
|
|
} else if(qq == nn) {
|
|
|
|
|
BnnShiftRight(&nn[orig_nl - 1], 1, k);
|
|
|
|
|
} else {
|
|
|
|
|
BnnShiftRight (nn, orig_nl, k);
|
|
|
|
|
} }
|
|
|
|
|
return (rl >> k);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
|
|
|