 |
Modular multiplication (contd.)
We shall start with an example: 2367 times 3214 modulo
6345. Since the multipliers are not powers of small numbers, we
shall start by computing the product explicitly:
and then compute the modulo. We already know that the trouble
with this method is that the product may be too large to handle.
To avoid this we can reduce each of the intermediate results
modulo 6345. The steps are:
2367 * 4 = 9468
2367 * 1 * 101 = 2367 * 101
2367 * 2 * 102 = 4734 * 102
2367 * 3 * 103 = 7101 * 103
At the end of each step we have a number multiplied by a power of
10. So we can reduce the product using the technique we have
learned in the last page. Suppose that we have a C
function modMultByPow10 for this modulo reduction (just
like the modMultByPow2 that we actually wrote). Then we
can write the above steps as
modMultByPow10(2367 * 4,6345)
modMultByPow10(2367 * 1,6345)
modMultByPow10(2367 * 2,6345)
modMultByPow10(2367 * 3,6345)
Now let us write these steps for multiplying a * b (mod m)
where the digits of b are
bk-1,
bk-2,
...
b1,
b0.
For example, when b=3214 we have k=4 and
b3 = 3,
b2 = 2,
b1 = 1,
b0 = 4.
With this notation the steps are
modMultByPow10(a * b0, 0, m)
...
modMultByPow10(a * bk-1, k-1, m)
We can add the results of these steps in a single for-loop in C:
sum = 0;
for(i=0;i<k;i++) {
sum = sum + modMultByPow10(a * bi, i, m);
}
Of course, this is still not a valid C code, since we do not yet
know how to find the i-th digit bi in
C. We shall learn that in a minute, but first notice that there
is a possibility that the sum might become large after some
steps. So it would be a good idea to reduce the sum
modulo m after each step:
sum = 0;
for(i=0;i<k;i++) {
sum = sum + modMultByPow10(a * bi, i, m);
sum = sum % m;
}
The
multiplication a * bi at each step is very easy
since each bi is a single digit, and so between
0 and 9. It becomes even easier if we work in binary, because a
binary digit (or bit) can be either 0 or 1. If bi=0, then we
basically skip the i-th step,
otherwise the product is just a.
sum = 0;
for(i=0;i<k;i++) {
if(bi==1) {
sum = sum + modMultByPow2(a, i, m);
sum = sum % m;
}
}
Notice that now we are using modMultByPow2 instead
of modMultByPow10.
So we have almost finished the C program, except that we still
do not know how to find the bits, bi.
Finding bits in a number
C has a binary operator called bitwise and which is
denoted by the symbol &.
To compute 34 & 7 we first write down the two numbers in
binary:
37 = 100101
7 = 111
Now add extra 0's (if needed) to the left of the smaller number
to make both the representations of the same length:
37 = 100101
7 = 000111
Now perform a logical AND operation on each pair of bit.
37 = 100101
7 = 000111
ans= 000101 = 5
Thus, the answer has a 1 in some bit iff both the operands have
1's in that bit.
<hr>
A calculator for bitwise and
Type two numbers in the two boxes in the lhs, and click "=".
If the 1's in the the operanrds are in disjoint positions then
the result is 0. For example
41 = 101001
6 = 000110
ans= 000000
We shall use the & operator to find the bits in a
number as follows. Let the number be b.
We shall create a another number called a mask that has
exactly a single bit that is 1 (the remaining bits being 0). For
example, the following numbers are all valid 4-bit masks:
1000
0001
0100
Clearly, the masks are the powers of 2. The
mask 2i has a 1 only in the i-th bit.
Thus the i-th bit of b is 1 iff b & 2i
is non-zero (need not be 1, why?). Check this out using the
calculator above.
C allows a handy notation for writing 2i. We just
write 1<<i. This basically means
-
write down a 1, which has a single 1-bit in the rightmost
position.
- then move the 1-bit i places to the left.
Back to modular multiplication
Recall that we had the incomplete program:
sum = 0;
for(i=0;i<k;i++) {
if(bi==1) {
sum = sum + modMultByPow2(a, i, m);
sum = sum % m;
}
}
We did not know how to check bi==1. Now we
shall use & for this:
sum = 0;
for(i=0;i<k;i++) {
if((b & (1<<i)) != 0) {
sum = sum + modMultByPow2(a, i, m);
sum = sum % m;
}
}
The != means "not equal to".
What k should we take? The number k is the number
of bits in b. How do we know that? Well, in C
unsigned int numbers are stored using 32 bits
(usually). So we shall take k=32.
Combining all these we have a function for modular
multiplication (notice how small it is!):
unsigned int modMult(unsigned int a, unsigned int b, unsigned int m) {
unsigned int sum = 0;
for(i=0;i<32;i++) {
if((b & (1<<i)) != 0) {
sum = sum + modMultByPow2(a, i, m);
sum = sum % m;
}
}
return sum;
}
Testing
Here is a complete C program for testing.
#include <stdio.h>
unsigned int modMultByPow2(unsigned int a, unsigned int k, unsigned int m) {
int x, i;
x = a % m;
for(i=0;i<k;i++) {
x = ( x << 1 ) % m;
}
return x;
}
unsigned int modMult(unsigned int a, unsigned int b, unsigned int m) {
unsigned int sum = 0;
for(i=0;i<32;i++) {
if((b & (1<<i)) != 0) {
sum = sum + modMultByPow2(a, i, m);
sum = sum % m;
}
}
return sum;
}
main() {
unsigned int y;
y = modMult(23,54,123);
printf("23 * 54 = %u mod 123.\n",y);
}
Where do we stand?
We have learned how to multiply two numbers modulo a third
number. Since our technique does not require us to explicitly
form the raw product, we can handle really large numbers using
this algorithm.
This algorithm is one of the core algorithms in cryptography. We
shall learn next how to use the modMult function to
perform modulo exponentiation, i.e.,
computing ab (mod m) for
given a,b and m.
|