304 lines
5.5 KiB
C
304 lines
5.5 KiB
C
/* spExtras.c */
|
|
|
|
/***** BEGIN LICENSE BLOCK *****
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright (c) 2001-15 David Ireland, D.I. Management Services Pty Limited
|
|
* <http://www.di-mgt.com.au/bigdigits.html>. All rights reserved.
|
|
*
|
|
***** END LICENSE BLOCK *****/
|
|
/*
|
|
* Last updated:
|
|
* $Date: 2015-10-22 10:23:00 $
|
|
* $Revision: 2.5.0 $
|
|
* $Author: dai $
|
|
*/
|
|
|
|
|
|
#include <assert.h>
|
|
#include "bigdigits.h"
|
|
#include "spExtras.h"
|
|
|
|
int spModMult(DIGIT_T *a, DIGIT_T x, DIGIT_T y, DIGIT_T m)
|
|
{ /* Computes a = (x * y) mod m */
|
|
|
|
/* Calc p[2] = x * y */
|
|
DIGIT_T p[2];
|
|
spMultiply(p, x, y);
|
|
|
|
/* Then modulo */
|
|
*a = mpShortMod(p, m, 2);
|
|
return 0;
|
|
}
|
|
|
|
DIGIT_T spGcd_old(DIGIT_T x, DIGIT_T y)
|
|
{ /* Returns gcd(x, y) */
|
|
|
|
/* Ref: Schneier 2nd ed, p245 */
|
|
|
|
DIGIT_T g;
|
|
|
|
if (x + y == 0)
|
|
return 0; /* Error */
|
|
|
|
g = y;
|
|
while (x > 0)
|
|
{
|
|
g = x;
|
|
x = y % x;
|
|
y = g;
|
|
}
|
|
return g;
|
|
}
|
|
|
|
DIGIT_T spGcd(DIGIT_T a, DIGIT_T b)
|
|
{ /* Returns gcd(a, b) */
|
|
|
|
/* Ref: Cohen, Algorithm 1.3.5 (Binary GCD)
|
|
and Menezes, Algorithm 14.54 */
|
|
|
|
DIGIT_T r, t;
|
|
unsigned int k;
|
|
|
|
/* 1. [Reduce size once] */
|
|
if (a < b)
|
|
{ /* exchange a and b */
|
|
t = a;
|
|
a = b;
|
|
b = t;
|
|
}
|
|
if (0 == b)
|
|
{
|
|
return a;
|
|
}
|
|
r = a % b;
|
|
a = b;
|
|
b = r;
|
|
|
|
if (0 == b)
|
|
{
|
|
return a;
|
|
}
|
|
/* 2. [Compute power of 2] */
|
|
k = 0;
|
|
while (ISEVEN(a) && ISEVEN(b))
|
|
{
|
|
a >>= 1; /* a <-- a/2 */
|
|
b >>= 1; /* b <-- b/2 */
|
|
k++; /* g <-- 2g */
|
|
}
|
|
|
|
while (a != 0)
|
|
{
|
|
while (ISEVEN(a))
|
|
{
|
|
a >>= 1; /* a <-- a/2 until a is odd */
|
|
}
|
|
while (ISEVEN(b))
|
|
{
|
|
b >>= 1; /* b <-- a/2 until b is odd */
|
|
}
|
|
/* t <-- |a-b|/2 */
|
|
if (b > a)
|
|
t = (b - a) >> 1;
|
|
else
|
|
t = (a - b) >> 1;
|
|
/* If a >= b then a = t, otherwise b = t */
|
|
if (a >= b)
|
|
a = t;
|
|
else
|
|
b = t;
|
|
}
|
|
/* Output (2^k.b) */
|
|
return (b << k);
|
|
}
|
|
|
|
/* spIsPrime */
|
|
|
|
static DIGIT_T SMALL_PRIMES[] = { 2, 3, 5, 7, 11, 13, 17, 19 };
|
|
#define N_SMALL_PRIMES sizeof(SMALL_PRIMES)/sizeof(DIGIT_T)
|
|
|
|
int spIsPrime(DIGIT_T w, size_t t)
|
|
{ /* Returns true if w is a probable prime
|
|
Carries out t iterations
|
|
(Use t = 50 for DSS Standard)
|
|
*/
|
|
/* Uses Rabin-Miller Probabilistic Primality Test,
|
|
Ref: FIPS-186-2 Appendix 2.
|
|
Also Schneier 2nd ed p 260 & Knuth Vol 2, p 379
|
|
and ANSI 9.42-2003 Annex B.1.1.
|
|
*/
|
|
|
|
unsigned int i, j;
|
|
DIGIT_T m, a, b, z;
|
|
int failed;
|
|
|
|
/* First check for small primes */
|
|
for (i = 0; i < N_SMALL_PRIMES; i++)
|
|
{
|
|
if (w % SMALL_PRIMES[i] == 0)
|
|
return 0; /* Failed */
|
|
}
|
|
|
|
/* Now do Rabin-Miller */
|
|
/* Step 2. Find a and m where w = 1 + (2^a)m
|
|
m is odd and 2^a is largest power of 2 dividing w - 1 */
|
|
|
|
m = w - 1;
|
|
for (a = 0; ISEVEN(m); a++)
|
|
m >>= 1; /* Divide by 2 until m is odd */
|
|
|
|
/*
|
|
assert((1 << a) * m + 1 == w);
|
|
*/
|
|
|
|
for (i = 0; i < t; i++)
|
|
{
|
|
failed = 1; /* Assume fail unless passed in loop */
|
|
/* Step 3. Generate a random integer 1 < b < w */
|
|
/* [v2.1] changed to 1 < b < w-1 */
|
|
b = spSimpleRand(2, w - 2);
|
|
|
|
/*
|
|
assert(1 < b && b < w-1);
|
|
*/
|
|
|
|
/* Step 4. Set j = 0 and z = b^m mod w */
|
|
j = 0;
|
|
spModExp(&z, b, m, w);
|
|
do
|
|
{
|
|
/* Step 5. If j = 0 and z = 1, or if z = w - 1 */
|
|
if ((j == 0 && z == 1) || (z == w - 1))
|
|
{ /* Passes on this loop - go to Step 9 */
|
|
failed = 0;
|
|
break;
|
|
}
|
|
|
|
/* Step 6. If j > 0 and z = 1 */
|
|
if (j > 0 && z == 1)
|
|
{ /* Fails - go to Step 8 */
|
|
failed = 1;
|
|
break;
|
|
}
|
|
|
|
/* Step 7. j = j + 1. If j < a set z = z^2 mod w */
|
|
j++;
|
|
if (j < a)
|
|
spModMult(&z, z, z, w);
|
|
/* Loop: if j < a go to Step 5 */
|
|
} while (j < a);
|
|
|
|
if (failed)
|
|
{ /* Step 8. Not a prime - stop */
|
|
return 0;
|
|
}
|
|
} /* Step 9. Go to Step 3 until i >= n */
|
|
/* If got here, probably prime => success */
|
|
return 1;
|
|
}
|
|
|
|
/* spModExp */
|
|
|
|
/* Two alternative functions for spModExp */
|
|
|
|
int spModExpK(DIGIT_T *exp, DIGIT_T x,
|
|
DIGIT_T n, DIGIT_T d)
|
|
{ /* Computes exp = x^n mod d */
|
|
/* Ref: Knuth Vol 2 Ch 4.6.3 p 462 Algorithm A
|
|
*/
|
|
DIGIT_T y = 1; /* Step A1. Initialise */
|
|
|
|
while (n > 0)
|
|
{ /* Step A2. Halve N */
|
|
if (n & 0x1) /* If odd */
|
|
spModMult(&y, y, x, d); /* Step A3. Multiply Y by Z */
|
|
|
|
n >>= 1; /* Halve N */
|
|
if (n > 0) /* Step A4. N = 0? Y is answer */
|
|
spModMult(&x, x, x, d); /* Step A5. Square Z */
|
|
}
|
|
|
|
*exp = y;
|
|
return 0;
|
|
}
|
|
|
|
int spModExpB(DIGIT_T *exp, DIGIT_T x,
|
|
DIGIT_T e, DIGIT_T m)
|
|
{ /* Computes exp = x^e mod m */
|
|
/* Binary left-to-right method
|
|
*/
|
|
DIGIT_T mask;
|
|
DIGIT_T y; /* Temp variable */
|
|
|
|
/* Find most significant bit in e */
|
|
for (mask = HIBITMASK; mask > 0; mask >>= 1)
|
|
{
|
|
if (e & mask)
|
|
break;
|
|
}
|
|
|
|
y = x;
|
|
/* For j = k-2 downto 0 step -1 */
|
|
for (mask >>= 1; mask > 0; mask >>= 1)
|
|
{
|
|
spModMult(&y, y, y, m); /* Square */
|
|
if (e & mask)
|
|
spModMult(&y, y, x, m); /* Multiply */
|
|
}
|
|
|
|
*exp = y;
|
|
return 0;
|
|
}
|
|
|
|
int spModInv(DIGIT_T *inv, DIGIT_T u, DIGIT_T v)
|
|
{ /* Computes inv = u^(-1) mod v */
|
|
/* Ref: Knuth Algorithm X Vol 2 p 342
|
|
ignoring u2, v2, t2
|
|
and avoiding negative numbers
|
|
*/
|
|
DIGIT_T u1, u3, v1, v3, t1, t3, q, w;
|
|
int bIterations = 1;
|
|
int result;
|
|
|
|
/* Step X1. Initialise */
|
|
u1 = 1;
|
|
u3 = u;
|
|
v1 = 0;
|
|
v3 = v;
|
|
|
|
while (v3 != 0) /* Step X2. */
|
|
{ /* Step X3. */
|
|
q = u3 / v3; /* Divide and */
|
|
t3 = u3 % v3;
|
|
w = q * v1; /* "Subtract" */
|
|
t1 = u1 + w;
|
|
/* Swap */
|
|
u1 = v1;
|
|
v1 = t1;
|
|
u3 = v3;
|
|
v3 = t3;
|
|
bIterations = -bIterations;
|
|
}
|
|
|
|
if (bIterations < 0)
|
|
*inv = v - u1;
|
|
else
|
|
*inv = u1;
|
|
|
|
/* Make sure u3 = gcd(u,v) == 1 */
|
|
if (u3 != 1)
|
|
{
|
|
result = 1;
|
|
*inv = 0;
|
|
}
|
|
else
|
|
result = 0;
|
|
|
|
return result;
|
|
}
|
|
|