If Alice and Bob want to communicate privately in the presence of an adversary, they must share some secret.
The longer the shared secret is, the more data they can send.
You just learned about PRGs, which can upgrade a short shared secret into a longer one.
This chapter introduces pseudorandom functions, which take the idea of a PRG to an extreme.
Using a PRF, Alice and Bob can expand a short shared secret into an effectively unlimited amount of shared secret data.
6.1.Motivating and defining PRFs
Alice and Bob want to appear (to the adversary) as though they have not just a uniformly sampled string but a huge, shared dictionary data structure filled with uniformly sampled strings.
A dictionary is like an array that is indexed by strings rather than integers.
A dictionary, indexed by n-bit strings and filled with uniformly sampled m-bit strings, would be accessed via the following interface:
for each X∈{0,1}n:
L[X]↞{0,1}m
query(X):
return L[X]
At each distinct position in this data structure, you'll find an independent, uniformly sampled m-bit string.
Of course, that m-bit string never changes after it is chosen, so if you call query twice with the same input, you'll get the same output.
We can even consider values of n like n=λ, which cause the dictionary to be exponentially large.
In that case, the code written above would require exponential time to initialize the dictionary.
On the other hand, a polynomial-time calling program would only be able to access a tiny fraction of its entries.
We can use the following trick to implement an “exponentially large” dictionary, in polynomial time:
Instead of sampling all entries eagerly at the beginning of time, the library can sample them lazily at the moment they are requested:
eager:
for each X∈{0,1}n:
L[X]↞{0,1}m
query(X):
return L[X]
≡
lazy:
// L[⋅] is global, and
// initially undefined everywhere
query(X):
if L[X] undefined:
L[X]↞{0,1}m
return L[X]
This way, if the calling program runs in polynomial time, then the library does too.
We refer to this idiom as a lazy random dictionary.
The goal of a pseudorandom function is to provide the same functionality as a lazy random dictionary.
A pseudorandom function (PRF) takes two inputs:
Just like a PRG, a PRF expects a uniformly chosen seed.
A PRF also expects an input corresponding to the value X in the libraries above, the “index” into the lazy random dictionary.
In our usual approach to security definitions, the victim is responsible for choosing the seed: uniformly, secretly, and in this case, reused in every call to the PRF.
The other PRF input is left completely under the adversary's control.
Definition 6.1.1 (Pseudorandom function)
A function F:{0,1}λ×{0,1}n→{0,1}m is a secure pseudorandom function (PRF) if the following two libraries are indistinguishable:
Lprf-realF
K↞{0,1}λ
prf.query(X):
return F(K,X)
≊
Lprf-randF
prf.query(X):
if L[X] undefined:
L[X]↞{0,1}m
return L[X]
n is called the input length and m is called the output length of the PRF.
Why “function?”
A PRF is a function in the sense that a dictionary is like a function that maps n-bit inputs to m-bit outputs, represented as a simple truth table.
A (lazy) random dictionary is the truth table of a function chosen uniformly from the set of all such functions.
English translation of the PRF security definition
If its key is secret and chosen uniformly, then a PRF's outputs (on distinct inputs) are pseudorandom, no matter how the inputs are chosen.
Key derivation:
One of the most common applications of a PRF is key derivation.
Imagine Alice and Bob share a secret key, K, but want to try out dozens of cryptographic algorithms.
As a general rule, it's not safe to reuse the same key for many different algorithms, since the security definition for each algorithm assumes that its key is used for nothing else.
So instead of using their shared key K for multiple purposes, they treat it as a “master key” and use a PRF to derive any needed application-specific keys.
They can use F(K,xyz) as their key for the XYZ algorithm;
F(K,abc) as their key for the ABC algorithm.
They can use F(K,this) for this and F(K,that) for that, and so on.
The security property of a PRF is that these application-specific keys are indistinguishable from unrelated, independent, uniformly chosen keys.
6.2.How to attack PRFs
Let's gain some intuition about PRFs by seeing attacks against some insecure constructions.
Remember, a PRF is a deterministic function, by design.
Don't try to attack a PRF by calling it twice on the same input and observing that the output repeats.
This is not an attack, because both Lprf-real and Lprf-rand repeat outputs when prf.query is called on a repeated input.
6.2.1.A first example
Claim 6.2.1 (An insecure PRF)
The function F(K,X)=G(K)⊕X is not a secure PRF, even if G is a secure PRG.
In other words, the following two libraries are not indistinguishable:
Lprf-real
K↞{0,1}λ
prf.query(X):
// F(K,X):
return G(K)⊕X
≊
Lprf-rand
prf.query(X):
if L[X] undefined:
L[X]↞{0,1}m
return L[X]
Proof:
The output of F has the form G(K)⊕X, which always contains the same G(K) term.
When part of an xor-expression is repeated several times, we can apply the cancellation strategy.
Suppose an adversary sees two outputs of F, which have the form:
Y1Y2=G(K)⊕X1,=G(K)⊕X2.
Taking the xor of these outputs causes the common term G(K) to cancel, resulting in X1⊕X2.
On the other hand, imagine probing a random dictionary at distinct points X1 and X2.
What is the chance that the results happen to xor to X1⊕X2?
Not likely! Thus, we can conclude that F does not behave like a random dictionary.
We can formalize the attack as follows.
The reasoning from above does not depend on any special properties of X1 or X2, other than the fact that they are distinct.
So we can keep the choice of X1 and X2 arbitrary in the description of the attack.
A
X1,X2:= arbitrary, distinct strings
Y1:=prf.query(X1)
Y2:=prf.query(X2)
return Y1⊕Y2==X1⊕X2
When A is linked to Lprf-real, as we established earlier, Y1⊕Y2=X1⊕X2 is always true.
The adversary outputs true with probability 1 in this case.
When A is linked to Lprf-rand, then since X1 and X2 are distinct, Y1 and Y2 are distinct values in the lazy dictionary, L[X1] and L[X2].
Therefore, Y1 and Y2 are distributed uniformly and independently.
The probability that two uniformly and independently chosen strings have a specific xor (X1⊕X2) is 1/2m.
The difference between these two output probabilities is nonnegligible, so the attack is successful and we conclude that F is not a secure PRF.
6.2.2.A second example
Below is an unsuccessful attempt to use a PRF with shorter input length to build one with a larger input length.
Claim 6.2.2 (Another insecure PRF)
The function H(K1∥K2,X1∥X2)=F(K1,X1)⊕F(K2,X2) is not a secure PRF, even if F is a secure PRF.
In other words, the following two libraries are not indistinguishable:
Lprf-real
K1∥K2↞{0,1}2λ
prf.query(X1∥X2):
// H(K1∥K2,X1∥X2):
return F(K1,X1)⊕F(K2,X2)
≊
Lprf-rand
prf.query(X1∥X2):
if L[X1∥X2] undefined:
L[X1∥X2]↞{0,1}m
return L[X1∥X2]
Proof:
Whenever two inputs to H share a common first half X1, the corresponding outputs of H have a common term F(K1,X1).
We can turn this observation into a proper attack with the cancellation strategy.
Suppose the adversary calls prf.query on two inputs A∥B and A∥B′ where B=B′.
The outputs then have the form:
F(K1,A)⊕F(K2,B);F(K1,A)⊕F(K2,B′).
We can xor the two outputs together to cancel the common term, and obtain the value
It may not be obvious how this value is helpful in an attack.
What's important is that we have obtained a value that depends only onB and B′, and not at all on A.
If we performed the same steps with the same choice of B and B′, but different A′, we would get the same result!
In more detail, suppose the adversary calls prf.query on four inputs: A∥B,A∥B′,A′∥B,A′∥B′, where A=A′ and B=B′.
Call the resulting outputs Y1,Y2,Y3,Y4, then:
Thus, Y1⊕Y2=Y3⊕Y4.
This relationship seems unlikely to happen if Y1,Y2,Y3,Y4 were sampled independently.
We formalize the attack as the following calling program:
A
A,A′:=arbitrary, distinct strings from {0,1}n
B,B′:=arbitrary, distinct strings from {0,1}n
Y1:=prf.query(A∥B)
Y2:=prf.query(A∥B′)
Y3:=prf.query(A′∥B)
Y4:=prf.query(A′∥B′)
return Y1⊕Y2==Y3⊕Y4
When A is linked to Lprf-real, then Y1⊕Y2=Y3⊕Y4, as we reasoned above.
The calling program returns true with probability 1.
Since A=A′ and B=B′, the calling program calls prf.query on four distinct inputs.
So when A is linked to Lprf-rand, each Yi is independently and uniformly distributed.
Rewrite the return condition of A as the equivalent expression Y1⊕Y2⊕Y3==Y4.
Consider the moment when Y1,Y2,Y3 have already been sampled but Y4 has not yet been sampled.
There is only one choice of Y4 (namely, Y1⊕Y2⊕Y3) that causes A to output true.
Since Y4 is uniform, this happens with exactly probability 1/2m.
The difference in output probabilities is nonnegligible, so the attack is successful and the construction is not a secure PRF.
Here's a slightly different way to think about this attack.
Imagine xor'ing all four of these expressions together:
Each term of the form F(⋅,⋅) appears exactly twice overall, meaning that every term will cancel when the values are xor'ed.
Hence, Y1⊕Y2⊕Y3⊕Y4=0m,
which is equivalent to the condition Y1⊕Y2=Y3⊕Y4 used in the attack above.
The Golden Rule:
The previous attack involved finding inputs to H that led to repeated inputs to the underlying PRF F.
This is the first example of a more general principle that applies whenever a PRF is used as a component in a larger construction.
Remember, a PRF produces pseudorandom outputs only when it is called on distinct inputs.
The Golden Rule of PRFs
If a PRF F is being used as a component in a larger construction H, then security usually rests on how well H can ensure distinct inputs to F.
When trying to attack H, choose inputs to H (according to its attack scenario) that will cause F to be called on a repeated input.
Remember, don't try to directly distinguish F's outputs from uniform.
Attack the erroneous way that H is using F!
When trying to prove security of H, you will most likely need to establish that inputs to F do not unexpectedly repeat, except with negligible probability.
In the next sections, we will see examples of how this Golden Rule appears in security proofs.
6.3.An example proof involving PRFs
Now let's see an example of a security proof involving PRFs.
In this case, we show that composing a PRF with itself, using independent keys, results in a secure PRF.
Claim 6.3.1 (Cascading two PRFs)
If F is a secure PRF with input/output length λ, then the following function H, also with input/output length λ, is also a secure PRF:
H(K1∥K2,X):
Y:=F(K1,X)
return F(K2,Y)
In other words,
if
Lprf-realF
K↞{0,1}λ
prf.queryF(X):
return F(K,X)
≊
Lprf-randF
prf.queryF(X):
if L[X] undefined:
L[X]↞{0,1}λ
return L[X]
then
Lprf-realH
K1∥K2↞{0,1}2λ
prf.queryH(X):
// return H(K1∥K2,X)
Y:=F(K1,X)
return F(K2,Y)
≊
Lprf-randH
prf.queryH(X):
if L[X] undefined:
L[X]↞{0,1}λ
return L[X]
.
Since both pairs of libraries are from the Lprf-* family, I have added subscripts to prf.query to disambiguate.
Proof idea:
The goal is to show that H is a secure PRF—that is, when H is called on distinct inputs, its outputs are pseudorandom.
Working backward from our goal, what can we say about the outputs of H?
Outputs of H are computed as direct outputs of F, which is itself a secure PRF.
But remember to be careful, don't forget the Golden Rule!
A PRF's outputs are pseudorandom only when its inputs are distinct.
The PRF inputs in question are the intermediate values labeled Y in the construction.
Indeed, if two different inputs for H produce the same Y, then they will produce identical outputs from H.
So can we say anything about these Y values being distinct (for distinct X)?
It might not be immediately clear whether the Y values can repeat,
but what is hopefully clear is that they are computed as outputs of F(K1,⋅), where F is a secure PRF.
Furthermore, the inputs to this F are the inputs to H, which we are assuming to be distinct.
Thus, the Y values are pseudorandom; they are indistinguishable from uniformly sampled values.
But uniformly sampled values repeat only with negligible probability (if they are sufficiently long, as they are here);
that is precisely the lesson of the birthday bound (section 4.5).
This is the final puzzle piece in the proof.
The formal details of the proof follow below.
Pay close attention to how these main ideas are formalized: (1) Y-values are pseudorandom and, therefore, indistinguishable from uniformly chosen values; (2) uniformly chosen values repeat only with negligible probability; and (3) distinct Y-values lead to pseudorandom outputs of H.
We first separate K1 from K2, since they will be treated separately during the proof. We can also add a dictionary L∗[⋅] to cache past answers of prf.queryH(⋅) so that they are not recomputed twice.
We can apply the PRF security of F in a three-hop maneuver, replacing F(K1,⋅) with a lazy random dictionary, which we name L1[⋅].
We can again apply the PRF security of F, this time replacing all calls to F(K2,⋅) with a lazy random dictionary. This is a new dictionary, which we call L2. The repetitive three-hop maneuver is not shown.
The “if L1[X] undefined” condition is always true, because L1[X] and L∗[X] are always assigned during the same call to prf.queryH(X), and we only reach this if-statement if L∗[X] is undefined. Thus, this if-statement's body can be made unconditional.
Now L1[⋅] is not needed, so it can be eliminated.
Uniformly sampled Y-values are indistinguishable from values sampled without replacement. The three-hop maneuver involving lemma 4.5.7 is omitted.
In this hybrid, the Y-values are guaranteed to not repeat. Thus, the inner if-statement is always taken, and its body can be made unconditional.
Now the overall effect of the if-statement's body is to assign a uniformly sampled value to L∗[X]. The same logic can be written more directly, without Y,Y, or L2[⋅]. The result of these simplification is Lprf-randH, which completes the proof.
Lprf-realH
K1
∥K2↞{0,1}2λ
↞{0,1}λ
K2↞{0,1}λ
Lprf-randH
prf.queryH(X):
if L∗[X] undefined:
if L1[X] undefined:
L1[X]↞{0,1}λ
Y
:=
F(K1,X)
prf.queryF(X)
L1[X]
↞{0,1}λ
∖Y
Y:=Y∪{Y}
if L2[Y] undefined:
L2[Y]↞{0,1}λ
L∗[X]
:=
F(K2,Y)
L2[Y]
↞{0,1}λ
return
F(K2,Y)
L∗[X]
⋄
Lprf-realF
K↞{0,1}λ
prf.queryF(X):
return F(K,X)
Lprf-randF
if L[X] undefined:
L[X]↞{0,1}λ
return L[X]
6.4.Building a PRG from a PRF: The CTR construction
A PRG is in many ways a simpler object than a PRF, because a PRG is “allowed” to generate its entire output as a monolithic string.
A PRF must provide easy access to individual blocks of its output.
(I hesitate to call this random access, since it invokes a different meaning of the word random.)
For theoretical and pedagogical purposes, it is natural to use simpler objects (PRG) to build more complex objects (PRF), as in the previous section.
In practice, however, it's more common to have access to a PRF than to a PRG.
If we want a PRG, we must therefore construct one from a PRF.
It is not hard to do so, since this is the “easy direction”—a simple object built from a more complex one.
Construction 6.4.1 (The CTR construction)
Let F be a PRF with input length n and output length m, and let k be an integer less than 2n.
Define the function G:{0,1}λ→{0,1}km as:
G(S):
for i=0 to k−1:
Xi:=F(S,i)
return X0∥⋯∥Xk−1
When we write F(S,i), we mean that the integer i is written as an n-bit binary integer in the standard way.
The construction is called the CTR construction because it uses a simple counter i as the input to F.
Claim 6.4.2 (Security of the CTR construction)
If F is a secure PRF, then construction 6.4.1 is a secure PRG.
In other words,
if
Lprf-realF
K↞{0,1}λ
prf.query(X):
return F(K,X)
≊
Lprf-randF
prf.query(X):
if L[X] undefined:
L[X]↞{0,1}λ
return L[X]
then
Lprg-realG
prg.sample():
S↞{0,1}λ
// return G(S)
for i=0 to k−1:
Xi:=F(S,i)
return X0∥⋯∥Xk−1
≊
Lprg-randG
prg.sample():
Y↞{0,1}km
return Y
The intuition for the CTR construction is reasonably clear.
If F is a secure PRF and we call it on distinct inputs 0,1,…,k−1, then the resulting outputs F(S,0),F(S,1),…,F(S,k−1) look independently pseudorandom.
However, the proof is not as simple as you might expect because of a mismatch between the PRG and PRF security games:
In the PRG security definition, the libraries model many instances of the PRG.
Each call to prg.sample represents a new instance of the PRG with a freshly sampled seed.
In the PRF security definition, the libraries model a single instance of the PRF,
with a single PRF key that is used for the entire lifetime of the computation.
All calls to prf.query use that same key.
We want to prove that construction 6.4.1 is a secure PRG.
In the Lprg-realG library, the construction G will be invoked many times, each time on a freshly sampled seed S.
Then G proceeds to use S as a PRF key.
When we apply the security of a PRF in a hybrid proof, we can reason only about a single PRF key.
To account for this mismatch, we use a proof with a sequence of many hybrids—one hybrid for each call that the adversary makes to prg.sample.
Hybrid #h acts like Lprg-rand for the first h calls to prg.sample, and acts like Lprg-real for the remaining calls.
Then hybrids h and h+1 are different only in how they respond to the adversary's (h+1)th call to prg.sample.
This difference involves only a single call to G, and, therefore, only a single PRF seed.
We can use the security of the PRF F to argue that hybrids h and h+1 are indistinguishable.
Proof:
We introduce the following library Lh with an integer parameter h:
Lh
prg.sample():
count:=count+1
if count⩽h:
Y↞{0,1}km
return Y
else:
S↞{0,1}λ
// G(S):
for i=0 to k−1:
Xi:=F(S,i)
return X0∥⋯∥Xk−1
The proof is divided into three steps:
Lprg-realG≡L0.
This is easy to see because the else-branch is always taken.
Lprg-randG≡Lq, where q is the number of calls that the calling program makes to prg.sample.
Again, this is easy to see because the if-branch is always taken.
For every h∈{0,…,q−1}, we have Lh≊Lh+1.
These three facts prove the claim because they imply that:
Lprg-realG≡L0≊L1≊⋯≊Lq≡Lprg-randG.
Since the calling program runs in polynomial time, q is a polynomial function of the security parameter.
We can create a separate branch of the if-statement to isolate the adversary's (h+1)th call to prg.sample. This allows us to give a name S∗ to the PRG's seed in this call.
We can apply the PRF-security of F to the (h+1)th call to prg.sample. This is a three-hop maneuver that replaces calls to F(S∗,⋅) with a lazy random dictionary.
The condition “if L[i] undefined” is always true, because i takes on distinct values. We can therefore make the body of the if-statement unconditional:
Now the “if” and “else if” branches behave identically: They uniformly sample a km-bit string. Unifying them into one branch results in Lh+1, which completes the proof.
Lh
Lh+1
prg.sample( ):
count:=count+1
if count⩽
h:
h+1:
Y↞{0,1}km
return Y
else if count==h+1:
S∗↞{0,1}λ
for i=0 to k−1:
if L[i] undefined:
L[i]↞{0,1}λ
Xi
:=
F(S∗,i)
prf.query(i)
L[i]
↞{0,1}λ
return X0∥⋯∥Xk−1
else:
S↞{0,1}λ
for i=0 to k−1:
Xi:=F(S,i)
return X0∥⋯∥Xk−1
⋄
Lprf-real
K↞{0,1}λ
prf.query(X):
return F(K,X)
Lprf-rand
prf.query(X):
if L[X] undefined:
L[X]↞{0,1}λ
return L[X]
6.5.☆ Building a PRF from a PRG: The GGM construction
We can construct a PRF from a PRG by cleverly connecting many PRG invocations together in a binary tree.
Each leaf of the tree corresponds to one of the PRF's outputs.
We can compute one of those outputs—without computing them all—by traversing a path from the root to the leaf.
We can use the bits of the PRF input X to decide whether to go left or right at each step of the traversal.
If X has n bits, then the binary tree has n levels.
Construction 6.5.1 (The GGM construction)
Let G be a length-doubling PRG.
Then the GGM construction—named after its creators Goldreich, Goldwasser, and Micali—is defined as the following function F:{0,1}λ×{0,1}n→{0,1}λ:
F(K,X):
R:=K
for i=1 to n:
S0∥S1:=G(R)
R:=SX[i]
return R
X[i] denotes the ith bit of the string X, numbering the bits from 1 to n.
It's important to keep in mind that the GGM algorithm computes only a single path in this binary tree.
It never computes the entire tree—it would be too large.
The binary tree is only a conceptual tool, for understanding this construction,
just like how an exponentially large random dictionary is a conceptual tool that helps us understand a lazy random dictionary.
Claim 6.5.2 (Security of the GGM construction)
If G is a secure length-doubling PRG, then the GGM construction (construction 6.5.1) is a secure PRF.
In other words,
if
Lprg-realG
prg.sample():
S↞{0,1}λ
return G(S)
≊
Lprg-randG
prg.sample():
Y↞{0,1}2λ
return Y
then
Lprf-realF
K↞{0,1}λ
prf.query(X):
// return F(K,X)
R:=K
for i=1 to n:
S0∥S1:=G(R)
R:=SX[i]
return R
≊
Lprf-randF
prf.query(X):
if L[X] undefined:
L[X]↞{0,1}λ
return L[X]
To build intuition about the proof,
let's just imagine an algorithm that generated the entire GGM binary tree, ignoring the fact that this would take exponential time.
Proving that the values on the leaves are pseudorandom would be similar to previous proofs that involve several PRG instances connected together (claim 5.4.3).
In our binary tree, the root node has uniform input and sends outputs of G to its children.
Such a tree is indistinguishable from a similar one that skips the root level and directly sends truly uniform values to the nodes of the second level.
After this change, the two nodes in the second level now have uniform input, so this modified tree is indistinguishable from one that skips the first two levels and directly sends truly uniform values to the nodes of the third level.
A picture is forming of one hybrid for each level of the tree.
In hybrid #h, the top h levels of the tree are skipped, and inputs to layer h of the tree are sampled uniformly.
This picture gives a good intuition about the necessary sequence of hybrids.
However, all of these hybrids would require exponential time if the tree is sufficiently tall.
We can avoid this, however, by generating these truncated binary trees in a lazy manner, just how Lprf-rand generates a random dictionary in a lazy manner.
All of the difficulty in this proof stems from generating the binary tree lazily.
Proof:
We introduce the following library Lh with an integer parameter h:
Lh
prf.query(X):
P:=first h bits of X
if L[P] undefined:
L[P]↞{0,1}λ
R:=L[P]
for i=h+1 to n:
S0∥S1:=G(R)
R:=SX[i]
return R
Lh implements a binary tree that skips the first h layers and gives uniform inputs to nodes at layer h+1.
However, Lh implements this tree lazily by storing the uniform values at layer h in a lazy random dictionary.
Using this library Lh, we will break the proof into three steps:
Lprf-realF≡L0.
Lprf-randF≡Ln, where n is the input length of the PRF construction.
For every h∈{1,…,n}, we have Lh−1≊Lh.
These three facts prove the claim because they imply that:
Lprf-realF≡L0≊L1≊⋯≊Ln≡Lprf-randF.
First, let's see why L0 is identical to Lprf-realF.
In L0,P is always the empty string ϵ.
The only part of L[⋅] that is ever accessed is the single value L[ϵ].
If we give L[ϵ] a simpler name like “K,” and sample it at the beginning of time instead of the first time it is used, we obtain exactly Lprf-realF:
L0
prf.query(X):
P:= first 0 bits of X
// ⇒P:=ϵ
if L[P] undefined:
L[P]↞{0,1}λ
R:=L[P]
for i=1 to n:
S0∥S1:=G(R)
R:=SX[i]
return R
≡
Lprf-realF
// K=L[ϵ]
K↞{0,1}λ
prf.query(X):
R:=K
for i=1 to n:
S0∥S1:=G(R)
R:=SX[i]
return R
Next, let's see why Ln is identical to Lprf-randF.
In Ln,P equals the entire input X.
The for-loop ranges “from n+1 to n,” so it is never taken.
Removing the for-loop, and replacing every reference to P with a corresponding reference to X, we obtain Lprf-randF:
Ln
prf.query(X):
P:= first n bits of X
// ⇒P:=X
if L[P] undefined:
L[P]↞{0,1}λ
R:=L[P]
// for-loop never taken:
for i=n+1 to n:
S0∥S1:=G(R)
R:=SX[i]
return R
≡
Lprf-randF
prf.query(X):
if L[X] undefined:
L[X]↞{0,1}λ
return L[X]
Finally, we need to show that Lh−1≊Lh, for h∈{1,…,n}.
We do so with the following sequence of hybrids.
Unroll the first iteration of the for-loop (i=h). Since h∈{1,…,n}, the loop indeed has a first iteration. The change has no effect on the calling program.
Replace a redundant variable to clean things up.
We can rename S0 and S1 to L[P∥0] and L[P∥1]. Then we can select the correct one using the entire h-bit prefix P′ of X, not just the h-th individual bit.
The library samples L[P] and then later (perhaps many times) computes G(L[P]). We could instead compute G(L[P]) immediately when L[P] is sampled and store the results for later.
The library assigns L[P] and L[P′] at the same time, for all possible pairs P and P′, so it doesn't matter which of L[P] or L[P′] we use in the if-condition.
Now L[P] is used only as the seed to the PRG, so we can apply the security of the PRG G. The standard three-hop maneuver is not shown.
The library simultaneously samples both L[P′] and its “sibling”: the same string as P′ with last bit flipped. But only one of these values is needed in a single call to prf.query. Since these values are sampled independently, we can sample only the needed one and defer the sibling value until later (if needed). The result is Lh, which completes the proof.
Lh−1
Lh
prf.query(X):
P:=first h−1 bits of X
P′:=first h bits of X
if
L[P] undefined:
L[P′] undefined:
L[P]↞{0,1}λ
L[P∥0]∥∥L[P∥1]
:=G(L[P])
// →
↞{0,1}2λ
L[P′]↞{0,1}λ
R:=L[P]
S0∥S1:=
G(R)
G(L[P])
L[P∥0]∥∥L[P∥1]:=G(L[P])
R:=
SX[h]
L[P′]
for i=
h to n:
h+1 to n:
S0∥S1:=G(R)
R:=SX[i]
return R
6.6.PRFs for long inputs: The CBC-MAC construction
We frequently require a PRF that supports long inputs.
The PRF in construction 6.5 can support inputs of any length, but it uses a PRG as its main primitive.
In practice, PRG implementations are not typically available, but PRFs for short inputs (e.g., λ bits) are.
This section describes a classic way to use a PRF for short inputs to build a PRF for long inputs.
The method is called CBC-MAC, a name that may require some explanation:
CBC refers to cipher-block chaining, which we will see later in the context of encryption (see section 8.5).
MAC refers to message authentication code, which is a different cryptographic primitive closely related to PRFs.
The name CBC-MAC reflects its traditional use as a MAC.
We will eventually discuss MACs in detail in section 9.4.
Be sure not to miss the important caveat about CBC-MAC's security, at the end of this section.
Construction 6.6.1 (CBC-MAC)
Let F be a PRF with input/output length λ.
For any ℓ⩾1, define ℓ-block CBC-MAC to be the following new function Fcbcℓ with input length ℓλ and output length λ:
// each Xi is exactly λ bits:
Fcbcℓ(K,X1∥X2∥⋯∥Xℓ):
Y0:=0λ
for i=1 to ℓ:
Yi:=F(K,Yi−1⊕Xi)
return Yℓ
Claim 6.6.2 (Security of CBC-MAC (for fixed input lengths))
If F is a secure PRF with input/output length λ, then ℓ-block CBC-MAC is also a secure PRF, for any ℓ.
Below we will prove only the special case of ℓ=2:
Fcbc2(K,X1∥X2):
Y1:=F(K,X1)
Y2:=F(K,Y1⊕X2)
return Y2
In other words,
if
Lprf-realF
K↞{0,1}λ
prf.queryF(X):
return F(K,X)
≊
Lprf-randF
prf.queryF(X):
if L[X] undefined:
L[X]↞{0,1}λ
return L[X]
then
Lprf-realcbc-2
K↞{0,1}λ
prf.querycbc-2(X1∥X2):
// return Fcbc2(K,X)
Y1:=F(K,X1)
Y2:=F(K,Y1⊕X2)
return Y2
≊
Lprf-randcbc-2
prf.querycbc-2(X1∥X2):
if L[X1∥X2] undefined:
L[X1∥X2]↞{0,1}λ
return L[X1∥X2]
The final output of (2-block) CBC-MAC is computed as F(K,Y1⊕X2).
Therefore, following the golden rule of PRFs, our goal will be to show that these Y1⊕X2 values do not repeat (except with negligible probability).
We do this using the technique of moving the library's bad-event logic to the end of time.
We can add a cache L[⋅] so that each output is computed only once.
We can replace the calls to PRF F with corresponding lookups in a lazy random dictionary R[⋅]. Note: There is a single dictionary R[⋅], which the library will access on both X1 and Y1⊕X2. The standard three-hop maneuver has been omitted.
This hybrid contains an if-statement “if R[Y1⊕X2] undefined.” Consider another hybrid in which the body of this if-statement is performed unconditionally. The two hybrids behave identically unless/until R[Y1⊕X2] is already defined. So, to show that the hybrids are indistinguishable, we can trigger a bad event in that case and later show that the bad event has negligible probability.
We can swap the assignment order of L[X1∥X2] and R[Y1⊕X2].
We can move L[X1∥X2]↞{0,1}λ earlier. After doing so, it is clear that R[⋅] does not affect the output of prf.query: It is used only to determine whether to trigger the bad event.
Instead of triggering the bad event as prf.query is called, we can do so at the end of time. This will not change the bad event's probability.
Lprf-real
K↞{0,1}λ
Lprf-rand
prf.query(X1∥X2):
if L[X1∥X2] undefined:
L[X1∥X2]↞{0,1}λ
X:=X∪{X1∥X2}
return L[X1∥X2]
end of time:
for X1∥X2∈X:
if R[X1] undefined: R[X1]↞{0,1}λ
Y1:=
F(K,X1)
R[X1]
Y2:=F(K,Y1⊕X2)
if R[Y1⊕X2]
undefined:
defined: bad:=true
R[Y1⊕X2]↞{0,1}λ
// ←
L[X1∥X2]
:=
F(K,Y1⊕X2)
R[Y1⊕X2]
↞{0,1}λ
R[Y1⊕X2]:=L[X1∥X2]
return
Y2
L[X1∥X2]
The final hybrid library is clearly just Lprf-rand, with some extra steps at the end of time that don't affect what the adversary sees; they only determine whether to (internally) trigger a bad event.
Thus, to complete the proof that Lprf-real≊Lprf-rand, we must show that the bad-event probability in this final library is negligible.
Each iteration of the end-of-time loop writes to R[⋅] in at most two positions, and has one opportunity to trigger the bad event, if it finds R[⋅] already defined at a certain position.
Fix a particular choice of X1∥X2 and X1′∥X2′;
what is the probability that a bad event is triggered while processing X1′∥X2′, because of something assigned to R[⋅] while processing X1∥X2?
This event can happen in the following ways:
Case 1:
While processing X1∥X2, the library writes to R[X1].
Later, X1′∥X2′ satisfies
R[X1′]⊕X2′=X1.
Then a bad event is triggered because R[X1] is already defined.
Since R[X1′] is chosen uniformly, and independent of X1,X2,X1′, and X2′, the above condition holds with probability 1/2λ.
Case 2:
While processing X1∥X2, the library computes Y1=R[X1]⊕X2 and writes to R[Y1].
Later, X1′∥X2′ satisfies
R[X1′]⊕X2′=Y1=R[X1]⊕X2.
Then a bad event is triggered because R[Y1] is already defined.
The condition can be rewritten as:
R[X1]⊕R[X1′]=X2⊕X2′.
Case 2a:
If X1=X1′ and X2=X2′, then the two strings are actually equal.
But Case 2 in general requires two different iterations through the end-of-time loop, and therefore different strings.
This subcase can never happen.
Case 2b:
If X1=X1′ and X2=X2′, then the left-hand side of the condition is 0λ and the right-hand side is nonzero.
This subcase can also never happen.
Case 2c:
If X1=X1′, then R[X1] and R[X1′] are chosen uniformly and independently (of each other and of X2,X2′).
The condition is satisfied with probability only 1/2λ.
So the probability that two particular strings interact to trigger a bad event is at most 2/2λ.
If the adversary makes q calls to prf.query, then there are at most q strings processed in the end-of-time loop, and at most q2pairs of such strings.
Then by the union bound, the overall probability of the bad event is:
Pr[bad event]=Pr[∃X1∥X2,X1′∥X2′∈X:X1∥X2 and X1′∥X2′ interfere]⩽q2Pr[specific strings X1∥X2 and X1′∥X2′ interfere]⩽q2(2/2λ).
Since the adversary can make only a polynomial number q of calls to prf.query,
this probability is negligible.
The Golden Rule of PRF proofs:
The proof included a step in which a hybrid library was changed in the following way:
A common idiom in proofs that use PRFs
⋯
if L[X] undefined:
L[X]↞{0,1}λ
⋯
≊
⋯
if L[X] defined: bad:=true
L[X]↞{0,1}λ
⋯
Perhaps you can see the Golden Rule of PRFs reflected in this idiom:
When a PRF appears as a component in a larger system, we often need to argue that PRF inputs do not repeat.
In the example above, X plays the role of an input to the PRF (lazy random dictionary).
The left library implements a lazy random dictionary, correctly accounting for repeated inputs.
The right library has been optimized to behave as if repeated inputs will never happen.
So the two libraries behave differently only in the case that X repeats.
We can trigger a bad event in this case; the libraries are indistinguishable if we can later show that the bad-event probability is negligible.
6.6.1.Fixed input length vs. variable input length
CBC-MAC has fragile security, and claim 6.6.2 must be interpreted carefully.
There is an important distinction to be made between a fixed-input-length PRF and variable-input-length PRF:
When we use CBC-MAC as a fixed-input-length PRF, we choose a single value of ℓ at the time we sample a key.
That key is used only for inputs with exactly ℓ blocks.
To prove security of a fixed-input-length PRF, the value ℓ in the Lprf-* libraries is fixed throughout the entire execution.
All of the adversary's inputs to prf.query must be of that same length.
When we use CBC-MAC as a variable-input-length PRF, we use a single key together with inputs of different lengths.
To prove security of a variable-input-length PRF, we let each input to prf.query in the Lprf-* libraries determine its own value of ℓ.
Within a single execution, the adversary may use inputs of different lengths to prf.query.
Claim 6.6.2 is about the security of CBC-MAC as a fixed-input-length PRF.
For any value of ℓ, the CBC-MAC construction provides a secure PRF for inputs of length exactlyℓλ bits.
However:
Claim 6.6.3 (Insecurity of CBC-MAC)
CBC-MAC is not secure as a variable-input-length PRF.
Proof:
The idea of the attack can be summarized in the following two pictures.
First, the adversary asks for the PRF output for two 2-block inputs X1∥X2 and X3∥X4:
Then, the adversary can “splice” the two computations together to obtain a 4-block input that gives the same PRF output as X3∥X4:
The attack can be formalized by the following calling program:
A
X1,X2,X3,X4:=arbitrary strings of length λ
Y:=prf.query(X1∥X2)
Y′:=prf.query(X3∥X4)
Z:=prf.query(X1∥∥X2∥∥(X3⊕Y)∥∥X4)
return Y′==Z
When the calling program is linked to Lprf-real, it outputs true with probability 1.
When it is linked to Lprf-rand, it outputs true only with probability 1/2λ, since Z is uniform and independent of Y′.
There are simple ways to modify CBC-MAC to obtain a secure variable-input-length PRF;
one is shown in exercise 6.31, and others are discussed later in chapter 11.
However, never forget that plain CBC-MAC is fragile.
If you use plain CBC-MAC as a PRF, you must be absolutely sure that each key is used only for inputs of a single length.
Exercises
We usually consider calling programs that output a single bit, but in this exercise we allow calling programs to output a longer string.
Suppose there is a polynomial-time algorithm A such that, with nonnegligible probability the combined program A⋄Lprf-realF outputs the correct value of K (the private variable in Lprf-real).
Prove that F is not a secure PRF by using A as a subroutine in an attack that can distinguish Lprf-real from Lprf-rand.
Equivalently, if F is a secure PRF, then no efficient algorithm can output K with better than negligible probability when linked to Lprf-real.
Our PRF security definition therefore implies that key-recovery attacks are hard.
Remember: A can often output the “wrong” guess for K.
When you use A as a subroutine, it may not be obvious whether A has produced the correct value K or not.
You'll have to find a way to deal with these cases in your analysis.
Let F be a secure PRF.
Suppose K is sampled uniformly, and strings X and X′ differ in only 1 bit.
How many bits of F(K,X) and F(K,X′) are expected to match, and why?
In claim 6.2.1 the adversary chooses arbitrary but distinct strings X1 and X2.
What would be the adversary's advantage distinguishing the two libraries if instead we used X1=X2?
Our attack against the construction in claim 6.2.2 required four calls to prf.query.
Prove that the construction is secure against adversaries who make at most three calls to prf.query.
Show that the following function is not a secure PRF, even if F is:
H(K,X)=F(K,X)∥∥F(K,F(K,X)).
Show that the following function is not a secure PRF, even if F is:
H(K,X1∥X2)=F(K,X1∥0)∥∥F(K,X2∥1).
Show that the following function is not a secure PRF, even if F is:
H(K,X1∥X2)=F(K,X1)∥∥F(K,X1⊕F(K,X2)).
If the first block of output is removed, then this construction becomes exactly 2-block CBC-MAC.
Show that the following function is not a secure PRF, even if F is:
H(K,X1∥X2)=F(K,X1)∥∥F(K,F(K,X1)⊕F(K,X2)).
Show that the following function is not a secure PRF, even if F is:
H(K,X)=F(K,X)⊕F(K,0n).
Prove that if F is a secure PRF, then the following function H is too:
H(K,X)=F(K,X)⊕X.
Prove that if F is a secure PRF, then the following function H is too:
H(K,X)=F(K,X).
Let F:{0,1}λ×{0,1}n→{0,1}λ be a secure PRF, and
let G:{0,1}λ→{0,1}λ+ℓ be a secure PRG.
Show that the following function H is a secure PRF:
H(K,X)=G(F(K,X)).
Prove that if F is a secure PRF with output length λ, then the following function H is too:
H(K1∥K2,X)=F(K1,X)⊕F(K2,X)⊕K1.
Prove that the following function H is a secure PRF, if eitherF1 or F2 is secure:
H(K1∥K2,X)=F1(K1,X)⊕F2(K2,X).
Your proof should consider two cases:
In the first case, assume that F1 is a secure PRF, but assume nothing about F2.
Then prove the same with the roles of F1 and F2 swapped.
Let F be a secure PRF with input length n+1.
Prove that the following function H is also a secure PRF with input length n:
H(K,X)=F(K,0∥X)∥∥F(K,1∥X).
Let F be a secure PRF with input length n+1.
Prove that the following two libraries are indistinguishable:
K↞{0,1}λ
prf.query0(X):
return F(K,0∥X)
prf.query1(X):
return F(K,1∥X)
≊
prf.query0(X):
if L0[X] undefined:
L0[X]↞{0,1}m
return L0[X]
prf.query1(X):
if L1[X] undefined:
L1[X]↞{0,1}m
return L1[X]
In other words, the two functions F(K,0∥⋅) and F(K,1∥⋅) act like independent random dictionaries, even though they use the same key.
Let F:{0,1}λ×{0,1}λ→{0,1}λ be a secure PRF.
One of the following functions is a secure PRF, and the other is not.
Give an attack and a security proof:
H1(K,X)H2(K,X)={0λ,F(K,X), if X=0λ otherwise={0λ,F(K,X), if K=0λ otherwise.
h
Let F be a secure PRF with input length λ.
Prove that the following function H is a secure PRF:
H(K1∥K2,X)=F(K1,X)⊕F(K1,K2).
Define a bad event in the case that the adversary manages to call H on input X=K2.
Use the end-of-time strategy to analyze the bad-event probability.
h
Let F be a secure PRF with input and output length λ.
Prove that the following function is also a secure PRF:
H(K1∥K2,X):
Y:=F(K1,X)
Z:=F(K1,X⊕K2)
return Y∥Z
Define a bad event in the case that the adversary calls H at inputs X and X′ where X⊕X′=K2.
Use the end-of-time strategy to analyze the bad-event probability.
h
Let F be a secure PRF with input and output length λ.
Prove that the following function is also a secure PRF:
H(K,X)=F(K,F(K,X)).
This construction is similar to claim 6.3.1, except that only one key is used.
In the computation of H(K,X), let Y denote the intermediate internal value Y=F(K,X).
Define a bad event in the case that the adversary calls H at an input that is the internal value of another call to H.
In other words, the adversary calls H at input X, and at some other time (either before or after), calls H at input Y=F(K,X).
Use the end-of-time strategy to analyze the bad-event probability.
Let F be a secure PRF with input and output length λ.
Prove that for any parameter k, the following is a secure PRG:
G(S):
X0:=0λ
for i=1 to k:
Xi:=F(S,Xi−1)
return X1∥⋯∥Xk
Let F be a secure PRF with input and output length λ.
Prove that the following PRF (with input length 2λ) is also a secure PRF:
H(K,X1∥X2)=F(F(K,X1),X2).
Use a hybrid proof with a variable number of hybrids, based on the following approach:
Lh
prf.query(X1∥X2):
if X1∈A and count<h:
count:=count+1
A:=A∪{X1}
if X1∈A:
if L′[X1∥X2] undefined: L′[X1∥X2]↞{0,1}λ
return L′[X1∥X2]
else:
if L[X1] undefined: L[X1]↞{0,1}λ
return F(L[X1],X2)
This library acts like Lprf-rand for the first hdistinct values of X1 that it sees, and acts like Lprf-real for the remaining ones.
Let q be the number of calls to prf.query made by the calling program.
Show that
Lprf-real≡L0≊⋯≊Lh≊Lh+1≊⋯≊Lq≡Lprf-rand.
Consider swapping the role of key and input in the GGM construction.
In other words, we are considering the following function:
F(K,X):
R:=X
for i=1 to n:
S0∥S1:=G(R)
R:=SK[i]
return R
Show that when this construction is instantiated with the secure PRG from exercise 5.17, the result is not a secure PRF.
Show that the GGM PRF (construction 6.5.1) is not secure as a variable-input-length PRF.
h⋆
Describe a construction of a secure variable-input-length PRF (for inputs of any length, not just a multiple of λ bits) from a PRG, based on construction 6.5.1.
Prove that your construction is secure.
Use a binary tree of length-tripling PRGs, where one third of the output is sent to the left child, one third sent to the right child, and one third is used as an output.
⋆
Prove that ℓ-block CBC-MAC is a secure (fixed-input-length) PRF, for any ℓ (not just ℓ=2), if its underlying F is a secure PRF.
The output of CBC-MAC is the last block.
Suppose instead that the output is the xor of all blocks.
Show that the resulting function is not a secure variable-input-length PRF:
// input may be any number of blocks:
H(K,X1∥⋯∥Xℓ):
Y0:=0λ
Z:=0λ
for i=1 to ℓ:
Yi:=F(K,Yi−1⊕Xi)
Z:=Z⊕Yi
return Z
Show that the following variant of CBC-MAC is not secure as a variable-input-length PRF, even if the underlying F is a secure PRF:
// input may be any number of blocks:
H(K,X1∥⋯∥Xℓ):
Y0:=0λ
for i=1 to ℓ:
Yi:=F(K,Yi−1⊕Xi)
// write ℓ as a λ-bit binary integer:
Y∗:=F(K,Yℓ⊕ℓ)
return Y∗
Show that the following variant of CBC-MAC is not secure as a variable-input-length PRF, even if the underlying F is a secure PRF:
// input may be any number of blocks:
H(K,X1∥⋯∥Xℓ):
Y0:=0λ
for i=1 to ℓ:
Yi:=F(K,Yi−1⊕Xi)
// apply F once more, for good measure:
Y∗:=F(K,Yℓ)
return Y∗
Show that the following variant of CBC-MAC is not secure as a variable-input-length PRF, even if the underlying F is a secure PRF:
// input may be any number of blocks:
H(K1∥K2,X1∥⋯∥Xℓ):
Y0:=0λ
for i=1 to ℓ:
Yi:=F(K1,Yi−1⊕Xi)
return Yℓ⊕K2
If K2 is applied before the final call to F, the result actually is a secure variable-input-length PRF (see exercise 11.13).
One natural way to modify CBC-MAC into a variable-input-length PRF is to derive an independent CBC-MAC key for each input length.
More formally, let F be a secure PRP with input/output length λ.
Define the following function H below, which accepts inputs of any number of blocks—that is, the value ℓ is not fixed but part of the input:
// input may be any number of blocks:
H(K,X1∥⋯∥Xℓ):
// write ℓ in binary as a string:
K∗:=F(K,ℓ)
Y0:=0λ
for i=1 to ℓ:
Yi:=F(K∗,Yi−1⊕Xi)
return Yℓ
Prove that H is a secure variable-input-length PRF.
You may use the fact that CBC-MAC is a secure fixed-input-length PRF for any number of blocks ℓ (claim 6.6.2).
Chapter Notes
Pseudorandom functions were first introduced and defined by Goldreich, Goldwasser, and Micali [112].
In that same work they describe how to construct a PRF from a PRG, using the construction that we present in section 6.5.
The security of CBC-MAC was first proven formally by Bellare, Kilian, and Rogaway [20],
with an alternate, shorter proof given later by Bernstein [35].
Plain CBC-MAC is secure as a fixed-input-length PRF.
The more general statement, first proven by Petrank and Rackoff [181], is that plain CBC-MAC is secure when no two inputs are prefixes of each other.
The idea of using a PRF to derive separate CBC-MAC keys for each input length (exercise 6.31) was first proposed by Bellare, Kilian, and Rogaway [20].
The attack in exercise 6.30 is attributed to Bellare in [43].