📄 nn.c
字号:
#include "rsa_incl.h"
#include "nn.h"
/* internal static functions */
static NN_DIGIT subdigitmult PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT, NN_DIGIT *, unsigned int));
static void dmult PROTO_LIST ((NN_DIGIT, NN_DIGIT, NN_DIGIT *, NN_DIGIT *));
static unsigned int NN_DigitBits PROTO_LIST ((NN_DIGIT));
#ifndef USEASM
/* Decodes character string b into a, where character string is ordered
from most to least significant.
Lengths: a[digits], b[len].
Assumes b[i] = 0 for i < len - digits * NN_DIGIT_LEN. (Otherwise most
significant bytes are truncated.)
*/
void NN_Decode (a, digits, b, len)
NN_DIGIT *a;
unsigned char *b;
unsigned int digits, len;
{
NN_DIGIT t;
unsigned int i, u;
int j;
/* @##$ unsigned/signed bug fix added JSAK - Fri 31/05/96 18:09:11 */
for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
t = 0;
for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u += 8)
t |= ((NN_DIGIT)b[j]) << u;
a[i] = t;
}
for (; i < digits; i++)
a[i] = 0;
}
/* Encodes b into character string a, where character string is ordered
from most to least significant.
Lengths: a[len], b[digits].
Assumes NN_Bits (b, digits) <= 8 * len. (Otherwise most significant
digits are truncated.)
*/
void NN_Encode (a, len, b, digits)
NN_DIGIT *b;
unsigned char *a;
unsigned int digits, len;
{
NN_DIGIT t;
unsigned int i, u;
int j;
/* @##$ unsigned/signed bug fix added JSAK - Fri 31/05/96 18:09:11 */
for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
t = b[i];
for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u += 8)
a[j] = (unsigned char)(t >> u);
}
for (; j >= 0; j--)
a[j] = 0;
}
/* Assigns a = 0. */
void NN_AssignZero (a, digits)
NN_DIGIT *a;
unsigned int digits;
{
if(digits) {
do {
*a++ = 0;
}while(--digits);
}
}
#endif
/* Assigns a = 2^b.
Lengths: a[digits].
Requires b < digits * NN_DIGIT_BITS.
*/
void NN_Assign2Exp (a, b, digits)
NN_DIGIT *a;
unsigned int b, digits;
{
NN_AssignZero (a, digits);
if (b >= digits * NN_DIGIT_BITS)
return;
a[b / NN_DIGIT_BITS] = (NN_DIGIT)1 << (b % NN_DIGIT_BITS);
}
/* Computes a = b - c. Returns borrow.
Lengths: a[digits], b[digits], c[digits].
*/
NN_DIGIT NN_Sub (a, b, c, digits)
NN_DIGIT *a, *b, *c;
unsigned int digits;
{
NN_DIGIT temp, borrow = 0;
if(digits)
do {
/* Bug fix 16/10/95 - JSK, code below removed, caused bug with
Sun Compiler SC4.
if((temp = (*b++) - borrow) == MAX_NN_DIGIT)
temp = MAX_NN_DIGIT - *c++;
*/
temp = *b - borrow;
b++;
if(temp == MAX_NN_DIGIT) {
temp = MAX_NN_DIGIT - *c;
c++;
}else { /* Patch to prevent bug for Sun CC */
if((temp -= *c) > (MAX_NN_DIGIT - *c))
borrow = 1;
else
borrow = 0;
c++;
}
*a++ = temp;
}while(--digits);
return(borrow);
}
/* Computes a = b * c.
Lengths: a[2*digits], b[digits], c[digits].
Assumes digits < MAX_NN_DIGITS.
*/
void NN_Mult (a, b, c, digits)
NN_DIGIT *a, *b, *c;
unsigned int digits;
{
NN_DIGIT t[2*MAX_NN_DIGITS];
NN_DIGIT dhigh, dlow, carry;
unsigned int bDigits, cDigits, i, j;
NN_AssignZero (t, 2 * digits);
bDigits = NN_Digits (b, digits);
cDigits = NN_Digits (c, digits);
for (i = 0; i < bDigits; i++) {
carry = 0;
if(*(b+i) != 0) {
for(j = 0; j < cDigits; j++) {
dmult(*(b+i), *(c+j), &dhigh, &dlow);
if((*(t+(i+j)) = *(t+(i+j)) + carry) < carry)
carry = 1;
else
carry = 0;
if((*(t+(i+j)) += dlow) < dlow)
carry++;
carry += dhigh;
}
}
*(t+(i+cDigits)) += carry;
}
NN_Assign(a, t, 2 * digits);
}
/* Computes a = b * 2^c (i.e., shifts left c bits), returning carry.
Requires c < NN_DIGIT_BITS. */
NN_DIGIT NN_LShift (a, b, c, digits)
NN_DIGIT *a, *b;
unsigned int c, digits;
{
NN_DIGIT temp, carry = 0;
unsigned int t;
if(c < NN_DIGIT_BITS)
if(digits) {
t = NN_DIGIT_BITS - c;
do {
temp = *b++;
*a++ = (temp << c) | carry;
carry = c ? (temp >> t) : 0;
}while(--digits);
}
return (carry);
}
/* Computes a = c div 2^c (i.e., shifts right c bits), returning carry.
Requires: c < NN_DIGIT_BITS. */
NN_DIGIT NN_RShift (a, b, c, digits)
NN_DIGIT *a, *b;
unsigned int c, digits;
{
NN_DIGIT temp, carry = 0;
unsigned int t;
if(c < NN_DIGIT_BITS)
if(digits) {
t = NN_DIGIT_BITS - c;
do {
digits--;
temp = *(b+digits);
*(a+digits) = (temp >> c) | carry;
carry = c ? (temp << t) : 0;
}while(digits);
}
return (carry);
}
/* Computes a = c div d and b = c mod d.
Lengths: a[cDigits], b[dDigits], c[cDigits], d[dDigits].
Assumes d > 0, cDigits < 2 * MAX_NN_DIGITS,
dDigits < MAX_NN_DIGITS.
*/
void NN_Div (a, b, c, cDigits, d, dDigits)
NN_DIGIT *a, *b, *c, *d;
unsigned int cDigits, dDigits;
{
NN_DIGIT ai, cc[2*MAX_NN_DIGITS+1], dd[MAX_NN_DIGITS], s;
NN_DIGIT t[2], u, v, *ccptr;
NN_HALF_DIGIT aHigh, aLow, cHigh, cLow;
int i;
unsigned int ddDigits, shift;
ddDigits = NN_Digits (d, dDigits);
if(ddDigits == 0)
return;
shift = NN_DIGIT_BITS - NN_DigitBits (d[ddDigits-1]);
NN_AssignZero (cc, ddDigits);
cc[cDigits] = NN_LShift (cc, c, shift, cDigits);
NN_LShift (dd, d, shift, ddDigits);
s = dd[ddDigits-1];
NN_AssignZero (a, cDigits);
for (i = cDigits-ddDigits; i >= 0; i--) {
if (s == MAX_NN_DIGIT)
ai = cc[i+ddDigits];
else {
ccptr = &cc[i+ddDigits-1];
s++;
cHigh = (NN_HALF_DIGIT)HIGH_HALF (s);
cLow = (NN_HALF_DIGIT)LOW_HALF (s);
*t = *ccptr;
*(t+1) = *(ccptr+1);
if (cHigh == MAX_NN_HALF_DIGIT)
aHigh = (NN_HALF_DIGIT)HIGH_HALF (*(t+1));
else
aHigh = (NN_HALF_DIGIT)(*(t+1) / (cHigh + 1));
u = (NN_DIGIT)aHigh * (NN_DIGIT)cLow;
v = (NN_DIGIT)aHigh * (NN_DIGIT)cHigh;
if ((*t -= TO_HIGH_HALF (u)) > (MAX_NN_DIGIT - TO_HIGH_HALF (u)))
t[1]--;
*(t+1) -= HIGH_HALF (u);
*(t+1) -= v;
while ((*(t+1) > cHigh) ||
((*(t+1) == cHigh) && (*t >= TO_HIGH_HALF (cLow)))) {
if ((*t -= TO_HIGH_HALF (cLow)) > MAX_NN_DIGIT - TO_HIGH_HALF (cLow))
t[1]--;
*(t+1) -= cHigh;
aHigh++;
}
if (cHigh == MAX_NN_HALF_DIGIT)
aLow = (NN_HALF_DIGIT)LOW_HALF (*(t+1));
else
aLow =
(NN_HALF_DIGIT)((TO_HIGH_HALF (*(t+1)) + HIGH_HALF (*t)) / (cHigh + 1));
u = (NN_DIGIT)aLow * (NN_DIGIT)cLow;
v = (NN_DIGIT)aLow * (NN_DIGIT)cHigh;
if ((*t -= u) > (MAX_NN_DIGIT - u))
t[1]--;
if ((*t -= TO_HIGH_HALF (v)) > (MAX_NN_DIGIT - TO_HIGH_HALF (v)))
t[1]--;
*(t+1) -= HIGH_HALF (v);
while ((*(t+1) > 0) || ((*(t+1) == 0) && *t >= s)) {
if ((*t -= s) > (MAX_NN_DIGIT - s))
t[1]--;
aLow++;
}
ai = TO_HIGH_HALF (aHigh) + aLow;
s--;
}
cc[i+ddDigits] -= subdigitmult(&cc[i], &cc[i], ai, dd, ddDigits);
while (cc[i+ddDigits] || (NN_Cmp (&cc[i], dd, ddDigits) >= 0)) {
ai++;
cc[i+ddDigits] -= NN_Sub (&cc[i], &cc[i], dd, ddDigits);
}
a[i] = ai;
}
NN_AssignZero (b, dDigits);
NN_RShift (b, cc, shift, ddDigits);
}
/* Computes a = b mod c.
Lengths: a[cDigits], b[bDigits], c[cDigits].
Assumes c > 0, bDigits < 2 * MAX_NN_DIGITS, cDigits < MAX_NN_DIGITS.
*/
void NN_Mod (a, b, bDigits, c, cDigits)
NN_DIGIT *a, *b, *c;
unsigned int bDigits, cDigits;
{
NN_DIGIT t[2 * MAX_NN_DIGITS];
NN_Div (t, a, b, bDigits, c, cDigits);
}
/* Computes a = b * c mod d.
Lengths: a[digits], b[digits], c[digits], d[digits].
Assumes d > 0, digits < MAX_NN_DIGITS.
*/
void NN_ModMult (a, b, c, d, digits)
NN_DIGIT *a, *b, *c, *d;
unsigned int digits;
{
NN_DIGIT t[2*MAX_NN_DIGITS];
NN_Mult (t, b, c, digits);
NN_Mod (a, t, 2 * digits, d, digits);
}
/* Computes a = b^c mod d.
Lengths: a[dDigits], b[dDigits], c[cDigits], d[dDigits].
Assumes d > 0, cDigits > 0, dDigits < MAX_NN_DIGITS.
*/
void NN_ModExp (a, b, c, cDigits, d, dDigits)
NN_DIGIT *a, *b, *c, *d;
unsigned int cDigits, dDigits;
{
NN_DIGIT bPower[3][MAX_NN_DIGITS], ci, t[MAX_NN_DIGITS];
int i;
unsigned int ciBits, j, s;
/* Store b, b^2 mod d, and b^3 mod d.
*/
NN_Assign (bPower[0], b, dDigits);
NN_ModMult (bPower[1], bPower[0], b, d, dDigits);
NN_ModMult (bPower[2], bPower[1], b, d, dDigits);
NN_ASSIGN_DIGIT (t, 1, dDigits);
cDigits = NN_Digits (c, cDigits);
for (i = cDigits - 1; i >= 0; i--) {
ci = c[i];
ciBits = NN_DIGIT_BITS;
/* Scan past leading zero bits of most significant digit.
*/
if (i == (int)(cDigits - 1)) {
while (! DIGIT_2MSB (ci)) {
ci <<= 2;
ciBits -= 2;
}
}
for (j = 0; j < ciBits; j += 2, ci <<= 2) {
/* Compute t = t^4 * b^s mod d, where s = two MSB's of ci. */
NN_ModMult (t, t, t, d, dDigits);
NN_ModMult (t, t, t, d, dDigits);
if ((s = DIGIT_2MSB (ci)) != 0)
NN_ModMult (t, t, bPower[s-1], d, dDigits);
}
}
NN_Assign (a, t, dDigits);
}
/* Compute a = 1/b mod c, assuming inverse exists.
Lengths: a[digits], b[digits], c[digits].
Assumes gcd (b, c) = 1, digits < MAX_NN_DIGITS.
*/
void NN_ModInv (a, b, c, digits)
NN_DIGIT *a, *b, *c;
unsigned int digits;
{
NN_DIGIT q[MAX_NN_DIGITS], t1[MAX_NN_DIGITS], t3[MAX_NN_DIGITS],
u1[MAX_NN_DIGITS], u3[MAX_NN_DIGITS], v1[MAX_NN_DIGITS],
v3[MAX_NN_DIGITS], w[2*MAX_NN_DIGITS];
int u1Sign;
/* Apply extended Euclidean algorithm, modified to avoid negative
numbers.
*/
NN_ASSIGN_DIGIT (u1, 1, digits);
NN_AssignZero (v1, digits);
NN_Assign (u3, b, digits);
NN_Assign (v3, c, digits);
u1Sign = 1;
while (! NN_Zero (v3, digits)) {
NN_Div (q, t3, u3, digits, v3, digits);
NN_Mult (w, q, v1, digits);
NN_Add (t1, u1, w, digits);
NN_Assign (u1, v1, digits);
NN_Assign (v1, t1, digits);
NN_Assign (u3, v3, digits);
NN_Assign (v3, t3, digits);
u1Sign = -u1Sign;
}
/* Negate result if sign is negative. */
if (u1Sign < 0)
NN_Sub (a, c, u1, digits);
else
NN_Assign (a, u1, digits);
}
/* Computes a = gcd(b, c).
Assumes b > c, digits < MAX_NN_DIGITS.
*/
#define iplus1 ( i==2 ? 0 : i+1 ) /* used by Euclid algorithms */
#define iminus1 ( i==0 ? 2 : i-1 ) /* used by Euclid algorithms */
#define g(i) ( &(t[i][0]) )
void NN_Gcd(a ,b ,c, digits)
NN_DIGIT *a, *b, *c;
unsigned int digits;
{
short i;
NN_DIGIT t[3][MAX_NN_DIGITS];
NN_Assign(g(0), c, digits);
NN_Assign(g(1), b, digits);
i=1;
while(!NN_Zero(g(i),digits)) {
NN_Mod(g(iplus1), g(iminus1), digits, g(i), digits);
i = iplus1;
}
NN_Assign(a , g(iminus1), digits);
}
/* Returns the significant length of a in bits.
Lengths: a[digits]. */
unsigned int NN_Bits (a, digits)
NN_DIGIT *a;
unsigned int digits;
{
if ((digits = NN_Digits (a, digits)) == 0)
return (0);
return ((digits - 1) * NN_DIGIT_BITS + NN_DigitBits (a[digits-1]));
}
#ifndef USEASM
/* Returns sign of a - b. */
int NN_Cmp (a, b, digits)
NN_DIGIT *a, *b;
unsigned int digits;
{
if(digits) {
do {
digits--;
if(*(a+digits) > *(b+digits))
return(1);
if(*(a+digits) < *(b+digits))
return(-1);
}while(digits);
}
return (0);
}
/* Returns nonzero iff a is zero. */
int NN_Zero (a, digits)
NN_DIGIT *a;
unsigned int digits;
{
if(digits) {
do {
if(*a++)
return(0);
}while(--digits);
}
return (1);
}
/* Assigns a = b. */
void NN_Assign (a, b, digits)
NN_DIGIT *a, *b;
unsigned int digits;
{
if(digits) {
do {
*a++ = *b++;
}while(--digits);
}
}
/* Returns the significant length of a in digits. */
unsigned int NN_Digits (a, digits)
NN_DIGIT *a;
unsigned int digits;
{
if(digits) {
digits--;
do {
if(*(a+digits))
break;
}while(digits--);
return(digits + 1);
}
return(digits);
}
/* Computes a = b + c. Returns carry.
Lengths: a[digits], b[digits], c[digits].
*/
NN_DIGIT NN_Add (a, b, c, digits)
NN_DIGIT *a, *b, *c;
unsigned int digits;
{
NN_DIGIT temp, carry = 0;
if(digits)
do {
if((temp = (*b++) + carry) < carry)
temp = *c++;
else { /* Patch to prevent bug for Sun CC */
if((temp += *c) < *c)
carry = 1;
else
carry = 0;
c++;
}
*a++ = temp;
}while(--digits);
return (carry);
}
#endif
static NN_DIGIT subdigitmult(a, b, c, d, digits)
NN_DIGIT *a, *b, c, *d;
unsigned int digits;
{
NN_DIGIT borrow, thigh, tlow;
unsigned int i;
borrow = 0;
if(c != 0) {
for(i = 0; i < digits; i++) {
dmult(c, d[i], &thigh, &tlow);
if((a[i] = b[i] - borrow) > (MAX_NN_DIGIT - borrow))
borrow = 1;
else
borrow = 0;
if((a[i] -= tlow) > (MAX_NN_DIGIT - tlow))
borrow++;
borrow += thigh;
}
}
return (borrow);
}
/* Returns the significant length of a in bits, where a is a digit. */
static unsigned int NN_DigitBits (a)
NN_DIGIT a;
{
unsigned int i;
for (i = 0; i < NN_DIGIT_BITS; i++, a >>= 1)
if (a == 0)
break;
return (i);
}
/* Computes a * b, result stored in high and low. */
static void dmult( a, b, high, low)
NN_DIGIT a, b;
NN_DIGIT *high;
NN_DIGIT *low;
{
NN_HALF_DIGIT al, ah, bl, bh;
NN_DIGIT m1, m2, m, ml, mh, carry = 0;
al = (NN_HALF_DIGIT)LOW_HALF(a);
ah = (NN_HALF_DIGIT)HIGH_HALF(a);
bl = (NN_HALF_DIGIT)LOW_HALF(b);
bh = (NN_HALF_DIGIT)HIGH_HALF(b);
*low = (NN_DIGIT) al*bl;
*high = (NN_DIGIT) ah*bh;
m1 = (NN_DIGIT) al*bh;
m2 = (NN_DIGIT) ah*bl;
m = m1 + m2;
if(m < m1)
carry = 1L << (NN_DIGIT_BITS / 2);
ml = (m & MAX_NN_HALF_DIGIT) << (NN_DIGIT_BITS / 2);
mh = m >> (NN_DIGIT_BITS / 2);
*low += ml;
if(*low < ml)
carry++;
*high += carry + mh;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -