Public-key Cryptography from Learning with Errors

The learning with errors problem is one of those “hard problems that you can build cryptography on.” The problem is to solve for constants , given a bunch of approximate equations of the form where each is a “small” error (in the linked example, is either 0 or 1).

In Yan’s post we saw how even a small case of this problem (, ) can be annoyingly tricky. In the real world, you should imagine that and are much bigger – maybe is in the range , and could be anywhere from to , say.

Now let’s see how to turn this into a public-key cryptosystem. We’ll use the same numbers from the “blue set” in Yan’s post. In fact, that “blue set” will be exactly the public key.

Public Key
(1, 0, 1, 7) : 2
(5, 8, 4, 10) : 9
(7, 7, 8, 5) : 3
(5, 1, 10, 6) : 3
(8, 0, 2, 4) : 1
(9, 3, 0, 6) : 9
(0, 6, 1, 6) : 9
(0, 4, 9, 7) : 5
(10, 7, 4, 10) : 10
(5, 5, 10, 6) : 8
(10, 7, 3, 1) : 9
(0, 2, 5, 5) : 6
(9, 10, 2, 1) : 2
(3, 7, 2, 1) : 5
(2, 3, 4, 5) : 3
(2, 1, 6, 9) : 3

The private key is simply the vector .

Private Key
= (10, 8, 10, 10)

How to encrypt ?

Suppose you have a message . (You’ll see in a moment why we insist that is one of these two values.) The ciphertext to encrypt will be a pair , where is a vector, is a scalar, and , where is “small”.

How to do the encryption? If you’re trying to encrypt, you only have access to the public key – that list of pairs above. You want to make up your own , for which you know approximately the value . You could just take one of the vectors from the table, but that wouldn’t be very secure: if I see your ciphertext, I can find that in the table and use it to decrypt .

Instead, you are going to combine several rows of the table to get your vector . Now you have to be careful: when you combine rows of the table, the errors will add up. We’re guaranteed that each row of the table has either or . So if you add at most rows, then the total will be at most . Since is either or (and we’re working modulo ), that’s just enough to determine uniquely.

So, here’s the method. You choose at random 4 (or fewer) rows of the table, and add them up to get a pair with . Then you take (mod of course), and send the message .

An example

Let’s suppose you randomly choose the first 4 rows:

Some rows of public key
(1, 0, 1, 7) : 2
(5, 8, 4, 10) : 9
(7, 7, 8, 5) : 3
(5, 1, 10, 6) : 3

Now you add them up to get the following. | | | - | | (7, 5, 1, 6) : 6 |

Finally, let’s say your message is . So you set , and send the ciphertext: | | | - | | (7, 5, 1, 6) : 1. |

Decryption

Decryption is easy! The decryptor knows where .

Plugging in and , the decryptor computes Plugging in , we see that

Now it’s a simple “rounding” problem. We know that is small and positive, so is either or … a little more. (In fact, it’s one of .) On the other hand, since is 0 or 5, well, had better be 1 or 6… so the only possibility is that , and .

How does this work in general?

In practice, and are often much larger. Maybe is in the hundreds, and could be anywhere from “a little bigger than ” to “almost exponentially large in ,” say . In fact, to do FHE, we’re going to want to take pretty big, so you should imagine that .

For security, the encryption algorithm shouldn’t just take add up 3 or 4 rows of the public key. In fact we want the encryption algorithm to add at least rows – to be safe, maybe make that number a little bigger, say . Of course, for this to work, the public key has to have at least rows.

So in practice, the public key will have rows, and the encryption algorithm will be “select some subset of the rows at random, and add them up”.

Of course, combining rows will have the effect of multiplying the error by – so if the initial was bounded by , then the error in the ciphertext will be at most . But remember that is exponentially large compared to and anyway, so a mere factor of isn’t going to scare us!

Now we could insist that the message is just a single bit – either or . Or we could allow the message to be any multiple of some constant , where is bigger than the error bound (right now that’s ) – which allows you to encode a message space of size rather than just a single bit.

When we do FHE, we’re going to apply many operations to a ciphertext, and each is going to cause the error to grow. We’re going to have to put some effort into keeping the error under control – and then, when the error inevitably grows beyond the permissible bound, we’ll need a special technique (“bootstrapping”) to refresh the ciphertext and start anew.