Algorithm Alley by Michael J. Wiener Listing One // To use this code, a BigInt class to handle big integers // is needed along with the following 5 functions. // set up an exponent to point to the top set bit for next_exponent_bit() void init_exponent(BigInt exponent); // get next exponent bit unsigned long next_exponent_bit(); // return TRUE if exponent used up int exponent_finished(); // result = result*result % modulus void modular_square(BigInt &result, BigInt modulus); // result = result*x % modulus void modular_multiply(BigInt &result, BigInt x, BigInt modulus); #define WINDOW 6 #define TABLE_LEN 32 BigInt table[TABLE_LEN]; void fill_table(BigInt message, BigInt modulus) { BigInt sq; long i; sq = message; modular_square(sq, modulus); table[0] = message; for (i = 1; i < TABLE_LEN; i++) { table[i] = table[i - 1]; modular_multiply(table[i], sq, modulus); } } BigInt modular_exponentiation(BigInt message, BigInt exponent, BigInt modulus) { BigInt result; long started, num_pending_bits, num_zero_bits, i; unsigned long pending_bits, bit; fill_table(message, modulus); init_exponent(exponent); if (exponent_finished()) return 1; started = 0; num_pending_bits = 0; pending_bits = 0; do { while (!exponent_finished() && ((bit = next_exponent_bit()) == 0)) modular_square(result, modulus); num_pending_bits = pending_bits = bit; while (!exponent_finished() && (num_pending_bits < WINDOW)) { pending_bits = (pending_bits << 1) + next_exponent_bit(); num_pending_bits++; } if (num_pending_bits > 0) { if (!started) { if (pending_bits & 1) result = table[pending_bits >> 1]; else if (pending_bits & 2) { result = table[pending_bits >> 2]; modular_square(result, modulus); } else { result = table[(pending_bits-1) >> 1]; modular_multiply(result, message, modulus); } started = 1; } else { for (num_zero_bits = 0; !(pending_bits & 1); num_zero_bits++) pending_bits >>= 1; for (i = num_zero_bits; i < num_pending_bits; i++) modular_square(result, modulus); modular_multiply(result, table[pending_bits >> 1], modulus); for (i = 0; i < num_zero_bits; i++) modular_square(result, modulus); } } } while (!exponent_finished()); return result; } Listing Two // To use this code, a BigInt class to handle big integers // is needed along with the following function. // return true if candidate is a highly-probable prime int miller_rabin_test(BigInt candidate); #define SMALL_PRIME_BOUND_DIV2 2048 #define SQRT_BOUND 64 char small_prime_flags[SMALL_PRIME_BOUND_DIV2]; // sieve to find small primes // small_prime_flag[i] == 1 means 2*i+1 is prime void generate_small_primes() { unsigned long i, sieve_val; small_prime_flags[0] = 0; // 1 is not prime for (i = 1; i < SMALL_PRIME_BOUND_DIV2; i++) small_prime_flags[i] = 1; // for each odd number, throw out its multiples for (sieve_val = 3; sieve_val <= SQRT_BOUND; sieve_val += 2) for (i = sieve_val + (sieve_val >> 1); i < SMALL_PRIME_BOUND_DIV2; i += sieve_val) small_prime_flags[i] = 0; } #define SIEVE_LEN 2048 BigInt generate_large_prime(BigInt start) { unsigned long small_prime, i, sp, candidate; char sieve_array[SIEVE_LEN]; generate_small_primes(); start |= 1; // force starting point odd for (;; start += 2*SIEVE_LEN) { for (i = 0; i < SIEVE_LEN; i++) sieve_array[i] = 1; for (sp = 0; sp < SMALL_PRIME_BOUND_DIV2; sp++) if (small_prime_flags[sp]) { small_prime = 2*sp + 1; // next prime to sieve with // magic to find i such that small_prime divides start+2*i i = (small_prime - 1) - ((start - 1) % small_prime); if (i & 1) i += small_prime; i /= 2; // remove multiples of small_prime for (; i < SIEVE_LEN; i += small_prime) sieve_array[i] = 0; } // test primality of remaining candidates for (i = 0; i < SIEVE_LEN; i++) if (sieve_array[i]) { candidate = start + 2*i; if (miller_rabin_test(candidate)) return candidate; } } } 3