size_t bdSetRandTest(T a, size_t ndigits) /* Make a random bigd a of up to ndigits digits -- NB just for testing Return # digits actually set */ { size_t i, n, bits; DIGIT_T mask; assert(a); /* Pick a random size */ n = (size_t)spSimpleRand(1, (DIGIT_T)ndigits); /* Check allocated memory */ bd_resize(a, n); /* Now fill with random digits */ for (i = 0; i < n; i++) a->digits[i] = spSimpleRand(0, MAX_DIGIT); a->ndigits = n; /* Zero out a random number of bits in leading digit about half the time */ bits = (size_t)spSimpleRand(0, 2*BITS_PER_DIGIT); if (bits != 0 && bits < BITS_PER_DIGIT) { mask = HIBITMASK; for (i = 1; i < bits; i++) { mask |= (mask >> 1); } mask = ~mask; a->digits[n-1] &= mask; }
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; }
int main(void) { DIGIT_T x, y, g; DIGIT_T m, e, n, c, z, t; DIGIT_T p, v, u, w, a, q; int res, i, ntries; DIGIT_T primes32[] = { 5, 17, 65, 99 }; DIGIT_T primes16[] = { 15, 17, 39 }; /* Test greatest common divisor (gcd) */ printf("Test spGcd:\n"); /* simple one */ x = 15; y = 27; g = spGcd(x, y); printf("gcd(%" PRIuBIGD ", %" PRIuBIGD ") = %" PRIuBIGD "\n", x, y, g); assert(g == 3); /* contrived using small primes */ x = 53 * 37; y = 53 * 83; g = spGcd(x, y); printf("gcd(%" PRIuBIGD ", %" PRIuBIGD ") = %" PRIuBIGD "\n", x, y, g); assert(g == 53); /* contrived using bigger primes */ x = 0x0345 * 0xfedc; y = 0xfedc * 0x0871; g = spGcd(x, y); printf("gcd(0x%" PRIxBIGD ", 0x%" PRIxBIGD ") = 0x%" PRIxBIGD "\n", x, y, g); assert(g == 0xfedc); /* Known primes: 2^16-15, 2^32-5 */ y = 0x10000 - 15; x = spSimpleRand(1, y); g = spGcd(x, y); printf("gcd(0x%" PRIxBIGD ", 0x%" PRIxBIGD ") = %" PRIxBIGD "\n", x, y, g); assert(g == 1); y = 0xffffffff - 5 + 1; x = spSimpleRand(1, y); g = spGcd(x, y); printf("gcd(0x%" PRIxBIGD ", 0x%" PRIxBIGD ") = %" PRIxBIGD "\n", x, y, g); assert(g == 1); /* Test spModExp */ printf("Test spModExp:\n"); /* Verify that (m^e mod n).(z^e mod n) == (m.z)^e mod n for random m, e, n, z */ /* Generate some random numbers */ n = spSimpleRand(MAX_DIGIT / 2, MAX_DIGIT); m = spSimpleRand(1, n -1); e = spSimpleRand(1, n -1); z = spSimpleRand(1, n -1); /* Compute c = m^e mod n */ spModExp(&c, m, e, n); printf("c=m^e mod n=%" PRIxBIGD "^%" PRIxBIGD " mod %" PRIxBIGD "=%" PRIxBIGD "\n", m, e, n, c); /* Compute x = c.z^e mod n */ printf("z=%" PRIxBIGD "\n", z); spModExp(&t, z, e, n); spModMult(&x, c, t, n); printf("x = c.z^e mod n = %" PRIxBIGD "\n", x); /* Compute y = (m.z)^e mod n */ spModMult(&t, m, z, n); spModExp(&y, t, e, n); printf("y = (m.z)^e mod n = %" PRIxBIGD "\n", x); /* Check they are equal */ assert(x == y); /* Test spModInv */ printf("Test spModInv:\n"); /* Use identity that (vp-1)^-1 mod p = p-1 for prime p and integer v */ /* known prime */ p = 0x10000 - 15; /* small multiplier */ v = spSimpleRand(2, 10); u = v * p - 1; printf("u = vp-1 = %" PRIuBIGD " * %" PRIuBIGD " - 1 = %" PRIuBIGD "\n", v, p, u); /* compute w = u^-1 mod p */ spModInv(&w, u, p); printf("w = u^-1 mod p = %" PRIuBIGD "\n", w); /* check wu mod p == 1 */ spModMult(&c, w, u, p); printf("Check 1 == wu mod p = %" PRIuBIGD "\n", c); assert(c == 1); /* Try mod inversion that should fail */ /* Set u = pq so that gcd(u, p) != 1 */ q = 31; u = p * q; printf("p=%" PRIuBIGD " q=%" PRIuBIGD " pq=%" PRIuBIGD "\n", p, q, u); printf("gcd(pq, p) = %" PRIuBIGD " (i.e. not 1)\n", spGcd(u, p)); res = spModInv(&w, u, p); printf("w = (pq)^-1 mod p returns error %d (expected 1)\n", res); assert(res != 0); /* Test spIsPrime */ printf("Test spIsPrime:\n"); /* Find primes just less than 2^32. Ref: Knuth p408 */ for (n = 0xffffffff, a = 1; a < 100; a++, n--) { if (spIsPrime(n, 50)) { printf("2^32-%" PRIuBIGD " is prime\n", a); assert(is_in_list(a, primes32, NELEMS(primes32))); } } /* And just less than 2^16 */ for (n = 0xffff, a = 1; a < 50; a++, n--) { if (spIsPrime(n, 50)) { printf("2^16-%" PRIuBIGD " is prime\n", a); assert(is_in_list(a, primes16, NELEMS(primes16))); } } /* Generate a random prime < MAX_DIGIT */ n = spSimpleRand(0, MAX_DIGIT); /* make sure odd */ n |= 0x01; /* expect to find a prime approx every lg(n) numbers, so for sure within 100 times that */ ntries = BITS_PER_DIGIT * 100; for (i = 0; i < ntries; i++) { if (spIsPrime(n, 50)) break; n += 2; } printf("Random prime, n = %" PRIuBIGD " (0x%" PRIxBIGD ")\n", n, n); printf("found after %d candidates\n", i+1); if (i >= ntries) printf("Didn't manage to find a prime in %d tries!\n", ntries); else assert(spIsPrime(n, 50)); res = spIsPrime(n, 50); printf("spIsPrime(%" PRIuBIGD ") is %s\n", n, (res ? "TRUE" : "FALSE")); /* Check using (less accurate) Fermat test (these could fail) */ w = 2; spModExp(&x, w, n-1, n); printf("Fermat test: %" PRIxBIGD "^(n-1) mod n = %" PRIxBIGD " (%s)\n", w, x, (x == 1 ? "PASSED" : "FAILED!")); w = 3; spModExp(&x, w, n-1, n); printf("Fermat test: %" PRIxBIGD "^(n-1) mod n = %" PRIxBIGD " (%s)\n", w, x, (x == 1 ? "PASSED" : "FAILED!")); w = 5; spModExp(&x, w, n-1, n); printf("Fermat test: %" PRIxBIGD "^(n-1) mod n = %" PRIxBIGD " (%s)\n", w, x, (x == 1 ? "PASSED" : "FAILED!")); /* Try a known Fermat liar (Carmichael number) */ n = 561; printf("Try n = 561 = 3.11.17 (a `Fermat liar')\n"); w = 5; spModExp(&x, w, n-1, n); printf("Fermat test: %" PRIxBIGD "^(n-1) mod n = %" PRIxBIGD " (%s)\n", w, x, (x == 1 ? "PASSED" : "FAILED!")); res = spIsPrime(n, 50); printf("spIsPrime(%" PRIuBIGD ") is %s\n", n, (res ? "TRUE" : "FALSE")); assert(!res); return 0; }