[SOUND] In this lecture we're going to begin our treatment of number theory.
Now you might actually be surprised that until this point in the class we
haven't had to rely on or to learn any number theory.
And the reason you might find that surprising is because my impression is
that when people think about cryptography popularly,
the first thing that comes to their mind is exactly the number theory.
That's kind of the quote, un-quote sexy part of cryptography.
However as we've seen in this class so far number theory is not really needed for
a lot of important cryptographic applications.
And in particular, all of practical private key cryptography is based on
things like stream ciphers, block ciphers, and hash functions, that can be
constructed analyzed, and reasoned about, without any mention of any number theory.
And so I think the point here is that number theory, is, of course, going to be
needed, for public key cryptography, but it's not needed for all of cryptography.
There's a lot of interesting things you can do without any number theory at all.
Having said that of course, it turns out that some kind of
number theory does seem to be inherent for any sort of public cryptography.
Now we haven't talked about public-key world cryptography yet.
We won't talk about it until next week, but this is just sort of a primer for
what we're going to need in that setting.
The point of this week is to really cover the basics of number theory, very quickly.
That is, the goal here is not to give a survey of number theory.
It's certainly not to give a comprehensive course on number theory.
But only to present the bare minimum that we need for
the applications that we're going to study.
And for that reason I'm not going to focus particularly on the proofs of a lot of
un-underlying concepts and results unless I
think that the proof sheds some insight on understanding what's going on.
For those that were interested I can recommend several textbooks that can be
used to supplement the material and
in particular a lot of what we cover here with appropriate proofs.
And also some additional details is available in the Cat Lyndel text book.
What we're going to talk about in this lecture is algorithmic number theory.
And this is actually interesting because very often from a mathematical point of
view or from a mathematician's point of view I should say,
they're interested in the existence of numbers with certain properties, or
in proving that some number has a particular property.
But there are very often less interested in the algorithmic efficiency of
determining whether or not some number has a given property.
In our setting, the computer scientist setting where we're
going to ultimately be interested in implementing cryptography.
We do have to also take care to think about the algorithmic
complexity of determining various properties of numbers, and
of computing various interesting things about those numbers.
Now one thing that's important to stress,
is that when we talk about the efficiency of number theoretic operations,
we're always going to be interested in asymptotic complexity, of course.
But the asymptotic complexity will be measured in
terms of the length of the input.
That's always true throughout computer science but
it's important to stress it here because it's very often easy to
get confused between the magnitude of an input and it's length.
And in particular if we have some input integer A then
the magnitude of A is itself.
If A is equal to 1000 then the magnitude of A is 1000.
But the length of that input,
the length of A, is the length of the binary representation of A.
So we have these the length of A.
The binary representation of a, and
the binary representation of an integer is the log of the magnitude of the integer.
Right, the number of bits that you need in order to represent some number,
is the logarithm of that number's magnitude, and conversely,
the magnitude of a number is exponential in its length.
And again it's very easy to get these concepts confused when thinking about
algorithms but we're going to try very carefully to keep them separate.
Now in terms of our study of algorithmic number theory, we're not going to
dwell extensively on different algorithms for different computational problems.
There's a lot of interesting things to be done there, and as I said it is
very important when it comes to efficient implementation of cryptography.
But for our purposes what we only want to do, is to
be able to distinguish between problems that are easy and problems that are hard.
Where for us, easy means that it can be solved in polynomial time.
And hard, at least for
now, is going to mean that it can't be solved in polynomial time.
And so beyond making that kind of a very gross distinction we're not going to
be extremely interested in fine tuning the, algorithms that we give or
that we discuss, or, the problems we consider.
And again, there are several textbooks you can use to supplement the material.
Several references you can use if you're ever implementing cryptography and
want to find out about the most efficient algorithms for some problem.
And note, of course, that bracket A mod N,
has to lie strictly between 0 and N minus 1.
I want to contrast that with the more standard notation that you might be
familiar with, namely that A ie equal to B mod N.
So A being equal to B mod N means exactly that A and
B have the same remainder modulo N.
But, the point is that the notation on the left,
A equals B mod N, is different from the notation a mod N inside the brackets.
Because again, A equals B mod N is expressing something about
the relationship between two integers.
And A mod N inside the brackets refers to a specific integer in the range of
0 to N minus1, which is the remainder of A when divided by N.
Okay. [SOUND] So
let's jump in with a our discussion of algori, algorithmic number
theory by just briefly noting some basic facts about what can be done efficiently.
So if we look at different standard arithmetic operations,
we can see that their's actually can be done efficiently.
So integer addition for
example, can be done efficiently using the standard grade school algorithm.
And if you think about how that works, you'll see that it runs in time,
essentially linear, in the length of the inputs and the same for subtraction.
Multiplication can also be done using a grade school algorithm.
The running time now is quadratic rather than liner.
And I'll mention that better algorithms are known, but, again, for
our purposes, we're just going to be happy with the grade school algorithm because it
does run in polynomial time.
A little bit more difficult to see, but perhaps not very surprising,
is that division with remainder, can be done efficiently.
And this in particular means that we can compute bracket A mod N
efficiently by just performing the divisions and taking the remainder.
For that reason similarly, we can do modular addition,
subtraction, multiplication, and reduction efficiently as well.
So for example, modular multiplication, would just mean that we have two integers.
We want to compute their product, modulus if any N, modulus N if any.
[COUGH] And what we can do there is to simply perform the multiplication over
the integers and then reduce mod N.
And because of those component operations can be
done efficiently we know that the entire computation can be done efficiently.
What about a more complicated operation, in particular, modular exponentiation?
And I focus here on modular exponentiation really for two reasons.
First is that it's an important computation that's going to be
used all the time in cryptography, and second,
because I think it gives a very good illustration of a non trivial algorithm.
That is one where the naive algorithm as we'll see does not run in polynomial time,
but with a little bit of cleverness you can come up with an algorithm that
does run in polynomial time.
Well, let's first consider the size of the result.
So the number of bits that we need to specify the result,
A to the B, is going to be the order of the logarithm of that,
which is the order of the magnitude of B, times the length of A.
And what you can see, here, is just writing down the answer
can require exponential time, exponential in B, that is.
Because the running time, sorry the, the number of bits we need to specify
the answer, is going to be linear in the magnitude of B, rather than length of B.
So we don't really have any hope of computing integer exponentiation in
polynomial time.
Fortunately in cryptography we never need to compute integer exponentiation,
what we do need instead is modular exponentiation, where we're interested in
computing the result of A to the B modulo sum, given modulus N.
And note here we don't run into the problem we had before,
because the size of the answer here is going to have to be at most the size of N,
because the answer has to lie in the interval 0 to N minus 1.
So how do we do it?
Well the first thing to observe is that a strategy that will not work.
If the compute a to the b over the integers.
And then reduce the result mod N.
That won't work because as we just noted, the the length of the intermediate result,
A to the B over the integers cannot even be written down in polynomial space.
So, that's not the approach we're going to want to use.
Let's consider a, maybe a naive algorithm that we would want to use for
computing modular exponentiation.
So here, I'm just writing a simple function that takes three arguments, A, B,
and N and is meant to compute the result, A to the B, mod N.
And we'll assume that B is greater than or equal to 0.
We won't worry about negative exponents, for now.
They can be handled but it's not important for our purposes.
So one natural approach is to just start off with a variable called ans that's
going to hold the answer, initialize that to 1.
And then for I ranging from 1 to B, what we'll do is we'll simply multiply
the current value of the answer by A and then reduce mod N.
So this of course is not valid C code.
This is meant to just be pseudo code.
But what I've indicated here is that we just multiply a into the current answer
and then increment B.
And we're going to avoid the problem that we had on the previous slide.
Of first computing A to the B and then reducing modular N.
Because you'll notice here that we're reducing modular N at every step.
So every time we multiply, we're going to then reduce.
And so the value of Ns at any point during the computation,
is going to be strictly in the range of 0 to N minus 1.
Well it's easiest to think about the problem if we assume for
simplicity that B is a power of 2.
So let's say that B equals 2 to the K for some integer K.
If you kind of unwrap the proceeding algorithm or
maybe just view it in a different way.
You can see that the preceding algorithm roughly corresponds to
performing B multiplications of A.
That is, to computing A times A, times A again, times A again, et cetera, for
A total of 2 to the K minus 1 multiplications.
But a better way to do the computation.
Would be to first square A, right to just compute A times A,
take that result and square it again.
Take that and square that, and keep going until you've done a total of K squarings.
So, that would give a much better algorithm.
Then the former one because we have k
squarings versus two to the k minus one multiplications.
And again, the important thing to note here is that k is order of log of B,
which means that K is order of the length of B.
So what we have here in the second case is an algorithm that's running in
time linear, in the length of B.
So of course this only works when B is a power of two.
But as we'll see in the next slide we can modify this approach even when B
is not a power of 2.
So here is the algorithm.
So again we're going to have an algorithm taking as input A, B, and N.
And we're going to again assume that B is greater than or equal to 0.
What we'll do here is to initialize two variables.
One called X and one called T.
We'll initialize X to a and T to 1.
And then while B is greater than 0 we do the following.
So first of all we check if B is odd.
If B is odd we then compute a within a set T equal to T times X mod N.
And we reduce B by 1.
Then we compute X equals X squared And B is equal to B divided by 2.
So note that in this point the algorithm must be even because if it
were odd at the beginning of the loop then in the previous step we checked that it
was odd and so we subtracted 1.
Now it's a bit difficult, perhaps, to be convinced that this is working.
But you can prove that the algorithm works by looking at, or
by showing that the algorithm satisfies the following invariant.
And the invariant is, that the answer, the correct answer that you're looking for
is always equal to T times X to the B amount N.
And that's certainly true at the beginning of the algorithm when we
initialized the variables because then X is equal to A and T is equal to 1.
And indeed A to the B amount N is exactly the answer we're looking for.
And then you can check throughout the loop.
That if B is even for example,
then what we end up doing is squaring the value of X and reducing B in half.
And so X to the b mod N, or t times x to the b mod N,
is of course equal to T to the X squared, to the B over 2 mod N.
Just algebra.
And similarly, if B is odd, we then shift a factor of X into T, and reduce B by 1.
And you can write down on paper and easily verify that the invariant is satisfied.
At the end of the algorithm, B is equal to 0, and
so the correct answer is given by exactly T.
And T is a value that we return.
What's the running time here?
Well the important thing to note is that in every execution of the inner loop.
The value of B is decreased by at least half.
And that means that the number of iterations of the inner loop is going to
be 0 of log B, which is linear in the length of B.
In each iteration of the inner loop,
we perform some computation that can be done in time polynomial, in, A, B and N.
And so without getting into too much of a fine grained analysis we can see that
the overall running time of the algorithm is indeed polynomial in the length
of it's three inputs.
In the next lecture we'll spend some more time on modular arithmetic.
And we'll also introduce the very important notion of an abstract group
that will allow us to think in a more clean away about various of
the manipulations that we're going to be doing and
that we're going to use for crypt, for cryptography.
See you next time.