]>
Oblivious Pseudorandom Functions (OPRFs) using Prime-Order GroupsBrave Softwarealex.davidson92@gmail.comCloudflare, Inc.101 Townsend StSan FranciscoUnited States of Americaarmfazh@cloudflare.comCloudflare, Inc.101 Townsend StSan FranciscoUnited States of Americanick@cloudflare.comCloudflare, Inc.101 Townsend StSan FranciscoUnited States of Americacaw@heapingbits.netInternet-DraftAn Oblivious Pseudorandom Function (OPRF) is a two-party protocol between
client and server for computing the output of a Pseudorandom Function (PRF).
The server provides the PRF secret key, and the client provides the PRF
input. At the end of the protocol, the client learns the PRF output without
learning anything about the PRF secret key, and the server learns neither
the PRF input nor output. An OPRF can also satisfy a notion of 'verifiability',
called a VOPRF. A VOPRF ensures clients can verify that the server used a
specific private key during the execution of the protocol. A VOPRF can also
be partially-oblivious, called a POPRF. A POPRF allows clients and servers
to provide public input to the PRF computation. This document specifies an OPRF,
VOPRF, and POPRF instantiated within standard prime-order groups, including
elliptic curves.Discussion VenuesSource for this draft and an issue tracker can be found at
.IntroductionA Pseudorandom Function (PRF) F(k, x) is an efficiently computable
function taking a private key k and a value x as input. This function is
pseudorandom if the keyed function K(_) = F(k, _) is indistinguishable
from a randomly sampled function acting on the same domain and range as
K(). An Oblivious PRF (OPRF) is a two-party protocol between a server
and a client, where the server holds a PRF key k and the client holds
some input x. The protocol allows both parties to cooperate in computing
F(k, x) such that the client learns F(k, x) without learning anything
about k; and the server does not learn anything about x or F(k, x).
A Verifiable OPRF (VOPRF) is an OPRF wherein the server also proves
to the client that F(k, x) was produced by the key k corresponding
to the server's public key the client knows. A Partially-Oblivious PRF (POPRF)
is a variant of a VOPRF wherein client and server interact in computing
F(k, x, y), for some PRF F with server-provided key k, client-provided
input x, and public input y, and client receives proof
that F(k, x, y) was computed using k corresponding to the public key
that the client knows. A POPRF with fixed input y is functionally
equivalent to a VOPRF.OPRFs have a variety of applications, including: password-protected secret
sharing schemes , privacy-preserving password stores , and
password-authenticated key exchange or PAKE .
Verifiable POPRFs are necessary in some applications such as Privacy Pass
. Verifiable OPRFs have also been used for
password-protected secret sharing schemes such as that of .This document specifies OPRF, VOPRF, and POPRF protocols built upon
prime-order groups. The document describes each protocol variant,
along with application considerations, and their security properties.Change logdraft-13:
Editorial improvements based on Crypto Panel Review.
draft-12:
Small editorial fixes
draft-11:
Change Evaluate to BlindEvaluate, and add Evaluate for PRF evaluation
draft-10:
Editorial improvements
draft-09:
Split syntax for OPRF, VOPRF, and POPRF functionalities.
Make Blind function fallible for invalid private and public inputs.
Specify key generation.
Remove serialization steps from core protocol functions.
Refactor protocol presentation for clarity.
Simplify security considerations.
Update application interface considerations.
Update test vectors.
draft-08:
Adopt partially-oblivious PRF construction from .
Update P-384 suite to use SHA-384 instead of SHA-512.
Update test vectors.
Apply various editorial changes.
draft-07:
Bind blinding mechanism to mode (additive for verifiable mode and
multiplicative for base mode).
Add explicit errors for deserialization.
Document explicit errors and API considerations.
Adopt SHAKE-256 for decaf448 ciphersuite.
Normalize HashToScalar functionality for all ciphersuites.
Refactor and generalize DLEQ proof functionality and domain separation
tags for use in other protocols.
Update test vectors.
Apply various editorial changes.
draft-06:
Specify of group element and scalar serialization.
Remove info parameter from the protocol API and update domain separation guidance.
Fold Unblind function into Finalize.
Optimize ComputeComposites for servers (using knowledge of the private key).
Specify deterministic key generation method.
Update test vectors.
Apply various editorial changes.
draft-05:
Move to ristretto255 and decaf448 ciphersuites.
Clean up ciphersuite definitions.
Pin domain separation tag construction to draft version.
Move key generation outside of context construction functions.
Editorial changes.
draft-04:
Introduce Client and Server contexts for controlling verifiability and
required functionality.
Condense API.
Remove batching from standard functionality (included as an extension)
Add Curve25519 and P-256 ciphersuites for applications that prevent
strong-DH oracle attacks.
Provide explicit prime-order group API and instantiation advice for
each ciphersuite.
Proof-of-concept implementation in sage.
Remove privacy considerations advice as this depends on applications.
draft-03:
Certify public key during VerifiableFinalize.
Remove protocol integration advice.
Add text discussing how to perform domain separation.
Drop OPRF_/VOPRF_ prefix from algorithm names.
Make prime-order group assumption explicit.
Changes to algorithms accepting batched inputs.
Changes to construction of batched DLEQ proofs.
Updated ciphersuites to be consistent with hash-to-curve and added
OPRF specific ciphersuites.
draft-02:
Added section discussing cryptographic security and static DH oracles.
Updated batched proof algorithms.
draft-01:
Updated ciphersuites to be in line with
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-04.
Made some necessary modular reductions more explicit.
RequirementsThe key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED",
"MAY", and "OPTIONAL" in this document are to be interpreted as
described in BCP 14 when, and only when, they
appear in all capitals, as shown here.Notation and TerminologyThe following functions and notation are used throughout the document.
For any object x, we write len(x) to denote its length in bytes.
For two byte arrays x and y, write x || y to denote their
concatenation.
I2OSP(x, xLen): Converts a non-negative integer x into a byte array
of specified length xLen as described in . Note that
this function returns a byte array in big-endian byte order.
The notation T U[N] refers to an array called U containing N items of type
T. The type opaque means one single byte of uninterpreted data. Items of
the array are zero-indexed and referred as U[j] such that 0 <= j < N.
All algorithms and procedures described in this document are laid out
in a Python-like pseudocode. Each function takes a set of inputs and parameters
and produces a set of output values. Parameters become constant values once the
protocol variant and the ciphersuite are fixed.The PrivateInput data type refers to inputs that are known only to the client
in the protocol, whereas the PublicInput data type refers to inputs that are
known to both client and server in the protocol. Both PrivateInput and
PublicInput are opaque byte strings of arbitrary length no larger than 2^13 octets.String values such as "DeriveKeyPair", "Seed-", and "Finalize" are ASCII string literals.The following terms are used throughout this document.
Client: Protocol initiator. Learns pseudorandom function evaluation as
the output of the protocol.
Server: Computes the pseudorandom function over a private key. Learns
nothing about the client's input or output.
PreliminariesThe protocols in this document have two primary dependencies:
Group: A prime-order group implementing the API described below in .
See for specific instances of groups.
Hash: A cryptographic hash function whose output length is Nh bytes.
specifies ciphersuites as combinations of Group and Hash.Prime-Order GroupIn this document, we assume the construction of an additive, prime-order
group Group for performing all mathematical operations. In prime-order groups,
any element can generate the other elements of the group. Usually, one element
is fixed and defined as the group generator. Such groups are
uniquely determined by the choice of the prime p that defines the
order of the group. (There may, however, exist different representations
of the group for a single p. lists specific groups which
indicate both order and representation.)The fundamental group operation is addition + with identity element
I. For any elements A and B of the group, A + B = B + A is
also a member of the group. Also, for any A in the group, there exists an element
-A such that A + (-A) = (-A) + A = I. Scalar multiplication is
equivalent to the repeated application of the group operation on an
element A with itself r-1 times, this is denoted as r*A = A + ... + A.
For any element A, p*A=I. The case when the scalar multiplication is
performed on the group generator is denoted as ScalarMultGen(r).
Given two elements A and B, the discrete logarithm problem is to find
an integer k such that B = k*A. Thus, k is the discrete logarithm of
B with respect to the base A.
The set of scalars corresponds to GF(p), a prime field of order p, and are
represented as the set of integers defined by {0, 1, ..., p-1}.
This document uses types
Element and Scalar to denote elements of the group and its set of
scalars, respectively.We now detail a number of member functions that can be invoked on a
prime-order group.
Order(): Outputs the order of the group (i.e. p).
Identity(): Outputs the identity element of the group (i.e. I).
Generator(): Outputs the generator element of the group.
HashToGroup(x): A member function of Group that deterministically maps
an array of bytes x to an element of Group. The map must ensure that,
for any adversary receiving R = HashToGroup(x), it is
computationally difficult to reverse the mapping. This function is optionally
parameterized by a domain separation tag (DST); see .
HashToScalar(x): A member function of Group that deterministically maps
an array of bytes x to an element in GF(p). This function is optionally
parameterized by a DST; see .
RandomScalar(): A member function of Group that chooses at random a
non-zero element in GF(p).
ScalarInverse(s): Returns the inverse of input Scalar s on GF(p).
SerializeElement(A): A member function of Group that maps a group element
A to a unique byte array buf of fixed length Ne bytes.
DeserializeElement(buf): A member function of Group that maps a byte
array buf to a group element A, or raise a DeserializeError if the
input is not a valid byte representation of an element.
See for further requirements on input validation.
SerializeScalar(s): A member function of Group that maps a scalar element
s to a unique byte array buf of fixed length Ns bytes.
DeserializeScalar(buf): A member function of Group that maps a byte
array buf to a scalar s, or raise a DeserializeError if the input
is not a valid byte representation of a scalar.
See for further requirements on input validation.
It is convenient in cryptographic applications to instantiate such
prime-order groups using elliptic curves, such as those detailed in
. For some choices of elliptic curves (e.g. those detailed in
, which require accounting for cofactors) there are some
implementation issues that introduce inherent discrepancies between
standard prime-order groups and the elliptic curve instantiation. In
this document, all algorithms that we detail assume that the group is a
prime-order group, and this MUST be upheld by any implementation. That is,
any curve instantiation should be written such that any discrepancies
with a prime-order group instantiation are removed. See
for advice corresponding to the implementation of this interface for
specific definitions of elliptic curves.Discrete Logarithm Equivalence ProofsA proof of knowledge allows a prover to convince a verifier that some
statement is true. If the prover can generate a proof without interaction
with the verifier, the proof is noninteractive. If the verifier learns
nothing other than whether the statement claimed by the prover is true or
false, the proof is zero-knowledge.This section describes a noninteractive zero-knowledge proof for discrete
logarithm equivalence (DLEQ). A DLEQ proof demonstrates that two pairs of
group elements have the same discrete logarithm without revealing the
discrete logarithm.The DLEQ proof resembles the Chaum-Pedersen proof, which
is shown to be zero-knowledge by Jarecki, et al. and is
noninteractive after applying the Fiat-Shamir transform .
Furthermore, Davidson, et al. showed a proof system for
batching DLEQ proofs that has constant-size proofs with respect to the
number of inputs.
The specific DLEQ proof system presented below follows this latter
construction with two modifications: (1) the transcript used to generate
the seed includes more context information, and (2) the individual challenges
for each element in the proof is derived from a seed-prefixed hash-to-scalar
invocation rather than being sampled from a seeded PRNG.
The description is split into
two sub-sections: one for generating the proof, which is done by servers
in the verifiable protocols, and another for verifying the proof, which is
done by clients in the protocol.Proof GenerationGenerating a proof is done with the GenerateProof function, defined below.
Given elements A and B, two non-empty lists of elements C and D of length
m, and a scalar k; this function produces a proof that k*A == B
and k*C[i] == D[i] for each i in [0, ..., m - 1].
The output is a value of type Proof, which is a tuple of two Scalar
values.GenerateProof accepts lists of inputs to amortize the cost of proof
generation. Applications can take advantage of this functionality to
produce a single, constant-sized proof for m DLEQ inputs, rather
than m proofs for m DLEQ inputs.The helper function ComputeCompositesFast is as defined below, and is an
optimization of the ComputeComposites function for servers since they have
knowledge of the private key.When used in the protocol described in , the parameter contextString is
as defined in .Proof VerificationVerifying a proof is done with the VerifyProof function, defined below.
This function takes elements A and B, two non-empty lists of elements C and D
of length m, and a Proof value output from GenerateProof. It outputs a
single boolean value indicating whether or not the proof is valid for the
given DLEQ inputs. Note this function can verify proofs on lists of inputs
whenever the proof was generated as a batched DLEQ proof with the same inputs.The definition of ComputeComposites is given below.When used in the protocol described in , the parameter contextString is
as defined in .ProtocolIn this section, we define three protocol variants referred as the OPRF, VOPRF,
and POPRF modes with the following properties.In the OPRF mode, a client and server interact to compute output = F(skS, input),
where input is the client's private input, skS is the server's private key,
and output is the OPRF output. After the execution of the protocol, the
client learns output and the server learns nothing.
This interaction is shown below.In the VOPRF mode, the client additionally receives proof that the server used
skS in computing the function. To achieve verifiability, as in the original
work of , the
server provides a zero-knowledge proof that the key provided as input by the server in
the BlindEvaluate function is the same key as it used to produce the server's public key, pkS,
which the client receives as input to the protocol. This proof does not reveal the server's
private key to the client. This interaction is shown below.The POPRF mode extends the VOPRF mode such that the client and
server can additionally provide a public input info that is used in computing
the pseudorandom function. That is, the client and server interact to compute
output = F(skS, input, info) as is shown below.Each protocol consists of an offline setup phase and an online phase,
described in and , respectively. Configuration details
for the offline phase are described in .ConfigurationEach of the three protocol variants are identified with a one-byte value (in hexadecimal):Identifiers for OPRF modes
Mode
Value
modeOPRF
0x00
modeVOPRF
0x01
modePOPRF
0x02
Additionally, each protocol variant is instantiated with a ciphersuite,
or suite. Each ciphersuite is identified with a two-byte value, referred
to as suiteID; see for the registry of initial values.The mode and ciphersuite ID values are combined to create a "context string"
used throughout the protocol with the following function:[[RFC editor: please change "VOPRF10" to "RFCXXXX", where XXXX is the final number, here and elsewhere before publication.]]Key Generation and Context SetupIn the offline setup phase, the server key pair (skS, pkS) is generated
using the following function, which accepts a randomly generated seed of length
Ns bytes and an optional (and possible empty) public info string. The
constant Ns corresponds to the size in bytes of a serialized Scalar and is
defined in . 255:
raise DeriveKeyPairError
skS = G.HashToScalar(deriveInput || I2OSP(counter, 1),
DST = "DeriveKeyPair" || contextString)
counter = counter + 1
pkS = G.ScalarMultGen(skS)
return skS, pkS
]]>Also during the offline setup phase, both the client and server create a
context used for executing the online phase of the protocol after agreeing on a
mode and ciphersuite value suiteID. The context, such as OPRFServerContext,
is an implementation-specific data structure that stores a context string and
the relevant key material for each party.The OPRF variant server and client contexts are created as follows:The VOPRF variant server and client contexts are created as follows:The POPRF variant server and client contexts are created as follows:Online ProtocolIn the online phase, the client and server engage in a two message protocol
to compute the protocol output. This section describes the protocol details
for each protocol variant. Throughout each description the following parameters
are assumed to exist:
G, a prime-order Group implementing the API described in .
contextString, a PublicInput domain separation tag constructed during context setup as created in .
skS and pkS, a Scalar and Element representing the private and public keys configured for client and server in .
Applications serialize protocol messages between client and server for
transmission. Elements and scalars are serialized to byte arrays, and values
of type Proof are serialized as the concatenation of two serialized scalars.
Deserializing these values can fail, in which case the application MUST abort
the protocol with a DeserializeError failure.Applications MUST check that input Element values received over the wire
are not the group identity element. This check is handled after deserializing
Element values; see for more information on input
validation.OPRF ProtocolThe OPRF protocol begins with the client blinding its input, as described
by the Blind function below. Note that this function can fail with an
InvalidInputError error for certain inputs that map to the group identity
element. Dealing with this failure is an application-specific decision;
see .Clients store blind locally, and send blindedElement to the server for evaluation.
Upon receipt, servers process blindedElement using the BlindEvaluate function described
below.Servers send the output evaluatedElement to clients for processing.
Recall that servers may process multiple client inputs by applying the
BlindEvaluate function to each blindedElement received, and returning an
array with the corresponding evaluatedElement values.Upon receipt of evaluatedElement, clients process it to complete the
OPRF evaluation with the Finalize function described below.Servers can compute the PRF result using a given input using the following
Evaluate function.VOPRF ProtocolThe VOPRF protocol begins with the client blinding its input, using the same
Blind function as in . Clients store the output blind locally
and send blindedElement to the server for evaluation. Upon receipt,
servers process blindedElement to compute an evaluated element and DLEQ
proof using the following BlindEvaluate function.In the description above, inputs to GenerateProof are one-item
lists. Using larger lists allows servers to batch the evaluation of multiple
elements while producing a single batched DLEQ proof for them.The server sends both evaluatedElement and proof back to the client.
Upon receipt, the client processes both values to complete the VOPRF computation
using the Finalize function below.As in BlindEvaluate, inputs to VerifyProof are one-item lists. Clients can
verify multiple inputs at once whenever the server produced a batched DLEQ proof
for them.Finally, servers can compute the PRF result using a given input using the Evaluate
function described in .POPRF ProtocolThe POPRF protocol begins with the client blinding its input, using the
following modified Blind function. In this step, the client also binds a
public info value, which produces an additional tweakedKey to be used later
in the protocol. Note that this function can fail with an
InvalidInputError error for certain private inputs that map to the group
identity element, as well as certain public inputs that, if not detected at
this point, will cause server evaluation to fail. Dealing with either failure
is an application-specific decision; see .Clients store the outputs blind and tweakedKey locally and send blindedElement to
the server for evaluation. Upon receipt, servers process blindedElement to
compute an evaluated element and DLEQ proof using the following BlindEvaluate function.In the description above, inputs to GenerateProof are one-item
lists. Using larger lists allows servers to batch the evaluation of multiple
elements while producing a single batched DLEQ proof for them.BlindEvaluate triggers InverseError when the function is about to
calculate the inverse of a zero scalar, which does not exist and therefore
yields a failure in the protocol.
This only occurs for info values that map to the secret key of the server. Thus,
clients that observe this signal are assumed to know the server secret key. Hence,
this error can be a signal for the server to replace its secret key.The server sends both evaluatedElement and proof back to the client.
Upon receipt, the client processes both values to complete the POPRF computation
using the Finalize function below.As in BlindEvaluate, inputs to VerifyProof are one-item lists.
Clients can verify multiple inputs at once whenever the server produced a
batched DLEQ proof for them.Finally, servers can compute the PRF result using a given input using the Evaluate
function described below.CiphersuitesA ciphersuite (also referred to as 'suite' in this document) for the protocol
wraps the functionality required for the protocol to take place. The
ciphersuite should be available to both the client and server, and agreement
on the specific instantiation is assumed throughout.A ciphersuite contains instantiations of the following functionalities:
Group: A prime-order Group exposing the API detailed in , with the
generator element defined in the corresponding reference for each group. Each
group also specifies HashToGroup, HashToScalar, and serialization
functionalities. For
HashToGroup, the domain separation tag (DST) is constructed in accordance
with the recommendations in , Section 3.1.
For HashToScalar, each group specifies an integer order that is used in
reducing integer values to a member of the corresponding scalar field.
Hash: A cryptographic hash function whose output length is Nh bytes long.
This section specifies an initial registry of ciphersuites with supported groups
and hash functions. It also includes implementation details for each ciphersuite,
focusing on input validation, as well as requirements for future ciphersuites.Ciphersuite RegistryFor each ciphersuite, contextString is that which is computed in the Setup functions.
Applications should take caution in using ciphersuites targeting P-256 and ristretto255.
See for related discussion.OPRF(ristretto255, SHA-512)
Group: ristretto255
HashToGroup(): Use hash_to_ristretto255
with DST =
"HashToGroup-" || contextString, and expand_message = expand_message_xmd
using SHA-512.
HashToScalar(): Compute uniform_bytes using expand_message = expand_message_xmd,
DST = "HashToScalar-" || contextString, and output length 64, interpret
uniform_bytes as a 512-bit integer in little-endian order, and reduce the
integer modulo Group.Order().
Serialization: Both group elements and scalars are encoded in Ne = Ns = 32
bytes. For group elements, use the 'Encode' and 'Decode' functions from
. For scalars, ensure they are fully reduced modulo
Group.Order()
and in little-endian order.
Hash: SHA-512, and Nh = 64 bytes.
ID: 0x0001
OPRF(decaf448, SHAKE-256)
Group: decaf448
HashToGroup(): Use hash_to_decaf448
with DST =
"HashToGroup-" || contextString, and expand_message = expand_message_xof
using SHAKE-256.
HashToScalar(): Compute uniform_bytes using expand_message = expand_message_xof,
DST = "HashToScalar-" || contextString, and output length 64, interpret
uniform_bytes as a 512-bit integer in little-endian order, and reduce the
integer modulo Group.Order().
Serialization: Both group elements and scalars are encoded in Ne = Ns = 56
bytes. For group elements, use the 'Encode' and 'Decode' functions from
. For scalars, ensure they are fully reduced modulo
Group.Order()
and in little-endian order.
Hash: SHAKE-256, and Nh = 64 bytes.
ID: 0x0002
OPRF(P-256, SHA-256)
Group: P-256 (secp256r1)
HashToGroup(): Use hash_to_curve with suite P256_XMD:SHA-256_SSWU_RO_
and DST =
"HashToGroup-" || contextString.
HashToScalar(): Use hash_to_field from
using L = 48, expand_message_xmd with SHA-256,
DST = "HashToScalar-" || contextString, and
prime modulus equal to Group.Order().
Serialization: Elements are serialized as Ne = 33 byte strings using
compressed point encoding for the curve . Scalars are serialized as
Ns = 32 byte strings by fully reducing the value modulo Group.Order() and
in big-endian order.
Hash: SHA-256, and Nh = 32 bytes.
ID: 0x0003
OPRF(P-384, SHA-384)
Group: P-384 (secp384r1)
HashToGroup(): Use hash_to_curve with suite P384_XMD:SHA-384_SSWU_RO_
and DST =
"HashToGroup-" || contextString.
HashToScalar(): Use hash_to_field from
using L = 72, expand_message_xmd with SHA-384,
DST = "HashToScalar-" || contextString, and
prime modulus equal to Group.Order().
Serialization: Elements are serialized as Ne = 49 byte strings using
compressed point encoding for the curve . Scalars are serialized as
Ns = 48 byte strings by fully reducing the value modulo Group.Order() and
in big-endian order.
Hash: SHA-384, and Nh = 48 bytes.
ID: 0x0004
OPRF(P-521, SHA-512)
Group: P-521 (secp521r1)
HashToGroup(): Use hash_to_curve with suite P521_XMD:SHA-512_SSWU_RO_
and DST =
"HashToGroup-" || contextString.
HashToScalar(): Use hash_to_field from
using L = 98, expand_message_xmd with SHA-512,
DST = "HashToScalar-" || contextString, and
prime modulus equal to Group.Order().
Serialization: Elements are serialized as Ne = 67 byte strings using
compressed point encoding for the curve . Scalars are serialized as
Ns = 66 byte strings by fully reducing the value modulo Group.Order() and
in big-endian order.
Hash: SHA-512, and Nh = 64 bytes.
ID: 0x0005
Input ValidationSince messages are serialized before transmission between client and server,
deserialization is followed by input validation to prevent malformed or
invalid inputs from being used in the protocol.
The DeserializeElement and DeserializeScalar functions instantiated for a
particular prime-order group corresponding to a ciphersuite MUST adhere
to the description in . This section describes how input validation
of elements and scalars is implemented for all prime-order groups included
in the above ciphersuite list.Element ValidationRecovering a group element from an arbitrary byte array must validate that
the element is a proper member of the group and is not the identity element,
and returns an error if either condition is not met.For P-256, P-384, and P-521 ciphersuites, it is required to perform partial
public-key validation as defined in Section 5.6.2.3.4 of .
This includes checking that the coordinates are in the correct range, that
the point is on the curve, and that the point is not the identity.
If these checks fail, validation returns an InputValidationError.For ristretto255 and decaf448, elements are deserialized by invoking the Decode
function from and , respectively,
which returns false if the input is invalid. If this function returns false
or if the decoded element is the identity, validation returns an
InputValidationError.Scalar ValidationThe DeserializeScalar function attempts to recover a scalar field element from an arbitrary
byte array. Like DeserializeElement, this function validates that the element
is a member of the scalar field and returns an error if this condition is not met.For P-256, P-384, and P-521 ciphersuites, this function ensures that the input,
when treated as a big-endian integer, is a value between 0 and
Group.Order() - 1. For
ristretto255 and decaf448, this function ensures that the input, when treated as
a little-endian integer, is a value between 0 and Group.Order() - 1.Future CiphersuitesA critical requirement of implementing the prime-order group using
elliptic curves is a method to instantiate the function
HashToGroup, that maps inputs to group elements. In the elliptic
curve setting, this deterministically maps inputs x (as byte arrays) to
uniformly chosen points on the curve.In the security proof of the construction Hash is modeled as a random
oracle. This implies that any instantiation of HashToGroup must be
pre-image and collision resistant. In we give
instantiations of this functionality based on the functions described in
. Consequently, any OPRF implementation
must adhere to the implementation and security considerations discussed
in when instantiating the function.Additionally, future ciphersuites must take care when choosing the
security level of the group. See for additional details.Application ConsiderationsThis section describes considerations for applications, including external interface
recommendations, explicit error treatment, and public input representation for the
POPRF protocol variant.Input LimitsApplication inputs, expressed as PrivateInput or PublicInput values, MUST be smaller
than 2^13 bytes in length. Applications that require longer inputs can use a cryptographic
hash function to map these longer inputs to a fixed-length input that fits within the
PublicInput or PrivateInput length bounds. Note that some cryptographic hash functions
have input length restrictions themselves, but these limits are often large enough to
not be a concern in practice. For example, SHA-256 has an input limit of 2^61 bytes.External Interface RecommendationsIn , the interface of the protocol functions allows that some inputs
(and outputs) to be group elements and scalars. However, implementations can
instead operate over group elements and scalars internally, and only expose
interfaces that operate with an application-specific format of messages.Error ConsiderationsSome OPRF variants specified in this document have fallible operations. For example, Finalize
and BlindEvaluate can fail if any element received from the peer fails input validation.
The explicit errors generated throughout this specification, along with the
conditions that lead to each error, are as follows:
VerifyError: Verifiable OPRF proof verification failed; and .
DeserializeError: Group Element or Scalar deserialization failure; and .
InputValidationError: Validation of byte array inputs failed; .
There are other explicit errors generated in this specification; however, they occur with
negligible probability in practice. We note them here for completeness.
InvalidInputError: OPRF Blind input produces an invalid output element; and .
InverseError: A tweaked private key is invalid (has no multiplicative inverse); and .
In general, the errors in this document are meant as a guide to implementors.
They are not an exhaustive list of all the errors an implementation might emit.
For example, implementations might run out of memory and return a corresponding error.POPRF Public InputFunctionally, the VOPRF and POPRF variants differ in that the POPRF variant
admits public input, whereas the VOPRF variant does not. Public input allows
clients and servers to cryptographically bind additional data to the POPRF output.
A POPRF with fixed public input is functionally equivalent to a VOPRF. However, there
are differences in the underlying security assumptions made about each variant;
see for more details.This public input is known to both parties at the start of the protocol. It is RECOMMENDED
that this public input be constructed with some type of higher-level domain separation
to avoid cross protocol attacks or related issues. For example, protocols using
this construction might ensure that the public input uses a unique, prefix-free encoding.
See for further discussion on
constructing domain separation values.Implementations of the POPRF may choose to not let applications control info in
cases where this value is fixed or otherwise not useful to the application. In this
case, the resulting protocol is functionally equivalent to the VOPRF, which does not
admit public input.Security ConsiderationsThis section discusses the cryptographic security of our protocol, along
with some suggestions and trade-offs that arise from the implementation
of the OPRF variants in this document. Note that the syntax of the POPRF
variant is different from that of the OPRF and VOPRF variants since it
admits an additional public input, but the same security considerations apply.Security PropertiesThe security properties of an OPRF protocol with functionality y = F(k, x)
include those of a standard PRF. Specifically:
Pseudorandomness: For a random sampling of k, F is pseudorandom if the output
y = F(k, x) on any input x is indistinguishable from uniformly sampling any
element in F's range.
In other words, consider an adversary that picks inputs x from the
domain of F and evaluates F on (k, x) (without knowledge of randomly
sampled k). Then the output distribution F(k, x) is indistinguishable
from the output distribution of a randomly chosen function with the same
domain and range.A consequence of showing that a function is pseudorandom, is that it is
necessarily non-malleable (i.e. we cannot compute a new evaluation of F
from an existing evaluation). A genuinely random function will be
non-malleable with high probability, and so a pseudorandom function must
be non-malleable to maintain indistinguishability.
Unconditional input secrecy: The server does not learn anything about
the client input x, even with unbounded computation.
In other words, an attacker with infinite computing power cannot recover any
information about the client's private input x from an invocation of the
protocol.Essentially, input secrecy is the property that, even if the server learns
the client's private input x at some point in the future, the server cannot
link any particular PRF evaluation to x. This property is
also known as unlinkability .For the VOPRF and POPRF protocol variants, there is an additional
security property:
Verifiable: The client must only complete execution of the protocol if
it can successfully assert that the output it computes is
correct. This is taken with respect to the private key held by the
server.
Any VOPRF or POPRF that satisfies the 'verifiable' security property is known
as 'verifiable'. In practice, the notion of verifiability requires that
the server commits to the key before the actual protocol execution takes
place. Then the client verifies that the server has used the key in the
protocol using this commitment. In the following, we may also refer to this
commitment as a public key.Finally, the POPRF variant also has the following security property:
Partial obliviousness: The client and server must be able to perform the
PRF on client's private input and public input. The server must learn nothing
about the client's private input or the output of the function. In addition,
the client must learn nothing about the server's private key.
This property becomes useful when dealing with key management operations such as
the rotation of server's keys.Security AssumptionsBelow, we discuss the cryptographic security of each protocol variant
from , relative to the necessary cryptographic assumptions
that need to be made.OPRF and VOPRF AssumptionsThe OPRF and VOPRF protocol variants in this document are based on .
In fact, the VOPRF construction is identical to the construction, except
that this document supports batching so that multiple evaluations can happen
at once whilst only constructing one DLEQ proof object. This is enabled using
an established batching technique .The pseudorandomness and input secrecy (and verifiability) of the OPRF (and
VOPRF) variant is based on an assumption with oracle access to the
Computational Diffie Hellman (CDH) assumption, known as the One-More Gap CDH,
that is computationally difficult to solve in the corresponding prime-order
group. The original paper gives a security proof that the
construction satisfies the security guarantees of a VOPRF protocol
(as in ) under the One-More Gap CDH assumption in the
universal composability (UC) security framework.POPRF AssumptionsThe POPRF construction in this document is based on the construction known
as 3HashSDHI given by . The construction is identical to
3HashSDHI, except that this design can optionally perform multiple POPRF
evaluations in one go, whilst only constructing one DLEQ proof object.
This is enabled using an established batching technique .Pseudorandomness, input secrecy, verifiability, and partial obliviousness of the POPRF variant is
based on the assumption that the One-More Gap Strong Diffie-Hellman Inversion (SDHI)
assumption from is computationally difficult to solve in the corresponding
prime-order group. Tyagi et al. show that both the One-More Gap CDH assumption
and the One-More Gap SDHI assumption reduce to the q-DL (Discrete Log) assumption
in the algebraic group model, for some q number of BlindEvaluate queries.
(The One-More Gap CDH assumption was the hardness assumption used to
evaluate the OPRF and VOPRF designs based on , which is a predecessor
to the POPRF variant in .)Static Diffie Hellman Attack and Security LimitsA side-effect of the OPRF protocol variants in this document is that they allow
instantiation of an oracle for constructing static DH samples; see and .
These attacks are meant to recover (bits of) the server private key.
Best-known attacks reduce the security of the prime-order group instantiation by log_2(Q)/2
bits, where Q is the number of BlindEvaluate calls made by the attacker.As a result of this class of attack, choosing prime-order groups with a 128-bit security
level instantiates an OPRF with a reduced security level of 128-(log_2(Q)/2) bits of security.
Moreover, such attacks are only possible for those certain applications where the
adversary can query the OPRF directly. Applications can mitigate against this problem
in a variety of ways, e.g., by rate-limiting client queries to BlindEvaluate or by
rotating private keys. In applications where such an oracle is not made available
this security loss does not apply.In most cases, it would require an informed and persistent attacker to
launch a highly expensive attack to reduce security to anything much
below 100 bits of security. Applications that admit the aforementioned
oracle functionality, and that cannot tolerate discrete logarithm security
of lower than 128 bits, are RECOMMENDED to choose groups that target a
higher security level, such as decaf448 (used by ciphersuite 0x0002),
P-384 (used by 0x0004), or P-521 (used by 0x0005).Domain SeparationApplications SHOULD construct input to the protocol to provide domain
separation. Any system which has multiple OPRF applications should
distinguish client inputs to ensure the OPRF results are separate.
Guidance for constructing info can be found in .Timing LeaksTo ensure no information is leaked during protocol execution, all
operations that use secret data MUST run in constant time. This includes
all prime-order group operations and proof-specific operations that
operate on secret data, including GenerateProof and BlindEvaluate.AcknowledgementsThis document resulted from the work of the Privacy Pass team
. The authors would also like to acknowledge helpful
conversations with Hugo Krawczyk. Eli-Shaoul Khedouri provided
additional review and comments on key consistency. Daniel Bourdrez,
Tatiana Bradley, Sofia Celi, Frank Denis, Kevin Lewi, Christopher Patton,
and Bas Westerbaan also provided helpful input and contributions to the document.ReferencesNormative ReferencesKey words for use in RFCs to Indicate Requirement LevelsIn many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.The OPAQUE Asymmetric PAKE ProtocolAlgorand FoundationNovi ResearchCloudflare, Inc. This document describes the OPAQUE protocol, a secure asymmetric
password-authenticated key exchange (aPAKE) that supports mutual
authentication in a client-server setting without reliance on PKI and
with security against pre-computation attacks upon server compromise.
In addition, the protocol provides forward secrecy and the ability to
hide the password from the server, even during password registration.
This document specifies the core OPAQUE protocol and one
instantiation based on 3DH.
Privacy Pass Issuance ProtocolBrave SoftwareBrave SoftwareCloudflareGoogle LLCCloudflare This document specifies two variants of the the two-message issuance
protocol for Privacy Pass tokens: one that produces tokens that are
privately verifiable, and another that produces tokens that are
publicly verifiable. The privately verifiable issuance protocol
optionally supports public metadata during the issuance flow.
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key WordsRFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.PKCS #1: RSA Cryptography Specifications Version 2.2This document provides recommendations for the implementation of public-key cryptography based on the RSA algorithm, covering cryptographic primitives, encryption schemes, signature schemes with appendix, and ASN.1 syntax for representing keys and for identifying the schemes.This document represents a republication of PKCS #1 v2.2 from RSA Laboratories' Public-Key Cryptography Standards (PKCS) series. By publishing this RFC, change control is transferred to the IETF.This document also obsoletes RFC 3447.Hashing to Elliptic CurvesCloudflare, Inc.Cornell TechCloudflare, Inc.Stanford UniversityCloudflare, Inc. This document specifies a number of algorithms for encoding or
hashing an arbitrary string to a point on an elliptic curve. This
document is a product of the Crypto Forum Research Group (CFRG) in
the IRTF.
The ristretto255 and decaf448 Groups This memo specifies two prime-order groups, ristretto255 and
decaf448, suitable for safely implementing higher-level and complex
cryptographic protocols. The ristretto255 group can be implemented
using Curve25519, allowing existing Curve25519 implementations to be
reused and extended to provide a prime-order group. Likewise, the
decaf448 group can be implemented using edwards448.
Informative ReferencesElliptic Curves for SecurityThis memo specifies two elliptic curves over prime fields that offer a high level of practical security in cryptographic applications, including Transport Layer Security (TLS). These curves are intended to operate at the ~128-bit and ~224-bit security level, respectively, and are generated deterministically based on a list of required properties.Privacy PassThe Static Diffie-Hellman ProblemCerticom ResearchCerticom ResearchWallet Databases with ObserversSecurity Analysis of the Strong Diffie-Hellman ProblemHow To Prove Yourself: Practical Solutions to Identification and Signature ProblemsHighly-Efficient and Composable Password-Protected Secret Sharing (Or: How to Protect Your Bitcoin Wallet Online)Round-Optimal Password-Protected Secret Sharing and T-PAKE in the Password-Only ModelSPHINX: A Password Store that Perfectly Hides Passwords from ItselfA Fast and Simple Partially Oblivious PRF, with ApplicationsPrivacy Pass: Bypassing Internet Challenges AnonymouslyRoyal Holloway, University of London (work completed during an internship at Cloudflare), London , UKUniversity of Waterloo, Waterloo , BelgiumCloudflare, San Francisco, California , USASEC 1: Elliptic Curve CryptographySEC 2: Recommended Elliptic Curve Domain ParametersPublic Key Cryptography for the Financial Services Industry: the Elliptic Curve Digital Signature Algorithm (ECDSA)ANSIRecommendation for pair-wise key-establishment schemes using discrete logarithm cryptographyTest VectorsThis section includes test vectors for the protocol variants specified
in this document. For each ciphersuite specified in ,
there is a set of test vectors for the protocol when run the OPRF,
VOPRF, and POPRF modes. Each test vector lists the batch size for
the evaluation. Each test vector value is encoded as a hexadecimal
byte string. The fields of each test vector are described below.
"Input": The private client input, an opaque byte string.
"Info": The public info, an opaque byte string. Only present for POPRF test
vectors.
"Blind": The blind value output by Blind(), a serialized Scalar
of Ns bytes long.
"BlindedElement": The blinded value output by Blind(), a serialized
Element of Ne bytes long.
"EvaluatedElement": The evaluated element output by BlindEvaluate(),
a serialized Element of Ne bytes long.
"Proof": The serialized Proof output from GenerateProof() composed of
two serialized Scalar values each of Ns bytes long. Only present for
VOPRF and POPRF test vectors.
"ProofRandomScalar": The random scalar r computed in GenerateProof(), a
serialized Scalar of Ns bytes long. Only present for VOPRF and POPRF
test vectors.
"Output": The protocol output, an opaque byte string of length Nh bytes.
Test vectors with batch size B > 1 have inputs separated by a comma
",". Applicable test vectors will have B different values for the
"Input", "Blind", "BlindedElement", "EvaluationElement", and
"Output" fields.The server key material, pkSm and skSm, are listed under the mode for
each ciphersuite. Both pkSm and skSm are the serialized values of
pkS and skS, respectively, as used in the protocol. Each key pair
is derived from a seed Seed and info string KeyInfo, which are
listed as well, using the DeriveKeyPair function from .OPRF(ristretto255, SHA-512)OPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1VOPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2POPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2OPRF(decaf448, SHAKE-256)OPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1VOPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2POPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2OPRF(P-256, SHA-256)OPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1VOPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2POPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2OPRF(P-384, SHA-384)OPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1VOPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2POPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2OPRF(P-521, SHA-512)OPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1VOPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2POPRF ModeTest Vector 1, Batch Size 1Test Vector 2, Batch Size 1Test Vector 3, Batch Size 2