Some quick notes on t-OPRFs

The basic (non-threshold OPRF) works as follows. Here we require an elliptic curve group of prime-order. We also need a special hash function H() that maps strings into non-identity points in the elliptic curve group. The output of the OPRF will be O = K * H(P), where the server’s secret K is a scalar, and * represents scalar point multiplication. That group element can be further hashed into a string, perhaps using a function like scrypt.

  1. The client computes the hash H(P), and blinds it by generating a random scalar B, and sends Q = B * H(P) to the server.
  2. The server uses its secret scalar K to compute and return R = K * Q.
  3. The client computes B-1 * R, which should be equal to K * H(P).

What’s cute about this approach (which is identical to the one used in OPAQUE) is that, from the server’s perspective, all it ever receives is a random group element. This means that the server never learns anything about the user’s password.

A neat feature of this OPRF is that the scalar K can be split up using Shamir secret sharing, so that each server possesses a “share” of the secret: for three servers, we’ll call these values K1, K2, K3. Using simple linear operations, any T-sized subset of these shares can be used to recover K.

A cool thing is that this same process works even if you have the values K1 * H(P), K2 * H(P) and/or K3 * H(P). That means the client can simply run the normal OPRF to obtain T values of that form, then use Shamir recovery to obtain the final value K * H(P), which is identical to the value you get from running the OPRF on a single server.

(The actual Juicebox protocol attaches some extra ZK proofs onto each server response, so that the server can prove that its share was computed correctly and it isn’t just handing you junk.)