It (or rather, the software running on it) will use arbitrary-precision ("bignum") arithmetic. The way this works is basically the same way in which you (probably) learned to do arithmetic on paper at school.
The arithmetic taught to us humans at school is base-10 arithmetic — that is, we represent numbers as strings made up of ten different digits, from "0" to "9", where each digit alone represents a different small number below 10, and where placing a digit to the left of another digit multiplies its value by 10.
Assuming you didn't totally sleep through grade school, you probably remember having to memorize the addition and multiplication tables for single-digit numbers: 1 + 1 = 2, 7 + 7 = 14, 6 × 4 = 24, and so on. Those are the basic "atomic" operations for base-10 arithmetic, and once you know how to do them, you can combine them to calculate things with larger numbers.
(You don't have to have the basic operations all perfectly memorized, of course; if you, say, forget what 7 × 6 is, but still remember that 6 × 6 = 36, you can just count six more numbers up from that to end up at 42. And even if you were to forget what e.g. 7 + 7 is, you could, say, count on your fingers to arrive at 14. It just turns out that, for us humans, memorizing those basic single-digit operations — i.e. implementing them with the human equivalent of a look-up table — makes arithmetic a lot faster than working them out from first principles every time. For computers, the tradeoff may be different.)
For example, depending on how math was taught at your school, you may remember writing down an addition problem on paper something like this:
Exercise: 12345 + 67890 = ______
<-- carries
12345 <-- first number
+ 67890 <-- second number
-------
<-- result
and the working it out digit by digit, from right to left. Here, you'd start with 5 + 0 = 5 (with no carry):
0 <-- carries
12345 <-- first number
+ 67890 <-- second number
-------
5 <-- result
and then proceed to 4 + 9 = 13 (i.e. write down 3, carry 1):
10 <-- carries
12345 <-- first number
+ 67890 <-- second number
-------
35 <-- result
and then 1 + 3 + 8 = 4 + 8 = 12 (i.e. write down 2, carry 1), and so on all the way to:
1110 <-- carries
12345 <-- first number
+ 67890 <-- second number
-------
80235 <-- result
You may have also learned similar pencil-and-paper algorithms for other elementary arithmetic operations, like subtraction, multiplication and even long division (which can also be used for modular reduction). The important thing to realize is that all these calculation methods are based on rules for manipulating strings of digits, and on simple arithmetic operations on single digits. As long as you can do the basic single-digit operations, and know the algorithm for combining them together, you can do arithmetic on paper with numbers as large as you want (or need) to!
So how do computers do it, then? They could of course use exactly the same decimal arithmetic rules as we do, but that would be pretty inefficient. A typical CPU already has fast circuitry to add or multiply together any two 32 or 64 bit (and possibly even larger) numbers with a single machine code instruction, so it makes a lot more sense to treat 32 or 64 bit arithmetic as the basic building block.
Thus, a typical computer implementation of bignum arithmetic effectively works with "digits" that are 32 or 64 bit integers, and represents larger numbers as strings of those smaller integers. The algorithms used are very similar to those we'd use for pencil-and-paper calculation, except that instead of base 10, a computer is far more likely to use base 232 or 264.
For example, let's calculate the sum of two random 128-bit numbers (written in hexadecimal for convenience):
Exercise: 3d96d3e9d019665051ecf94e4c0c697b +
a80314053a779df7464ea2feebf771be = ______
A modern CPU might be able to calculate that directly, but let's assume that we only have a 32-bit CPU available. Fortunately, we can break up our numbers into 32-bit chunks and use the same addition algorithm we used before:
<-- carries
3d96d3e9 d0196650 51ecf94e 4c0c697b <-- first number
+ a8031405 3a779df7 464ea2fe ebf771be <-- second number
-------------------------------------
<-- result
So first, we need to calculate 4c0c697b + ebf771be
, which our CPU easily tells us is 13803db39
(i.e. 32-bit result 3803db39
, plus carry 1):
1 <-- carries
3d96d3e9 d0196650 51ecf94e 4c0c697b <-- first number
+ a8031405 3a779df7 464ea2fe ebf771be <-- second number
-------------------------------------
3803db39 <-- result
Next we ask our CPU to calculate 51ecf94e + 464ea2fe
, and to increment the result by one because of the carry, which yields 983b9c4d
(and no carry for the next position):
0 1 <-- carries
3d96d3e9 d0196650 51ecf94e 4c0c697b <-- first number
+ a8031405 3a779df7 464ea2fe ebf771be <-- second number
-------------------------------------
983b9c4d 3803db39 <-- result
We can then proceed with the remaining two 32-bit additions in the same way, getting d0196650 + 3a779df7 = 10a910447
(i.e. 0a910447
and carry 1) and 3d96d3e9 + a8031405 + 1 = e599e7ef
:
0 1 0 1 <-- carries
3d96d3e9 d0196650 51ecf94e 4c0c697b <-- first number
+ a8031405 3a779df7 464ea2fe ebf771be <-- second number
-------------------------------------
e599e7ef 0a910447 983b9c4d 3803db39 <-- result
And there we have our result!
I used addition for this simple example, but similar algorithms can be used for other arithmetic operations, including exponentiation and modular reduction (which one would normally combine into a single modular exponentiation algorithm, since it's much more efficient to do them together rather that to first exponentiate and then reduce).
Also note that the arithmetic algorithms used for cryptography tend to be somewhat specialized, since in crypto it's often important to avoid timing attacks and other types of side-channel attacks by making sure that the algorithm takes the same amount of time to run (and consumes roughly the same amount of power, etc.) regardless of what the numbers being added (or multiplied or raised to a power, etc.) are.
9
? $\endgroup$