7

I'm trying to figure out how to implement RSA crypto from scratch (just for the intellectual exercise), and i'm stuck on this point:

For encryption, c = me mod n

Now, e is normally 65537. m and n are 1024-bit integers (eg 128-byte arrays). This is obviously too big for standard methods. How would you implement this?

I've been reading a bit about exponentiation here but it just isn't clicking for me:

Wikipedia-Exponentiation by squaring

This Chapter (see section 14.85)

Thanks.

edit: Also found this - is this more what i should be looking at? Wikipedia- Modular Exponentiation

onkar
  • 4,427
  • 10
  • 52
  • 89
Chris
  • 39,719
  • 45
  • 189
  • 235
  • Hmm... i guess what i'm asking is, i'd just like to know where to start, when implementing it. – Chris Jul 07 '10 at 00:54
  • 5
    Yes, modular exponentiation is what you should look at. The main point is the repeated modular reduction at each step, instead of a single one at the end. – lhf Jul 07 '10 at 00:55
  • Remember, premature optimisation is the root of all evil. Implement a simple algorithm and if it takes more than a minute find the slowest part and optimise that. Using a straightforward exponentiation-by-squaring, as in my answer, will reduce your number of bigint operations from about 130000 to about 35, so there's probably no need to find anything faster. – Artelius Jul 07 '10 at 01:10

4 Answers4

8

Exponentiation by squaring:

Let's take an example. You want to find 1723. Note that 23 is 10111 in binary. Let's try to build it up from left to right.

           // a      exponent in binary

a = 17     //17^1          1

a = a * a  //17^2         10

a = a * a  //17^4        100
a = a * 17 //17^5        101

a = a * a  //17^10      1010
a = a * 17 //17^11      1011

a = a * a  //17^22     10110
a = a * 17 //17^23     10111

When you square, you double the exponent (shift left by 1 bit). When you multiply by m, you add 1 to the exponent.

If you want to reduce modulo n, you can do it after each multiplication (rather than leaving it to the end, which would make the numbers get very large).

65537 is 10000000000000001 in binary which makes all of this pretty easy. It's basically

a = m
repeat 16 times:
    a = a * a
    a = a mod n
a = a * m
a = a mod n

where of course a, n and m are "big integers". a needs to be at least 2048 bits as it can get as large as (n-1)2.

Artelius
  • 48,337
  • 13
  • 89
  • 105
  • Fantastic answer. I'm taking a while to soak it in though, it's taking a while! – Chris Jul 07 '10 at 01:24
  • And, for implementations sake, all i need further is to implement a bignum for the multiplication and modulus steps above? – Chris Jul 07 '10 at 01:51
  • You're almost sure to implement bignum incorrectly. The problem of multiplying big numbers and adding big numbers is almost as tricky as exponentation. Can you not use a language library that handles that automatically? – Stefan Kendall Jul 07 '10 at 02:14
  • Adding big numbers is not terribly hard. Multiplying them is trickier although the Karatsuba Algorithm is not that hard to implement. I suggest starting with a library and then replacing it with your own implementation if you really want to. – Artelius Jul 07 '10 at 02:29
  • This is a learning exercise, so i really want to implement it myself. I'll start by implementing the longhand version, then move on to karatsuba later possibly. I'm sure i'll get it wrong first time, that's never stopped me before! – Chris Jul 07 '10 at 02:49
  • 1
    Ah, okay :). Slow multiplication will kill the exponentation by squaring method, so you'll want to get that right before you tackle the main problem. This exact set of problems was posed to my algorithms class when I attended university, and about 80% of the students slammed into a brick wall with multiplication. – Stefan Kendall Jul 07 '10 at 03:05
  • Boo-yah! Got the multiplication to work pretty much first go :) – Chris Jul 07 '10 at 05:00
  • Just wanted to point out that this solution only computes 1 exponent. For RSA you're going to need a general solution for the other key - see solution below :-) – phkahler Jul 07 '10 at 11:30
  • I know this is a REALLY old answer, but for anyone looking around, multiplication can be done by several methods. The most easiest to understand that i found is the kochanski modular multiplication which is very fast and straightforward to implement. – Chiguireitor Aug 26 '19 at 16:23
3

For an efficient algorithm you need to combine the exponentiation by squaring with repeated application of mod after each step.

For odd e this holds:

me mod n = m ⋅ me-1 mod n

For even e:

me mod n = (me/2 mod n)2 mod n

With m1 = m as a base case this defines a recursive way to do efficient modular exponentiation.

But even with an algorithm like this, because m and n will be very large, you will still need to use a type/library that can handle integers of such sizes.

sth
  • 222,467
  • 53
  • 283
  • 367
3
result = 1
while e>0:
  if (e & 1) != 0:
    result = result * m
    result = result mod n
  m = m*m
  m = m mod n
  e = e>>1
return result

This checks bits in the exponent starting with the least significant bit. Each time we move up a bit it corresponds to doubling the power of m - hence we shift e and square m. The result only gets the power of m multiplied in if the exponent has a 1 bit in that position. All multiplications need to be reduced mod n.

As an example, consider m^13. 11 = 1101 in binary. so this is the same as m^8 * m^4 * m. Notice the powers 8,4,(not 2),1 which is the same as the bits 1101. And then recall that m^8 = (m^4)^2 and m^4 = (m^2)^2.

phkahler
  • 5,687
  • 1
  • 23
  • 31
  • Don't we have to start with the most significant bit? See VII.A here: http://people.csail.mit.edu/rivest/Rsapaper.pdf – Chris Jul 08 '10 at 23:15
  • My mistake, you're using the right-to-left binary method, which is a different algorithm to what i was thinking: http://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method – Chris Jul 08 '10 at 23:40
  • I was going to write it scanning left to right, but at the time it seemed like a hassle. This way you don't need to find the MSB, but you do have to shift the whole exponent each loop. It's a small trade. – phkahler Jul 09 '10 at 01:17
1

If g(x) = x mod 2^k is faster to calculate for your bignum library than f(x) = x mod N for N not divisible by 2, then consider using Montgomery multiplication. When used with modular exponentiation, it avoids having to calculate modulo N at each step, you just need to do the "Montgomeryization" / "un-Montgomeryization" at the beginning and end.

Jason S
  • 184,598
  • 164
  • 608
  • 970