Oblivious Pseudorandom Functions (OPRFs) using Prime-Order Groups
Brave Software
alex.davidson92@gmail.com
Cloudflare, Inc.
101 Townsend St
San Francisco
United States of America
armfazh@cloudflare.com
Cloudflare, Inc.
101 Townsend St
San Francisco
United States of America
nick@cloudflare.com
Cloudflare, Inc.
101 Townsend St
San Francisco
United States of America
caw@heapingbits.net
Internet-Draft
An 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. A Partially-Oblivious PRF (POPRF) is an OPRF
that allows client and server to provide public input to the
PRF. OPRFs and POPRFs can also satisfy a notion of 'verifiability'.
In this setting, clients can verify that the server used a specific
private key during the execution of the protocol. This document
specifies a POPRF protocol with optional verifiability instantiated within
standard prime-order groups, including elliptic curves.
Discussion Venues
Source for this draft and an issue tracker can be found at
.
Introduction
A 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 Partially-Oblivious PRF (POPRF) is a variant of an OPRF 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 .
A POPRF with fixed input y is functionally equivalent to an OPRF.
A POPRF is said to be 'verifiable' if the server can prove to the client
that F(k, x, y) was computed using key k, without revealing k to the client.
POPRFs 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 POPRFs have also been used for
password-protected secret sharing schemes such as that of .
This document introduces a POPRF protocol built upon prime-order groups based on .
The protocol supports optional verifiability with the addition of a non-interactive
zero knowledge proof (NIZK). This proof demonstrates correctness of the computation,
using a known public key that serves as a commitment to the server's private
key. The document describes the protocol, application considerations, and its
security properties.
Change log
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.
Requirements
The 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.
Preliminaries
The (V)OPRF protocol in this document has two primary dependencies:
-
GG: A prime-order group implementing the API described below in ,
with base point defined in the corresponding reference for each group.
(See for these base points.)
-
Hash: A cryptographic hash function that is indifferentiable from a
Random Oracle, whose output length is Nh bytes long.
specifies ciphersuites as combinations of GG and Hash.
Prime-Order Group Dependency
In this document, we assume the construction of an additive, prime-order
group GG for performing all mathematical operations. Such groups are
uniquely determined by the choice of the prime p that defines the
order of the group. We use GF(p) to represent the finite field of
order p. For the purpose of understanding and implementing this
document, we take GF(p) to be equal to the set of integers defined by
{0, 1, ..., p-1}.
The fundamental group operation is addition + with identity element
I. For any elements A and B of the group GG, A + B = B + A is
also a member of GG. Also, for any A in GG, 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. We denote G as the fixed generator of
the group. Scalar base multiplication is equivalent to the repeated
application of the group operation G with itself r-1 times, this
is denoted as ScalarBaseMult(r). The set of scalars corresponds to
GF(p). This document uses types Element and Scalar to denote elements
of the group GG and its set of scalars, respectively.
We now detail a number of member functions that can be invoked on a
prime-order group GG.
- Order(): Outputs the order of GG (i.e. p).
- Identity(): Outputs the identity element of the group (i.e. I).
- HashToGroup(x): A member function of GG that deterministically maps
an array of bytes x to an element of GG. 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 GG 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 GG that chooses at random a
non-zero element in GF(p).
- SerializeElement(A): A member function of GG that maps a group element A
to a unique byte array buf of fixed length Ne. The output type of
this function is SerializedElement.
- DeserializeElement(buf): A member function of GG that maps a byte array
buf to a group element A, or fails if the input is not a valid
byte representation of an element. This function can raise a
DeserializeError if deserialization fails or A is the identity element
of the group; see .
- SerializeScalar(s): A member function of GG that maps a scalar element s
to a unique byte array buf of fixed length Ns. The output type of this
function is SerializedScalar.
- DeserializeScalar(buf): A member function of GG that maps a byte array
buf to a scalar s, or fails if the input is not a valid byte
representation of a scalar. This function can raise a
DeserializeError if deserialization fails; see .
Two functions can be used for generating a (V)OPRF key pair (skS, pkS)
where skS is a non-zero integer less than p and pkS = ScalarBaseMult(skS):
GenerateKeyPair and DeriveKeyPair. GenerateKeyPair is a randomized function
that outputs a fresh key pair (skS, pkS) upon every invocation. DeriveKeyPair
is a deterministic function that generates private key skS from a random byte
string seed, which SHOULD have at least Ns bytes of entropy, and then
computes pkS = ScalarBaseMult(skS).
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.
Notation and Terminology
The 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 and OS2IP: Convert a byte array to and from a non-negative
integer as described in . Note that these functions
operate on byte arrays in big-endian byte order.
- For any two byte strings a and b, CT_EQUAL(a, b) represents
constant-time equality between a and b which returns true if
a and b are equal and false otherwise.
Data structure descriptions use TLS notation .
All algorithms and procedures described in this document are laid out
in a Python-like pseudocode.
String values such as "Context-" are ASCII string literals.
The following terms are used throughout this document.
- PRF: Pseudorandom Function.
- OPRF: Oblivious Pseudorandom Function.
- VOPRF: Verifiable Oblivious Pseudorandom Function.
- POPRF: Partially Oblivious Pseudorandom Function.
- 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.
- NIZK: Non-interactive zero knowledge.
- DLEQ: Discrete Logarithm Equality.
POPRF Protocol
In this section, we define two POPRF variants: a base mode and verifiable
mode. In the base mode, a client and server interact to compute
output = F(skS, input, info), where input is the client's private input,
skS is the server's private key, info is the public input (or metadata),
and output is the POPRF output. The client learns output and the server
learns nothing. In the verifiable mode, the client also receives proof that
the server used skS in computing the function.
To achieve verifiability, as in the original work of , we
provide a zero-knowledge proof that the key provided as input by the
server in the Evaluate function is the same key as it used to produce
their public key. As an example of the nature of attacks that this
prevents, this ensures that the server uses the same private key for
computing the verifiable POPRF output and does not attempt to "tag"
individual clients with select keys. This proof does not reveal the
server's private key to the client.
The following one-byte values distinguish between these two modes:
Mode |
Value |
modeBase |
0x00 |
modeVerifiable |
0x01 |
Overview
Both participants agree on the mode and a choice of ciphersuite that is
used before the protocol exchange. Once established, the base mode of
the protocol runs to compute output = F(skS, input, info) as follows:
evaluatedElement = Evaluate(skS, blindedElement, info)
evaluatedElement
<----------
output = Finalize(input, blind, evaluatedElement, blindedElement, info)
]]>
In Blind the client generates a blinded element and blinding data. The server
computes the POPRF evaluation in Evaluate over the client's blinded element,
and public information info. In Finalize the client unblinds the server
response and produces the POPRF output.
In the verifiable mode of the protocol, the server additionally computes
a proof in Evaluate. The client verifies this proof using the server's
expected public key before completing the protocol and producing the
protocol output.
Context Setup
Both modes of the POPRF involve an offline setup phase. In this phase,
both the client and server create a context used for executing the
online phase of the protocol. The key pair (skS, pkS) should be
generated by calling either GenerateKeyPair or DeriveKeyPair.
The base mode setup functions for creating client and server contexts are below:
The verifiable mode setup functions for creating client and server
contexts are below:
Each setup function takes a ciphersuite from the list defined in
. Each ciphersuite has a two-byte field ID used to
identify the suite.
[[RFC editor: please change "VOPRF08" to "RFCXXXX", where XXXX is the final number, here and elsewhere before publication.]]
Context APIs
In this section, we detail the APIs available on the client and server
POPRF contexts. Each API has the following implicit parameters:
- GG, a prime-order group implementing the API described in .
- contextString, a domain separation tag constructed during context setup.
The data types PrivateInput and PublicInput are opaque byte strings
of arbitrary length no larger than 2^13 octets. Proof is a sequence
of two SerializedScalar values, as shown below.
Server Context
The ServerContext encapsulates the context string constructed during
setup and the POPRF key pair. It has three functions, Evaluate,
FullEvaluate and VerifyFinalize described below. Evaluate takes
serialized representations of blinded group elements from the client
as inputs along with public input info.
FullEvaluate takes PrivateInput values, and it is useful for applications
that need to compute the whole POPRF protocol on the server side only.
VerifyFinalize takes PrivateInput values and their corresponding output
digests from Finalize as input, and returns true if the inputs match the outputs.
Note that VerifyFinalize and FullEvaluate are not used in the main POPRF
protocol. They are exposed as an API for building higher-level protocols.
VerifiableServerContext
The VerifiableServerContext extends the base ServerContext with an
augmented Evaluate() function. This function produces a proof that
skS was used in computing the result. It makes use of the helper
functions GenerateProof and ComputeComposites, described below.
Evaluate
The helper functions GenerateProof and ComputeComposites are defined
below.
GenerateProof
Batching inputs
Unlike other functions, ComputeComposites takes lists of inputs,
rather than a single input. Applications can take advantage of this
functionality by invoking GenerateProof on batches of inputs to
produce a combined, constant-size proof. (In the pseudocode above,
the single inputs blindedElement and evaluatedElement are passed
as single-item lists to ComputeComposites.)
In particular, servers can produce a single, constant-sized proof for N
client inputs sent in a single request, rather than one proof per client
input. This optimization benefits clients and servers since it amortizes
the cost of proof generation and bandwidth across multiple requests.
ComputeComposites
The definition of ComputeComposites is given below. This function is
used both on generation and verification of the proof.
If the private key is known, as is the case for the server, this function
can be optimized as shown in ComputeCompositesFast below.
Client Context
The ClientContext encapsulates the context string constructed during
setup. It has two functions, Blind() and Finalize(), as described
below. It also has an internal function, Unblind(), which is used
by Finalize. The implementation of these functions varies depending
on the mode.
Blind and Unblind
The inverse Unblind is implemented as follows.
Finalize
Finalize depends on the internal Unblind function. In this mode, Finalize
does not include all inputs listed in . These additional
inputs are only useful for the verifiable mode, described in .
VerifiableClientContext
The VerifiableClientContext extends the base ClientContext with the
desired server public key pkS with an augmented Unblind() function.
This function verifies an evaluation proof using pkS. It makes use of
the helper function ComputeComposites described above. It has one
helper function, VerifyProof(), defined below.
VerifyProof
This algorithm outputs a boolean verified which indicates whether the
proof inside of the evaluation verifies correctly, or not.
Verifiable Unblind
The inverse VerifiableUnblind is implemented as follows. This function
can raise an exception if element deserialization or proof verification
fails.
Ciphersuites
A ciphersuite (also referred to as 'suite' in this document) for the protocol
wraps the functionality required for the protocol to take place. This
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:
-
GG: A prime-order group exposing the API detailed in , with base
point 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 that is indifferentiable from a
Random Oracle, whose output length is Nh bytes long.
This section specifies ciphersuites with supported groups and hash functions.
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)
-
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 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 Order()
and in little-endian order.
- Hash: SHA-512, and Nh = 64.
- 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 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 Order()
and in little-endian order.
- Hash: SHAKE-256, and Nh = 64.
- 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 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 Order() and in big-endian
order.
- Hash: SHA-256, and Nh = 32.
- 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 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 Order() and in big-endian
order.
- Hash: SHA-384, and Nh = 48.
- 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 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 Order() and in big-endian
order.
- Hash: SHA-512, and Nh = 64.
- ID: 0x0005
Application Considerations
This section describes considerations for applications, including explicit error
treatment and public metadata representation.
Error Considerations
Some POPRF APIs specified in this document are fallible. For example, Finalize
and Evaluate can fail if any element received from the peer fails deserialization.
The explicit errors generated throughout this specification, along with the
conditions that lead to each error, are as follows:
-
VerifyError: Verifiable POPRF proof verification failed; .
-
DeserializeError: Group element or scalar deserialization failure; .
-
InverseError: A scalar is zero and has no inverse; .
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.
Public Metadata
The optional and public info string included in the protocol allows clients
and servers to cryptographically bind additional data to the POPRF output. This
metadata is known to both parties at the start of the protocol. It is RECOMMENDED
that this metadata 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 metadata uses a unique, prefix-free encoding.
See for further discussion on
constructing domain separation values.
Security Considerations
This section discusses the cryptographic security of our protocol, along
with some suggestions and trade-offs that arise from the implementation
of a POPRF.
Security Properties
The security properties of a POPRF protocol with functionality
y = F(k, x, t) include those of a standard PRF. Specifically:
- Pseudorandomness: F is pseudorandom if the output y = F(k, x, t) on any
input x is indistinguishable from uniformly sampling any element in
F's range, for a random sampling of k.
In other words, consider an adversary that picks inputs x from the
domain of F and evaluates F on (k, x, t) (without knowledge of randomly
sampled k). Then the output distribution F(k, x, t) 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.
A POPRF protocol must also satisfy the following property:
- Partial obliviousness: 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. Both client and server learn
the public input (info).
Essentially, partial obliviousness tells us that, even if the server learns
the client's private input x at some point in the future, then the server will
not be able to link any particular POPRF evaluation to x. This property is
also known as unlinkability .
Optionally, for any protocol that satisfies the above properties, there
is an additional security property:
- Verifiable: The client must only complete execution of the protocol if
it can successfully assert that the POPRF output it computes is
correct. This is taken with respect to the POPRF key held by the
server.
Any POPRF that satisfies the 'verifiable' security property is known as a
verifiable POPRF. 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.
Cryptographic Security
Below, we discuss the cryptographic security of the verifiable POPRF
protocol from , relative to the necessary cryptographic
assumptions that need to be made.
Protocol Security and Computational Hardness Assumptions
The 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 NIZK proof object.
This is enabled using an established batching technique.
The cryptographic security of the construction is based on the assumption
that the One-More Gap Strong Diffie-Hellman Inversion (SDHI) assumption from
is computationally difficult to solve. show that
both the One-More Gap Computational Diffie Hellman (CDH)
assumption and the One-More Gap SDHI assumption reduce to the q-DL assumption
in the algebraic group model, for some q number of Evaluate queries.
(The One-More Gap CDH assumption was the hardness assumption used to
evaluate the 2HashDH-NIZK construction from , which is a predecessor
to the design in this specification.)
Static q-DL Assumption
A side-effect of the POPRF design is that it allows instantiation of an oracle for
retrieving "strong-DH" evaluations, in which an adversary can query a group element
B and scalar c, and receive evaluation output 1/(k+c)*B. This type of oracle allows
an adversary to form elements of "repeated powers" of the server-side secret. This
"repeated powers" structure has been studied in terms of the q-DL problem which
asks the following: Given G1, G2, h*G2, (h^2)*G2, ..., (h^Q)*G2; for G1 and G2
generators of GG. Output h where h is an element of GF(p)
For example, consider an adversary that queries the strong-DH oracle provided by the
POPRF on a fixed scalar c starting with group element G2, then passes the received
evaluation group element back as input for the next evaluation. If we set h = 1/(k+c),
such an adversary would receive exactly the evaluations given in the q-DL problem: h*G2,
(h^2)*G2, ..., (h^Q)*G2.
capture the power of the strong-DH oracle in the One-More Gap SDHI assumption
and show, in the algebraic group model, the security of this assumption can be reduced to
the security of the q-DL problem, where q is the number of queries made to the blind
evaluation oracle.
The q-DL assumption has been well studied in the literature, and there exist a number of
cryptanalytic studies to inform parameter choice and group instantiation (for example,
and ).
Implications for Ciphersuite Choices
The POPRF instantiations that we recommend in this document are informed
by the cryptanalytic discussion above. In particular, choosing elliptic
curves configurations that describe 128-bit group instantiations would
appear to in fact instantiate a POPRF with 128-(log_2(Q)/2) bits of
security. Moreover, such attacks are only possible for those certain
applications where the adversary can query the POPRF directly.
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. We see this possibility as something that
may result in problems in the future. Applications that admit the
aforementioned oracle functionality, and that cannot tolerate discrete
logarithm security of lower than 128 bits, are RECOMMENDED to only
implement ciphersuites 0x0002, 0x0004, and 0x0005.
Proof Randomness
It is essential that a different r value is used for every invocation
of GenerateProof. Failure to do so may leak skS as is possible in Schnorr
or (EC)DSA scenarios where fresh randomness is not used.
Domain Separation
Applications SHOULD construct input to the protocol to provide domain
separation. Any system which has multiple POPRF applications should
distinguish client inputs to ensure the POPRF results are separate.
Guidance for constructing info can be found in .
Element and Scalar Validation
The DeserializeElement function recovers a group element from an arbitrary
byte array. This function validates 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, this function performs 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 point at infinity.
If these checks fail, deserialization returns an error.
For ristretto255 and decaf448, elements are deserialized by invoking the Decode
function from and , respectively,
which returns false if the element is invalid. If this function returns false,
deserialization returns an error.
The DeserializeScalar function recovers 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 Order(). For
ristretto255 and decaf448, this function ensures that the input, when treated as
a little-endian integer, is a valud between 0 and Order().
Hashing to Group
A critical requirement of implementing the prime-order group using
elliptic curves is a method to instantiate the function
GG.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 GG.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.
Timing Leaks
To ensure no information is leaked during protocol execution, all
operations that use secret data MUST run in constant time. Operations that
SHOULD run in constant time include all prime-order group operations and
proof-specific operations (GenerateProof() and VerifyProof()).
Acknowledgements
This 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, and Bas Westerbaan
also provided helpful input and contributions to the document.
References
Normative References
Key words for use in RFCs to Indicate Requirement Levels
In 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 Protocol
Algorand Foundation
Novi Research
Cloudflare
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: The Protocol
Cloudflare
This document specifies the Privacy Pass protocol. This protocol
provides anonymity-preserving authorization of clients to servers.
In particular, client re-authorization events cannot be linked to any
previous initial authorization. Privacy Pass is intended to be used
as a performant protocol in the application-layer.
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words
RFC 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.2
This 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 Curves
Cloudflare
Cornell Tech
Cloudflare
Stanford University
Cloudflare
This document specifies a number of algorithms for encoding or
hashing an arbitrary string to a point on an elliptic curve.
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 References
Elliptic Curves for Security
This 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.
The Transport Layer Security (TLS) Protocol Version 1.3
This document specifies version 1.3 of the Transport Layer Security (TLS) protocol. TLS allows client/server applications to communicate over the Internet in a way that is designed to prevent eavesdropping, tampering, and message forgery.
This document updates RFCs 5705 and 6066, and obsoletes RFCs 5077, 5246, and 6961. This document also specifies new requirements for TLS 1.2 implementations.
Privacy Pass
The Static Diffie-Hellman Problem
Security Analysis of the Strong Diffie-Hellman Problem
Highly-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 model
SPHINX, A Password Store that Perfectly Hides from Itself
A Fast and Simple Partially Oblivious PRF, with Applications
Privacy Pass, Bypassing Internet Challenges Anonymously
SEC 1: Elliptic Curve Cryptography
SEC 2: Recommended Elliptic Curve Domain Parameters
Public Key Cryptography for the Financial Services Industry: the Elliptic Curve Digital Signature Algorithm (ECDSA)
ANSI
Recommendation for pair-wise key-establishment schemes using discrete logarithm cryptography
Test Vectors
This section includes test vectors for the (V)OPRF protocol specified
in this document. For each ciphersuite specified in ,
there is a set of test vectors for the protocol when run in the base
mode and verifiable mode. Each test vector lists the batch size for
the evaluation. Each test vector value is encoded as a hexadecimal
byte string. The label for each test vector value is described below.
- "Input": The private client input, an opaque byte string.
- "Info": The public info, an opaque byte string.
- "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 Evaluate(),
a serialized Element of Ne bytes long.
- "Proof": The serialized Proof output from GenerateProof() (only
listed for verifiable mode test vectors), composed of two serialized
Scalar values each of Ns bytes long.
- "ProofRandomScalar": The random scalar r computed in GenerateProof()
(only listed for verifiable mode test vectors), a serialized Scalar of
Ns bytes long.
- "Output": The OPRF output, a 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.
Base mode and verifiable mode uses multiplicative blinding.
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, which is listed as well, using the following
implementation of DeriveKeyPair:
OPRF(ristretto255, SHA-512)
Base Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Verifiable Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Test Vector 3, Batch Size 2
OPRF(decaf448, SHAKE-256)
Base Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Verifiable Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Test Vector 3, Batch Size 2
OPRF(P-256, SHA-256)
Base Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Verifiable Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Test Vector 3, Batch Size 2
OPRF(P-384, SHA-384)
Base Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Verifiable Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Test Vector 3, Batch Size 2
OPRF(P-521, SHA-512)
Base Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Verifiable Mode
Test Vector 1, Batch Size 1
Test Vector 2, Batch Size 1
Test Vector 3, Batch Size 2