Mathematics of Large Exponents : Algorithms for Tackling extremely large intermediate results

Mathematics of Large Exponents : Algorithms for Tackling extremely large intermediate results

Consider a 256 bit capable key.

The Modulus (n) must be greater than 2256.

This number represented in decimal is very large. 90 odd decimal digits !

2^256 == 115792089237316195423570985008687907853269984665640564039457584007913129639936

Compared to the numbers generated by raising large numbers to large exponents, though, 2256 seems quite trivial.

The RSA encryption algorithms are based on taking large numbers to the power of a key value, and then applying the modulus of that result with a large pre-calculated value (n) based on a prime number multiplication.

encoded = cd%n

For instance 2256 to the power of a 6 digit key (say 5,000,000) produces a number of approximately 385,318,394 digits !

Obviously, such large intermediate results are impractical. For the purpose of this tool, intermediate values with up to 100,000 digits are shown (and can be dealt with directly using the unix bc utility ).

An effective way to break this problem down is to use results from residue theory . From residue theory we can state that where d is even:

cd%n == ((c^2%n)d/2)%n

If d is an integer power of 2, (i.e. d == 2n where n is a positive integer) this can be extended to a recursive algorithm.

Recursive algorithm for simplifying equations of the form cd%n where d is an integer power of 2


calc_residue ( bigint c, bigint d, bigint n ) {
  if ( d == 1 ) return ( c ^ d % n );
  return calc_residue ( c^2, d/2, n ) % n; # recursion
}

This is all very well, and solves the large exponentiation problem. But most exponents used in RSA are not integer powers of 2 ! Some way of breaking the exponent up and handling each integer power of 2 part is required.

Breaking down exponent to Powers of 2 As pseudo code

Consider for instance the number 323 can be represented by

323 == 28 + 26 + 21 + 20

Thus 'c' to the power of 323, could be written as (where ^ means to the power of, as in c and bc scripts)

c(2^8+2^6+2^1+2^0)


or written as

c2^8*c2^6*c2^1*c2^0

In this form it is easy to see that any exponent can be broken down into powers of two for processing by the calc_residues algorithm.

The following pseudo code takes the variable d, and breaks it down into into its integer power of 2 parts.



break_down_into_powers_of_two ( bigint d ) {
 

  integer i = 0;
  
  # find biggest power of 2 left in exponentiation
  # 
  while(d >= (2^i)) { i = i+1; }

  # subtract highest power of 2 possible from d
  #
  d = (d - (2^(i-1)));
 
  PRINT (2^(i-1));

  if (d>0) { 
        # d is greater than 0 so we need to break this down further
        #       
        break_down_into_powers_of_two(d); # recurse with new d value
        return (2^(i-1));
  }
  if (d == 0) {
        # d is 0, we have found the last power of 2 required
        #
        return (2^(i-1);
  }
}

In order to implement code that can process any d exponent in a c^d%n equation in a bc script the problem has been divided into two distinct but linked stages:

Script to calculate cd%n equations without incredibly large intermediate results

Integrating these together produces the following bc program.
# bc program. Call with -q parameter
# R.P. Clark 10APR2004

# recursive routine to calculate c^d%n
# by breaking it down. Works only where
# d is a power of 2.
#
define x ( c,d,n) {
  if ( d == 1 ) return (c^d%n);
  return x(c^2,d/2,n)%n;
}

r = 1;

# recursive routine to break d into powers of 2
# and then to collect multiply the results
# of the 2^n exponents.
#
define t(c,d,n) {
  auto i
  i = 0;
  
  # find biggest power of 2 left in exponentiation
  # 
  while(d >= (2^i)) { i = i+1; }

  # subtract from exponent
  #
  d = (d - (2^(i-1)));
 
  
  if (d>0) { 
        r=(r*x(c,2^(i-1),n))%n;  # calculate this large exponentiation
        t(c,d,n);                # recursion with new d value
        return (2^(i-1));
  }
  if (d == 0) {
         r = (r*x(c,2^(i-1),n))%n; # last one
         return (2^(i-1));
  }
}

Thus the function t(c,d,n), will break down the exponent, and pass it on as powers of 2, to calculate the residues using the 'x' function. Thus very large exponentiation and mod equations,will be calculated without having to handle incredibly large intermediate results.

Some results, of timings for the equation 21255511266511%999999 run on a 1 Ghz Celeron laptop (Redhat 8.0 : bc version 1.06). Note that larger numbers than this in the exponent are rejected by bc.

To see how large 21255511266511 is, a text file containing it is included here .

[robin@localhost bc]$ date; bc < calc_big_expon.bc | tail -1; date
Sun Apr 11 17:21:10 BST 2004
407926
Sun Apr 11 17:26:37 BST 2004
[robin@localhost bc]$ date ; echo "21255511^266511%999999" | bc ; date
Sun Apr 11 17:36:13 BST 2004
407926
Sun Apr 11 17:43:29 BST 2004
[robin@localhost bc]$ bc -v
bc 1.06
Thus the recursive algorithm is faster, and large exponents are not rejected.