OPRF (oblivious pseudorandom function)¶
The client learns F(k, x) for a key only the server holds, and the server learns nothing about x. A small two-party trick under OPAQUE, Privacy Pass and password breach checks.
Status and standards: see Advanced primitives in the main table.
What it is¶
A pseudorandom function F(k, x) looks random to anyone without the key
k. In an oblivious PRF two parties compute it together: the server holds
k, the client holds x, and only the client gets the output. The server
sees neither x nor the output, and the client learns nothing about k
beyond the outputs it asked for. Freedman, Ishai, Pinkas and Reingold
defined OPRFs at TCC 2005, for keyword search. The version in use is
Jarecki, Kiayias and Krawczyk's 2HashDH (ASIACRYPT 2014):
F(k, x) = H(x, H'(x)ᵏ), where H' hashes onto a group of prime order.
RFC 9497 (December 2023, from the IRTF's CFRG) defines three modes:
- OPRF (mode 0x00): the protocol above.
- VOPRF (0x01): verifiable. The server publishes
pkS = Gᵏand proves with each answer that it used that same k, so it can't give one client its own key to recognize it later. - POPRF (0x02): partially oblivious. Both sides also know a public
input
info, such as a date or a token type, and it changes the output. The design is from Tyagi et al. (EUROCRYPT 2022).
The suites are ristretto255-SHA512, decaf448-SHAKE256, P256-SHA256, P384-SHA384 and P521-SHA512. The 256-bit groups give 128-bit security, minus a little for heavy use (see Security notes).
How it works¶
In a group of prime order q with generator G (the RFC writes the group additively; this page writes it multiplicatively):
- Blind: the client picks a random r and sends
B = H'(x)ʳ. - Evaluate: the server sends back
Z = Bᵏ. - Finalize: the client computes
N = Z^(r⁻¹ mod q) = H'(x)ᵏand outputsH(x, N). The RFC hashes length-prefixed x and N with the label "Finalize".
B is a uniformly random group element whatever x is, so the server learns nothing about x even with unlimited computing power. RFC 9497 calls this unconditional input secrecy. The other half, that a client can't work out outputs it didn't ask for, rests on the one-more gap computational Diffie-Hellman assumption.
- VOPRF adds a proof that
log_G(pkS) = log_B(Z): a Chaum–Pedersen DLEQ proof, made non-interactive with Fiat–Shamir. One proof can cover a whole batch of answers. - POPRF hashes
infoto a scalar m and uses the keyt = k + m: the server returnsB^(1/t), and the client checks the proof againstpkS·Gᵐ. One public key covers every value ofinfo. Its security rests on a one-more gap strong Diffie-Hellman inversion assumption.
When to use it¶
Use it when a server must help turn a client's secret into a strong value, and must not see the secret.
- OPAQUE (RFC 9807, July 2025): the client runs the OPRF on its
password, under a per-client key the server derives from its
oprf_seedand the client's credential identifier. The output, stretched with Argon2id or scrypt, opens the envelope that holds the client's key. The server never sees the password, and a stolen database gives nothing to precompute against. See PAKE. WhatsApp's end-to-end encrypted backups build on OPAQUE. - Privacy Pass (RFC 9578, June 2024): token type 0x0001 is VOPRF(P-384, SHA-384). The issuer evaluates a blinded token, and later only the issuer, with its private key, can check it. The proof ties each answer to the issuer's published key. Type 0x0002 is blind RSA, which anyone can check.
- Password breach checks: Apple's Password Monitoring hashes the password to a P-256 point and blinds it with a random β, and the server multiplies it by its secret α. The server also returns the bucket of leaked passwords whose SHA-256 starts with the same 15 bits, already multiplied by α. The device compares on its own side, so Apple sees only the 15-bit prefix. Microsoft Edge's Password Monitor (2021) runs the credential through an OPRF too, so a client can't run a dictionary attack on the breach list, then looks it up with homomorphic encryption.
- Private set intersection: the server sends
F(k, y)for each y in its set, the client getsF(k, x)for each of its own, and the client compares.
Example (Python)¶
The three steps over the RFC 3526 2048-bit group from Diffie-Hellman. Squaring a hash mod p lands in the subgroup of order q, which stands in for H'. RFC 9497 uses elliptic-curve groups and hashes onto them with hash-to-curve (RFC 9380); this toy has no domain separation and isn't constant-time.
import hashlib, secrets
p = int("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437"
"4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05"
"98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
q = (p - 1) // 2 # RFC 3526 group 14; the squares mod p form a group of prime order q
def hash_to_group(x): # toy: hash, then square into the order-q group
return pow(int.from_bytes(hashlib.shake_256(b"toy H2G" + x).digest(256), "big"), 2, p)
def finalize(x, N): # F(k, x) = H(x, H'(x)^k)
return hashlib.sha256(x + N.to_bytes(256, "big")).hexdigest()
k = secrets.randbelow(q - 1) + 1 # the server's key
def oprf(x):
r = secrets.randbelow(q - 1) + 1
B = pow(hash_to_group(x), r, p) # client blinds; this is all the server sees
Z = pow(B, k, p) # server raises to k
N = pow(Z, pow(r, -1, q), p) # client unblinds with r⁻¹ mod q
return B, finalize(x, N)
B1, y1 = oprf(b"hunter2")
B2, y2 = oprf(b"hunter2")
print(y1 == y2, B1 != B2) # True True: same output, unrelated requests
print(y1 == finalize(b"hunter2", pow(hash_to_group(b"hunter2"), k, p))) # True: it is F(k, x)
print(oprf(b"hunter3")[1] == y1) # False
Security notes¶
- Each answer is a static Diffie-Hellman sample. With Q evaluations,
the best attacks (Brown and Gallant, 2004; Cheon, 2006) cut security by
about
log₂(Q) / 2bits, so a million queries cost about 10. RFC 9497 says to rate-limit clients and rotate keys, or pick decaf448, P-384 or P-521 when 128 bits isn't enough. - Hash onto the group properly. If
H'(x)wereG^h(x)with h known, one answer would let the client work outF(k, x)for every x. Use the RFC 9380 maps, and reject the identity element as the RFC does. - Plain OPRF mode proves nothing. A server could use a different key for each client and tell them apart later. Use VOPRF or POPRF when that matters, and make sure everyone gets the same public key.
- Online guesses still need a limit. The server answers anyone, so it must rate-limit; an OPRF only stops offline guessing by those without k. Whoever steals k can guess offline again, which is why OPAQUE also stretches the output with a slow hash.
- A quantum computer could recover k from the public key or past answers. Blinding hides x perfectly, so the requests themselves stay private.
See also¶
- PAKE: OPAQUE, the best-known user of an OPRF
- Blind signatures: the other Privacy Pass token
- Zero-knowledge proofs: the kind of proof behind VOPRF
- Multi-party computation: an OPRF is a two-party computation of one function
- VRF: the same kind of keyed hash, computed in the open with a proof
References¶
- Freedman, Ishai, Pinkas and Reingold, "Keyword Search and Oblivious Pseudorandom Functions" (TCC 2005)
- Jarecki, Kiayias and Krawczyk, "Round-Optimal Password-Protected Secret Sharing and T-PAKE in the Password-Only Model" (ASIACRYPT 2014)
- Tyagi et al., "A Fast and Simple Partially Oblivious PRF, with Applications" (EUROCRYPT 2022)
- RFC 9497: OPRFs Using Prime-Order Groups / RFC 9380: Hashing to Elliptic Curves / RFC 3526: MODP groups
- RFC 9807: OPAQUE / RFC 9578: Privacy Pass issuance protocols
- Davies et al., "Security Analysis of the WhatsApp End-to-End Encrypted Backup Protocol" (CRYPTO 2023)
- Apple Platform Security: Password Monitoring
Weaker sources: Microsoft Research's Password Monitor post (2021) for Edge's OPRF step.