VOPRF

Verifiable Oblivious Pseudorandom Function (VOPRF) #

Two-party protocol where server evaluates PRF on client’s input without learning the input, and client verifies correct evaluation without learning the key.

OPRF vs VOPRF vs POPRF #

VariantServer Learns InputClient VerifiesPublic Metadata
OPRFNoNoNo
VOPRFNoYesNo
POPRFNoYesYes

Protocol (RFC 9497) #

Setup #

  • Server generates keypair: (sk, pk) where pk = sk·G
  • Client knows pk

Blind #

Client blinds input x:

r ←$ Zq          // random scalar
P = H2C(x)       // hash-to-curve
B = r·P          // blinded point

Evaluate #

Server computes on blinded input:

Z = sk·B         // evaluate
π = DLEQ(sk, G, pk, B, Z)  // proof
return (Z, π)

Unblind & Verify #

Client:

verify DLEQ(π, G, pk, B, Z)
N = r⁻¹·Z = r⁻¹·sk·r·P = sk·P
output = H(x, N)

DLEQ Proof #

Proves log_G(pk) = log_B(Z) (same secret key used) without revealing sk.

Schnorr-style:

Prover:                         Verifier:
  t ←$ Zq
  A = t·G, D = t·B
  c = H(G, pk, B, Z, A, D)
  s = t - c·sk
  send (c, s)
                                A' = s·G + c·pk
                                D' = s·B + c·Z
                                check c = H(G, pk, B, Z, A', D')

Ciphersuites (RFC 9497) #

SuiteCurveHashSecurity
P256-SHA256NIST P-256SHA-256128-bit
P384-SHA384NIST P-384SHA-384192-bit
P521-SHA512NIST P-521SHA-512256-bit
ristretto255-SHA512Ristretto255SHA-512128-bit
decaf448-SHAKE256Decaf448SHAKE256224-bit

Security Properties #

PropertyGuarantee
ObliviousnessServer learns nothing about input
VerifiabilityClient detects malicious evaluation
PseudorandomnessOutput indistinguishable from random without key
UnlinkabilityCannot link blind request to unblinded output

Applications #

ApplicationHow VOPRF is Used
Privacy PassBlind token signing
OPAQUEPassword hardening without server learning password
Private Set IntersectionCompare elements without revealing sets
Rate limitingAnonymous but bounded access

OPAQUE Integration #

VOPRF hardens password authentication:

Client                              Server
  |                                   |
  |-- blind(pwd) -------------------->|
  |                                   |
  |<-- OPRF(sk, blind(pwd)) ---------|
  |                                   |
  rwd = unblind(response)             |
  key = KDF(rwd)                      |

Server never sees password; compromise doesn’t yield offline dictionary attack.

When to Use #

  • Need server-assisted computation without revealing input
  • Client must verify server behaved honestly (use VOPRF over OPRF)
  • Token issuance with unlinkability (Privacy Pass)
  • Password hardening (OPAQUE)
  • Rate limiting with anonymity

When Not to Use #

  • No need for verifiability (plain OPRF is simpler)
  • Server is fully trusted (just use HMAC)
  • Need public verifiability by third parties (use blind signatures)
  • Input domain is small/enumerable (server can brute-force)
  • Quantum adversaries (current constructions not post-quantum)

See Also #


Written by Claude Opus 4.5