]>
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. This document is a product of the Crypto Forum Research Group
(CFRG) in the IRTF.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 OPRFs 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.This document represents the consensus of the Crypto Forum Research
Group (CFRG). It is not an IETF product and is not a standard.Change logdraft-20:
Address IRSG comments.
draft-19:
Fix error.
draft-18:
Apply editorial suggestions from CFRG chair review.
draft-17:
Change how suites are identified and finalize test vectors.
Apply editorial suggestions from IRTF chair review.
draft-16:
Apply editorial suggestions from document shepherd.
draft-15:
Apply editorial suggestions from CFRG RGLC.
draft-14:
Correct current state of formal analysis for the VOPRF protocol variant.
draft-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^{16} - 1 bytes.
This length restriction exists because PublicInput and PrivateInput values
are length-prefixed with two bytes before use throughout the protocol.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 using 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 (other than the identity) 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 by r 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): 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 .
Security properties of this function are described
in .
HashToScalar(x): Deterministically maps
an array of bytes x to an element in GF(p). This function is optionally
parameterized by a DST; see . Security properties of this
function are described in .
RandomScalar(): Chooses at random a non-zero element in GF(p).
ScalarInverse(s): Returns the inverse of input Scalars on GF(p).
SerializeElement(A): Maps an ElementA
to a canonical byte array buf of fixed length Ne.
DeserializeElement(buf): Attempts to map a byte array buf to
an ElementA, and fails if the input is not the valid canonical byte
representation of an element of the group. This function can raise a
DeserializeError if deserialization fails or A is the identity element of
the group; see for group-specific input validation steps.
SerializeScalar(s): Maps a Scalars to a canonical
byte array buf of fixed length Ns.
DeserializeScalar(buf): Attempts to map a byte array buf to a Scalars.
This function can raise a DeserializeError if deserialization fails; see
for group-specific input validation steps.
contains details for the implementation of this interface
for different prime-order groups instantiated over elliptic curves. In
particular, for some choices of elliptic curves, e.g., those detailed in
, which require accounting for cofactors,
describes required steps necessary to ensure the resulting group is of
prime order.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), which is used in the construction of VOPRF and
POPRF. 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. We use the notation proof[0] and proof[1] to denote
the first and second elements in this tuple, respectively.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 and describe three protocol variants referred to as the
OPRF, VOPRF, and POPRF modes. Each of these variants involve two messages between
client and server but differ slightly in terms of the security properties; see
for more information. A high level description of the functionality
of each mode follows.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
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 protocol variants.
Mode
Value
modeOPRF
0x00
modeVOPRF
0x01
modePOPRF
0x02
Additionally, each protocol variant is instantiated with a ciphersuite,
or suite. Each ciphersuite is identified with an ASCII string identifier,
referred to as identifier; see for the set of initial
ciphersuite values.The mode and ciphersuite identifier values are combined to create a
"context string" used throughout the protocol with the following function:Key Generation and Context SetupIn the offline setup phase, the server generates a fresh, random key
pair (skS, pkS). There are two ways to generate this key pair.
The first of which is using the GenerateKeyPair function described below.The second way to generate the key pair is via the deterministic key
generation function DeriveKeyPair described in .
Applications and implementations can use either method in practice.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 identifier. 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:Deterministic Key GenerationThis section describes a deterministic key generation function, DeriveKeyPair.
It accepts a seed of Ns bytes generated from a cryptographically secure
random number generator and an optional (possibly empty) info string.
The constant Ns corresponds to the size in bytes of a serialized Scalar
and is defined in . Note that by design knowledge of seed and info
is necessary to compute this function, which means that the secrecy of the
output private key (skS) depends on the secrecy of seed (since the info
string is public). 255:
raise DeriveKeyPairError
skS = G.HashToScalar(deriveInput || I2OSP(counter, 1),
DST = "DeriveKeyPair" || contextString)
counter = counter + 1
pkS = G.ScalarMultGen(skS)
return skS, pkS
]]>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 raising 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 and requirements
on input validation for each ciphersuite.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.An entity which knows both the secret key and the input can compute the PRF
result 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, an entity which knows both the secret key and the input can compute the PRF
result 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, an entity which knows both the secret key and the input can compute
the PRF result 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 .
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 includes an initial set of ciphersuites with supported groups
and hash functions. It also includes implementation details for each ciphersuite,
focusing on input validation. Future documents can specify additional ciphersuites
as needed provided they meet the requirements in .For 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)This ciphersuite uses ristretto255 for the Group and SHA-512 for the Hash
function. The value of the ciphersuite identifier is "ristretto255-SHA512".
Group: ristretto255
Order(): Return 2^252 + 27742317777372353535851937790883648493 (see )
Identity(): As defined in .
Generator(): As defined in .
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().
ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().
RandomScalar(): Implemented by returning a uniformly random Scalar in the range
[0, G.Order() - 1]. Refer to for implementation guidance.
SerializeElement(A): Implemented using the 'Encode' function from Section 4.3.2 of ; Ne = 32.
DeserializeElement(buf): Implemented using the 'Decode' function from Section 4.3.1 of .
Additionally, this function validates that the resulting element is not the group
identity element. If these checks fail, deserialization returns an InputValidationError error.
SerializeScalar(s): Implemented by outputting the little-endian 32-byte encoding of
the Scalar value with the top three bits set to zero; Ns = 32.
DeserializeScalar(buf): Implemented by attempting to deserialize a Scalar from a
little-endian 32-byte string. This function can fail if the input does not
represent a Scalar in the range [0, G.Order() - 1]. Note that this means the
top three bits of the input MUST be zero.
Hash: SHA-512; Nh = 64.
OPRF(decaf448, SHAKE-256)This ciphersuite uses decaf448 for the Group and SHAKE-256 for the Hash
function. The value of the ciphersuite identifier is "decaf448-SHAKE256".
RandomScalar(): Implemented by returning a uniformly random Scalar in the range
[0, G.Order() - 1]. Refer to for implementation guidance.
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().
ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().
SerializeElement(A): Implemented using the 'Encode' function from Section 5.3.2 of ; Ne = 56.
DeserializeElement(buf): Implemented using the 'Decode' function from Section 5.3.1 of .
Additionally, this function validates that the resulting element is not the group
identity element. If these checks fail, deserialization returns an InputValidationError error.
SerializeScalar(s): Implemented by outputting the little-endian 56-byte encoding of
the Scalar value; Ns = 56.
DeserializeScalar(buf): Implemented by attempting to deserialize a Scalar from a
little-endian 56-byte string. This function can fail if the input does not
represent a Scalar in the range [0, G.Order() - 1].
Hash: SHAKE-256; Nh = 64.
OPRF(P-256, SHA-256)This ciphersuite uses P-256 for the Group and SHA-256 for the Hash
function. The value of the ciphersuite identifier is "P256-SHA256".
RandomScalar(): Implemented by returning a uniformly random Scalar in the range
[0, G.Order() - 1]. Refer to for implementation guidance.
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().
ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().
SerializeElement(A): Implemented using the compressed Elliptic-Curve-Point-to-Octet-String
method according to ; Ne = 33.
DeserializeElement(buf): Implemented by attempting to deserialize a 33 byte input string to
a public key using the compressed Octet-String-to-Elliptic-Curve-Point method according to ,
and then performs partial public-key validation as defined in section 5.6.2.3.4 of
. This includes checking that the
coordinates of the resulting point are in the correct range, that the point is on
the curve, and that the point is not the group identity element.
If these checks fail, deserialization returns an InputValidationError error.
SerializeScalar(s): Implemented using the Field-Element-to-Octet-String conversion
according to ; Ns = 32.
DeserializeScalar(buf): Implemented by attempting to deserialize a Scalar from a 32-byte
string using Octet-String-to-Field-Element from . This function can fail if the
input does not represent a Scalar in the range [0, G.Order() - 1].
Hash: SHA-256; Nh = 32.
OPRF(P-384, SHA-384)This ciphersuite uses P-384 for the Group and SHA-384 for the Hash
function. The value of the ciphersuite identifier is "P384-SHA384".
RandomScalar(): Implemented by returning a uniformly random Scalar in the range
[0, G.Order() - 1]. Refer to for implementation guidance.
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().
ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().
SerializeElement(A): Implemented using the compressed Elliptic-Curve-Point-to-Octet-String
method according to ; Ne = 49.
DeserializeElement(buf): Implemented by attempting to deserialize a 49-byte array to
a public key using the compressed Octet-String-to-Elliptic-Curve-Point method according to ,
and then performs partial public-key validation as defined in section 5.6.2.3.4 of
. This includes checking that the
coordinates of the resulting point are in the correct range, that the point is on
the curve, and that the point is not the point at infinity. Additionally, this function
validates that the resulting element is not the group identity element.
If these checks fail, deserialization returns an InputValidationError error.
SerializeScalar(s): Implemented using the Field-Element-to-Octet-String conversion
according to ; Ns = 48.
DeserializeScalar(buf): Implemented by attempting to deserialize a Scalar from a 48-byte
string using Octet-String-to-Field-Element from . This function can fail if the
input does not represent a Scalar in the range [0, G.Order() - 1].
Hash: SHA-384; Nh = 48.
OPRF(P-521, SHA-512)This ciphersuite uses P-521 for the Group and SHA-512 for the Hash
function. The value of the ciphersuite identifier is "P521-SHA512".
RandomScalar(): Implemented by returning a uniformly random Scalar in the range
[0, G.Order() - 1]. Refer to for implementation guidance.
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().
ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().
SerializeElement(A): Implemented using the compressed Elliptic-Curve-Point-to-Octet-String
method according to ; Ne = 67.
DeserializeElement(buf): Implemented by attempting to deserialize a 49 byte input string to
a public key using the compressed Octet-String-to-Elliptic-Curve-Point method according to ,
and then performs partial public-key validation as defined in section 5.6.2.3.4 of
. This includes checking that the
coordinates of the resulting point are in the correct range, that the point is on
the curve, and that the point is not the point at infinity. Additionally, this function
validates that the resulting element is not the group identity element.
If these checks fail, deserialization returns an InputValidationError error.
SerializeScalar(s): Implemented using the Field-Element-to-Octet-String conversion
according to ; Ns = 66.
DeserializeScalar(buf): Implemented by attempting to deserialize a Scalar from a 66-byte
string using Octet-String-to-Field-Element from . This function can fail if the
input does not represent a Scalar in the range [0, G.Order() - 1].
Hash: SHA-512; Nh = 64.
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 (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.The DeserializeElement and DeserializeScalar functions instantiated for a
particular prime-order group corresponding to a ciphersuite MUST adhere to
the description in . Future ciphersuites MUST describe how input
validation is done for DeserializeElement and DeserializeScalar.Additionally, future ciphersuites must take care when choosing the
security level of the group. See for additional details.Random Scalar GenerationTwo popular algorithms for generating a random integer uniformly distributed in
the range [0, G.Order() -1] are as follows:Rejection SamplingGenerate a random byte array with Ns bytes, and attempt to map to a Scalar
by calling DeserializeScalar in constant time. If it succeeds, return the
result. If it fails, try again with another random byte array, until the
procedure succeeds. Failure to implement DeserializeScalar in constant time
can leak information about the underlying corresponding Scalar.As an optimization, if the group order is very close to a power of
2, it is acceptable to omit the rejection test completely. In
particular, if the group order is p, and there is an integer b
such that |p - 2^{b}| is less than 2^{(b/2)}, then
RandomScalar can simply return a uniformly random integer of at
most b bits.Random Number Generation Using Extra Random BitsGenerate a random byte array with L = ceil(((3 * ceil(log2(G.Order()))) / 2) / 8)
bytes, and interpret it as an integer; reduce the integer modulo G.Order() and return the
result. See for the underlying derivation of L.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^{16}-1 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.IANA considerationsThis document has no IANA actions.Security ConsiderationsThis section discusses the security of the protocols defined in this specification, along
with some suggestions and trade-offs that arise from the implementation
of the protocol 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 .Beyond client input secret, in the OPRF protocol, the server learns nothing about
the output y of the function, nor does the client learn anything about the
server's private key k.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. Both client and server know
the public input, but similar to the OPRF and VOPRF protocols, the server
learns nothing about the client's private input or the output of the function,
and the client learns 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. Note that partial obliviousness only applies
to the POPRF variant because neither the OPRF nor VOPRF variants accept public
input to the protocol.Since the POPRF variant has a different syntax than the OPRF and VOPRF variants,
i.e., y = F(k, x, info), the pseudorandomness property is generalized:
Pseudorandomness: For a random sampling of k, F is pseudorandom if the output
y = F(k, x, info) on any input pairs (x, info) is indistinguishable from uniformly
sampling any element in F's range.
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 particular, the VOPRF construction is similar to the construction
with the following distinguishing properties:
This document does not use session identifiers to differentiate different instances of the protocol; and
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) protocols in are based on the One-More Gap Computational
Diffie Hellman assumption that is computationally difficult to solve in the corresponding prime-order group.
In , these properties are proven for one instance (i.e., one key) of
the VOPRF protocol, and without batching. There is currently no security
analysis available for the VOPRF protocol described in this document in
a setting with multiple server keys or batching.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 batch, 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 Computational Diffie Hellman 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 Computational Diffie Hellman 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 attacks, 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 decaf448-SHAKE256),
P-384 (used by ciphersuite P384-SHA384), or P-521 (used by ciphersuite P521-SHA512).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, Julia Hesse, Russ Housley,
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.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.
Recommendation for pair-wise key-establishment schemes using discrete logarithm cryptographyInformative 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 CryptographyDigital Signature Standard (DSS)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 two-message issuance
protocol for Privacy Pass tokens: one that produces tokens that are
privately verifiable using the issuance private key, and another that
produces tokens that are publicly verifiable using the issuance
public key.
Test 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 .ristretto255-SHA512OPRF 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 2decaf448-SHAKE256OPRF 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 2P256-SHA256OPRF 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 2P384-SHA384OPRF 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 2P521-SHA512OPRF 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