# 5.2: Pseudorandom Generators in Practice

- Page ID
- 7342

You are probably expecting to now see at least one example of a secure PRG. Unfortunately, things are not so simple. We have no examples of secure PRGs! If it were possible to prove that some function \(G\) is a secure \(P R G\), **it would resolve the famous** \(P\) **vs** \(NP\) **problem** - the most famous unsolved problem in computer science (and arguably, all of mathematics).

The next best thing that cryptographic research can offer are **candidate PRGs**, which are conjectured to be secure. The best examples of such PRGs are the ones that have been subjected to significant public scrutiny and resisted all attempts at attacks so far.

In fact, the entire rest of this book is based on cryptography that is only conjectured to be secure. How is this possible, given the book’s stated focus on provable security? As you progress through the book, pay attention to how all of the provable security claims are conditional - if \(\mathrm{X}\) is secure then \(\mathrm{Y}\) is secure. You will be able to trace back through this web of implications and discover that there are only a small number of underlying cryptographic primitives whose security is merely conjectured (PRGs are one example of such a primitive). Everything else builds on these primitives in a provably secure way.

With that disclaimer out of the way, surely now you can be shown an example of a conjectured secure \(P R G\), right? There are indeed some conjectured PRGs that are simple enough to show you at this point, but you won’t find them in the book. The problem is that none of these PRG candidates are really used in practice. When you really need a PRG in practice, you would actually use a PRG that is built from something called a block cipher (which we won’t see until Chapter 6). A block cipher is conceptually more complicated than a PRG, and can even be built from a PRG (in principle). That explains why this book starts with PRGs. In practice, a block cipher is just a more useful object, so that is what you would find easily available (even implemented with specialized CPU instructions in most CPUs). When we introduce block ciphers (and pseudorandom functions), we will discuss how they can be used to construct PRGs.

## How NOT to Build a PRG

We can appreciate the challenges involved in building a PRG "from scratch" by first looking at an obvious idea for a PRG and understanding why it’s insecure.

Let’s focus on the case of a length-doubling PRG. It should take in \(\lambda\) bits and output \(2 \lambda\) bits. The output should look random when the input is sampled uniformly. A natural idea is for the candidate PRG to simply repeat the input twice. After all, if the input \(s\) is random, then \(s \| s\) is also random, too, right?

To understand why this PRG is insecure, first let me ask you whether the following strings look like they were sampled uniformly from \(\{0,1\}^{8}\) :

\(11011101,01010101,01110111,01000100, \cdots\)

Do you see any patterns? Every string has its first half equal to its second half. That is a conspicuous pattern because it is relatively rare for a uniformly chosen string to have this property.

Of course, this is exactly what is wrong with this simplistic PRG G defined above. Every output of \(G\) has equal first/second halves. But it is rare for uniformly sampled strings to have this property. We can formalize this observation as an attack against the PRG-security of \(G\) :

The first line means to obtain the result of QUERY and set its first half to be the string \(x\) and its second half to be \(y\). This calling program simply checks whether the output of QUERY has equal halves.

To complete the attack, we must show that this calling program has non-negligible bias distinguishing the \(\mathcal{L}_{\text {prg- } \star \text { libraries. }}\)

- When linked to \(\mathcal{L}_{\text {prg-real, }}\) the calling program receives outputs of \(G\), which always have matching first/second halves. So \(\operatorname{Pr}\left[\mathcal{A} \diamond \mathcal{L}_{\mathrm{prg} \text {-real }}^{G} \Rightarrow 1\right]=1\). Below we have filled in \(\mathcal{L}_{\text {prg-real }}\) with the details of our \(G\) algorithm:
- When linked to \(\mathcal{L}_{\mathrm{prg}-\mathrm{rand}}\), the calling program receives uniform samples from \(\{0,1\}^{2 \lambda}\). \(\mathcal{A}\) outputs 1 whenever we sample a string from \(\{0,1\}^{2 \lambda}\) with equal first/second halves. What exactly is the probability of this happening? There are several ways to see that the probability is \(1 / 2^{\lambda}\) (this is like asking the probability of rolling doubles with two dice, but each die has \(2^{\lambda}\) sides instead of 6). Therefore, \(\operatorname{Pr}\left[\mathcal{A} \diamond \mathcal{L}_{\mathrm{prg} \text {-rand }}^{G} \Rightarrow 1\right]=1 / 2^{\lambda}\).

The advantage of this adversary is \(1-1 / 2^{\lambda}\) which is certainly non-negligible - it does not even approach 0 as \(\lambda\) grows. This shows that \(G\) is not a secure PRG.

This example illustrates how randomness/pseudorandomness is a property of the entire process, not of individual strings. If you take a string of 1 s and concatenate it with another string of 1s, you get a long string of 1s. "Containing only 1s" is a property of individual strings. If you take a "random string" and concatenate it with another "random string" you might not get a "random long string." Being random is not a property of an individual string, but of the entire process that generates it.

Outputs from this \(G\) have equal first/second halves, which is an obvious pattern. The challenge of desiging a secure PRG is that its outputs must have no discernable pattern! Any pattern will lead to an attack similar to the one shown above.

## Related Concept: Random Number Generation

The security of a PRG requires the seed to be chosen uniformly. In practice, the seed has to come from somewhere. Generally a source of "randomness" is provided by the hardware or operating system, and the process that generates these random bits is (confusingly) called a **random number generator** (RNG).

In this course we won’t cover low-level random number generation, but merely point out what makes it different than the PRGs that we study:

- The job of a PRG is to take a small amount of "ideal" (in other words, uniform) randomness and extend it.
- By contrast, an RNG usually takes many inputs over time and maintains an internal state. These inputs are often from physical/hardware sources. While these inputs are "noisy" in some sense, it is hard to imagine that they would be statistically uniform. So the job of the RNG is to "refine" (sometimes many) sources of noisy data into uniform outputs.

\({ }^{1}\) For one list of such tests, see http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev 1a.pdf.